mitmproxy/libmproxy/web/__init__.py

216 lines
5.7 KiB
Python
Raw Normal View History

from __future__ import absolute_import, print_function
import collections
2014-09-13 23:30:00 +00:00
import tornado.ioloop
import tornado.httpserver
2016-02-08 01:10:10 +00:00
from netlib.http import authentication
from .. import controller, flow
from . import app
2014-09-13 23:30:00 +00:00
class Stop(Exception):
pass
class WebFlowView(flow.FlowView):
2016-01-27 09:12:18 +00:00
def __init__(self, store):
super(WebFlowView, self).__init__(store, None)
def _add(self, f):
super(WebFlowView, self)._add(f)
2014-12-09 17:55:16 +00:00
app.ClientConnection.broadcast(
type="flows",
cmd="add",
2016-02-08 01:10:10 +00:00
data=app._strip_content(f.get_state())
2014-12-09 17:55:16 +00:00
)
def _update(self, f):
super(WebFlowView, self)._update(f)
2014-12-09 17:55:16 +00:00
app.ClientConnection.broadcast(
type="flows",
cmd="update",
2016-02-08 01:10:10 +00:00
data=app._strip_content(f.get_state())
2014-12-09 17:55:16 +00:00
)
def _remove(self, f):
super(WebFlowView, self)._remove(f)
2014-12-09 17:55:16 +00:00
app.ClientConnection.broadcast(
type="flows",
cmd="remove",
2014-12-24 00:07:57 +00:00
data=f.id
2014-12-09 17:55:16 +00:00
)
def _recalculate(self, flows):
super(WebFlowView, self)._recalculate(flows)
2014-12-09 17:55:16 +00:00
app.ClientConnection.broadcast(
type="flows",
cmd="reset"
)
2014-09-13 23:30:00 +00:00
class WebState(flow.State):
2016-01-27 09:12:18 +00:00
2014-09-13 23:30:00 +00:00
def __init__(self):
super(WebState, self).__init__()
self.view._close()
self.view = WebFlowView(self.flows)
2014-09-13 23:30:00 +00:00
self._last_event_id = 0
self.events = collections.deque(maxlen=1000)
def add_event(self, e, level):
self._last_event_id += 1
entry = {
"id": self._last_event_id,
"message": e,
"level": level
}
self.events.append(entry)
app.ClientConnection.broadcast(
type="events",
cmd="add",
data=entry
)
2014-09-13 23:30:00 +00:00
2014-12-13 00:56:04 +00:00
def clear(self):
super(WebState, self).clear()
self.events.clear()
app.ClientConnection.broadcast(
type="events",
cmd="reset",
data=[]
)
2015-05-30 00:03:28 +00:00
2014-09-13 23:30:00 +00:00
class Options(object):
attributes = [
"app",
"app_domain",
"app_ip",
"anticache",
"anticomp",
"client_replay",
"eventlog",
"keepserving",
"kill",
"intercept",
"no_server",
"refresh_server_playback",
"rfile",
"scripts",
"showhost",
"replacements",
"rheaders",
"setheaders",
"server_replay",
"stickycookie",
"stickyauth",
"stream_large_bodies",
"verbosity",
"wfile",
"nopop",
2014-09-14 00:22:28 +00:00
"wdebug",
"wport",
"wiface",
"wauthenticator",
"wsingleuser",
"whtpasswd",
2014-09-13 23:30:00 +00:00
]
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
for i in self.attributes:
if not hasattr(self, i):
setattr(self, i, None)
def process_web_options(self, parser):
if self.wsingleuser or self.whtpasswd:
if self.wsingleuser:
if len(self.wsingleuser.split(':')) != 2:
return parser.error(
"Invalid single-user specification. Please use the format username:password"
)
username, password = self.wsingleuser.split(':')
self.wauthenticator = authentication.PassManSingleUser(username, password)
elif self.whtpasswd:
try:
self.wauthenticator = authentication.PassManHtpasswd(self.whtpasswd)
except ValueError as v:
return parser.error(v.message)
else:
self.wauthenticator = None
2014-09-13 23:30:00 +00:00
class WebMaster(flow.FlowMaster):
2016-01-27 09:12:18 +00:00
2014-09-13 23:30:00 +00:00
def __init__(self, server, options):
2014-09-14 00:22:28 +00:00
self.options = options
super(WebMaster, self).__init__(server, WebState())
self.app = app.Application(self, self.options.wdebug, self.options.wauthenticator)
if options.rfile:
try:
self.load_flows_file(options.rfile)
2015-05-30 00:03:28 +00:00
except flow.FlowReadError as v:
self.add_event(
2015-05-30 00:03:28 +00:00
"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)
2014-09-13 23:30:00 +00:00
def tick(self):
flow.FlowMaster.tick(self, self.masterq, timeout=0)
def run(self): # pragma: no cover
self.server.start_slave(
controller.Slave,
controller.Channel(self.masterq, self.should_exit)
)
iol = tornado.ioloop.IOLoop.instance()
2014-09-14 00:22:28 +00:00
http_server = tornado.httpserver.HTTPServer(self.app)
2014-09-14 00:22:28 +00:00
http_server.listen(self.options.wport)
2014-09-13 23:30:00 +00:00
tornado.ioloop.PeriodicCallback(self.tick, 5).start()
try:
iol.start()
except (Stop, KeyboardInterrupt):
self.shutdown()
2014-12-23 19:33:42 +00:00
def _process_flow(self, f):
2015-05-30 00:03:28 +00:00
if self.state.intercept and self.state.intercept(
f) and not f.request.is_replay:
2014-12-23 19:33:42 +00:00
f.intercept(self)
else:
f.reply()
2014-09-13 23:30:00 +00:00
def handle_request(self, f):
super(WebMaster, self).handle_request(f)
2014-12-23 19:33:42 +00:00
self._process_flow(f)
2014-09-13 23:30:00 +00:00
def handle_response(self, f):
super(WebMaster, self).handle_response(f)
2014-12-23 19:33:42 +00:00
self._process_flow(f)
def handle_error(self, f):
super(WebMaster, self).handle_error(f)
self._process_flow(f)
2014-09-13 23:30:00 +00:00
def add_event(self, e, level="info"):
super(WebMaster, self).add_event(e, level)
self.state.add_event(e, level)