Issue #5262: Improved fix.
[python.git] / Doc / library / asynchat.rst
blob44d3007ee83159e77b90b4632b1619cff21b2f4c
2 :mod:`asynchat` --- Asynchronous socket command/response handler
3 ================================================================
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>
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.
24 .. class:: async_chat()
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.
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.
39    Two class attributes can be modified, to improve performance, or possibly
40    even to conserve memory.
43    .. data:: ac_in_buffer_size
45       The asynchronous input buffer size (default ``4096``).
48    .. data:: ac_out_buffer_size
50       The asynchronous output buffer size (default ``4096``).
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.
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.
71 .. method:: async_chat.close_when_done()
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.
77 .. method:: async_chat.collect_incoming_data(data)
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.
84 .. method:: async_chat._collect_incoming_data(data)
86    Sample implementation of a data collection rutine to be used in conjunction
87    with :meth:`_get_data` in a user-specified :meth:`found_terminator`.
90 .. method:: async_chat.discard_buffers()
92    In emergencies this method will discard any data held in the input and/or
93    output buffers and the producer fifo.
96 .. method:: async_chat.found_terminator()
98    Called when the incoming data stream  matches the termination condition set
99    by :meth:`set_terminator`. The default method, which must be overridden,
100    raises a :exc:`NotImplementedError` exception. The buffered input data
101    should be available via an instance attribute.
104 .. method:: async_chat._get_data()
106    Will return and clear the data received with the sample
107    :meth:`_collect_incoming_data` implementation.
110 .. method:: async_chat.get_terminator()
112    Returns the current terminator for the channel.
115 .. method:: async_chat.handle_close()
117    Called when the channel is closed. The default method silently closes the
118    channel's socket.
121 .. method:: async_chat.handle_read()
123    Called when a read event fires on the channel's socket in the asynchronous
124    loop.  The default method checks for the termination condition established
125    by :meth:`set_terminator`, which can be either the appearance of a
126    particular string in the input stream or the receipt of a particular number
127    of characters.  When the terminator is found, :meth:`handle_read` calls the
128    :meth:`found_terminator` method after calling :meth:`collect_incoming_data`
129    with any data preceding the terminating condition.
132 .. method:: async_chat.handle_write()
134    Called when the application may write data to the channel.   The default
135    method calls the :meth:`initiate_send` method, which in turn will call
136    :meth:`refill_buffer` to collect data from the producer fifo associated
137    with the channel.
140 .. method:: async_chat.push(data)
142    Creates a :class:`simple_producer` object (*see below*) containing the data
143    and pushes it on to the channel's ``producer_fifo`` to ensure its
144    transmission.  This is all you need to do to have the channel write the
145    data out to the network, although it is possible to use your own producers
146    in more complex schemes to implement encryption and chunking, for example.
149 .. method:: async_chat.push_with_producer(producer)
151    Takes a producer object and adds it to the producer fifo associated with
152    the channel.  When all currently-pushed producers have been exhausted the
153    channel will consume this producer's data by calling its :meth:`more`
154    method and send the data to the remote endpoint.
157 .. method:: async_chat.readable()
159    Should return ``True`` for the channel to be included in the set of
160    channels tested by the :cfunc:`select` loop for readability.
163 .. method:: async_chat.refill_buffer()
165    Refills the output buffer by calling the :meth:`more` method of the
166    producer at the head of the fifo.  If it is exhausted then the producer is
167    popped off the fifo and the next producer is activated.  If the current
168    producer is, or becomes, ``None`` then the channel is closed.
171 .. method:: async_chat.set_terminator(term)
173    Sets the terminating condition to be recognized on the channel.  ``term``
174    may be any of three types of value, corresponding to three different ways
175    to handle incoming protocol data.
177    +-----------+---------------------------------------------+
178    | term      | Description                                 |
179    +===========+=============================================+
180    | *string*  | Will call :meth:`found_terminator` when the |
181    |           | string is found in the input stream         |
182    +-----------+---------------------------------------------+
183    | *integer* | Will call :meth:`found_terminator` when the |
184    |           | indicated number of characters have been    |
185    |           | received                                    |
186    +-----------+---------------------------------------------+
187    | ``None``  | The channel continues to collect data       |
188    |           | forever                                     |
189    +-----------+---------------------------------------------+
191    Note that any data following the terminator will be available for reading
192    by the channel after :meth:`found_terminator` is called.
195 .. method:: async_chat.writable()
197    Should return ``True`` as long as items remain on the producer fifo, or the
198    channel is connected and the channel's output buffer is non-empty.
201 asynchat - Auxiliary Classes and Functions
202 ------------------------------------------
205 .. class:: simple_producer(data[, buffer_size=512])
207    A :class:`simple_producer` takes a chunk of data and an optional buffer
208    size.  Repeated calls to its :meth:`more` method yield successive chunks of
209    the data no larger than *buffer_size*.
212    .. method:: more()
214       Produces the next chunk of information from the producer, or returns the
215       empty string.
218 .. class:: fifo([list=None])
220    Each channel maintains a :class:`fifo` holding data which has been pushed
221    by the application but not yet popped for writing to the channel.  A
222    :class:`fifo` is a list used to hold data and/or producers until they are
223    required.  If the *list* argument is provided then it should contain
224    producers or data items to be written to the channel.
227    .. method:: is_empty()
229       Returns ``True`` if and only if the fifo is empty.
232    .. method:: first()
234       Returns the least-recently :meth:`push`\ ed item from the fifo.
237    .. method:: push(data)
239       Adds the given data (which may be a string or a producer object) to the
240       producer fifo.
243    .. method:: pop()
245       If the fifo is not empty, returns ``True, first()``, deleting the popped
246       item.  Returns ``False, None`` for an empty fifo.
248 The :mod:`asynchat` module also defines one utility function, which may be of
249 use in network and textual analysis operations.
252 .. function:: find_prefix_at_end(haystack, needle)
254    Returns ``True`` if string *haystack* ends with any non-empty prefix of
255    string *needle*.
258 .. _asynchat-example:
260 asynchat Example
261 ----------------
263 The following partial example shows how HTTP requests can be read with
264 :class:`async_chat`.  A web server might create an
265 :class:`http_request_handler` object for each incoming client connection.
266 Notice that initially the channel terminator is set to match the blank line at
267 the end of the HTTP headers, and a flag indicates that the headers are being
268 read.
270 Once the headers have been read, if the request is of type POST (indicating
271 that further data are present in the input stream) then the
272 ``Content-Length:`` header is used to set a numeric terminator to read the
273 right amount of data from the channel.
275 The :meth:`handle_request` method is called once all relevant input has been
276 marshalled, after setting the channel terminator to ``None`` to ensure that
277 any extraneous data sent by the web client are ignored. ::
279    class http_request_handler(asynchat.async_chat):
281        def __init__(self, sock, addr, sessions, log):
282            asynchat.async_chat.__init__(self, sock=sock)
283            self.addr = addr
284            self.sessions = sessions
285            self.ibuffer = []
286            self.obuffer = ""
287            self.set_terminator("\r\n\r\n")
288            self.reading_headers = True
289            self.handling = False
290            self.cgi_data = None
291            self.log = log
293        def collect_incoming_data(self, data):
294            """Buffer the data"""
295            self.ibuffer.append(data)
297        def found_terminator(self):
298            if self.reading_headers:
299                self.reading_headers = False
300                self.parse_headers("".join(self.ibuffer))
301                self.ibuffer = []
302                if self.op.upper() == "POST":
303                    clen = self.headers.getheader("content-length")
304                    self.set_terminator(int(clen))
305                else:
306                    self.handling = True
307                    self.set_terminator(None)
308                    self.handle_request()
309            elif not self.handling:
310                self.set_terminator(None) # browsers sometimes over-send
311                self.cgi_data = parse(self.headers, "".join(self.ibuffer))
312                self.handling = True
313                self.ibuffer = []
314                self.handle_request()