def setUp(self): """Initialize this test instance.""" yield super(ServerTunnelProtocolTestCase, self).setUp() self.ws = MockWebServer() self.addCleanup(self.ws.stop) self.dest_url = self.ws.get_iri().encode("utf-8") + SIMPLERESOURCE self.transport = FakeTransport() self.transport.cookie = FAKE_COOKIE self.fake_client = FakeClient() self.proto = tunnel_server.ServerTunnelProtocol( lambda _: self.fake_client) self.fake_client.protocol = self.proto self.proto.transport = self.transport self.cookie_line = "%s: %s" % (tunnel_server.TUNNEL_COOKIE_HEADER, FAKE_COOKIE)
class ServerTunnelProtocolTestCase(SquidTestCase): """Tests for the ServerTunnelProtocol.""" @defer.inlineCallbacks def setUp(self): """Initialize this test instance.""" yield super(ServerTunnelProtocolTestCase, self).setUp() self.ws = MockWebServer() self.addCleanup(self.ws.stop) self.dest_url = self.ws.get_iri().encode("utf-8") + SIMPLERESOURCE self.transport = FakeTransport() self.transport.cookie = FAKE_COOKIE self.fake_client = FakeClient() self.proto = tunnel_server.ServerTunnelProtocol( lambda _: self.fake_client) self.fake_client.protocol = self.proto self.proto.transport = self.transport self.cookie_line = "%s: %s" % (tunnel_server.TUNNEL_COOKIE_HEADER, FAKE_COOKIE) def test_broken_request(self): """Broken request.""" self.proto.dataReceived("Broken request." + CRLF) self.assertTrue(self.transport.getvalue().startswith("HTTP/1.0 400 "), "A broken request must fail.") def test_wrong_method(self): """Wrong method.""" self.proto.dataReceived("GET http://slashdot.org HTTP/1.0" + CRLF) self.assertTrue(self.transport.getvalue().startswith("HTTP/1.0 405 "), "Using a wrong method fails.") def test_invalid_http_version(self): """Invalid HTTP version.""" self.proto.dataReceived("CONNECT 127.0.0.1:9999 HTTP/1.1" + CRLF) self.assertTrue(self.transport.getvalue().startswith("HTTP/1.0 505 "), "Invalid http version is not allowed.") def test_connection_is_established(self): """The response code is sent.""" expected = "HTTP/1.0 200 Proxy connection established" + CRLF self.proto.dataReceived("CONNECT 127.0.0.1:9999 HTTP/1.0" + CRLF + self.cookie_line + CRLF * 2) self.assertTrue(self.transport.getvalue().startswith(expected), "First line must be the response status") def test_connection_fails(self): """The connection to the other end fails, and it's handled.""" error = tunnel_server.ConnectionError() self.patch(self.fake_client, "connection_result", defer.fail(error)) expected = "HTTP/1.0 500 Connection error" + CRLF self.proto.dataReceived("CONNECT 127.0.0.1:9999 HTTP/1.0" + CRLF + self.cookie_line + CRLF * 2) self.assertTrue(self.transport.getvalue().startswith(expected), "The connection should fail at this point.") def test_headers_stored(self): """The request headers are stored.""" expected = [ ("Header1", "value1"), ("Header2", "value2"), ] self.proto.dataReceived("CONNECT 127.0.0.1:9999 HTTP/1.0" + CRLF + "Header1: value1" + CRLF + "Header2: value2" + CRLF + CRLF) self.assertEqual(self.proto.received_headers, expected) def test_cookie_header_present(self): """The cookie header must be present.""" self.proto.received_headers = [ (tunnel_server.TUNNEL_COOKIE_HEADER, FAKE_COOKIE), ] self.proto.verify_cookie() def test_cookie_header_absent(self): """The tunnel should refuse connections without the cookie.""" self.proto.received_headers = [] exception = self.assertRaises(tunnel_server.ConnectionError, self.proto.verify_cookie) self.assertEqual(exception.code, 418) def test_successful_connect(self): """A successful connect thru the tunnel.""" url = urlparse(self.dest_url) data = FAKE_SESSION_TEMPLATE % (url.netloc, self.transport.cookie, url.path) self.proto.dataReceived(data) lines = self.transport.getvalue().split(CRLF) self.assertEqual(lines[-1], SAMPLE_CONTENT) def test_header_split(self): """Test a header with many colons.""" self.proto.header_line("key: host:port") self.assertIn("key", dict(self.proto.received_headers)) @defer.inlineCallbacks def test_keyring_credentials_are_retried(self): """Wrong credentials are retried with values from keyring.""" self.fake_client.check_credentials = True self.patch(self.proto, "verify_cookie", lambda: None) self.patch(self.proto, "error_response", lambda code, desc: self.fail(desc)) self.proto.proxy_domain = "xxx" self.patch(tunnel_server.Keyring, "get_credentials", lambda _, domain: defer.succeed(FAKE_CREDS)) yield self.proto.headers_done() def test_creds_are_not_logged(self): """The proxy credentials are not logged.""" log = [] self.patch(tunnel_server.logger, "info", lambda text, *args: log.append(text % args)) proxy = tunnel_server.build_proxy(FAKE_AUTH_SETTINGS) authenticator = QAuthenticator() username = FAKE_AUTH_SETTINGS["http"]["username"] password = FAKE_AUTH_SETTINGS["http"]["password"] self.proto.proxy_credentials = { "username": username, "password": password, } self.proto.proxy_domain = proxy.hostName() self.proto.proxy_auth_required(proxy, authenticator) for line in log: self.assertNotIn(username, line) self.assertNotIn(password, line)