diff options
-rw-r--r-- | examples/redirect_requests.py | 4 | ||||
-rw-r--r-- | examples/sslstrip.py | 40 | ||||
-rw-r--r-- | libmproxy/console/__init__.py | 9 | ||||
-rw-r--r-- | libmproxy/dump.py | 12 | ||||
-rw-r--r-- | libmproxy/flow.py | 12 | ||||
-rw-r--r-- | libmproxy/protocol/http.py | 6 | ||||
-rw-r--r-- | libmproxy/web/__init__.py | 10 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | test/test_protocol_http.py | 8 |
9 files changed, 80 insertions, 23 deletions
diff --git a/examples/redirect_requests.py b/examples/redirect_requests.py index 5cc81633..a3145083 100644 --- a/examples/redirect_requests.py +++ b/examples/redirect_requests.py @@ -12,11 +12,11 @@ def request(context, flow): # Method 1: Answer with a locally generated response if flow.request.pretty_host.endswith("example.com"): resp = HTTPResponse( - [1, 1], 200, "OK", + "HTTP/1.1", 200, "OK", Headers(Content_Type="text/html"), "helloworld") flow.reply(resp) # Method 2: Redirect the request to a different server if flow.request.pretty_host.endswith("example.org"): - flow.request.host = "mitmproxy.org"
\ No newline at end of file + flow.request.host = "mitmproxy.org" diff --git a/examples/sslstrip.py b/examples/sslstrip.py new file mode 100644 index 00000000..369427a2 --- /dev/null +++ b/examples/sslstrip.py @@ -0,0 +1,40 @@ +from netlib.http import decoded +import re +from six.moves import urllib + +def start(context, argv) : + + #set of SSL/TLS capable hosts + context.secure_hosts = set() + +def request(context, flow) : + + flow.request.headers.pop('If-Modified-Since', None) + flow.request.headers.pop('Cache-Control', None) + + #proxy connections to SSL-enabled hosts + if flow.request.pretty_host in context.secure_hosts : + flow.request.scheme = 'https' + flow.request.port = 443 + +def response(context, flow) : + + with decoded(flow.response) : + flow.request.headers.pop('Strict-Transport-Security', None) + flow.request.headers.pop('Public-Key-Pins', None) + + #strip links in response body + flow.response.content = flow.response.content.replace('https://', 'http://') + + #strip links in 'Location' header + if flow.response.headers.get('Location','').startswith('https://'): + location = flow.response.headers['Location'] + hostname = urllib.parse.urlparse(location).hostname + if hostname: + context.secure_hosts.add(hostname) + flow.response.headers['Location'] = location.replace('https://', 'http://', 1) + + #strip secure flag from 'Set-Cookie' headers + cookies = flow.response.headers.get_all('Set-Cookie') + cookies = [re.sub(r';\s*secure\s*', '', s) for s in cookies] + flow.response.headers.set_all('Set-Cookie', cookies) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index cef2013e..31edca81 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -290,15 +290,6 @@ class ConsoleMaster(flow.FlowMaster): self.loop.widget = window self.loop.draw_screen() - def start_stream_to_path(self, path, mode="wb"): - path = os.path.expanduser(path) - try: - f = file(path, mode) - self.start_stream(f, None) - except IOError as v: - return str(v) - self.stream_path = path - def _run_script_method(self, method, s, f): status, val = s.run(method, f) if val: diff --git a/libmproxy/dump.py b/libmproxy/dump.py index 22a2b75c..c2a3268a 100644 --- a/libmproxy/dump.py +++ b/libmproxy/dump.py @@ -85,12 +85,12 @@ class DumpMaster(flow.FlowMaster): self.set_stickyauth(options.stickyauth) if options.outfile: - path = os.path.expanduser(options.outfile[0]) - try: - f = open(path, options.outfile[1]) - self.start_stream(f, self.filt) - except IOError as v: - raise DumpError(v.strerror) + err = self.start_stream_to_path( + options.outfile[0], + options.outfile[1] + ) + if err: + raise DumpError(err) if options.replacements: for i in options.replacements: diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 9815a298..8e066191 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -665,7 +665,7 @@ class FlowMaster(controller.Master): self.add_event("Script error:\n" + str(e), "error") script.reloader.unwatch(script_obj) self.scripts.remove(script_obj) - + def load_script(self, command, use_reloader=False): """ Loads a script. Returns an error description if something went @@ -1070,6 +1070,16 @@ class FlowMaster(controller.Master): self.stream.fo.close() self.stream = None + def start_stream_to_path(self, path, mode="wb"): + path = os.path.expanduser(path) + try: + f = file(path, mode) + self.start_stream(f, None) + except IOError as v: + return str(v) + self.stream_path = path + + def read_flows_from_paths(paths): """ Given a list of filepaths, read all flows and return a list of them. diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index d3fd4b37..d72adc37 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -53,7 +53,7 @@ class _StreamingHttpLayer(_HttpLayer): def read_response(self, request): response = self.read_response_headers() - response.content = b"".join( + response.data.content = b"".join( self.read_response_body(request, response) ) return response @@ -469,9 +469,9 @@ class HttpLayer(Layer): if self.supports_streaming: if flow.response.stream: - flow.response.content = CONTENT_MISSING + flow.response.data.content = CONTENT_MISSING else: - flow.response.content = b"".join(self.read_response_body( + flow.response.data.content = b"".join(self.read_response_body( flow.request, flow.response )) diff --git a/libmproxy/web/__init__.py b/libmproxy/web/__init__.py index a0af7315..90da6ffe 100644 --- a/libmproxy/web/__init__.py +++ b/libmproxy/web/__init__.py @@ -134,6 +134,16 @@ class WebMaster(flow.FlowMaster): "Could not read flow file: %s" % v, "error" ) + + if options.outfile: + err = self.start_stream_to_path( + options.outfile[0], + options.outfile[1] + ) + if err: + print >> sys.stderr, "Stream file error:", err + sys.exit(1) + if self.options.app: self.start_app(self.options.app_host, self.options.app_port) @@ -26,7 +26,7 @@ deps = { "construct>=2.5.2, <2.6", "six>=1.10.0, <1.11", "lxml==3.4.4", # there are no Windows wheels for newer versions, so we pin this. - "Pillow>=3.0.0, <3.1", + "Pillow>=3.0.0, <3.2", "watchdog>=0.8.3, <0.9", } # A script -> additional dependencies dict. diff --git a/test/test_protocol_http.py b/test/test_protocol_http.py index 8c843d73..1f0386b4 100644 --- a/test/test_protocol_http.py +++ b/test/test_protocol_http.py @@ -1,7 +1,6 @@ import socket from io import BytesIO from netlib.exceptions import HttpSyntaxException - from netlib.http import http1 from netlib.tcp import TCPClient from netlib.tutils import treq, raises @@ -82,3 +81,10 @@ class TestExpectHeader(tservers.HTTPProxTest): assert resp.status_code == 200 client.finish() + + +class TestHeadContentLength(tservers.HTTPProxTest): + def test_head_content_length(self): + p = self.pathoc() + resp = p.request("""head:'%s/p/200:h"Content-Length"="42"'""" % self.server.urlbase) + assert resp.headers["Content-Length"] == "42"
\ No newline at end of file |