Commit 865e876
committed
Fix Fetch.enable + http-proxy CDP send/recv deadlock (#2462)
WsConnection.send used to switch the socket to blocking mode on
EWOULDBLOCK, with a comment claiming this 'should virtually never
happen'. Under CDP Fetch.enable + --http-proxy it is routine: the
CONNECT+TLS proxy round-trip means many subresources are in flight
simultaneously, lightpanda emits a flood of Fetch.requestPaused events,
the kernel send buffer fills, lightpanda blocks on write, and
puppeteer's matching Fetch.continueRequest replies pile up in
lightpanda's TCP recv buffer (which lightpanda can't drain because it
is blocked on the write). Both peers wedge until the client times out.
Other contributing problems all collapse paused-intercept sites where
an outer loop polls without ever draining the CDP socket, OR where
disconnect-time cleanup re-enters JS through paths the runtime can no
longer satisfy:
* HttpClient.perform skipped the CDP socket poll entirely whenever
processMessages() returned non-empty, so a steady stream of HTTP
completions could starve CDP reads.
* ScriptManagerBase.waitForImport spun on `client.tick(200)` and
discarded the .cdp_socket return, so a script `import()` whose
request was paused at the InterceptionLayer hung forever.
* BrowserContext.deinit aborted pending intercepts via `transfer.abort`,
which fired XHR/script error_callback chains into a half-torn-down
V8 context (the inspector had already been stopped two lines above).
* Headers.deinit was non-idempotent, so a value-copied Headers (the
hazard RobotsLayer documents) double-freed its curl_slist on the
second deinit; the symptom was an "incorrect alignment" panic
inside ZigToCurlAllocator.free.
* Transfer.deinit was non-idempotent, so a cascade out of
error_callback (e.g. Script.errorCallback -> manager.evaluate() ->
JS execution -> Frame.deinit -> abortOwner -> Transfer.kill ->
Transfer.deinit) reached `arena_pool.release` twice on the same
arena.
Coordinated changes:
* src/network/WsConnection.zig: On EWOULDBLOCK, instead of switching
to a blocking write, poll for both POLLOUT and POLLIN. While waiting
for write space, drain any incoming bytes into the reader buffer
(without dispatching - that would re-enter send and recurse). Adds
tryRead/bufferedBytes accessors.
* src/browser/HttpClient.zig:
- Add has_buffered_input to CDPClient. In perform(), return
.cdp_socket when buffered input exists, and always do at least a
non-blocking poll on the CDP socket so HTTP completions can no
longer starve CDP reads.
- Make Transfer.deinit idempotent by claiming ownership through
`client.transfers.remove(self.id)`. Second deinits (cascades out
of error_callback) early-return.
- Make `Transfer.kill` public (was `fn`) so BrowserContext.deinit
can use it.
- Tighten RequestParams.deinit / Request.deinit to take `*` instead
of `*const` so they can call into `Headers.deinit` (now mutating).
* src/network/http.zig: Headers.deinit now nulls out `self.headers`
after `curl_slist_free_all`, so a second deinit is a no-op. Without
this guard a value-copied Headers double-frees the curl_slist (the
hazard RobotsLayer's call site already documents).
* src/browser/ScriptManagerBase.zig: waitForImport now drains pending
CDP messages on every iteration (matching the syncRequest pattern)
and re-fetches the imported_modules entry per iteration. The cached
entry was a use-after-free risk because the CDP-drain step above
re-enters JS, and a transitively-imported module's preloadImport()
-> getOrPut() can rehash the map and invalidate the prior entry
pointer. A failed CDP blocking_read surfaces as error.Failed so the
caller breaks the loop rather than retrying against a dead socket.
* src/cdp/CDP.zig:
- Wire hasBufferedInput.
- Replace read() with tryRead() in readSocket and tolerate the
no_new_data case so we still process messages drained during a
backpressured send.
- BrowserContext.deinit aborts pending intercepts via
`transfer.kill` instead of `transfer.abort`. `kill` fires
shutdown_callback (or no-op for transfers without one), avoiding
error_callback's re-entry into JS through XHR/script error
handlers - those crash because the V8 context and inspector this
BC owns have either been torn down already or are about to be.
Verified end-to-end against a puppeteer + http-proxy reproducer:
| URL | before | after |
|----------------------------|----------------------|------------------|
| example.com | OK 124ms | OK 117ms |
| github.com | HANG 20s (12/82) | OK 1410ms (82/82)|
| shopify.com | HANG 20s (1/4) | OK 1973ms (66/66)|
| allbirds.com | HANG 20s (12/53) | OK 3944ms (372) |
| allbirds wool-runners PDP | HANG 20s (12/53) | OK 6286ms (459) |
(nike.com still doesn't reach `load` event but all 68 continueRequests
process cleanly - the remaining stall is third-party widgets keeping
the page in `loading` state, not the CDP/HTTP deadlock this PR fixes.)
Lightpanda survives 18 back-to-back navigation runs across the matrix
above (3 per URL) without crashing.
Fixes #2462.1 parent bdd456f commit 865e876
5 files changed
Lines changed: 238 additions & 46 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
170 | 170 | | |
171 | 171 | | |
172 | 172 | | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
173 | 179 | | |
174 | 180 | | |
175 | 181 | | |
| |||
413 | 419 | | |
414 | 420 | | |
415 | 421 | | |
416 | | - | |
| 422 | + | |
| 423 | + | |
417 | 424 | | |
418 | 425 | | |
419 | 426 | | |
| |||
660 | 667 | | |
661 | 668 | | |
662 | 669 | | |
663 | | - | |
664 | | - | |
665 | | - | |
| 670 | + | |
666 | 671 | | |
667 | 672 | | |
668 | 673 | | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
669 | 689 | | |
670 | 690 | | |
671 | 691 | | |
672 | 692 | | |
673 | 693 | | |
674 | | - | |
| 694 | + | |
675 | 695 | | |
676 | 696 | | |
677 | 697 | | |
| 698 | + | |
| 699 | + | |
678 | 700 | | |
679 | 701 | | |
680 | 702 | | |
| |||
963 | 985 | | |
964 | 986 | | |
965 | 987 | | |
966 | | - | |
| 988 | + | |
967 | 989 | | |
968 | 990 | | |
969 | 991 | | |
| |||
1133 | 1155 | | |
1134 | 1156 | | |
1135 | 1157 | | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
| 1162 | + | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
| 1166 | + | |
| 1167 | + | |
| 1168 | + | |
| 1169 | + | |
| 1170 | + | |
| 1171 | + | |
| 1172 | + | |
| 1173 | + | |
1136 | 1174 | | |
1137 | 1175 | | |
1138 | 1176 | | |
| |||
1147 | 1185 | | |
1148 | 1186 | | |
1149 | 1187 | | |
1150 | | - | |
1151 | | - | |
1152 | | - | |
1153 | | - | |
1154 | 1188 | | |
1155 | 1189 | | |
1156 | 1190 | | |
| |||
1177 | 1211 | | |
1178 | 1212 | | |
1179 | 1213 | | |
1180 | | - | |
1181 | | - | |
| 1214 | + | |
| 1215 | + | |
| 1216 | + | |
| 1217 | + | |
| 1218 | + | |
| 1219 | + | |
1182 | 1220 | | |
1183 | 1221 | | |
1184 | 1222 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
286 | 286 | | |
287 | 287 | | |
288 | 288 | | |
289 | | - | |
290 | | - | |
291 | | - | |
292 | | - | |
293 | | - | |
294 | | - | |
295 | 289 | | |
296 | 290 | | |
297 | 291 | | |
298 | 292 | | |
299 | 293 | | |
300 | 294 | | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
301 | 308 | | |
302 | 309 | | |
303 | | - | |
304 | | - | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
305 | 327 | | |
306 | 328 | | |
307 | 329 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
| 114 | + | |
114 | 115 | | |
115 | 116 | | |
116 | 117 | | |
| |||
149 | 150 | | |
150 | 151 | | |
151 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
152 | 158 | | |
153 | | - | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
154 | 164 | | |
155 | 165 | | |
156 | 166 | | |
157 | 167 | | |
158 | | - | |
159 | | - | |
160 | | - | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
161 | 174 | | |
162 | 175 | | |
163 | 176 | | |
| |||
574 | 587 | | |
575 | 588 | | |
576 | 589 | | |
577 | | - | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
578 | 597 | | |
579 | 598 | | |
580 | 599 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
353 | 353 | | |
354 | 354 | | |
355 | 355 | | |
356 | | - | |
357 | 356 | | |
358 | 357 | | |
359 | | - | |
360 | | - | |
361 | | - | |
362 | | - | |
363 | | - | |
364 | | - | |
365 | | - | |
366 | | - | |
367 | 358 | | |
368 | 359 | | |
369 | 360 | | |
370 | | - | |
371 | | - | |
372 | | - | |
373 | | - | |
374 | | - | |
375 | | - | |
376 | | - | |
377 | | - | |
378 | | - | |
379 | | - | |
380 | | - | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
381 | 377 | | |
382 | 378 | | |
383 | 379 | | |
| |||
390 | 386 | | |
391 | 387 | | |
392 | 388 | | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
393 | 466 | | |
394 | 467 | | |
395 | 468 | | |
| |||
477 | 550 | | |
478 | 551 | | |
479 | 552 | | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
480 | 584 | | |
481 | 585 | | |
482 | 586 | | |
| |||
0 commit comments