Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2024-05-01 - [Python Regex Precompilation]
**Learning:** Python code in this application often performs repeated regex matches on incoming request headers or payload lines (e.g. `domain_fronter.py` content-range matching or cookie splitting).
**Action:** Extract inline `re.search` or `re.split` inside high-traffic loops into module-level variables like `RE_CONTENT_RANGE = re.compile(...)`. This yields measurable CPU and memory savings by skipping implicit dictionary lookups and potential cache evictions in the internal Python re cache.
18 changes: 12 additions & 6 deletions src/domain_fronter.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@

log = logging.getLogger("Fronter")

# Pre-compiled regexes for performance
RE_CONTENT_RANGE = re.compile(r"/(\d+)")
RE_JSON_EXTRACT = re.compile(r'\{.*\}', re.DOTALL)
RE_STATUS_CODE = re.compile(r"\d{3}")
RE_COOKIE_SPLIT = re.compile(r",\s*(?=[A-Za-z0-9!#$%&'*+\-.^_`|~]+=)")


class DomainFronter:
def __init__(self, config: dict):
Expand Down Expand Up @@ -590,7 +596,7 @@ async def relay_parallel(self, method: str, url: str,

# Parse total size from Content-Range: "bytes 0-262143/1048576"
content_range = resp_hdrs.get("content-range", "")
m = re.search(r"/(\d+)", content_range)
m = RE_CONTENT_RANGE.search(content_range)
if not m:
# Can't parse β€” downgrade to 200 so the client (which sent a
# plain GET) doesn't get confused by 206 + Content-Range.
Expand Down Expand Up @@ -1012,7 +1018,7 @@ def _parse_batch_body(self, resp_body: bytes,
try:
data = json.loads(text)
except json.JSONDecodeError:
m = re.search(r'\{.*\}', text, re.DOTALL)
m = RE_JSON_EXTRACT.search(text)
data = json.loads(m.group()) if m else None
if not data:
raise RuntimeError(f"Bad batch response: {text[:200]}")
Expand Down Expand Up @@ -1049,7 +1055,7 @@ async def _read_http_response(self, reader: asyncio.StreamReader):
lines = header_section.split(b"\r\n")

status_line = lines[0].decode(errors="replace")
m = re.search(r"\d{3}", status_line)
m = RE_STATUS_CODE.search(status_line)
status = int(m.group()) if m else 0

headers = {}
Expand Down Expand Up @@ -1139,7 +1145,7 @@ def _parse_relay_response(self, body: bytes) -> bytes:
try:
data = json.loads(text)
except json.JSONDecodeError:
m = re.search(r'\{.*\}', text, re.DOTALL)
m = RE_JSON_EXTRACT.search(text)
if m:
try:
data = json.loads(m.group())
Expand Down Expand Up @@ -1201,7 +1207,7 @@ def _split_set_cookie(blob: str) -> list[str]:
return []
# Split on ", " but only when the following text looks like the start
# of a new cookie (a token followed by '=').
parts = re.split(r",\s*(?=[A-Za-z0-9!#$%&'*+\-.^_`|~]+=)", blob)
parts = RE_COOKIE_SPLIT.split(blob)
return [p.strip() for p in parts if p.strip()]

def _split_raw_response(self, raw: bytes):
Expand All @@ -1210,7 +1216,7 @@ def _split_raw_response(self, raw: bytes):
return 0, {}, raw
header_section, body = raw.split(b"\r\n\r\n", 1)
lines = header_section.split(b"\r\n")
m = re.search(r"\d{3}", lines[0].decode(errors="replace"))
m = RE_STATUS_CODE.search(lines[0].decode(errors="replace"))
status = int(m.group()) if m else 0
headers = {}
for line in lines[1:]:
Expand Down
8 changes: 6 additions & 2 deletions src/proxy_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

log = logging.getLogger("Proxy")

# Pre-compiled regexes for performance
RE_MAX_AGE = re.compile(r"max-age=(\d+)")
RE_CONTENT_TYPE = re.compile(r"content-type:\s*([^\r\n]+)")


class ResponseCache:
"""Simple LRU response cache β€” avoids repeated relay calls."""
Expand Down Expand Up @@ -73,7 +77,7 @@ def parse_ttl(raw_response: bytes, url: str) -> int:
return 0

# Explicit max-age
m = re.search(r"max-age=(\d+)", hdr)
m = RE_MAX_AGE.search(hdr)
if m:
return min(int(m.group(1)), 86400)

Expand All @@ -88,7 +92,7 @@ def parse_ttl(raw_response: bytes, url: str) -> int:
if path.endswith(ext):
return 3600 # 1 hour for static assets

ct_m = re.search(r"content-type:\s*([^\r\n]+)", hdr)
ct_m = RE_CONTENT_TYPE.search(hdr)
ct = ct_m.group(1) if ct_m else ""
if "image/" in ct or "font/" in ct:
return 3600
Expand Down