aboutsummaryrefslogtreecommitdiff
path: root/scripts/async-http.py
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2009-04-15 04:17:48 +0000
committerRob Austein <sra@hactrn.net>2009-04-15 04:17:48 +0000
commit5c08745bdecef6deab78300305a06f0c8752c734 (patch)
tree4242b6250bd1ccad14ebd3843f32e1d87910025d /scripts/async-http.py
parent6222279a30be25e5378f55809680b52e25467fe5 (diff)
Checkpoint
svn path=/scripts/async-http.py; revision=2340
Diffstat (limited to 'scripts/async-http.py')
-rw-r--r--scripts/async-http.py98
1 files changed, 62 insertions, 36 deletions
diff --git a/scripts/async-http.py b/scripts/async-http.py
index 3c6251c6..79dcb342 100644
--- a/scripts/async-http.py
+++ b/scripts/async-http.py
@@ -27,7 +27,9 @@ import sys, os, time, socket, fcntl, asyncore, asynchat, getopt, email, tracebac
class http_message(object):
- def __init__(self, headers):
+ @classmethod
+ def parse_from_wire(cls, headers):
+ self = cls()
headers = headers.split("\r\n")
self.parse_first_line(*headers.pop(0).split(None, 2))
for i in xrange(len(headers) - 2, -1, -1):
@@ -36,46 +38,67 @@ class http_message(object):
del headers[i + 1]
headers = [h.split(":", 1) for h in headers]
self.headers = dict((k.lower(), v) for (k,v) in headers)
+ return self
+
+ def format(self):
+ s = self.format_first_line()
+ if self.body is not None:
+ assert isinstance(self.body, str)
+ self.headers["content-length"] = len(self.body)
+ for kv in self.headers.iteritems():
+ s += "%s: %s\r\n" % kv
+ s += "\r\n"
+ if self.body is not None:
+ s += self.body
+ return s
def __str__(self):
- s = "Version: %d.%d\n" % self.version
- s += "Type: %s\n" % self.__class__.__name__
- s += "Command: %s\n" % getattr(self, "cmd", "")
- s += "Path: %s\n" % getattr(self, "path", "")
- s += "Code: %s\n" % getattr(self, "code", "")
- s += "Msg: %s\n" % getattr(self, "msg", "")
- for k,v in self.headers.iteritems():
- s += " %s: %s\n" % (k, v)
- return s
+ return self.format()
+
+ def parse_version(self, version):
+ if version[:5] != "HTTP/":
+ raise RuntimeError
+ self.version = tuple(int(i) for i in version[5:].split("."))
class http_request(http_message):
- def parse_first_line(self, cmd, path, version = None):
+ def __init__(self, cmd = None, path = None, version = (1,0), body = None, headers = None):
+ self.cmd = cmd
+ self.path = path
+ self.version = version
+ self.body = body
+ self.headers = {} if headers is None else headers
+
+ def parse_first_line(self, cmd, path, version):
+ self.parse_version(version)
self.cmd = cmd.upper()
self.path = path
- if version is None:
- self.version = (0, 9)
- elif version[:5] == "HTTP/":
- self.version = tuple(int(i) for i in version[5:].split("."))
- else:
- raise RuntimeError
+
+ def format_first_line(self):
+ return "%s %s HTTPS/%d.%d\r\n" % (self.cmd, self.path, self.version[0], self.version[1])
class http_response(http_message):
+ def __init__(self, code = None, msg = None, version = (1,0), body = None, headers = None):
+ self.code = code
+ self.msg = msg
+ self.version = version
+ self.body = body
+ self.headers = {} if headers is None else headers
+
def parse_first_line(self, version, code, msg):
- if version[:5] == "HTTP/":
- self.version = tuple(int(i) for i in version[5:].split("."))
- else:
- raise RuntimeError
+ self.parse_version(version)
self.code = int(code)
self.msg = msg
+ def format_first_line(self):
+ return "HTTPS/%d.%d %s %s\r\n" % (self.version[0], self.version[1], self.code, self.msg)
+
class http_server(asynchat.async_chat):
- """This started out as the asynchat example from the Python manual."""
def __init__(self, conn):
asynchat.async_chat.__init__(self, conn = conn)
- self.ibuffer = []
+ self.buffer = []
self.set_terminator("\r\n\r\n")
def reading_headers(self):
@@ -86,11 +109,11 @@ class http_server(asynchat.async_chat):
def collect_incoming_data(self, data):
"""Buffer the data"""
- self.ibuffer.append(data)
+ self.buffer.append(data)
- def get_ibuffer(self):
- val = "".join(self.ibuffer)
- self.ibuffer = []
+ def get_buffer(self):
+ val = "".join(self.buffer)
+ self.buffer = []
return val
def found_terminator(self):
@@ -101,17 +124,20 @@ class http_server(asynchat.async_chat):
raise RuntimeError
def handle_headers(self):
- msg = http_request(self.get_ibuffer())
- print msg
- self.reply(msg)
+ self.msg = http_request.parse_from_wire(self.get_buffer())
+ if self.msg.cmd == "POST":
+ self.set_terminator(int(self.msg.headers["content-length"]))
+ else:
+ self.handle_message()
- def reply(self, msg):
- self.push("HTTP/1.0 200 Yo!\r\nContent-Type: text/plain\r\n\r\n")
- self.push(str(msg).replace("\n", "\r\n"))
- self.close_when_done()
+ def handle_body(self):
+ self.msg.body = self.get_buffer()
+ assert len(self.msg.body) == int(self.msg.headers["content-length"])
+ self.handle_message()
- def push_line(self, line = ""):
- self.push(line + "\r\n")
+ def handle_message(self):
+ self.push(http_response(code = 200, msg = "OK", body = self.msg.format(), headers = { "content-type" : "text/plain" }).format())
+ self.close_when_done()
def handle_error(self):
print traceback.format_exc()