update examples, fix #353

This commit is contained in:
Maximilian Hils 2014-09-08 16:02:31 +02:00
parent d06b4bfa4e
commit ebd539b49f
20 changed files with 140 additions and 132 deletions

View File

@ -1,10 +1,23 @@
# inline script examples
add_header.py Simple script that just adds a header to every request. add_header.py Simple script that just adds a header to every request.
change_upstream_proxy.py Dynamically change the upstream proxy
dup_and_replay.py Duplicates each request, changes it, and then replays the modified request. dup_and_replay.py Duplicates each request, changes it, and then replays the modified request.
flowbasic Basic use of mitmproxy as a library. iframe_injector.py Inject configurable iframe into pages.
modify_form.py Modify all form submissions to add a parameter. modify_form.py Modify all form submissions to add a parameter.
modify_querystring.py Modify all query strings to add a parameters. modify_querystring.py Modify all query strings to add a parameters.
proxapp How to embed a WSGI app in a mitmproxy server modify_response_body.py Replace arbitrary strings in all responses
nonblocking.py Demonstrate parallel processing with a blocking script.
proxapp.py How to embed a WSGI app in a mitmproxy server
redirect_requests.py Redirect requests or directly reply to them.
stub.py Script stub with a method definition for every event. stub.py Script stub with a method definition for every event.
upsidedownternet.py Rewrites traffic to turn images upside down.
# libmproxy examples
flowbasic Basic use of mitmproxy as a library.
stickycookies An example of writing a custom proxy with libmproxy. stickycookies An example of writing a custom proxy with libmproxy.
upsidedownternet.py Rewrites traffic to turn PNGs upside down.
# misc
read_dumpfile Read a dumpfile generated by mitmproxy.
mitmproxywrapper.py Bracket mitmproxy run with proxy enable/disable on OS X mitmproxywrapper.py Bracket mitmproxy run with proxy enable/disable on OS X

View File

@ -1,2 +1,2 @@
def response(ctx, flow): def response(context, flow):
flow.response.headers["newheader"] = ["foo"] flow.response.headers["newheader"] = ["foo"]

View File

@ -4,11 +4,12 @@
# Usage: mitmdump -s "change_upstream_proxy.py host" # Usage: mitmdump -s "change_upstream_proxy.py host"
from libmproxy.protocol.http import send_connect_request from libmproxy.protocol.http import send_connect_request
alternative_upstream_proxy = ("localhost", 8082)
def should_redirect(flow): def should_redirect(flow):
return (flow.request.host == "example.com") return flow.request.host == "example.com"
alternative_upstream_proxy = ("localhost",8082)
def request(ctx, flow):
def request(context, flow):
if flow.live and should_redirect(flow): if flow.live and should_redirect(flow):
# If you want to change the target server, you should modify flow.request.host and flow.request.port # If you want to change the target server, you should modify flow.request.host and flow.request.port

View File

@ -1,4 +1,4 @@
def request(ctx, flow): def request(context, flow):
f = ctx.duplicate_flow(flow) f = context.duplicate_flow(flow)
f.request.path = "/changed" f.request.path = "/changed"
ctx.replay_request(f) context.replay_request(f)

View File

@ -12,6 +12,7 @@ import os
from libmproxy import flow, proxy from libmproxy import flow, proxy
from libmproxy.proxy.server import ProxyServer from libmproxy.proxy.server import ProxyServer
class MyMaster(flow.FlowMaster): class MyMaster(flow.FlowMaster):
def run(self): def run(self):
try: try:
@ -34,7 +35,7 @@ class MyMaster(flow.FlowMaster):
config = proxy.ProxyConfig( config = proxy.ProxyConfig(
ca_file = os.path.expanduser("~/.mitmproxy/mitmproxy-ca.pem") ca_file=os.path.expanduser("~/.mitmproxy/mitmproxy-ca.pem")
) )
state = flow.State() state = flow.State()
server = ProxyServer(config, 8080) server = ProxyServer(config, 8080)

View File

