UserString.MutableString has been removed in Python 3.0.
[python.git] / Doc / library / asynchat.rst
blob6f154417f5962dbb08f858a64e49b1a21e7a6e56
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.discard_buffers()
86    In emergencies this method will discard any data held in the input and/or
87    output buffers and the producer fifo.
90 .. method:: async_chat.found_terminator()
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.
98 .. method:: async_chat.get_terminator()
100    Returns the current terminator for the channel.
103 .. method:: async_chat.handle_close()
105    Called when the channel is closed. The default method silently closes the
106    channel's socket.
109 .. method:: async_chat.handle_read()
111    Called when a read event fires on the channel's socket in the asynchronous
112    loop.  The default method checks for the termination condition established
113    by :meth:`set_terminator`, which can be either the appearance of a
114    particular string in the input stream or the receipt of a particular number
115    of characters.  When the terminator is found, :meth:`handle_read` calls the
116    :meth:`found_terminator` method after calling :meth:`collect_incoming_data`
117    with any data preceding the terminating condition.
120 .. method:: async_chat.handle_write()
122    Called when the application may write data to the channel.   The default
123    method calls the :meth:`initiate_send` method, which in turn will call
124    :meth:`refill_buffer` to collect data from the producer fifo associated
125    with the channel.
128 .. method:: async_chat.push(data)
130    Creates a :class:`simple_producer` object (*see below*) containing the data
131    and pushes it on to the channel's ``producer_fifo`` to ensure its
132    transmission.  This is all you need to do to have the channel write the
133    data out to the network, although it is possible to use your own producers
134    in more complex schemes to implement encryption and chunking, for example.
137 .. method:: async_chat.push_with_producer(producer)
139    Takes a producer object and adds it to the producer fifo associated with
140    the channel.  When all currently-pushed producers have been exhausted the
141    channel will consume this producer's data by calling its :meth:`more`
142    method and send the data to the remote endpoint.
145 .. method:: async_chat.readable()
147    Should return ``True`` for the channel to be included in the set of
148    channels tested by the :cfunc:`select` loop for readability.
151 .. method:: async_chat.refill_buffer()
153    Refills the output buffer by calling the :meth:`more` method of the
154    producer at the head of the fifo.  If it is exhausted then the producer is
155    popped off the fifo and the next producer is activated.  If the current
156    producer is, or becomes, ``None`` then the channel is closed.
159 .. method:: async_chat.set_terminator(term)
161    Sets the terminating condition to be recognized on the channel.  ``term``
162    may be any of three types of value, corresponding to three different ways
163    to handle incoming protocol data.
165    +-----------+---------------------------------------------+
166    | term      | Description                                 |
167    +===========+=============================================+
168    | *string*  | Will call :meth:`found_terminator` when the |
169    |           | string is found in the input stream         |
170    +-----------+---------------------------------------------+
171    | *integer* | Will call :meth:`found_terminator` when the |
172    |           | indicated number of characters have been    |
173    |           | received                                    |
174    +-----------+---------------------------------------------+
175    | ``None``  | The channel continues to collect data       |
176    |           | forever                                     |
177    +-----------+---------------------------------------------+
179    Note that any data following the terminator will be available for reading
180    by the channel after :meth:`found_terminator` is called.
183 .. method:: async_chat.writable()
185    Should return ``True`` as long as items remain on the producer fifo, or the
186    channel is connected and the channel's output buffer is non-empty.
189 asynchat - Auxiliary Classes and Functions
190 ------------------------------------------
193 .. class:: simple_producer(data[, buffer_size=512])
195    A :class:`simple_producer` takes a chunk of data and an optional buffer
196    size.  Repeated calls to its :meth:`more` method yield successive chunks of
197    the data no larger than *buffer_size*.
200    .. method:: more()
202       Produces the next chunk of information from the producer, or returns the
203       empty string.
206 .. class:: fifo([list=None])
208    Each channel maintains a :class:`fifo` holding data which has been pushed
209    by the application but not yet popped for writing to the channel.  A
210    :class:`fifo` is a list used to hold data and/or producers until they are
211    required.  If the *list* argument is provided then it should contain
212    producers or data items to be written to the channel.
215    .. method:: is_empty()
217       Returns ``True`` if and only if the fifo is empty.
220    .. method:: first()
222       Returns the least-recently :meth:`push`\ ed item from the fifo.
225    .. method:: push(data)
227       Adds the given data (which may be a string or a producer object) to the
228       producer fifo.
231    .. method:: pop()
233       If the fifo is not empty, returns ``True, first()``, deleting the popped
234       item.  Returns ``False, None`` for an empty fifo.
236 The :mod:`asynchat` module also defines one utility function, which may be of
237 use in network and textual analysis operations.
240 .. function:: find_prefix_at_end(haystack, needle)
242    Returns ``True`` if string *haystack* ends with any non-empty prefix of
243    string *needle*.
246 .. _asynchat-example:
248 asynchat Example
249 ----------------
251 The following partial example shows how HTTP requests can be read with
252 :class:`async_chat`.  A web server might create an
253 :class:`http_request_handler` object for each incoming client connection.
254 Notice that initially the channel terminator is set to match the blank line at
255 the end of the HTTP headers, and a flag indicates that the headers are being
256 read.
258 Once the headers have been read, if the request is of type POST (indicating
259 that further data are present in the input stream) then the
260 ``Content-Length:`` header is used to set a numeric terminator to read the
261 right amount of data from the channel.
263 The :meth:`handle_request` method is called once all relevant input has been
264 marshalled, after setting the channel terminator to ``None`` to ensure that
265 any extraneous data sent by the web client are ignored. ::
267    class http_request_handler(asynchat.async_chat):
269        def __init__(self, conn, addr, sessions, log):
270            asynchat.async_chat.__init__(self, conn=conn)
271            self.addr = addr
272            self.sessions = sessions
273            self.ibuffer = []
274            self.obuffer = ""
275            self.set_terminator("\r\n\r\n")
276            self.reading_headers = True
277            self.handling = False
278            self.cgi_data = None
279            self.log = log
281        def collect_incoming_data(self, data):
282            """Buffer the data"""
283            self.ibuffer.append(data)
285        def found_terminator(self):
286            if self.reading_headers:
287                self.reading_headers = False
288                self.parse_headers("".join(self.ibuffer))
289                self.ibuffer = []
290                if self.op.upper() == "POST":
291                    clen = self.headers.getheader("content-length")
292                    self.set_terminator(int(clen))
293                else:
294                    self.handling = True
295                    self.set_terminator(None)
296                    self.handle_request()
297            elif not self.handling:
298                self.set_terminator(None) # browsers sometimes over-send
299                self.cgi_data = parse(self.headers, "".join(self.ibuffer))
300                self.handling = True
301                self.ibuffer = []
302                self.handle_request()