From 82ac7d05a65f5bfd95a20112da09e2dc40960f07 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 5 Nov 2016 10:10:59 +1300 Subject: [PATCH] Bug: ask requestheaders before request body is read Also add the beginnings of a test suite to exercise issues like this. --- mitmproxy/proxy/protocol/http.py | 5 +-- test/mitmproxy/test_eventsequence.py | 48 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 test/mitmproxy/test_eventsequence.py diff --git a/mitmproxy/proxy/protocol/http.py b/mitmproxy/proxy/protocol/http.py index 17d09b077..4caaf1e30 100644 --- a/mitmproxy/proxy/protocol/http.py +++ b/mitmproxy/proxy/protocol/http.py @@ -161,10 +161,11 @@ class HttpLayer(base.Layer): def _process_flow(self, f): try: request = self.read_request_headers(f) - request.data.content = b"".join(self.read_request_body(request)) - request.timestamp_end = time.time() f.request = request self.channel.ask("requestheaders", f) + + request.data.content = b"".join(self.read_request_body(request)) + request.timestamp_end = time.time() if request.headers.get("expect", "").lower() == "100-continue": # TODO: We may have to use send_response_headers for HTTP2 here. self.send_response(http.expect_continue_response) diff --git a/test/mitmproxy/test_eventsequence.py b/test/mitmproxy/test_eventsequence.py new file mode 100644 index 000000000..7fdbce1b9 --- /dev/null +++ b/test/mitmproxy/test_eventsequence.py @@ -0,0 +1,48 @@ +from mitmproxy import events +import contextlib +from . import tservers + + +class EAddon: + def __init__(self, handlers): + self.failure = None + self.handlers = handlers + for i in events.Events: + def mkprox(): + evt = i + + def prox(*args, **kwargs): + if evt in self.handlers: + try: + handlers[evt](*args, **kwargs) + except AssertionError as e: + self.failure = e + return prox + setattr(self, i, mkprox()) + + def fail(self): + pass + + +class SequenceTester: + @contextlib.contextmanager + def events(self, **kwargs): + m = EAddon(kwargs) + self.master.addons.add(m) + yield + self.master.addons.remove(m) + if m.failure: + raise m.failure + + +class TestBasic(tservers.HTTPProxyTest, SequenceTester): + def test_requestheaders(self): + + def req(f): + assert f.request.headers + assert not f.request.content + + with self.events(requestheaders=req): + p = self.pathoc() + with p.connect(): + assert p.request("get:'%s/p/200':b@10" % self.server.urlbase).status_code == 200