Move script hooks into the flow primitives.

This lets handle scripts in corner cases like playback situations more easily.
This commit is contained in:
Aldo Cortesi 2011-02-21 11:40:49 +13:00
parent fe99871df8
commit 7bc913c40d
3 changed files with 52 additions and 31 deletions

View File

@ -32,6 +32,11 @@ class DumpMaster(flow.FlowMaster):
else: else:
self.filt = None self.filt = None
if self.o.response_script:
self.set_response_script(self.o.response_script)
if self.o.request_script:
self.set_request_script(self.o.request_script)
if options.wfile: if options.wfile:
path = os.path.expanduser(options.wfile) path = os.path.expanduser(options.wfile)
try: try:
@ -47,7 +52,7 @@ class DumpMaster(flow.FlowMaster):
flows = list(flow.FlowReader(f).stream()) flows = list(flow.FlowReader(f).stream())
except IOError, v: except IOError, v:
raise DumpError(v.strerror) raise DumpError(v.strerror)
self.start_playback(flows) self.start_playback(flows, options.kill)
def _runscript(self, f, script): def _runscript(self, f, script):
try: try:
@ -65,17 +70,7 @@ class DumpMaster(flow.FlowMaster):
def handle_request(self, r): def handle_request(self, r):
f = flow.FlowMaster.handle_request(self, r) f = flow.FlowMaster.handle_request(self, r)
if self.o.request_script: if f:
self._runscript(f, self.o.request_script)
if self.o.replay:
pb = self.playback(f)
if not pb:
if self.o.kill:
self.state.kill_flow(f)
else:
r.ack()
else:
r.ack() r.ack()
def indent(self, n, t): def indent(self, n, t):
@ -85,8 +80,6 @@ class DumpMaster(flow.FlowMaster):
def handle_response(self, msg): def handle_response(self, msg):
f = flow.FlowMaster.handle_response(self, msg) f = flow.FlowMaster.handle_response(self, msg)
if f: if f:
if self.o.response_script:
self._runscript(f, self.o.response_script)
msg.ack() msg.ack()
if self.filt and not f.match(self.filt): if self.filt and not f.match(self.filt):
return return

View File

@ -35,7 +35,7 @@ class ServerPlaybackState:
def __init__(self): def __init__(self):
self.fmap = {} self.fmap = {}
def __len__(self): def count(self):
return sum([len(i) for i in self.fmap.values()]) return sum([len(i) for i in self.fmap.values()])
def load(self, flows): def load(self, flows):
@ -329,19 +329,35 @@ class FlowMaster(controller.Master):
def __init__(self, server, state): def __init__(self, server, state):
controller.Master.__init__(self, server) controller.Master.__init__(self, server)
self.state = state self.state = state
self._playback_state = None self.playback = None
self.scripts = {}
self.kill_nonreplay = False
def start_playback(self, flows): def _runscript(self, f, script):
self._playback_state = ServerPlaybackState() return f.run_script(script)
self._playback_state.load(flows)
def playback(self, flow): def set_response_script(self, s):
self.scripts["response"] = s
def set_request_script(self, s):
self.scripts["request"] = s
def start_playback(self, flows, kill):
"""
flows: A list of flows.
kill: Boolean, should we kill requests not part of the replay?
"""
self.playback = ServerPlaybackState()
self.playback.load(flows)
self.kill_nonreplay = kill
def do_playback(self, flow):
""" """
This method should be called by child classes in the handle_request This method should be called by child classes in the handle_request
handler. Returns True if playback has taken place, None if not. handler. Returns True if playback has taken place, None if not.
""" """
if self._playback_state: if self.playback:
rflow = self._playback_state.next_flow(flow) rflow = self.playback.next_flow(flow)
if not rflow: if not rflow:
return None return None
response = proxy.Response.from_state(flow.request, rflow.response.get_state()) response = proxy.Response.from_state(flow.request, rflow.response.get_state())
@ -365,12 +381,24 @@ class FlowMaster(controller.Master):
return f return f
def handle_request(self, r): def handle_request(self, r):
return self.state.add_request(r) f = self.state.add_request(r)
if "request" in self.scripts:
self._runscript(f, self.scripts["request"])
if self.playback:
pb = self.do_playback(f)
if not pb:
if self.kill_nonreplay:
self.state.kill_flow(f)
else:
r.ack()
return f
def handle_response(self, r): def handle_response(self, r):
f = self.state.add_response(r) f = self.state.add_response(r)
if not f: if not f:
r.ack() r.ack()
if "response" in self.scripts:
self._runscript(f, self.scripts["response"])
return f return f

View File

@ -26,16 +26,16 @@ class uServerPlaybackState(libpry.AutoTree):
r2.request.headers["key"] = ["two"] r2.request.headers["key"] = ["two"]
s.load([r, r2]) s.load([r, r2])
assert len(s) == 2 assert s.count() == 2
assert len(s.fmap.keys()) == 1 assert len(s.fmap.keys()) == 1
n = s.next_flow(r) n = s.next_flow(r)
assert n.request.headers["key"] == ["one"] assert n.request.headers["key"] == ["one"]
assert len(s) == 1 assert s.count() == 1
n = s.next_flow(r) n = s.next_flow(r)
assert n.request.headers["key"] == ["two"] assert n.request.headers["key"] == ["two"]
assert len(s) == 0 assert s.count() == 0
assert not s.next_flow(r) assert not s.next_flow(r)
@ -317,15 +317,15 @@ class uFlowMaster(libpry.AutoTree):
pb = [f] pb = [f]
fm = flow.FlowMaster(None, s) fm = flow.FlowMaster(None, s)
assert not fm.playback(utils.tflow()) assert not fm.do_playback(utils.tflow())
fm.start_playback(pb) fm.start_playback(pb, False)
assert fm.playback(utils.tflow()) assert fm.do_playback(utils.tflow())
fm.start_playback(pb) fm.start_playback(pb, False)
r = utils.tflow() r = utils.tflow()
r.request.content = "gibble" r.request.content = "gibble"
assert not fm.playback(r) assert not fm.do_playback(r)