aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmproxy/cmdline.py4
-rw-r--r--libmproxy/console/__init__.py45
-rw-r--r--libmproxy/dump.py15
-rw-r--r--libmproxy/flow.py19
-rw-r--r--libmproxy/protocol/http.py6
-rw-r--r--libmproxy/protocol/tcp.py6
-rw-r--r--test/test_dump.py8
7 files changed, 61 insertions, 42 deletions
diff --git a/libmproxy/cmdline.py b/libmproxy/cmdline.py
index 185944da..e45cc54c 100644
--- a/libmproxy/cmdline.py
+++ b/libmproxy/cmdline.py
@@ -418,14 +418,14 @@ def common_options(parser):
group = parser.add_argument_group("Client Replay")
group.add_argument(
"-c", "--client-replay",
- action="store", dest="client_replay", default=None, metavar="PATH",
+ action="append", dest="client_replay", default=None, metavar="PATH",
help="Replay client requests from a saved file."
)
group = parser.add_argument_group("Server Replay")
group.add_argument(
"-S", "--server-replay",
- action="store", dest="server_replay", default=None, metavar="PATH",
+ action="append", dest="server_replay", default=None, metavar="PATH",
help="Replay server responses from a saved file."
)
group.add_argument(
diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py
index dc20d21f..0db06832 100644
--- a/libmproxy/console/__init__.py
+++ b/libmproxy/console/__init__.py
@@ -498,37 +498,34 @@ class ConsoleMaster(flow.FlowMaster):
self.eventlog = not self.eventlog
self.view_flowlist()
- def _readflow(self, path):
- path = os.path.expanduser(path)
+ def _readflow(self, paths):
+ """
+ Utitility function that reads a list of flows
+ or prints an error to the UI if that fails.
+ Returns
+ - None, if there was an error.
+ - a list of flows, otherwise.
+ """
try:
- f = file(path, "rb")
- flows = list(flow.FlowReader(f).stream())
- except (IOError, flow.FlowReadError), v:
- return True, v.strerror
- return False, flows
-
- def client_playback_path(self, path):
- err, ret = self._readflow(path)
- if err:
+ return flow.read_flows_from_paths(paths)
+ except flow.FlowReadError as e:
if not self.statusbar:
- print >> sys.stderr, ret
+ print >> sys.stderr, e.strerror
sys.exit(1)
else:
- self.statusbar.message(ret)
- else:
- self.start_client_playback(ret, False)
+ self.statusbar.message(e.strerror)
+ return None
+
+ def client_playback_path(self, path):
+ flows = self._readflow(path)
+ if flows:
+ self.start_client_playback(flows, False)
def server_playback_path(self, path):
- err, ret = self._readflow(path)
- if err:
- if not self.statusbar:
- print >> sys.stderr, ret
- sys.exit(1)
- else:
- self.statusbar.message(ret)
- else:
+ flows = self._readflow(path)
+ if flows:
self.start_server_playback(
- ret,
+ flows,
self.killextra, self.rheaders,
False, self.nopop,
self.options.replay_ignore_params, self.options.replay_ignore_content, self.options.replay_ignore_payload_params
diff --git a/libmproxy/dump.py b/libmproxy/dump.py
index 91ccb42b..59ddcf5f 100644
--- a/libmproxy/dump.py
+++ b/libmproxy/dump.py
@@ -143,14 +143,15 @@ class DumpMaster(flow.FlowMaster):
if self.o.app:
self.start_app(self.o.app_host, self.o.app_port)
- def _readflow(self, path):
- path = os.path.expanduser(path)
+ def _readflow(self, paths):
+ """
+ Utitility function that reads a list of flows
+ or raises a DumpError if that fails.
+ """
try:
- f = file(path, "rb")
- flows = list(flow.FlowReader(f).stream())
- except (IOError, flow.FlowReadError), v:
- raise DumpError(v.strerror)
- return flows
+ return flow.read_flows_from_paths(paths)
+ except flow.FlowReadError as e:
+ raise DumpError(e.strerror)
def add_event(self, e, level="info"):
needed = dict(error=0, info=1, debug=2).get(level, 1)
diff --git a/libmproxy/flow.py b/libmproxy/flow.py
index 97ebc572..f9e2b94d 100644
--- a/libmproxy/flow.py
+++ b/libmproxy/flow.py
@@ -945,6 +945,25 @@ class FlowMaster(controller.Master):
self.stream = None
+def read_flows_from_paths(paths):
+ """
+ Given a list of filepaths, read all flows and return a list of them.
+ From a performance perspective, streaming would be advisable -
+ however, if there's an error with one of the files, we want it to be raised immediately.
+
+ If an error occurs, a FlowReadError will be raised.
+ """
+ try:
+ flows = []
+ for path in paths:
+ path = os.path.expanduser(path)
+ with file(path, "rb") as f:
+ flows.extend(FlowReader(f).stream())
+ except IOError as e:
+ raise FlowReadError(e.strerror)
+ return flows
+
+
class FlowWriter:
def __init__(self, fo):
self.fo = fo
diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py
index 50691ea2..284731b0 100644
--- a/libmproxy/protocol/http.py
+++ b/libmproxy/protocol/http.py
@@ -995,7 +995,7 @@ class HTTPHandler(ProtocolHandler):
include_body=False
)
break
- except (tcp.NetLibDisconnect, http.HttpErrorConnClosed), v:
+ except (tcp.NetLibError, http.HttpErrorConnClosed), v:
self.c.log(
"error in server communication: %s" % repr(v),
level="debug"
@@ -1042,7 +1042,7 @@ class HTTPHandler(ProtocolHandler):
self.c.client_conn.rfile,
body_size_limit=self.c.config.body_size_limit
)
- except tcp.NetLibDisconnect:
+ except tcp.NetLibError:
# don't throw an error for disconnects that happen
# before/between requests.
return False
@@ -1140,7 +1140,7 @@ class HTTPHandler(ProtocolHandler):
message = repr(error)
message_debug = None
- if isinstance(error, tcp.NetLibDisconnect):
+ if isinstance(error, tcp.NetLibError):
message = None
message_debug = "TCP connection closed unexpectedly."
elif "tlsv1 alert unknown ca" in message:
diff --git a/libmproxy/protocol/tcp.py b/libmproxy/protocol/tcp.py
index da0c9087..d2d21829 100644
--- a/libmproxy/protocol/tcp.py
+++ b/libmproxy/protocol/tcp.py
@@ -3,6 +3,7 @@ import select
import socket
from .primitives import ProtocolHandler
from netlib.utils import cleanBin
+from netlib.tcp import NetLibError
class TCPHandler(ProtocolHandler):
@@ -76,7 +77,8 @@ class TCPHandler(ProtocolHandler):
),
"info"
)
- dst.connection.send(contents)
+ # Do not use dst.connection.send here, which may raise OpenSSL-specific errors.
+ dst.send(contents)
else:
# socket.socket.send supports raw bytearrays/memoryviews
if self.log:
@@ -87,6 +89,6 @@ class TCPHandler(ProtocolHandler):
"info"
)
dst.connection.send(buf[:size])
- except socket.error as e:
+ except (socket.error, NetLibError) as e:
self.c.log("TCP connection closed unexpectedly.", "debug")
return
diff --git a/test/test_dump.py b/test/test_dump.py
index 927b5b50..11a024e3 100644
--- a/test/test_dump.py
+++ b/test/test_dump.py
@@ -75,24 +75,24 @@ class TestDumpMaster:
def test_replay(self):
cs = StringIO()
- o = dump.Options(server_replay="nonexistent", kill=True)
+ o = dump.Options(server_replay=["nonexistent"], kill=True)
tutils.raises(dump.DumpError, dump.DumpMaster, None, o, outfile=cs)
with tutils.tmpdir() as t:
p = os.path.join(t, "rep")
self._flowfile(p)
- o = dump.Options(server_replay=p, kill=True)
+ o = dump.Options(server_replay=[p], kill=True)
m = dump.DumpMaster(None, o, outfile=cs)
self._cycle(m, "content")
self._cycle(m, "content")
- o = dump.Options(server_replay=p, kill=False)
+ o = dump.Options(server_replay=[p], kill=False)
m = dump.DumpMaster(None, o, outfile=cs)
self._cycle(m, "nonexistent")
- o = dump.Options(client_replay=p, kill=False)
+ o = dump.Options(client_replay=[p], kill=False)
m = dump.DumpMaster(None, o, outfile=cs)
def test_read(self):