2014-09-17 19:14:55 +00:00
|
|
|
from __future__ import absolute_import, print_function
|
2014-12-09 23:47:05 +00:00
|
|
|
import collections
|
2014-09-13 23:30:00 +00:00
|
|
|
import tornado.ioloop
|
2014-09-13 23:46:01 +00:00
|
|
|
import tornado.httpserver
|
2015-01-02 00:26:22 +00:00
|
|
|
import os
|
2014-09-17 19:14:55 +00:00
|
|
|
from .. import controller, flow
|
|
|
|
from . import app
|
2014-09-13 23:30:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Stop(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2014-11-26 03:18:21 +00:00
|
|
|
class WebFlowView(flow.FlowView):
|
|
|
|
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",
|
|
|
|
data=f.get_state(short=True)
|
|
|
|
)
|
2014-11-26 03:18:21 +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",
|
|
|
|
data=f.get_state(short=True)
|
|
|
|
)
|
2014-11-26 03:18:21 +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
|
|
|
)
|
2014-11-26 03:18:21 +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-11-26 03:18:21 +00:00
|
|
|
|
|
|
|
|
2014-09-13 23:30:00 +00:00
|
|
|
class WebState(flow.State):
|
|
|
|
def __init__(self):
|
2014-11-26 03:18:21 +00:00
|
|
|
super(WebState, self).__init__()
|
|
|
|
self.view._close()
|
|
|
|
self.view = WebFlowView(self.flows)
|
2014-09-13 23:30:00 +00:00
|
|
|
|
2014-12-09 23:47:05 +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=[]
|
|
|
|
)
|
|
|
|
|
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",
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
class WebMaster(flow.FlowMaster):
|
|
|
|
def __init__(self, server, options):
|
2014-09-14 00:22:28 +00:00
|
|
|
self.options = options
|
2014-09-17 19:14:55 +00:00
|
|
|
super(WebMaster, self).__init__(server, WebState())
|
2014-12-23 19:33:42 +00:00
|
|
|
self.app = app.Application(self, self.options.wdebug)
|
2015-01-02 00:26:22 +00:00
|
|
|
if options.rfile:
|
|
|
|
try:
|
2015-01-02 02:29:51 +00:00
|
|
|
self.load_flows_file(options.rfile)
|
2015-01-02 00:26:22 +00:00
|
|
|
except flow.FlowReadError, v:
|
|
|
|
self.add_event(
|
|
|
|
"Could not read flow file: %s"%v,
|
|
|
|
"error"
|
|
|
|
)
|
2015-03-26 16:20:32 +00:00
|
|
|
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
|
|
|
|
2014-09-16 21:40:25 +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):
|
|
|
|
if self.state.intercept and self.state.intercept(f) and not f.request.is_replay:
|
|
|
|
f.intercept(self)
|
|
|
|
else:
|
|
|
|
f.reply()
|
|
|
|
|
2014-09-13 23:30:00 +00:00
|
|
|
def handle_request(self, f):
|
2014-11-26 03:18:21 +00:00
|
|
|
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):
|
2014-11-26 03:18:21 +00:00
|
|
|
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
|
|
|
|
2014-12-09 23:47:05 +00:00
|
|
|
def add_event(self, e, level="info"):
|
|
|
|
super(WebMaster, self).add_event(e, level)
|
2015-03-26 16:20:32 +00:00
|
|
|
self.state.add_event(e, level)
|