From 8bec99f858deb8aaf35b6502355e3e00a98ffed7 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 24 Jun 2012 19:12:52 +1200 Subject: Request service rendering. --- libpathod/rparse.py | 177 +++++++++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 79 deletions(-) (limited to 'libpathod') diff --git a/libpathod/rparse.py b/libpathod/rparse.py index af0f9671..bb45ae00 100644 --- a/libpathod/rparse.py +++ b/libpathod/rparse.py @@ -4,6 +4,7 @@ from netlib import http_status import utils BLOCKSIZE = 1024 +TRUNCATE = 1024 class ParseException(Exception): def __init__(self, msg, s, col): @@ -421,21 +422,82 @@ class Code: return e.setParseAction(lambda x: klass(*x)) -class Request: + +class Message: + version = "HTTP/1.1" + def length(self): + l = sum(len(x) for x in self.preamble()) + l += 2 + for i in self.headers: + l += len(i[0]) + len(i[1]) + l += 4 + l += 2 + l += len(self.body) + return l + + def serve(self, fp): + started = time.time() + if self.body and not utils.get_header("Content-Length", self.headers): + self.headers.append( + ( + LiteralGenerator("Content-Length"), + LiteralGenerator(str(len(self.body))), + ) + ) + + hdrs = [] + for k, v in self.headers: + hdrs.extend([ + k, + ": ", + v, + "\r\n", + ]) + vals = self.preamble() + vals.append("\r\n") + vals.extend(hdrs) + vals.append("\r\n") + if self.body: + vals.append(self.body) + vals.reverse() + actions = ready_actions(self.length(), self.actions) + actions.reverse() + disconnect = write_values(fp, vals, actions[:]) + duration = time.time() - started + ret = dict( + disconnect = disconnect, + started = started, + duration = duration, + actions = actions, + ) + for i in self.logattrs: + v = getattr(self, i) + # Careful not to log any VALUE specs without sanitizing them first. We truncate at 1k. + if hasattr(v, "__len__"): + v = v[:TRUNCATE] + ret[i] = v + return ret + + +class Response(Message): comps = ( Body, Header, PauseAt, DisconnectAt, ShortcutContentType, + ShortcutLocation, ) - version = "HTTP/1.1" + logattrs = ["code", "version"] def __init__(self): - self.method = None - self.path = None - self.body = LiteralGenerator("") self.headers = [] self.actions = [] + self.code = 200 + self.msg = LiteralGenerator(http_status.RESPONSES[self.code]) + self.body = LiteralGenerator("") + + def preamble(self): + return [self.version, " ", str(self.code), " ", self.msg] @classmethod def expr(klass): @@ -443,115 +505,72 @@ class Request: atom = pp.MatchFirst(parts) resp = pp.And( [ - Method.expr(), - pp.Literal(":").suppress(), - Path.expr(), + Code.expr(), pp.ZeroOrMore(pp.Literal(":").suppress() + atom) ] ) return resp - -class CraftedRequest(Request): - def __init__(self, settings, spec, tokens): - Request.__init__(self) - self.spec, self.tokens = spec, tokens - for i in tokens: - i.accept(settings, self) - - def serve(self, fp): - d = Request.serve(self, fp) - d["spec"] = self.spec - return d + def __str__(self): + parts = [ + "%s %s"%(self.code, self.msg[:]) + ] + return "\n".join(parts) -class Response: +class Request(Message): comps = ( Body, Header, PauseAt, DisconnectAt, ShortcutContentType, - ShortcutLocation, ) - version = "HTTP/1.1" - code = 200 - msg = LiteralGenerator(http_status.RESPONSES[code]) - body = LiteralGenerator("") + logattrs = ["method", "path"] def __init__(self): + self.method = None + self.path = None + self.body = LiteralGenerator("") self.headers = [] self.actions = [] + def preamble(self): + return [self.method, " ", self.path, " ", self.version] + @classmethod def expr(klass): parts = [i.expr() for i in klass.comps] atom = pp.MatchFirst(parts) resp = pp.And( [ - Code.expr(), + Method.expr(), + pp.Literal(":").suppress(), + Path.expr(), pp.ZeroOrMore(pp.Literal(":").suppress() + atom) ] ) return resp - def length(self): - l = len("%s %s "%(self.version, self.code)) - l += len(self.msg) - l += 2 - for i in self.headers: - l += len(i[0]) + len(i[1]) - l += 4 - l += 2 - l += len(self.body) - return l - - def serve(self, fp): - started = time.time() - if self.body and not utils.get_header("Content-Length", self.headers): - self.headers.append( - ( - LiteralGenerator("Content-Length"), - LiteralGenerator(str(len(self.body))), - ) - ) - - hdrs = [] - for k, v in self.headers: - hdrs.extend([ - k, - ": ", - v, - "\r\n", - ]) - vals = [ - "%s %s "%(self.version, self.code), - self.msg, - "\r\n", - ] - vals.extend(hdrs) - vals.append("\r\n") - if self.body: - vals.append(self.body) - vals.reverse() - actions = ready_actions(self.length(), self.actions) - actions.reverse() - disconnect = write_values(fp, vals, actions[:]) - duration = time.time() - started - return dict( - disconnect = disconnect, - started = started, - duration = duration, - actions = actions, - code = self.code, - ) - def __str__(self): parts = [ - "%s %s"%(self.code, self.msg[:]) + "%s %s"%(self.method[:], self.path[:]) ] return "\n".join(parts) +class CraftedRequest(Request): + def __init__(self, settings, spec, tokens): + Request.__init__(self) + self.spec, self.tokens = spec, tokens + for i in tokens: + i.accept(settings, self) + + def serve(self, fp): + d = Request.serve(self, fp) + d["spec"] = self.spec + return d + + class CraftedResponse(Response): def __init__(self, settings, spec, tokens): Response.__init__(self) -- cgit v1.2.3