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