@ -3,16 +3,16 @@
from libmproxy.protocol.http import decoded from libmproxy.protocol.http import decoded
def start(ctx, argv): def start(context, argv):
if len(argv) != 2: if len(argv) != 2:
raise ValueError('Usage: -s "iframe_injector.py url"') raise ValueError('Usage: -s "iframe_injector.py url"')
ctx.iframe_url = argv[1] context.iframe_url = argv[1]
def handle_response(ctx, flow): def handle_response(context, flow):
with decoded(flow.response): # Remove content encoding (gzip, ...) with decoded(flow.response): # Remove content encoding (gzip, ...)
c = flow.response.replace( c = flow.response.replace(
'<body>', '<body>',
'<body><iframe src="%s" frameborder="0" height="0" width="0"></iframe>' % ctx.iframe_url) '<body><iframe src="%s" frameborder="0" height="0" width="0"></iframe>' % context.iframe_url)
if c > 0: if c > 0:
ctx.log("Iframe injected!") context.log("Iframe injected!")

View File

@ -1,5 +1,5 @@
def request(ctx, flow): def request(context, flow):
if "application/x-www-form-urlencoded" in flow.request.headers["content-type"]: if "application/x-www-form-urlencoded" in flow.request.headers["content-type"]:
form = flow.request.get_form_urlencoded() form = flow.request.get_form_urlencoded()
form["mitmproxy"] = ["rocks"] form["mitmproxy"] = ["rocks"]

View File

@ -1,5 +1,5 @@
def request(ctx, flow): def request(context, flow):
q = flow.request.get_query() q = flow.request.get_query()
if q: if q:
q["mitmproxy"] = ["rocks"] q["mitmproxy"] = ["rocks"]

View File

@ -3,13 +3,13 @@
from libmproxy.protocol.http import decoded from libmproxy.protocol.http import decoded
def start(ctx, argv): def start(context, argv):
if len(argv) != 3: if len(argv) != 3:
raise ValueError('Usage: -s "modify-response-body.py old new"') raise ValueError('Usage: -s "modify-response-body.py old new"')
# You may want to use Python's argparse for more sophisticated argument parsing. # You may want to use Python's argparse for more sophisticated argument parsing.
ctx.old, ctx.new = argv[1], argv[2] context.old, context.new = argv[1], argv[2]
def response(ctx, flow): def response(context, flow):
with decoded(flow.response): # automatically decode gzipped responses. with decoded(flow.response): # automatically decode gzipped responses.
flow.response.content = flow.response.content.replace(ctx.old, ctx.new) flow.response.content = flow.response.content.replace(context.old, context.new)

View File

@ -2,7 +2,7 @@ import time
from libmproxy.script import concurrent from libmproxy.script import concurrent
@concurrent @concurrent # Remove this and see what happens
def request(context, flow): def request(context, flow):
print "handle request: %s%s" % (flow.request.host, flow.request.path) print "handle request: %s%s" % (flow.request.host, flow.request.path)
time.sleep(5) time.sleep(5)

View File

@ -1,47 +0,0 @@
#!/usr/bin/env python
"""
This example shows how to graft a WSGI app onto mitmproxy. In this
instance, we're using the Bottle framework (http://bottlepy.org/) to expose
a single simplest-possible page.
"""
import bottle
import os
from libmproxy import proxy, flow
@bottle.route('/')
def index():
return 'Hi!'
class MyMaster(flow.FlowMaster):
def run(self):
try:
flow.FlowMaster.run(self)
except KeyboardInterrupt:
self.shutdown()
def handle_request(self, f):
f = flow.FlowMaster.handle_request(self, f)
if f:
f.reply()
return f
def handle_response(self, f):
f = flow.FlowMaster.handle_response(self, f)
if f:
f.reply()
print f
return f
config = proxy.ProxyConfig(
cacert = os.path.expanduser("~/.mitmproxy/mitmproxy-ca.pem")
)
state = flow.State()
server = proxy.ProxyServer(config, 8080)
# Register the app using the magic domain "proxapp" on port 80. Requests to
# this domain and port combination will now be routed to the WSGI app instance.
server.apps.add(bottle.app(), "proxapp", 80)
m = MyMaster(server, state)
m.run()

24
examples/proxapp.py Normal file
View File

@ -0,0 +1,24 @@
"""
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
app = Flask("proxapp")
@app.route('/')
def hello_world():
return 'Hello World!'
# Register the app using the magic domain "proxapp" on port 80. Requests to
# this domain and port combination will now be routed to the WSGI app instance.
def start(context, argv):
context.app_registry.add(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.
context.app_registry.add(app, "example.com", 443)

View File

@ -6,12 +6,13 @@
from libmproxy import flow from libmproxy import flow
import json, sys import json, sys
with open("logfile", "rb") as f: with open("logfile", "rb") as logfile:
freader = flow.FlowReader(f) freader = flow.FlowReader(logfile)
try: try:
for i in freader.stream(): for f in freader.stream():
print i.request.host print(f)
json.dump(i._get_state(), sys.stdout, indent=4) print(f.request.host)
json.dump(f._get_state(), sys.stdout, indent=4)
print "" print ""
except flow.FlowReadError, v: except flow.FlowReadError, v:
print "Flow file corrupted. Stopped loading." print "Flow file corrupted. Stopped loading."

View File

@ -6,15 +6,19 @@ This example shows two ways to redirect flows to other destinations.
""" """
def request(ctx, flow): def request(context, flow):
# pretty_host(hostheader=True) takes the Host: header of the request into account, # pretty_host(hostheader=True) takes the Host: header of the request into account,
# which is useful in transparent mode where we usually only have the IP otherwise. # which is useful in transparent mode where we usually only have the IP otherwise.
# Method 1: Answer with a locally generated response
if flow.request.pretty_host(hostheader=True).endswith("example.com"): if flow.request.pretty_host(hostheader=True).endswith("example.com"):
resp = HTTPResponse( resp = HTTPResponse(
[1, 1], 200, "OK", [1, 1], 200, "OK",
ODictCaseless([["Content-Type", "text/html"]]), ODictCaseless([["Content-Type", "text/html"]]),
"helloworld") "helloworld")
flow.reply(resp) flow.reply(resp)
# Method 2: Redirect the request to a different server
if flow.request.pretty_host(hostheader=True).endswith("example.org"): if flow.request.pretty_host(hostheader=True).endswith("example.org"):
flow.request.host = "mitmproxy.org" flow.request.host = "mitmproxy.org"
flow.request.update_host_header() flow.request.update_host_header()

View File

@ -1,9 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
This example builds on mitmproxy's base proxying infrastructure to This example builds on mitmproxy's base proxying infrastructure to
implement functionality similar to the "sticky cookies" option. This is at implement functionality similar to the "sticky cookies" option.
a lower level than the Flow mechanism, so we're dealing directly with
request and response objects. Heads Up: In the majority of cases, you want to use inline scripts.
""" """
import os import os
from libmproxy import controller, proxy from libmproxy import controller, proxy
@ -21,19 +21,19 @@ class StickyMaster(controller.Master):
except KeyboardInterrupt: except KeyboardInterrupt:
self.shutdown() self.shutdown()
def handle_request(self, msg): def handle_request(self, flow):
hid = (msg.host, msg.port) hid = (flow.request.host, flow.request.port)
if msg.headers["cookie"]: if flow.request.headers["cookie"]:
self.stickyhosts[hid] = msg.headers["cookie"] self.stickyhosts[hid] = flow.request.headers["cookie"]
elif hid in self.stickyhosts: elif hid in self.stickyhosts:
msg.headers["cookie"] = self.stickyhosts[hid] flow.request.headers["cookie"] = self.stickyhosts[hid]
msg.reply() flow.reply()
def handle_response(self, msg): def handle_response(self, flow):
hid = (msg.request.host, msg.request.port) hid = (flow.request.host, flow.request.port)
if msg.headers["set-cookie"]: if flow.response.headers["set-cookie"]:
self.stickyhosts[hid] = msg.headers["set-cookie"] self.stickyhosts[hid] = flow.response.headers["set-cookie"]
msg.reply() flow.reply()
config = proxy.ProxyConfig( config = proxy.ProxyConfig(

View File

@ -1,4 +1,4 @@
def responseheaders(ctx, flow): def responseheaders(context, flow):
""" """
Enables streaming for all responses. Enables streaming for all responses.
""" """

View File

@ -1,63 +1,63 @@
""" """
This is a script stub, with definitions for all events. This is a script stub, with definitions for all events.
""" """
def start(ctx, argv): def start(context, argv):
""" """
Called once on script startup, before any other events. Called once on script startup, before any other events.
""" """
ctx.log("start") context.log("start")
def clientconnect(ctx, conn_handler): def clientconnect(context, conn_handler):
""" """
Called when a client initiates a connection to the proxy. Note that a Called when a client initiates a connection to the proxy. Note that a
connection can correspond to multiple HTTP requests connection can correspond to multiple HTTP requests
""" """
ctx.log("clientconnect") context.log("clientconnect")
def serverconnect(ctx, conn_handler): def serverconnect(context, conn_handler):
""" """
Called when the proxy initiates a connection to the target server. Note that a Called when the proxy initiates a connection to the target server. Note that a
connection can correspond to multiple HTTP requests connection can correspond to multiple HTTP requests
""" """
ctx.log("serverconnect") context.log("serverconnect")
def request(ctx, flow): def request(context, flow):
""" """
Called when a client request has been received. Called when a client request has been received.
""" """
ctx.log("request") context.log("request")
def responseheaders(ctx, flow): def responseheaders(context, flow):
""" """
Called when the response headers for a server response have been received, Called when the response headers for a server response have been received,
but the response body has not been processed yet. Can be used to tell mitmproxy but the response body has not been processed yet. Can be used to tell mitmproxy
to stream the response. to stream the response.
""" """
ctx.log("responseheaders") context.log("responseheaders")
def response(ctx, flow): def response(context, flow):
""" """
Called when a server response has been received. Called when a server response has been received.
""" """
ctx.log("response") context.log("response")
def error(ctx, flow): def error(context, flow):
""" """
Called when a flow error has occured, e.g. invalid server responses, or Called when a flow error has occured, e.g. invalid server responses, or
interrupted connections. This is distinct from a valid server HTTP error interrupted connections. This is distinct from a valid server HTTP error
response, which is simply a response with an HTTP error code. response, which is simply a response with an HTTP error code.
""" """
ctx.log("error") context.log("error")
def clientdisconnect(ctx, conn_handler): def clientdisconnect(context, conn_handler):
""" """
Called when a client disconnects from the proxy. Called when a client disconnects from the proxy.
""" """
ctx.log("clientdisconnect") context.log("clientdisconnect")
def done(ctx): def done(context):
""" """
Called once on script shutdown, after any other events. Called once on script shutdown, after any other events.
""" """
ctx.log("done") context.log("done")

View File

@ -1,10 +1,16 @@
import cStringIO import cStringIO
from PIL import Image from PIL import Image
from libmproxy.protocol.http import decoded
def response(ctx, flow): def response(context, flow):
if flow.response.headers["content-type"] == ["image/png"]: if flow.response.headers.get_first("content-type", "").startswith("image"):
with decoded(flow.response): # automatically decode gzipped responses.
try:
s = cStringIO.StringIO(flow.response.content) s = cStringIO.StringIO(flow.response.content)
img = Image.open(s).rotate(180) img = Image.open(s).rotate(180)
s2 = cStringIO.StringIO() s2 = cStringIO.StringIO()
img.save(s2, "png") img.save(s2, "png")
flow.response.content = s2.getvalue() flow.response.content = s2.getvalue()
flow.response.headers["content-type"] = ["image/png"]
except: # Unknown image types etc.
pass

View File

@ -1095,7 +1095,8 @@ class HTTPHandler(ProtocolHandler):
if request.form_in == "absolute": if request.form_in == "absolute":
if request.scheme != "http": if request.scheme != "http":
raise http.HttpError(400, "Invalid request scheme: %s" % request.scheme) raise http.HttpError(400, "Invalid request scheme: %s" % request.scheme)
if request.form_out == "relative": if self.c.config.mode == "regular":
# Update info so that an inline script sees the correct value at flow.server_conn
self.c.set_server_address((request.host, request.port)) self.c.set_server_address((request.host, request.port))
flow.server_conn = self.c.server_conn flow.server_conn = self.c.server_conn

View File

@ -38,6 +38,10 @@ class ScriptContext:
""" """
self._master.replay_request(f) self._master.replay_request(f)
@property
def app_registry(self):
return self._master.apps
class Script: class Script:
""" """