aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/mitmproxy/addons/test_proxyauth.py174
-rw-r--r--test/mitmproxy/addons/test_upstream_auth.py65
-rw-r--r--test/mitmproxy/net/http/test_authentication.py122
-rw-r--r--test/mitmproxy/protocol/test_http1.py2
-rw-r--r--test/mitmproxy/test_eventsequence.py81
-rw-r--r--test/mitmproxy/test_proxy.py31
-rw-r--r--test/mitmproxy/test_proxy_config.py21
-rw-r--r--test/mitmproxy/test_server.py103
8 files changed, 364 insertions, 235 deletions
diff --git a/test/mitmproxy/addons/test_proxyauth.py b/test/mitmproxy/addons/test_proxyauth.py
new file mode 100644
index 00000000..494a992f
--- /dev/null
+++ b/test/mitmproxy/addons/test_proxyauth.py
@@ -0,0 +1,174 @@
+import binascii
+
+from mitmproxy import exceptions
+from mitmproxy.test import taddons
+from mitmproxy.test import tflow
+from mitmproxy.test import tutils
+from mitmproxy.addons import proxyauth
+
+
+def test_parse_http_basic_auth():
+ assert proxyauth.parse_http_basic_auth(
+ proxyauth.mkauth("test", "test")
+ ) == ("basic", "test", "test")
+ assert not proxyauth.parse_http_basic_auth("")
+ assert not proxyauth.parse_http_basic_auth("foo bar")
+ v = "basic " + binascii.b2a_base64(b"foo").decode("ascii")
+ assert not proxyauth.parse_http_basic_auth(v)
+
+
+def test_configure():
+ up = proxyauth.ProxyAuth()
+ with taddons.context() as ctx:
+ tutils.raises(
+ exceptions.OptionsError,
+ ctx.configure, up, auth_singleuser="foo"
+ )
+
+ ctx.configure(up, auth_singleuser="foo:bar")
+ assert up.singleuser == ["foo", "bar"]
+
+ ctx.configure(up, auth_singleuser=None)
+ assert up.singleuser is None
+
+ ctx.configure(up, auth_nonanonymous=True)
+ assert up.nonanonymous
+ ctx.configure(up, auth_nonanonymous=False)
+ assert not up.nonanonymous
+
+ tutils.raises(
+ exceptions.OptionsError,
+ ctx.configure,
+ up,
+ auth_htpasswd = tutils.test_data.path(
+ "mitmproxy/net/data/server.crt"
+ )
+ )
+ tutils.raises(
+ exceptions.OptionsError,
+ ctx.configure,
+ up,
+ auth_htpasswd = "nonexistent"
+ )
+
+ ctx.configure(
+ up,
+ auth_htpasswd = tutils.test_data.path(
+ "mitmproxy/net/data/htpasswd"
+ )
+ )
+ assert up.htpasswd
+ assert up.htpasswd.check_password("test", "test")
+ assert not up.htpasswd.check_password("test", "foo")
+ ctx.configure(up, auth_htpasswd = None)
+ assert not up.htpasswd
+
+ tutils.raises(
+ exceptions.OptionsError,
+ ctx.configure,
+ up,
+ auth_nonanonymous = True,
+ mode = "transparent"
+ )
+ tutils.raises(
+ exceptions.OptionsError,
+ ctx.configure,
+ up,
+ auth_nonanonymous = True,
+ mode = "socks5"
+ )
+
+
+def test_check():
+ up = proxyauth.ProxyAuth()
+ with taddons.context() as ctx:
+ ctx.configure(up, auth_nonanonymous=True)
+ f = tflow.tflow()
+ assert not up.check(f)
+ f.request.headers["Proxy-Authorization"] = proxyauth.mkauth(
+ "test", "test"
+ )
+ assert up.check(f)
+
+ f.request.headers["Proxy-Authorization"] = "invalid"
+ assert not up.check(f)
+
+ f.request.headers["Proxy-Authorization"] = proxyauth.mkauth(
+ "test", "test", scheme = "unknown"
+ )
+ assert not up.check(f)
+
+ ctx.configure(up, auth_nonanonymous=False, auth_singleuser="test:test")
+ f.request.headers["Proxy-Authorization"] = proxyauth.mkauth(
+ "test", "test"
+ )
+ assert up.check(f)
+ ctx.configure(up, auth_nonanonymous=False, auth_singleuser="test:foo")
+ assert not up.check(f)
+
+ ctx.configure(
+ up,
+ auth_singleuser = None,
+ auth_htpasswd = tutils.test_data.path(
+ "mitmproxy/net/data/htpasswd"
+ )
+ )
+ f.request.headers["Proxy-Authorization"] = proxyauth.mkauth(
+ "test", "test"
+ )
+ assert up.check(f)
+ f.request.headers["Proxy-Authorization"] = proxyauth.mkauth(
+ "test", "foo"
+ )
+ assert not up.check(f)
+
+
+def test_authenticate():
+ up = proxyauth.ProxyAuth()
+ with taddons.context() as ctx:
+ ctx.configure(up, auth_nonanonymous=True)
+
+ f = tflow.tflow()
+ assert not f.response
+ up.authenticate(f)
+ assert f.response.status_code == 407
+
+ f = tflow.tflow()
+ f.request.headers["Proxy-Authorization"] = proxyauth.mkauth(
+ "test", "test"
+ )
+ up.authenticate(f)
+ assert not f.response
+ assert not f.request.headers.get("Proxy-Authorization")
+
+ f = tflow.tflow()
+ f.mode = "transparent"
+ assert not f.response
+ up.authenticate(f)
+ assert f.response.status_code == 401
+
+ f = tflow.tflow()
+ f.mode = "transparent"
+ f.request.headers["Authorization"] = proxyauth.mkauth(
+ "test", "test"
+ )
+ up.authenticate(f)
+ assert not f.response
+ assert not f.request.headers.get("Authorization")
+
+
+def test_handlers():
+ up = proxyauth.ProxyAuth()
+ with taddons.context() as ctx:
+ ctx.configure(up, auth_nonanonymous=True)
+
+ f = tflow.tflow()
+ assert not f.response
+ up.requestheaders(f)
+ assert f.response.status_code == 407
+
+ f = tflow.tflow()
+ f.request.method = "CONNECT"
+ assert not f.response
+ up.http_connect(f)
+ assert f.response.status_code == 407
diff --git a/test/mitmproxy/addons/test_upstream_auth.py b/test/mitmproxy/addons/test_upstream_auth.py
new file mode 100644
index 00000000..985b13a7
--- /dev/null
+++ b/test/mitmproxy/addons/test_upstream_auth.py
@@ -0,0 +1,65 @@
+import base64
+
+from mitmproxy import exceptions
+from mitmproxy.test import taddons
+from mitmproxy.test import tflow
+from mitmproxy.test import tutils
+from mitmproxy.addons import upstream_auth
+
+
+def test_configure():
+ up = upstream_auth.UpstreamAuth()
+ with taddons.context() as tctx:
+ tctx.configure(up, upstream_auth="test:test")
+ assert up.auth == b"Basic" + b" " + base64.b64encode(b"test:test")
+
+ tctx.configure(up, upstream_auth="test:")
+ assert up.auth == b"Basic" + b" " + base64.b64encode(b"test:")
+
+ tctx.configure(up, upstream_auth=None)
+ assert not up.auth
+
+ tutils.raises(
+ exceptions.OptionsError,
+ tctx.configure,
+ up,
+ upstream_auth=""
+ )
+ tutils.raises(
+ exceptions.OptionsError,
+ tctx.configure,
+ up,
+ upstream_auth=":"
+ )
+ tutils.raises(
+ exceptions.OptionsError,
+ tctx.configure,
+ up,
+ upstream_auth=":test"
+ )
+
+
+def test_simple():
+ up = upstream_auth.UpstreamAuth()
+ with taddons.context() as tctx:
+ tctx.configure(up, upstream_auth="foo:bar")
+
+ f = tflow.tflow()
+ f.mode = "upstream"
+ up.requestheaders(f)
+ assert "proxy-authorization" in f.request.headers
+
+ f = tflow.tflow()
+ up.requestheaders(f)
+ assert "proxy-authorization" not in f.request.headers
+
+ tctx.configure(up, mode="reverse")
+ f = tflow.tflow()
+ f.mode = "transparent"
+ up.requestheaders(f)
+ assert "proxy-authorization" in f.request.headers
+
+ f = tflow.tflow()
+ f.mode = "upstream"
+ up.http_connect(f)
+ assert "proxy-authorization" in f.request.headers
diff --git a/test/mitmproxy/net/http/test_authentication.py b/test/mitmproxy/net/http/test_authentication.py
deleted file mode 100644
index 01eae52d..00000000
--- a/test/mitmproxy/net/http/test_authentication.py
+++ /dev/null
@@ -1,122 +0,0 @@
-import binascii
-
-from mitmproxy.test import tutils
-from mitmproxy.net.http import authentication, Headers
-
-
-def test_parse_http_basic_auth():
- vals = ("basic", "foo", "bar")
- assert authentication.parse_http_basic_auth(
- authentication.assemble_http_basic_auth(*vals)
- ) == vals
- assert not authentication.parse_http_basic_auth("")
- assert not authentication.parse_http_basic_auth("foo bar")
- v = "basic " + binascii.b2a_base64(b"foo").decode("ascii")
- assert not authentication.parse_http_basic_auth(v)
-
-
-class TestPassManNonAnon:
-
- def test_simple(self):
- p = authentication.PassManNonAnon()
- assert not p.test("", "")
- assert p.test("user", "")
-
-
-class TestPassManHtpasswd:
-
- def test_file_errors(self):
- tutils.raises(
- "malformed htpasswd file",
- authentication.PassManHtpasswd,
- tutils.test_data.path("mitmproxy/net/data/server.crt"))
-
- def test_simple(self):
- pm = authentication.PassManHtpasswd(tutils.test_data.path("mitmproxy/net/data/htpasswd"))
-
- vals = ("basic", "test", "test")
- authentication.assemble_http_basic_auth(*vals)
- assert pm.test("test", "test")
- assert not pm.test("test", "foo")
- assert not pm.test("foo", "test")
- assert not pm.test("test", "")
- assert not pm.test("", "")
-
-
-class TestPassManSingleUser:
-
- def test_simple(self):
- pm = authentication.PassManSingleUser("test", "test")
- assert pm.test("test", "test")
- assert not pm.test("test", "foo")
- assert not pm.test("foo", "test")
-
-
-class TestNullProxyAuth:
-
- def test_simple(self):
- na = authentication.NullProxyAuth(authentication.PassManNonAnon())
- assert not na.auth_challenge_headers()
- assert na.authenticate("foo")
- na.clean({})
-
-
-class TestBasicProxyAuth:
-
- def test_simple(self):
- ba = authentication.BasicProxyAuth(authentication.PassManNonAnon(), "test")
- headers = Headers()
- assert ba.auth_challenge_headers()
- assert not ba.authenticate(headers)
-
- def test_authenticate_clean(self):
- ba = authentication.BasicProxyAuth(authentication.PassManNonAnon(), "test")
-
- headers = Headers()
- vals = ("basic", "foo", "bar")
- headers[ba.AUTH_HEADER] = authentication.assemble_http_basic_auth(*vals)
- assert ba.authenticate(headers)
-
- ba.clean(headers)
- assert ba.AUTH_HEADER not in headers
-
- headers[ba.AUTH_HEADER] = ""
- assert not ba.authenticate(headers)
-
- headers[ba.AUTH_HEADER] = "foo"
- assert not ba.authenticate(headers)
-
- vals = ("foo", "foo", "bar")
- headers[ba.AUTH_HEADER] = authentication.assemble_http_basic_auth(*vals)
- assert not ba.authenticate(headers)
-
- ba = authentication.BasicProxyAuth(authentication.PassMan(), "test")
- vals = ("basic", "foo", "bar")
- headers[ba.AUTH_HEADER] = authentication.assemble_http_basic_auth(*vals)
- assert not ba.authenticate(headers)
-
-
-class Bunch:
- pass
-
-
-class TestAuthAction:
-
- def test_nonanonymous(self):
- m = Bunch()
- aa = authentication.NonanonymousAuthAction(None, "authenticator")
- aa(None, m, None, None)
- assert m.authenticator
-
- def test_singleuser(self):
- m = Bunch()
- aa = authentication.SingleuserAuthAction(None, "authenticator")
- aa(None, m, "foo:bar", None)
- assert m.authenticator
- tutils.raises("invalid", aa, None, m, "foo", None)
-
- def test_httppasswd(self):
- m = Bunch()
- aa = authentication.HtpasswdAuthAction(None, "authenticator")
- aa(None, m, tutils.test_data.path("mitmproxy/net/data/htpasswd"), None)
- assert m.authenticator
diff --git a/test/mitmproxy/protocol/test_http1.py b/test/mitmproxy/protocol/test_http1.py
index 5026bef1..cd937ada 100644
--- a/test/mitmproxy/protocol/test_http1.py
+++ b/test/mitmproxy/protocol/test_http1.py
@@ -20,7 +20,7 @@ class TestInvalidRequests(tservers.HTTPProxyTest):
with p.connect():
r = p.request("connect:'%s:%s'" % ("127.0.0.1", self.server2.port))
assert r.status_code == 400
- assert b"Invalid HTTP request form" in r.content
+ assert b"Unexpected CONNECT" in r.content
def test_relative_request(self):
p = self.pathoc_raw()
diff --git a/test/mitmproxy/test_eventsequence.py b/test/mitmproxy/test_eventsequence.py
new file mode 100644
index 00000000..262df4b0
--- /dev/null
+++ b/test/mitmproxy/test_eventsequence.py
@@ -0,0 +1,81 @@
+from mitmproxy import events
+import contextlib
+from . import tservers
+
+
+class Eventer:
+ def __init__(self, **handlers):
+ self.failure = None
+ self.called = []
+ self.handlers = handlers
+ for i in events.Events - {"tick"}:
+ def mkprox():
+ evt = i
+
+ def prox(*args, **kwargs):
+ self.called.append(evt)
+ if evt in self.handlers:
+ try:
+ handlers[evt](*args, **kwargs)
+ except AssertionError as e:
+ self.failure = e
+ return prox
+ setattr(self, i, mkprox())
+
+ def fail(self):
+ pass
+
+
+class SequenceTester:
+ @contextlib.contextmanager
+ def addon(self, addon):
+ self.master.addons.add(addon)
+ yield
+ self.master.addons.remove(addon)
+ if addon.failure:
+ raise addon.failure
+
+
+class TestBasic(tservers.HTTPProxyTest, SequenceTester):
+ ssl = True
+
+ def test_requestheaders(self):
+
+ def hdrs(f):
+ assert f.request.headers
+ assert not f.request.content
+
+ def req(f):
+ assert f.request.headers
+ assert f.request.content
+
+ with self.addon(Eventer(requestheaders=hdrs, request=req)):
+ p = self.pathoc()
+ with p.connect():
+ assert p.request("get:'/p/200':b@10").status_code == 200
+
+ def test_100_continue_fail(self):
+ e = Eventer()
+ with self.addon(e):
+ p = self.pathoc()
+ with p.connect():
+ p.request(
+ """
+ get:'/p/200'
+ h'expect'='100-continue'
+ h'content-length'='1000'
+ da
+ """
+ )
+ assert "requestheaders" in e.called
+ assert "responseheaders" not in e.called
+
+ def test_connect(self):
+ e = Eventer()
+ with self.addon(e):
+ p = self.pathoc()
+ with p.connect():
+ p.request("get:'/p/200:b@1'")
+ assert "http_connect" in e.called
+ assert e.called.count("requestheaders") == 1
+ assert e.called.count("request") == 1
diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py
index 7cadb6c2..aa3b8979 100644
--- a/test/mitmproxy/test_proxy.py
+++ b/test/mitmproxy/test_proxy.py
@@ -107,23 +107,12 @@ class TestProcessProxyOptions:
self.assert_noerr("-T")
self.assert_noerr("-U", "http://localhost")
- self.assert_err("expected one argument", "-U")
self.assert_err("Invalid server specification", "-U", "upstream")
self.assert_noerr("--upstream-auth", "test:test")
self.assert_err("expected one argument", "--upstream-auth")
- self.assert_err(
- "Invalid upstream auth specification", "--upstream-auth", "test"
- )
self.assert_err("mutually exclusive", "-R", "http://localhost", "-T")
- def test_socks_auth(self):
- self.assert_err(
- "Proxy Authentication not supported in SOCKS mode.",
- "--socks",
- "--nonanonymous"
- )
-
def test_client_certs(self):
with tutils.tmpdir() as cadir:
self.assert_noerr("--client-certs", cadir)
@@ -141,26 +130,6 @@ class TestProcessProxyOptions:
tutils.test_data.path("mitmproxy/data/testkey.pem"))
self.assert_err("does not exist", "--cert", "nonexistent")
- def test_auth(self):
- p = self.assert_noerr("--nonanonymous")
- assert p.authenticator
-
- p = self.assert_noerr(
- "--htpasswd",
- tutils.test_data.path("mitmproxy/data/htpasswd"))
- assert p.authenticator
- self.assert_err(
- "malformed htpasswd file",
- "--htpasswd",
- tutils.test_data.path("mitmproxy/data/htpasswd.invalid"))
-
- p = self.assert_noerr("--singleuser", "test:test")
- assert p.authenticator
- self.assert_err(
- "invalid single-user specification",
- "--singleuser",
- "test")
-
def test_insecure(self):
p = self.assert_noerr("--insecure")
assert p.openssl_verification_mode_server == SSL.VERIFY_NONE
diff --git a/test/mitmproxy/test_proxy_config.py b/test/mitmproxy/test_proxy_config.py
index e012cb5e..e2c39846 100644
--- a/test/mitmproxy/test_proxy_config.py
+++ b/test/mitmproxy/test_proxy_config.py
@@ -1,5 +1,4 @@
from mitmproxy.test import tutils
-import base64
from mitmproxy.proxy import config
@@ -26,23 +25,3 @@ def test_parse_server_spec():
config.parse_server_spec,
"http://"
)
-
-
-def test_parse_upstream_auth():
- tutils.raises(
- "Invalid upstream auth specification",
- config.parse_upstream_auth,
- ""
- )
- tutils.raises(
- "Invalid upstream auth specification",
- config.parse_upstream_auth,
- ":"
- )
- tutils.raises(
- "Invalid upstream auth specification",
- config.parse_upstream_auth,
- ":test"
- )
- assert config.parse_upstream_auth("test:test") == b"Basic" + b" " + base64.b64encode(b"test:test")
- assert config.parse_upstream_auth("test:") == b"Basic" + b" " + base64.b64encode(b"test:")
diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py
index 9fa6ed06..9429ab0f 100644
--- a/test/mitmproxy/test_server.py
+++ b/test/mitmproxy/test_server.py
@@ -6,6 +6,7 @@ from mitmproxy.test import tutils
from mitmproxy import controller
from mitmproxy import options
from mitmproxy.addons import script
+from mitmproxy.addons import proxyauth
from mitmproxy import http
from mitmproxy.proxy.config import HostMatcher, parse_server_spec
import mitmproxy.net.http
@@ -13,7 +14,6 @@ from mitmproxy.net import tcp
from mitmproxy.net import socks
from mitmproxy import certs
from mitmproxy import exceptions
-from mitmproxy.net.http import authentication
from mitmproxy.net.http import http1
from mitmproxy.net.tcp import Address
from pathod import pathoc
@@ -50,10 +50,7 @@ class CommonMixin:
def test_replay(self):
assert self.pathod("304").status_code == 304
- if isinstance(self, tservers.HTTPUpstreamProxyTest) and self.ssl:
- assert len(self.master.state.flows) == 2
- else:
- assert len(self.master.state.flows) == 1
+ assert len(self.master.state.flows) == 1
l = self.master.state.flows[-1]
assert l.response.status_code == 304
l.request.path = "/p/305"
@@ -288,6 +285,7 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin):
class TestHTTPAuth(tservers.HTTPProxyTest):
def test_auth(self):
+ self.master.addons.add(proxyauth.ProxyAuth())
self.master.options.auth_singleuser = "test:test"
assert self.pathod("202").status_code == 407
p = self.pathoc()
@@ -298,14 +296,15 @@ class TestHTTPAuth(tservers.HTTPProxyTest):
h'%s'='%s'
""" % (
self.server.port,
- mitmproxy.net.http.authentication.BasicProxyAuth.AUTH_HEADER,
- authentication.assemble_http_basic_auth("basic", "test", "test")
+ "Proxy-Authorization",
+ proxyauth.mkauth("test", "test")
))
assert ret.status_code == 202
class TestHTTPReverseAuth(tservers.ReverseProxyTest):
def test_auth(self):
+ self.master.addons.add(proxyauth.ProxyAuth())
self.master.options.auth_singleuser = "test:test"
assert self.pathod("202").status_code == 401
p = self.pathoc()
@@ -315,8 +314,8 @@ class TestHTTPReverseAuth(tservers.ReverseProxyTest):
'/p/202'
h'%s'='%s'
""" % (
- mitmproxy.net.http.authentication.BasicWebsiteAuth.AUTH_HEADER,
- authentication.assemble_http_basic_auth("basic", "test", "test")
+ "Authorization",
+ proxyauth.mkauth("test", "test")
))
assert ret.status_code == 202
@@ -672,6 +671,13 @@ class TestProxySSL(tservers.HTTPProxyTest):
first_flow = self.master.state.flows[0]
assert first_flow.server_conn.timestamp_ssl_setup
+ def test_via(self):
+ # tests that the ssl timestamp is present when ssl is used
+ f = self.pathod("200:b@10")
+ assert f.status_code == 200
+ first_flow = self.master.state.flows[0]
+ assert not first_flow.server_conn.via
+
class MasterRedirectRequest(tservers.TestMaster):
redirect_port = None # Set by TestRedirectRequest
@@ -952,12 +958,15 @@ class TestUpstreamProxySSL(
assert req.status_code == 418
# CONNECT from pathoc to chain[0],
- assert self.proxy.tmaster.state.flow_count() == 2
+ assert self.proxy.tmaster.state.flow_count() == 1
+ assert self.proxy.tmaster.state.flows[0].server_conn.via
# request from pathoc to chain[0]
# CONNECT from proxy to chain[1],
- assert self.chain[0].tmaster.state.flow_count() == 2
+ assert self.chain[0].tmaster.state.flow_count() == 1
+ assert self.chain[0].tmaster.state.flows[0].server_conn.via
# request from proxy to chain[1]
# request from chain[0] (regular proxy doesn't store CONNECTs)
+ assert not self.chain[1].tmaster.state.flows[0].server_conn.via
assert self.chain[1].tmaster.state.flow_count() == 1
@@ -978,21 +987,12 @@ class TestProxyChainingSSLReconnect(tservers.HTTPUpstreamProxyTest):
def test_reconnect(self):
"""
Tests proper functionality of ConnectionHandler.server_reconnect mock.
- If we have a disconnect on a secure connection that's transparently proxified to
- an upstream http proxy, we need to send the CONNECT request again.
+ If we have a disconnect on a secure connection that's transparently
+ proxified to an upstream http proxy, we need to send the CONNECT
+ request again.
"""
- self.chain[1].tmaster.addons.add(
- RequestKiller([2])
- )
- self.chain[0].tmaster.addons.add(
- RequestKiller(
- [
- 1, # CONNECT
- 3, # reCONNECT
- 4 # request
- ]
- )
- )
+ self.chain[0].tmaster.addons.add(RequestKiller([1, 2]))
+ self.chain[1].tmaster.addons.add(RequestKiller([1]))
p = self.pathoc()
with p.connect():
@@ -1000,44 +1000,27 @@ class TestProxyChainingSSLReconnect(tservers.HTTPUpstreamProxyTest):
assert req.content == b"content"
assert req.status_code == 418
- assert self.proxy.tmaster.state.flow_count() == 2 # CONNECT and request
- # CONNECT, failing request,
- assert self.chain[0].tmaster.state.flow_count() == 4
- # reCONNECT, request
- # failing request, request
- assert self.chain[1].tmaster.state.flow_count() == 2
- # (doesn't store (repeated) CONNECTs from chain[0]
- # as it is a regular proxy)
-
- assert not self.chain[1].tmaster.state.flows[0].response # killed
- assert self.chain[1].tmaster.state.flows[1].response
-
- assert self.proxy.tmaster.state.flows[0].request.first_line_format == "authority"
- assert self.proxy.tmaster.state.flows[1].request.first_line_format == "relative"
-
- assert self.chain[0].tmaster.state.flows[
- 0].request.first_line_format == "authority"
- assert self.chain[0].tmaster.state.flows[
- 1].request.first_line_format == "relative"
- assert self.chain[0].tmaster.state.flows[
- 2].request.first_line_format == "authority"
- assert self.chain[0].tmaster.state.flows[
- 3].request.first_line_format == "relative"
-
- assert self.chain[1].tmaster.state.flows[
- 0].request.first_line_format == "relative"
- assert self.chain[1].tmaster.state.flows[
- 1].request.first_line_format == "relative"
+ # First request goes through all three proxies exactly once
+ assert self.proxy.tmaster.state.flow_count() == 1
+ assert self.chain[0].tmaster.state.flow_count() == 1
+ assert self.chain[1].tmaster.state.flow_count() == 1
req = p.request("get:'/p/418:b\"content2\"'")
-
assert req.status_code == 502
- assert self.proxy.tmaster.state.flow_count() == 3 # + new request
- # + new request, repeated CONNECT from chain[1]
- assert self.chain[0].tmaster.state.flow_count() == 6
- # (both terminated)
- # nothing happened here
- assert self.chain[1].tmaster.state.flow_count() == 2
+
+ assert self.proxy.tmaster.state.flow_count() == 2
+ assert self.chain[0].tmaster.state.flow_count() == 2
+ # Upstream sees two requests due to reconnection attempt
+ assert self.chain[1].tmaster.state.flow_count() == 3
+ assert not self.chain[1].tmaster.state.flows[-1].response
+ assert not self.chain[1].tmaster.state.flows[-2].response
+
+ # Reconnection failed, so we're now disconnected
+ tutils.raises(
+ exceptions.HttpException,
+ p.request,
+ "get:'/p/418:b\"content3\"'"
+ )
class AddUpstreamCertsToClientChainMixin: