blob: 9e51416b83a570b45964431e85ef8b07070b27f5 [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
Guido van Rossum16591f42016-10-25 08:49:13 -070012.. deprecated:: 3.6
13 Please use :mod:`asyncio` instead.
14
Raymond Hettingeread49752011-01-24 16:28:06 +000015--------------
Georg Brandl116aa622007-08-15 14:28:22 +000016
Guido van Rossum4da459c2013-11-22 12:27:45 -080017.. note::
18
19 This module exists for backwards compatibility only. For new code we
20 recommend using :mod:`asyncio`.
Guido van Rossumaa407752013-11-22 11:57:35 -080021
Georg Brandl116aa622007-08-15 14:28:22 +000022This module builds on the :mod:`asyncore` infrastructure, simplifying
Georg Brandl9afde1c2007-11-01 20:32:30 +000023asynchronous clients and servers and making it easier to handle protocols
24whose elements are terminated by arbitrary strings, or are of variable length.
Georg Brandl116aa622007-08-15 14:28:22 +000025:mod:`asynchat` defines the abstract class :class:`async_chat` that you
26subclass, providing implementations of the :meth:`collect_incoming_data` and
27:meth:`found_terminator` methods. It uses the same asynchronous loop as
Georg Brandl9afde1c2007-11-01 20:32:30 +000028:mod:`asyncore`, and the two types of channel, :class:`asyncore.dispatcher`
29and :class:`asynchat.async_chat`, can freely be mixed in the channel map.
30Typically an :class:`asyncore.dispatcher` server channel generates new
31:class:`asynchat.async_chat` channel objects as it receives incoming
32connection requests.
Georg Brandl116aa622007-08-15 14:28:22 +000033
34
35.. class:: async_chat()
36
37 This class is an abstract subclass of :class:`asyncore.dispatcher`. To make
38 practical use of the code you must subclass :class:`async_chat`, providing
Georg Brandl9afde1c2007-11-01 20:32:30 +000039 meaningful :meth:`collect_incoming_data` and :meth:`found_terminator`
40 methods.
Georg Brandl116aa622007-08-15 14:28:22 +000041 The :class:`asyncore.dispatcher` methods can be used, although not all make
42 sense in a message/response context.
43
Georg Brandl9afde1c2007-11-01 20:32:30 +000044 Like :class:`asyncore.dispatcher`, :class:`async_chat` defines a set of
45 events that are generated by an analysis of socket conditions after a
Georg Brandl60203b42010-10-06 10:11:56 +000046 :c:func:`select` call. Once the polling loop has been started the
Georg Brandl9afde1c2007-11-01 20:32:30 +000047 :class:`async_chat` object's methods are called by the event-processing
48 framework with no action on the part of the programmer.
Georg Brandl116aa622007-08-15 14:28:22 +000049
Georg Brandl9afde1c2007-11-01 20:32:30 +000050 Two class attributes can be modified, to improve performance, or possibly
51 even to conserve memory.
52
53
54 .. data:: ac_in_buffer_size
55
56 The asynchronous input buffer size (default ``4096``).
57
58
59 .. data:: ac_out_buffer_size
60
61 The asynchronous output buffer size (default ``4096``).
62
63 Unlike :class:`asyncore.dispatcher`, :class:`async_chat` allows you to
Serhiy Storchaka98019e12016-05-16 09:10:43 +030064 define a :abbr:`FIFO (first-in, first-out)` queue of *producers*. A producer need
Georg Brandl9afde1c2007-11-01 20:32:30 +000065 have only one method, :meth:`more`, which should return data to be
66 transmitted on the channel.
Georg Brandl116aa622007-08-15 14:28:22 +000067 The producer indicates exhaustion (*i.e.* that it contains no more data) by
Serhiy Storchaka5e028ae2014-02-06 21:10:41 +020068 having its :meth:`more` method return the empty bytes object. At this point
Serhiy Storchaka98019e12016-05-16 09:10:43 +030069 the :class:`async_chat` object removes the producer from the queue and starts
70 using the next producer, if any. When the producer queue is empty the
Georg Brandl116aa622007-08-15 14:28:22 +000071 :meth:`handle_write` method does nothing. You use the channel object's
Georg Brandl9afde1c2007-11-01 20:32:30 +000072 :meth:`set_terminator` method to describe how to recognize the end of, or
73 an important breakpoint in, an incoming transmission from the remote
74 endpoint.
Georg Brandl116aa622007-08-15 14:28:22 +000075
76 To build a functioning :class:`async_chat` subclass your input methods
Georg Brandl9afde1c2007-11-01 20:32:30 +000077 :meth:`collect_incoming_data` and :meth:`found_terminator` must handle the
78 data that the channel receives asynchronously. The methods are described
79 below.
Georg Brandl116aa622007-08-15 14:28:22 +000080
81
82.. method:: async_chat.close_when_done()
83
Serhiy Storchaka98019e12016-05-16 09:10:43 +030084 Pushes a ``None`` on to the producer queue. When this producer is popped off
85 the queue it causes the channel to be closed.
Georg Brandl116aa622007-08-15 14:28:22 +000086
87
88.. method:: async_chat.collect_incoming_data(data)
89
Georg Brandl9afde1c2007-11-01 20:32:30 +000090 Called with *data* holding an arbitrary amount of received data. The
91 default method, which must be overridden, raises a
92 :exc:`NotImplementedError` exception.
Georg Brandl116aa622007-08-15 14:28:22 +000093
94
95.. method:: async_chat.discard_buffers()
96
Georg Brandl9afde1c2007-11-01 20:32:30 +000097 In emergencies this method will discard any data held in the input and/or
Serhiy Storchaka98019e12016-05-16 09:10:43 +030098 output buffers and the producer queue.
Georg Brandl116aa622007-08-15 14:28:22 +000099
100
101.. method:: async_chat.found_terminator()
102
Georg Brandl9afde1c2007-11-01 20:32:30 +0000103 Called when the incoming data stream matches the termination condition set
104 by :meth:`set_terminator`. The default method, which must be overridden,
105 raises a :exc:`NotImplementedError` exception. The buffered input data
106 should be available via an instance attribute.
Georg Brandl116aa622007-08-15 14:28:22 +0000107
108
109.. method:: async_chat.get_terminator()
110
111 Returns the current terminator for the channel.
112
113
Georg Brandl116aa622007-08-15 14:28:22 +0000114.. method:: async_chat.push(data)
115
Serhiy Storchaka98019e12016-05-16 09:10:43 +0300116 Pushes data on to the channel's queue to ensure its transmission.
Giampaolo RodolĂ 81302902010-04-29 20:45:01 +0000117 This is all you need to do to have the channel write the data out to the
118 network, although it is possible to use your own producers in more complex
119 schemes to implement encryption and chunking, for example.
Georg Brandl116aa622007-08-15 14:28:22 +0000120
121
122.. method:: async_chat.push_with_producer(producer)
123
Serhiy Storchaka98019e12016-05-16 09:10:43 +0300124 Takes a producer object and adds it to the producer queue associated with
Georg Brandl9afde1c2007-11-01 20:32:30 +0000125 the channel. When all currently-pushed producers have been exhausted the
126 channel will consume this producer's data by calling its :meth:`more`
127 method and send the data to the remote endpoint.
Georg Brandl116aa622007-08-15 14:28:22 +0000128
129
Georg Brandl116aa622007-08-15 14:28:22 +0000130.. method:: async_chat.set_terminator(term)
131
Georg Brandl9afde1c2007-11-01 20:32:30 +0000132 Sets the terminating condition to be recognized on the channel. ``term``
133 may be any of three types of value, corresponding to three different ways
134 to handle incoming protocol data.
Georg Brandl116aa622007-08-15 14:28:22 +0000135
136 +-----------+---------------------------------------------+
137 | term | Description |
138 +===========+=============================================+
139 | *string* | Will call :meth:`found_terminator` when the |
140 | | string is found in the input stream |
141 +-----------+---------------------------------------------+
142 | *integer* | Will call :meth:`found_terminator` when the |
143 | | indicated number of characters have been |
144 | | received |
145 +-----------+---------------------------------------------+
146 | ``None`` | The channel continues to collect data |
147 | | forever |
148 +-----------+---------------------------------------------+
149
Georg Brandl9afde1c2007-11-01 20:32:30 +0000150 Note that any data following the terminator will be available for reading
151 by the channel after :meth:`found_terminator` is called.
Georg Brandl116aa622007-08-15 14:28:22 +0000152
153
Georg Brandl116aa622007-08-15 14:28:22 +0000154.. _asynchat-example:
155
156asynchat Example
157----------------
158
159The following partial example shows how HTTP requests can be read with
Georg Brandl9afde1c2007-11-01 20:32:30 +0000160:class:`async_chat`. A web server might create an
161:class:`http_request_handler` object for each incoming client connection.
162Notice that initially the channel terminator is set to match the blank line at
163the end of the HTTP headers, and a flag indicates that the headers are being
164read.
Georg Brandl116aa622007-08-15 14:28:22 +0000165
Georg Brandl9afde1c2007-11-01 20:32:30 +0000166Once the headers have been read, if the request is of type POST (indicating
167that further data are present in the input stream) then the
168``Content-Length:`` header is used to set a numeric terminator to read the
169right amount of data from the channel.
Georg Brandl116aa622007-08-15 14:28:22 +0000170
171The :meth:`handle_request` method is called once all relevant input has been
Georg Brandl9afde1c2007-11-01 20:32:30 +0000172marshalled, after setting the channel terminator to ``None`` to ensure that
173any extraneous data sent by the web client are ignored. ::
Georg Brandl116aa622007-08-15 14:28:22 +0000174
Giampaolo Rodola'0fb41b52012-05-15 15:46:00 +0200175
176 import asynchat
177
Georg Brandl116aa622007-08-15 14:28:22 +0000178 class http_request_handler(asynchat.async_chat):
179
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000180 def __init__(self, sock, addr, sessions, log):
181 asynchat.async_chat.__init__(self, sock=sock)
Georg Brandl116aa622007-08-15 14:28:22 +0000182 self.addr = addr
183 self.sessions = sessions
184 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000185 self.obuffer = b""
186 self.set_terminator(b"\r\n\r\n")
Georg Brandl116aa622007-08-15 14:28:22 +0000187 self.reading_headers = True
188 self.handling = False
189 self.cgi_data = None
190 self.log = log
191
192 def collect_incoming_data(self, data):
193 """Buffer the data"""
194 self.ibuffer.append(data)
195
196 def found_terminator(self):
197 if self.reading_headers:
198 self.reading_headers = False
Serhiy Storchaka5e028ae2014-02-06 21:10:41 +0200199 self.parse_headers(b"".join(self.ibuffer))
Georg Brandl116aa622007-08-15 14:28:22 +0000200 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000201 if self.op.upper() == b"POST":
Georg Brandl116aa622007-08-15 14:28:22 +0000202 clen = self.headers.getheader("content-length")
203 self.set_terminator(int(clen))
204 else:
205 self.handling = True
206 self.set_terminator(None)
207 self.handle_request()
208 elif not self.handling:
Serhiy Storchakadba90392016-05-10 12:01:23 +0300209 self.set_terminator(None) # browsers sometimes over-send
Josiah Carlson1893ce72008-07-07 04:23:14 +0000210 self.cgi_data = parse(self.headers, b"".join(self.ibuffer))
Georg Brandl116aa622007-08-15 14:28:22 +0000211 self.handling = True
212 self.ibuffer = []
213 self.handle_request()