The asynchat Module

The asynchat module is an extension to asyncore. It provides additional support for line-oriented protocols. It also provides improved buffering support, via the push methods and the "producer" mechanism.

Example 7-12 implements a very minimal HTTP responder. It simply returns an HTML document containing information from an HTTP request (the output appears in the browser window).

Example 7-12. Using the asynchat Module to Implement a Minimal HTTP Server

File: asynchat-example-1.py

import asyncore, asynchat
import os, socket, string

PORT = 8000

class HTTPChannel(asynchat.async_chat):

 def _ _init_ _(self, server, sock, addr):
 asynchat.async_chat._ _init_ _(self, sock)
 self.set_terminator("
")
 self.request = None
 self.data = ""
 self.shutdown = 0

 def collect_incoming_data(self, data):
 self.data = self.data + data

 def found_terminator(self):
 if not self.request:
 # got the request line
 self.request = string.split(self.data, None, 2)
 if len(self.request) != 3:
 self.shutdown = 1
 else:
 self.push("HTTP/1.0 200 OK
")
 self.push("Content-type: text/html
")
 self.push("
")
 self.data = self.data + "
"
 self.set_terminator("

") # look for end of headers
 else:
 # return payload.
 self.push("

")
 self.push(self.data)
 self.push("

") self.close_when_done() class HTTPServer(asyncore.dispatcher): def _ _init_ _(self, port): self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.bind(("", port)) self.listen(5) def handle_accept(self): conn, addr = self.accept() HTTPChannel(self, conn, addr) # # try it out s = HTTPServer(PORT) print "serving at port", PORT, "..." asyncore.loop() GET / HTTP/1.1 Accept: */* Accept-Language: en, sv Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; Bruce/1.0) Host: localhost:8000 Connection: Keep-Alive

The producer interface allows you to "push" objects that are too large to store in memory. asyncore calls the producer's more method whenever it needs more data. To signal end of file, just return an empty string.

Example 7-13 implements a very simple file-based HTTP server, using a simple FileProducer class that reads data from a file, a few kilobytes at the time.

Example 7-13. Using the asynchat Module to Implement a Simple HTTP Server

File: asynchat-example-2.py

import asyncore, asynchat
import os, socket, string, sys
import StringIO, mimetools

ROOT = "."

PORT = 8000

class HTTPChannel(asynchat.async_chat):

 def _ _init_ _(self, server, sock, addr):
 asynchat.async_chat._ _init_ _(self, sock)
 self.server = server
 self.set_terminator("

")
 self.header = None
 self.data = ""
 self.shutdown = 0

 def collect_incoming_data(self, data):
 self.data = self.data + data
 if len(self.data) > 16384:
 # limit the header size to prevent attacks
 self.shutdown = 1

 def found_terminator(self):
 if not self.header:
 # parse http header
 fp = StringIO.StringIO(self.data)
 request = string.split(fp.readline(), None, 2)
 if len(request) != 3:
 # badly formed request; just shut down
 self.shutdown = 1
 else:
 # parse message header
 self.header = mimetools.Message(fp)
 self.set_terminator("
")
 self.server.handle_request(
 self, request[0], request[1], self.header
 )
 self.close_when_done()
 self.data = ""
 else:
 pass # ignore body data, for now

 def pushstatus(self, status, explanation="OK"):
 self.push("HTTP/1.0 %d %s
" % (status, explanation))


class FileProducer:
 # a producer that reads data from a file object

 def _ _init_ _(self, file):
 self.file = file

 def more(self):
 if self.file:
 data = self.file.read(2048)
 if data:
 return data
 self.file = None
 return ""


class HTTPServer(asyncore.dispatcher):

 def _ _init_ _(self, port=None, request=None):
 if not port:
 port = 80
 self.port = port
 if request:
 self.handle_request = request # external request handler
 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
 self.bind(("", port))
 self.listen(5)

 def handle_accept(self):
 conn, addr = self.accept()
 HTTPChannel(self, conn, addr)

 def handle_request(self, channel, method, path, header):
 try:
 # this is not safe!
 while path[:1] == "/":
 path = path[1:]
 filename = os.path.join(ROOT, path)
 print path, "=>", filename
 file = open(filename, "r")
 except IOError:
 channel.pushstatus(404, "Not found")
 channel.push("Content-type: text/html
")
 channel.push("
")
 channel.push("

File not found. ") else: channel.pushstatus(200, "OK") channel.push("Content-type: text/html ") channel.push(" ") channel.push_with_producer(FileProducer(file)) # # try it out s = HTTPServer(PORT) print "serving at port", PORT asyncore.loop() serving at port 8000 log: adding channel log: adding channel samples/sample.htm => .samples/sample.htm log: closing channel 96:

Core Modules

More Standard Modules

Threads and Processes

Data Representation

File Formats

Mail and News Message Processing

Network Protocols

Internationalization

Multimedia Modules

Data Storage

Tools and Utilities

Platform-Specific Modules

Implementation Support Modules

Other Modules



Python Standard Library
Python Standard Library (Nutshell Handbooks) with
ISBN: 0596000960
EAN: 2147483647
Year: 2000
Pages: 252
Authors: Fredrik Lundh

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net