- scripts/mitmproxy-to-har.py: Конвертер mitm → HAR - MITMPROXY.md: Инструкция по записи и конвертации - Два способа: mitmweb (GUI) и mitmdump + скрипт
98 lines
3.7 KiB
Python
98 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Convert mitmproxy flow dump to HAR format
|
|
Usage: mitmproxy-to-har.py <input.mitm> <output.har>
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
from datetime import datetime
|
|
from mitmproxy import io
|
|
from mitmproxy.http import HTTPFlow
|
|
|
|
|
|
def flow_to_har_entry(flow: HTTPFlow) -> dict:
|
|
"""Convert single flow to HAR entry."""
|
|
if not flow.request or not flow.response:
|
|
return None
|
|
|
|
entry = {
|
|
"startedDateTime": datetime.fromtimestamp(flow.request.timestamp_start).isoformat() + "Z",
|
|
"time": int((flow.response.timestamp_end - flow.request.timestamp_start) * 1000) if flow.response.timestamp_end else 0,
|
|
"request": {
|
|
"method": flow.request.method,
|
|
"url": flow.request.url,
|
|
"httpVersion": flow.request.http_version,
|
|
"headers": [{"name": k, "value": v} for k, v in flow.request.headers.items()],
|
|
"queryString": [{"name": k, "value": v} for k, v in flow.request.query.items()],
|
|
"cookies": [{"name": k, "value": v} for k, v in flow.request.cookies.items()],
|
|
"headersSize": -1,
|
|
"bodySize": len(flow.request.content) if flow.request.content else 0,
|
|
},
|
|
"response": {
|
|
"status": flow.response.status_code,
|
|
"statusText": flow.response.reason,
|
|
"httpVersion": flow.response.http_version,
|
|
"headers": [{"name": k, "value": v} for k, v in flow.response.headers.items()],
|
|
"cookies": [{"name": k, "value": v} for k, v in flow.response.cookies.items()],
|
|
"content": {
|
|
"size": len(flow.response.content) if flow.response.content else 0,
|
|
"mimeType": flow.response.headers.get("Content-Type", "unknown").split(";")[0],
|
|
"text": flow.response.get_text() if flow.response.content else ""
|
|
},
|
|
"redirectURL": flow.response.headers.get("Location", ""),
|
|
"headersSize": -1,
|
|
"bodySize": len(flow.response.content) if flow.response.content else 0,
|
|
},
|
|
"cache": {},
|
|
"timings": {
|
|
"send": 0,
|
|
"wait": int((flow.response.timestamp_start - flow.request.timestamp_end) * 1000) if flow.response.timestamp_start and flow.request.timestamp_end else 0,
|
|
"receive": int((flow.response.timestamp_end - flow.response.timestamp_start) * 1000) if flow.response.timestamp_end and flow.response.timestamp_start else 0,
|
|
}
|
|
}
|
|
|
|
# Add POST data if present
|
|
if flow.request.method == "POST" and flow.request.content:
|
|
entry["request"]["postData"] = {
|
|
"mimeType": flow.request.headers.get("Content-Type", "application/octet-stream"),
|
|
"text": flow.request.get_text() if flow.request.content else ""
|
|
}
|
|
|
|
return entry
|
|
|
|
|
|
def convert_mitm_to_har(input_file: str, output_file: str):
|
|
"""Convert mitmproxy dump to HAR."""
|
|
har = {
|
|
"log": {
|
|
"version": "1.2",
|
|
"creator": {
|
|
"name": "mitmproxy-to-har",
|
|
"version": "1.0"
|
|
},
|
|
"entries": []
|
|
}
|
|
}
|
|
|
|
with open(input_file, 'rb') as f:
|
|
reader = io.FlowReader(f)
|
|
for flow in reader.read():
|
|
if isinstance(flow, HTTPFlow):
|
|
entry = flow_to_har_entry(flow)
|
|
if entry:
|
|
har["log"]["entries"].append(entry)
|
|
|
|
with open(output_file, 'w', encoding='utf-8') as f:
|
|
json.dump(har, f, indent=2, ensure_ascii=False)
|
|
|
|
print(f"Converted {len(har['log']['entries'])} flows to {output_file}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) != 3:
|
|
print("Usage: mitmproxy-to-har.py <input.mitm> <output.har>")
|
|
sys.exit(1)
|
|
|
|
convert_mitm_to_har(sys.argv[1], sys.argv[2])
|