fix: HAR captures 0 entries — dangling HashMap keys cause new CDP client per request - #122
Closed
lekt9 wants to merge 1 commit into
Closed
fix: HAR captures 0 entries — dangling HashMap keys cause new CDP client per request#122lekt9 wants to merge 1 commit into
lekt9 wants to merge 1 commit into
Conversation
Root cause: getCdpClient() and getHarRecorder() stored dangling pointer keys in HashMaps, creating a new CDP client per request. Network.enable was sent on connection #1 but navigate/harStop used connection #3. Also adds Network.getResponseBody support — after HAR recording stops, kuri fetches response bodies for JSON/text API responses via CDP and includes them in the HAR output as content.text. Fixes: - Dupe tab_id keys before HashMap.put in getCdpClient/getHarRecorder - Replace fixed 32-slot EventBuffer with dynamic ArrayListUnmanaged - Add drainWsEvents() for mutex-safe WS event reading - Fetch response bodies via Network.getResponseBody before Network.disable - Fix toJson brace count and JSON escaping for response bodies Result: httpbin.org → 2 entries with full response bodies (was 0). Closes justrach#118, closes justrach#120 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
lekt9
force-pushed
the
fix/cdp-client-key-ownership
branch
from
March 29, 2026 04:31
cb32735 to
1f3eadf
Compare
justrach
requested changes
Mar 29, 2026
justrach
left a comment
Owner
There was a problem hiding this comment.
The runtime fix looks directionally right, but this patch introduces ownership regressions that should be fixed before merge.
flushEventsToHar()now clearsclient.event_bufwithout freeing the buffered event payloads. Those payloads can be allocated from the bridge allocator duringNetwork.enable/Network.disable, so this leaks event strings across HAR sessions.- The new duplicated
tab_idkeys inserted intocdp_clientsandhar_recordersare not freed inBridge.deinit()orremoveTab(), so each tab now leaks one key per map.
I opened #123 with the same cross-request HAR fix, plus the ownership cleanup and validation against the original httpbin.org/get repro.
Owner
|
Closing — the core fixes here are already on main:
The remaining response-body capture is handled more cleanly in PR #127, which will be merged separately. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
HAR recorder always returned 0 entries because every HTTP request created a new CDP client instead of reusing the existing one.
Network.enablewas sent on connection #1, butnavigateandharStopused different connections that never received network events.Root cause
getCdpClient()andgetHarRecorder()inbridge.zigstoredtab_idslices directly asStringHashMapkeys. These slices point into per-request arena memory that is freed after each HTTP handler returns. On the next request, the newtab_idslice has the same content but a different memory address, and since the old key's memory was freed,HashMap.get()reads garbage and never matches — so it creates a new client every time.Verified with debug logging:
Changes
bridge.zig: Dupetab_idkeys withallocator.dupe()beforeHashMap.put()in bothgetCdpClient()andgetHarRecorder()client.zig: Replace fixed 32-slotEventBufferwith dynamicArrayListUnmanagedso events aren't silently dropped. AdddrainWsEvents()for mutex-safe WS reading.router.zig: UsedrainWsEvents()instead of direct WS access. FixflushEventsToHar()to clear buffer without double-freeing arena-allocated events.har.zig: SendNetwork.disablebefore settingrecording=falseso late events are still processed.Results
Invalid freein EventBuffer)Closes #118, closes #120