# 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("\r\n\r\n") 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("\r\n") 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\r\n" % (status, explanation)) class FileProducer: # a producer which 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): asyncore.dispatcher.__init__(self) 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\r\n") channel.push("\r\n") channel.push("File not found.\r\n") else: channel.pushstatus(200, "OK") channel.push("Content-type: text/html\r\n") channel.push("\r\n") 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: