Collect all flow filter matches before modifying headers, fixes #4245 (#4246)

This commit is contained in:
Alexander Prinzhorn 2021-02-09 19:37:46 +01:00 committed by GitHub
parent 2e3d481544
commit 4212a56f25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 8 deletions

View File

@ -53,6 +53,7 @@ If you depend on these features, please raise your voice in
mitmproxy never phones home, which means we don't know how prominently these options were used. (@mhils) mitmproxy never phones home, which means we don't know how prominently these options were used. (@mhils)
* Fix IDNA host 'Bad HTTP request line' error (@grahamrobbins) * Fix IDNA host 'Bad HTTP request line' error (@grahamrobbins)
* Pressing `?` now exits console help view (@abitrolly) * Pressing `?` now exits console help view (@abitrolly)
* `--modify-headers` now works correctly when modifying a header that is also part of the filter expression (@Prinzhorn)
* --- TODO: add new PRs above this line --- * --- TODO: add new PRs above this line ---
* ... and various other fixes, documentation improvements, dependency version bumps, etc. * ... and various other fixes, documentation improvements, dependency version bumps, etc.
@ -88,11 +89,11 @@ If you depend on these features, please raise your voice in
* Support for Python 3.9 (@mhils) * Support for Python 3.9 (@mhils)
* Add MsgPack content viewer (@tasn) * Add MsgPack content viewer (@tasn)
* Use `@charset` to decode CSS files if available (@prinzhorn) * Use `@charset` to decode CSS files if available (@Prinzhorn)
* Fix links to anticache docs in mitmweb and use HTTPS for links to documentation (@rugk) * Fix links to anticache docs in mitmweb and use HTTPS for links to documentation (@rugk)
* Updated typing for WebsocketMessage.content (@prinzhorn) * Updated typing for WebsocketMessage.content (@Prinzhorn)
* Add option `console_strip_trailing_newlines`, and no longer strip trailing newlines by default (@capt8bit) * Add option `console_strip_trailing_newlines`, and no longer strip trailing newlines by default (@capt8bit)
* Prevent transparent mode from connecting to itself in the basic cases (@prinzhorn) * Prevent transparent mode from connecting to itself in the basic cases (@Prinzhorn)
* Display HTTP trailers in mitmweb (@sanlengjingvv) * Display HTTP trailers in mitmweb (@sanlengjingvv)
* Revamp onboarding app (@mhils) * Revamp onboarding app (@mhils)
* Add ASGI support for embedded apps (@mhils) * Add ASGI support for embedded apps (@mhils)

View File

@ -83,14 +83,21 @@ class ModifyHeaders:
self.run(flow, flow.response.headers) self.run(flow, flow.response.headers)
def run(self, flow: http.HTTPFlow, hdrs: Headers) -> None: def run(self, flow: http.HTTPFlow, hdrs: Headers) -> None:
# unset all specified headers matches = []
# first check all the filters against the original, unmodified flow
for spec in self.replacements: for spec in self.replacements:
if spec.matches(flow): matches.append(spec.matches(flow))
# unset all specified headers
for i, spec in enumerate(self.replacements):
if matches[i]:
hdrs.pop(spec.subject, None) hdrs.pop(spec.subject, None)
# set all specified headers if the replacement string is not empty # set all specified headers if the replacement string is not empty
for spec in self.replacements:
if spec.matches(flow): for i, spec in enumerate(self.replacements):
if matches[i]:
try: try:
replacement = spec.read_replacement() replacement = spec.read_replacement()
except OSError as e: except OSError as e:

View File

@ -113,6 +113,19 @@ class TestModifyHeaders:
mh.response(f) mh.response(f)
assert "one" not in f.response.headers assert "one" not in f.response.headers
# test modifying a header that is also part of the filter expression
# https://github.com/mitmproxy/mitmproxy/issues/4245
tctx.configure(
mh,
modify_headers=[
"/~hq ^user-agent:.+Mozilla.+$/user-agent/Definitely not Mozilla ;)"
]
)
f = tflow.tflow()
f.request.headers["user-agent"] = "Hello, it's me, Mozilla"
mh.request(f)
assert "Definitely not Mozilla ;)" == f.request.headers["user-agent"]
@pytest.mark.parametrize("take", [True, False]) @pytest.mark.parametrize("take", [True, False])
def test_taken(self, take): def test_taken(self, take):
mh = ModifyHeaders() mh = ModifyHeaders()