diff --git a/examples/change_upstream_proxy.py b/examples/change_upstream_proxy.py index e063ca4fa..74a43bd0d 100644 --- a/examples/change_upstream_proxy.py +++ b/examples/change_upstream_proxy.py @@ -1,7 +1,7 @@ -# This scripts demonstrates how mitmproxy can switch to a different upstream proxy +# This scripts demonstrates how mitmproxy can switch to a second/different upstream proxy # in upstream proxy mode. # -# Usage: mitmdump -s "change_upstream_proxy.py host" +# Usage: mitmdump -U http://default-upstream-proxy.local:8080/ -s "change_upstream_proxy.py host" from libmproxy.protocol.http import send_connect_request alternative_upstream_proxy = ("localhost", 8082) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index ffd9eda88..fc6600c1e 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -516,7 +516,8 @@ class ConsoleMaster(flow.FlowMaster): self.start_server_playback( ret, self.killextra, self.rheaders, - False, self.nopop + False, self.nopop, + self.options.replay_ignore_params, self.options.replay_ignore_content ) def spawn_editor(self, data): diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index e03301712..3eb4eb1a5 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -120,13 +120,15 @@ class ConnectionItem(common.WWrap): self.master.start_server_playback( [i.copy() for i in self.master.state.view], self.master.killextra, self.master.rheaders, - False, self.master.nopop + False, self.master.nopop, + self.master.options.replay_ignore_params, self.master.options.replay_ignore_content ) elif k == "t": self.master.start_server_playback( [self.flow.copy()], self.master.killextra, self.master.rheaders, - False, self.master.nopop + False, self.master.nopop, + self.master.options.replay_ignore_params, self.master.options.replay_ignore_content ) else: self.master.path_prompt( diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index b2c461475..3dceff704 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -749,7 +749,7 @@ class FlowView(common.WWrap): self.master.statusbar.message("") elif key == "m": p = list(contentview.view_prompts) - p.insert(0, ("clear", "c")) + p.insert(0, ("Clear", "C")) self.master.prompt_onekey( "Display mode", p, diff --git a/libmproxy/flow.py b/libmproxy/flow.py index bd35e864e..1826af3de 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -192,6 +192,7 @@ class ClientPlaybackState: """ if self.flows and not self.current: n = self.flows.pop(0) + n.response = None n.reply = controller.DummyReply() self.current = master.handle_request(n) if not testing and not self.current.response: @@ -615,7 +616,7 @@ class FlowMaster(controller.Master): ] if all(e): self.shutdown() - self.client_playback.tick(self, timeout) + self.client_playback.tick(self) return controller.Master.tick(self, q, timeout) diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 1472f2cac..c8974d251 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -434,11 +434,9 @@ class HTTPRequest(HTTPMessage): self.host, self.port)] - if self.content: + # If content is defined (i.e. not None or CONTENT_MISSING), we always add a content-length header. + if self.content or self.content == "": headers["Content-Length"] = [str(len(self.content))] - elif 'Transfer-Encoding' in self.headers: - # content-length for e.g. chuncked transfer-encoding with no content - headers["Content-Length"] = ["0"] return str(headers) @@ -761,11 +759,9 @@ class HTTPResponse(HTTPMessage): if not preserve_transfer_encoding: del headers['Transfer-Encoding'] - if self.content: + # If content is defined (i.e. not None or CONTENT_MISSING), we always add a content-length header. + if self.content or self.content == "": headers["Content-Length"] = [str(len(self.content))] - # add content-length for chuncked transfer-encoding with no content - elif not preserve_transfer_encoding and 'Transfer-Encoding' in self.headers: - headers["Content-Length"] = ["0"] return str(headers) diff --git a/test/test_protocol_http.py b/test/test_protocol_http.py index db2629508..16870777d 100644 --- a/test/test_protocol_http.py +++ b/test/test_protocol_http.py @@ -31,7 +31,9 @@ class TestHTTPRequest: f.request.host = f.server_conn.address.host f.request.port = f.server_conn.address.port f.request.scheme = "http" - assert f.request.assemble() == "OPTIONS * HTTP/1.1\r\nHost: address:22\r\n\r\n" + assert f.request.assemble() == ("OPTIONS * HTTP/1.1\r\n" + "Host: address:22\r\n" + "Content-Length: 0\r\n\r\n") def test_relative_form_in(self): s = StringIO("GET /foo\xff HTTP/1.1") @@ -58,7 +60,9 @@ class TestHTTPRequest: s = StringIO("CONNECT address:22 HTTP/1.1") r = HTTPRequest.from_stream(s) r.scheme, r.host, r.port = "http", "address", 22 - assert r.assemble() == "CONNECT address:22 HTTP/1.1\r\nHost: address:22\r\n\r\n" + assert r.assemble() == ("CONNECT address:22 HTTP/1.1\r\n" + "Host: address:22\r\n" + "Content-Length: 0\r\n\r\n") assert r.pretty_url(False) == "address:22" def test_absolute_form_in(self): @@ -66,7 +70,7 @@ class TestHTTPRequest: tutils.raises("Bad HTTP request line", HTTPRequest.from_stream, s) s = StringIO("GET http://address:22/ HTTP/1.1") r = HTTPRequest.from_stream(s) - assert r.assemble() == "GET http://address:22/ HTTP/1.1\r\nHost: address:22\r\n\r\n" + assert r.assemble() == "GET http://address:22/ HTTP/1.1\r\nHost: address:22\r\nContent-Length: 0\r\n\r\n" def test_http_options_relative_form_in(self): """ @@ -77,9 +81,9 @@ class TestHTTPRequest: r.host = 'address' r.port = 80 r.scheme = "http" - assert r.assemble() == ("OPTIONS " - "/secret/resource " - "HTTP/1.1\r\nHost: address\r\n\r\n") + assert r.assemble() == ("OPTIONS /secret/resource HTTP/1.1\r\n" + "Host: address\r\n" + "Content-Length: 0\r\n\r\n") def test_http_options_absolute_form_in(self): s = StringIO("OPTIONS http://address/secret/resource HTTP/1.1") @@ -87,9 +91,9 @@ class TestHTTPRequest: r.host = 'address' r.port = 80 r.scheme = "http" - assert r.assemble() == ("OPTIONS " - "http://address:80/secret/resource " - "HTTP/1.1\r\nHost: address\r\n\r\n") + assert r.assemble() == ("OPTIONS http://address:80/secret/resource HTTP/1.1\r\n" + "Host: address\r\n" + "Content-Length: 0\r\n\r\n") def test_assemble_unknown_form(self):