From c10ff719f7af759a5ff9c4659c514923f4ab3137 Mon Sep 17 00:00:00 2001 From: lukant Date: Thu, 31 Oct 2024 23:08:17 +0100 Subject: [PATCH] Fix interaction of modifyheaders addon with stream_large_bodies option (#7286) * Fix interaction of modifyheaders addon with stream_large_bodies option `modifyheaders` addon uses `request` and `response` hooks which, when `stream_large_bodies` is enabled, are called after headers have already been sent and can no longer be modified. This commit changes `modifyheaders` addon to use `requestheaders` and `responseheaders` hooks. * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- CHANGELOG.md | 4 ++++ mitmproxy/addons/modifyheaders.py | 4 ++-- test/mitmproxy/addons/test_modifyheaders.py | 26 ++++++++++----------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 978ac5b46..422def74d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ ([#7241](https://github.com/mitmproxy/mitmproxy/pull/7241), @mhils) - `browser.start` command now supports Firefox. ([#7239](https://github.com/mitmproxy/mitmproxy/pull/7239), @sujaldev) +- Fix interaction of the `modify_headers` and `stream_large_bodies` options. + This may break users of `modify_headers` that rely on filters referencing the message body. + We expect this to be uncommon, but please make yourself heard if that's not the case. + ([#7286](https://github.com/mitmproxy/mitmproxy/pull/7286), @lukant) ## 02 October 2024: mitmproxy 11.0.0 diff --git a/mitmproxy/addons/modifyheaders.py b/mitmproxy/addons/modifyheaders.py index a7e45b0dd..503ba2282 100644 --- a/mitmproxy/addons/modifyheaders.py +++ b/mitmproxy/addons/modifyheaders.py @@ -81,12 +81,12 @@ class ModifyHeaders: ) from e self.replacements.append(spec) - def request(self, flow): + def requestheaders(self, flow): if flow.response or flow.error or not flow.live: return self.run(flow, flow.request.headers) - def response(self, flow): + def responseheaders(self, flow): if flow.error or not flow.live: return self.run(flow, flow.response.headers) diff --git a/test/mitmproxy/addons/test_modifyheaders.py b/test/mitmproxy/addons/test_modifyheaders.py index 83a46256f..d5bf8936b 100644 --- a/test/mitmproxy/addons/test_modifyheaders.py +++ b/test/mitmproxy/addons/test_modifyheaders.py @@ -41,48 +41,48 @@ class TestModifyHeaders: tctx.configure(mh, modify_headers=["/~q/one/two", "/~s/one/three"]) f = tflow.tflow() f.request.headers["one"] = "xxx" - mh.request(f) + mh.requestheaders(f) assert f.request.headers["one"] == "two" f = tflow.tflow(resp=True) f.response.headers["one"] = "xxx" - mh.response(f) + mh.responseheaders(f) assert f.response.headers["one"] == "three" tctx.configure(mh, modify_headers=["/~s/one/two", "/~s/one/three"]) f = tflow.tflow(resp=True) f.request.headers["one"] = "xxx" f.response.headers["one"] = "xxx" - mh.response(f) + mh.responseheaders(f) assert f.response.headers.get_all("one") == ["two", "three"] tctx.configure(mh, modify_headers=["/~q/one/two", "/~q/one/three"]) f = tflow.tflow() f.request.headers["one"] = "xxx" - mh.request(f) + mh.requestheaders(f) assert f.request.headers.get_all("one") == ["two", "three"] # test removal of existing headers tctx.configure(mh, modify_headers=["/~q/one/", "/~s/one/"]) f = tflow.tflow() f.request.headers["one"] = "xxx" - mh.request(f) + mh.requestheaders(f) assert "one" not in f.request.headers f = tflow.tflow(resp=True) f.response.headers["one"] = "xxx" - mh.response(f) + mh.responseheaders(f) assert "one" not in f.response.headers tctx.configure(mh, modify_headers=["/one/"]) f = tflow.tflow() f.request.headers["one"] = "xxx" - mh.request(f) + mh.requestheaders(f) assert "one" not in f.request.headers f = tflow.tflow(resp=True) f.response.headers["one"] = "xxx" - mh.response(f) + mh.responseheaders(f) assert "one" not in f.response.headers # test modifying a header that is also part of the filter expression @@ -95,7 +95,7 @@ class TestModifyHeaders: ) f = tflow.tflow() f.request.headers["user-agent"] = "Hello, it's me, Mozilla" - mh.request(f) + mh.requestheaders(f) assert "Definitely not Mozilla ;)" == f.request.headers["user-agent"] @pytest.mark.parametrize("take", [True, False]) @@ -106,13 +106,13 @@ class TestModifyHeaders: f = tflow.tflow() if take: f.response = tresp() - mh.request(f) + mh.requestheaders(f) assert (f.request.headers["content-length"] == "42") ^ take f = tflow.tflow(resp=True) if take: f.kill() - mh.response(f) + mh.responseheaders(f) assert (f.response.headers["content-length"] == "42") ^ take @@ -125,7 +125,7 @@ class TestModifyHeadersFile: tctx.configure(mh, modify_headers=["/~q/one/@" + str(tmpfile)]) f = tflow.tflow() f.request.headers["one"] = "xxx" - mh.request(f) + mh.requestheaders(f) assert f.request.headers["one"] == "two" async def test_nonexistent(self, tmpdir, caplog): @@ -142,5 +142,5 @@ class TestModifyHeadersFile: tmpfile.remove() f = tflow.tflow() f.request.content = b"foo" - mh.request(f) + mh.requestheaders(f) assert "Could not read" in caplog.text