11.24.2 asynchat Example

##
11.24.2 asynchat Example

The following partial example shows how HTTP requests can be read with `async_chat`. A web server might create an `http_request_handler` object for each incoming client connection. Notice that initially the channel terminator is set to match the blank line at the end of the HTTP headers, and a flag indicates that the headers are being read.

Once the headers have been read, if the request is of type POST (indicating that further data are present in the input stream) then the `Content-Length:` header is used to set a numeric terminator to read the right amount of data from the channel.

The `handle_request()` method is called once all relevant input has been marshalled, after setting the channel terminator to `None` to ensure that any extraneous data sent by the web client are ignored.

    class http_request_handler(asynchat.async_chat):

        def __init__(self, conn, addr, sessions, log):
            asynchat.async_chat.__init__(self, conn=conn)
            self.addr = addr
            self.sessions = sessions
            self.ibuffer = []
            self.obuffer = ""
            self.set_terminator("\r\n\r\n")
            self.reading_headers = True
            self.handling = False
            self.cgi_data = None
            self.log = log

        def collect_incoming_data(self, data):
            """Buffer the data"""
            self.ibuffer.append(data)

        def found_terminator(self):
            if self.reading_headers:
                self.reading_headers = False
                self.parse_headers("".join(self.ibuffer))
                self.ibuffer = []
                if self.op.upper() == "POST":
                    clen = self.headers.getheader("content-length")
                    self.set_terminator(int(clen))
                else:
                    self.handling = True
                    self.set_terminator(None)
                    self.handle_request()
            elif not self.handling:
                self.set_terminator(None) # browsers sometimes over-send
                self.cgi_data = parse(self.headers, "".join(self.ibuffer))
                self.handling = True
                self.ibuffer = []
                self.handle_request()