blob: 7b8107434a70f48e4b7f28c0d285f0094dcb760a [file] [log] [blame]
Georg Brandl116aa622007-08-15 14:28:22 +00001:mod:`asynchat` --- Asynchronous socket command/response handler
2================================================================
3
4.. module:: asynchat
5 :synopsis: Support for asynchronous command/response protocols.
6.. moduleauthor:: Sam Rushing <rushing@nightmare.com>
Josiah Carlson35bf9bf2008-07-07 04:24:24 +00007.. sectionauthor:: Steve Holden <sholden@holdenweb.com>
Georg Brandl116aa622007-08-15 14:28:22 +00008
Raymond Hettingeread49752011-01-24 16:28:06 +00009**Source code:** :source:`Lib/asynchat.py`
10
11--------------
Georg Brandl116aa622007-08-15 14:28:22 +000012
Guido van Rossum4da459c2013-11-22 12:27:45 -080013.. note::
14
15 This module exists for backwards compatibility only. For new code we
16 recommend using :mod:`asyncio`.
Guido van Rossumaa407752013-11-22 11:57:35 -080017
Georg Brandl116aa622007-08-15 14:28:22 +000018This module builds on the :mod:`asyncore` infrastructure, simplifying
Georg Brandl9afde1c2007-11-01 20:32:30 +000019asynchronous clients and servers and making it easier to handle protocols
20whose elements are terminated by arbitrary strings, or are of variable length.
Georg Brandl116aa622007-08-15 14:28:22 +000021:mod:`asynchat` defines the abstract class :class:`async_chat` that you
22subclass, providing implementations of the :meth:`collect_incoming_data` and
23:meth:`found_terminator` methods. It uses the same asynchronous loop as
Georg Brandl9afde1c2007-11-01 20:32:30 +000024:mod:`asyncore`, and the two types of channel, :class:`asyncore.dispatcher`
25and :class:`asynchat.async_chat`, can freely be mixed in the channel map.
26Typically an :class:`asyncore.dispatcher` server channel generates new
27:class:`asynchat.async_chat` channel objects as it receives incoming
28connection requests.
Georg Brandl116aa622007-08-15 14:28:22 +000029
30
31.. class:: async_chat()
32
33 This class is an abstract subclass of :class:`asyncore.dispatcher`. To make
34 practical use of the code you must subclass :class:`async_chat`, providing
Georg Brandl9afde1c2007-11-01 20:32:30 +000035 meaningful :meth:`collect_incoming_data` and :meth:`found_terminator`
36 methods.
Georg Brandl116aa622007-08-15 14:28:22 +000037 The :class:`asyncore.dispatcher` methods can be used, although not all make
38 sense in a message/response context.
39
Georg Brandl9afde1c2007-11-01 20:32:30 +000040 Like :class:`asyncore.dispatcher`, :class:`async_chat` defines a set of
41 events that are generated by an analysis of socket conditions after a
Georg Brandl60203b42010-10-06 10:11:56 +000042 :c:func:`select` call. Once the polling loop has been started the
Georg Brandl9afde1c2007-11-01 20:32:30 +000043 :class:`async_chat` object's methods are called by the event-processing
44 framework with no action on the part of the programmer.
Georg Brandl116aa622007-08-15 14:28:22 +000045
Georg Brandl9afde1c2007-11-01 20:32:30 +000046 Two class attributes can be modified, to improve performance, or possibly
47 even to conserve memory.
48
49
50 .. data:: ac_in_buffer_size
51
52 The asynchronous input buffer size (default ``4096``).
53
54
55 .. data:: ac_out_buffer_size
56
57 The asynchronous output buffer size (default ``4096``).
58
59 Unlike :class:`asyncore.dispatcher`, :class:`async_chat` allows you to
60 define a first-in-first-out queue (fifo) of *producers*. A producer need
61 have only one method, :meth:`more`, which should return data to be
62 transmitted on the channel.
Georg Brandl116aa622007-08-15 14:28:22 +000063 The producer indicates exhaustion (*i.e.* that it contains no more data) by
64 having its :meth:`more` method return the empty string. At this point the
Georg Brandl9afde1c2007-11-01 20:32:30 +000065 :class:`async_chat` object removes the producer from the fifo and starts
66 using the next producer, if any. When the producer fifo is empty the
Georg Brandl116aa622007-08-15 14:28:22 +000067 :meth:`handle_write` method does nothing. You use the channel object's
Georg Brandl9afde1c2007-11-01 20:32:30 +000068 :meth:`set_terminator` method to describe how to recognize the end of, or
69 an important breakpoint in, an incoming transmission from the remote
70 endpoint.
Georg Brandl116aa622007-08-15 14:28:22 +000071
72 To build a functioning :class:`async_chat` subclass your input methods
Georg Brandl9afde1c2007-11-01 20:32:30 +000073 :meth:`collect_incoming_data` and :meth:`found_terminator` must handle the
74 data that the channel receives asynchronously. The methods are described
75 below.
Georg Brandl116aa622007-08-15 14:28:22 +000076
77
78.. method:: async_chat.close_when_done()
79
Georg Brandl9afde1c2007-11-01 20:32:30 +000080 Pushes a ``None`` on to the producer fifo. When this producer is popped off
81 the fifo it causes the channel to be closed.
Georg Brandl116aa622007-08-15 14:28:22 +000082
83
84.. method:: async_chat.collect_incoming_data(data)
85
Georg Brandl9afde1c2007-11-01 20:32:30 +000086 Called with *data* holding an arbitrary amount of received data. The
87 default method, which must be overridden, raises a
88 :exc:`NotImplementedError` exception.
Georg Brandl116aa622007-08-15 14:28:22 +000089
90
91.. method:: async_chat.discard_buffers()
92
Georg Brandl9afde1c2007-11-01 20:32:30 +000093 In emergencies this method will discard any data held in the input and/or
94 output buffers and the producer fifo.
Georg Brandl116aa622007-08-15 14:28:22 +000095
96
97.. method:: async_chat.found_terminator()
98
Georg Brandl9afde1c2007-11-01 20:32:30 +000099 Called when the incoming data stream matches the termination condition set
100 by :meth:`set_terminator`. The default method, which must be overridden,
101 raises a :exc:`NotImplementedError` exception. The buffered input data
102 should be available via an instance attribute.
Georg Brandl116aa622007-08-15 14:28:22 +0000103
104
105.. method:: async_chat.get_terminator()
106
107 Returns the current terminator for the channel.
108
109
Georg Brandl116aa622007-08-15 14:28:22 +0000110.. method:: async_chat.push(data)
111
Giampaolo Rodolà81302902010-04-29 20:45:01 +0000112 Pushes data on to the channel's fifo to ensure its transmission.
113 This is all you need to do to have the channel write the data out to the
114 network, although it is possible to use your own producers in more complex
115 schemes to implement encryption and chunking, for example.
Georg Brandl116aa622007-08-15 14:28:22 +0000116
117
118.. method:: async_chat.push_with_producer(producer)
119
Georg Brandl9afde1c2007-11-01 20:32:30 +0000120 Takes a producer object and adds it to the producer fifo associated with
121 the channel. When all currently-pushed producers have been exhausted the
122 channel will consume this producer's data by calling its :meth:`more`
123 method and send the data to the remote endpoint.
Georg Brandl116aa622007-08-15 14:28:22 +0000124
125
Georg Brandl116aa622007-08-15 14:28:22 +0000126.. method:: async_chat.set_terminator(term)
127
Georg Brandl9afde1c2007-11-01 20:32:30 +0000128 Sets the terminating condition to be recognized on the channel. ``term``
129 may be any of three types of value, corresponding to three different ways
130 to handle incoming protocol data.
Georg Brandl116aa622007-08-15 14:28:22 +0000131
132 +-----------+---------------------------------------------+
133 | term | Description |
134 +===========+=============================================+
135 | *string* | Will call :meth:`found_terminator` when the |
136 | | string is found in the input stream |
137 +-----------+---------------------------------------------+
138 | *integer* | Will call :meth:`found_terminator` when the |
139 | | indicated number of characters have been |
140 | | received |
141 +-----------+---------------------------------------------+
142 | ``None`` | The channel continues to collect data |
143 | | forever |
144 +-----------+---------------------------------------------+
145
Georg Brandl9afde1c2007-11-01 20:32:30 +0000146 Note that any data following the terminator will be available for reading
147 by the channel after :meth:`found_terminator` is called.
Georg Brandl116aa622007-08-15 14:28:22 +0000148
149
Giampaolo Rodolà81302902010-04-29 20:45:01 +0000150asynchat - Auxiliary Classes
Georg Brandl116aa622007-08-15 14:28:22 +0000151------------------------------------------
152
Georg Brandlb868a662009-04-02 02:56:10 +0000153.. class:: fifo(list=None)
Georg Brandl116aa622007-08-15 14:28:22 +0000154
Giampaolo Rodolà81302902010-04-29 20:45:01 +0000155 A :class:`fifo` holding data which has been pushed by the application but
156 not yet popped for writing to the channel. A :class:`fifo` is a list used
157 to hold data and/or producers until they are required. If the *list*
158 argument is provided then it should contain producers or data items to be
159 written to the channel.
Georg Brandl116aa622007-08-15 14:28:22 +0000160
161
Benjamin Petersone41251e2008-04-25 01:59:09 +0000162 .. method:: is_empty()
Georg Brandl116aa622007-08-15 14:28:22 +0000163
Benjamin Petersone41251e2008-04-25 01:59:09 +0000164 Returns ``True`` if and only if the fifo is empty.
Georg Brandl116aa622007-08-15 14:28:22 +0000165
166
Benjamin Petersone41251e2008-04-25 01:59:09 +0000167 .. method:: first()
Georg Brandl116aa622007-08-15 14:28:22 +0000168
Benjamin Petersone41251e2008-04-25 01:59:09 +0000169 Returns the least-recently :meth:`push`\ ed item from the fifo.
Georg Brandl116aa622007-08-15 14:28:22 +0000170
171
Benjamin Petersone41251e2008-04-25 01:59:09 +0000172 .. method:: push(data)
Georg Brandl116aa622007-08-15 14:28:22 +0000173
Benjamin Petersone41251e2008-04-25 01:59:09 +0000174 Adds the given data (which may be a string or a producer object) to the
175 producer fifo.
Georg Brandl116aa622007-08-15 14:28:22 +0000176
177
Benjamin Petersone41251e2008-04-25 01:59:09 +0000178 .. method:: pop()
Georg Brandl116aa622007-08-15 14:28:22 +0000179
Benjamin Petersone41251e2008-04-25 01:59:09 +0000180 If the fifo is not empty, returns ``True, first()``, deleting the popped
181 item. Returns ``False, None`` for an empty fifo.
Georg Brandl116aa622007-08-15 14:28:22 +0000182
Georg Brandl116aa622007-08-15 14:28:22 +0000183
184.. _asynchat-example:
185
186asynchat Example
187----------------
188
189The following partial example shows how HTTP requests can be read with
Georg Brandl9afde1c2007-11-01 20:32:30 +0000190:class:`async_chat`. A web server might create an
191:class:`http_request_handler` object for each incoming client connection.
192Notice that initially the channel terminator is set to match the blank line at
193the end of the HTTP headers, and a flag indicates that the headers are being
194read.
Georg Brandl116aa622007-08-15 14:28:22 +0000195
Georg Brandl9afde1c2007-11-01 20:32:30 +0000196Once the headers have been read, if the request is of type POST (indicating
197that further data are present in the input stream) then the
198``Content-Length:`` header is used to set a numeric terminator to read the
199right amount of data from the channel.
Georg Brandl116aa622007-08-15 14:28:22 +0000200
201The :meth:`handle_request` method is called once all relevant input has been
Georg Brandl9afde1c2007-11-01 20:32:30 +0000202marshalled, after setting the channel terminator to ``None`` to ensure that
203any extraneous data sent by the web client are ignored. ::
Georg Brandl116aa622007-08-15 14:28:22 +0000204
Giampaolo Rodola'0fb41b52012-05-15 15:46:00 +0200205
206 import asynchat
207
Georg Brandl116aa622007-08-15 14:28:22 +0000208 class http_request_handler(asynchat.async_chat):
209
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000210 def __init__(self, sock, addr, sessions, log):
211 asynchat.async_chat.__init__(self, sock=sock)
Georg Brandl116aa622007-08-15 14:28:22 +0000212 self.addr = addr
213 self.sessions = sessions
214 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000215 self.obuffer = b""
216 self.set_terminator(b"\r\n\r\n")
Georg Brandl116aa622007-08-15 14:28:22 +0000217 self.reading_headers = True
218 self.handling = False
219 self.cgi_data = None
220 self.log = log
221
222 def collect_incoming_data(self, data):
223 """Buffer the data"""
224 self.ibuffer.append(data)
225
226 def found_terminator(self):
227 if self.reading_headers:
228 self.reading_headers = False
229 self.parse_headers("".join(self.ibuffer))
230 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000231 if self.op.upper() == b"POST":
Georg Brandl116aa622007-08-15 14:28:22 +0000232 clen = self.headers.getheader("content-length")
233 self.set_terminator(int(clen))
234 else:
235 self.handling = True
236 self.set_terminator(None)
237 self.handle_request()
238 elif not self.handling:
239 self.set_terminator(None) # browsers sometimes over-send
Josiah Carlson1893ce72008-07-07 04:23:14 +0000240 self.cgi_data = parse(self.headers, b"".join(self.ibuffer))
Georg Brandl116aa622007-08-15 14:28:22 +0000241 self.handling = True
242 self.ibuffer = []
243 self.handle_request()