mirror of
https://github.com/usestrix/strix.git
synced 2026-08-18 17:52:32 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
511397eb90 | ||
|
|
5bfe6604d4 |
@@ -167,6 +167,9 @@ async def get_request_with_client(
|
|||||||
return await client.request.get(request_id, opts)
|
return await client.request.get(request_id, opts)
|
||||||
|
|
||||||
|
|
||||||
|
_FRAMING_HEADERS = frozenset({"content-length", "transfer-encoding"})
|
||||||
|
|
||||||
|
|
||||||
def build_raw_request(
|
def build_raw_request(
|
||||||
*,
|
*,
|
||||||
method: str,
|
method: str,
|
||||||
@@ -187,11 +190,15 @@ def build_raw_request(
|
|||||||
final_headers = {**headers}
|
final_headers = {**headers}
|
||||||
final_headers.setdefault("Host", parsed.netloc)
|
final_headers.setdefault("Host", parsed.netloc)
|
||||||
final_headers.setdefault("User-Agent", "strix")
|
final_headers.setdefault("User-Agent", "strix")
|
||||||
# A Content-Length inherited from the captured request describes the ORIGINAL
|
# Framing headers inherited from the captured request describe the ORIGINAL
|
||||||
# body; once the body is modified for replay it is stale. Drop any inherited
|
# body; once the body is modified for replay they are stale. We always send a
|
||||||
# value (case-insensitively) and recompute it from the body actually being
|
# plain (non-chunked) body with an explicit Content-Length, so drop any
|
||||||
# sent, so the replayed request is never desynced (truncated / smuggled).
|
# inherited Content-Length AND Transfer-Encoding (case-insensitively) and
|
||||||
final_headers = {k: v for k, v in final_headers.items() if k.title() != "Content-Length"}
|
# recompute the length from the body actually being sent. This keeps the two
|
||||||
|
# framing mechanisms from conflicting (RFC 7230 3.3.3: a leftover
|
||||||
|
# Transfer-Encoding would make the target ignore Content-Length and try to
|
||||||
|
# parse the body as chunked), so the replay is never desynced.
|
||||||
|
final_headers = {k: v for k, v in final_headers.items() if k.lower() not in _FRAMING_HEADERS}
|
||||||
if body:
|
if body:
|
||||||
final_headers["Content-Length"] = str(len(body.encode("utf-8")))
|
final_headers["Content-Length"] = str(len(body.encode("utf-8")))
|
||||||
|
|
||||||
|
|||||||
@@ -166,6 +166,22 @@ def test_build_raw_request_recomputes_content_length_for_modified_body() -> None
|
|||||||
assert _headers_named(raw, "Content-Length") == [str(len(body.encode("utf-8")))]
|
assert _headers_named(raw, "Content-Length") == [str(len(body.encode("utf-8")))]
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_raw_request_drops_transfer_encoding_for_modified_body() -> None:
|
||||||
|
body = '{"user":"updated"}'
|
||||||
|
_conn, raw = caido_api.build_raw_request(
|
||||||
|
method="POST",
|
||||||
|
url="https://example.com/login",
|
||||||
|
headers={
|
||||||
|
"tRaNsFeR-EnCoDiNg": "chunked",
|
||||||
|
"Content-Length": "7",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body=body,
|
||||||
|
)
|
||||||
|
assert _headers_named(raw, "Transfer-Encoding") == []
|
||||||
|
assert _headers_named(raw, "Content-Length") == [str(len(body.encode("utf-8")))]
|
||||||
|
|
||||||
|
|
||||||
def test_build_raw_request_drops_stale_content_length_for_empty_body() -> None:
|
def test_build_raw_request_drops_stale_content_length_for_empty_body() -> None:
|
||||||
# A body cleared to empty must not keep the inherited (non-zero) length.
|
# A body cleared to empty must not keep the inherited (non-zero) length.
|
||||||
_conn, raw = caido_api.build_raw_request(
|
_conn, raw = caido_api.build_raw_request(
|
||||||
|
|||||||
Reference in New Issue
Block a user