diff options
Diffstat (limited to 'test')
25 files changed, 420 insertions, 345 deletions
diff --git a/test/mitmproxy/test_examples.py b/test/mitmproxy/test_examples.py index b560d9a1..0c117306 100644 --- a/test/mitmproxy/test_examples.py +++ b/test/mitmproxy/test_examples.py @@ -5,11 +5,12 @@ from contextlib import contextmanager from mitmproxy import utils, script from mitmproxy.proxy import config +import netlib.utils from netlib import tutils as netutils from netlib.http import Headers from . import tservers, tutils -example_dir = utils.Data(__name__).path("../../examples") +example_dir = netlib.utils.Data(__name__).path("../../examples") class DummyContext(object): @@ -106,8 +107,8 @@ def test_modify_querystring(): def test_modify_response_body(): with tutils.raises(script.ScriptException): - with example("modify_response_body.py") as ex: - pass + with example("modify_response_body.py"): + assert True flow = tutils.tflow(resp=netutils.tresp(content="I <3 mitmproxy")) with example("modify_response_body.py mitmproxy rocks") as ex: @@ -125,7 +126,7 @@ def test_redirect_requests(): def test_har_extractor(): with tutils.raises(script.ScriptException): - with example("har_extractor.py") as ex: + with example("har_extractor.py"): pass times = dict( diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py index 145e91cf..b9c6a2f6 100644 --- a/test/mitmproxy/test_flow.py +++ b/test/mitmproxy/test_flow.py @@ -7,7 +7,7 @@ import netlib.utils from netlib import odict from netlib.http import Headers from mitmproxy import filt, controller, tnetstring, flow -from mitmproxy.exceptions import FlowReadException +from mitmproxy.exceptions import FlowReadException, ScriptException from mitmproxy.models import Error from mitmproxy.models import Flow from mitmproxy.models import HTTPFlow @@ -76,6 +76,21 @@ class TestStickyCookieState: googlekey = s.jar.keys()[0] assert len(s.jar[googlekey].keys()) == 2 + # Test setting of weird cookie keys + s = flow.StickyCookieState(filt.parse(".*")) + f = tutils.tflow(req=netlib.tutils.treq(host="www.google.com", port=80), resp=True) + cs = [ + "foo/bar=hello", + "foo:bar=world", + "foo@bar=fizz", + "foo,bar=buzz", + ] + for c in cs: + f.response.headers["Set-Cookie"] = c + s.handle_response(f) + googlekey = s.jar.keys()[0] + assert len(s.jar[googlekey].keys()) == len(cs) + # Test overwriting of a cookie value c1 = "somecookie=helloworld; Path=/" c2 = "somecookie=newvalue; Path=/" @@ -84,7 +99,7 @@ class TestStickyCookieState: s.handle_response(f) googlekey = s.jar.keys()[0] assert len(s.jar[googlekey].keys()) == 1 - assert s.jar[googlekey]["somecookie"].value == "newvalue" + assert s.jar[googlekey]["somecookie"].items()[0][1] == "newvalue" def test_handle_request(self): s, f = self._response("SSID=mooo", "www.google.com") @@ -747,12 +762,16 @@ class TestFlowMaster: def test_load_script(self): s = flow.State() fm = flow.FlowMaster(None, s) - assert not fm.load_script(tutils.test_data.path("scripts/a.py")) - assert not fm.load_script(tutils.test_data.path("scripts/a.py")) - assert not fm.unload_scripts() - assert fm.load_script("nonexistent") - assert "ValueError" in fm.load_script( - tutils.test_data.path("scripts/starterr.py")) + + fm.load_script(tutils.test_data.path("scripts/a.py")) + fm.load_script(tutils.test_data.path("scripts/a.py")) + fm.unload_scripts() + with tutils.raises(ScriptException): + fm.load_script("nonexistent") + try: + fm.load_script(tutils.test_data.path("scripts/starterr.py")) + except ScriptException as e: + assert "ValueError" in str(e) assert len(fm.scripts) == 0 def test_getset_ignore(self): @@ -779,7 +798,7 @@ class TestFlowMaster: def test_script_reqerr(self): s = flow.State() fm = flow.FlowMaster(None, s) - assert not fm.load_script(tutils.test_data.path("scripts/reqerr.py")) + fm.load_script(tutils.test_data.path("scripts/reqerr.py")) f = tutils.tflow() fm.handle_clientconnect(f.client_conn) assert fm.handle_request(f) @@ -787,7 +806,7 @@ class TestFlowMaster: def test_script(self): s = flow.State() fm = flow.FlowMaster(None, s) - assert not fm.load_script(tutils.test_data.path("scripts/all.py")) + fm.load_script(tutils.test_data.path("scripts/all.py")) f = tutils.tflow(resp=True) fm.handle_clientconnect(f.client_conn) @@ -799,7 +818,7 @@ class TestFlowMaster: fm.handle_response(f) assert fm.scripts[0].ns["log"][-1] == "response" # load second script - assert not fm.load_script(tutils.test_data.path("scripts/all.py")) + fm.load_script(tutils.test_data.path("scripts/all.py")) assert len(fm.scripts) == 2 fm.handle_clientdisconnect(f.server_conn) assert fm.scripts[0].ns["log"][-1] == "clientdisconnect" @@ -808,7 +827,7 @@ class TestFlowMaster: # unload first script fm.unload_scripts() assert len(fm.scripts) == 0 - assert not fm.load_script(tutils.test_data.path("scripts/all.py")) + fm.load_script(tutils.test_data.path("scripts/all.py")) f.error = tutils.terr() fm.handle_error(f) diff --git a/test/mitmproxy/test_flow_export.py b/test/mitmproxy/test_flow_export.py index 75a8090f..035f07b7 100644 --- a/test/mitmproxy/test_flow_export.py +++ b/test/mitmproxy/test_flow_export.py @@ -1,152 +1,74 @@ import json from textwrap import dedent +import re import netlib.tutils from netlib.http import Headers from mitmproxy import flow_export from . import tutils -req_get = netlib.tutils.treq( - method='GET', - content='', -) -req_post = netlib.tutils.treq( - method='POST', - headers=None, -) +def clean_blanks(s): + return re.sub(r"^(\s+)$", "", s, flags=re.MULTILINE) -req_patch = netlib.tutils.treq( - method='PATCH', - path=b"/path?query=param", -) +def python_equals(testdata, text): + """ + Compare two bits of Python code, disregarding non-significant differences + like whitespace on blank lines and trailing space. + """ + d = open(tutils.test_data.path(testdata)).read() + assert clean_blanks(text).rstrip() == clean_blanks(d).rstrip() + + +req_get = lambda: netlib.tutils.treq(method='GET', content='') + +req_post = lambda: netlib.tutils.treq(method='POST', headers=None) + +req_patch = lambda: netlib.tutils.treq(method='PATCH', path=b"/path?query=param") -class TestExportCurlCommand(): +class TestExportCurlCommand(): def test_get(self): - flow = tutils.tflow(req=req_get) + flow = tutils.tflow(req=req_get()) result = """curl -H 'header:qvalue' -H 'content-length:7' 'http://address/path'""" assert flow_export.curl_command(flow) == result def test_post(self): - flow = tutils.tflow(req=req_post) + flow = tutils.tflow(req=req_post()) result = """curl -X POST 'http://address/path' --data-binary 'content'""" assert flow_export.curl_command(flow) == result def test_patch(self): - flow = tutils.tflow(req=req_patch) + flow = tutils.tflow(req=req_patch()) result = """curl -H 'header:qvalue' -H 'content-length:7' -X PATCH 'http://address/path?query=param' --data-binary 'content'""" assert flow_export.curl_command(flow) == result class TestExportPythonCode(): - def test_get(self): - flow = tutils.tflow(req=req_get) - result = dedent(""" - import requests - - url = 'http://address/path' - - headers = { - 'header': 'qvalue', - 'content-length': '7', - } - - response = requests.request( - method='GET', - url=url, - headers=headers, - ) - - print(response.text) - """).strip() - assert flow_export.python_code(flow) == result + flow = tutils.tflow(req=req_get()) + python_equals("test_flow_export/python_get.py", flow_export.python_code(flow)) def test_post(self): - flow = tutils.tflow(req=req_post) - result = dedent(""" - import requests - - url = 'http://address/path' - - data = '''content''' - - response = requests.request( - method='POST', - url=url, - data=data, - ) - - print(response.text) - """).strip() - assert flow_export.python_code(flow) == result + flow = tutils.tflow(req=req_post()) + python_equals("test_flow_export/python_post.py", flow_export.python_code(flow)) def test_post_json(self): - req_post.content = '{"name": "example", "email": "example@example.com"}' - req_post.headers = Headers(content_type="application/json") - flow = tutils.tflow(req=req_post) - result = dedent(""" - import requests - - url = 'http://address/path' - - headers = { - 'content-type': 'application/json', - } - - json = { - "name": "example", - "email": "example@example.com" - } - - response = requests.request( - method='POST', - url=url, - headers=headers, - json=json, - ) - - print(response.text) - """).strip() - assert flow_export.python_code(flow) == result + p = req_post() + p.content = '{"name": "example", "email": "example@example.com"}' + p.headers = Headers(content_type="application/json") + flow = tutils.tflow(req=p) + python_equals("test_flow_export/python_post_json.py", flow_export.python_code(flow)) def test_patch(self): - flow = tutils.tflow(req=req_patch) - result = dedent(""" - import requests - - url = 'http://address/path' - - headers = { - 'header': 'qvalue', - 'content-length': '7', - } - - params = { - 'query': 'param', - } - - data = '''content''' - - response = requests.request( - method='PATCH', - url=url, - headers=headers, - params=params, - data=data, - ) - - print(response.text) - """).strip() - assert flow_export.python_code(flow) == result + flow = tutils.tflow(req=req_patch()) + python_equals("test_flow_export/python_patch.py", flow_export.python_code(flow)) class TestRawRequest(): - def test_get(self): - flow = tutils.tflow(req=req_get) + flow = tutils.tflow(req=req_get()) result = dedent(""" GET /path HTTP/1.1\r header: qvalue\r @@ -157,18 +79,17 @@ class TestRawRequest(): assert flow_export.raw_request(flow) == result def test_post(self): - flow = tutils.tflow(req=req_post) + flow = tutils.tflow(req=req_post()) result = dedent(""" POST /path HTTP/1.1\r - content-type: application/json\r host: address:22\r \r - {"name": "example", "email": "example@example.com"} + content """).strip() assert flow_export.raw_request(flow) == result def test_patch(self): - flow = tutils.tflow(req=req_patch) + flow = tutils.tflow(req=req_patch()) result = dedent(""" PATCH /path?query=param HTTP/1.1\r header: qvalue\r @@ -179,212 +100,50 @@ class TestRawRequest(): """).strip() assert flow_export.raw_request(flow) == result -class TestExportLocustCode(): +class TestExportLocustCode(): def test_get(self): - flow = tutils.tflow(req=req_get) - result = """ -from locust import HttpLocust, TaskSet, task - -class UserBehavior(TaskSet): - def on_start(self): - ''' on_start is called when a Locust start before any task is scheduled ''' - self.path() - - @task() - def path(self): - url = self.locust.host + '/path' - - headers = { - 'header': 'qvalue', - 'content-length': '7', - } - - self.response = self.client.request( - method='GET', - url=url, - headers=headers, - ) - - ### Additional tasks can go here ### - - -class WebsiteUser(HttpLocust): - task_set = UserBehavior - min_wait = 1000 - max_wait = 3000 - """.strip() - - assert flow_export.locust_code(flow) == result + flow = tutils.tflow(req=req_get()) + python_equals("test_flow_export/locust_get.py", flow_export.locust_code(flow)) def test_post(self): - req_post.content = '''content''' - req_post.headers = '' - flow = tutils.tflow(req=req_post) - result = """ -from locust import HttpLocust, TaskSet, task - -class UserBehavior(TaskSet): - def on_start(self): - ''' on_start is called when a Locust start before any task is scheduled ''' - self.path() - - @task() - def path(self): - url = self.locust.host + '/path' - - data = '''content''' - - self.response = self.client.request( - method='POST', - url=url, - data=data, - ) - - ### Additional tasks can go here ### - - -class WebsiteUser(HttpLocust): - task_set = UserBehavior - min_wait = 1000 - max_wait = 3000 - - """.strip() - - assert flow_export.locust_code(flow) == result - + p = req_post() + p.content = '''content''' + p.headers = '' + flow = tutils.tflow(req=p) + python_equals("test_flow_export/locust_post.py", flow_export.locust_code(flow)) def test_patch(self): - flow = tutils.tflow(req=req_patch) - result = """ -from locust import HttpLocust, TaskSet, task - -class UserBehavior(TaskSet): - def on_start(self): - ''' on_start is called when a Locust start before any task is scheduled ''' - self.path() - - @task() - def path(self): - url = self.locust.host + '/path' - - headers = { - 'header': 'qvalue', - 'content-length': '7', - } - - params = { - 'query': 'param', - } - - data = '''content''' - - self.response = self.client.request( - method='PATCH', - url=url, - headers=headers, - params=params, - data=data, - ) - - ### Additional tasks can go here ### - - -class WebsiteUser(HttpLocust): - task_set = UserBehavior - min_wait = 1000 - max_wait = 3000 - - """.strip() - - assert flow_export.locust_code(flow) == result + flow = tutils.tflow(req=req_patch()) + python_equals("test_flow_export/locust_patch.py", flow_export.locust_code(flow)) class TestExportLocustTask(): - def test_get(self): - flow = tutils.tflow(req=req_get) - result = ' ' + """ - @task() - def path(self): - url = self.locust.host + '/path' - - headers = { - 'header': 'qvalue', - 'content-length': '7', - } - - self.response = self.client.request( - method='GET', - url=url, - headers=headers, - ) - """.strip() + '\n' - - assert flow_export.locust_task(flow) == result + flow = tutils.tflow(req=req_get()) + python_equals("test_flow_export/locust_task_get.py", flow_export.locust_task(flow)) def test_post(self): - flow = tutils.tflow(req=req_post) - result = ' ' + """ - @task() - def path(self): - url = self.locust.host + '/path' - - data = '''content''' - - self.response = self.client.request( - method='POST', - url=url, - data=data, - ) - """.strip() + '\n' - - assert flow_export.locust_task(flow) == result - + flow = tutils.tflow(req=req_post()) + python_equals("test_flow_export/locust_task_post.py", flow_export.locust_task(flow)) def test_patch(self): - flow = tutils.tflow(req=req_patch) - result = ' ' + """ - @task() - def path(self): - url = self.locust.host + '/path' - - headers = { - 'header': 'qvalue', - 'content-length': '7', - } - - params = { - 'query': 'param', - } - - data = '''content''' - - self.response = self.client.request( - method='PATCH', - url=url, - headers=headers, - params=params, - data=data, - ) - """.strip() + '\n' - - assert flow_export.locust_task(flow) == result + flow = tutils.tflow(req=req_patch()) + python_equals("test_flow_export/locust_task_patch.py", flow_export.locust_task(flow)) class TestIsJson(): - def test_empty(self): - assert flow_export.is_json(None, None) == False + assert flow_export.is_json(None, None) is False def test_json_type(self): headers = Headers(content_type="application/json") - assert flow_export.is_json(headers, "foobar") == False + assert flow_export.is_json(headers, "foobar") is False def test_valid(self): headers = Headers(content_type="application/foobar") j = flow_export.is_json(headers, '{"name": "example", "email": "example@example.com"}') - assert j == False + assert j is False def test_valid(self): headers = Headers(content_type="application/json") diff --git a/test/mitmproxy/test_flow_export/locust_get.py b/test/mitmproxy/test_flow_export/locust_get.py new file mode 100644 index 00000000..72d5932a --- /dev/null +++ b/test/mitmproxy/test_flow_export/locust_get.py @@ -0,0 +1,29 @@ +from locust import HttpLocust, TaskSet, task + +class UserBehavior(TaskSet): + def on_start(self): + ''' on_start is called when a Locust start before any task is scheduled ''' + self.path() + + @task() + def path(self): + url = self.locust.host + '/path' + + headers = { + 'header': 'qvalue', + 'content-length': '7', + } + + self.response = self.client.request( + method='GET', + url=url, + headers=headers, + ) + + ### Additional tasks can go here ### + + +class WebsiteUser(HttpLocust): + task_set = UserBehavior + min_wait = 1000 + max_wait = 3000 diff --git a/test/mitmproxy/test_flow_export/locust_patch.py b/test/mitmproxy/test_flow_export/locust_patch.py new file mode 100644 index 00000000..f64e0857 --- /dev/null +++ b/test/mitmproxy/test_flow_export/locust_patch.py @@ -0,0 +1,37 @@ +from locust import HttpLocust, TaskSet, task + +class UserBehavior(TaskSet): + def on_start(self): + ''' on_start is called when a Locust start before any task is scheduled ''' + self.path() + + @task() + def path(self): + url = self.locust.host + '/path' + + headers = { + 'header': 'qvalue', + 'content-length': '7', + } + + params = { + 'query': 'param', + } + + data = '''content''' + + self.response = self.client.request( + method='PATCH', + url=url, + headers=headers, + params=params, + data=data, + ) + + ### Additional tasks can go here ### + + +class WebsiteUser(HttpLocust): + task_set = UserBehavior + min_wait = 1000 + max_wait = 3000 diff --git a/test/mitmproxy/test_flow_export/locust_post.py b/test/mitmproxy/test_flow_export/locust_post.py new file mode 100644 index 00000000..df23476a --- /dev/null +++ b/test/mitmproxy/test_flow_export/locust_post.py @@ -0,0 +1,26 @@ +from locust import HttpLocust, TaskSet, task + +class UserBehavior(TaskSet): + def on_start(self): + ''' on_start is called when a Locust start before any task is scheduled ''' + self.path() + + @task() + def path(self): + url = self.locust.host + '/path' + + data = '''content''' + + self.response = self.client.request( + method='POST', + url=url, + data=data, + ) + + ### Additional tasks can go here ### + + +class WebsiteUser(HttpLocust): + task_set = UserBehavior + min_wait = 1000 + max_wait = 3000 diff --git a/test/mitmproxy/test_flow_export/locust_task_get.py b/test/mitmproxy/test_flow_export/locust_task_get.py new file mode 100644 index 00000000..76f144fa --- /dev/null +++ b/test/mitmproxy/test_flow_export/locust_task_get.py @@ -0,0 +1,14 @@ + @task() + def path(self): + url = self.locust.host + '/path' + + headers = { + 'header': 'qvalue', + 'content-length': '7', + } + + self.response = self.client.request( + method='GET', + url=url, + headers=headers, + ) diff --git a/test/mitmproxy/test_flow_export/locust_task_patch.py b/test/mitmproxy/test_flow_export/locust_task_patch.py new file mode 100644 index 00000000..d425209c --- /dev/null +++ b/test/mitmproxy/test_flow_export/locust_task_patch.py @@ -0,0 +1,22 @@ + @task() + def path(self): + url = self.locust.host + '/path' + + headers = { + 'header': 'qvalue', + 'content-length': '7', + } + + params = { + 'query': 'param', + } + + data = '''content''' + + self.response = self.client.request( + method='PATCH', + url=url, + headers=headers, + params=params, + data=data, + ) diff --git a/test/mitmproxy/test_flow_export/locust_task_post.py b/test/mitmproxy/test_flow_export/locust_task_post.py new file mode 100644 index 00000000..989df455 --- /dev/null +++ b/test/mitmproxy/test_flow_export/locust_task_post.py @@ -0,0 +1,11 @@ + @task() + def path(self): + url = self.locust.host + '/path' + + data = '''content''' + + self.response = self.client.request( + method='POST', + url=url, + data=data, + ) diff --git a/test/mitmproxy/test_flow_export/python_get.py b/test/mitmproxy/test_flow_export/python_get.py new file mode 100644 index 00000000..ee3f48eb --- /dev/null +++ b/test/mitmproxy/test_flow_export/python_get.py @@ -0,0 +1,16 @@ +import requests + +url = 'http://address/path' + +headers = { + 'header': 'qvalue', + 'content-length': '7', +} + +response = requests.request( + method='GET', + url=url, + headers=headers, +) + +print(response.text) diff --git a/test/mitmproxy/test_flow_export/python_patch.py b/test/mitmproxy/test_flow_export/python_patch.py new file mode 100644 index 00000000..159e802f --- /dev/null +++ b/test/mitmproxy/test_flow_export/python_patch.py @@ -0,0 +1,24 @@ +import requests + +url = 'http://address/path' + +headers = { + 'header': 'qvalue', + 'content-length': '7', +} + +params = { + 'query': 'param', +} + +data = '''content''' + +response = requests.request( + method='PATCH', + url=url, + headers=headers, + params=params, + data=data, +) + +print(response.text) diff --git a/test/mitmproxy/test_flow_export/python_post.py b/test/mitmproxy/test_flow_export/python_post.py new file mode 100644 index 00000000..b13f6441 --- /dev/null +++ b/test/mitmproxy/test_flow_export/python_post.py @@ -0,0 +1,13 @@ +import requests + +url = 'http://address/path' + +data = '''content''' + +response = requests.request( + method='POST', + url=url, + data=data, +) + +print(response.text) diff --git a/test/mitmproxy/test_flow_export/python_post_json.py b/test/mitmproxy/test_flow_export/python_post_json.py new file mode 100644 index 00000000..7e105bf6 --- /dev/null +++ b/test/mitmproxy/test_flow_export/python_post_json.py @@ -0,0 +1,21 @@ +import requests + +url = 'http://address/path' + +headers = { + 'content-type': 'application/json', +} + +json = { + "name": "example", + "email": "example@example.com" +} + +response = requests.request( + method='POST', + url=url, + headers=headers, + json=json, +) + +print(response.text) diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py index 1da140d8..c3950975 100644 --- a/test/mitmproxy/test_protocol_http2.py +++ b/test/mitmproxy/test_protocol_http2.py @@ -1,3 +1,5 @@ +# coding=utf-8 + from __future__ import (absolute_import, print_function, division) import OpenSSL @@ -36,7 +38,7 @@ class _Http2ServerBase(netlib_tservers.ServerTestBase): class handler(netlib.tcp.BaseHandler): def handle(self): - h2_conn = h2.connection.H2Connection(client_side=False) + h2_conn = h2.connection.H2Connection(client_side=False, header_encoding=False) preamble = self.rfile.read(24) h2_conn.initiate_connection() @@ -122,7 +124,7 @@ class _Http2TestBase(object): client.convert_to_ssl(alpn_protos=[b'h2']) - h2_conn = h2.connection.H2Connection(client_side=True) + h2_conn = h2.connection.H2Connection(client_side=True, header_encoding=False) h2_conn.initiate_connection() client.wfile.write(h2_conn.data_to_send()) client.wfile.flush() @@ -160,15 +162,19 @@ class TestSimple(_Http2TestBase, _Http2ServerBase): if isinstance(event, h2.events.ConnectionTerminated): return False elif isinstance(event, h2.events.RequestReceived): - h2_conn.send_headers(1, [ + assert ('client-foo', 'client-bar-1') in event.headers + assert ('client-foo', 'client-bar-2') in event.headers + + h2_conn.send_headers(event.stream_id, [ (':status', '200'), - ('foo', 'bar'), + ('server-foo', 'server-bar'), + ('föo', 'bär'), + ('X-Stream-ID', str(event.stream_id)), ]) - h2_conn.send_data(1, b'foobar') - h2_conn.end_stream(1) + h2_conn.send_data(event.stream_id, b'foobar') + h2_conn.end_stream(event.stream_id) wfile.write(h2_conn.data_to_send()) wfile.flush() - return True def test_simple(self): @@ -179,6 +185,8 @@ class TestSimple(_Http2TestBase, _Http2ServerBase): (':method', 'GET'), (':scheme', 'https'), (':path', '/'), + ('ClIeNt-FoO', 'client-bar-1'), + ('ClIeNt-FoO', 'client-bar-2'), ], body='my request body echoed back to me') done = False @@ -200,7 +208,8 @@ class TestSimple(_Http2TestBase, _Http2ServerBase): assert len(self.master.state.flows) == 1 assert self.master.state.flows[0].response.status_code == 200 - assert self.master.state.flows[0].response.headers['foo'] == 'bar' + assert self.master.state.flows[0].response.headers['server-foo'] == 'server-bar' + assert self.master.state.flows[0].response.headers['föo'] == 'bär' assert self.master.state.flows[0].response.body == b'foobar' @@ -425,3 +434,51 @@ class TestPushPromise(_Http2TestBase, _Http2ServerBase): assert len(bodies) >= 1 assert b'regular_stream' in bodies # the other two bodies might not be transmitted before the reset + +@requires_alpn +class TestConnectionLost(_Http2TestBase, _Http2ServerBase): + + @classmethod + def setup_class(self): + _Http2TestBase.setup_class() + _Http2ServerBase.setup_class() + + @classmethod + def teardown_class(self): + _Http2TestBase.teardown_class() + _Http2ServerBase.teardown_class() + + @classmethod + def handle_server_event(self, event, h2_conn, rfile, wfile): + if isinstance(event, h2.events.RequestReceived): + h2_conn.send_headers(1, [(':status', '200')]) + wfile.write(h2_conn.data_to_send()) + wfile.flush() + return False + + def test_connection_lost(self): + client, h2_conn = self._setup_connection() + + self._send_request(client.wfile, h2_conn, stream_id=1, headers=[ + (':authority', "127.0.0.1:%s" % self.server.server.address.port), + (':method', 'GET'), + (':scheme', 'https'), + (':path', '/'), + ('foo', 'bar') + ]) + + done = False + ended_streams = 0 + pushed_streams = 0 + responses = 0 + while not done: + try: + raw = b''.join(http2_read_raw_frame(client.rfile)) + events = h2_conn.receive_data(raw) + except: + break + client.wfile.write(h2_conn.data_to_send()) + client.wfile.flush() + + if len(self.master.state.flows) == 1: + assert self.master.state.flows[0].response is None diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py index 8843ee62..454736d4 100644 --- a/test/mitmproxy/test_server.py +++ b/test/mitmproxy/test_server.py @@ -285,8 +285,7 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin, AppMixin): self.master.set_stream_large_bodies(None) def test_stream_modify(self): - self.master.load_script( - tutils.test_data.path("scripts/stream_modify.py")) + self.master.load_script(tutils.test_data.path("scripts/stream_modify.py")) d = self.pathod('200:b"foo"') assert d.content == "bar" self.master.unload_scripts() @@ -511,8 +510,7 @@ class TestTransparent(tservers.TransparentProxyTest, CommonMixin, TcpMixin): ssl = False def test_tcp_stream_modify(self): - self.master.load_script( - tutils.test_data.path("scripts/tcp_stream_modify.py")) + self.master.load_script(tutils.test_data.path("scripts/tcp_stream_modify.py")) self._tcpproxy_on() d = self.pathod('200:b"foo"') diff --git a/test/mitmproxy/tutils.py b/test/mitmproxy/tutils.py index d51ac185..2dfd710e 100644 --- a/test/mitmproxy/tutils.py +++ b/test/mitmproxy/tutils.py @@ -8,6 +8,7 @@ from contextlib import contextmanager from unittest.case import SkipTest +import netlib.utils import netlib.tutils from mitmproxy import utils, controller from mitmproxy.models import ( @@ -163,4 +164,4 @@ def capture_stderr(command, *args, **kwargs): sys.stderr = out -test_data = utils.Data(__name__) +test_data = netlib.utils.Data(__name__) diff --git a/test/netlib/http/test_cookies.py b/test/netlib/http/test_cookies.py index 3b520a44..da28850f 100644 --- a/test/netlib/http/test_cookies.py +++ b/test/netlib/http/test_cookies.py @@ -228,7 +228,16 @@ def test_refresh_cookie(): c = "MOO=BAR; Expires=Tue, 08-Mar-2011 00:20:38 GMT; Path=foo.com; Secure" assert "00:21:38" in cookies.refresh_set_cookie_header(c, 60) + c = "foo,bar" + with raises(ValueError): + cookies.refresh_set_cookie_header(c, 60) + # https://github.com/mitmproxy/mitmproxy/issues/773 c = ">=A" - with raises(ValueError): - cookies.refresh_set_cookie_header(c, 60)
\ No newline at end of file + assert cookies.refresh_set_cookie_header(c, 60) + + # https://github.com/mitmproxy/mitmproxy/issues/1118 + c = "foo:bar=bla" + assert cookies.refresh_set_cookie_header(c, 0) + c = "foo/bar=bla" + assert cookies.refresh_set_cookie_header(c, 0) diff --git a/test/netlib/http/test_request.py b/test/netlib/http/test_request.py index 50ad2d05..7ed6bd0f 100644 --- a/test/netlib/http/test_request.py +++ b/test/netlib/http/test_request.py @@ -107,6 +107,14 @@ class TestRequestUtils(object): with raises(ValueError): request.url = "not-a-url" + def test_url_options(self): + request = treq(method=b"OPTIONS", path=b"*") + assert request.url == "http://address:22" + + def test_url_authority(self): + request = treq(first_line_format="authority") + assert request.url == "address:22" + def test_pretty_host(self): request = treq() # Without host header @@ -140,6 +148,10 @@ class TestRequestUtils(object): request.headers["host"] = "other" assert request.pretty_url == "http://address:22/path" + def test_pretty_url_options(self): + request = treq(method=b"OPTIONS", path=b"*") + assert request.pretty_url == "http://address:22" + def test_pretty_url_authority(self): request = treq(first_line_format="authority") assert request.pretty_url == "address:22" @@ -160,7 +172,7 @@ class TestRequestUtils(object): def test_get_cookies_none(self): request = treq() request.headers = Headers() - assert len(request.cookies) == 0 + assert not request.cookies def test_get_cookies_single(self): request = treq() diff --git a/test/netlib/http/test_response.py b/test/netlib/http/test_response.py index a0c44d90..5440176c 100644 --- a/test/netlib/http/test_response.py +++ b/test/netlib/http/test_response.py @@ -98,7 +98,7 @@ class TestResponseUtils(object): resp = tresp() v = resp.cookies v.add("foo", ["bar", ODictCaseless()]) - resp.set_cookies(v) + resp.cookies = v v = resp.cookies assert len(v) == 1 diff --git a/test/netlib/test_odict.py b/test/netlib/test_odict.py index f0985ef6..b6fd6401 100644 --- a/test/netlib/test_odict.py +++ b/test/netlib/test_odict.py @@ -27,16 +27,6 @@ class TestODict(object): b.set_state(state) assert b == od - def test_in_any(self): - od = odict.ODict() - od["one"] = ["atwoa", "athreea"] - assert od.in_any("one", "two") - assert od.in_any("one", "three") - assert not od.in_any("one", "four") - assert not od.in_any("nonexistent", "foo") - assert not od.in_any("one", "TWO") - assert od.in_any("one", "TWO", True) - def test_iter(self): od = odict.ODict() assert not [i for i in od] diff --git a/test/netlib/test_utils.py b/test/netlib/test_utils.py index be2a59fc..1d8f7b0f 100644 --- a/test/netlib/test_utils.py +++ b/test/netlib/test_utils.py @@ -1,3 +1,4 @@ +# coding=utf-8 from netlib import utils, tutils from netlib.http import Headers @@ -170,3 +171,17 @@ class TestSerializable: def test_safe_subn(): assert utils.safe_subn("foo", u"bar", "\xc2foo") + + +def test_bytes_to_escaped_str(): + assert utils.bytes_to_escaped_str(b"foo") == "foo" + assert utils.bytes_to_escaped_str(b"\b") == r"\x08" + assert utils.bytes_to_escaped_str(br"&!?=\)") == r"&!?=\\)" + assert utils.bytes_to_escaped_str(b'\xc3\xbc') == r"\xc3\xbc" + + +def test_escaped_str_to_bytes(): + assert utils.escaped_str_to_bytes("foo") == b"foo" + assert utils.escaped_str_to_bytes(r"\x08") == b"\b" + assert utils.escaped_str_to_bytes(r"&!?=\\)") == br"&!?=\)" + assert utils.escaped_str_to_bytes(r"ü") == b'\xc3\xbc' diff --git a/test/pathod/test_language_websocket.py b/test/pathod/test_language_websocket.py index f1105dfe..29155dba 100644 --- a/test/pathod/test_language_websocket.py +++ b/test/pathod/test_language_websocket.py @@ -97,7 +97,7 @@ class TestWebsocketFrame: assert self.fr("wf:r'foo'").payload == "foo" - def test_construction(self): + def test_construction_2(self): # Simple server frame frm = self.fr("wf:b'foo'") assert not frm.header.mask diff --git a/test/pathod/test_pathoc.py b/test/pathod/test_pathoc.py index 8d0f92ac..4e8c89c5 100644 --- a/test/pathod/test_pathoc.py +++ b/test/pathod/test_pathoc.py @@ -211,7 +211,7 @@ class TestDaemon(_TestDaemon): c.stop() @skip_windows - @pytest.mark.xfail + @pytest.mark.skip(reason="race condition") def test_wait_finish(self): c = pathoc.Pathoc( ("127.0.0.1", self.d.port), diff --git a/test/pathod/test_pathod.py b/test/pathod/test_pathod.py index 7583148b..05a3962e 100644 --- a/test/pathod/test_pathod.py +++ b/test/pathod/test_pathod.py @@ -129,7 +129,7 @@ class CommonTests(tutils.DaemonTests): l = self.d.last_log() # FIXME: Other binary data elements - @pytest.mark.xfail + @pytest.mark.skip(reason="race condition") def test_sizelimit(self): r = self.get("200:b@1g") assert r.status_code == 800 @@ -143,7 +143,7 @@ class CommonTests(tutils.DaemonTests): def test_info(self): assert tuple(self.d.info()["version"]) == version.IVERSION - @pytest.mark.xfail + @pytest.mark.skip(reason="race condition") def test_logs(self): assert self.d.clear_log() assert not self.d.last_log() @@ -223,7 +223,7 @@ class CommonTests(tutils.DaemonTests): ) assert r[1].payload == "test" - @pytest.mark.xfail + @pytest.mark.skip(reason="race condition") def test_websocket_frame_reflect_error(self): r, _ = self.pathoc( ["ws:/p/", "wf:-mask:knone:f'wf:b@10':i13,'a'"], @@ -233,6 +233,7 @@ class CommonTests(tutils.DaemonTests): # FIXME: Race Condition? assert "Parse error" in self.d.text_log() + @pytest.mark.skip(reason="race condition") def test_websocket_frame_disconnect_error(self): self.pathoc(["ws:/p/", "wf:b@10:d3"], ws_read_limit=0) assert self.d.last_log() diff --git a/test/pathod/tutils.py b/test/pathod/tutils.py index 9739afde..f6ed3efb 100644 --- a/test/pathod/tutils.py +++ b/test/pathod/tutils.py @@ -116,7 +116,7 @@ tmpdir = netlib.tutils.tmpdir raises = netlib.tutils.raises -test_data = utils.Data(__name__) +test_data = netlib.utils.Data(__name__) def render(r, settings=language.Settings()): |