blob: 794da8cced7f70b17df69bf6fb6c85ff090e09ff [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
Serhiy Storchaka5e028ae2014-02-06 21:10:41 +020064 having its :meth:`more` method return the empty bytes object. At this point
65 the :class:`async_chat` object removes the producer from the fifo and starts
Georg Brandl9afde1c2007-11-01 20:32:30 +000066 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
Georg Brandl116aa622007-08-15 14:28:22 +0000150.. _asynchat-example:
151
152asynchat Example
153----------------
154
155The following partial example shows how HTTP requests can be read with
Georg Brandl9afde1c2007-11-01 20:32:30 +0000156:class:`async_chat`. A web server might create an
157:class:`http_request_handler` object for each incoming client connection.
158Notice that initially the channel terminator is set to match the blank line at
159the end of the HTTP headers, and a flag indicates that the headers are being
160read.
Georg Brandl116aa622007-08-15 14:28:22 +0000161
Georg Brandl9afde1c2007-11-01 20:32:30 +0000162Once the headers have been read, if the request is of type POST (indicating
163that further data are present in the input stream) then the
164``Content-Length:`` header is used to set a numeric terminator to read the
165right amount of data from the channel.
Georg Brandl116aa622007-08-15 14:28:22 +0000166
167The :meth:`handle_request` method is called once all relevant input has been
Georg Brandl9afde1c2007-11-01 20:32:30 +0000168marshalled, after setting the channel terminator to ``None`` to ensure that
169any extraneous data sent by the web client are ignored. ::
Georg Brandl116aa622007-08-15 14:28:22 +0000170
Giampaolo Rodola'0fb41b52012-05-15 15:46:00 +0200171
172 import asynchat
173
Georg Brandl116aa622007-08-15 14:28:22 +0000174 class http_request_handler(asynchat.async_chat):
175
Benjamin Peterson9bc93512008-09-22 22:10:59 +0000176 def __init__(self, sock, addr, sessions, log):
177 asynchat.async_chat.__init__(self, sock=sock)
Georg Brandl116aa622007-08-15 14:28:22 +0000178 self.addr = addr
179 self.sessions = sessions
180 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000181 self.obuffer = b""
182 self.set_terminator(b"\r\n\r\n")
Georg Brandl116aa622007-08-15 14:28:22 +0000183 self.reading_headers = True
184 self.handling = False
185 self.cgi_data = None
186 self.log = log
187
188 def collect_incoming_data(self, data):
189 """Buffer the data"""
190 self.ibuffer.append(data)
191
192 def found_terminator(self):
193 if self.reading_headers:
194 self.reading_headers = False
Serhiy Storchaka5e028ae2014-02-06 21:10:41 +0200195 self.parse_headers(b"".join(self.ibuffer))
Georg Brandl116aa622007-08-15 14:28:22 +0000196 self.ibuffer = []
Josiah Carlson1893ce72008-07-07 04:23:14 +0000197 if self.op.upper() == b"POST":
Georg Brandl116aa622007-08-15 14:28:22 +0000198 clen = self.headers.getheader("content-length")
199 self.set_terminator(int(clen))
200 else:
201 self.handling = True
202 self.set_terminator(None)
203 self.handle_request()
204 elif not self.handling:
205 self.set_terminator(None) # browsers sometimes over-send
Josiah Carlson1893ce72008-07-07 04:23:14 +0000206 self.cgi_data = parse(self.headers, b"".join(self.ibuffer))
Georg Brandl116aa622007-08-15 14:28:22 +0000207 self.handling = True
208 self.ibuffer = []
209 self.handle_request()