diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 8ee017f67..7d51b6d14 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -922,7 +922,7 @@ class FlowMaster(controller.Master): if f.request: f.backup() f.request.is_replay = True - if f.request.content: + if "Content-Length" in f.request.headers: f.request.headers["Content-Length"] = str(len(f.request.content)) f.response = None f.error = None diff --git a/libmproxy/models/http.py b/libmproxy/models/http.py index 7e46c8345..c0a2c55aa 100644 --- a/libmproxy/models/http.py +++ b/libmproxy/models/http.py @@ -549,7 +549,6 @@ def make_connect_request(address): def make_connect_response(http_version): headers = Headers( - Content_Length="0", Proxy_Agent=version.NAMEVERSION ) return HTTPResponse( diff --git a/libmproxy/protocol/__init__.py b/libmproxy/protocol/__init__.py index 35d59f287..0d624fd7c 100644 --- a/libmproxy/protocol/__init__.py +++ b/libmproxy/protocol/__init__.py @@ -27,13 +27,13 @@ as late as possible; this makes server replay without any outgoing connections p from __future__ import (absolute_import, print_function, division) from .base import Layer, ServerConnectionMixin, Kill -from .http import Http1Layer, Http2Layer +from .http import Http1Layer, UpstreamConnectLayer, Http2Layer from .tls import TlsLayer, is_tls_record_magic from .rawtcp import RawTCPLayer __all__ = [ "Layer", "ServerConnectionMixin", "Kill", - "Http1Layer", "Http2Layer", + "Http1Layer", "UpstreamConnectLayer", "Http2Layer", "TlsLayer", "is_tls_record_magic", "RawTCPLayer" ] diff --git a/libmproxy/protocol/http_replay.py b/libmproxy/protocol/http_replay.py index 00b0b82b8..14fbe5476 100644 --- a/libmproxy/protocol/http_replay.py +++ b/libmproxy/protocol/http_replay.py @@ -1,5 +1,6 @@ from __future__ import (absolute_import, print_function, division) import threading +import traceback from libmproxy.exceptions import ReplayException from netlib.exceptions import HttpException, TcpException from netlib.http import http1 @@ -97,5 +98,8 @@ class RequestReplayThread(threading.Thread): # first place. from ..proxy.root_context import Log self.channel.tell("log", Log("Connection killed", "info")) + except Exception: + from ..proxy.root_context import Log + self.channel.tell("log", Log(traceback.format_exc(), "error")) finally: r.form_out = form_out_backup diff --git a/libmproxy/proxy/root_context.py b/libmproxy/proxy/root_context.py index 48cb72a0f..307d0c4b8 100644 --- a/libmproxy/proxy/root_context.py +++ b/libmproxy/proxy/root_context.py @@ -8,7 +8,8 @@ from libmproxy.exceptions import ProtocolException from netlib.exceptions import TcpException from netlib.http import ALPN_PROTO_H2, ALPN_PROTO_HTTP1 from ..protocol import ( - RawTCPLayer, TlsLayer, Http1Layer, Http2Layer, is_tls_record_magic, ServerConnectionMixin + RawTCPLayer, TlsLayer, Http1Layer, Http2Layer, is_tls_record_magic, ServerConnectionMixin, + UpstreamConnectLayer ) from .modes import HttpProxy, HttpUpstreamProxy, ReverseProxy @@ -63,7 +64,7 @@ class RootContext(object): # in which case we need some form of TLS layer. if isinstance(top_layer, ReverseProxy): return TlsLayer(top_layer, client_tls, top_layer.server_tls) - if isinstance(top_layer, ServerConnectionMixin): + if isinstance(top_layer, ServerConnectionMixin) or isinstance(top_layer, UpstreamConnectLayer): return TlsLayer(top_layer, client_tls, client_tls) # 3. In Http Proxy mode and Upstream Proxy mode, the next layer is fixed. diff --git a/setup.py b/setup.py index 30556c16e..2838ec819 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ from setuptools import setup, find_packages from codecs import open import os +import sys from libmproxy import version # Based on https://github.com/pypa/sampleproject/blob/master/setup.py @@ -47,6 +48,11 @@ dev_deps = { "sphinx-autobuild>=0.5.2", "sphinxcontrib-documentedlist>=0.2", } +example_deps = { + "pytz", + "harparser", + "beautifulsoup4", +} # Add *all* script dependencies to developer dependencies. for script_deps in scripts.values(): dev_deps.update(script_deps) @@ -60,6 +66,9 @@ if os.name == "nt": for script_deps in scripts.values(): deps.update(script_deps) +if sys.version_info < (3, 4): + example_deps.add("enum34") + console_scripts = ["%s = libmproxy.main:%s" % (s, s) for s in scripts.keys()] setup( @@ -101,11 +110,6 @@ setup( "protobuf>=2.5.0", "cssutils>=1.0" ], - 'examples': [ - "pytz", - "harparser", - "beautifulsoup4", - "enum34" - ] + 'examples': list(example_deps) } ) diff --git a/test/test_server.py b/test/test_server.py index d1fef6ff3..34ae46015 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -118,17 +118,18 @@ class TcpMixin: del self._ignore_backup def test_ignore(self): - spec = '304:h"Alternate-Protocol"="mitmproxy-will-remove-this"' - n = self.pathod(spec) + n = self.pathod("304") self._ignore_on() - i = self.pathod(spec) - i2 = self.pathod(spec) + i = self.pathod("305") + i2 = self.pathod("306") self._ignore_off() - assert i.status_code == i2.status_code == n.status_code == 304 - assert "Alternate-Protocol" in i.headers - assert "Alternate-Protocol" in i2.headers - assert "Alternate-Protocol" not in n.headers + assert n.status_code == 304 + assert i.status_code == 305 + assert i2.status_code == 306 + assert any(f.response.status_code == 304 for f in self.master.state.flows) + assert not any(f.response.status_code == 305 for f in self.master.state.flows) + assert not any(f.response.status_code == 306 for f in self.master.state.flows) # Test that we get the original SSL cert if self.ssl: @@ -161,17 +162,18 @@ class TcpMixin: del self._tcpproxy_backup def test_tcp(self): - spec = '304:h"Alternate-Protocol"="mitmproxy-will-remove-this"' - n = self.pathod(spec) + n = self.pathod("304") self._tcpproxy_on() - i = self.pathod(spec) - i2 = self.pathod(spec) + i = self.pathod("305") + i2 = self.pathod("306") self._tcpproxy_off() - assert i.status_code == i2.status_code == n.status_code == 304 - assert "Alternate-Protocol" in i.headers - assert "Alternate-Protocol" in i2.headers - assert "Alternate-Protocol" not in n.headers + assert n.status_code == 304 + assert i.status_code == 305 + assert i2.status_code == 306 + assert any(f.response.status_code == 304 for f in self.master.state.flows) + assert not any(f.response.status_code == 305 for f in self.master.state.flows) + assert not any(f.response.status_code == 306 for f in self.master.state.flows) # Test that we get the original SSL cert if self.ssl: @@ -182,7 +184,8 @@ class TcpMixin: assert i_cert == i2_cert == n_cert # Make sure that TCP messages are in the event log. - assert any("mitmproxy-will-remove-this" in m for m in self.master.log) + assert any("305" in m for m in self.master.log) + assert any("306" in m for m in self.master.log) class AppMixin: @@ -886,23 +889,6 @@ class TestUpstreamProxySSL( # request from chain[0] (regular proxy doesn't store CONNECTs) assert self.chain[1].tmaster.state.flow_count() == 1 - def test_closing_connect_response(self): - """ - https://github.com/mitmproxy/mitmproxy/issues/313 - """ - - def handle_request(f): - f.request.http_version = b"HTTP/1.1" - del f.request.headers["Content-Length"] - f.reply() - - _handle_request = self.chain[0].tmaster.handle_request - self.chain[0].tmaster.handle_request = handle_request - try: - assert self.pathoc().request("get:/p/418").status_code == 418 - finally: - self.chain[0].tmaster.handle_request = _handle_request - class TestProxyChainingSSLReconnect(tservers.HTTPUpstreamProxTest): ssl = True