Skip to content

Commit 5524ecc

Browse files
authored
Merge pull request #11 from sleeyax/fix/header-ordering
fix: store headers as ordered pairs to preserve header ordering
2 parents 2378179 + 48a663b commit 5524ecc

1 file changed

Lines changed: 36 additions & 10 deletions

File tree

src/mitmproxy_mcp/core/recorder.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@
1414
from .utils import get_safe_text
1515

1616

17+
def _parse_headers(raw: str) -> Dict[str, str]:
18+
"""Parse stored headers into a dict for backward compat.
19+
20+
Headers are stored as either:
21+
- list of [key, value] pairs (new format, preserves order)
22+
- dict (legacy format)
23+
Returns a dict in both cases. Duplicate keys are collapsed (last wins).
24+
"""
25+
parsed = json.loads(raw)
26+
if isinstance(parsed, list):
27+
return {k: v for k, v in parsed}
28+
return parsed
29+
30+
1731
class SimpleRequest:
1832
def __init__(self, method: str, url: str, headers: Dict[str, str], body: Optional[str]):
1933
self.method = method
@@ -96,9 +110,21 @@ def save_flow(self, flow: http.HTTPFlow):
96110
flow.request.url,
97111
flow.request.method,
98112
status_code,
99-
json.dumps(dict(flow.request.headers)),
113+
json.dumps(
114+
[
115+
[k.decode("latin-1"), v.decode("latin-1")]
116+
for k, v in flow.request.headers.fields
117+
],
118+
),
100119
req_body,
101-
json.dumps(dict(flow.response.headers)) if flow.response else None,
120+
json.dumps(
121+
[
122+
[k.decode("latin-1"), v.decode("latin-1")]
123+
for k, v in flow.response.headers.fields
124+
],
125+
)
126+
if flow.response
127+
else None,
102128
resp_body,
103129
flow.request.timestamp_start,
104130
size,
@@ -128,7 +154,7 @@ def get_summary(
128154
for row in rows:
129155
content_type = "unknown"
130156
if row["response_headers"]:
131-
headers = json.loads(row["response_headers"])
157+
headers = _parse_headers(row["response_headers"])
132158
content_type = headers.get(
133159
"content-type",
134160
headers.get("Content-Type", "unknown"),
@@ -156,8 +182,8 @@ def get_detail(self, flow_id: str) -> Optional[Dict[str, Any]]:
156182
if not row:
157183
return None
158184

159-
req_headers = json.loads(row["request_headers"])
160-
resp_headers = json.loads(row["response_headers"]) if row["response_headers"] else None
185+
req_headers = _parse_headers(row["request_headers"])
186+
resp_headers = _parse_headers(row["response_headers"]) if row["response_headers"] else None
161187

162188
simple_request = SimpleRequest(
163189
method=row["method"],
@@ -237,12 +263,12 @@ def get_all_for_analysis(self, limit: int = 1000) -> List[Dict[str, Any]]:
237263
"request": {
238264
"url": row["url"],
239265
"method": row["method"],
240-
"headers": json.loads(row["request_headers"]),
266+
"headers": _parse_headers(row["request_headers"]),
241267
"body": row["request_body"],
242268
},
243269
"response": {
244270
"status_code": row["status_code"],
245-
"headers": json.loads(row["response_headers"])
271+
"headers": _parse_headers(row["response_headers"])
246272
if row["response_headers"]
247273
else {},
248274
"body": row["response_body"],
@@ -272,12 +298,12 @@ def get_by_ids(self, flow_ids: List[str]) -> List[Dict[str, Any]]:
272298
"request": {
273299
"url": row["url"],
274300
"method": row["method"],
275-
"headers": json.loads(row["request_headers"]),
301+
"headers": _parse_headers(row["request_headers"]),
276302
"body": row["request_body"],
277303
},
278304
"response": {
279305
"status_code": row["status_code"],
280-
"headers": json.loads(row["response_headers"])
306+
"headers": _parse_headers(row["response_headers"])
281307
if row["response_headers"]
282308
else {},
283309
"body": row["response_body"],
@@ -376,7 +402,7 @@ def get_flow_object(self, flow_id: str) -> Optional[SimpleRequest]:
376402
if not row:
377403
return None
378404

379-
headers = json.loads(row["request_headers"])
405+
headers = _parse_headers(row["request_headers"])
380406
return SimpleRequest(
381407
method=row["method"],
382408
url=row["url"],

0 commit comments

Comments
 (0)