aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2012-02-18 23:56:40 +1300
committerAldo Cortesi <aldo@nullcube.com>2012-02-18 23:56:40 +1300
commit8ddc3b4ef275d70cdbc9bc49add02ea21cca3583 (patch)
tree8f57ae878938f2e642e6e40589ba3ed982ecd5a1
parent5f1d7a07469d9ee12267f79fb1b398145d153bcf (diff)
downloadmitmproxy-8ddc3b4ef275d70cdbc9bc49add02ea21cca3583.tar.gz
mitmproxy-8ddc3b4ef275d70cdbc9bc49add02ea21cca3583.tar.bz2
mitmproxy-8ddc3b4ef275d70cdbc9bc49add02ea21cca3583.zip
Add API for duplicating flows.
-rw-r--r--libmproxy/console/common.py28
-rw-r--r--libmproxy/flow.py29
-rw-r--r--test/test_flow.py18
3 files changed, 55 insertions, 20 deletions
diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py
index 5f80c250..fbeb83d7 100644
--- a/libmproxy/console/common.py
+++ b/libmproxy/console/common.py
@@ -43,20 +43,20 @@ def format_keyvals(lst, key="key", val="text", indent=0):
if kv is None:
ret.append(urwid.Text(""))
else:
- ret.append(
- urwid.Columns(
- [
- ("fixed", indent, urwid.Text("")),
- (
- "fixed",
- maxk,
- urwid.Text([(key, kv[0] or "")])
- ),
- urwid.Text([(val, kv[1])])
- ],
- dividechars = 2
- )
- )
+ cols = []
+ # This cumbersome construction process is here for a reason:
+ # Urwid < 1.0 barfs if given a fixed size column of size zero.
+ if indent:
+ cols.append(("fixed", indent, urwid.Text("")))
+ cols.extend([
+ (
+ "fixed",
+ maxk,
+ urwid.Text([(key, kv[0] or "")])
+ ),
+ urwid.Text([(val, kv[1])])
+ ])
+ ret.append(urwid.Columns(cols, dividechars = 2))
return ret
diff --git a/libmproxy/flow.py b/libmproxy/flow.py
index 81199035..8ce25c5c 100644
--- a/libmproxy/flow.py
+++ b/libmproxy/flow.py
@@ -851,6 +851,15 @@ class Flow:
self.intercepting = False
self._backup = None
+ def copy(self):
+ rc = self.request.copy()
+ f = Flow(rc)
+ if self.response:
+ f.response = self.response.copy()
+ if self.error:
+ f.error = self.error.copy()
+ return f
+
@classmethod
def _from_state(klass, state):
f = klass(None)
@@ -1011,6 +1020,7 @@ class State(object):
f = Flow(req)
self._flow_list.append(f)
self._flow_map[req] = f
+ assert len(self._flow_list) == len(self._flow_map)
if f.match(self._limit):
self.view.append(f)
return f
@@ -1235,17 +1245,24 @@ class FlowMaster(controller.Master):
return controller.Master.tick(self, q)
+ def duplicate_flow(self, f):
+ return self.load_flow(f.copy())
+
+ def load_flow(self, f):
+ if f.request:
+ fr = self.handle_request(f.request)
+ if f.response:
+ self.handle_response(f.response)
+ if f.error:
+ self.handle_error(f.error)
+ return fr
+
def load_flows(self, fr):
"""
Load flows from a FlowReader object.
"""
for i in fr.stream():
- if i.request:
- self.handle_request(i.request)
- if i.response:
- self.handle_response(i.response)
- if i.error:
- self.handle_error(i.error)
+ self.load_flow(i)
def process_new_request(self, f):
if self.stickycookie_state:
diff --git a/test/test_flow.py b/test/test_flow.py
index 94c4614d..fe84be53 100644
--- a/test/test_flow.py
+++ b/test/test_flow.py
@@ -136,6 +136,14 @@ class uServerPlaybackState(libpry.AutoTree):
class uFlow(libpry.AutoTree):
+ def test_copy(self):
+ f = tutils.tflow_full()
+ f2 = f.copy()
+ assert not f is f2
+ assert not f.request is f2.request
+ assert f.request.headers == f2.request.headers
+ assert not f.request.headers is f2.request.headers
+
def test_match(self):
f = tutils.tflow()
f.response = tutils.tresp()
@@ -485,6 +493,15 @@ class uFlowMaster(libpry.AutoTree):
fm.handle_error(err)
assert fm.script.ns["log"][-1] == "error"
+ def test_duplicate_flow(self):
+ s = flow.State()
+ fm = flow.FlowMaster(None, s)
+ f = tutils.tflow_full()
+ fm.load_flow(f)
+ assert s.flow_count() == 1
+ f2 = fm.duplicate_flow(f)
+ assert s.flow_count() == 2
+
def test_all(self):
s = flow.State()
fm = flow.FlowMaster(None, s)
@@ -572,6 +589,7 @@ class uFlowMaster(libpry.AutoTree):
fm.handle_response(tf.response)
assert fm.stickycookie_state.jar
assert not "cookie" in tf.request.headers
+ tf = tf.copy()
fm.handle_request(tf.request)
assert tf.request.headers["cookie"] == ["foo=bar"]