aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorRouli <rouli.net@gmail.com>2013-03-18 14:24:13 +0200
committerRouli <rouli.net@gmail.com>2013-03-18 14:24:13 +0200
commitc94aadcb0ee5e7aab8acc46a0e4ac7d02a28df6f (patch)
tree1e62785d669d86f6e551a99b9debfe445389bd48 /test
parentb6cae7cd2d0105d6a6fe9d35864d0f9b7c5f8924 (diff)
parent5c33f6784b4ba34dd9825ea7e3070cdf0b2b4621 (diff)
downloadmitmproxy-c94aadcb0ee5e7aab8acc46a0e4ac7d02a28df6f.tar.gz
mitmproxy-c94aadcb0ee5e7aab8acc46a0e4ac7d02a28df6f.tar.bz2
mitmproxy-c94aadcb0ee5e7aab8acc46a0e4ac7d02a28df6f.zip
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'test')
-rw-r--r--test/data/htpasswd1
-rw-r--r--test/data/htpasswd.invalid1
-rwxr-xr-xtest/fuzzing/go_proxy22
-rw-r--r--test/test_authentication.py58
-rw-r--r--test/test_console_common.py10
-rw-r--r--test/test_controller.py12
-rw-r--r--test/test_dump.py18
-rw-r--r--test/test_flow.py32
-rw-r--r--test/test_fuzzing.py39
-rw-r--r--test/test_proxy.py91
-rw-r--r--test/test_server.py169
-rw-r--r--test/tservers.py102
12 files changed, 410 insertions, 145 deletions
diff --git a/test/data/htpasswd b/test/data/htpasswd
new file mode 100644
index 00000000..54c95b8c
--- /dev/null
+++ b/test/data/htpasswd
@@ -0,0 +1 @@
+test:$apr1$/LkYxy3x$WI4.YbiJlu537jLGEW2eu1
diff --git a/test/data/htpasswd.invalid b/test/data/htpasswd.invalid
new file mode 100644
index 00000000..257cc564
--- /dev/null
+++ b/test/data/htpasswd.invalid
@@ -0,0 +1 @@
+foo
diff --git a/test/fuzzing/go_proxy b/test/fuzzing/go_proxy
new file mode 100755
index 00000000..c9b6aef6
--- /dev/null
+++ b/test/fuzzing/go_proxy
@@ -0,0 +1,22 @@
+#!/bin/sh
+# Assuming:
+# mitmproxy/mitmdump is running on port 8080 in straight proxy mode.
+# pathod is running on port 9999
+
+BASE_HTTP="/Users/aldo/git/public/pathod/pathoc -Tt 1 -eo -I 200,400,405,502 -p 8080 localhost "
+#$BASE_HTTP -n 10000 "get:'http://localhost:9999':ir,@1"
+#$BASE_HTTP -n 100 "get:'http://localhost:9999':dr"
+#$BASE_HTTP -n 10000 "get:'http://localhost:9999/p/200:ir,@300.0
+
+
+# Assuming:
+# mitmproxy/mitmdump is running on port 8080 in straight proxy mode.
+# pathod with SSL enabled is running on port 9999
+
+BASE_HTTPS="/Users/aldo/git/public/pathod/pathoc -sc localhost:9999 -Tt 1 -eo -I 200,400,404,405,502,800 -p 8080 localhost "
+$BASE_HTTPS -en 10000 "get:'/p/200:b@10:ir,@1'"
+#$BASE_HTTPS -en 10000 "get:'/p/200:ir,@1'"
+
+#$BASE_HTTPS -n 100 "get:'/p/200:dr'"
+#$BASE_HTTPS -n 10000 "get:'/p/200:ir,@3000'"
+#$BASE_HTTPS -n 10000 "get:'/p/200:ir,\"\\n\"'"
diff --git a/test/test_authentication.py b/test/test_authentication.py
deleted file mode 100644
index f7a5ecd3..00000000
--- a/test/test_authentication.py
+++ /dev/null
@@ -1,58 +0,0 @@
-import binascii
-from libmproxy import authentication
-from netlib import odict
-import tutils
-
-
-class TestNullProxyAuth:
- def test_simple(self):
- na = authentication.NullProxyAuth(authentication.PermissivePasswordManager())
- assert not na.auth_challenge_headers()
- assert na.authenticate("foo")
- na.clean({})
-
-
-class TestBasicProxyAuth:
- def test_simple(self):
- ba = authentication.BasicProxyAuth(authentication.PermissivePasswordManager(), "test")
- h = odict.ODictCaseless()
- assert ba.auth_challenge_headers()
- assert not ba.authenticate(h)
-
- def test_parse_auth_value(self):
- ba = authentication.BasicProxyAuth(authentication.PermissivePasswordManager(), "test")
- vals = ("basic", "foo", "bar")
- assert ba.parse_auth_value(ba.unparse_auth_value(*vals)) == vals
- tutils.raises(ValueError, ba.parse_auth_value, "")
- tutils.raises(ValueError, ba.parse_auth_value, "foo bar")
-
- v = "basic " + binascii.b2a_base64("foo")
- tutils.raises(ValueError, ba.parse_auth_value, v)
-
- def test_authenticate_clean(self):
- ba = authentication.BasicProxyAuth(authentication.PermissivePasswordManager(), "test")
-
- hdrs = odict.ODictCaseless()
- vals = ("basic", "foo", "bar")
- hdrs[ba.AUTH_HEADER] = [ba.unparse_auth_value(*vals)]
- assert ba.authenticate(hdrs)
-
- ba.clean(hdrs)
- assert not ba.AUTH_HEADER in hdrs
-
-
- hdrs[ba.AUTH_HEADER] = [""]
- assert not ba.authenticate(hdrs)
-
- hdrs[ba.AUTH_HEADER] = ["foo"]
- assert not ba.authenticate(hdrs)
-
- vals = ("foo", "foo", "bar")
- hdrs[ba.AUTH_HEADER] = [ba.unparse_auth_value(*vals)]
- assert not ba.authenticate(hdrs)
-
- ba = authentication.BasicProxyAuth(authentication.PasswordManager(), "test")
- vals = ("basic", "foo", "bar")
- hdrs[ba.AUTH_HEADER] = [ba.unparse_auth_value(*vals)]
- assert not ba.authenticate(hdrs)
-
diff --git a/test/test_console_common.py b/test/test_console_common.py
new file mode 100644
index 00000000..29bf7b84
--- /dev/null
+++ b/test/test_console_common.py
@@ -0,0 +1,10 @@
+import libmproxy.console.common as common
+from libmproxy import utils, flow, encoding
+import tutils
+
+
+def test_format_flow():
+ f = tutils.tflow_full()
+ assert common.format_flow(f, True)
+ assert common.format_flow(f, True, hostheader=True)
+ assert common.format_flow(f, True, extended=True)
diff --git a/test/test_controller.py b/test/test_controller.py
new file mode 100644
index 00000000..f6d6b5eb
--- /dev/null
+++ b/test/test_controller.py
@@ -0,0 +1,12 @@
+import mock
+from libmproxy import controller
+
+
+class TestMaster:
+ def test_default_handler(self):
+ m = controller.Master(None)
+ msg = mock.MagicMock()
+ m.handle(msg)
+ assert msg.reply.call_count == 1
+
+
diff --git a/test/test_dump.py b/test/test_dump.py
index 5d3f9133..94d0b195 100644
--- a/test/test_dump.py
+++ b/test/test_dump.py
@@ -1,6 +1,5 @@
import os
from cStringIO import StringIO
-import libpry
from libmproxy import dump, flow, proxy
import tutils
import mock
@@ -13,8 +12,10 @@ def test_strfuncs():
t = tutils.treq()
t.client_conn = None
t.stickycookie = True
- assert "stickycookie" in dump.str_request(t)
- assert "replay" in dump.str_request(t)
+ assert "stickycookie" in dump.str_request(t, False)
+ assert "stickycookie" in dump.str_request(t, True)
+ assert "replay" in dump.str_request(t, False)
+ assert "replay" in dump.str_request(t, True)
class TestDumpMaster:
@@ -65,7 +66,7 @@ class TestDumpMaster:
cs = StringIO()
o = dump.Options(server_replay="nonexistent", kill=True)
- libpry.raises(dump.DumpError, dump.DumpMaster, None, o, None, outfile=cs)
+ tutils.raises(dump.DumpError, dump.DumpMaster, None, o, None, outfile=cs)
with tutils.tmpdir() as t:
p = os.path.join(t, "rep")
@@ -90,7 +91,7 @@ class TestDumpMaster:
self._flowfile(p)
assert "GET" in self._dummy_cycle(0, None, "", verbosity=1, rfile=p)
- libpry.raises(
+ tutils.raises(
dump.DumpError, self._dummy_cycle,
0, None, "", verbosity=1, rfile="/nonexistent"
)
@@ -101,7 +102,6 @@ class TestDumpMaster:
def test_options(self):
o = dump.Options(verbosity = 2)
assert o.verbosity == 2
- libpry.raises(AttributeError, dump.Options, nonexistent = 2)
def test_filter(self):
assert not "GET" in self._dummy_cycle(1, "~u foo", "", verbosity=1)
@@ -131,7 +131,7 @@ class TestDumpMaster:
assert len(list(flow.FlowReader(open(p)).stream())) == 1
def test_write_err(self):
- libpry.raises(
+ tutils.raises(
dump.DumpError,
self._dummy_cycle,
1,
@@ -149,11 +149,11 @@ class TestDumpMaster:
assert "XREQUEST" in ret
assert "XRESPONSE" in ret
assert "XCLIENTDISCONNECT" in ret
- libpry.raises(
+ tutils.raises(
dump.DumpError,
self._dummy_cycle, 1, None, "", script="nonexistent"
)
- libpry.raises(
+ tutils.raises(
dump.DumpError,
self._dummy_cycle, 1, None, "", script="starterr.py"
)
diff --git a/test/test_flow.py b/test/test_flow.py
index 6aa898ad..fce4e98a 100644
--- a/test/test_flow.py
+++ b/test/test_flow.py
@@ -498,6 +498,23 @@ class TestSerialize:
fm.load_flows(r)
assert len(s._flow_list) == 6
+ def test_filter(self):
+ sio = StringIO()
+ fl = filt.parse("~c 200")
+ w = flow.FilteredFlowWriter(sio, fl)
+
+ f = tutils.tflow_full()
+ f.response.code = 200
+ w.add(f)
+
+ f = tutils.tflow_full()
+ f.response.code = 201
+ w.add(f)
+
+ sio.seek(0)
+ r = flow.FlowReader(sio)
+ assert len(list(r.stream()))
+
def test_error(self):
sio = StringIO()
@@ -723,7 +740,7 @@ class TestFlowMaster:
fm = flow.FlowMaster(None, s)
tf = tutils.tflow_full()
- fm.start_stream(file(p, "ab"))
+ fm.start_stream(file(p, "ab"), None)
fm.handle_request(tf.request)
fm.handle_response(tf.response)
fm.stop_stream()
@@ -731,7 +748,7 @@ class TestFlowMaster:
assert r()[0].response
tf = tutils.tflow_full()
- fm.start_stream(file(p, "ab"))
+ fm.start_stream(file(p, "ab"), None)
fm.handle_request(tf.request)
fm.shutdown()
@@ -766,6 +783,17 @@ class TestRequest:
r.content = flow.CONTENT_MISSING
assert not r._assemble()
+ def test_get_url(self):
+ h = flow.ODictCaseless()
+ h["test"] = ["test"]
+ c = flow.ClientConnect(("addr", 2222))
+ r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
+ assert r.get_url() == "https://host:22/"
+ assert r.get_url(hostheader=True) == "https://host:22/"
+ r.headers["Host"] = ["foo.com"]
+ assert r.get_url() == "https://host:22/"
+ assert r.get_url(hostheader=True) == "https://foo.com:22/"
+
def test_path_components(self):
h = flow.ODictCaseless()
c = flow.ClientConnect(("addr", 2222))
diff --git a/test/test_fuzzing.py b/test/test_fuzzing.py
new file mode 100644
index 00000000..ba7b751c
--- /dev/null
+++ b/test/test_fuzzing.py
@@ -0,0 +1,39 @@
+import tservers
+
+"""
+ A collection of errors turned up by fuzzing. Errors are integrated here
+ after being fixed to check for regressions.
+"""
+
+class TestFuzzy(tservers.HTTPProxTest):
+ def test_idna_err(self):
+ req = r'get:"http://localhost:%s":i10,"\xc6"'
+ p = self.pathoc()
+ assert p.request(req%self.server.port).status_code == 400
+
+ def test_nullbytes(self):
+ req = r'get:"http://localhost:%s":i19,"\x00"'
+ p = self.pathoc()
+ assert p.request(req%self.server.port).status_code == 400
+
+ def test_invalid_ports(self):
+ req = 'get:"http://localhost:999999"'
+ p = self.pathoc()
+ assert p.request(req).status_code == 400
+
+ def test_invalid_ipv6_url(self):
+ req = 'get:"http://localhost:%s":i13,"["'
+ p = self.pathoc()
+ assert p.request(req%self.server.port).status_code == 400
+
+ def test_invalid_upstream(self):
+ req = r"get:'http://localhost:%s/p/200:i10,\'+\''"
+ p = self.pathoc()
+ assert p.request(req%self.server.port).status_code == 502
+
+ def test_upstream_disconnect(self):
+ req = r'200:d0:h"Date"="Sun, 03 Mar 2013 04:00:00 GMT"'
+ p = self.pathod(req)
+ assert p.status_code == 400
+
+
diff --git a/test/test_proxy.py b/test/test_proxy.py
index 3995b393..5828d077 100644
--- a/test/test_proxy.py
+++ b/test/test_proxy.py
@@ -1,4 +1,5 @@
-from libmproxy import proxy, flow
+import argparse
+from libmproxy import proxy, flow, cmdline
import tutils
from libpathod import test
from netlib import http, tcp
@@ -22,7 +23,6 @@ def test_app_registry():
r.port = 81
assert not ar.get(r)
-
r = tutils.treq()
r.host = "domain2"
r.port = 80
@@ -59,3 +59,90 @@ class TestServerConnection:
sc.connection.close = mock.Mock(side_effect=IOError)
sc.terminate()
+
+class MockParser:
+ def __init__(self):
+ self.err = None
+
+ def error(self, e):
+ self.err = e
+
+ def __repr__(self):
+ return "ParseError(%s)"%self.err
+
+
+class TestProcessProxyOptions:
+ def p(self, *args):
+ parser = argparse.ArgumentParser()
+ cmdline.common_options(parser)
+ opts = parser.parse_args(args=args)
+ m = MockParser()
+ return m, proxy.process_proxy_options(m, opts)
+
+ def assert_err(self, err, *args):
+ m, p = self.p(*args)
+ assert err.lower() in m.err.lower()
+
+ def assert_noerr(self, *args):
+ m, p = self.p(*args)
+ assert p
+ return p
+
+ def test_simple(self):
+ assert self.p()
+
+ def test_cert(self):
+ self.assert_noerr("--cert", tutils.test_data.path("data/testkey.pem"))
+ self.assert_err("does not exist", "--cert", "nonexistent")
+
+ def test_confdir(self):
+ with tutils.tmpdir() as confdir:
+ self.assert_noerr("--confdir", confdir)
+
+ @mock.patch("libmproxy.platform.resolver", None)
+ def test_no_transparent(self):
+ self.assert_err("transparent mode not supported", "-T")
+
+ @mock.patch("libmproxy.platform.resolver")
+ def test_transparent_reverse(self, o):
+ self.assert_err("can't set both", "-P", "reverse", "-T")
+ self.assert_noerr("-T")
+ assert o.call_count == 1
+ self.assert_err("invalid reverse proxy", "-P", "reverse")
+ self.assert_noerr("-P", "http://localhost")
+
+ def test_certs(self):
+ with tutils.tmpdir() as confdir:
+ self.assert_noerr("--client-certs", confdir)
+ self.assert_err("directory does not exist", "--client-certs", "nonexistent")
+
+ self.assert_noerr("--dummy-certs", confdir)
+ self.assert_err("directory does not exist", "--dummy-certs", "nonexistent")
+
+ def test_auth(self):
+ p = self.assert_noerr("--nonanonymous")
+ assert p.authenticator
+
+ p = self.assert_noerr("--htpasswd", tutils.test_data.path("data/htpasswd"))
+ assert p.authenticator
+ self.assert_err("invalid htpasswd file", "--htpasswd", tutils.test_data.path("data/htpasswd.invalid"))
+
+ p = self.assert_noerr("--singleuser", "test:test")
+ assert p.authenticator
+ self.assert_err("invalid single-user specification", "--singleuser", "test")
+
+
+class TestProxyServer:
+ def test_err(self):
+ parser = argparse.ArgumentParser()
+ cmdline.common_options(parser)
+ opts = parser.parse_args(args=[])
+ tutils.raises("error starting proxy server", proxy.ProxyServer, opts, 1)
+
+
+class TestDummyServer:
+ def test_simple(self):
+ d = proxy.DummyServer(None)
+ d.start_slave()
+ d.shutdown()
+
diff --git a/test/test_server.py b/test/test_server.py
index 034fab41..f12fbcee 100644
--- a/test/test_server.py
+++ b/test/test_server.py
@@ -1,6 +1,6 @@
import socket, time
import mock
-from netlib import tcp
+from netlib import tcp, http_auth, http
from libpathod import pathoc
import tutils, tservers
from libmproxy import flow, proxy
@@ -13,11 +13,7 @@ from libmproxy import flow, proxy
for a 200 response.
"""
-class SanityMixin:
- def test_http(self):
- assert self.pathod("304").status_code == 304
- assert self.master.state.view
-
+class CommonMixin:
def test_large(self):
assert len(self.pathod("200:b@50k").content) == 1024*50
@@ -40,27 +36,30 @@ class SanityMixin:
self.master.replay_request(l, block=True)
assert l.error
+ def test_http(self):
+ f = self.pathod("304")
+ assert f.status_code == 304
-class TestHTTP(tservers.HTTPProxTest, SanityMixin):
- def test_app(self):
- p = self.pathoc()
- ret = p.request("get:'http://testapp/'")
- assert ret[1] == 200
- assert ret[4] == "testapp"
-
- def test_app_err(self):
- p = self.pathoc()
- ret = p.request("get:'http://errapp/'")
- assert ret[1] == 500
- assert "ValueError" in ret[4]
+ l = self.master.state.view[0]
+ assert l.request.client_conn.address
+ assert "host" in l.request.headers
+ assert l.response.code == 304
def test_invalid_http(self):
t = tcp.TCPClient("127.0.0.1", self.proxy.port)
t.connect()
- t.wfile.write("invalid\n\n")
+ t.wfile.write("invalid\r\n\r\n")
t.wfile.flush()
assert "Bad Request" in t.rfile.readline()
+
+class TestHTTP(tservers.HTTPProxTest, CommonMixin):
+ def test_app_err(self):
+ p = self.pathoc()
+ ret = p.request("get:'http://errapp/'")
+ assert ret.status_code == 500
+ assert "ValueError" in ret.content
+
def test_invalid_connect(self):
t = tcp.TCPClient("127.0.0.1", self.proxy.port)
t.connect()
@@ -71,16 +70,7 @@ class TestHTTP(tservers.HTTPProxTest, SanityMixin):
def test_upstream_ssl_error(self):
p = self.pathoc()
ret = p.request("get:'https://localhost:%s/'"%self.server.port)
- assert ret[1] == 400
-
- def test_http(self):
- f = self.pathod("304")
- assert f.status_code == 304
-
- l = self.master.state.view[0]
- assert l.request.client_conn.address
- assert "host" in l.request.headers
- assert l.response.code == 304
+ assert ret.status_code == 400
def test_connection_close(self):
# Add a body, so we have a content-length header, which combined with
@@ -116,7 +106,7 @@ class TestHTTP(tservers.HTTPProxTest, SanityMixin):
# within our read loop.
with mock.patch("libmproxy.proxy.ProxyHandler.read_request") as m:
m.side_effect = IOError("error!")
- tutils.raises("empty reply", self.pathod, "304")
+ tutils.raises("server disconnect", self.pathod, "304")
def test_get_connection_switching(self):
def switched(l):
@@ -132,30 +122,101 @@ class TestHTTP(tservers.HTTPProxTest, SanityMixin):
def test_get_connection_err(self):
p = self.pathoc()
ret = p.request("get:'http://localhost:0'")
- assert ret[1] == 502
+ assert ret.status_code == 502
+
+ def test_blank_leading_line(self):
+ p = self.pathoc()
+ req = "get:'%s/p/201':i0,'\r\n'"
+ assert p.request(req%self.server.urlbase).status_code == 201
+
+ def test_invalid_headers(self):
+ p = self.pathoc()
+ req = p.request("get:'http://foo':h':foo'='bar'")
+ assert req.status_code == 400
-class TestHTTPS(tservers.HTTPProxTest, SanityMixin):
+class TestHTTPAuth(tservers.HTTPProxTest):
+ authenticator = http_auth.BasicProxyAuth(http_auth.PassManSingleUser("test", "test"), "realm")
+ def test_auth(self):
+ assert self.pathod("202").status_code == 407
+ p = self.pathoc()
+ ret = p.request("""
+ get
+ 'http://localhost:%s/p/202'
+ h'%s'='%s'
+ """%(
+ self.server.port,
+ http_auth.BasicProxyAuth.AUTH_HEADER,
+ http.assemble_http_basic_auth("basic", "test", "test")
+ ))
+ assert ret.status_code == 202
+
+
+class TestHTTPConnectSSLError(tservers.HTTPProxTest):
+ certfile = True
+ def test_go(self):
+ p = self.pathoc()
+ req = "connect:'localhost:%s'"%self.proxy.port
+ assert p.request(req).status_code == 200
+ assert p.request(req).status_code == 400
+
+
+class TestHTTPS(tservers.HTTPProxTest, CommonMixin):
ssl = True
clientcerts = True
def test_clientcert(self):
f = self.pathod("304")
+ assert f.status_code == 304
assert self.server.last_log()["request"]["clientcert"]["keyinfo"]
+ def test_sni(self):
+ f = self.pathod("304", sni="testserver.com")
+ assert f.status_code == 304
+ l = self.server.last_log()
+ assert self.server.last_log()["request"]["sni"] == "testserver.com"
-class TestHTTPSCertfile(tservers.HTTPProxTest, SanityMixin):
+ def test_error_post_connect(self):
+ p = self.pathoc()
+ assert p.request("get:/:i0,'invalid\r\n\r\n'").status_code == 400
+
+
+class TestHTTPSNoUpstream(tservers.HTTPProxTest, CommonMixin):
+ ssl = True
+ no_upstream_cert = True
+ def test_cert_gen_error(self):
+ f = self.pathoc_raw()
+ f.connect((u"foo..bar".encode("utf8"), 0))
+ f.request("get:/")
+ assert "dummy cert" in "".join(self.proxy.log)
+
+
+class TestHTTPSCertfile(tservers.HTTPProxTest, CommonMixin):
ssl = True
certfile = True
def test_certfile(self):
assert self.pathod("304")
-class TestReverse(tservers.ReverseProxTest, SanityMixin):
+class TestReverse(tservers.ReverseProxTest, CommonMixin):
reverse = True
-class TestTransparent(tservers.TransparentProxTest, SanityMixin):
- transparent = True
+class TestTransparent(tservers.TransparentProxTest, CommonMixin):
+ ssl = False
+
+
+class TestTransparentSSL(tservers.TransparentProxTest, CommonMixin):
+ ssl = True
+ def test_sni(self):
+ f = self.pathod("304", sni="testserver.com")
+ assert f.status_code == 304
+ l = self.server.last_log()
+ assert self.server.last_log()["request"]["sni"] == "testserver.com"
+
+ def test_sslerr(self):
+ p = pathoc.Pathoc("localhost", self.proxy.port)
+ p.connect()
+ assert p.request("get:/").status_code == 400
class TestProxy(tservers.HTTPProxTest):
@@ -216,8 +277,7 @@ class MasterFakeResponse(tservers.TestMaster):
class TestFakeResponse(tservers.HTTPProxTest):
masterclass = MasterFakeResponse
- def test_kill(self):
- p = self.pathoc()
+ def test_fake(self):
f = self.pathod("200")
assert "header_response" in f.headers.keys()
@@ -231,8 +291,7 @@ class MasterKillRequest(tservers.TestMaster):
class TestKillRequest(tservers.HTTPProxTest):
masterclass = MasterKillRequest
def test_kill(self):
- p = self.pathoc()
- tutils.raises("empty reply", self.pathod, "200")
+ tutils.raises("server disconnect", self.pathod, "200")
# Nothing should have hit the server
assert not self.server.last_log()
@@ -245,8 +304,34 @@ class MasterKillResponse(tservers.TestMaster):
class TestKillResponse(tservers.HTTPProxTest):
masterclass = MasterKillResponse
def test_kill(self):
- p = self.pathoc()
- tutils.raises("empty reply", self.pathod, "200")
+ tutils.raises("server disconnect", self.pathod, "200")
# The server should have seen a request
assert self.server.last_log()
+
+class EResolver(tservers.TResolver):
+ def original_addr(self, sock):
+ return None
+
+
+class TestTransparentResolveError(tservers.TransparentProxTest):
+ resolver = EResolver
+ def test_resolve_error(self):
+ assert self.pathod("304").status_code == 502
+
+
+
+class MasterIncomplete(tservers.TestMaster):
+ def handle_request(self, m):
+ resp = tutils.tresp()
+ resp.content = flow.CONTENT_MISSING
+ m.reply(resp)
+
+
+class TestIncompleteResponse(tservers.HTTPProxTest):
+ masterclass = MasterIncomplete
+ def test_incomplete(self):
+ assert self.pathod("200").status_code == 502
+
+
+
diff --git a/test/tservers.py b/test/tservers.py
index 998ad6c6..0c2f8c2f 100644
--- a/test/tservers.py
+++ b/test/tservers.py
@@ -1,6 +1,5 @@
import threading, Queue
import flask
-import human_curl as hurl
import libpathod.test, libpathod.pathoc
from libmproxy import proxy, flow, controller
import tutils
@@ -28,7 +27,7 @@ class TestMaster(flow.FlowMaster):
state = flow.State()
flow.FlowMaster.__init__(self, s, state)
self.testq = testq
- self.log = []
+ self.clear_log()
def handle_request(self, m):
flow.FlowMaster.handle_request(self, m)
@@ -38,6 +37,9 @@ class TestMaster(flow.FlowMaster):
flow.FlowMaster.handle_response(self, m)
m.reply()
+ def clear_log(self):
+ self.log = []
+
def handle_log(self, l):
self.log.append(l.msg)
l.reply()
@@ -69,7 +71,8 @@ class ProxTestBase:
ssl = None
clientcerts = False
certfile = None
-
+ no_upstream_cert = False
+ authenticator = None
masterclass = TestMaster
@classmethod
def setupAll(cls):
@@ -78,7 +81,9 @@ class ProxTestBase:
cls.server2 = libpathod.test.Daemon(ssl=cls.ssl)
pconf = cls.get_proxy_config()
config = proxy.ProxyConfig(
+ no_upstream_cert = cls.no_upstream_cert,
cacert = tutils.test_data.path("data/serverkey.pem"),
+ authenticator = cls.authenticator,
**pconf
)
tmaster = cls.masterclass(cls.tqueue, config)
@@ -96,7 +101,10 @@ class ProxTestBase:
cls.server2.shutdown()
def setUp(self):
+ self.master.clear_log()
self.master.state.clear()
+ self.server.clear_log()
+ self.server2.clear_log()
@property
def scheme(self):
@@ -122,24 +130,31 @@ class ProxTestBase:
class HTTPProxTest(ProxTestBase):
- def pathoc(self, connect_to = None):
+ def pathoc_raw(self):
+ return libpathod.pathoc.Pathoc("127.0.0.1", self.proxy.port)
+
+ def pathoc(self, sni=None):
"""
Returns a connected Pathoc instance.
"""
- p = libpathod.pathoc.Pathoc("localhost", self.proxy.port)
- p.connect(connect_to)
+ p = libpathod.pathoc.Pathoc("localhost", self.proxy.port, ssl=self.ssl, sni=sni)
+ if self.ssl:
+ p.connect(("127.0.0.1", self.server.port))
+ else:
+ p.connect()
return p
- def pathod(self, spec):
+ def pathod(self, spec, sni=None):
"""
- Constructs a pathod request, with the appropriate base and proxy.
+ Constructs a pathod GET request, with the appropriate base and proxy.
"""
- return hurl.get(
- self.server.urlbase + "/p/" + spec,
- proxy=self.proxies,
- validate_cert=False,
- #debug=hurl.utils.stdout_debug
- )
+ p = self.pathoc(sni=sni)
+ spec = spec.encode("string_escape")
+ if self.ssl:
+ q = "get:'/p/%s'"%spec
+ else:
+ q = "get:'%s/p/%s'"%(self.server.urlbase, spec)
+ return p.request(q)
class TResolver:
@@ -152,25 +167,39 @@ class TResolver:
class TransparentProxTest(ProxTestBase):
ssl = None
+ resolver = TResolver
@classmethod
def get_proxy_config(cls):
d = ProxTestBase.get_proxy_config()
+ if cls.ssl:
+ ports = [cls.server.port, cls.server2.port]
+ else:
+ ports = []
d["transparent_proxy"] = dict(
- resolver = TResolver(cls.server.port),
- sslports = []
+ resolver = cls.resolver(cls.server.port),
+ sslports = ports
)
return d
- def pathod(self, spec):
+ def pathod(self, spec, sni=None):
"""
- Constructs a pathod request, with the appropriate base and proxy.
+ Constructs a pathod GET request, with the appropriate base and proxy.
"""
- r = hurl.get(
- "http://127.0.0.1:%s"%self.proxy.port + "/p/" + spec,
- validate_cert=False,
- #debug=hurl.utils.stdout_debug
- )
- return r
+ if self.ssl:
+ p = self.pathoc(sni=sni)
+ q = "get:'/p/%s'"%spec
+ else:
+ p = self.pathoc()
+ q = "get:'/p/%s'"%spec
+ return p.request(q)
+
+ def pathoc(self, sni=None):
+ """
+ Returns a connected Pathoc instance.
+ """
+ p = libpathod.pathoc.Pathoc("localhost", self.proxy.port, ssl=self.ssl, sni=sni)
+ p.connect()
+ return p
class ReverseProxTest(ProxTestBase):
@@ -185,14 +214,23 @@ class ReverseProxTest(ProxTestBase):
)
return d
- def pathod(self, spec):
+ def pathoc(self, sni=None):
"""
- Constructs a pathod request, with the appropriate base and proxy.
+ Returns a connected Pathoc instance.
"""
- r = hurl.get(
- "http://127.0.0.1:%s"%self.proxy.port + "/p/" + spec,
- validate_cert=False,
- #debug=hurl.utils.stdout_debug
- )
- return r
+ p = libpathod.pathoc.Pathoc("localhost", self.proxy.port, ssl=self.ssl, sni=sni)
+ p.connect()
+ return p
+
+ def pathod(self, spec, sni=None):
+ """
+ Constructs a pathod GET request, with the appropriate base and proxy.
+ """
+ if self.ssl:
+ p = self.pathoc(sni=sni)
+ q = "get:'/p/%s'"%spec
+ else:
+ p = self.pathoc()
+ q = "get:'/p/%s'"%spec
+ return p.request(q)