From ba674ad5514c5f30315fc688a07fdac634d94dfc Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 1 Mar 2013 09:05:39 +1300 Subject: New SNI handling mechanism. --- test/test_server.py | 62 ++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'test/test_server.py') diff --git a/test/test_server.py b/test/test_server.py index 034fab41..466c0f94 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -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,19 +36,23 @@ 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" + l = self.master.state.view[0] + assert l.request.client_conn.address + assert "host" in l.request.headers + assert l.response.code == 304 + + +class TestHTTP(tservers.HTTPProxTest, CommonMixin): def test_app_err(self): p = self.pathoc() ret = p.request("get:'http://errapp/'") - assert ret[1] == 500 - assert "ValueError" in ret[4] + assert ret.status_code == 500 + assert "ValueError" in ret.content def test_invalid_http(self): t = tcp.TCPClient("127.0.0.1", self.proxy.port) @@ -71,16 +71,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 +107,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 +123,39 @@ 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 -class TestHTTPS(tservers.HTTPProxTest, SanityMixin): +class TestHTTPS(tservers.HTTPProxTest, CommonMixin): ssl = True clientcerts = True def test_clientcert(self): f = self.pathod("304") assert self.server.last_log()["request"]["clientcert"]["keyinfo"] + def test_sni(self): + pass + -class TestHTTPSCertfile(tservers.HTTPProxTest, SanityMixin): +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): +class TestTransparent(tservers.TransparentProxTest, CommonMixin): + transparent = True + ssl = False + + +class TestTransparentSSL(tservers.TransparentProxTest, CommonMixin): transparent = True + ssl = True class TestProxy(tservers.HTTPProxTest): @@ -232,7 +232,7 @@ 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() @@ -246,7 +246,7 @@ 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() -- cgit v1.2.3 From 10db82e9a030235ab884e70d1809ad6d673c2d13 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 2 Mar 2013 14:52:05 +1300 Subject: Test SNI for ordinary proxy connections. --- test/test_server.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'test/test_server.py') diff --git a/test/test_server.py b/test/test_server.py index 466c0f94..244f972f 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -131,10 +131,14 @@ class TestHTTPS(tservers.HTTPProxTest, CommonMixin): 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): - pass + 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, CommonMixin): -- cgit v1.2.3 From a95d78438c7197b0b6643a61899914083de70da9 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 2 Mar 2013 15:06:49 +1300 Subject: Test SNI for transparent mode. --- test/test_server.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/test_server.py') diff --git a/test/test_server.py b/test/test_server.py index 244f972f..47bd56b1 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -160,6 +160,12 @@ class TestTransparent(tservers.TransparentProxTest, CommonMixin): class TestTransparentSSL(tservers.TransparentProxTest, CommonMixin): transparent = True 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" + class TestProxy(tservers.HTTPProxTest): -- cgit v1.2.3 From 415844511c19b17743b42a5833590d1d683427d2 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 2 Mar 2013 16:59:16 +1300 Subject: Test cert generation errors. --- test/test_server.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'test/test_server.py') diff --git a/test/test_server.py b/test/test_server.py index 47bd56b1..86a75452 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -141,6 +141,16 @@ class TestHTTPS(tservers.HTTPProxTest, CommonMixin): assert self.server.last_log()["request"]["sni"] == "testserver.com" +class TestHTTPSNoUpstream(tservers.HTTPProxTest, CommonMixin): + ssl = True + no_upstream_cert = True + def test_cert_gen_error(self): + f = self.pathoc_raw() + f.connect((u"\u2102\u0001".encode("utf8"), 0)) + f.request("get:/") + assert "dummy cert" in "".join(self.proxy.log) + + class TestHTTPSCertfile(tservers.HTTPProxTest, CommonMixin): ssl = True certfile = True @@ -227,7 +237,6 @@ class MasterFakeResponse(tservers.TestMaster): class TestFakeResponse(tservers.HTTPProxTest): masterclass = MasterFakeResponse def test_kill(self): - p = self.pathoc() f = self.pathod("200") assert "header_response" in f.headers.keys() @@ -241,7 +250,6 @@ class MasterKillRequest(tservers.TestMaster): class TestKillRequest(tservers.HTTPProxTest): masterclass = MasterKillRequest def test_kill(self): - p = self.pathoc() tutils.raises("server disconnect", self.pathod, "200") # Nothing should have hit the server assert not self.server.last_log() @@ -255,7 +263,6 @@ class MasterKillResponse(tservers.TestMaster): class TestKillResponse(tservers.HTTPProxTest): masterclass = MasterKillResponse def test_kill(self): - p = self.pathoc() tutils.raises("server disconnect", self.pathod, "200") # The server should have seen a request assert self.server.last_log() -- cgit v1.2.3 From c20d1d7d32ea2ab1d1c4dd9a34724a8732c23338 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 2 Mar 2013 22:42:36 +1300 Subject: Extend unit tests for proxy.py to some tricky cases. --- test/test_server.py | 59 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 9 deletions(-) (limited to 'test/test_server.py') diff --git a/test/test_server.py b/test/test_server.py index 86a75452..3a1b019f 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -45,6 +45,12 @@ class CommonMixin: 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\r\n\r\n") + t.wfile.flush() + assert "Bad Request" in t.rfile.readline() class TestHTTP(tservers.HTTPProxTest, CommonMixin): @@ -54,13 +60,6 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin): assert ret.status_code == 500 assert "ValueError" in ret.content - 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.flush() - assert "Bad Request" in t.rfile.readline() - def test_invalid_connect(self): t = tcp.TCPClient("127.0.0.1", self.proxy.port) t.connect() @@ -125,6 +124,25 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin): ret = p.request("get:'http://localhost:0'") 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'") + print req + + +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 @@ -140,6 +158,11 @@ class TestHTTPS(tservers.HTTPProxTest, CommonMixin): l = self.server.last_log() assert self.server.last_log()["request"]["sni"] == "testserver.com" + 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 @@ -163,12 +186,10 @@ class TestReverse(tservers.ReverseProxTest, CommonMixin): class TestTransparent(tservers.TransparentProxTest, CommonMixin): - transparent = True ssl = False class TestTransparentSSL(tservers.TransparentProxTest, CommonMixin): - transparent = True ssl = True def test_sni(self): f = self.pathod("304", sni="testserver.com") @@ -176,6 +197,10 @@ class TestTransparentSSL(tservers.TransparentProxTest, CommonMixin): 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): @@ -267,3 +292,19 @@ class TestKillResponse(tservers.HTTPProxTest): # 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 + + + + + + -- cgit v1.2.3 From 5c6587d4a80cc45b23154237ca94858da60c7da5 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 3 Mar 2013 10:37:06 +1300 Subject: Move HTTP auth module to netlib. --- test/test_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/test_server.py') diff --git a/test/test_server.py b/test/test_server.py index 3a1b019f..0af4bae8 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -132,7 +132,7 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin): def test_invalid_headers(self): p = self.pathoc() req = p.request("get:'http://foo':h':foo'='bar'") - print req + assert req.status_code == 400 class TestHTTPConnectSSLError(tservers.HTTPProxTest): -- cgit v1.2.3 From 33cdd5d0836b706a9d06c332fa5381bbeb4fa69f Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 3 Mar 2013 11:04:33 +1300 Subject: Unit test proxy auth. --- test/test_server.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'test/test_server.py') diff --git a/test/test_server.py b/test/test_server.py index 0af4bae8..8a6228ad 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 @@ -135,6 +135,23 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin): assert req.status_code == 400 +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): @@ -163,7 +180,6 @@ class TestHTTPS(tservers.HTTPProxTest, CommonMixin): assert p.request("get:/:i0,'invalid\r\n\r\n'").status_code == 400 - class TestHTTPSNoUpstream(tservers.HTTPProxTest, CommonMixin): ssl = True no_upstream_cert = True @@ -303,8 +319,3 @@ class TestTransparentResolveError(tservers.TransparentProxTest): def test_resolve_error(self): assert self.pathod("304").status_code == 502 - - - - - -- cgit v1.2.3 From 2465b8a376a7eb04eef6a1cce46dd11a8f1830d8 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 3 Mar 2013 12:13:33 +1300 Subject: 100% unit test coverage on proxy.py. Hallelujah! --- test/test_server.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'test/test_server.py') diff --git a/test/test_server.py b/test/test_server.py index 8a6228ad..cc1fa8ce 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -277,7 +277,7 @@ class MasterFakeResponse(tservers.TestMaster): class TestFakeResponse(tservers.HTTPProxTest): masterclass = MasterFakeResponse - def test_kill(self): + def test_fake(self): f = self.pathod("200") assert "header_response" in f.headers.keys() @@ -319,3 +319,19 @@ class TestTransparentResolveError(tservers.TransparentProxTest): 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 + + + -- cgit v1.2.3 From cde66cd58470cd68a76a9d8b1022a45e99a5cd8d Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 3 Mar 2013 22:03:27 +1300 Subject: Fuzzing, and fixes for errors found with fuzzing. --- test/test_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/test_server.py') diff --git a/test/test_server.py b/test/test_server.py index cc1fa8ce..f12fbcee 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -185,7 +185,7 @@ class TestHTTPSNoUpstream(tservers.HTTPProxTest, CommonMixin): no_upstream_cert = True def test_cert_gen_error(self): f = self.pathoc_raw() - f.connect((u"\u2102\u0001".encode("utf8"), 0)) + f.connect((u"foo..bar".encode("utf8"), 0)) f.request("get:/") assert "dummy cert" in "".join(self.proxy.log) -- cgit v1.2.3