aboutsummaryrefslogtreecommitdiffstats
path: root/examples/simple
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2016-11-21 02:16:20 +0100
committerMaximilian Hils <git@maximilianhils.com>2016-11-21 02:28:10 +0100
commit9af8f4bb31c94a25780a4189bffa406906249626 (patch)
treecf52f1c312b7bac3d83d796d6b03bb33b4556f26 /examples/simple
parentf74e561524d04c93cd7953f34e78ebe67eaa58a8 (diff)
downloadmitmproxy-9af8f4bb31c94a25780a4189bffa406906249626.tar.gz
mitmproxy-9af8f4bb31c94a25780a4189bffa406906249626.tar.bz2
mitmproxy-9af8f4bb31c94a25780a4189bffa406906249626.zip
organize examples
This commit is largely based on work by Thiago Arrais (@thiagoarrais) and Shane Bradfield (@l33tLumberjack). I wasn't really able to get their PR reasonably merged onto the latest master, so I reapplied their changes manually here and did some further improvements on that.
Diffstat (limited to 'examples/simple')
-rw-r--r--examples/simple/README.md18
-rw-r--r--examples/simple/add_header.py2
-rw-r--r--examples/simple/add_header_class.py7
-rw-r--r--examples/simple/custom_contentview.py28
-rw-r--r--examples/simple/filter_flows.py23
-rw-r--r--examples/simple/io_read_dumpfile.py21
-rw-r--r--examples/simple/io_write_dumpfile.py29
-rw-r--r--examples/simple/logging.py12
-rw-r--r--examples/simple/modify_body_inject_iframe.py29
-rw-r--r--examples/simple/modify_form.py10
-rw-r--r--examples/simple/modify_querystring.py2
-rw-r--r--examples/simple/redirect_requests.py11
-rw-r--r--examples/simple/script_arguments.py17
-rw-r--r--examples/simple/send_reply_from_proxy.py17
-rw-r--r--examples/simple/upsidedownternet.py16
-rw-r--r--examples/simple/wsgi_flask_app.py25
16 files changed, 267 insertions, 0 deletions
diff --git a/examples/simple/README.md b/examples/simple/README.md
new file mode 100644
index 00000000..52f15627
--- /dev/null
+++ b/examples/simple/README.md
@@ -0,0 +1,18 @@
+## Simple Examples
+
+| Filename | Description |
+|:-----------------------------|:---------------------------------------------------------------------------|
+| add_header.py | Simple script that just adds a header to every request. |
+| custom_contentview.py | Add a custom content view to the mitmproxy UI. |
+| filter_flows.py | This script demonstrates how to use mitmproxy's filter pattern in scripts. |
+| io_read_dumpfile.py | Read a dumpfile generated by mitmproxy. |
+| io_write_dumpfile.py | Only write selected flows into a mitmproxy dumpfile. |
+| logging.py | Use mitmproxy's logging API. |
+| modify_body_inject_iframe.py | Inject configurable iframe into pages. |
+| modify_form.py | Modify HTTP form submissions. |
+| modify_querystring.py | Modify HTTP query strings. |
+| redirect_requests.py | Redirect a request to a different server. |
+| script_arguments.py | Add arguments to a script. |
+| send_reply_from_proxy.py | Send a HTTP response directly from the proxy. |
+| upsidedownternet.py | Turn all images upside down. |
+| wsgi_flask_app.py | Embed a WSGI app into mitmproxy. | \ No newline at end of file
diff --git a/examples/simple/add_header.py b/examples/simple/add_header.py
new file mode 100644
index 00000000..3e0b5f1e
--- /dev/null
+++ b/examples/simple/add_header.py
@@ -0,0 +1,2 @@
+def response(flow):
+ flow.response.headers["newheader"] = "foo"
diff --git a/examples/simple/add_header_class.py b/examples/simple/add_header_class.py
new file mode 100644
index 00000000..6443798a
--- /dev/null
+++ b/examples/simple/add_header_class.py
@@ -0,0 +1,7 @@
+class AddHeader:
+ def response(self, flow):
+ flow.response.headers["newheader"] = "foo"
+
+
+def start():
+ return AddHeader()
diff --git a/examples/simple/custom_contentview.py b/examples/simple/custom_contentview.py
new file mode 100644
index 00000000..35216397
--- /dev/null
+++ b/examples/simple/custom_contentview.py
@@ -0,0 +1,28 @@
+"""
+This example shows how one can add a custom contentview to mitmproxy.
+The content view API is explained in the mitmproxy.contentviews module.
+"""
+from mitmproxy import contentviews
+
+
+class ViewSwapCase(contentviews.View):
+ name = "swapcase"
+
+ # We don't have a good solution for the keyboard shortcut yet -
+ # you manually need to find a free letter. Contributions welcome :)
+ prompt = ("swap case text", "p")
+ content_types = ["text/plain"]
+
+ def __call__(self, data: bytes, **metadata):
+ return "case-swapped text", contentviews.format_text(data.swapcase())
+
+
+view = ViewSwapCase()
+
+
+def start():
+ contentviews.add(view)
+
+
+def done():
+ contentviews.remove(view)
diff --git a/examples/simple/filter_flows.py b/examples/simple/filter_flows.py
new file mode 100644
index 00000000..29d0a9b8
--- /dev/null
+++ b/examples/simple/filter_flows.py
@@ -0,0 +1,23 @@
+"""
+This scripts demonstrates how to use mitmproxy's filter pattern in scripts.
+Usage:
+ mitmdump -s "flowfilter.py FILTER"
+"""
+import sys
+from mitmproxy import flowfilter
+
+
+class Filter:
+ def __init__(self, spec):
+ self.filter = flowfilter.parse(spec)
+
+ def response(self, flow):
+ if flowfilter.match(self.filter, flow):
+ print("Flow matches filter:")
+ print(flow)
+
+
+def start():
+ if len(sys.argv) != 2:
+ raise ValueError("Usage: -s 'filt.py FILTER'")
+ return Filter(sys.argv[1])
diff --git a/examples/simple/io_read_dumpfile.py b/examples/simple/io_read_dumpfile.py
new file mode 100644
index 00000000..edbbe2dd
--- /dev/null
+++ b/examples/simple/io_read_dumpfile.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+#
+# Simple script showing how to read a mitmproxy dump file
+#
+
+from mitmproxy import io
+from mitmproxy.exceptions import FlowReadException
+import pprint
+import sys
+
+with open(sys.argv[1], "rb") as logfile:
+ freader = io.FlowReader(logfile)
+ pp = pprint.PrettyPrinter(indent=4)
+ try:
+ for f in freader.stream():
+ print(f)
+ print(f.request.host)
+ pp.pprint(f.get_state())
+ print("")
+ except FlowReadException as e:
+ print("Flow file corrupted: {}".format(e))
diff --git a/examples/simple/io_write_dumpfile.py b/examples/simple/io_write_dumpfile.py
new file mode 100644
index 00000000..ff1fd0f4
--- /dev/null
+++ b/examples/simple/io_write_dumpfile.py
@@ -0,0 +1,29 @@
+"""
+This script how to generate a mitmproxy dump file,
+as it would also be generated by passing `-w` to mitmproxy.
+In contrast to `-w`, this gives you full control over which
+flows should be saved and also allows you to rotate files or log
+to multiple files in parallel.
+"""
+import random
+import sys
+from mitmproxy import io
+
+
+class Writer:
+ def __init__(self, path):
+ if path == "-":
+ f = sys.stdout
+ else:
+ f = open(path, "wb")
+ self.w = io.FlowWriter(f)
+
+ def response(self, flow):
+ if random.choice([True, False]):
+ self.w.add(flow)
+
+
+def start():
+ if len(sys.argv) != 2:
+ raise ValueError('Usage: -s "flowriter.py filename"')
+ return Writer(sys.argv[1])
diff --git a/examples/simple/logging.py b/examples/simple/logging.py
new file mode 100644
index 00000000..ab1baf75
--- /dev/null
+++ b/examples/simple/logging.py
@@ -0,0 +1,12 @@
+"""
+It is recommended to use `ctx.log` for logging within a script.
+This goes to the event log in mitmproxy and to stdout in mitmdump.
+
+If you want to help us out: https://github.com/mitmproxy/mitmproxy/issues/1530 :-)
+"""
+from mitmproxy import ctx
+
+
+def start():
+ ctx.log.info("This is some informative text.")
+ ctx.log.error("This is an error.")
diff --git a/examples/simple/modify_body_inject_iframe.py b/examples/simple/modify_body_inject_iframe.py
new file mode 100644
index 00000000..33d18bbd
--- /dev/null
+++ b/examples/simple/modify_body_inject_iframe.py
@@ -0,0 +1,29 @@
+# Usage: mitmdump -s "iframe_injector.py url"
+# (this script works best with --anticache)
+import sys
+from bs4 import BeautifulSoup
+
+
+class Injector:
+ def __init__(self, iframe_url):
+ self.iframe_url = iframe_url
+
+ def response(self, flow):
+ if flow.request.host in self.iframe_url:
+ return
+ html = BeautifulSoup(flow.response.content, "lxml")
+ if html.body:
+ iframe = html.new_tag(
+ "iframe",
+ src=self.iframe_url,
+ frameborder=0,
+ height=0,
+ width=0)
+ html.body.insert(0, iframe)
+ flow.response.content = str(html).encode("utf8")
+
+
+def start():
+ if len(sys.argv) != 2:
+ raise ValueError('Usage: -s "iframe_injector.py url"')
+ return Injector(sys.argv[1])
diff --git a/examples/simple/modify_form.py b/examples/simple/modify_form.py
new file mode 100644
index 00000000..b425efb0
--- /dev/null
+++ b/examples/simple/modify_form.py
@@ -0,0 +1,10 @@
+def request(flow):
+ if flow.request.urlencoded_form:
+ # If there's already a form, one can just add items to the dict:
+ flow.request.urlencoded_form["mitmproxy"] = "rocks"
+ else:
+ # One can also just pass new form data.
+ # This sets the proper content type and overrides the body.
+ flow.request.urlencoded_form = [
+ ("foo", "bar")
+ ]
diff --git a/examples/simple/modify_querystring.py b/examples/simple/modify_querystring.py
new file mode 100644
index 00000000..ee8a89ad
--- /dev/null
+++ b/examples/simple/modify_querystring.py
@@ -0,0 +1,2 @@
+def request(flow):
+ flow.request.query["mitmproxy"] = "rocks"
diff --git a/examples/simple/redirect_requests.py b/examples/simple/redirect_requests.py
new file mode 100644
index 00000000..51876df7
--- /dev/null
+++ b/examples/simple/redirect_requests.py
@@ -0,0 +1,11 @@
+"""
+This example shows two ways to redirect flows to another server.
+"""
+
+
+def request(flow):
+ # pretty_host takes the "Host" header of the request into account,
+ # which is useful in transparent mode where we usually only have the IP
+ # otherwise.
+ if flow.request.pretty_host == "example.org":
+ flow.request.host = "mitmproxy.org"
diff --git a/examples/simple/script_arguments.py b/examples/simple/script_arguments.py
new file mode 100644
index 00000000..70851192
--- /dev/null
+++ b/examples/simple/script_arguments.py
@@ -0,0 +1,17 @@
+import argparse
+
+
+class Replacer:
+ def __init__(self, src, dst):
+ self.src, self.dst = src, dst
+
+ def response(self, flow):
+ flow.response.replace(self.src, self.dst)
+
+
+def start():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("src", type=str)
+ parser.add_argument("dst", type=str)
+ args = parser.parse_args()
+ return Replacer(args.src, args.dst)
diff --git a/examples/simple/send_reply_from_proxy.py b/examples/simple/send_reply_from_proxy.py
new file mode 100644
index 00000000..bef2e7e7
--- /dev/null
+++ b/examples/simple/send_reply_from_proxy.py
@@ -0,0 +1,17 @@
+"""
+This example shows how to send a reply from the proxy immediately
+without sending any data to the remote server.
+"""
+from mitmproxy import http
+
+
+def request(flow):
+ # pretty_url takes the "Host" header of the request into account, which
+ # is useful in transparent mode where we usually only have the IP otherwise.
+
+ if flow.request.pretty_url == "http://example.com/path":
+ flow.response = http.HTTPResponse.make(
+ 200, # (optional) status code
+ b"Hello World", # (optional) content
+ {"Content-Type": "text/html"} # (optional) headers
+ )
diff --git a/examples/simple/upsidedownternet.py b/examples/simple/upsidedownternet.py
new file mode 100644
index 00000000..8ba450ab
--- /dev/null
+++ b/examples/simple/upsidedownternet.py
@@ -0,0 +1,16 @@
+"""
+This script rotates all images passing through the proxy by 180 degrees.
+"""
+import io
+
+from PIL import Image
+
+
+def response(flow):
+ if flow.response.headers.get("content-type", "").startswith("image"):
+ s = io.BytesIO(flow.response.content)
+ img = Image.open(s).rotate(180)
+ s2 = io.BytesIO()
+ img.save(s2, "png")
+ flow.response.content = s2.getvalue()
+ flow.response.headers["content-type"] = "image/png"
diff --git a/examples/simple/wsgi_flask_app.py b/examples/simple/wsgi_flask_app.py
new file mode 100644
index 00000000..f95c41e5
--- /dev/null
+++ b/examples/simple/wsgi_flask_app.py
@@ -0,0 +1,25 @@
+"""
+This example shows how to graft a WSGI app onto mitmproxy. In this
+instance, we're using the Flask framework (http://flask.pocoo.org/) to expose
+a single simplest-possible page.
+"""
+from flask import Flask
+from mitmproxy.addons import wsgiapp
+
+app = Flask("proxapp")
+
+
+@app.route('/')
+def hello_world():
+ return 'Hello World!'
+
+
+def start():
+ # Host app at the magic domain "proxapp" on port 80. Requests to this
+ # domain and port combination will now be routed to the WSGI app instance.
+ return wsgiapp.WSGIApp(app, "proxapp", 80)
+
+ # SSL works too, but the magic domain needs to be resolvable from the mitmproxy machine due to mitmproxy's design.
+ # mitmproxy will connect to said domain and use serve its certificate (unless --no-upstream-cert is set)
+ # but won't send any data.
+ # mitmproxy.ctx.master.apps.add(app, "example.com", 443)