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

cle-b / httpdbg / 18804750869

25 Oct 2025 03:06PM UTC coverage: 87.781%. First build
18804750869

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 svg_file_to_symbol(svg_path: Path, symbol_id: str) -> str:
1✔
13
    ET.register_namespace("", "http://www.w3.org/2000/svg")
1✔
14
    root = ET.parse(svg_path).getroot()
1✔
15
    symbol = ET.Element("symbol", {"id": symbol_id, "viewBox": root.attrib["viewBox"]})
1✔
16
    for child in list(root):
1✔
17
        symbol.append(child)
1✔
18
    return ET.tostring(symbol, encoding="unicode")
1✔
19

20

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

23
    current_dir = Path(__file__).resolve().parent
1✔
24

25
    with open(Path(current_dir) / "webapp/static/index.htm") as findexhtml:
1✔
26
        html = findexhtml.read()
1✔
27

28
    html = html.replace("$**HTTPDBG_VERSION**$", httpdbg.__version__)
1✔
29

30
    # favicon
31
    with open(current_dir / "webapp/static/favicon.ico", "rb") as ffavicon:
1✔
32
        b64_icon = base64.b64encode(ffavicon.read()).decode("utf-8")
1✔
33
        data_uri = f"data:image/x-icon;base64,{b64_icon}"
1✔
34

35
        html = html.replace(
1✔
36
            '<link rel="shortcut icon" href="static/favicon.ico">',
37
            f'<link rel="icon" type="image/x-icon" href="{data_uri}">',
38
        )
39

40
    # icons
41
    icons_inline = ""
1✔
42
    for icon_path in (current_dir / "webapp/static/icons").glob("*.svg"):
1✔
43

44
        icons_inline += "\n        " + svg_file_to_symbol(
1✔
45
            icon_path, icon_path.name[:-4]
46
        )
47

48
    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✔
49
    html = html.replace("$**PRELOAD_ICONS**$", icons_inline)
1✔
50

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

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

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

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

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

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

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

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

106
    return html
1✔
107

108

109
def export_html(records: HTTPRecords, filename: Path):
1✔
NEW
110
    with open(filename, "w") as f:
×
NEW
111
        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