From 55ddf853cd8cac13bb6021ef92d21af85cb9b2f1 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 10 Jun 2012 10:46:22 +1200 Subject: [PATCH] Add HTTP version to flow.Request This is a serialization format change, that makes us incompatible with previous versions. --- libmproxy/flow.py | 30 +++++++++++++++++++++++++----- libmproxy/proxy.py | 6 +++--- test/test_filt.py | 1 + test/test_flow.py | 22 +++++++++++----------- test/tutils.py | 2 +- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/libmproxy/flow.py b/libmproxy/flow.py index bb9d34f86..549942a52 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -346,9 +346,10 @@ class Request(HTTPMsg): timestamp: Seconds since the epoch method: HTTP method """ - def __init__(self, client_conn, host, port, scheme, method, path, headers, content, timestamp=None): + def __init__(self, client_conn, httpversion, host, port, scheme, method, path, headers, content, timestamp=None): assert isinstance(headers, ODictCaseless) self.client_conn = client_conn + self.httpversion = httpversion self.host, self.port, self.scheme = host, port, scheme self.method, self.path, self.headers, self.content = method, path, headers, content self.timestamp = timestamp or utils.timestamp() @@ -420,6 +421,7 @@ class Request(HTTPMsg): def _get_state(self): return dict( client_conn = self.client_conn._get_state() if self.client_conn else None, + httpversion = self.httpversion, host = self.host, port = self.port, scheme = self.scheme, @@ -434,6 +436,7 @@ class Request(HTTPMsg): def _from_state(klass, state): return klass( ClientConnect._from_state(state["client_conn"]), + tuple(state["httpversion"]), str(state["host"]), state["port"], str(state["scheme"]), @@ -523,8 +526,8 @@ class Request(HTTPMsg): """ if self.content == CONTENT_MISSING: return None - FMT = '%s %s HTTP/1.1\r\n%s\r\n%s' - FMT_PROXY = '%s %s://%s:%s%s HTTP/1.1\r\n%s\r\n%s' + FMT = '%s %s HTTP/%s.%s\r\n%s\r\n%s' + FMT_PROXY = '%s %s://%s:%s%s HTTP/%s.%s\r\n%s\r\n%s' headers = self.headers.copy() utils.del_all( @@ -547,9 +550,26 @@ class Request(HTTPMsg): if self.close: headers["connection"] = ["close"] if not _proxy: - return FMT % (self.method, self.path, str(headers), content) + return FMT % ( + self.method, + self.path, + self.httpversion[0], + self.httpversion[1], + str(headers), + content + ) else: - return FMT_PROXY % (self.method, self.scheme, self.host, self.port, self.path, str(headers), content) + return FMT_PROXY % ( + self.method, + self.scheme, + self.host, + self.port, + self.path, + self.httpversion[0], + self.httpversion[1], + str(headers), + content + ) def replace(self, pattern, repl, *args, **kwargs): """ diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 4eeb17c9a..c7e5d972f 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -465,7 +465,7 @@ class ProxyHandler(SocketServer.StreamRequestHandler): method, path, httpversion = parse_init_http(line) headers = read_headers(self.rfile) content = self.read_contents(client_conn, headers, httpversion) - return flow.Request(client_conn, host, port, "http", method, path, headers, content) + return flow.Request(client_conn, httpversion, host, port, "http", method, path, headers, content) elif line.startswith("CONNECT"): host, port, httpversion = parse_init_connect(line) # FIXME: Discard additional headers sent to the proxy. Should I expose @@ -486,12 +486,12 @@ class ProxyHandler(SocketServer.StreamRequestHandler): method, path, httpversion = parse_init_http(self.rfile.readline(line)) headers = read_headers(self.rfile) content = self.read_contents(client_conn, headers, httpversion) - return flow.Request(client_conn, host, port, "https", method, path, headers, content) + return flow.Request(client_conn, httpversion, host, port, "https", method, path, headers, content) else: method, scheme, host, port, path, httpversion = parse_init_proxy(line) headers = read_headers(self.rfile) content = self.read_contents(client_conn, headers, httpversion) - return flow.Request(client_conn, host, port, scheme, method, path, headers, content) + return flow.Request(client_conn, httpversion, host, port, scheme, method, path, headers, content) def send_response(self, response): d = response._assemble() diff --git a/test/test_filt.py b/test/test_filt.py index 287ef376c..62c9fb51e 100644 --- a/test/test_filt.py +++ b/test/test_filt.py @@ -77,6 +77,7 @@ class TestMatching: headers["header"] = ["qvalue"] req = flow.Request( conn, + (1, 1), "host", 80, "http", diff --git a/test/test_flow.py b/test/test_flow.py index 885299d84..fd26b0956 100644 --- a/test/test_flow.py +++ b/test/test_flow.py @@ -686,7 +686,7 @@ class TestRequest: h = flow.ODictCaseless() h["test"] = ["test"] c = flow.ClientConnect(("addr", 2222)) - r = flow.Request(c, "host", 22, "https", "GET", "/", h, "content") + r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content") u = r.get_url() assert r.set_url(u) assert not r.set_url("") @@ -711,7 +711,7 @@ class TestRequest: h = flow.ODictCaseless() h["content-type"] = [flow.HDR_FORM_URLENCODED] d = flow.ODict([("one", "two"), ("three", "four")]) - r = flow.Request(None, "host", 22, "https", "GET", "/", h, utils.urlencode(d.lst)) + r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/", h, utils.urlencode(d.lst)) assert r.get_form_urlencoded() == d d = flow.ODict([("x", "y")]) @@ -724,19 +724,19 @@ class TestRequest: def test_getset_query(self): h = flow.ODictCaseless() - r = flow.Request(None, "host", 22, "https", "GET", "/foo?x=y&a=b", h, "content") + r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/foo?x=y&a=b", h, "content") q = r.get_query() assert q.lst == [("x", "y"), ("a", "b")] - r = flow.Request(None, "host", 22, "https", "GET", "/", h, "content") + r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/", h, "content") q = r.get_query() assert not q - r = flow.Request(None, "host", 22, "https", "GET", "/?adsfa", h, "content") + r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/?adsfa", h, "content") q = r.get_query() assert not q - r = flow.Request(None, "host", 22, "https", "GET", "/foo?x=y&a=b", h, "content") + r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/foo?x=y&a=b", h, "content") assert r.get_query() r.set_query(flow.ODict([])) assert not r.get_query() @@ -746,7 +746,7 @@ class TestRequest: def test_anticache(self): h = flow.ODictCaseless() - r = flow.Request(None, "host", 22, "https", "GET", "/", h, "content") + r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/", h, "content") h["if-modified-since"] = ["test"] h["if-none-match"] = ["test"] r.anticache() @@ -757,7 +757,7 @@ class TestRequest: h = flow.ODictCaseless() h["test"] = ["test"] c = flow.ClientConnect(("addr", 2222)) - r = flow.Request(c, "host", 22, "https", "GET", "/", h, "content") + r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content") state = r._get_state() assert flow.Request._from_state(state) == r @@ -765,7 +765,7 @@ class TestRequest: state = r._get_state() assert flow.Request._from_state(state) == r - r2 = flow.Request(c, "testing", 20, "http", "PUT", "/foo", h, "test") + r2 = flow.Request(c, (1, 1), "testing", 20, "http", "PUT", "/foo", h, "test") assert not r == r2 r._load_state(r2._get_state()) assert r == r2 @@ -825,7 +825,7 @@ class TestResponse: h = flow.ODictCaseless() h["test"] = ["test"] c = flow.ClientConnect(("addr", 2222)) - req = flow.Request(c, "host", 22, "https", "GET", "/", h, "content") + req = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content") resp = flow.Response(req, 200, "msg", h.copy(), "content", None) assert resp._assemble() @@ -883,7 +883,7 @@ class TestResponse: h = flow.ODictCaseless() h["test"] = ["test"] c = flow.ClientConnect(("addr", 2222)) - req = flow.Request(c, "host", 22, "https", "GET", "/", h, "content") + req = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content") resp = flow.Response(req, 200, "msg", h.copy(), "content", None) state = resp._get_state() diff --git a/test/tutils.py b/test/tutils.py index 5f4739c65..7852a8b8c 100644 --- a/test/tutils.py +++ b/test/tutils.py @@ -12,7 +12,7 @@ def treq(conn=None): conn = flow.ClientConnect(("address", 22)) headers = flow.ODictCaseless() headers["header"] = ["qvalue"] - return flow.Request(conn, "host", 80, "http", "GET", "/path", headers, "content") + return flow.Request(conn, (1, 1), "host", 80, "http", "GET", "/path", headers, "content") def tresp(req=None):