aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2012-07-21 20:50:41 +1200
committerAldo Cortesi <aldo@nullcube.com>2012-07-21 20:50:41 +1200
commit7a49cdfef3d9f5eeaecf6d6c8938f0bb8da7c15d (patch)
treec72cd520b3249591d107c707cc12f7023522b1e2
parent86fe199988801232f209b7e39a2910065bf5db5f (diff)
downloadmitmproxy-7a49cdfef3d9f5eeaecf6d6c8938f0bb8da7c15d.tar.gz
mitmproxy-7a49cdfef3d9f5eeaecf6d6c8938f0bb8da7c15d.tar.bz2
mitmproxy-7a49cdfef3d9f5eeaecf6d6c8938f0bb8da7c15d.zip
More robust response handling.
-rw-r--r--libpathod/pathoc.py12
-rw-r--r--libpathod/pathod.py150
-rw-r--r--test/test_pathod.py5
3 files changed, 94 insertions, 73 deletions
diff --git a/libpathod/pathoc.py b/libpathod/pathoc.py
index 7af5a288..793135e7 100644
--- a/libpathod/pathoc.py
+++ b/libpathod/pathoc.py
@@ -40,23 +40,23 @@ class Pathoc(tcp.TCPClient):
r = rparse.parse_request({}, i)
req = r.serve(self.wfile)
if reqdump:
- print >> fp, ">>", req["method"], req["path"]
+ print >> fp, "\n>>", req["method"], req["path"]
for a in req["actions"]:
print >> fp, "\t",
for x in a:
- print x,
- print
+ print >> fp, x,
+ print >> fp
self.wfile.flush()
- resp = self.request(i)
+ resp = http.read_response(self.rfile, r.method, None)
except rparse.ParseException, v:
print >> fp, "Error parsing request spec: %s"%v.msg
print >> fp, v.marked()
return
except http.HttpError, v:
- print >> fp, v.msg
+ print >> fp, "<<", v.msg
return
except tcp.NetLibTimeout:
- print >> fp, "Timeout"
+ print >> fp, "<<", "Timeout"
else:
if respdump:
print_full(fp, *resp)
diff --git a/libpathod/pathod.py b/libpathod/pathod.py
index 44bcadb7..026986bb 100644
--- a/libpathod/pathod.py
+++ b/libpathod/pathod.py
@@ -18,6 +18,82 @@ class PathodHandler(tcp.BaseHandler):
def handle_sni(self, connection):
self.sni = connection.get_servername()
+ def handle_request(self):
+ """
+ Returns True if handling should continue.
+ """
+ line = self.rfile.readline()
+ if line == "\r\n" or line == "\n": # Possible leftover from previous message
+ line = self.rfile.readline()
+ if line == "":
+ return
+
+ parts = http.parse_init_http(line)
+ if not parts:
+ s = "Invalid first line: %s"%line.rstrip()
+ self.info(s)
+ self.server.add_log(
+ dict(
+ type = "error",
+ msg = s
+ )
+ )
+ return
+ method, path, httpversion = parts
+
+ headers = http.read_headers(self.rfile)
+ content = http.read_http_body_request(
+ self.rfile, self.wfile, headers, httpversion, None
+ )
+
+ crafted = None
+ for i in self.server.anchors:
+ if i[0].match(path):
+ crafted = i[1]
+
+ if not crafted and path.startswith(self.server.prefix):
+ spec = urllib.unquote(path)[len(self.server.prefix):]
+ try:
+ crafted = rparse.parse_response(self.server.request_settings, spec)
+ except rparse.ParseException, v:
+ crafted = rparse.InternalResponse(
+ 800,
+ "Error parsing response spec: %s\n"%v.msg + v.marked()
+ )
+
+ request_log = dict(
+ path = path,
+ method = method,
+ headers = headers.lst,
+ sni = self.sni,
+ remote_address = self.client_address,
+ httpversion = httpversion,
+ )
+ if crafted:
+ response_log = crafted.serve(self.wfile)
+ if response_log["disconnect"]:
+ return
+ self.server.add_log(
+ dict(
+ type = "crafted",
+ request=request_log,
+ response=response_log
+ )
+ )
+ else:
+ cc = wsgi.ClientConn(self.client_address)
+ req = wsgi.Request(cc, "http", method, path, headers, content)
+ sn = self.connection.getsockname()
+ app = wsgi.WSGIAdaptor(
+ self.server.app,
+ sn[0],
+ self.server.port,
+ version.NAMEVERSION
+ )
+ app.serve(req, self.wfile)
+ self.debug("%s %s"%(method, path))
+ return True
+
def handle(self):
if self.server.ssloptions:
try:
@@ -34,79 +110,21 @@ class PathodHandler(tcp.BaseHandler):
)
)
self.info(s)
- self.finish()
+ return
while not self.finished:
- line = self.rfile.readline()
- if line == "\r\n" or line == "\n": # Possible leftover from previous message
- line = self.rfile.readline()
- if line == "":
- return None
-
- parts = http.parse_init_http(line)
- if not parts:
- s = "Invalid first line: %s"%line.rstrip()
- self.info(s)
+ try:
+ if not self.handle_request():
+ return
+ except tcp.NetLibDisconnect:
+ self.info("Disconnect")
self.server.add_log(
dict(
type = "error",
- msg = s
+ msg = "Disconnect"
)
)
- return None
- method, path, httpversion = parts
-
- headers = http.read_headers(self.rfile)
- content = http.read_http_body_request(
- self.rfile, self.wfile, headers, httpversion, None
- )
-
- crafted = None
- for i in self.server.anchors:
- if i[0].match(path):
- crafted = i[1]
-
- if not crafted and path.startswith(self.server.prefix):
- spec = urllib.unquote(path)[len(self.server.prefix):]
- try:
- crafted = rparse.parse_response(self.server.request_settings, spec)
- except rparse.ParseException, v:
- crafted = rparse.InternalResponse(
- 800,
- "Error parsing response spec: %s\n"%v.msg + v.marked()
- )
-
- request_log = dict(
- path = path,
- method = method,
- headers = headers.lst,
- sni = self.sni,
- remote_address = self.client_address,
- httpversion = httpversion,
- )
- if crafted:
- response_log = crafted.serve(self.wfile)
- if response_log["disconnect"]:
- self.finish()
- self.server.add_log(
- dict(
- type = "crafted",
- request=request_log,
- response=response_log
- )
- )
- else:
- cc = wsgi.ClientConn(self.client_address)
- req = wsgi.Request(cc, "http", method, path, headers, content)
- sn = self.connection.getsockname()
- app = wsgi.WSGIAdaptor(
- self.server.app,
- sn[0],
- self.server.port,
- version.NAMEVERSION
- )
- app.serve(req, self.wfile)
- self.debug("%s %s"%(method, path))
+ return
class Pathod(tcp.TCPServer):
diff --git a/test/test_pathod.py b/test/test_pathod.py
index a23b7c71..1484efcd 100644
--- a/test/test_pathod.py
+++ b/test/test_pathod.py
@@ -64,11 +64,13 @@ class _DaemonTests:
scheme = "https" if self.SSL else "http"
return requests.get("%s://localhost:%s/p/%s"%(scheme, self.d.port, spec), verify=False)
- def pathoc(self, spec):
+ def pathoc(self, spec, timeout=None):
c = pathoc.Pathoc("localhost", self.d.port)
c.connect()
if self.SSL:
c.convert_to_ssl()
+ if timeout:
+ c.settimeout(timeout)
return c.request(spec)
def test_preline(self):
@@ -114,6 +116,7 @@ class _DaemonTests:
assert "foo" in l["msg"]
+
class TestDaemon(_DaemonTests):
SSL = False