blob: 55c61d7e68f35b27e6c2e62083e80615e8d4180e [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
13This module builds on the :mod:`asyncore` infrastructure, simplifying
Georg Brandl9afde1c2007-11-01 20:32:30 +000014asynchronous clients and servers and making it easier to handle protocols
15whose elements are terminated by arbitrary strings, or are of variable length.
Georg Brandl116aa622007-08-15 14:28:22 +000016:mod:`asynchat` defines the abstract class :class:`async_chat` that you
17subclass, providing implementations of the :meth:`collect_incoming_data` and
18:meth:`found_terminator` methods. It uses the same asynchronous loop as
Georg Brandl9afde1c2007-11-01 20:32:30 +000019:mod:`asyncore`, and the two types of channel, :class:`asyncore.dispatcher`
20and :class:`asynchat.async_chat`, can freely be mixed in the channel map.
21Typically an :class:`asyncore.dispatcher` server channel generates new
22:class:`asynchat.async_chat` channel objects as it receives incoming
23connection requests.
Georg Brandl116aa622007-08-15 14:28:22 +000024
25
26.. class:: async_chat()
27
28 This class is an abstract subclass of :class:`asyncore.dispatcher`. To make
29 practical use of the code you must subclass :class:`async_chat`, providing
Georg Brandl9afde1c2007-11-01 20:32:30 +000030 meaningful :meth:`collect_incoming_data` and :meth:`found_terminator`
31 methods.
Georg Brandl116aa622007-08-15 14:28:22 +000032 The :class:`asyncore.dispatcher` methods can be used, although not all make
33 sense in a message/response context.
34
Georg Brandl9afde1c2007-11-01 20:32:30 +000035 Like :class:`asyncore.dispatcher`, :class:`async_chat` defines a set of
36 events that are generated by an analysis of socket conditions after a
Georg Brandl60203b42010-10-06 10:11:56 +000037 :c:func:`select` call. Once the polling loop has been started the
Georg Brandl9afde1c2007-11-01 20:32:30 +000038 :class:`async_chat` object's methods are called by the event-processing
39 framework with no action on the part of the programmer.
Georg Brandl116aa622007-08-15 14:28:22 +000040
Georg Brandl9afde1c2007-11-01 20:32:30 +000041 Two class attributes can be modified, to improve performance, or possibly
42 even to conserve memory.
43
44
45 .. data:: ac_in_buffer_size
46
47 The asynchronous input buffer size (default ``4096``).
48
49
50 .. data:: ac_out_buffer_size
51
52 The asynchronous output buffer size (default ``4096``).
53
54 Unlike :class:`asyncore.dispatcher`, :class:`async_chat` allows you to
55 define a first-in-first-out queue (fifo) of *producers*. A producer need
56 have only one method, :meth:`more`, which should return data to be
57 transmitted on the channel.
Georg Brandl116aa622007-08-15 14:28:22 +000058 The producer indicates exhaustion (*i.e.* that it contains no more data) by
59 having its :meth:`more` method return the empty string. At this point the
Georg Brandl9afde1c2007-11-01 20:32:30 +000060 :class:`async_chat` object removes the producer from the fifo and starts
61 using the next producer, if any. When the producer fifo is empty the
Georg Brandl116aa622007-08-15 14:28:22 +000062 :meth:`handle_write` method does nothing. You use the channel object's
Georg Brandl9afde1c2007-11-01 20:32:30 +000063 :meth:`set_terminator` method to describe how to recognize the end of, or
64 an important breakpoint in, an incoming transmission from the remote
65 endpoint.
Georg Brandl116aa622007-08-15 14:28:22 +000066
67 To build a functioning :class:`async_chat` subclass your input methods
Georg Brandl9afde1c2007-11-01 20:32:30 +000068 :meth:`collect_incoming_data` and :meth:`found_terminator` must handle the
69 data that the channel receives asynchronously. The methods are described
70 below.
Georg Brandl116aa622007-08-15 14:28:22 +000071
72
73.. method:: async_chat.close_when_done()
74
Georg Brandl9afde1c2007-11-01 20:32:30 +000075 Pushes a ``None`` on to the producer fifo. When this producer is popped off
76 the fifo it causes the channel to be closed.
Georg Brandl116aa622007-08-15 14:28:22 +000077
78
79.. method:: async_chat.collect_incoming_data(data)
80
Georg Brandl9afde1c2007-11-01 20:32:30 +000081 Called with *data* holding an arbitrary amount of received data. The
82 default method, which must be overridden, raises a
83 :exc:`NotImplementedError` exception.
Georg Brandl116aa622007-08-15 14:28:22 +000084
85
86.. method:: async_chat.discard_buffers()
87
Georg Brandl9afde1c2007-11-01 20:32:30 +000088 In emergencies this method will discard any data held in the input and/or
89 output buffers and the producer fifo.
Georg Brandl116aa622007-08-15 14:28:22 +000090
91
92.. method:: async_chat.found_terminator()
93
Georg Brandl9afde1c2007-11-01 20:32:30 +000094 Called when the incoming data stream matches the termination condition set
95 by :meth:`set_terminator`. The default method, which must be overridden,
96 raises a :exc:`NotImplementedError` exception. The buffered input data
97 should be available via an instance attribute.
Georg Brandl116aa622007-08-15 14:28:22 +000098
99
100.. method:: async_chat.get_terminator()
101
102 Returns the current terminator for the channel.
103
104
Georg Brandl116aa622007-08-15 14:28:22 +0000105.. method:: async_chat.push(data)
106
Giampaolo Rodolà81302902010-04-29 20:45:01 +0000107 Pushes data on to the channel's fifo to ensure its transmission.
108 This is all you need to do to have the channel write the data out to the
109 network, although it is possible to use your own producers in more complex
110 schemes to implement encryption and chunking, for example.
Georg Brandl116aa622007-08-15 14:28:22 +0000111
112
113.. method:: async_chat.push_with_producer(producer)
114
Georg Brandl9afde1c2007-11-01 20:32:30 +0000115 Takes a producer object and adds it to the producer fifo associated with
116 the channel. When all currently-pushed producers have been exhausted the
117 channel will consume this producer's data by calling its :meth:`more`
118 method and send the data to the remote endpoint.
Georg Brandl116aa622007-08-15 14:28:22 +0000119
120
Georg Brandl116aa622007-08-15 14:28:22 +0000121.. method:: async_chat.set_terminator(term)
122
Georg Brandl9afde1c2007-11-01 20:32:30 +0000123 Sets the terminating condition to be recognized on the channel. ``term``
124 may be any of three types of value, corresponding to three different ways
125 to handle incoming protocol data.
Georg Brandl116aa622007-08-15 14:28:22 +0000126
127 +-----------+---------------------------------------------+
128 | term | Description |
129 +===========+=============================================+
130 | *string* | Will call :meth:`found_terminator` when the |
131 | | string is found in the input stream |
132 +-----------+---------------------------------------------+
133 | *integer* | Will call :meth:`found_terminator` when the |
134 | | indicated number of characters have been |
135 | | received |
136 +-----------+---------------------------------------------+
137 | ``None`` | The channel continues to collect data |
138 | | forever |
139 +-----------+---------------------------------------------+
140
Georg Brandl9afde1c2007-11-01 20:32:30 +0000141 Note that any data following the terminator will be available for reading
142 by the channel after :meth:`found_terminator` is called.
Georg Brandl116aa622007-08-15 14:28:22 +0000143
144
Giampaolo Rodolà81302902010-04-29 20:45:01 +0000145asynchat - Auxiliary Classes
Georg Brandl116aa622007-08-15 14:28:22 +0000146------------------------------------------
147
Georg Brandlb868a662009-04-02 02:56:10 +0000148.. class:: fifo(list=None)
Georg Brandl116aa622007-08-15 14:28:22 +0000149
Giampaolo Rodolà81302902010-04-29 20:45:01 +0000150 A :class:`fifo` holding data which has been pushed by the application but
151 not yet popped for writing to the channel. A :class:`fifo` is a list used
152 to hold data and/or producers until they are required. If the *list*
153 argument is provided then it should contain producers or data items to be
154 written to the channel.
Georg Brandl116aa622007-08-15 14:28:22 +0000155
156
Benjamin Petersone41251e2008-04-25 01:59:09 +0000157 .. method:: is_empty()
Georg Brandl116aa622007-08-15 14:28:22 +0000158
Benjamin Petersone41251e2008-04-25 01:59:09 +0000159 Returns ``True`` if and only if the fifo is empty.
Georg Brandl116aa622007-08-15 14:28:22 +0000160
161
Benjamin Petersone41251e2008-04-25 01:59:09 +0000162 .. method:: first()
Georg Brandl116aa622007-08-15 14:28:22 +0000163
Benjamin Petersone41251e2008-04-25 01:59:09 +0000164 Returns the least-recently :meth:`push`\ ed item from the fifo.
Georg Brandl116aa622007-08-15 14:28:22 +0000165
166
Benjamin Petersone41251e2008-04-25 01:59:09 +0000167 .. method:: push(data)
Georg Brandl116aa622007-08-15 14:28:22 +0000168
Benjamin Petersone41251e2008-04-25 01:59:09 +0000169 Adds the given data (which may be a string or a producer object) to the
170 producer fifo.
Georg Brandl116aa622007-08-15 14:28:22 +0000171
172
Benjamin Petersone41251e2008-04-25 01:59:09 +0000173 .. method:: pop()
Georg Brandl116aa622007-08-15 14:28:22 +0000174
Benjamin Petersone41251e2008-04-25 01:59:09 +0000175 If the fifo is not empty, returns ``True, first()``, deleting the popped
176 item. Returns ``False, None`` for an empty fifo.
Georg Brandl116aa622007-08-15 14:28:22 +0000177
Georg Brandl116aa622007-08-15 14:28:22 +0000178
179.. _asynchat-example:
180
181asynchat Example
182----------------
183
184The following partial example shows how HTTP requests can be read with
Georg Brandl9afde1c2007-11-01 20:32:30 +0000185:class:`async_chat`. A web server might create an
186:class:`http_request_handler` object for each incoming client connection.
187Notice that initially the channel terminator is set to match the blank line at
188the end of the HTTP headers, and a flag indicates that the headers are being
189read.
Georg Brandl116aa622007-08-15 14:28:22 +0000190
Georg Brandl9afde1c2007-11-01 20:32:30 +0000191Once the headers have been read, if the request is of type POST (indicating
192that further data are present in the input stream) then the
193``Content-Length:`` header is used to set a numeric terminator to read the
194right amount of data from the channel.
Georg Brandl116aa622007-08-15 14:28:22 +0000195
196The :meth:`handle_request` method is called once all relevant input has been
Georg Brandl9afde1c2007-11-01 20:32:30 +0000197marshalled, after setting the channel terminator to ``None`` to ensure that
198any extraneous data sent by the web client are ignored. ::
Georg Brandl116aa622007-08-15 14:28:22 +0000199
Giampaolo Rodola'0fb41b52012-05-15 15:46:00 +0200200
201 import asynchat
202
Georg Brandl116aa622007-08-15 14:28:22 +0000203 class http_request_handler(asynchat.async_chat):
204
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000205 def __init__(self, sock, addr, sessions, log):
206 asynchat.async_chat.__init__(self, sock=sock)
Georg Brandl116aa622007-08-15 14:28:22 +0000207 self.addr = addr
208 self.sessions = sessions
209 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000210 self.obuffer = b""
211 self.set_terminator(b"\r\n\r\n")
Georg Brandl116aa622007-08-15 14:28:22 +0000212 self.reading_headers = True
213 self.handling = False
214 self.cgi_data = None
215 self.log = log
216
217 def collect_incoming_data(self, data):
218 """Buffer the data"""
219 self.ibuffer.append(data)
220
221 def found_terminator(self):
222 if self.reading_headers:
223 self.reading_headers = False
224 self.parse_headers("".join(self.ibuffer))
225 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000226 if self.op.upper() == b"POST":
Georg Brandl116aa622007-08-15 14:28:22 +0000227 clen = self.headers.getheader("content-length")
228 self.set_terminator(int(clen))
229 else:
230 self.handling = True
231 self.set_terminator(None)
232 self.handle_request()
233 elif not self.handling:
234 self.set_terminator(None) # browsers sometimes over-send
Josiah Carlson1893ce72008-07-07 04:23:14 +0000235 self.cgi_data = parse(self.headers, b"".join(self.ibuffer))
Georg Brandl116aa622007-08-15 14:28:22 +0000236 self.handling = True
237 self.ibuffer = []
238 self.handle_request()