blob: e02360c883cc86c9831c02dc661b3999cffb981b [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.
Terry Jan Reedyfa089b92016-06-11 15:02:54 -04006
Georg Brandl116aa622007-08-15 14:28:22 +00007.. moduleauthor:: Sam Rushing <rushing@nightmare.com>
Josiah Carlson35bf9bf2008-07-07 04:24:24 +00008.. sectionauthor:: Steve Holden <sholden@holdenweb.com>
Georg Brandl116aa622007-08-15 14:28:22 +00009
Raymond Hettingeread49752011-01-24 16:28:06 +000010**Source code:** :source:`Lib/asynchat.py`
11
12--------------
Georg Brandl116aa622007-08-15 14:28:22 +000013
Guido van Rossum4da459c2013-11-22 12:27:45 -080014.. note::
15
16 This module exists for backwards compatibility only. For new code we
17 recommend using :mod:`asyncio`.
Guido van Rossumaa407752013-11-22 11:57:35 -080018
Georg Brandl116aa622007-08-15 14:28:22 +000019This module builds on the :mod:`asyncore` infrastructure, simplifying
Georg Brandl9afde1c2007-11-01 20:32:30 +000020asynchronous clients and servers and making it easier to handle protocols
21whose elements are terminated by arbitrary strings, or are of variable length.
Georg Brandl116aa622007-08-15 14:28:22 +000022:mod:`asynchat` defines the abstract class :class:`async_chat` that you
23subclass, providing implementations of the :meth:`collect_incoming_data` and
24:meth:`found_terminator` methods. It uses the same asynchronous loop as
Georg Brandl9afde1c2007-11-01 20:32:30 +000025:mod:`asyncore`, and the two types of channel, :class:`asyncore.dispatcher`
26and :class:`asynchat.async_chat`, can freely be mixed in the channel map.
27Typically an :class:`asyncore.dispatcher` server channel generates new
28:class:`asynchat.async_chat` channel objects as it receives incoming
29connection requests.
Georg Brandl116aa622007-08-15 14:28:22 +000030
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 Brandl9afde1c2007-11-01 20:32:30 +000036 meaningful :meth:`collect_incoming_data` and :meth:`found_terminator`
37 methods.
Georg Brandl116aa622007-08-15 14:28:22 +000038 The :class:`asyncore.dispatcher` methods can be used, although not all make
39 sense in a message/response context.
40
Georg Brandl9afde1c2007-11-01 20:32:30 +000041 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 Brandl60203b42010-10-06 10:11:56 +000043 :c:func:`select` call. Once the polling loop has been started the
Georg Brandl9afde1c2007-11-01 20:32:30 +000044 :class:`async_chat` object's methods are called by the event-processing
45 framework with no action on the part of the programmer.
Georg Brandl116aa622007-08-15 14:28:22 +000046
Georg Brandl9afde1c2007-11-01 20:32:30 +000047 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 Storchaka98019e12016-05-16 09:10:43 +030061 define a :abbr:`FIFO (first-in, first-out)` queue of *producers*. A producer need
Georg Brandl9afde1c2007-11-01 20:32:30 +000062 have only one method, :meth:`more`, which should return data to be
63 transmitted on the channel.
Georg Brandl116aa622007-08-15 14:28:22 +000064 The producer indicates exhaustion (*i.e.* that it contains no more data) by
Serhiy Storchaka5e028ae2014-02-06 21:10:41 +020065 having its :meth:`more` method return the empty bytes object. At this point
Serhiy Storchaka98019e12016-05-16 09:10:43 +030066 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 Brandl116aa622007-08-15 14:28:22 +000068 :meth:`handle_write` method does nothing. You use the channel object's
Georg Brandl9afde1c2007-11-01 20:32:30 +000069 :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 Brandl116aa622007-08-15 14:28:22 +000072
73 To build a functioning :class:`async_chat` subclass your input methods
Georg Brandl9afde1c2007-11-01 20:32:30 +000074 :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 Brandl116aa622007-08-15 14:28:22 +000077
78
79.. method:: async_chat.close_when_done()
80
Serhiy Storchaka98019e12016-05-16 09:10:43 +030081 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 Brandl116aa622007-08-15 14:28:22 +000083
84
85.. method:: async_chat.collect_incoming_data(data)
86
Georg Brandl9afde1c2007-11-01 20:32:30 +000087 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 Brandl116aa622007-08-15 14:28:22 +000090
91
92.. method:: async_chat.discard_buffers()
93
Georg Brandl9afde1c2007-11-01 20:32:30 +000094 In emergencies this method will discard any data held in the input and/or
Serhiy Storchaka98019e12016-05-16 09:10:43 +030095 output buffers and the producer queue.
Georg Brandl116aa622007-08-15 14:28:22 +000096
97
98.. method:: async_chat.found_terminator()
99
Georg Brandl9afde1c2007-11-01 20:32:30 +0000100 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 Brandl116aa622007-08-15 14:28:22 +0000104
105
106.. method:: async_chat.get_terminator()
107
108 Returns the current terminator for the channel.
109
110
Georg Brandl116aa622007-08-15 14:28:22 +0000111.. method:: async_chat.push(data)
112
Serhiy Storchaka98019e12016-05-16 09:10:43 +0300113 Pushes data on to the channel's queue to ensure its transmission.
Giampaolo RodolĂ 81302902010-04-29 20:45:01 +0000114 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 Brandl116aa622007-08-15 14:28:22 +0000117
118
119.. method:: async_chat.push_with_producer(producer)
120
Serhiy Storchaka98019e12016-05-16 09:10:43 +0300121 Takes a producer object and adds it to the producer queue associated with
Georg Brandl9afde1c2007-11-01 20:32:30 +0000122 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 Brandl116aa622007-08-15 14:28:22 +0000125
126
Georg Brandl116aa622007-08-15 14:28:22 +0000127.. method:: async_chat.set_terminator(term)
128
Georg Brandl9afde1c2007-11-01 20:32:30 +0000129 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 Brandl116aa622007-08-15 14:28:22 +0000132
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 Brandl9afde1c2007-11-01 20:32:30 +0000147 Note that any data following the terminator will be available for reading
148 by the channel after :meth:`found_terminator` is called.
Georg Brandl116aa622007-08-15 14:28:22 +0000149
150
Georg Brandl116aa622007-08-15 14:28:22 +0000151.. _asynchat-example:
152
153asynchat Example
154----------------
155
156The following partial example shows how HTTP requests can be read with
Georg Brandl9afde1c2007-11-01 20:32:30 +0000157:class:`async_chat`. A web server might create an
158:class:`http_request_handler` object for each incoming client connection.
159Notice that initially the channel terminator is set to match the blank line at
160the end of the HTTP headers, and a flag indicates that the headers are being
161read.
Georg Brandl116aa622007-08-15 14:28:22 +0000162
Georg Brandl9afde1c2007-11-01 20:32:30 +0000163Once the headers have been read, if the request is of type POST (indicating
164that further data are present in the input stream) then the
165``Content-Length:`` header is used to set a numeric terminator to read the
166right amount of data from the channel.
Georg Brandl116aa622007-08-15 14:28:22 +0000167
168The :meth:`handle_request` method is called once all relevant input has been
Georg Brandl9afde1c2007-11-01 20:32:30 +0000169marshalled, after setting the channel terminator to ``None`` to ensure that
170any extraneous data sent by the web client are ignored. ::
Georg Brandl116aa622007-08-15 14:28:22 +0000171
Giampaolo Rodola'0fb41b52012-05-15 15:46:00 +0200172
173 import asynchat
174
Georg Brandl116aa622007-08-15 14:28:22 +0000175 class http_request_handler(asynchat.async_chat):
176
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000177 def __init__(self, sock, addr, sessions, log):
178 asynchat.async_chat.__init__(self, sock=sock)
Georg Brandl116aa622007-08-15 14:28:22 +0000179 self.addr = addr
180 self.sessions = sessions
181 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000182 self.obuffer = b""
183 self.set_terminator(b"\r\n\r\n")
Georg Brandl116aa622007-08-15 14:28:22 +0000184 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 Storchaka5e028ae2014-02-06 21:10:41 +0200196 self.parse_headers(b"".join(self.ibuffer))
Georg Brandl116aa622007-08-15 14:28:22 +0000197 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000198 if self.op.upper() == b"POST":
Georg Brandl116aa622007-08-15 14:28:22 +0000199 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 Storchakadba90392016-05-10 12:01:23 +0300206 self.set_terminator(None) # browsers sometimes over-send
Josiah Carlson1893ce72008-07-07 04:23:14 +0000207 self.cgi_data = parse(self.headers, b"".join(self.ibuffer))
Georg Brandl116aa622007-08-15 14:28:22 +0000208 self.handling = True
209 self.ibuffer = []
210 self.handle_request()