Add option to return various status codes rather than killing during server replay (#6465)

#### Description

Designed to satisfy the requirements of
https://github.com/mitmproxy/mitmproxy/issues/3489

Add `server_replay_404_extra` which behaves similarly to the kill flag,
but returns 404 responses rather than killing

#### Checklist

 - [x] I have updated tests where applicable.
 - [x] I have added an entry to the CHANGELOG.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Daniel Karandikar 2023-11-08 10:12:44 +00:00 committed by GitHub
parent 0c91733df8
commit 746537e051
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 75 additions and 3 deletions

View file

@ -8,6 +8,9 @@
* Update savehar addon to handle scenarios where "path" key in cookie
attrs dict is missing.
([#6458](https://github.com/mitmproxy/mitmproxy/pull/6458), @pogzyb)
* Add `server_replay_extra` option to serverplayback to define behaviour
when replayable response is missing.
([#6465](https://github.com/mitmproxy/mitmproxy/pull/6465), @dkarandikar)
## 04 November 2023: mitmproxy 10.1.3

View file

@ -30,7 +30,16 @@ class ServerPlayback:
"server_replay_kill_extra",
bool,
False,
"Kill extra requests during replay (for which no replayable response was found).",
"Kill extra requests during replay (for which no replayable response was found)."
"[Deprecated, prefer to use server_replay_extra='kill']",
)
loader.add_option(
"server_replay_extra",
str,
"forward",
"Behaviour for extra requests during replay for which no replayable response was found. "
"Setting a numeric string value will return an empty HTTP response with the respective status code.",
choices=["forward", "kill", "204", "400", "404", "500"],
)
loader.add_option(
"server_replay_reuse",
@ -230,6 +239,11 @@ class ServerPlayback:
return None
def configure(self, updated):
if ctx.options.server_replay_kill_extra:
logger.warning(
"server_replay_kill_extra has been deprecated, "
"please update your config to use server_replay_extra='kill'."
)
if ctx.options.server_replay_nopop: # pragma: no cover
logger.error(
"server_replay_nopop has been renamed to server_replay_reuse, please update your config."
@ -252,10 +266,21 @@ class ServerPlayback:
response.refresh()
f.response = response
f.is_replay = "response"
elif ctx.options.server_replay_kill_extra:
elif (
ctx.options.server_replay_kill_extra
or ctx.options.server_replay_extra == "kill"
):
logging.warning(
"server_playback: killed non-replay request {}".format(
f.request.url
)
)
f.kill()
elif ctx.options.server_replay_extra != "forward":
logging.warning(
"server_playback: returned {} non-replay request {}".format(
ctx.options.server_replay_extra, f.request.url
)
)
f.response = http.Response.make(int(ctx.options.server_replay_extra))
f.is_replay = "response"

View file

@ -83,6 +83,7 @@ def common_options(parser, opts):
group = parser.add_argument_group("Server Replay")
opts.make_parser(group, "server_replay", metavar="PATH", short="S")
opts.make_parser(group, "server_replay_kill_extra")
opts.make_parser(group, "server_replay_extra")
opts.make_parser(group, "server_replay_reuse")
opts.make_parser(group, "server_replay_refresh")

View file

@ -280,6 +280,8 @@ class StatusBar(urwid.WidgetWrap):
opts.append("norefresh")
if self.master.options.server_replay_kill_extra:
opts.append("killextra")
if self.master.options.server_replay_extra:
opts.append("replay-extra")
if not self.master.options.upstream_cert:
opts.append("no-upstream-cert")
if self.master.options.console_focus_follow:

View file

@ -364,6 +364,45 @@ async def test_server_playback_kill():
assert f.error
async def test_server_playback_kill_new_option():
s = serverplayback.ServerPlayback()
with taddons.context(s) as tctx:
tctx.configure(s, server_replay_refresh=True, server_replay_extra="kill")
f = tflow.tflow()
f.response = mitmproxy.test.tutils.tresp(content=f.request.content)
s.load_flows([f])
f = tflow.tflow()
f.request.host = "nonexistent"
await tctx.cycle(s, f)
assert f.error
@pytest.mark.parametrize(
"option,status",
[
("204", 204),
("400", 400),
("404", 404),
("500", 500),
],
)
async def test_server_playback_404(option, status):
s = serverplayback.ServerPlayback()
with taddons.context(s) as tctx:
tctx.configure(s, server_replay_refresh=True, server_replay_extra=option)
f = tflow.tflow()
f.response = mitmproxy.test.tutils.tresp(content=f.request.content)
s.load_flows([f])
f = tflow.tflow()
f.request.host = "nonexistent"
s.request(f)
assert f.response.status_code == status
def test_server_playback_response_deleted():
"""
The server playback addon holds references to flows that can be modified by the user in the meantime.

View file

@ -18,7 +18,7 @@ async def test_statusbar(console, monkeypatch):
anticomp=True,
showhost=True,
server_replay_refresh=False,
server_replay_kill_extra=True,
server_replay_extra="kill",
upstream_cert=False,
stream_large_bodies="3m",
mode=["transparent"],

View file

@ -51,6 +51,7 @@ export interface OptionsState {
scripts: string[];
server: boolean;
server_replay: string[];
server_replay_extra: string;
server_replay_ignore_content: boolean;
server_replay_ignore_host: boolean;
server_replay_ignore_params: string[];
@ -146,6 +147,7 @@ export const defaultState: OptionsState = {
scripts: [],
server: true,
server_replay: [],
server_replay_extra: "forward",
server_replay_ignore_content: false,
server_replay_ignore_host: false,
server_replay_ignore_params: [],