aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/data/confdir/mitmproxy-ca-cert.cer17
-rw-r--r--test/data/confdir/mitmproxy-ca-cert.p12bin0 -> 1689 bytes
-rw-r--r--test/data/confdir/mitmproxy-ca-cert.pem17
-rw-r--r--test/data/confdir/mitmproxy-ca.pem32
-rw-r--r--test/data/serverkey.pem32
-rw-r--r--test/mock_urwid.py8
-rw-r--r--test/test_app.py19
-rw-r--r--test/test_console.py24
-rw-r--r--test/test_dump.py20
-rw-r--r--test/test_filt.py44
-rw-r--r--test/test_flow.py320
-rw-r--r--test/test_fuzzing.py4
-rw-r--r--test/test_protocol_http.py201
-rw-r--r--test/test_proxy.py15
-rw-r--r--test/test_script.py15
-rw-r--r--test/test_server.py61
-rw-r--r--test/tservers.py69
-rw-r--r--test/tutils.py89
18 files changed, 634 insertions, 353 deletions
diff --git a/test/data/confdir/mitmproxy-ca-cert.cer b/test/data/confdir/mitmproxy-ca-cert.cer
new file mode 100644
index 00000000..cc7f8f19
--- /dev/null
+++ b/test/data/confdir/mitmproxy-ca-cert.cer
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICnzCCAgigAwIBAgIGDKiSwuJOMA0GCSqGSIb3DQEBBQUAMCgxEjAQBgNVBAMT
+CW1pdG1wcm94eTESMBAGA1UEChMJbWl0bXByb3h5MB4XDTE0MDIwNzIzMjcwOFoX
+DTE2MDEyODIzMjcwOFowKDESMBAGA1UEAxMJbWl0bXByb3h5MRIwEAYDVQQKEwlt
+aXRtcHJveHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKsZ+XnBvjCjAJ00
+9M+v41AT91h7v7cF1UG0BpS3y4MOysN88btHM/IWRCllnmY+zx5LTMAEtbnqyOIk
+nkgJ0sU3CFWHRIfwkinssEtMM2mOAFXm0wqffECxwe1p5z84M7nOolzuuw4FtkaK
+G9/UqANdRVs6uOwz+CuyOSY7illTAgMBAAGjgdMwgdAwDwYDVR0TAQH/BAUwAwEB
+/zAUBglghkgBhvhCAQEBAf8EBAMCAgQwewYDVR0lAQH/BHEwbwYIKwYBBQUHAwEG
+CCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQB
+gjcCARYGCisGAQQBgjcKAwEGCisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG
++EIEATALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFFKVDIF+w2Ns4KsJx6tJZpILqWwG
+MA0GCSqGSIb3DQEBBQUAA4GBABWYxoYFLgZh/ujz/0jrNsx0pvSNVTU1T669374z
+PhO+ScvzuxVbgI2NQv86aqih35pzakK/DyKaTck85QduDiSiLNw2Yb5UfJvO4C0d
+dPzQMIKNTInFFiLBjbvxx9cuDwAPyYOF247Xj9M6C2x6e/gq1L+GR75wT5288x9h
+rFTJ
+-----END CERTIFICATE-----
diff --git a/test/data/confdir/mitmproxy-ca-cert.p12 b/test/data/confdir/mitmproxy-ca-cert.p12
new file mode 100644
index 00000000..d4cec0d4
--- /dev/null
+++ b/test/data/confdir/mitmproxy-ca-cert.p12
Binary files differ
diff --git a/test/data/confdir/mitmproxy-ca-cert.pem b/test/data/confdir/mitmproxy-ca-cert.pem
new file mode 100644
index 00000000..cc7f8f19
--- /dev/null
+++ b/test/data/confdir/mitmproxy-ca-cert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICnzCCAgigAwIBAgIGDKiSwuJOMA0GCSqGSIb3DQEBBQUAMCgxEjAQBgNVBAMT
+CW1pdG1wcm94eTESMBAGA1UEChMJbWl0bXByb3h5MB4XDTE0MDIwNzIzMjcwOFoX
+DTE2MDEyODIzMjcwOFowKDESMBAGA1UEAxMJbWl0bXByb3h5MRIwEAYDVQQKEwlt
+aXRtcHJveHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKsZ+XnBvjCjAJ00
+9M+v41AT91h7v7cF1UG0BpS3y4MOysN88btHM/IWRCllnmY+zx5LTMAEtbnqyOIk
+nkgJ0sU3CFWHRIfwkinssEtMM2mOAFXm0wqffECxwe1p5z84M7nOolzuuw4FtkaK
+G9/UqANdRVs6uOwz+CuyOSY7illTAgMBAAGjgdMwgdAwDwYDVR0TAQH/BAUwAwEB
+/zAUBglghkgBhvhCAQEBAf8EBAMCAgQwewYDVR0lAQH/BHEwbwYIKwYBBQUHAwEG
+CCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQB
+gjcCARYGCisGAQQBgjcKAwEGCisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG
++EIEATALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFFKVDIF+w2Ns4KsJx6tJZpILqWwG
+MA0GCSqGSIb3DQEBBQUAA4GBABWYxoYFLgZh/ujz/0jrNsx0pvSNVTU1T669374z
+PhO+ScvzuxVbgI2NQv86aqih35pzakK/DyKaTck85QduDiSiLNw2Yb5UfJvO4C0d
+dPzQMIKNTInFFiLBjbvxx9cuDwAPyYOF247Xj9M6C2x6e/gq1L+GR75wT5288x9h
+rFTJ
+-----END CERTIFICATE-----
diff --git a/test/data/confdir/mitmproxy-ca.pem b/test/data/confdir/mitmproxy-ca.pem
new file mode 100644
index 00000000..2a2343a6
--- /dev/null
+++ b/test/data/confdir/mitmproxy-ca.pem
@@ -0,0 +1,32 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCrGfl5wb4wowCdNPTPr+NQE/dYe7+3BdVBtAaUt8uDDsrDfPG7
+RzPyFkQpZZ5mPs8eS0zABLW56sjiJJ5ICdLFNwhVh0SH8JIp7LBLTDNpjgBV5tMK
+n3xAscHtaec/ODO5zqJc7rsOBbZGihvf1KgDXUVbOrjsM/grsjkmO4pZUwIDAQAB
+AoGAUtjn4Fm8cqZqpLRAmdOruFmCmbiJ0uAjK4Y07Yu1IgdmjJOSJMFMWLsJVBYd
+RZrCBQQm7I8bQyN5E27xqSYAhKz7ymjgHGWlTXENtvfx/XlIIn9DYENKpN1N8Y/5
+BCt0O/F9h2/Z+zGNdV3R2tX3WuSjYlqzzD2RDBIDPe6Fr8kCQQDSLcyqGRXamt0X
+MjPtltJHIjIXHp+++qQDT3n8eaP0maWtAm+75PzWGqOvfg4F2VoWMTGdDEbHbCmH
+Qa6EW0B/AkEA0Gc90xLD+qLqVEbzdveca+yO1lAastqoYzRuM1StZ1Y4pW7F5D23
+MNhV0zV6z7ejZYnnsGvuQLTx51X8Ff59LQJAF1mxQECTNfs4jugr7rxv1ilNaVYk
+p0IPULLWuZ8GARnE10jLAxP4pwzEnK2jfzDbmlWSzoDbqDIzFuzMJ7Y/nwJBAL+s
+dNxRAhbfCA6DQyFEE4XfiG/sNOIS4ZR8gG6Njv7f+jGNdEy7xmUSU71yDoZFK+8T
+qxhD7FlvEp3mI3hHG/ECQQC0x7z/lr5KRsFGqVZOErkc3nOZO+4rjApHSlbuhDLU
+mnUwIi06KyjbN+0XL+6bJl+L5nfL3TIlnyHMJAta2uta
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICnzCCAgigAwIBAgIGDKiSwuJOMA0GCSqGSIb3DQEBBQUAMCgxEjAQBgNVBAMT
+CW1pdG1wcm94eTESMBAGA1UEChMJbWl0bXByb3h5MB4XDTE0MDIwNzIzMjcwOFoX
+DTE2MDEyODIzMjcwOFowKDESMBAGA1UEAxMJbWl0bXByb3h5MRIwEAYDVQQKEwlt
+aXRtcHJveHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKsZ+XnBvjCjAJ00
+9M+v41AT91h7v7cF1UG0BpS3y4MOysN88btHM/IWRCllnmY+zx5LTMAEtbnqyOIk
+nkgJ0sU3CFWHRIfwkinssEtMM2mOAFXm0wqffECxwe1p5z84M7nOolzuuw4FtkaK
+G9/UqANdRVs6uOwz+CuyOSY7illTAgMBAAGjgdMwgdAwDwYDVR0TAQH/BAUwAwEB
+/zAUBglghkgBhvhCAQEBAf8EBAMCAgQwewYDVR0lAQH/BHEwbwYIKwYBBQUHAwEG
+CCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQB
+gjcCARYGCisGAQQBgjcKAwEGCisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG
++EIEATALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFFKVDIF+w2Ns4KsJx6tJZpILqWwG
+MA0GCSqGSIb3DQEBBQUAA4GBABWYxoYFLgZh/ujz/0jrNsx0pvSNVTU1T669374z
+PhO+ScvzuxVbgI2NQv86aqih35pzakK/DyKaTck85QduDiSiLNw2Yb5UfJvO4C0d
+dPzQMIKNTInFFiLBjbvxx9cuDwAPyYOF247Xj9M6C2x6e/gq1L+GR75wT5288x9h
+rFTJ
+-----END CERTIFICATE-----
diff --git a/test/data/serverkey.pem b/test/data/serverkey.pem
deleted file mode 100644
index 289bfa71..00000000
--- a/test/data/serverkey.pem
+++ /dev/null
@@ -1,32 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXQIBAAKBgQC+N+9bv1YC0GKbGdv2wMuuWTGSNwE/Hq5IIxYN1eITsvbD1GgB
-69x++XJd6KTIthnta0KCpCAtbaYbCkhUfxCVv2bP+iQt2AjwMOZlgRZ+RGJ25dBu
-AjAxQmqDJcAdS6MoRHWziomnUNfNogVrfqjpvJor+1iRnrj2q00ab9WYCwIDAQAB
-AoGBAIM7V9l2UcKzPbQ/zO+Z52urgXWcmTGQ2zBNdIOrEcQBbhmAyxi4PnEja3G6
-dSU77PtNSp+S19g/k5+IIoqY9zkGigdaPhRVRKJgBTAzFzMz+WHpQIffDojFKCnL
-gyDnzMRJY8+cnsCqbHRY4hqFiCr8Rq9sCdlynAytdtrnxzqhAkEA9bha6MO+L0JA
-6IEEbVY1vtaUO9Xg5DUDjRxQcfniSJACb/2IvF0tvxAnG7I/S8AavCXqtlDPtYkI
-WOxY5Sd62QJBAMYtKUxGka4XxwCyBK8EUNaN8m9C++mpjoHD1kFri9B1bXm91nCO
-iGWqtqdarwyEc/pAHw5UGzVyBXticPIcs4MCQQCcPvsHsZhYoq91aLyw7bXFQNsH
-ZUvYsOEuNIfuwa+i5ne2UKhG5pU1PgcwNFrNRz140D98aMx7KcS2DqvEIyOZAkBF
-6Yi4L+0Uza6WwDaGx679AfaU6byVIgv0G3JqgdZBJCwK1r3f12im9SKax5MZh2Ci
-2Bwcoe83W5IzhPbzcsyhAkBo8O2U2vig5PQWQ0BUKJrCGHLq//D/ttdLVtmc6eWc
-zqssCF3Unkk3bOq35swSKeAx8WotPPVsALWr87N2hCB+
------END RSA PRIVATE KEY-----
------BEGIN CERTIFICATE-----
-MIICsDCCAhmgAwIBAgIJANwogM9sqMHLMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQwHhcNMTAwMTMxMDEzOTEzWhcNMTEwMTMxMDEzOTEzWjBF
-MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
-ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
-gQC+N+9bv1YC0GKbGdv2wMuuWTGSNwE/Hq5IIxYN1eITsvbD1GgB69x++XJd6KTI
-thnta0KCpCAtbaYbCkhUfxCVv2bP+iQt2AjwMOZlgRZ+RGJ25dBuAjAxQmqDJcAd
-S6MoRHWziomnUNfNogVrfqjpvJor+1iRnrj2q00ab9WYCwIDAQABo4GnMIGkMB0G
-A1UdDgQWBBTTnBZyw7ZZsb8+/6gvZFIHhVgtDzB1BgNVHSMEbjBsgBTTnBZyw7ZZ
-sb8+/6gvZFIHhVgtD6FJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt
-U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJANwogM9s
-qMHLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEApz428aOar0EBuAib
-I+liefRlK4I3MQQxq3tOeB1dgAIo0ivKtdVJGi1kPg8EO0KMvFfn6IRtssUmFgCp
-JBD+HoDzFxwI1bLMVni+g7OzaNSwL3nQ94lZUdpWMYDxqY4bLUv3goX1TlN9lmpG
-8FiBLYUC0RNTCCRDFGfDr/wUT/M=
------END CERTIFICATE-----
diff --git a/test/mock_urwid.py b/test/mock_urwid.py
new file mode 100644
index 00000000..f132e0bd
--- /dev/null
+++ b/test/mock_urwid.py
@@ -0,0 +1,8 @@
+import os, sys, mock
+if os.name == "nt":
+ m = mock.Mock()
+ m.__version__ = "1.1.1"
+ m.Widget = mock.Mock
+ m.WidgetWrap = mock.Mock
+ sys.modules['urwid'] = m
+ sys.modules['urwid.util'] = mock.Mock() \ No newline at end of file
diff --git a/test/test_app.py b/test/test_app.py
new file mode 100644
index 00000000..f0eab7cc
--- /dev/null
+++ b/test/test_app.py
@@ -0,0 +1,19 @@
+import mock, socket, os, time
+from libmproxy import dump
+from netlib import certutils, tcp
+from libpathod.pathoc import Pathoc
+import tutils, tservers
+
+class TestApp(tservers.HTTPProxTest):
+ def test_basic(self):
+ assert self.app("/").status_code == 200
+
+ def test_cert(self):
+ path = tutils.test_data.path("data/confdir/") + "mitmproxy-ca-cert."
+ with tutils.tmpdir() as d:
+ for ext in ["pem", "p12"]:
+ resp = self.app("/cert/%s" % ext)
+ assert resp.status_code == 200
+ with open(path + ext, "rb") as f:
+ assert resp.content == f.read()
+
diff --git a/test/test_console.py b/test/test_console.py
index 4fd9bb9f..0c5b4591 100644
--- a/test/test_console.py
+++ b/test/test_console.py
@@ -1,10 +1,9 @@
-import os
-from nose.plugins.skip import SkipTest
-if os.name == "nt":
- raise SkipTest("Skipped on Windows.")
-
+import os, sys, mock, gc
+from os.path import normpath
+import mock_urwid
from libmproxy import console
from libmproxy.console import common
+
import tutils
class TestConsoleState:
@@ -16,7 +15,7 @@ class TestConsoleState:
"""
c = console.ConsoleState()
f = self._add_request(c)
- assert f.request in c._flow_map
+ assert f in c._flow_list
assert c.get_focus() == (f, 0)
def test_focus(self):
@@ -89,6 +88,7 @@ class TestConsoleState:
assert len(c.flowsettings) == 1
c.delete_flow(f)
del f
+ gc.collect()
assert len(c.flowsettings) == 0
@@ -107,19 +107,17 @@ def test_format_keyvals():
class TestPathCompleter:
def test_lookup_construction(self):
c = console._PathCompleter()
- assert c.complete("/tm") == "/tmp/"
- c.reset()
cd = tutils.test_data.path("completion")
ca = os.path.join(cd, "a")
- assert c.complete(ca).endswith("/completion/aaa")
- assert c.complete(ca).endswith("/completion/aab")
+ assert c.complete(ca).endswith(normpath("/completion/aaa"))
+ assert c.complete(ca).endswith(normpath("/completion/aab"))
c.reset()
ca = os.path.join(cd, "aaa")
- assert c.complete(ca).endswith("/completion/aaa")
- assert c.complete(ca).endswith("/completion/aaa")
+ assert c.complete(ca).endswith(normpath("/completion/aaa"))
+ assert c.complete(ca).endswith(normpath("/completion/aaa"))
c.reset()
- assert c.complete(cd).endswith("/completion/aaa")
+ assert c.complete(cd).endswith(normpath("/completion/aaa"))
def test_completion(self):
c = console._PathCompleter(True)
diff --git a/test/test_dump.py b/test/test_dump.py
index a958a2ec..8b4b9aa5 100644
--- a/test/test_dump.py
+++ b/test/test_dump.py
@@ -6,11 +6,11 @@ import mock
def test_strfuncs():
t = tutils.tresp()
- t._set_replay()
+ t.is_replay = True
dump.str_response(t)
t = tutils.treq()
- t.client_conn = None
+ t.flow.client_conn = None
t.stickycookie = True
assert "stickycookie" in dump.str_request(t, False)
assert "stickycookie" in dump.str_request(t, True)
@@ -20,24 +20,20 @@ def test_strfuncs():
class TestDumpMaster:
def _cycle(self, m, content):
- req = tutils.treq()
- req.content = content
+ req = tutils.treq(content=content)
l = proxy.Log("connect")
l.reply = mock.MagicMock()
m.handle_log(l)
- cc = req.client_conn
- cc.connection_error = "error"
- resp = tutils.tresp(req)
- resp.content = content
+ cc = req.flow.client_conn
+ cc.reply = mock.MagicMock()
m.handle_clientconnect(cc)
- sc = proxy.ServerConnection(m.o, req.scheme, req.host, req.port, None)
+ sc = proxy.ServerConnection((req.get_host(), req.get_port()), None)
sc.reply = mock.MagicMock()
m.handle_serverconnection(sc)
m.handle_request(req)
+ resp = tutils.tresp(req, content=content)
f = m.handle_response(resp)
- cd = flow.ClientDisconnect(cc)
- cd.reply = mock.MagicMock()
- m.handle_clientdisconnect(cd)
+ m.handle_clientdisconnect(cc)
return f
def _dummy_cycle(self, n, filt, content, **options):
diff --git a/test/test_filt.py b/test/test_filt.py
index 4e059196..452a4505 100644
--- a/test/test_filt.py
+++ b/test/test_filt.py
@@ -1,6 +1,8 @@
import cStringIO
from libmproxy import filt, flow
-
+from libmproxy.protocol import http
+from libmproxy.protocol.primitives import Error
+import tutils
class TestParsing:
def _dump(self, x):
@@ -72,41 +74,37 @@ class TestParsing:
class TestMatching:
def req(self):
- conn = flow.ClientConnect(("one", 2222))
headers = flow.ODictCaseless()
headers["header"] = ["qvalue"]
- req = flow.Request(
- conn,
- (1, 1),
- "host",
- 80,
- "http",
- "GET",
- "/path",
- headers,
- "content_request"
+ req = http.HTTPRequest(
+ "absolute",
+ "GET",
+ "http",
+ "host",
+ 80,
+ "/path",
+ (1, 1),
+ headers,
+ "content_request",
+ None,
+ None
)
- return flow.Flow(req)
+ f = http.HTTPFlow(tutils.tclient_conn(), None)
+ f.request = req
+ return f
def resp(self):
f = self.req()
headers = flow.ODictCaseless()
headers["header_response"] = ["svalue"]
- f.response = flow.Response(
- f.request,
- (1, 1),
- 200,
- "message",
- headers,
- "content_response",
- None
- )
+ f.response = http.HTTPResponse((1, 1), 200, "OK", headers, "content_response", None, None)
+
return f
def err(self):
f = self.req()
- f.error = flow.Error(f.request, "msg")
+ f.error = Error("msg")
return f
def q(self, q, o):
diff --git a/test/test_flow.py b/test/test_flow.py
index f9198f0c..fbead1ca 100644
--- a/test/test_flow.py
+++ b/test/test_flow.py
@@ -1,7 +1,10 @@
import Queue, time, os.path
from cStringIO import StringIO
import email.utils
-from libmproxy import filt, flow, controller, utils, tnetstring, proxy
+from libmproxy import filt, protocol, controller, utils, tnetstring, proxy, flow
+from libmproxy.protocol.primitives import Error, Flow
+from libmproxy.protocol.http import decoded
+from netlib import tcp
import tutils
@@ -10,8 +13,7 @@ def test_app_registry():
ar.add("foo", "domain", 80)
r = tutils.treq()
- r.host = "domain"
- r.port = 80
+ r.set_url("http://domain:80/")
assert ar.get(r)
r.port = 81
@@ -30,7 +32,7 @@ class TestStickyCookieState:
def _response(self, cookie, host):
s = flow.StickyCookieState(filt.parse(".*"))
f = tutils.tflow_full()
- f.request.host = host
+ f.server_conn.address = tcp.Address((host, 80))
f.response.headers["Set-Cookie"] = [cookie]
s.handle_response(f)
return s, f
@@ -66,7 +68,7 @@ class TestStickyAuthState:
f = tutils.tflow_full()
f.request.headers["authorization"] = ["foo"]
s.handle_request(f)
- assert "host" in s.hosts
+ assert "address" in s.hosts
f = tutils.tflow_full()
s.handle_request(f)
@@ -171,8 +173,14 @@ class TestServerPlaybackState:
class TestFlow:
def test_copy(self):
f = tutils.tflow_full()
+ a0 = f._get_state()
f2 = f.copy()
+ a = f._get_state()
+ b = f2._get_state()
+ assert f._get_state() == f2._get_state()
+ assert not f == f2
assert not f is f2
+ assert f.request == f2.request
assert not f.request is f2.request
assert f.request.headers == f2.request.headers
assert not f.request.headers is f2.request.headers
@@ -189,9 +197,7 @@ class TestFlow:
assert not f.error is f2.error
def test_match(self):
- f = tutils.tflow()
- f.response = tutils.tresp()
- f.request = f.response.request
+ f = tutils.tflow_full()
assert not f.match("~b test")
assert f.match(None)
assert not f.match("~b test")
@@ -201,11 +207,9 @@ class TestFlow:
tutils.raises(ValueError, f.match, "~")
-
def test_backup(self):
f = tutils.tflow()
f.response = tutils.tresp()
- f.request = f.response.request
f.request.content = "foo"
assert not f.modified()
f.backup()
@@ -222,18 +226,19 @@ class TestFlow:
f.revert()
def test_getset_state(self):
- f = tutils.tflow()
- f.response = tutils.tresp(f.request)
+ f = tutils.tflow_full()
state = f._get_state()
- assert f._get_state() == flow.Flow._from_state(state)._get_state()
+ assert f._get_state() == protocol.http.HTTPFlow._from_state(state)._get_state()
f.response = None
- f.error = flow.Error(f.request, "error")
+ f.error = Error("error")
state = f._get_state()
- assert f._get_state() == flow.Flow._from_state(state)._get_state()
+ assert f._get_state() == protocol.http.HTTPFlow._from_state(state)._get_state()
- f2 = tutils.tflow()
- f2.error = flow.Error(f.request, "e2")
+ f2 = f.copy()
+ assert f._get_state() == f2._get_state()
+ assert not f == f2
+ f2.error = Error("e2")
assert not f == f2
f._load_state(f2._get_state())
assert f._get_state() == f2._get_state()
@@ -249,7 +254,6 @@ class TestFlow:
assert f.request.reply.acked
f.intercept()
f.response = tutils.tresp()
- f.request = f.response.request
f.request.reply()
assert not f.response.reply.acked
f.kill(fm)
@@ -279,17 +283,12 @@ class TestFlow:
f.accept_intercept()
assert f.request.reply.acked
f.response = tutils.tresp()
- f.request = f.response.request
f.intercept()
f.request.reply()
assert not f.response.reply.acked
f.accept_intercept()
assert f.response.reply.acked
- def test_serialization(self):
- f = flow.Flow(None)
- f.request = tutils.treq()
-
def test_replace_unicode(self):
f = tutils.tflow_full()
f.response.content = "\xc2foo"
@@ -310,10 +309,6 @@ class TestFlow:
assert f.response.headers["bar"] == ["bar"]
assert f.response.content == "abarb"
- f = tutils.tflow_err()
- f.replace("error", "bar")
- assert f.error.msg == "bar"
-
def test_replace_encoded(self):
f = tutils.tflow_full()
f.request.content = "afoob"
@@ -348,30 +343,27 @@ class TestState:
connect -> request -> response
"""
- bc = flow.ClientConnect(("address", 22))
+ bc = tutils.tclient_conn()
c = flow.State()
req = tutils.treq(bc)
f = c.add_request(req)
assert f
assert c.flow_count() == 1
- assert c._flow_map.get(req)
assert c.active_flow_count() == 1
newreq = tutils.treq()
assert c.add_request(newreq)
- assert c._flow_map.get(newreq)
assert c.active_flow_count() == 2
resp = tutils.tresp(req)
assert c.add_response(resp)
assert c.flow_count() == 2
- assert c._flow_map.get(resp.request)
assert c.active_flow_count() == 1
unseen_resp = tutils.tresp()
+ unseen_resp.flow = None
assert not c.add_response(unseen_resp)
- assert not c._flow_map.get(unseen_resp.request)
assert c.active_flow_count() == 1
resp = tutils.tresp(newreq)
@@ -382,19 +374,18 @@ class TestState:
c = flow.State()
req = tutils.treq()
f = c.add_request(req)
- e = flow.Error(f.request, "message")
- assert c.add_error(e)
+ f.error = Error("message")
+ assert c.add_error(f.error)
- e = flow.Error(tutils.tflow().request, "message")
+ e = Error("message")
assert not c.add_error(e)
c = flow.State()
req = tutils.treq()
f = c.add_request(req)
- e = flow.Error(f.request, "message")
+ e = tutils.terr()
c.set_limit("~e")
assert not c.view
- assert not c.view
assert c.add_error(e)
assert c.view
@@ -448,7 +439,7 @@ class TestState:
def _add_error(self, state):
req = tutils.treq()
f = state.add_request(req)
- f.error = flow.Error(f.request, "msg")
+ f.error = Error("msg")
def test_clear(self):
c = flow.State()
@@ -472,7 +463,7 @@ class TestState:
c.clear()
c.load_flows(flows)
- assert isinstance(c._flow_list[0], flow.Flow)
+ assert isinstance(c._flow_list[0], Flow)
def test_accept_all(self):
c = flow.State()
@@ -585,7 +576,7 @@ class TestFlowMaster:
fm = flow.FlowMaster(None, s)
assert not fm.load_script(tutils.test_data.path("scripts/reqerr.py"))
req = tutils.treq()
- fm.handle_clientconnect(req.client_conn)
+ fm.handle_clientconnect(req.flow.client_conn)
assert fm.handle_request(req)
def test_script(self):
@@ -593,9 +584,9 @@ class TestFlowMaster:
fm = flow.FlowMaster(None, s)
assert not fm.load_script(tutils.test_data.path("scripts/all.py"))
req = tutils.treq()
- fm.handle_clientconnect(req.client_conn)
+ fm.handle_clientconnect(req.flow.client_conn)
assert fm.scripts[0].ns["log"][-1] == "clientconnect"
- sc = proxy.ServerConnection(None, req.scheme, req.host, req.port, None)
+ sc = proxy.ServerConnection((req.get_host(), req.get_port()), None)
sc.reply = controller.DummyReply()
fm.handle_serverconnection(sc)
assert fm.scripts[0].ns["log"][-1] == "serverconnect"
@@ -607,9 +598,7 @@ class TestFlowMaster:
#load second script
assert not fm.load_script(tutils.test_data.path("scripts/all.py"))
assert len(fm.scripts) == 2
- dc = flow.ClientDisconnect(req.client_conn)
- dc.reply = controller.DummyReply()
- fm.handle_clientdisconnect(dc)
+ fm.handle_clientdisconnect(sc)
assert fm.scripts[0].ns["log"][-1] == "clientdisconnect"
assert fm.scripts[1].ns["log"][-1] == "clientdisconnect"
@@ -619,7 +608,7 @@ class TestFlowMaster:
assert len(fm.scripts) == 0
assert not fm.load_script(tutils.test_data.path("scripts/all.py"))
- err = flow.Error(f.request, "msg")
+ err = tutils.terr()
err.reply = controller.DummyReply()
fm.handle_error(err)
assert fm.scripts[0].ns["log"][-1] == "error"
@@ -633,7 +622,7 @@ class TestFlowMaster:
f2 = fm.duplicate_flow(f)
assert f2.response
assert s.flow_count() == 2
- assert s.index(f2)
+ assert s.index(f2) == 1
def test_all(self):
s = flow.State()
@@ -641,7 +630,7 @@ class TestFlowMaster:
fm.anticache = True
fm.anticomp = True
req = tutils.treq()
- fm.handle_clientconnect(req.client_conn)
+ fm.handle_clientconnect(req.flow.client_conn)
f = fm.handle_request(req)
assert s.flow_count() == 1
@@ -651,16 +640,14 @@ class TestFlowMaster:
assert s.flow_count() == 1
rx = tutils.tresp()
+ rx.flow = None
assert not fm.handle_response(rx)
- dc = flow.ClientDisconnect(req.client_conn)
- dc.reply = controller.DummyReply()
- req.client_conn.requestcount = 1
- fm.handle_clientdisconnect(dc)
+ fm.handle_clientdisconnect(req.flow.client_conn)
- err = flow.Error(f.request, "msg")
- err.reply = controller.DummyReply()
- fm.handle_error(err)
+ f.error = Error("msg")
+ f.error.reply = controller.DummyReply()
+ fm.handle_error(f.error)
fm.load_script(tutils.test_data.path("scripts/a.py"))
fm.shutdown()
@@ -679,9 +666,9 @@ class TestFlowMaster:
fm.tick(q)
assert fm.state.flow_count()
- err = flow.Error(f.request, "error")
- err.reply = controller.DummyReply()
- fm.handle_error(err)
+ f.error = Error("error")
+ f.error.reply = controller.DummyReply()
+ fm.handle_error(f.error)
def test_server_playback(self):
controller.should_exit = False
@@ -784,20 +771,16 @@ class TestFlowMaster:
assert r()[0].response
- tf = tutils.tflow_full()
+ tf = tutils.tflow()
fm.start_stream(file(p, "ab"), None)
fm.handle_request(tf.request)
fm.shutdown()
assert not r()[1].response
-
class TestRequest:
def test_simple(self):
- h = flow.ODictCaseless()
- h["test"] = ["test"]
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
+ r = tutils.treq()
u = r.get_url()
assert r.set_url(u)
assert not r.set_url("")
@@ -812,31 +795,34 @@ class TestRequest:
assert r._assemble()
assert r.size() == len(r._assemble())
- r.close = True
- assert "connection: close" in r._assemble()
-
- assert r._assemble(True)
-
r.content = flow.CONTENT_MISSING
- assert not r._assemble()
+ tutils.raises("Cannot assemble flow with CONTENT_MISSING", 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 = tutils.tflow().request
+
+ assert r.get_url() == "http://address:22/path"
+
+ r.flow.server_conn.ssl_established = True
+ assert r.get_url() == "https://address:22/path"
+
+ r.flow.server_conn.address = tcp.Address(("host", 42))
+ assert r.get_url() == "https://host:42/path"
+
+ r.host = "address"
+ r.port = 22
+ assert r.get_url() == "https://address:22/path"
+
+ assert r.get_url(hostheader=True) == "https://address:22/path"
r.headers["Host"] = ["foo.com"]
- assert r.get_url() == "https://host:22/"
- assert r.get_url(hostheader=True) == "https://foo.com:22/"
+ assert r.get_url() == "https://address:22/path"
+ assert r.get_url(hostheader=True) == "https://foo.com:22/path"
def test_path_components(self):
- h = flow.ODictCaseless()
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
+ r = tutils.treq()
+ r.path = "/"
assert r.get_path_components() == []
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/foo/bar", h, "content")
+ r.path = "/foo/bar"
assert r.get_path_components() == ["foo", "bar"]
q = flow.ODict()
q["test"] = ["123"]
@@ -852,10 +838,9 @@ class TestRequest:
assert "%2F" in r.path
def test_getset_form_urlencoded(self):
- h = flow.ODictCaseless()
- h["content-type"] = [flow.HDR_FORM_URLENCODED]
d = flow.ODict([("one", "two"), ("three", "four")])
- r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/", h, utils.urlencode(d.lst))
+ r = tutils.treq(content=utils.urlencode(d.lst))
+ r.headers["content-type"] = [protocol.http.HDR_FORM_URLENCODED]
assert r.get_form_urlencoded() == d
d = flow.ODict([("x", "y")])
@@ -868,19 +853,20 @@ class TestRequest:
def test_getset_query(self):
h = flow.ODictCaseless()
- r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/foo?x=y&a=b", h, "content")
+ r = tutils.treq()
+ r.path = "/foo?x=y&a=b"
q = r.get_query()
assert q.lst == [("x", "y"), ("a", "b")]
- r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/", h, "content")
+ r.path = "/"
q = r.get_query()
assert not q
- r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/?adsfa", h, "content")
+ r.path = "/?adsfa"
q = r.get_query()
assert q.lst == [("adsfa", "")]
- r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/foo?x=y&a=b", h, "content")
+ r.path = "/foo?x=y&a=b"
assert r.get_query()
r.set_query(flow.ODict([]))
assert not r.get_query()
@@ -890,34 +876,14 @@ class TestRequest:
def test_anticache(self):
h = flow.ODictCaseless()
- r = flow.Request(None, (1, 1), "host", 22, "https", "GET", "/", h, "content")
+ r = tutils.treq()
+ r.headers = h
h["if-modified-since"] = ["test"]
h["if-none-match"] = ["test"]
r.anticache()
assert not "if-modified-since" in r.headers
assert not "if-none-match" in r.headers
- def test_getset_state(self):
- h = flow.ODictCaseless()
- h["test"] = ["test"]
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
- state = r._get_state()
- assert flow.Request._from_state(state) == r
-
- r.client_conn = None
- state = r._get_state()
- assert flow.Request._from_state(state) == r
-
- r2 = flow.Request(c, (1, 1), "testing", 20, "http", "PUT", "/foo", h, "test")
- assert not r == r2
- r._load_state(r2._get_state())
- assert r == r2
-
- r2.client_conn = None
- r._load_state(r2._get_state())
- assert not r.client_conn
-
def test_replace(self):
r = tutils.treq()
r.path = "path/foo"
@@ -975,15 +941,15 @@ class TestRequest:
def test_get_cookies_none(self):
h = flow.ODictCaseless()
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
- assert r.get_cookies() == None
+ r = tutils.treq()
+ r.headers = h
+ assert r.get_cookies() is None
def test_get_cookies_single(self):
h = flow.ODictCaseless()
h["Cookie"] = ["cookiename=cookievalue"]
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
+ r = tutils.treq()
+ r.headers = h
result = r.get_cookies()
assert len(result)==1
assert result['cookiename']==('cookievalue',{})
@@ -991,8 +957,8 @@ class TestRequest:
def test_get_cookies_double(self):
h = flow.ODictCaseless()
h["Cookie"] = ["cookiename=cookievalue;othercookiename=othercookievalue"]
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
+ r = tutils.treq()
+ r.headers = h
result = r.get_cookies()
assert len(result)==2
assert result['cookiename']==('cookievalue',{})
@@ -1001,49 +967,35 @@ class TestRequest:
def test_get_cookies_withequalsign(self):
h = flow.ODictCaseless()
h["Cookie"] = ["cookiename=coo=kievalue;othercookiename=othercookievalue"]
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
+ r = tutils.treq()
+ r.headers = h
result = r.get_cookies()
assert len(result)==2
assert result['cookiename']==('coo=kievalue',{})
assert result['othercookiename']==('othercookievalue',{})
- def test_get_header_size(self):
+ def test_header_size(self):
h = flow.ODictCaseless()
h["headername"] = ["headervalue"]
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
- result = r.get_header_size()
- assert result==43
-
- def test_get_transmitted_size(self):
- h = flow.ODictCaseless()
- h["headername"] = ["headervalue"]
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
- result = r.get_transmitted_size()
- assert result==len("content")
- r.content = None
- assert r.get_transmitted_size() == 0
+ r = tutils.treq()
+ r.headers = h
+ result = len(r._assemble_headers())
+ assert result == 62
def test_get_content_type(self):
h = flow.ODictCaseless()
h["Content-Type"] = ["text/plain"]
- c = flow.ClientConnect(("addr", 2222))
- r = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
- assert r.get_content_type()=="text/plain"
+ resp = tutils.tresp()
+ resp.headers = h
+ assert resp.headers.get_first("content-type") == "text/plain"
class TestResponse:
def test_simple(self):
- h = flow.ODictCaseless()
- h["test"] = ["test"]
- c = flow.ClientConnect(("addr", 2222))
- req = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
- resp = flow.Response(req, (1, 1), 200, "msg", h.copy(), "content", None)
+ f = tutils.tflow_full()
+ resp = f.response
assert resp._assemble()
assert resp.size() == len(resp._assemble())
-
resp2 = resp.copy()
assert resp2 == resp
@@ -1052,7 +1004,7 @@ class TestResponse:
assert resp.size() == len(resp._assemble())
resp.content = flow.CONTENT_MISSING
- assert not resp._assemble()
+ tutils.raises("Cannot assemble flow with CONTENT_MISSING", resp._assemble)
def test_refresh(self):
r = tutils.tresp()
@@ -1081,21 +1033,6 @@ class TestResponse:
c = "MOO=BAR; Expires=Tue, 08-Mar-2011 00:20:38 GMT; Path=foo.com; Secure"
assert "00:21:38" in r._refresh_cookie(c, 60)
- def test_getset_state(self):
- h = flow.ODictCaseless()
- h["test"] = ["test"]
- c = flow.ClientConnect(("addr", 2222))
- req = flow.Request(c, (1, 1), "host", 22, "https", "GET", "/", h, "content")
- resp = flow.Response(req, (1, 1), 200, "msg", h.copy(), "content", None)
-
- state = resp._get_state()
- assert flow.Response._from_state(req, state) == resp
-
- resp2 = flow.Response(req, (1, 1), 220, "foo", h.copy(), "test", None)
- assert not resp == resp2
- resp._load_state(resp2._get_state())
- assert resp == resp2
-
def test_replace(self):
r = tutils.tresp()
r.headers["Foo"] = ["fOo"]
@@ -1108,7 +1045,7 @@ class TestResponse:
r = tutils.tresp()
r.headers["content-encoding"] = ["identity"]
r.content = "falafel"
- r.decode()
+ assert r.decode()
assert not r.headers["content-encoding"]
assert r.content == "falafel"
@@ -1125,24 +1062,30 @@ class TestResponse:
r.encode("gzip")
assert r.headers["content-encoding"] == ["gzip"]
assert r.content != "falafel"
- r.decode()
+ assert r.decode()
assert not r.headers["content-encoding"]
assert r.content == "falafel"
- def test_get_header_size(self):
+ r.headers["content-encoding"] = ["gzip"]
+ assert not r.decode()
+ assert r.content == "falafel"
+
+ def test_header_size(self):
r = tutils.tresp()
- result = r.get_header_size()
- assert result==49
+ result = len(r._assemble_headers())
+ assert result==44
def test_get_cookies_none(self):
h = flow.ODictCaseless()
- resp = flow.Response(None, (1, 1), 200, "OK", h, "content", None)
+ resp = tutils.tresp()
+ resp.headers = h
assert not resp.get_cookies()
def test_get_cookies_simple(self):
h = flow.ODictCaseless()
h["Set-Cookie"] = ["cookiename=cookievalue"]
- resp = flow.Response(None, (1, 1), 200, "OK", h, "content", None)
+ resp = tutils.tresp()
+ resp.headers = h
result = resp.get_cookies()
assert len(result)==1
assert "cookiename" in result
@@ -1151,7 +1094,8 @@ class TestResponse:
def test_get_cookies_with_parameters(self):
h = flow.ODictCaseless()
h["Set-Cookie"] = ["cookiename=cookievalue;domain=example.com;expires=Wed Oct 21 16:29:41 2015;path=/; HttpOnly"]
- resp = flow.Response(None, (1, 1), 200, "OK", h, "content", None)
+ resp = tutils.tresp()
+ resp.headers = h
result = resp.get_cookies()
assert len(result)==1
assert "cookiename" in result
@@ -1165,7 +1109,8 @@ class TestResponse:
def test_get_cookies_no_value(self):
h = flow.ODictCaseless()
h["Set-Cookie"] = ["cookiename=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/"]
- resp = flow.Response(None, (1, 1), 200, "OK", h, "content", None)
+ resp = tutils.tresp()
+ resp.headers = h
result = resp.get_cookies()
assert len(result)==1
assert "cookiename" in result
@@ -1175,7 +1120,8 @@ class TestResponse:
def test_get_cookies_twocookies(self):
h = flow.ODictCaseless()
h["Set-Cookie"] = ["cookiename=cookievalue","othercookie=othervalue"]
- resp = flow.Response(None, (1, 1), 200, "OK", h, "content", None)
+ resp = tutils.tresp()
+ resp.headers = h
result = resp.get_cookies()
assert len(result)==2
assert "cookiename" in result
@@ -1186,19 +1132,20 @@ class TestResponse:
def test_get_content_type(self):
h = flow.ODictCaseless()
h["Content-Type"] = ["text/plain"]
- resp = flow.Response(None, (1, 1), 200, "OK", h, "content", None)
- assert resp.get_content_type()=="text/plain"
+ resp = tutils.tresp()
+ resp.headers = h
+ assert resp.headers.get_first("content-type") == "text/plain"
class TestError:
def test_getset_state(self):
- e = flow.Error(None, "Error")
+ e = Error("Error")
state = e._get_state()
- assert flow.Error._from_state(None, state) == e
+ assert Error._from_state(state) == e
assert e.copy()
- e2 = flow.Error(None, "bar")
+ e2 = Error("bar")
assert not e == e2
e._load_state(e2._get_state())
assert e == e2
@@ -1207,23 +1154,20 @@ class TestError:
e3 = e.copy()
assert e3 == e
- def test_replace(self):
- e = flow.Error(None, "amoop")
- e.replace("moo", "bar")
- assert e.msg == "abarp"
-
-class TestClientConnect:
+class TestClientConnection:
def test_state(self):
- c = flow.ClientConnect(("a", 22))
- assert flow.ClientConnect._from_state(c._get_state()) == c
- c2 = flow.ClientConnect(("a", 25))
+ c = tutils.tclient_conn()
+ assert proxy.ClientConnection._from_state(c._get_state()) == c
+
+ c2 = tutils.tclient_conn()
+ c2.address.address = (c2.address.host, 4242)
assert not c == c2
- c2.requestcount = 99
+ c2.timestamp_start = 42
c._load_state(c2._get_state())
- assert c.requestcount == 99
+ assert c.timestamp_start == 42
c3 = c.copy()
assert c3 == c
@@ -1238,13 +1182,13 @@ def test_decoded():
r.encode("gzip")
assert r.headers["content-encoding"]
assert r.content != "content"
- with flow.decoded(r):
+ with decoded(r):
assert not r.headers["content-encoding"]
assert r.content == "content"
assert r.headers["content-encoding"]
assert r.content != "content"
- with flow.decoded(r):
+ with decoded(r):
r.content = "foo"
assert r.content != "foo"
diff --git a/test/test_fuzzing.py b/test/test_fuzzing.py
index ba7b751c..646ce5c1 100644
--- a/test/test_fuzzing.py
+++ b/test/test_fuzzing.py
@@ -32,8 +32,8 @@ class TestFuzzy(tservers.HTTPProxTest):
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"'
+ req = r'200:d0'
p = self.pathod(req)
- assert p.status_code == 400
+ assert p.status_code == 502
diff --git a/test/test_protocol_http.py b/test/test_protocol_http.py
new file mode 100644
index 00000000..3bf5af22
--- /dev/null
+++ b/test/test_protocol_http.py
@@ -0,0 +1,201 @@
+from libmproxy import proxy # FIXME: Remove
+from libmproxy.protocol.http import *
+from libmproxy.protocol import KILL
+from cStringIO import StringIO
+import tutils, tservers
+
+
+def test_HttpAuthenticationError():
+ x = HttpAuthenticationError({"foo": "bar"})
+ assert str(x)
+ assert "foo" in x.auth_headers
+
+
+def test_stripped_chunked_encoding_no_content():
+ """
+ https://github.com/mitmproxy/mitmproxy/issues/186
+ """
+ r = tutils.tresp(content="")
+ r.headers["Transfer-Encoding"] = ["chunked"]
+ assert "Content-Length" in r._assemble_headers()
+
+ r = tutils.treq(content="")
+ r.headers["Transfer-Encoding"] = ["chunked"]
+ assert "Content-Length" in r._assemble_headers()
+
+
+class TestHTTPRequest:
+ def test_asterisk_form(self):
+ s = StringIO("OPTIONS * HTTP/1.1")
+ f = tutils.tflow_noreq()
+ f.request = HTTPRequest.from_stream(s)
+ assert f.request.form_in == "asterisk"
+ x = f.request._assemble()
+ assert f.request._assemble() == "OPTIONS * HTTP/1.1\r\nHost: address:22\r\n\r\n"
+
+ def test_origin_form(self):
+ s = StringIO("GET /foo\xff HTTP/1.1")
+ tutils.raises("Bad HTTP request line", HTTPRequest.from_stream, s)
+
+ def test_authority_form(self):
+ s = StringIO("CONNECT oops-no-port.com HTTP/1.1")
+ tutils.raises("Bad HTTP request line", HTTPRequest.from_stream, s)
+ s = StringIO("CONNECT address:22 HTTP/1.1")
+ r = HTTPRequest.from_stream(s)
+ assert r._assemble() == "CONNECT address:22 HTTP/1.1\r\nHost: address:22\r\n\r\n"
+
+
+ def test_absolute_form(self):
+ s = StringIO("GET oops-no-protocol.com HTTP/1.1")
+ tutils.raises("Bad HTTP request line", HTTPRequest.from_stream, s)
+ s = StringIO("GET http://address:22/ HTTP/1.1")
+ r = HTTPRequest.from_stream(s)
+ assert r._assemble() == "GET http://address:22/ HTTP/1.1\r\nHost: address:22\r\n\r\n"
+
+ def test_assemble_unknown_form(self):
+ r = tutils.treq()
+ tutils.raises("Invalid request form", r._assemble, "antiauthority")
+
+
+ def test_set_url(self):
+ r = tutils.treq_absolute()
+ r.set_url("https://otheraddress:42/ORLY")
+ assert r.scheme == "https"
+ assert r.host == "otheraddress"
+ assert r.port == 42
+ assert r.path == "/ORLY"
+
+
+class TestHTTPResponse:
+ def test_read_from_stringio(self):
+ _s = "HTTP/1.1 200 OK\r\n" \
+ "Content-Length: 7\r\n" \
+ "\r\n"\
+ "content\r\n" \
+ "HTTP/1.1 204 OK\r\n" \
+ "\r\n"
+ s = StringIO(_s)
+ r = HTTPResponse.from_stream(s, "GET")
+ assert r.code == 200
+ assert r.content == "content"
+ assert HTTPResponse.from_stream(s, "GET").code == 204
+
+ s = StringIO(_s)
+ r = HTTPResponse.from_stream(s, "HEAD") # HEAD must not have content by spec. We should leave it on the pipe.
+ assert r.code == 200
+ assert r.content == ""
+ tutils.raises("Invalid server response: 'content", HTTPResponse.from_stream, s, "GET")
+
+
+class TestInvalidRequests(tservers.HTTPProxTest):
+ ssl = True
+
+ def test_double_connect(self):
+ p = self.pathoc()
+ r = p.request("connect:'%s:%s'" % ("127.0.0.1", self.server2.port))
+ assert r.status_code == 502
+ assert "Must not CONNECT on already encrypted connection" in r.content
+
+ def test_origin_request(self):
+ p = self.pathoc_raw()
+ p.connect()
+ r = p.request("get:/p/200")
+ assert r.status_code == 400
+ assert "Invalid request form" in r.content
+
+
+class TestProxyChaining(tservers.HTTPChainProxyTest):
+ def test_all(self):
+ self.chain[1].tmaster.replacehooks.add("~q", "foo", "bar") # replace in request
+ self.chain[0].tmaster.replacehooks.add("~q", "foo", "oh noes!")
+ self.proxy.tmaster.replacehooks.add("~q", "bar", "baz")
+ self.chain[0].tmaster.replacehooks.add("~s", "baz", "ORLY") # replace in response
+
+ p = self.pathoc()
+ req = p.request("get:'%s/p/418:b\"foo\"'" % self.server.urlbase)
+ assert req.content == "ORLY"
+ assert req.status_code == 418
+
+class TestProxyChainingSSL(tservers.HTTPChainProxyTest):
+ ssl = True
+
+ def test_simple(self):
+
+ p = self.pathoc()
+ req = p.request("get:'/p/418:b\"content\"'")
+ assert req.content == "content"
+ assert req.status_code == 418
+
+ assert self.chain[1].tmaster.state.flow_count() == 2 # CONNECT from pathoc to chain[0],
+ # request from pathoc to chain[0]
+ assert self.chain[0].tmaster.state.flow_count() == 2 # CONNECT from chain[1] to proxy,
+ # request from chain[1] to proxy
+ assert self.proxy.tmaster.state.flow_count() == 1 # request from chain[0] (regular proxy doesn't store CONNECTs)
+
+class TestProxyChainingSSLReconnect(tservers.HTTPChainProxyTest):
+ ssl = True
+
+ 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.
+ """
+ def kill_requests(master, attr, exclude):
+ k = [0] # variable scope workaround: put into array
+ _func = getattr(master, attr)
+ def handler(r):
+ k[0] += 1
+ if not (k[0] in exclude):
+ r.flow.client_conn.finish()
+ r.flow.error = Error("terminated")
+ r.reply(KILL)
+ return _func(r)
+ setattr(master, attr, handler)
+
+ kill_requests(self.proxy.tmaster, "handle_request",
+ exclude=[
+ # fail first request
+ 2, # allow second request
+ ])
+
+ kill_requests(self.chain[0].tmaster, "handle_request",
+ exclude=[
+ 1, # CONNECT
+ # fail first request
+ 3, # reCONNECT
+ 4, # request
+ ])
+
+ p = self.pathoc()
+ req = p.request("get:'/p/418:b\"content\"'")
+ assert self.chain[1].tmaster.state.flow_count() == 2 # CONNECT and request
+ assert self.chain[0].tmaster.state.flow_count() == 4 # CONNECT, failing request,
+ # reCONNECT, request
+ assert self.proxy.tmaster.state.flow_count() == 2 # failing request, request
+ # (doesn't store (repeated) CONNECTs from chain[0]
+ # as it is a regular proxy)
+ assert req.content == "content"
+ assert req.status_code == 418
+
+ assert not self.proxy.tmaster.state._flow_list[0].response # killed
+ assert self.proxy.tmaster.state._flow_list[1].response
+
+ assert self.chain[1].tmaster.state._flow_list[0].request.form_in == "authority"
+ assert self.chain[1].tmaster.state._flow_list[1].request.form_in == "origin"
+
+ assert self.chain[0].tmaster.state._flow_list[0].request.form_in == "authority"
+ assert self.chain[0].tmaster.state._flow_list[1].request.form_in == "origin"
+ assert self.chain[0].tmaster.state._flow_list[2].request.form_in == "authority"
+ assert self.chain[0].tmaster.state._flow_list[3].request.form_in == "origin"
+
+ assert self.proxy.tmaster.state._flow_list[0].request.form_in == "origin"
+ assert self.proxy.tmaster.state._flow_list[1].request.form_in == "origin"
+
+ req = p.request("get:'/p/418:b\"content2\"'")
+
+ assert req.status_code == 502
+ assert self.chain[1].tmaster.state.flow_count() == 3 # + new request
+ assert self.chain[0].tmaster.state.flow_count() == 6 # + new request, repeated CONNECT from chain[1]
+ # (both terminated)
+ assert self.proxy.tmaster.state.flow_count() == 2 # nothing happened here
diff --git a/test/test_proxy.py b/test/test_proxy.py
index 371e5ef7..c42d66e7 100644
--- a/test/test_proxy.py
+++ b/test/test_proxy.py
@@ -19,25 +19,24 @@ class TestServerConnection:
self.d.shutdown()
def test_simple(self):
- sc = proxy.ServerConnection(proxy.ProxyConfig(), "http", self.d.IFACE, self.d.port, "host.com")
+ sc = proxy.ServerConnection((self.d.IFACE, self.d.port), None)
sc.connect()
r = tutils.treq()
+ r.flow.server_conn = sc
r.path = "/p/200:da"
- sc.send(r)
+ sc.send(r._assemble())
assert http.read_response(sc.rfile, r.method, 1000)
assert self.d.last_log()
- r.content = flow.CONTENT_MISSING
- tutils.raises("incomplete request", sc.send, r)
-
- sc.terminate()
+ sc.finish()
def test_terminate_error(self):
- sc = proxy.ServerConnection(proxy.ProxyConfig(), "http", self.d.IFACE, self.d.port, "host.com")
+ sc = proxy.ServerConnection((self.d.IFACE, self.d.port), None)
sc.connect()
sc.connection = mock.Mock()
+ sc.connection.recv = mock.Mock(return_value=False)
sc.connection.flush = mock.Mock(side_effect=tcp.NetLibDisconnect)
- sc.terminate()
+ sc.finish()
class MockParser:
diff --git a/test/test_script.py b/test/test_script.py
index 025e9f37..13903066 100644
--- a/test/test_script.py
+++ b/test/test_script.py
@@ -32,8 +32,8 @@ class TestScript:
r = tutils.treq()
fm.handle_request(r)
assert fm.state.flow_count() == 2
- assert not fm.state.view[0].request.is_replay()
- assert fm.state.view[1].request.is_replay()
+ assert not fm.state.view[0].request.is_replay
+ assert fm.state.view[1].request.is_replay
def test_err(self):
s = flow.State()
@@ -75,9 +75,6 @@ class TestScript:
# Two instantiations
assert m.call_count == 2
assert (time.time() - t_start) < 0.09
- time.sleep(0.2)
- # Plus two invocations
- assert m.call_count == 4
def test_concurrent2(self):
s = flow.State()
@@ -89,13 +86,17 @@ class TestScript:
f.reply = f.request.reply
with mock.patch("libmproxy.controller.DummyReply.__call__") as m:
+ t_start = time.time()
s.run("clientconnect", f)
s.run("serverconnect", f)
s.run("response", f)
s.run("error", f)
s.run("clientdisconnect", f)
- time.sleep(0.1)
- assert m.call_count == 5
+ while (time.time() - t_start) < 1 and m.call_count <= 5:
+ if m.call_count == 5:
+ return
+ time.sleep(0.001)
+ assert False
def test_concurrent_err(self):
s = flow.State()
diff --git a/test/test_server.py b/test/test_server.py
index 646460ab..2f9e6728 100644
--- a/test/test_server.py
+++ b/test/test_server.py
@@ -4,6 +4,7 @@ from netlib import tcp, http_auth, http
from libpathod import pathoc, pathod
import tutils, tservers
from libmproxy import flow, proxy
+from libmproxy.protocol import KILL
"""
Note that the choice of response code in these tests matters more than you
@@ -41,16 +42,17 @@ class CommonMixin:
assert f.status_code == 304
l = self.master.state.view[0]
- assert l.request.client_conn.address
+ assert l.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 = 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()
+ line = t.rfile.readline()
+ assert ("Bad Request" in line) or ("Bad Gateway" in line)
@@ -70,7 +72,7 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin, AppMixin):
assert "ValueError" in ret.content
def test_invalid_connect(self):
- t = tcp.TCPClient("127.0.0.1", self.proxy.port)
+ t = tcp.TCPClient(("127.0.0.1", self.proxy.port))
t.connect()
t.wfile.write("CONNECT invalid\n\n")
t.wfile.flush()
@@ -105,22 +107,17 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin, AppMixin):
assert p.request(req)
assert p.request(req)
- # However, if the server disconnects on our first try, it's an error.
- req = "get:'%s/p/200:b@1:d0'"%self.server.urlbase
- p = self.pathoc()
- tutils.raises("server disconnect", p.request, req)
-
def test_proxy_ioerror(self):
# Tests a difficult-to-trigger condition, where an IOError is raised
# within our read loop.
- with mock.patch("libmproxy.proxy.ProxyHandler.read_request") as m:
+ with mock.patch("libmproxy.protocol.http.HTTPRequest.from_stream") as m:
m.side_effect = IOError("error!")
tutils.raises("server disconnect", self.pathod, "304")
def test_get_connection_switching(self):
def switched(l):
for i in l:
- if "switching" in i:
+ if "serverdisconnect" in i:
return True
req = "get:'%s/p/200:b@1'"
p = self.pathoc()
@@ -156,6 +153,7 @@ class TestHTTP(tservers.HTTPProxTest, CommonMixin, AppMixin):
connection.close()
assert "content-length" in resp.lower()
+
class TestHTTPAuth(tservers.HTTPProxTest):
authenticator = http_auth.BasicProxyAuth(http_auth.PassManSingleUser("test", "test"), "realm")
def test_auth(self):
@@ -230,12 +228,13 @@ class TestTransparentSSL(tservers.TransparentProxTest, CommonMixin):
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"
+ assert l["request"]["sni"] == "testserver.com"
def test_sslerr(self):
- p = pathoc.Pathoc("localhost", self.proxy.port)
+ p = pathoc.Pathoc(("localhost", self.proxy.port))
p.connect()
- assert p.request("get:/").status_code == 400
+ r = p.request("get:/")
+ assert r.status_code == 502
class TestProxy(tservers.HTTPProxTest):
@@ -243,10 +242,10 @@ class TestProxy(tservers.HTTPProxTest):
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
+ f = self.master.state.view[0]
+ assert f.client_conn.address
+ assert "host" in f.request.headers
+ assert f.response.code == 304
def test_response_timestamps(self):
# test that we notice at least 2 sec delay between timestamps
@@ -288,8 +287,7 @@ class TestProxy(tservers.HTTPProxTest):
assert request.timestamp_end - request.timestamp_start <= 0.1
def test_request_tcp_setup_timestamp_presence(self):
- # tests that the first request in a tcp connection has a tcp_setup_timestamp
- # while others do not
+ # tests that the client_conn a tcp connection has a tcp_setup_timestamp
connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connection.connect(("localhost", self.proxy.port))
connection.send("GET http://localhost:%d/p/304:b@1k HTTP/1.1\r\n"%self.server.port)
@@ -300,18 +298,18 @@ class TestProxy(tservers.HTTPProxTest):
connection.recv(5000)
connection.close()
- first_request = self.master.state.view[0].request
- second_request = self.master.state.view[1].request
- assert first_request.tcp_setup_timestamp
- assert first_request.ssl_setup_timestamp == None
- assert second_request.tcp_setup_timestamp == None
- assert second_request.ssl_setup_timestamp == None
+ first_flow = self.master.state.view[0]
+ second_flow = self.master.state.view[1]
+ assert first_flow.server_conn.timestamp_tcp_setup
+ assert first_flow.server_conn.timestamp_ssl_setup is None
+ assert second_flow.server_conn.timestamp_tcp_setup
+ assert first_flow.server_conn.timestamp_tcp_setup == second_flow.server_conn.timestamp_tcp_setup
def test_request_ip(self):
f = self.pathod("200:b@100")
assert f.status_code == 200
- request = self.master.state.view[0].request
- assert request.ip == "127.0.0.1"
+ f = self.master.state.view[0]
+ assert f.server_conn.peername == ("127.0.0.1", self.server.port)
class TestProxySSL(tservers.HTTPProxTest):
ssl=True
@@ -320,7 +318,7 @@ class TestProxySSL(tservers.HTTPProxTest):
f = self.pathod("304:b@10k")
assert f.status_code == 304
first_request = self.master.state.view[0].request
- assert first_request.ssl_setup_timestamp
+ assert first_request.flow.server_conn.timestamp_ssl_setup
class MasterFakeResponse(tservers.TestMaster):
def handle_request(self, m):
@@ -335,10 +333,9 @@ class TestFakeResponse(tservers.HTTPProxTest):
assert "header_response" in f.headers.keys()
-
class MasterKillRequest(tservers.TestMaster):
def handle_request(self, m):
- m.reply(proxy.KILL)
+ m.reply(KILL)
class TestKillRequest(tservers.HTTPProxTest):
@@ -351,7 +348,7 @@ class TestKillRequest(tservers.HTTPProxTest):
class MasterKillResponse(tservers.TestMaster):
def handle_response(self, m):
- m.reply(proxy.KILL)
+ m.reply(KILL)
class TestKillResponse(tservers.HTTPProxTest):
diff --git a/test/tservers.py b/test/tservers.py
index ac95b168..812e8921 100644
--- a/test/tservers.py
+++ b/test/tservers.py
@@ -21,13 +21,12 @@ def errapp(environ, start_response):
class TestMaster(flow.FlowMaster):
- def __init__(self, testq, config):
+ def __init__(self, config):
s = proxy.ProxyServer(config, 0)
state = flow.State()
flow.FlowMaster.__init__(self, s, state)
self.apps.add(testapp, "testapp", 80)
self.apps.add(errapp, "errapp", 80)
- self.testq = testq
self.clear_log()
self.start_app(APP_HOST, APP_PORT, False)
@@ -51,11 +50,12 @@ class ProxyThread(threading.Thread):
def __init__(self, tmaster):
threading.Thread.__init__(self)
self.tmaster = tmaster
+ self.name = "ProxyThread (%s:%s)" % (tmaster.server.address.host, tmaster.server.address.port)
controller.should_exit = False
@property
def port(self):
- return self.tmaster.server.port
+ return self.tmaster.server.address.port
@property
def log(self):
@@ -68,7 +68,7 @@ class ProxyThread(threading.Thread):
self.tmaster.shutdown()
-class ProxTestBase:
+class ProxTestBase(object):
# Test Configuration
ssl = None
ssloptions = False
@@ -79,17 +79,16 @@ class ProxTestBase:
masterclass = TestMaster
@classmethod
def setupAll(cls):
- cls.tqueue = Queue.Queue()
cls.server = libpathod.test.Daemon(ssl=cls.ssl, ssloptions=cls.ssloptions)
cls.server2 = libpathod.test.Daemon(ssl=cls.ssl, ssloptions=cls.ssloptions)
pconf = cls.get_proxy_config()
config = proxy.ProxyConfig(
no_upstream_cert = cls.no_upstream_cert,
- cacert = tutils.test_data.path("data/serverkey.pem"),
+ cacert = tutils.test_data.path("data/confdir/mitmproxy-ca.pem"),
authenticator = cls.authenticator,
**pconf
)
- tmaster = cls.masterclass(cls.tqueue, config)
+ tmaster = cls.masterclass(config)
cls.proxy = ProxyThread(tmaster)
cls.proxy.start()
@@ -134,13 +133,13 @@ class ProxTestBase:
class HTTPProxTest(ProxTestBase):
def pathoc_raw(self):
- return libpathod.pathoc.Pathoc("127.0.0.1", self.proxy.port)
+ 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, ssl=self.ssl, sni=sni)
+ 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:
@@ -161,10 +160,8 @@ class HTTPProxTest(ProxTestBase):
def app(self, page):
if self.ssl:
- p = libpathod.pathoc.Pathoc("127.0.0.1", self.proxy.port, True)
- print "PRE"
+ p = libpathod.pathoc.Pathoc(("127.0.0.1", self.proxy.port), True)
p.connect((APP_HOST, APP_PORT))
- print "POST"
return p.request("get:'/%s'"%page)
else:
p = self.pathoc()
@@ -211,7 +208,7 @@ class TransparentProxTest(ProxTestBase):
"""
Returns a connected Pathoc instance.
"""
- p = libpathod.pathoc.Pathoc("localhost", self.proxy.port, ssl=self.ssl, sni=sni)
+ p = libpathod.pathoc.Pathoc(("localhost", self.proxy.port), ssl=self.ssl, sni=sni)
p.connect()
return p
@@ -232,7 +229,7 @@ class ReverseProxTest(ProxTestBase):
"""
Returns a connected Pathoc instance.
"""
- p = libpathod.pathoc.Pathoc("localhost", self.proxy.port, ssl=self.ssl, sni=sni)
+ p = libpathod.pathoc.Pathoc(("localhost", self.proxy.port), ssl=self.ssl, sni=sni)
p.connect()
return p
@@ -249,5 +246,49 @@ class ReverseProxTest(ProxTestBase):
return p.request(q)
+class ChainProxTest(ProxTestBase):
+ """
+ Chain n instances of mitmproxy in a row - because we can.
+ """
+ n = 2
+ chain_config = [lambda: proxy.ProxyConfig(
+ cacert = tutils.test_data.path("data/confdir/mitmproxy-ca.pem"),
+ )] * n
+ @classmethod
+ def setupAll(cls):
+ super(ChainProxTest, cls).setupAll()
+ cls.chain = []
+ for i in range(cls.n):
+ config = cls.chain_config[i]()
+ config.forward_proxy = ("http", "127.0.0.1",
+ cls.proxy.port if i == 0 else
+ cls.chain[-1].port
+ )
+ tmaster = cls.masterclass(config)
+ cls.chain.append(ProxyThread(tmaster))
+ cls.chain[-1].start()
+ @classmethod
+ def teardownAll(cls):
+ super(ChainProxTest, cls).teardownAll()
+ for p in cls.chain:
+ p.tmaster.server.shutdown()
+ def setUp(self):
+ super(ChainProxTest, self).setUp()
+ for p in self.chain:
+ p.tmaster.clear_log()
+ p.tmaster.state.clear()
+
+
+class HTTPChainProxyTest(ChainProxTest):
+ def pathoc(self, sni=None):
+ """
+ Returns a connected Pathoc instance.
+ """
+ p = libpathod.pathoc.Pathoc(("localhost", self.chain[-1].port), ssl=self.ssl, sni=sni)
+ if self.ssl:
+ p.connect(("127.0.0.1", self.server.port))
+ else:
+ p.connect()
+ return p
diff --git a/test/tutils.py b/test/tutils.py
index fb41d77a..75fb7c0b 100644
--- a/test/tutils.py
+++ b/test/tutils.py
@@ -1,12 +1,15 @@
import os, shutil, tempfile
from contextlib import contextmanager
-from libmproxy import flow, utils, controller
-if os.name != "nt":
- from libmproxy.console.flowview import FlowView
- from libmproxy.console import ConsoleState
+from libmproxy import flow, utils, controller, proxy
+from libmproxy.protocol import http
+import mock_urwid
+from libmproxy.console.flowview import FlowView
+from libmproxy.console import ConsoleState
+from libmproxy.protocol.primitives import Error
from netlib import certutils
from nose.plugins.skip import SkipTest
from mock import Mock
+from time import time
def _SkipWindows():
raise SkipTest("Skipped on Windows.")
@@ -16,40 +19,82 @@ def SkipWindows(fn):
else:
return fn
+
+def tclient_conn():
+ c = proxy.ClientConnection._from_state(dict(
+ address=dict(address=("address", 22), use_ipv6=True),
+ clientcert=None
+ ))
+ c.reply = controller.DummyReply()
+ return c
+
+
+def tserver_conn():
+ c = proxy.ServerConnection._from_state(dict(
+ address=dict(address=("address", 22), use_ipv6=True),
+ source_address=dict(address=("address", 22), use_ipv6=True),
+ cert=None
+ ))
+ c.reply = controller.DummyReply()
+ return c
+
+
+def treq_absolute(conn=None, content="content"):
+ r = treq(conn, content)
+ r.form_in = r.form_out = "absolute"
+ r.host = "address"
+ r.port = 22
+ r.scheme = "http"
+ return r
+
def treq(conn=None, content="content"):
if not conn:
- conn = flow.ClientConnect(("address", 22))
- conn.reply = controller.DummyReply()
+ conn = tclient_conn()
+ server_conn = tserver_conn()
headers = flow.ODictCaseless()
headers["header"] = ["qvalue"]
- r = flow.Request(conn, (1, 1), "host", 80, "http", "GET", "/path", headers,
- content)
- r.reply = controller.DummyReply()
- return r
+ f = http.HTTPFlow(conn, server_conn)
+ f.request = http.HTTPRequest("origin", "GET", None, None, None, "/path", (1, 1), headers, content,
+ None, None, None)
+ f.request.reply = controller.DummyReply()
+ return f.request
-def tresp(req=None):
+
+def tresp(req=None, content="message"):
if not req:
req = treq()
+ f = req.flow
+
headers = flow.ODictCaseless()
headers["header_response"] = ["svalue"]
- cert = certutils.SSLCert.from_der(file(test_data.path("data/dercert"),"rb").read())
- resp = flow.Response(req, (1, 1), 200, "message", headers, "content_response", cert)
- resp.reply = controller.DummyReply()
- return resp
+ cert = certutils.SSLCert.from_der(file(test_data.path("data/dercert"), "rb").read())
+ f.server_conn = proxy.ServerConnection._from_state(dict(
+ address=dict(address=("address", 22), use_ipv6=True),
+ source_address=None,
+ cert=cert.to_pem()))
+ f.response = http.HTTPResponse((1, 1), 200, "OK", headers, content, time(), time())
+ f.response.reply = controller.DummyReply()
+ return f.response
+
def terr(req=None):
if not req:
req = treq()
- err = flow.Error(req, "error")
- err.reply = controller.DummyReply()
- return err
+ f = req.flow
+ f.error = Error("error")
+ f.error.reply = controller.DummyReply()
+ return f.error
+def tflow_noreq():
+ f = tflow()
+ f.request = None
+ return f
-def tflow(r=None):
- if r == None:
- r = treq()
- return flow.Flow(r)
+def tflow(req=None):
+ if not req:
+ req = treq()
+ return req.flow
def tflow_full():