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.
change_upstream_proxy.py Dynamically change the upstream proxy
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_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.
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.
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

View File

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

View File

@ -4,11 +4,12 @@
# Usage: mitmdump -s "change_upstream_proxy.py host"
from libmproxy.protocol.http import send_connect_request
def should_redirect(flow):
return (flow.request.host == "example.com")
alternative_upstream_proxy = ("localhost", 8082)
def should_redirect(flow):
return flow.request.host == "example.com"
def request(ctx, flow):
def request(context, 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

View File

@ -1,4 +1,4 @@
def request(ctx, flow):
f = ctx.duplicate_flow(flow)
def request(context, flow):
f = context.duplicate_flow(flow)
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.proxy.server import ProxyServer
class MyMaster(flow.FlowMaster):
def run(self):
try:

View File

@ -3,16 +3,16 @@
from libmproxy.protocol.http import decoded
def start(ctx, argv):
def start(context, argv):
if len(argv) != 2:
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, ...)
c = flow.response.replace(
'<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:
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"]:
form = flow.request.get_form_urlencoded()
form["mitmproxy"] = ["rocks"]

View File

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

View File

@ -3,13 +3,13 @@
from libmproxy.protocol.http import decoded
def start(ctx, argv):
def start(context, argv):
if len(argv) != 3:
raise ValueError('Usage: -s "modify-response-body.py old new"')
# 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.
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
@concurrent
@concurrent # Remove this and see what happens
def request(context, flow):
print "handle request: %s%s" % (flow.request.host, flow.request.path)
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
import json, sys
with open("logfile", "rb") as f:
freader = flow.FlowReader(f)
with open("logfile", "rb") as logfile:
freader = flow.FlowReader(logfile)
try:
for i in freader.stream():
print i.request.host
json.dump(i._get_state(), sys.stdout, indent=4)
for f in freader.stream():
print(f)
print(f.request.host)
json.dump(f._get_state(), sys.stdout, indent=4)
print ""
except flow.FlowReadError, v:
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,
# 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"):
resp = HTTPResponse(
[1, 1], 200, "OK",
ODictCaseless([["Content-Type", "text/html"]]),
"helloworld")
flow.reply(resp)
# Method 2: Redirect the request to a different server
if flow.request.pretty_host(hostheader=True).endswith("example.org"):
flow.request.host = "mitmproxy.org"
flow.request.update_host_header()

View File

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

View File

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

View File

@ -1,63 +1,63 @@
"""
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.
"""
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
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
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.
"""
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,
but the response body has not been processed yet. Can be used to tell mitmproxy
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.
"""
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
interrupted connections. This is distinct from a valid server HTTP error
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.
"""
ctx.log("clientdisconnect")
context.log("clientdisconnect")
def done(ctx):
def done(context):
"""
Called once on script shutdown, after any other events.
"""
ctx.log("done")
context.log("done")

View File

@ -1,10 +1,16 @@
import cStringIO
from PIL import Image
from libmproxy.protocol.http import decoded
def response(ctx, flow):
if flow.response.headers["content-type"] == ["image/png"]:
def response(context, flow):
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)
img = Image.open(s).rotate(180)
s2 = cStringIO.StringIO()
img.save(s2, "png")
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.scheme != "http":
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))
flow.server_conn = self.c.server_conn

View File

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