5096e4c10d8b022394d45cde9313b8982eb9b768
[profile/ivi/python.git] / Doc / library / asynchat.rst
1
2 :mod:`asynchat` --- Asynchronous socket command/response handler
3 ================================================================
4
5 .. module:: asynchat
6    :synopsis: Support for asynchronous command/response protocols.
7 .. moduleauthor:: Sam Rushing <rushing@nightmare.com>
8 .. sectionauthor:: Steve Holden <sholden@holdenweb.com>
9
10
11 This module builds on the :mod:`asyncore` infrastructure, simplifying
12 asynchronous clients and servers and making it easier to handle protocols
13 whose elements are terminated by arbitrary strings, or are of variable length.
14 :mod:`asynchat` defines the abstract class :class:`async_chat` that you
15 subclass, providing implementations of the :meth:`collect_incoming_data` and
16 :meth:`found_terminator` methods. It uses the same asynchronous loop as
17 :mod:`asyncore`, and the two types of channel, :class:`asyncore.dispatcher`
18 and :class:`asynchat.async_chat`, can freely be mixed in the channel map.
19 Typically an :class:`asyncore.dispatcher` server channel generates new
20 :class:`asynchat.async_chat` channel objects as it receives incoming
21 connection requests.
22
23
24 .. class:: async_chat()
25
26    This class is an abstract subclass of :class:`asyncore.dispatcher`. To make
27    practical use of the code you must subclass :class:`async_chat`, providing
28    meaningful :meth:`collect_incoming_data` and :meth:`found_terminator`
29    methods.
30    The :class:`asyncore.dispatcher` methods can be used, although not all make
31    sense in a message/response context.
32
33    Like :class:`asyncore.dispatcher`, :class:`async_chat` defines a set of
34    events that are generated by an analysis of socket conditions after a
35    :cfunc:`select` call. Once the polling loop has been started the
36    :class:`async_chat` object's methods are called by the event-processing
37    framework with no action on the part of the programmer.
38
39    Two class attributes can be modified, to improve performance, or possibly
40    even to conserve memory.
41
42
43    .. data:: ac_in_buffer_size
44
45       The asynchronous input buffer size (default ``4096``).
46
47
48    .. data:: ac_out_buffer_size
49
50       The asynchronous output buffer size (default ``4096``).
51
52    Unlike :class:`asyncore.dispatcher`, :class:`async_chat` allows you to
53    define a first-in-first-out queue (fifo) of *producers*. A producer need
54    have only one method, :meth:`more`, which should return data to be
55    transmitted on the channel.
56    The producer indicates exhaustion (*i.e.* that it contains no more data) by
57    having its :meth:`more` method return the empty string. At this point the
58    :class:`async_chat` object removes the producer from the fifo and starts
59    using the next producer, if any. When the producer fifo is empty the
60    :meth:`handle_write` method does nothing. You use the channel object's
61    :meth:`set_terminator` method to describe how to recognize the end of, or
62    an important breakpoint in, an incoming transmission from the remote
63    endpoint.
64
65    To build a functioning :class:`async_chat` subclass your  input methods
66    :meth:`collect_incoming_data` and :meth:`found_terminator` must handle the
67    data that the channel receives asynchronously. The methods are described
68    below.
69
70
71 .. method:: async_chat.close_when_done()
72
73    Pushes a ``None`` on to the producer fifo. When this producer is popped off
74    the fifo it causes the channel to be closed.
75
76
77 .. method:: async_chat.collect_incoming_data(data)
78
79    Called with *data* holding an arbitrary amount of received data.  The
80    default method, which must be overridden, raises a
81    :exc:`NotImplementedError` exception.
82
83
84 .. method:: async_chat.discard_buffers()
85
86    In emergencies this method will discard any data held in the input and/or
87    output buffers and the producer fifo.
88
89
90 .. method:: async_chat.found_terminator()
91
92    Called when the incoming data stream  matches the termination condition set
93    by :meth:`set_terminator`. The default method, which must be overridden,
94    raises a :exc:`NotImplementedError` exception. The buffered input data
95    should be available via an instance attribute.
96
97
98 .. method:: async_chat.get_terminator()
99
100    Returns the current terminator for the channel.
101
102
103 .. method:: async_chat.push(data)
104
105    Pushes data on to the channel's fifo to ensure its transmission.
106    This is all you need to do to have the channel write the data out to the
107    network, although it is possible to use your own producers in more complex
108    schemes to implement encryption and chunking, for example.
109
110
111 .. method:: async_chat.push_with_producer(producer)
112
113    Takes a producer object and adds it to the producer fifo associated with
114    the channel.  When all currently-pushed producers have been exhausted the
115    channel will consume this producer's data by calling its :meth:`more`
116    method and send the data to the remote endpoint.
117
118
119 .. method:: async_chat.set_terminator(term)
120
121    Sets the terminating condition to be recognized on the channel.  ``term``
122    may be any of three types of value, corresponding to three different ways
123    to handle incoming protocol data.
124
125    +-----------+---------------------------------------------+
126    | term      | Description                                 |
127    +===========+=============================================+
128    | *string*  | Will call :meth:`found_terminator` when the |
129    |           | string is found in the input stream         |
130    +-----------+---------------------------------------------+
131    | *integer* | Will call :meth:`found_terminator` when the |
132    |           | indicated number of characters have been    |
133    |           | received                                    |
134    +-----------+---------------------------------------------+
135    | ``None``  | The channel continues to collect data       |
136    |           | forever                                     |
137    +-----------+---------------------------------------------+
138
139    Note that any data following the terminator will be available for reading
140    by the channel after :meth:`found_terminator` is called.
141
142
143 asynchat - Auxiliary Classes
144 ------------------------------------------
145
146 .. class:: fifo([list=None])
147
148    A :class:`fifo` holding data which has been pushed by the application but
149    not yet popped for writing to the channel.  A :class:`fifo` is a list used
150    to hold data and/or producers until they are required.  If the *list*
151    argument is provided then it should contain producers or data items to be
152    written to the channel.
153
154
155    .. method:: is_empty()
156
157       Returns ``True`` if and only if the fifo is empty.
158
159
160    .. method:: first()
161
162       Returns the least-recently :meth:`push`\ ed item from the fifo.
163
164
165    .. method:: push(data)
166
167       Adds the given data (which may be a string or a producer object) to the
168       producer fifo.
169
170
171    .. method:: pop()
172
173       If the fifo is not empty, returns ``True, first()``, deleting the popped
174       item.  Returns ``False, None`` for an empty fifo.
175
176
177 .. _asynchat-example:
178
179 asynchat Example
180 ----------------
181
182 The following partial example shows how HTTP requests can be read with
183 :class:`async_chat`.  A web server might create an
184 :class:`http_request_handler` object for each incoming client connection.
185 Notice that initially the channel terminator is set to match the blank line at
186 the end of the HTTP headers, and a flag indicates that the headers are being
187 read.
188
189 Once the headers have been read, if the request is of type POST (indicating
190 that further data are present in the input stream) then the
191 ``Content-Length:`` header is used to set a numeric terminator to read the
192 right amount of data from the channel.
193
194 The :meth:`handle_request` method is called once all relevant input has been
195 marshalled, after setting the channel terminator to ``None`` to ensure that
196 any extraneous data sent by the web client are ignored. ::
197
198    class http_request_handler(asynchat.async_chat):
199
200        def __init__(self, sock, addr, sessions, log):
201            asynchat.async_chat.__init__(self, sock=sock)
202            self.addr = addr
203            self.sessions = sessions
204            self.ibuffer = []
205            self.obuffer = ""
206            self.set_terminator("\r\n\r\n")
207            self.reading_headers = True
208            self.handling = False
209            self.cgi_data = None
210            self.log = log
211
212        def collect_incoming_data(self, data):
213            """Buffer the data"""
214            self.ibuffer.append(data)
215
216        def found_terminator(self):
217            if self.reading_headers:
218                self.reading_headers = False
219                self.parse_headers("".join(self.ibuffer))
220                self.ibuffer = []
221                if self.op.upper() == "POST":
222                    clen = self.headers.getheader("content-length")
223                    self.set_terminator(int(clen))
224                else:
225                    self.handling = True
226                    self.set_terminator(None)
227                    self.handle_request()
228            elif not self.handling:
229                self.set_terminator(None) # browsers sometimes over-send
230                self.cgi_data = parse(self.headers, "".join(self.ibuffer))
231                self.handling = True
232                self.ibuffer = []
233                self.handle_request()