• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cle-b / httpdbg / 18805071004

25 Oct 2025 03:35PM UTC coverage: 87.781%. First build
18805071004

Pull #209

github

cle-b
format
Pull Request #209: export to single html file

76 of 111 new or added lines in 5 files covered. (68.47%)

2378 of 2709 relevant lines covered (87.78%)

0.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.85
/httpdbg/export.py
1
import base64
1✔
2
import json
1✔
3
from pathlib import Path
1✔
4
import re
1✔
5
import xml.etree.ElementTree as ET
1✔
6

7
import httpdbg
1✔
8
from httpdbg import HTTPRecords
1✔
9
from httpdbg.webapp.api import RequestListPayload, RequestPayload
1✔
10

11

12
def generate_html(records: HTTPRecords, for_export: bool = True) -> str:
1✔
13

14
    current_dir = Path(__file__).resolve().parent
1✔
15

16
    with open(Path(current_dir) / "webapp/static/index.htm") as findexhtml:
1✔
17
        html = findexhtml.read()
1✔
18

19
    html = html.replace("$**HTTPDBG_VERSION**$", httpdbg.__version__)
1✔
20

21
    # favicon
22
    with open(current_dir / "webapp/static/favicon.ico", "rb") as ffavicon:
1✔
23
        b64_icon = base64.b64encode(ffavicon.read()).decode("utf-8")
1✔
24
        data_uri = f"data:image/x-icon;base64,{b64_icon}"
1✔
25
        html = html.replace(
1✔
26
            '<link rel="shortcut icon" href="static/favicon.ico">',
27
            f'<link rel="icon" type="image/x-icon" href="{data_uri}">',
28
        )
29

30
    # icons
31
    def svg_file_to_symbol(svg_path: Path, symbol_id: str) -> str:
1✔
32
        ET.register_namespace("", "http://www.w3.org/2000/svg")
1✔
33
        root = ET.parse(svg_path).getroot()
1✔
34
        symbol = ET.Element(
1✔
35
            "symbol", {"id": symbol_id, "viewBox": root.attrib["viewBox"]}
36
        )
37
        for child in list(root):
1✔
38
            symbol.append(child)
1✔
39
        return ET.tostring(symbol, encoding="unicode")
1✔
40

41
    icons_inline = ""
1✔
42
    for icon_path in (current_dir / "webapp/static/icons").glob("*.svg"):
1✔
43
        icons_inline += "\n        " + svg_file_to_symbol(
1✔
44
            icon_path, icon_path.name[:-4]
45
        )
46
    icons_inline = f'<svg width="0" height="0" style="position:absolute;visibility:hidden" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">{icons_inline}\n    </svg>'
1✔
47
    html = html.replace("$**PRELOAD_ICONS**$", icons_inline)
1✔
48

49
    # css
50
    stylesheet_pattern = (
1✔
51
        r'<link\s+[^>]*rel=["\']stylesheet["\'][^>]*href=["\']([^"\']+)["\']'
52
    )
53
    for stylesheet in re.findall(stylesheet_pattern, html):
1✔
54
        with open(Path(current_dir) / "webapp" / stylesheet) as fcss:
1✔
55
            html = html.replace(
1✔
56
                f'<link rel="stylesheet" href="{stylesheet}">',
57
                f"<style>{fcss.read()}</style>",
58
            )
59

60
    # js
61
    javascript_pattern = r'<script\s+[^>]*src=["\']([^"\']+)["\']'
1✔
62
    for js in re.findall(javascript_pattern, html):
1✔
63
        with open(Path(current_dir) / "webapp" / js) as fjs:
1✔
64
            html = html.replace(
1✔
65
                f'<script src="{js}"></script>', f"<script>{fjs.read()}</script>"
66
            )
67

68
    # static export of the requests data
69
    if for_export:
1✔
NEW
70
        static_all_requests = json.dumps(
×
71
            records, cls=RequestListPayload, ensure_ascii=False
72
        )
NEW
73
        map_requests: dict[str, object] = dict()
×
NEW
74
        for record in records:
×
NEW
75
            map_requests[record.id] = json.loads(json.dumps(record, cls=RequestPayload))
×
NEW
76
        static_requests: str = json.dumps(map_requests, ensure_ascii=False)
×
77

NEW
78
        def safe_for_script_tag(s: str) -> str:
×
NEW
79
            return s.replace("</script>", "<\\/script>")
×
80

NEW
81
        html_export = f"""
×
82
    <script id="all-requests" type="application/json">
83
        {safe_for_script_tag(static_all_requests)}
84
    </script>
85

86
    <script id="requests-map" type="application/json">
87
        {safe_for_script_tag(static_requests)}
88
    </script>
89

90
    <script>
91
    global.static_all_requests = JSON.parse(
92
        document.getElementById('all-requests').textContent
93
    );
94
    global.static_requests = JSON.parse(
95
        document.getElementById('requests-map').textContent
96
    );
97
    </script>
98
"""
99

NEW
100
        html = html.replace("$**EXPORT**$", html_export)
×
101
    else:
102
        html = html.replace("$**EXPORT**$", "")
1✔
103

104
    return html
1✔
105

106

107
def export_html(records: HTTPRecords, filename: Path):
1✔
NEW
108
    with open(filename, "w") as f:
×
NEW
109
        f.write(generate_html(records))
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc