Add a basic built-in web app.

This commit is contained in:
Aldo Cortesi 2013-03-25 09:20:26 +13:00
parent 98e4421a90
commit e3fd0e838d
6 changed files with 68 additions and 10 deletions

8
libmproxy/app.py Normal file
View File

@ -0,0 +1,8 @@
import flask
mapp = flask.Flask(__name__)
@mapp.route("/")
def hello():
return "mitmproxy"

View File

@ -163,7 +163,7 @@ def get_common_options(options):
def common_options(parser):
parser.add_argument(
"-a",
"-b",
action="store", type = str, dest="addr", default='',
help = "Address to bind proxy to (defaults to all interfaces)"
)
@ -261,6 +261,13 @@ def common_options(parser):
help="Don't connect to upstream server to look up certificate details."
)
group = parser.add_argument_group("Web App")
group.add_argument(
"-a",
action="store_true", dest="app", default=False,
help="Enable the mitmproxy web app."
)
group = parser.add_argument_group("Client Replay")
group.add_argument(
"-c",

View File

@ -23,6 +23,7 @@ import tnetstring, filt, script, utils, encoding, proxy
from email.utils import parsedate_tz, formatdate, mktime_tz
from netlib import odict, http, certutils
import controller, version
import app
HDR_FORM_URLENCODED = "application/x-www-form-urlencoded"
CONTENT_MISSING = 0
@ -42,13 +43,13 @@ class ReplaceHooks:
def add(self, fpatt, rex, s):
"""
Add a replacement hook.
add a replacement hook.
fpatt: A string specifying a filter pattern.
rex: A regular expression.
s: The replacement string
fpatt: a string specifying a filter pattern.
rex: a regular expression.
s: the replacement string
Returns True if hook was added, False if the pattern could not be
returns true if hook was added, false if the pattern could not be
parsed.
"""
cpatt = filt.parse(fpatt)
@ -1352,6 +1353,7 @@ class FlowMaster(controller.Master):
self.setheaders = SetHeaders()
self.stream = None
app.mapp.config["PMASTER"] = self
def add_event(self, e, level="info"):
"""

View File

@ -17,8 +17,11 @@ import shutil, tempfile, threading
import SocketServer
from OpenSSL import SSL
from netlib import odict, tcp, http, wsgi, certutils, http_status, http_auth
import utils, flow, version, platform, controller
import utils, flow, version, platform, controller, app
APP_DOMAIN = "mitm"
APP_IP = "1.1.1.1"
KILL = 0
@ -36,8 +39,8 @@ class Log:
class ProxyConfig:
def __init__(self, certfile = None, cacert = None, clientcerts = None, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, transparent_proxy=None, certdir = None, authenticator=None):
assert not (reverse_proxy and transparent_proxy)
def __init__(self, app=False, certfile = None, cacert = None, clientcerts = None, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, transparent_proxy=None, certdir = None, authenticator=None):
self.app = app
self.certfile = certfile
self.cacert = cacert
self.clientcerts = clientcerts
@ -85,6 +88,7 @@ class ServerConnection(tcp.TCPClient):
pass
class RequestReplayThread(threading.Thread):
def __init__(self, config, flow, masterq):
self.config, self.flow, self.channel = config, flow, controller.Channel(masterq)
@ -497,6 +501,17 @@ class ProxyServer(tcp.TCPServer):
raise ProxyServerError('Error starting proxy server: ' + v.strerror)
self.channel = None
self.apps = AppRegistry()
if config.app:
self.apps.add(
app.mapp,
APP_DOMAIN,
80
)
self.apps.add(
app.mapp,
APP_IP,
80
)
def start_slave(self, klass, channel):
slave = klass(channel, self)
@ -629,6 +644,7 @@ def process_proxy_options(parser, options):
authenticator = http_auth.NullProxyAuth(None)
return ProxyConfig(
app = options.app,
certfile = options.cert,
cacert = cacert,
clientcerts = options.clientcerts,

View File

@ -53,7 +53,16 @@ class CommonMixin:
assert "Bad Request" in t.rfile.readline()
class TestHTTP(tservers.HTTPProxTest, CommonMixin):
class AppMixin:
def test_app(self):
ret = self.app("/")
assert ret.status_code == 200
assert "mitmproxy" in ret.content
class TestHTTP(tservers.HTTPProxTest, CommonMixin, AppMixin):
def test_app_err(self):
p = self.pathoc()
ret = p.request("get:'http://errapp/'")
@ -135,6 +144,7 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin):
assert req.status_code == 400
class TestHTTPAuth(tservers.HTTPProxTest):
authenticator = http_auth.BasicProxyAuth(http_auth.PassManSingleUser("test", "test"), "realm")
def test_auth(self):

View File

@ -84,6 +84,7 @@ class ProxTestBase:
no_upstream_cert = cls.no_upstream_cert,
cacert = tutils.test_data.path("data/serverkey.pem"),
authenticator = cls.authenticator,
app = True,
**pconf
)
tmaster = cls.masterclass(cls.tqueue, config)
@ -156,6 +157,17 @@ class HTTPProxTest(ProxTestBase):
q = "get:'%s/p/%s'"%(self.server.urlbase, spec)
return p.request(q)
def app(self, page):
if self.ssl:
p = libpathod.pathoc.Pathoc("127.0.0.1", self.proxy.port, True)
print "PRE"
p.connect((proxy.APP_IP, 80))
print "POST"
return p.request("get:'/%s'"%page)
else:
p = self.pathoc()
return p.request("get:'http://%s/%s'"%(proxy.APP_DOMAIN, page))
class TResolver:
def __init__(self, port):
@ -234,3 +246,6 @@ class ReverseProxTest(ProxTestBase):
q = "get:'/p/%s'"%spec
return p.request(q)