mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-02 08:35:07 +08:00
feat(http): expand the static Node HTTP surface (#410)
* feat(http): materialize static distinct header snapshots - Preserve precise string array types for whole incoming header and trailer collections. - Cover duplicate headers, trailers, and raw header reads against Node in both backends. - Refresh test-backed static HTTP compatibility claims. * feat(http): expand the static Node HTTP surface - Add HTTP module values, request and response lifecycle state, and socket controls. - Implement server timeout and connection shutdown behavior in the native runtime. - Cover C and LLVM behavior with Node differential fixtures, refresh compatibility evidence, and recover interrupted Sandbox streams. * fix(http): honor message timeout handlers - Keep server sockets open when request or response timeout listeners handle the event. - Add differential regressions and refresh the TypeScript 7 order baseline.
This commit is contained in:
@@ -2,6 +2,6 @@
|
||||
"schemaVersion": 3,
|
||||
"nodeVersion": "24.15.0",
|
||||
"nodeCommit": "848430679556aed0bd073f2bc263331ad84fa119",
|
||||
"artifactVersion": "b92c655b71259eb9c1f8",
|
||||
"artifactVersion": "314fa26f7ef394cb4433",
|
||||
"rowCount": 3662
|
||||
}
|
||||
|
||||
@@ -506,9 +506,9 @@
|
||||
"apiEntries": 174,
|
||||
"static": {
|
||||
"supported": 0,
|
||||
"partial": 78,
|
||||
"partial": 131,
|
||||
"refused": 0,
|
||||
"not-implemented": 96,
|
||||
"not-implemented": 43,
|
||||
"by-design": 0,
|
||||
"unreviewed": 0,
|
||||
"not-applicable": 0
|
||||
@@ -45401,9 +45401,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -45513,9 +45513,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -45541,9 +45541,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -45569,9 +45569,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -45597,9 +45597,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -45625,9 +45625,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -45681,9 +45681,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -45709,9 +45709,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -45737,9 +45737,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -45765,9 +45765,9 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -45877,9 +45877,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46129,9 +46129,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46157,9 +46157,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46186,7 +46186,7 @@
|
||||
},
|
||||
"static": {
|
||||
"status": "partial",
|
||||
"detail": "Implemented by a dedicated static compiler/runtime path.",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
@@ -46269,9 +46269,9 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46297,9 +46297,9 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Static ServerResponse state, socket access, timeouts, and strict body length checks support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46325,9 +46325,9 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46493,9 +46493,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46521,9 +46521,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Static ServerResponse state, socket access, timeouts, and strict body length checks support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46577,9 +46577,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Static ServerResponse state, socket access, timeouts, and strict body length checks support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46605,9 +46605,9 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46633,9 +46633,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46717,9 +46717,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46773,9 +46773,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46801,9 +46801,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46829,9 +46829,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46857,9 +46857,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46885,9 +46885,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "refused",
|
||||
@@ -46941,9 +46941,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -46969,9 +46969,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -47025,9 +47025,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -47389,9 +47389,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -47417,9 +47417,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -47445,9 +47445,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -47501,9 +47501,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -47529,9 +47529,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -47557,9 +47557,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48089,9 +48089,9 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48369,9 +48369,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48397,9 +48397,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48425,9 +48425,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -48453,9 +48453,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -48481,9 +48481,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48509,9 +48509,9 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48565,9 +48565,9 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48593,9 +48593,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48622,7 +48622,7 @@
|
||||
},
|
||||
"static": {
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"detail": "Static IncomingMessage header and trailer reads support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
@@ -48705,9 +48705,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Static IncomingMessage header and trailer reads support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48734,7 +48734,7 @@
|
||||
},
|
||||
"static": {
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"detail": "Static IncomingMessage header and trailer reads support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
@@ -48761,9 +48761,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Static ServerResponse state, socket access, timeouts, and strict body length checks support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48817,9 +48817,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Static ServerResponse state, socket access, timeouts, and strict body length checks support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48846,7 +48846,7 @@
|
||||
},
|
||||
"static": {
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"detail": "Static IncomingMessage header and trailer reads support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
@@ -48874,7 +48874,7 @@
|
||||
},
|
||||
"static": {
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"detail": "Static IncomingMessage header and trailer reads support the tested HTTP/1.1 forms.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
@@ -48929,9 +48929,9 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -48957,9 +48957,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -50105,9 +50105,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -50133,9 +50133,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -50189,9 +50189,9 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -555,9 +555,9 @@
|
||||
"apiEntries": 174,
|
||||
"static": {
|
||||
"supported": 0,
|
||||
"partial": 78,
|
||||
"partial": 131,
|
||||
"refused": 0,
|
||||
"not-implemented": 96,
|
||||
"not-implemented": 43,
|
||||
"by-design": 0,
|
||||
"unreviewed": 0,
|
||||
"not-applicable": 0
|
||||
@@ -62166,7 +62166,26 @@
|
||||
"tests/corpus/2955-http-static-state.ts",
|
||||
"tests/corpus/2956-http-static-informational.ts",
|
||||
"tests/corpus/2957-http-static-response-controls.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/corpus/2973-http-static-agent.ts",
|
||||
"tests/corpus/2974-http-static-module-values.ts",
|
||||
"tests/corpus/2975-http-static-client-controls.ts",
|
||||
"tests/corpus/2976-http-static-incoming-state.ts",
|
||||
"tests/corpus/2977-http-static-incoming-timeout.ts",
|
||||
"tests/corpus/2978-http-static-client-timeout.ts",
|
||||
"tests/corpus/2979-http-static-server-timeout.ts",
|
||||
"tests/corpus/2980-http-static-server-timeout-default.ts",
|
||||
"tests/corpus/2981-http-static-events.ts",
|
||||
"tests/corpus/2982-http-static-close-all.ts",
|
||||
"tests/corpus/2983-http-static-close-idle.ts",
|
||||
"tests/corpus/2984-http-static-close-upgrade.ts",
|
||||
"tests/corpus/2985-http-static-message-destroy.ts",
|
||||
"tests/corpus/2986-http-static-client-socket-finish.ts",
|
||||
"tests/corpus/2987-http-static-timeout-errors.ts",
|
||||
"tests/corpus/2988-http-static-client-abort.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts",
|
||||
"tests/fixtures/server/cases/http2-connect/main.ts",
|
||||
"tests/fixtures/server/cases/upgrade-both/main.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
@@ -62277,8 +62296,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.http.Agent",
|
||||
"tests": [
|
||||
"tests/corpus/2973-http-static-agent.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -62388,8 +62410,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.agent.destroy",
|
||||
"tests": [
|
||||
"tests/corpus/2973-http-static-agent.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -62418,8 +62443,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.agent.getName",
|
||||
"tests": [
|
||||
"tests/corpus/2973-http-static-agent.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -62445,8 +62473,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.freeSockets",
|
||||
"tests": [
|
||||
"tests/corpus/2973-http-static-agent.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -62472,8 +62503,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.maxFreeSockets",
|
||||
"tests": [
|
||||
"tests/corpus/2973-http-static-agent.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -62499,8 +62533,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.maxSockets",
|
||||
"tests": [
|
||||
"tests/corpus/2973-http-static-agent.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -62553,8 +62590,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.requests",
|
||||
"tests": [
|
||||
"tests/corpus/2973-http-static-agent.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -62580,8 +62620,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.sockets",
|
||||
"tests": [
|
||||
"tests/corpus/2973-http-static-agent.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -62607,8 +62650,12 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.http.ClientRequest",
|
||||
"tests": [
|
||||
"tests/corpus/2981-http-static-events.ts",
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -62637,8 +62684,11 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.request.abort",
|
||||
"tests": [
|
||||
"tests/corpus/2988-http-static-client-abort.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -62673,6 +62723,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -62770,8 +62821,12 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.destroyed",
|
||||
"tests": [
|
||||
"tests/corpus/2978-http-static-client-timeout.ts",
|
||||
"tests/corpus/2986-http-static-client-socket-finish.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -62803,6 +62858,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -63052,8 +63108,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.request.setNoDelay",
|
||||
"tests": [
|
||||
"tests/corpus/2975-http-static-client-controls.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63079,8 +63138,12 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.request.setSocketKeepAlive",
|
||||
"tests": [
|
||||
"tests/corpus/2978-http-static-client-timeout.ts",
|
||||
"tests/corpus/2987-http-static-timeout-errors.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63107,11 +63170,10 @@
|
||||
},
|
||||
"static": {
|
||||
"status": "partial",
|
||||
"evidence": "compiler-dedicated:request.setTimeout",
|
||||
"evidence": "compiler-feature:http.request.setTimeout",
|
||||
"tests": [
|
||||
"tests/corpus/1780-http-res-surface.ts",
|
||||
"tests/corpus/2672-http-request-response-callback.ts",
|
||||
"tests/corpus/2689-http-server-timeout-properties.ts"
|
||||
"tests/corpus/2978-http-static-client-timeout.ts",
|
||||
"tests/corpus/2987-http-static-timeout-errors.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
@@ -63147,6 +63209,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -63209,8 +63272,11 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.aborted",
|
||||
"tests": [
|
||||
"tests/corpus/2988-http-static-client-abort.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63236,8 +63302,11 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.connection",
|
||||
"tests": [
|
||||
"tests/corpus/2986-http-static-client-socket-finish.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63263,8 +63332,11 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.finished",
|
||||
"tests": [
|
||||
"tests/corpus/2975-http-static-client-controls.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63437,8 +63509,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.reusedSocket",
|
||||
"tests": [
|
||||
"tests/corpus/2975-http-static-client-controls.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63464,8 +63539,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.socket",
|
||||
"tests": [
|
||||
"tests/corpus/2986-http-static-client-socket-finish.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63521,8 +63599,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.writableFinished",
|
||||
"tests": [
|
||||
"tests/corpus/2986-http-static-client-socket-finish.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63548,8 +63629,11 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'abort'",
|
||||
"tests": [
|
||||
"tests/corpus/2988-http-static-client-abort.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63575,8 +63659,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'close'",
|
||||
"tests": [
|
||||
"tests/corpus/2981-http-static-events.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63656,8 +63743,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'finish'",
|
||||
"tests": [
|
||||
"tests/corpus/2986-http-static-client-socket-finish.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63710,8 +63800,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'response'",
|
||||
"tests": [
|
||||
"tests/corpus/2981-http-static-events.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63737,8 +63830,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'socket'",
|
||||
"tests": [
|
||||
"tests/corpus/2986-http-static-client-socket-finish.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63764,8 +63860,12 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'timeout'",
|
||||
"tests": [
|
||||
"tests/corpus/2978-http-static-client-timeout.ts",
|
||||
"tests/corpus/2987-http-static-timeout-errors.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63791,8 +63891,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'upgrade'",
|
||||
"tests": [
|
||||
"tests/fixtures/server/cases/upgrade-both/main.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63818,8 +63921,12 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.http.Server",
|
||||
"tests": [
|
||||
"tests/corpus/2981-http-static-events.ts",
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "refused",
|
||||
@@ -63876,8 +63983,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.server.closeAllConnections",
|
||||
"tests": [
|
||||
"tests/corpus/2982-http-static-close-all.ts",
|
||||
"tests/corpus/2983-http-static-close-idle.ts",
|
||||
"tests/corpus/2984-http-static-close-upgrade.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63903,8 +64015,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.server.closeIdleConnections",
|
||||
"tests": [
|
||||
"tests/corpus/2982-http-static-close-all.ts",
|
||||
"tests/corpus/2983-http-static-close-idle.ts",
|
||||
"tests/corpus/2984-http-static-close-upgrade.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -63961,8 +64078,12 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.server.setTimeout",
|
||||
"tests": [
|
||||
"tests/corpus/2979-http-static-server-timeout.ts",
|
||||
"tests/corpus/2980-http-static-server-timeout-default.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -64340,8 +64461,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'close'",
|
||||
"tests": [
|
||||
"tests/corpus/2981-http-static-events.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -64367,8 +64491,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'connect'",
|
||||
"tests": [
|
||||
"tests/fixtures/server/cases/http2-connect/main.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -64394,8 +64521,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'connection'",
|
||||
"tests": [
|
||||
"tests/corpus/2981-http-static-events.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -64448,8 +64578,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'request'",
|
||||
"tests": [
|
||||
"tests/corpus/2981-http-static-events.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -64475,8 +64608,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'upgrade'",
|
||||
"tests": [
|
||||
"tests/fixtures/server/cases/upgrade-both/main.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -64502,8 +64638,12 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.http.ServerResponse",
|
||||
"tests": [
|
||||
"tests/corpus/2981-http-static-events.ts",
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -64535,6 +64675,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -64568,6 +64709,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -64633,6 +64775,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -64884,6 +65027,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -65095,8 +65239,11 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.finished",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65392,8 +65539,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'close'",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65419,8 +65569,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'finish'",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65446,8 +65599,12 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.http.IncomingMessage",
|
||||
"tests": [
|
||||
"tests/corpus/2981-http-static-events.ts",
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -65476,8 +65633,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.message.destroy",
|
||||
"tests": [
|
||||
"tests/corpus/2985-http-static-message-destroy.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -65506,8 +65666,13 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.message.setTimeout",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts",
|
||||
"tests/corpus/2977-http-static-incoming-timeout.ts",
|
||||
"tests/corpus/2987-http-static-timeout-errors.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65533,8 +65698,11 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.aborted",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65590,8 +65758,11 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.message.connection",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65617,8 +65788,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.headers",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65650,6 +65824,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -65737,8 +65912,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.rawHeaders",
|
||||
"tests": [
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65770,6 +65948,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -65797,8 +65976,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.socket",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65854,8 +66036,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.statusMessage",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -65887,6 +66072,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -65920,6 +66106,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -65977,8 +66164,11 @@
|
||||
"inherited": false
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'aborted'",
|
||||
"tests": [
|
||||
"tests/corpus/2985-http-static-message-destroy.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -66004,8 +66194,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.'close'",
|
||||
"tests": [
|
||||
"tests/corpus/2976-http-static-incoming-state.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -66064,6 +66257,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -66124,6 +66318,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -66211,6 +66406,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -66487,6 +66683,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -66631,6 +66828,7 @@
|
||||
"tests/corpus/2700-http-static-trailers.ts",
|
||||
"tests/corpus/2701-http-static-trailer-wire.ts",
|
||||
"tests/corpus/2702-http-static-trailer-end.ts",
|
||||
"tests/corpus/2972-http-static-distinct-snapshots.ts",
|
||||
"tests/fixtures/server/cases/http-trailers/main.ts"
|
||||
]
|
||||
},
|
||||
@@ -67190,8 +67388,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.METHODS",
|
||||
"tests": [
|
||||
"tests/corpus/2974-http-static-module-values.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -67220,8 +67421,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.STATUS_CODES",
|
||||
"tests": [
|
||||
"tests/corpus/2974-http-static-module-values.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
@@ -67280,8 +67484,11 @@
|
||||
"inherited": true
|
||||
},
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:http"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:http.maxHeaderSize",
|
||||
"tests": [
|
||||
"tests/corpus/2974-http-static-module-values.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
|
||||
@@ -621,6 +621,9 @@ function publicDetail(tier) {
|
||||
if (/^compiler-feature:http\.(?:response\.setTimeout|connection|req|sendDate|socket|statusMessage|strictContentLength|writableFinished)$/.test(source)) {
|
||||
return "Static ServerResponse state, socket access, timeouts, and strict body length checks support the tested HTTP/1.1 forms.";
|
||||
}
|
||||
if (/^compiler-feature:http\.(?:headersDistinct|rawHeaders|rawTrailers|trailers|trailersDistinct)$/.test(source)) {
|
||||
return "Static IncomingMessage header and trailer reads support the tested HTTP/1.1 forms.";
|
||||
}
|
||||
return "Implemented for the documented scriptc module-loader subset.";
|
||||
}
|
||||
if (source.startsWith("compiler-chapter-policy:")) {
|
||||
|
||||
@@ -79,13 +79,35 @@
|
||||
"stdlib.abort": ["tests/harness/fetch-conformance.test.ts"]
|
||||
},
|
||||
"features": [
|
||||
{ "chapter": "http", "signatures": ["Class: `http.ClientRequest`", "Class: `http.Server`", "Class: `http.ServerResponse`", "Class: `http.IncomingMessage`"], "status": "partial", "evidence": ["tests/corpus/2981-http-static-events.ts", "tests/corpus/2976-http-static-incoming-state.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ClientRequest`", "signatures": ["`request.setSocketKeepAlive([enable][, initialDelay])`", "`request.setTimeout(timeout[, callback])`", "`destroyed` Type: {boolean}", "Event: `'timeout'`"], "status": "partial", "evidence": ["tests/corpus/2978-http-static-client-timeout.ts", "tests/corpus/2987-http-static-timeout-errors.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ClientRequest`", "signatures": ["`request.abort()`", "`aborted` Type: {boolean}", "Event: `'abort'`"], "status": "partial", "evidence": ["tests/corpus/2988-http-static-client-abort.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ClientRequest`", "signatures": ["Event: `'close'`", "Event: `'response'`"], "status": "partial", "evidence": ["tests/corpus/2981-http-static-events.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ClientRequest`", "signatures": ["`socket` Type: {stream.Duplex}", "`connection` Type: {stream.Duplex}", "`writableFinished` Type: {boolean}", "Event: `'socket'`", "Event: `'finish'`"], "status": "partial", "evidence": ["tests/corpus/2986-http-static-client-socket-finish.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`destroyed` Type: {boolean}"], "status": "partial", "evidence": ["tests/corpus/2978-http-static-client-timeout.ts", "tests/corpus/2986-http-static-client-socket-finish.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ClientRequest`", "signatures": ["Event: `'upgrade'`"], "status": "partial", "evidence": ["tests/fixtures/server/cases/upgrade-both/main.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.IncomingMessage`", "signatures": ["`message.destroy([error])`", "Event: `'aborted'`"], "status": "partial", "evidence": ["tests/corpus/2985-http-static-message-destroy.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.Server`", "signatures": ["`server.setTimeout([msecs][, callback])`"], "status": "partial", "evidence": ["tests/corpus/2979-http-static-server-timeout.ts", "tests/corpus/2980-http-static-server-timeout-default.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.Server`", "signatures": ["`server.closeAllConnections()`", "`server.closeIdleConnections()`"], "status": "partial", "evidence": ["tests/corpus/2982-http-static-close-all.ts", "tests/corpus/2983-http-static-close-idle.ts", "tests/corpus/2984-http-static-close-upgrade.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.Server`", "signatures": ["Event: `'close'`", "Event: `'connection'`", "Event: `'request'`"], "status": "partial", "evidence": ["tests/corpus/2981-http-static-events.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.Server`", "signatures": ["Event: `'upgrade'`"], "status": "partial", "evidence": ["tests/fixtures/server/cases/upgrade-both/main.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.Server`", "signatures": ["Event: `'connect'`"], "status": "partial", "evidence": ["tests/fixtures/server/cases/http2-connect/main.ts"] },
|
||||
{ "chapter": "http", "signatures": ["Class: `http.Agent`"], "status": "partial", "evidence": ["tests/corpus/2973-http-static-agent.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.Agent`", "signatures": ["`agent.destroy()`", "`agent.getName([options])`", "`freeSockets` Type: {Object}", "`maxFreeSockets` Type: {number}", "`maxSockets` Type: {number}", "`requests` Type: {Object}", "`sockets` Type: {Object}"], "status": "partial", "evidence": ["tests/corpus/2973-http-static-agent.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`METHODS` Type: {string\\[]}", "`STATUS_CODES` Type: {Object}", "`maxHeaderSize` Type: {number}"], "status": "partial", "evidence": ["tests/corpus/2974-http-static-module-values.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`request.setNoDelay([noDelay])`"], "status": "partial", "evidence": ["tests/corpus/2975-http-static-client-controls.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ClientRequest`", "signatures": ["`finished` Type: {boolean}", "`reusedSocket` Type: {boolean} Whether the request is send through a reused socket."], "status": "partial", "evidence": ["tests/corpus/2975-http-static-client-controls.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.IncomingMessage`", "signatures": ["`message.setTimeout(msecs[, callback])`"], "status": "partial", "evidence": ["tests/corpus/2976-http-static-incoming-state.ts", "tests/corpus/2977-http-static-incoming-timeout.ts", "tests/corpus/2987-http-static-timeout-errors.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.IncomingMessage`", "signatures": ["`aborted` Type: {boolean}", "`message.connection`", "`headers` Type: {Object}", "`socket` Type: {stream.Duplex}", "`statusMessage` Type: {string}", "Event: `'close'`"], "status": "partial", "evidence": ["tests/corpus/2976-http-static-incoming-state.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ServerResponse`", "signatures": ["`finished` Type: {boolean}", "Event: `'close'`", "Event: `'finish'`"], "status": "partial", "evidence": ["tests/corpus/2976-http-static-incoming-state.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`http.validateHeaderName(name[, label])`", "`http.validateHeaderValue(name, value)`"], "status": "partial", "evidence": ["tests/corpus/2953-http-header-validation.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`request.getHeader(name)`", "`request.getHeaderNames()`", "`request.getHeaders()`", "`request.getRawHeaderNames()`", "`request.hasHeader(name)`", "`request.removeHeader(name)`", "`request.setHeader(name, value)`", "`response.getHeaderNames()`", "`response.getHeaders()`"], "status": "partial", "evidence": ["tests/corpus/2954-http-outgoing-headers.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`path` Type: {string} The request path.", "`method` Type: {string} The request method.", "`host` Type: {string} The request host.", "`protocol` Type: {string} The request protocol.", "`listening` Type: {boolean} Indicates whether or not the server is listening for connections.", "`headersSent` Type: {boolean}", "`writableEnded` Type: {boolean}", "`complete` Type: {boolean}", "`httpVersion` Type: {string}", "`method` Type: {string}", "`url` Type: {string}", "`statusCode` Type: {number}", "`statusCode` Type: {number} **Default:** `200`"], "status": "partial", "evidence": ["tests/corpus/2955-http-static-state.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`response.writeContinue()`", "`response.writeProcessing()`", "`response.writeEarlyHints(hints[, callback])`"], "status": "partial", "evidence": ["tests/corpus/2956-http-static-informational.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`response.setTimeout(msecs[, callback])`"], "status": "partial", "evidence": ["tests/corpus/2957-http-static-response-controls.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ServerResponse`", "signatures": ["`req` Type: {http.IncomingMessage}", "`sendDate` Type: {boolean}", "`strictContentLength` Type: {boolean} **Default:** `false`", "`statusMessage` Type: {string}", "`socket` Type: {stream.Duplex}", "`connection` Type: {stream.Duplex}", "`writableFinished` Type: {boolean}"], "status": "partial", "evidence": ["tests/corpus/2957-http-static-response-controls.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`request.cork()`", "`request.flushHeaders()`", "`request.uncork()`", "`response.addTrailers(headers)`", "`response.cork()`", "`response.flushHeaders()`", "`response.uncork()`", "`headersDistinct` Type: {Object}", "`rawTrailers` Type: {string\\[]}", "`trailers` Type: {Object}", "`trailersDistinct` Type: {Object}", "`outgoingMessage.addTrailers(headers)`", "`outgoingMessage.cork()`", "`outgoingMessage.flushHeaders()`", "`outgoingMessage.uncork()`", "`writableCorked` Type: {number}"], "status": "partial", "evidence": ["tests/corpus/2700-http-static-trailers.ts", "tests/corpus/2701-http-static-trailer-wire.ts", "tests/corpus/2702-http-static-trailer-end.ts", "tests/fixtures/server/cases/http-trailers/main.ts"] },
|
||||
{ "chapter": "http", "signatures": ["`request.cork()`", "`request.flushHeaders()`", "`request.uncork()`", "`response.addTrailers(headers)`", "`response.cork()`", "`response.flushHeaders()`", "`response.uncork()`", "`headersDistinct` Type: {Object}", "`rawTrailers` Type: {string\\[]}", "`trailers` Type: {Object}", "`trailersDistinct` Type: {Object}", "`outgoingMessage.addTrailers(headers)`", "`outgoingMessage.cork()`", "`outgoingMessage.flushHeaders()`", "`outgoingMessage.uncork()`", "`writableCorked` Type: {number}"], "status": "partial", "evidence": ["tests/corpus/2700-http-static-trailers.ts", "tests/corpus/2701-http-static-trailer-wire.ts", "tests/corpus/2702-http-static-trailer-end.ts", "tests/corpus/2972-http-static-distinct-snapshots.ts", "tests/fixtures/server/cases/http-trailers/main.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.IncomingMessage`", "signatures": ["`rawHeaders` Type: {string\\[]}"], "status": "partial", "evidence": ["tests/corpus/2972-http-static-distinct-snapshots.ts"] },
|
||||
{ "chapter": "buffer", "signatures": ["`buf.readBigInt64BE([offset])`", "`buf.readBigInt64LE([offset])`", "`buf.readBigUInt64BE([offset])`", "`buf.readBigUInt64LE([offset])`", "`buf.writeBigInt64BE(value[, offset])`", "`buf.writeBigInt64LE(value[, offset])`", "`buf.writeBigUInt64BE(value[, offset])`", "`buf.writeBigUInt64LE(value[, offset])`"], "status": "supported", "evidence": ["tests/corpus/2902-bigint-bytes.ts", "tests/corpus/2904-bigint-errors.ts"] },
|
||||
{ "chapter": "environment_variables", "symbols": ["export"], "status": "not-applicable" },
|
||||
{ "chapter": "globals", "symbols": ["fetch"], "status": "partial", "evidence": ["tests/harness/fetch-conformance.test.ts"] },
|
||||
|
||||
+35
-9
@@ -2247,6 +2247,7 @@ declare module "net" {
|
||||
emit(event: "connection", socket: Socket): boolean;
|
||||
on(event: "connection" | "secureConnection", listener: (socket: Socket) => void): void;
|
||||
on(event: "close" | "listening", listener: () => void): void;
|
||||
on(event: "timeout", listener: (socket: Socket) => void): void;
|
||||
on(event: "error", listener: (err: Error) => void): void;
|
||||
/* The WebSocket handover: fires INSTEAD of 'request' for
|
||||
* Connection: upgrade requests, with the raw socket + head bytes. */
|
||||
@@ -2257,11 +2258,13 @@ declare module "net" {
|
||||
/* addListener IS on (Node aliases them) — the suite spells both. */
|
||||
addListener(event: "connection" | "secureConnection", listener: (socket: Socket) => void): void;
|
||||
addListener(event: "close" | "listening", listener: () => void): void;
|
||||
addListener(event: "timeout", listener: (socket: Socket) => void): void;
|
||||
addListener(event: "error", listener: (err: Error) => void): void;
|
||||
addListener(event: "upgrade", listener: (req: import("http").IncomingMessage, socket: Socket, head: Buffer) => void): void;
|
||||
addListener(event: "request", listener: (req: import("http").IncomingMessage, res: import("http").ServerResponse) => void): void;
|
||||
once(event: "connection" | "secureConnection", listener: (socket: Socket) => void): void;
|
||||
once(event: "close" | "listening", listener: () => void): void;
|
||||
once(event: "timeout", listener: (socket: Socket) => void): void;
|
||||
once(event: "error", listener: (err: Error) => void): void;
|
||||
once(event: "upgrade", listener: (req: import("http").IncomingMessage, socket: Socket, head: Buffer) => void): void;
|
||||
once(event: "request", listener: (req: import("http").IncomingMessage, res: import("http").ServerResponse) => void): void;
|
||||
@@ -2318,8 +2321,14 @@ declare module "node:net" {
|
||||
* connection per call (no agent pooling) with Node's exact wire head. */
|
||||
declare module "http" {
|
||||
import { Server as NetServer, Socket } from "net";
|
||||
export const METHODS: string[];
|
||||
export const STATUS_CODES: { [status: number]: string | undefined };
|
||||
export const maxHeaderSize: number;
|
||||
export interface Server extends NetServer {
|
||||
timeout: number;
|
||||
setTimeout(msecs: number, callback?: (socket: Socket) => void): this;
|
||||
closeAllConnections(): void;
|
||||
closeIdleConnections(): void;
|
||||
keepAliveTimeout: number;
|
||||
keepAliveTimeoutBuffer: number;
|
||||
headersTimeout: number;
|
||||
@@ -2359,9 +2368,11 @@ declare module "http" {
|
||||
readonly method: string;
|
||||
readonly httpVersion: string;
|
||||
readonly complete: boolean;
|
||||
readonly aborted: boolean;
|
||||
readonly statusCode: number | undefined;
|
||||
readonly statusMessage: string | undefined;
|
||||
readonly socket: Socket;
|
||||
readonly connection: Socket;
|
||||
readonly headers: { [name: string]: string | undefined };
|
||||
readonly headersDistinct: { [name: string]: string[] | undefined };
|
||||
readonly rawHeaders: string[];
|
||||
@@ -2370,6 +2381,7 @@ declare module "http" {
|
||||
readonly rawTrailers: string[];
|
||||
resume(): void;
|
||||
destroy(): void;
|
||||
setTimeout(msecs: number, callback?: () => void): this;
|
||||
/* setEncoding('utf8'): 'data' delivers strings (other real encodings
|
||||
* fence loudly at runtime; unknown names throw ERR_UNKNOWN_ENCODING). */
|
||||
setEncoding(encoding: string): void;
|
||||
@@ -2377,19 +2389,20 @@ declare module "http" {
|
||||
* ClientRequest, or a raw Socket; natural end ends the destination. */
|
||||
pipe(destination: ServerResponse | import("http2").Http2ServerResponse | ClientRequest | Socket): void;
|
||||
on(event: "data", listener: (chunk: any) => void): void;
|
||||
on(event: "end" | "close", listener: () => void): void;
|
||||
on(event: "end" | "close" | "aborted", listener: () => void): void;
|
||||
on(event: "error", listener: (err: Error) => void): void;
|
||||
/* addListener IS on (Node aliases them) — the suite spells both. */
|
||||
addListener(event: "data", listener: (chunk: any) => void): void;
|
||||
addListener(event: "end" | "close", listener: () => void): void;
|
||||
addListener(event: "end" | "close" | "aborted", listener: () => void): void;
|
||||
addListener(event: "error", listener: (err: Error) => void): void;
|
||||
once(event: "data", listener: (chunk: any) => void): void;
|
||||
once(event: "end" | "close", listener: () => void): void;
|
||||
once(event: "end" | "close" | "aborted", listener: () => void): void;
|
||||
once(event: "error", listener: (err: Error) => void): void;
|
||||
}
|
||||
export interface ServerResponse {
|
||||
readonly headersSent: boolean;
|
||||
readonly writableEnded: boolean;
|
||||
readonly finished: boolean;
|
||||
readonly writableFinished: boolean;
|
||||
readonly writableCorked: number;
|
||||
readonly req: IncomingMessage;
|
||||
@@ -2425,10 +2438,10 @@ declare module "http" {
|
||||
end(data?: string | Uint8Array, callback?: () => void): void;
|
||||
end(callback: () => void): void;
|
||||
destroy(): void;
|
||||
on(event: "close", listener: () => void): void;
|
||||
on(event: "close" | "finish", listener: () => void): void;
|
||||
/* addListener IS on (Node aliases them) — the suite spells both. */
|
||||
addListener(event: "close", listener: () => void): void;
|
||||
once(event: "close", listener: () => void): void;
|
||||
addListener(event: "close" | "finish", listener: () => void): void;
|
||||
once(event: "close" | "finish", listener: () => void): void;
|
||||
}
|
||||
/* The CLIENT slice (http.request/http.get): the options-object form
|
||||
* with hostname/host, port, path, method, timeout, and headers; the
|
||||
@@ -2495,6 +2508,9 @@ declare module "http" {
|
||||
export const globalAgent: Agent;
|
||||
export interface ClientRequest {
|
||||
readonly destroyed: boolean;
|
||||
readonly aborted: boolean;
|
||||
readonly socket: Socket;
|
||||
readonly connection: Socket;
|
||||
readonly writableCorked: number;
|
||||
readonly method: string;
|
||||
readonly path: string;
|
||||
@@ -2502,6 +2518,9 @@ declare module "http" {
|
||||
readonly protocol: string;
|
||||
readonly headersSent: boolean;
|
||||
readonly writableEnded: boolean;
|
||||
readonly writableFinished: boolean;
|
||||
readonly finished: boolean;
|
||||
readonly reusedSocket: boolean;
|
||||
setHeader(name: string, value: string): void;
|
||||
getHeader(name: string): string | undefined;
|
||||
hasHeader(name: string): boolean;
|
||||
@@ -2513,21 +2532,28 @@ declare module "http" {
|
||||
addTrailers(headers: OutgoingHttpHeaders | ReadonlyArray<[string, string]>): void;
|
||||
cork(): void;
|
||||
uncork(): void;
|
||||
setNoDelay(noDelay?: boolean): void;
|
||||
setSocketKeepAlive(enable?: boolean, initialDelay?: number): void;
|
||||
setTimeout(timeout: number, callback?: () => void): this;
|
||||
write(data: string | Uint8Array): void;
|
||||
end(data?: string | Uint8Array): void;
|
||||
destroy(): void;
|
||||
abort(): void;
|
||||
on(event: "response", listener: (res: IncomingMessage) => void): void;
|
||||
on(event: "socket", listener: (socket: Socket) => void): void;
|
||||
on(event: "upgrade", listener: (res: IncomingMessage, socket: Socket, head: Buffer) => void): void;
|
||||
on(event: "timeout" | "close", listener: () => void): void;
|
||||
on(event: "timeout" | "close" | "finish" | "abort", listener: () => void): void;
|
||||
on(event: "error", listener: (err: Error) => void): void;
|
||||
/* addListener IS on (Node aliases them) — the suite spells both. */
|
||||
addListener(event: "response", listener: (res: IncomingMessage) => void): void;
|
||||
addListener(event: "socket", listener: (socket: Socket) => void): void;
|
||||
addListener(event: "upgrade", listener: (res: IncomingMessage, socket: Socket, head: Buffer) => void): void;
|
||||
addListener(event: "timeout" | "close", listener: () => void): void;
|
||||
addListener(event: "timeout" | "close" | "finish" | "abort", listener: () => void): void;
|
||||
addListener(event: "error", listener: (err: Error) => void): void;
|
||||
once(event: "response", listener: (res: IncomingMessage) => void): void;
|
||||
once(event: "socket", listener: (socket: Socket) => void): void;
|
||||
once(event: "upgrade", listener: (res: IncomingMessage, socket: Socket, head: Buffer) => void): void;
|
||||
once(event: "timeout" | "close", listener: () => void): void;
|
||||
once(event: "timeout" | "close" | "finish" | "abort", listener: () => void): void;
|
||||
once(event: "error", listener: (err: Error) => void): void;
|
||||
}
|
||||
export function createServer(
|
||||
|
||||
@@ -6033,9 +6033,7 @@ function emitNetworkLibCall(state: LibCallState): Temp {
|
||||
const cb = args[1]!;
|
||||
emitter.moveTemp(cb);
|
||||
const adapter = cbT.params.length === 0 ? "scr_net_conn_thunk0" : "scr_net_conn_thunk_sock";
|
||||
const entry = e.fn === "net.serverOnConnection"
|
||||
? "scr_net_server_on_connection"
|
||||
: "scr_net_server_on_secure_connection";
|
||||
const entry = e.fn === "net.serverOnConnection" ? "scr_net_server_on_connection" : "scr_net_server_on_secure_connection";
|
||||
emitter.line(`${entry}(${arg(0)}, ${cb.name}, &${adapter}, ${arg(2)});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
@@ -6687,6 +6685,31 @@ function emitHttpLibCall(state: LibCallState): Temp {
|
||||
case "http.serverAllowMissingHostHeader":
|
||||
emitter.line(`scr_http_server_allow_missing_host_header(${arg(0)});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
case "http.serverSetTimeout":
|
||||
emitter.line(`scr_net_server_set_timeout_plain(${arg(0)}, ${arg(1)});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
case "http.serverCloseAllConnections":
|
||||
case "http.serverCloseIdleConnections": {
|
||||
const entry = e.fn === "http.serverCloseAllConnections"
|
||||
? "scr_net_server_close_all_connections" : "scr_net_server_close_idle_connections";
|
||||
emitter.line(`${entry}(${arg(0)});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
case "http.serverOnTimeout":
|
||||
case "http.serverSetTimeoutCb": {
|
||||
const cbIndex = e.fn === "http.serverSetTimeoutCb" ? 2 : 1;
|
||||
const cbT = e.args[cbIndex]!.type;
|
||||
if (cbT.kind !== "func") throw new InternalCompilerError(`emitter bug: ${e.fn} callback not a func`);
|
||||
const cb = args[cbIndex]!;
|
||||
emitter.moveTemp(cb);
|
||||
const adapter = cbT.params.length === 0 ? "scr_net_conn_thunk0" : "scr_net_conn_thunk_sock";
|
||||
const entry = e.fn === "http.serverOnTimeout" ? "scr_net_server_on_timeout" : "scr_net_server_set_timeout_cb";
|
||||
const callArgs = e.fn === "http.serverOnTimeout"
|
||||
? `${arg(0)}, ${cb.name}, &${adapter}, ${arg(2)}`
|
||||
: `${arg(0)}, ${arg(1)}, ${cb.name}, &${adapter}`;
|
||||
emitter.line(`${entry}(${callArgs});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
case "http.serverTimeoutGet":
|
||||
return finish(`scr_net_server_timeout_get(${arg(0)}, ${arg(1)})`);
|
||||
case "http.serverTimeoutSet":
|
||||
@@ -6787,6 +6810,14 @@ function emitHttpLibCall(state: LibCallState): Temp {
|
||||
return finish(`scr_http_res_write_head_dyn(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "http.reqSetEncoding":
|
||||
return finish(`scr_http_req_set_encoding(${arg(0)}, ${arg(1)})`);
|
||||
case "http.reqSetTimeout":
|
||||
return finish(`scr_http_req_set_timeout_plain(${arg(0)}, ${arg(1)})`);
|
||||
case "http.reqSetTimeoutCb": {
|
||||
const cb = args[2]!;
|
||||
emitter.moveTemp(cb);
|
||||
emitter.line(`scr_http_req_set_timeout(${arg(0)}, ${arg(1)}, ${cb.name});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
// node:http, the client slice (scr_http.c over the net client).
|
||||
case "http.request":
|
||||
case "http.requestCb": {
|
||||
@@ -7014,9 +7045,36 @@ function emitHttpLibCall(state: LibCallState): Temp {
|
||||
return finish(`scr_http_client_headers_sent(${arg(0)})`);
|
||||
case "http.clientWritableEnded":
|
||||
return finish(`scr_http_client_writable_ended(${arg(0)})`);
|
||||
case "http.clientWritableFinished":
|
||||
return finish(`scr_http_client_writable_finished(${arg(0)})`);
|
||||
case "http.clientSocket":
|
||||
return finish(`scr_http_client_socket(${arg(0)})`);
|
||||
case "http.clientReusedSocket":
|
||||
return finish(`scr_http_client_reused_socket(${arg(0)})`);
|
||||
case "http.clientSetNoDelay":
|
||||
return finish(`scr_http_client_set_nodelay(${arg(0)}, ${arg(1)})`);
|
||||
case "http.clientSetSocketKeepAlive":
|
||||
return finish(`scr_http_client_set_socket_keepalive(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "http.clientSetTimeout":
|
||||
return finish(`scr_http_client_set_timeout(${arg(0)}, ${arg(1)})`);
|
||||
case "http.clientSetTimeoutCb": {
|
||||
const cb = args[2]!;
|
||||
emitter.moveTemp(cb);
|
||||
emitter.line(`scr_http_client_set_timeout_cb(${arg(0)}, ${arg(1)}, ${cb.name});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
case "http.statusCodes":
|
||||
return finish("scr_http_status_codes()");
|
||||
case "http.methods":
|
||||
return finish("scr_http_methods()");
|
||||
case "http.clientDestroy":
|
||||
emitter.line(`scr_http_client_destroy(${arg(0)});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
case "http.clientAbort":
|
||||
emitter.line(`scr_http_client_abort(${arg(0)});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
case "http.clientAborted":
|
||||
return finish(`scr_http_client_aborted(${arg(0)})`);
|
||||
case "http.clientDestroyed":
|
||||
return finish(`scr_http_client_destroyed(${arg(0)})`);
|
||||
case "http.clientOnResponse": {
|
||||
@@ -7028,6 +7086,15 @@ function emitHttpLibCall(state: LibCallState): Temp {
|
||||
emitter.line(`scr_http_client_on_response(${arg(0)}, ${cb.name}, &${adapter}, ${arg(2)});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
case "http.clientOnSocket": {
|
||||
const cbT = e.args[1]!.type;
|
||||
if (cbT.kind !== "func") throw new InternalCompilerError("emitter bug: http.clientOnSocket callback not a func");
|
||||
const cb = args[1]!;
|
||||
emitter.moveTemp(cb);
|
||||
const adapter = cbT.params.length === 0 ? "scr_net_conn_thunk0" : "scr_net_conn_thunk_sock";
|
||||
emitter.line(`scr_http_client_on_socket(${arg(0)}, ${cb.name}, &${adapter}, ${arg(2)});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
case "http.clientOnError": {
|
||||
const cbT = e.args[1]!.type;
|
||||
if (cbT.kind !== "func") throw new InternalCompilerError("emitter bug: http.clientOnError callback not a func");
|
||||
@@ -7038,10 +7105,14 @@ function emitHttpLibCall(state: LibCallState): Temp {
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
case "http.clientOnTimeout":
|
||||
case "http.clientOnClose": {
|
||||
case "http.clientOnClose":
|
||||
case "http.clientOnFinish":
|
||||
case "http.clientOnAbort": {
|
||||
const cb = args[1]!;
|
||||
emitter.moveTemp(cb);
|
||||
const fn = e.fn === "http.clientOnTimeout" ? "scr_http_client_on_timeout" : "scr_http_client_on_close";
|
||||
const fn = e.fn === "http.clientOnTimeout" ? "scr_http_client_on_timeout"
|
||||
: e.fn === "http.clientOnClose" ? "scr_http_client_on_close"
|
||||
: e.fn === "http.clientOnAbort" ? "scr_http_client_on_abort" : "scr_http_client_on_finish";
|
||||
emitter.line(`${fn}(${arg(0)}, ${cb.name}, ${arg(2)});${emitter.srcComment(e.loc)}`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
|
||||
@@ -167,8 +167,8 @@ export function emitNetworkHttpLibCall(host: LlvmEmitterContext, e: LibCallExpr)
|
||||
e.fn === "net.serverOnClose" || e.fn === "net.serverOnListening" ||
|
||||
e.fn === "net.sockOnEnd" || e.fn === "net.sockOnClose" || e.fn === "net.sockOnConnect" ||
|
||||
e.fn === "net.sockOnTimeout" || e.fn === "net.sockOnReadable" ||
|
||||
e.fn === "http.reqOnEnd" || e.fn === "http.reqOnClose" || e.fn === "http.resOnClose" ||
|
||||
e.fn === "http.clientOnTimeout" || e.fn === "http.clientOnClose"
|
||||
e.fn === "http.reqOnEnd" || e.fn === "http.reqOnClose" || e.fn === "http.reqOnAborted" || e.fn === "http.resOnClose" ||
|
||||
e.fn === "http.clientOnTimeout" || e.fn === "http.clientOnClose" || e.fn === "http.clientOnFinish" || e.fn === "http.clientOnAbort"
|
||||
) {
|
||||
// Adapter-free registrations: (recv, cb /moves/, once).
|
||||
const entry = {
|
||||
@@ -181,9 +181,12 @@ export function emitNetworkHttpLibCall(host: LlvmEmitterContext, e: LibCallExpr)
|
||||
"net.sockOnReadable": "scr_net_sock_on_readable",
|
||||
"http.reqOnEnd": "scr_http_req_on_end",
|
||||
"http.reqOnClose": "scr_http_req_on_close",
|
||||
"http.reqOnAborted": "scr_http_req_on_aborted",
|
||||
"http.resOnClose": "scr_http_res_on_close",
|
||||
"http.clientOnTimeout": "scr_http_client_on_timeout",
|
||||
"http.clientOnClose": "scr_http_client_on_close",
|
||||
"http.clientOnFinish": "scr_http_client_on_finish",
|
||||
"http.clientOnAbort": "scr_http_client_on_abort",
|
||||
}[e.fn]!;
|
||||
const args = e.args.map((a) => host.emitExpr(a));
|
||||
host.moveTemp(args[1]!);
|
||||
@@ -191,15 +194,23 @@ export function emitNetworkHttpLibCall(host: LlvmEmitterContext, e: LibCallExpr)
|
||||
B.line(`call void @${entry}(ptr ${args[0]!.name}, ptr ${args[1]!.name}, i1 ${args[2]!.name})`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
if (e.fn === "net.serverOnConnection") {
|
||||
const cbT = e.args[1]!.type;
|
||||
if (cbT.kind !== "func") throw new InternalCompilerError("llvm emitter bug: net.serverOnConnection callback not a func");
|
||||
if (e.fn === "net.serverOnConnection" || e.fn === "http.serverOnTimeout" || e.fn === "http.serverSetTimeoutCb" || e.fn === "http.clientOnSocket") {
|
||||
const cbIndex = e.fn === "http.serverSetTimeoutCb" ? 2 : 1;
|
||||
const cbT = e.args[cbIndex]!.type;
|
||||
if (cbT.kind !== "func") throw new InternalCompilerError(`llvm emitter bug: ${e.fn} callback not a func`);
|
||||
const args = e.args.map((a) => host.emitExpr(a));
|
||||
host.moveTemp(args[1]!);
|
||||
host.moveTemp(args[cbIndex]!);
|
||||
const adapter = cbT.params.length === 0 ? "scr_net_conn_thunk0" : "scr_net_conn_thunk_sock";
|
||||
host.declare(`declare void @${adapter}(ptr, ptr)`);
|
||||
host.declare(`declare void @scr_net_server_on_connection(ptr, ptr, ptr, i1 zeroext)`);
|
||||
B.line(`call void @scr_net_server_on_connection(ptr ${args[0]!.name}, ptr ${args[1]!.name}, ptr @${adapter}, i1 ${args[2]!.name})`);
|
||||
if (e.fn === "http.serverSetTimeoutCb") {
|
||||
host.declare("declare void @scr_net_server_set_timeout_cb(ptr, double, ptr, ptr)");
|
||||
B.line(`call void @scr_net_server_set_timeout_cb(ptr ${args[0]!.name}, double ${args[1]!.name}, ptr ${args[2]!.name}, ptr @${adapter})`);
|
||||
} else {
|
||||
const entry = e.fn === "net.serverOnConnection" ? "scr_net_server_on_connection"
|
||||
: e.fn === "http.clientOnSocket" ? "scr_http_client_on_socket" : "scr_net_server_on_timeout";
|
||||
host.declare(`declare void @${entry}(ptr, ptr, ptr, i1 zeroext)`);
|
||||
B.line(`call void @${entry}(ptr ${args[0]!.name}, ptr ${args[1]!.name}, ptr @${adapter}, i1 ${args[2]!.name})`);
|
||||
}
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
if (e.fn === "net.connect" || e.fn === "net.connectCb") {
|
||||
@@ -431,11 +442,19 @@ export function emitNetworkHttpLibCall(host: LlvmEmitterContext, e: LibCallExpr)
|
||||
B.line(`call void @scr_http_res_on_finish(ptr ${args[0]!.name}, ptr ${args[1]!.name})`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
if (e.fn === "http.resSetTimeoutCb") {
|
||||
if (e.fn === "http.resSetTimeoutCb" || e.fn === "http.reqSetTimeoutCb") {
|
||||
const args = e.args.map((a) => host.emitExpr(a));
|
||||
host.moveTemp(args[2]!);
|
||||
host.declare(`declare void @scr_http_res_set_timeout(ptr, double, ptr)`);
|
||||
B.line(`call void @scr_http_res_set_timeout(ptr ${args[0]!.name}, double ${args[1]!.name}, ptr ${args[2]!.name})`);
|
||||
const entry = e.fn === "http.resSetTimeoutCb" ? "scr_http_res_set_timeout" : "scr_http_req_set_timeout";
|
||||
host.declare(`declare void @${entry}(ptr, double, ptr)`);
|
||||
B.line(`call void @${entry}(ptr ${args[0]!.name}, double ${args[1]!.name}, ptr ${args[2]!.name})`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
if (e.fn === "http.clientSetTimeoutCb") {
|
||||
const args = e.args.map((a) => host.emitExpr(a));
|
||||
host.moveTemp(args[2]!);
|
||||
host.declare("declare void @scr_http_client_set_timeout_cb(ptr, double, ptr)");
|
||||
B.line(`call void @scr_http_client_set_timeout_cb(ptr ${args[0]!.name}, double ${args[1]!.name}, ptr ${args[2]!.name})`);
|
||||
return { name: "", type: e.type };
|
||||
}
|
||||
if (e.fn === "net.sockOnFinish") {
|
||||
|
||||
@@ -666,6 +666,9 @@ export const LIB_FN_SYMS: Record<string, string> = {
|
||||
"http.serverJoinDupHeaders": "scr_http_server_join_duplicate_headers",
|
||||
"http.serverAllowMissingHostHeader": "scr_http_server_allow_missing_host_header",
|
||||
"http.serverTimeoutGet": "scr_net_server_timeout_get",
|
||||
"http.serverSetTimeout": "scr_net_server_set_timeout_plain",
|
||||
"http.serverCloseAllConnections": "scr_net_server_close_all_connections",
|
||||
"http.serverCloseIdleConnections": "scr_net_server_close_idle_connections",
|
||||
"http.serverTimeoutSet": "scr_net_server_timeout_set",
|
||||
"http.serverTimeoutOptionSet": "scr_net_server_timeout_option_set",
|
||||
"http.clientWrite": "scr_http_client_write_str",
|
||||
@@ -692,7 +695,18 @@ export const LIB_FN_SYMS: Record<string, string> = {
|
||||
"http.clientProtocol": "scr_http_client_protocol",
|
||||
"http.clientHeadersSent": "scr_http_client_headers_sent",
|
||||
"http.clientWritableEnded": "scr_http_client_writable_ended",
|
||||
"http.clientWritableFinished": "scr_http_client_writable_finished",
|
||||
"http.clientSocket": "scr_http_client_socket",
|
||||
"http.clientReusedSocket": "scr_http_client_reused_socket",
|
||||
"http.clientSetNoDelay": "scr_http_client_set_nodelay",
|
||||
"http.clientSetSocketKeepAlive": "scr_http_client_set_socket_keepalive",
|
||||
"http.clientSetTimeout": "scr_http_client_set_timeout",
|
||||
"http.statusCodes": "scr_http_status_codes",
|
||||
"http.methods": "scr_http_methods",
|
||||
"http.reqSetTimeout": "scr_http_req_set_timeout_plain",
|
||||
"http.clientDestroy": "scr_http_client_destroy",
|
||||
"http.clientAbort": "scr_http_client_abort",
|
||||
"http.clientAborted": "scr_http_client_aborted",
|
||||
"http.clientDestroyed": "scr_http_client_destroyed",
|
||||
"http2.streamUndefCall": "scr_http2_stream_undef_call",
|
||||
"http.agentNew": "scr_http_agent_new",
|
||||
|
||||
@@ -938,6 +938,12 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
if (bi.module === "module" && bi.member === "builtinModules") {
|
||||
return builtinModulesArrayLit(loc);
|
||||
}
|
||||
if (bi.module === "http" && bi.member === "METHODS") {
|
||||
return { kind: "libCall", fn: "http.methods", args: [], type: arrayOf(STRING), loc };
|
||||
}
|
||||
if (bi.module === "http" && bi.member === "STATUS_CODES") {
|
||||
return { kind: "libCall", fn: "http.statusCodes", args: [], type: DYN, loc };
|
||||
}
|
||||
// tls.rootCertificates: a runtime-valued module constant (the
|
||||
// cached bundled-CA array) — the one member read that lowers
|
||||
// to a libCall instead of a baked literal.
|
||||
|
||||
@@ -1031,6 +1031,26 @@ function lowerNetServerMethodCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
const name = access.name.text;
|
||||
const loc = locOf(call);
|
||||
const args = call.arguments;
|
||||
if (name === "setTimeout") {
|
||||
if (args.length < 1 || args.length > 2) lowerer.noLowering("server.setTimeout arguments", call, "pass milliseconds and an optional socket callback");
|
||||
const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
|
||||
const ms = lowerer.lowerExprExpecting(args[0]!, F64);
|
||||
const cb = args.length === 2
|
||||
? lowerCallbackArg(lowerer, args[1]!, "server timeout callbacks", 1,
|
||||
(p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]).cb
|
||||
: null;
|
||||
const fn: IrLibFn = cb === null ? "http.serverSetTimeout" : "http.serverSetTimeoutCb";
|
||||
const callArgs = cb === null ? [receiver, ms] : [receiver, ms, cb];
|
||||
if (resultIsDiscarded(call)) return { kind: "libCall", fn, args: callArgs, type: VOID, loc };
|
||||
return receiverReturningCall(lowerer, fn, callArgs, NETSERVER_T, loc);
|
||||
}
|
||||
if (name === "closeAllConnections" || name === "closeIdleConnections") {
|
||||
requireStatementPosition(lowerer, call, `server.${name}()`);
|
||||
if (args.length !== 0) lowerer.noLowering(`server.${name} arguments`, call, `${name}() takes no arguments`);
|
||||
const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
|
||||
const fn: IrLibFn = name === "closeAllConnections" ? "http.serverCloseAllConnections" : "http.serverCloseIdleConnections";
|
||||
return { kind: "libCall", fn, args: [receiver], type: VOID, loc };
|
||||
}
|
||||
if (name === "listen") {
|
||||
if (args.length < 1 || args.length > 3) {
|
||||
lowerer.noLowering(
|
||||
@@ -1280,6 +1300,11 @@ function lowerNetServerMethodCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
const { cb } = lowerCallbackArg(lowerer, args[1]!, "close listeners", 0, () => false, "use ()", []);
|
||||
return { kind: "libCall", fn: "net.serverOnClose", args: [receiver, cb, once], type: VOID, loc };
|
||||
}
|
||||
if (event === "timeout") {
|
||||
const { cb } = lowerCallbackArg(lowerer, args[1]!, "timeout listeners", 1,
|
||||
(p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
|
||||
return { kind: "libCall", fn: "http.serverOnTimeout", args: [receiver, cb, once], type: VOID, loc };
|
||||
}
|
||||
if (event === "listening") {
|
||||
// The deferred bind emit — listen(port, cb)'s event twin: fires
|
||||
// once after a successful listen; late registrations on an
|
||||
@@ -1773,6 +1798,17 @@ function trailersSnapshotHelper(lowerer: Lowerer, shapeId: string, loc: SrcLoc):
|
||||
});
|
||||
}
|
||||
|
||||
function distinctSnapshotHelper(lowerer: Lowerer, shapeId: string, loc: SrcLoc,
|
||||
collection: "headersDistinct" | "trailersDistinct",): string | null {
|
||||
return pairsSnapshotHelper(lowerer, shapeId, loc, {
|
||||
keyPrefix: collection,
|
||||
libCall: collection === "headersDistinct" ? "http.reqHeaderPairs" : "http.reqTrailerPairs",
|
||||
lookupValue: collection === "headersDistinct" ? "http.reqHeaderValues" : "http.reqTrailerValues",
|
||||
params: [{ localId: "r.0", name: "r", type: HTTPREQ_T }],
|
||||
callArgs: [varRef("r.0", HTTPREQ_T, loc)],
|
||||
});
|
||||
}
|
||||
|
||||
/** The `endStream` boolean of an h2 options object literal, as a literal
|
||||
* bool. Returns undefined when absent (or the arg is absent). Fences on
|
||||
* a non-literal endStream value or unknown keys that would matter. */
|
||||
@@ -2082,7 +2118,7 @@ export function lowerServerProperty(lowerer: Lowerer, expr: ts.PropertyAccessExp
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
|
||||
return { kind: "libCall", fn: "http.reqStatusCode", args: [receiver], type: lowerer.withUndefinedArm(F64), loc };
|
||||
}
|
||||
if (name === "socket") {
|
||||
if (name === "socket" || name === "connection") {
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
|
||||
return { kind: "libCall", fn: "http.reqSocket", args: [receiver], type: NETSOCKET_T, loc };
|
||||
}
|
||||
@@ -2152,15 +2188,15 @@ export function lowerServerProperty(lowerer: Lowerer, expr: ts.PropertyAccessExp
|
||||
"compatibility requests do not expose their backing h2 stream/session yet; guarded method calls no-op and other reads have no lowering",
|
||||
);
|
||||
}
|
||||
if (name === "headers" || name === "trailers") {
|
||||
// `req.headers` as a VALUE — the `{ ...req.headers }` spread and
|
||||
// record flows: a fresh snapshot record per read (Node's spread
|
||||
// copies too; the per-name READS keep their direct lowerings).
|
||||
if (name === "headers" || name === "trailers" || name === "headersDistinct" || name === "trailersDistinct") {
|
||||
// Whole-object reads materialize a typed snapshot record. Per-name
|
||||
// reads retain their direct lowerings.
|
||||
const mapped = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
||||
if (mapped?.kind === "record") {
|
||||
const helper = name === "headers"
|
||||
? headersSnapshotHelper(lowerer, mapped.shapeId, loc)
|
||||
: trailersSnapshotHelper(lowerer, mapped.shapeId, loc);
|
||||
: name === "trailers" ? trailersSnapshotHelper(lowerer, mapped.shapeId, loc)
|
||||
: distinctSnapshotHelper(lowerer, mapped.shapeId, loc, name);
|
||||
if (helper !== null) {
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPREQ_T);
|
||||
return { kind: "call", callee: helper, args: [receiver], type: mapped, loc };
|
||||
@@ -2172,9 +2208,6 @@ export function lowerServerProperty(lowerer: Lowerer, expr: ts.PropertyAccessExp
|
||||
`req.${name} as a value of this type (read one field: req.${name}.name or req.${name}[name])`,
|
||||
);
|
||||
}
|
||||
if (name === "headersDistinct" || name === "trailersDistinct") {
|
||||
lowerer.unsupported("SC1090", expr, `req.${name} as a value (read one name with req.${name}[name])`);
|
||||
}
|
||||
}
|
||||
if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "stream") {
|
||||
lowerer.noLowering(
|
||||
@@ -2246,6 +2279,11 @@ export function lowerServerProperty(lowerer: Lowerer, expr: ts.PropertyAccessExp
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
|
||||
return { kind: "libCall", fn: "http.clientDestroyed", args: [receiver], type: BOOL, loc };
|
||||
}
|
||||
if (recvKind === "httpClientReq" && lowerer.isStdlibMember(expr) &&
|
||||
(expr.name.text === "socket" || expr.name.text === "connection")) {
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
|
||||
return { kind: "libCall", fn: "http.clientSocket", args: [receiver], type: NETSOCKET_T, loc };
|
||||
}
|
||||
if (recvKind === "httpClientReq" && lowerer.isStdlibMember(expr) && expr.name.text === "writableCorked") {
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
|
||||
return { kind: "libCall", fn: "http.clientWritableCorked", args: [receiver], type: F64, loc };
|
||||
@@ -2260,8 +2298,11 @@ export function lowerServerProperty(lowerer: Lowerer, expr: ts.PropertyAccessExp
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
|
||||
return { kind: "libCall", fn: strFn, args: [receiver], type: STRING, loc };
|
||||
}
|
||||
const boolFn: IrLibFn | null = name === "headersSent" ? "http.clientHeadersSent"
|
||||
: name === "writableEnded" ? "http.clientWritableEnded" : null;
|
||||
const boolFn: IrLibFn | null = name === "aborted" ? "http.clientAborted"
|
||||
: name === "headersSent" ? "http.clientHeadersSent"
|
||||
: name === "writableEnded" || name === "finished" ? "http.clientWritableEnded"
|
||||
: name === "writableFinished" ? "http.clientWritableFinished"
|
||||
: name === "reusedSocket" ? "http.clientReusedSocket" : null;
|
||||
if (boolFn !== null) {
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPCLIENTREQ_T);
|
||||
return { kind: "libCall", fn: boolFn, args: [receiver], type: BOOL, loc };
|
||||
@@ -2285,6 +2326,10 @@ export function lowerServerProperty(lowerer: Lowerer, expr: ts.PropertyAccessExp
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
|
||||
return { kind: "libCall", fn: "http.resWritableEnded", args: [receiver], type: BOOL, loc };
|
||||
}
|
||||
if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "finished") {
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
|
||||
return { kind: "libCall", fn: "http.resWritableEnded", args: [receiver], type: BOOL, loc };
|
||||
}
|
||||
if (recvKind === "httpRes" && lowerer.isStdlibMember(expr) && expr.name.text === "writableCorked") {
|
||||
const receiver = coerceToHandle(lowerer, expr.expression, HTTPRES_T);
|
||||
return { kind: "libCall", fn: "http.resWritableCorked", args: [receiver], type: F64, loc };
|
||||
@@ -4333,6 +4378,33 @@ function lowerHttpClientMethodCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
: name === "cork" ? "http.clientCork" : "http.clientUncork";
|
||||
return { kind: "libCall", fn, args: [receiver], type: VOID, loc };
|
||||
}
|
||||
if (name === "setNoDelay") {
|
||||
requireStatementPosition(lowerer, call, "request.setNoDelay(...)");
|
||||
if (args.length > 1) lowerer.noLowering("request.setNoDelay arguments", call, "pass an optional boolean");
|
||||
const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
|
||||
const enable = args.length === 0 ? boolLit(true, loc) : lowerer.lowerExprExpecting(args[0]!, BOOL);
|
||||
return { kind: "libCall", fn: "http.clientSetNoDelay", args: [receiver, enable], type: VOID, loc };
|
||||
}
|
||||
if (name === "setSocketKeepAlive") {
|
||||
requireStatementPosition(lowerer, call, "request.setSocketKeepAlive(...)");
|
||||
if (args.length > 2) lowerer.noLowering("request.setSocketKeepAlive arguments", call, "pass an optional boolean and initial delay in milliseconds");
|
||||
const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
|
||||
const enable = args.length === 0 ? boolLit(true, loc) : lowerer.lowerExprExpecting(args[0]!, BOOL);
|
||||
const delay = args.length < 2 ? numLit(0, loc) : lowerer.lowerExprExpecting(args[1]!, F64);
|
||||
return { kind: "libCall", fn: "http.clientSetSocketKeepAlive", args: [receiver, enable, delay], type: VOID, loc };
|
||||
}
|
||||
if (name === "setTimeout") {
|
||||
if (args.length < 1 || args.length > 2) lowerer.noLowering("request.setTimeout arguments", call, "pass milliseconds and an optional callback");
|
||||
const receiver = coerceToHandle(lowerer, access.expression, HTTPCLIENTREQ_T);
|
||||
const ms = lowerer.lowerExprExpecting(args[0]!, F64);
|
||||
const cb = args.length === 2
|
||||
? lowerCallbackArg(lowerer, args[1]!, "request timeout callbacks", 0, () => false, "use ()", []).cb
|
||||
: null;
|
||||
const fn: IrLibFn = cb === null ? "http.clientSetTimeout" : "http.clientSetTimeoutCb";
|
||||
const callArgs = cb === null ? [receiver, ms] : [receiver, ms, cb];
|
||||
if (resultIsDiscarded(call)) return { kind: "libCall", fn, args: callArgs, type: VOID, loc };
|
||||
return receiverReturningCall(lowerer, fn, callArgs, HTTPCLIENTREQ_T, loc);
|
||||
}
|
||||
if (name === "addTrailers") {
|
||||
requireStatementPosition(lowerer, call, "request.addTrailers(...)");
|
||||
if (args.length !== 1) lowerer.noLowering("request.addTrailers argument count", call, "pass one trailer object or pair-list literal");
|
||||
@@ -4370,13 +4442,13 @@ function lowerHttpClientMethodCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
}
|
||||
lowerer.noLowering(`${name} of '${lowerer.fmt(data.type)}' data`, args[0] ?? call, NARROW_DATA_HINT);
|
||||
}
|
||||
if (name === "destroy") {
|
||||
requireStatementPosition(lowerer, call, "request.destroy()");
|
||||
if (name === "destroy" || name === "abort") {
|
||||
requireStatementPosition(lowerer, call, `request.${name}()`);
|
||||
if (args.length !== 0) {
|
||||
lowerer.noLowering(`destroy with ${args.length} arguments`, call, "destroy() takes no arguments here");
|
||||
lowerer.noLowering(`${name} with ${args.length} arguments`, call, `${name}() takes no arguments here`);
|
||||
}
|
||||
const receiver = lowerer.lowerExpr(access.expression);
|
||||
return { kind: "libCall", fn: "http.clientDestroy", args: [receiver], type: VOID, loc };
|
||||
return { kind: "libCall", fn: name === "destroy" ? "http.clientDestroy" : "http.clientAbort", args: [receiver], type: VOID, loc };
|
||||
}
|
||||
if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
|
||||
requireStatementPosition(lowerer, call, `request.${name}(...)`);
|
||||
@@ -4393,6 +4465,11 @@ function lowerHttpClientMethodCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
);
|
||||
return { kind: "libCall", fn: "http.clientOnResponse", args: [receiver, cb, once], type: VOID, loc };
|
||||
}
|
||||
if (event === "socket") {
|
||||
const { cb } = lowerCallbackArg(lowerer, args[1]!, "socket listeners", 1,
|
||||
(p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
|
||||
return { kind: "libCall", fn: "http.clientOnSocket", args: [receiver, cb, once], type: VOID, loc };
|
||||
}
|
||||
if (event === "error") {
|
||||
const { cb } = lowerCallbackArg(
|
||||
lowerer, args[1]!, "error listeners", 1,
|
||||
@@ -4402,9 +4479,11 @@ function lowerHttpClientMethodCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
);
|
||||
return { kind: "libCall", fn: "http.clientOnError", args: [receiver, cb, once], type: VOID, loc };
|
||||
}
|
||||
if (event === "timeout" || event === "close") {
|
||||
if (event === "timeout" || event === "close" || event === "finish" || event === "abort") {
|
||||
const { cb } = lowerCallbackArg(lowerer, args[1]!, `${event} listeners`, 0, () => false, "use ()", []);
|
||||
const fn: IrLibFn = event === "timeout" ? "http.clientOnTimeout" : "http.clientOnClose";
|
||||
const fn: IrLibFn = event === "timeout" ? "http.clientOnTimeout"
|
||||
: event === "close" ? "http.clientOnClose"
|
||||
: event === "abort" ? "http.clientOnAbort" : "http.clientOnFinish";
|
||||
return { kind: "libCall", fn, args: [receiver, cb, once], type: VOID, loc };
|
||||
}
|
||||
if (event === "upgrade") {
|
||||
@@ -4443,7 +4522,7 @@ function lowerHttpClientMethodCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
lowerer.noLowering(
|
||||
`request.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`,
|
||||
args[0]!,
|
||||
'"response", "upgrade", "error", "timeout", and "close" are the supported request events (as literals)',
|
||||
'"response", "socket", "upgrade", "error", "timeout", "finish", "abort", and "close" are the supported request events (as literals)',
|
||||
);
|
||||
}
|
||||
lowerer.noLowering(
|
||||
@@ -4548,6 +4627,15 @@ function lowerHttpReqMethodCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
const name = access.name.text;
|
||||
const loc = locOf(call);
|
||||
const args = call.arguments;
|
||||
if (name === "setTimeout") {
|
||||
requireStatementPosition(lowerer, call, "message.setTimeout(...)");
|
||||
if (args.length < 1 || args.length > 2) lowerer.noLowering("message.setTimeout arguments", call, "pass milliseconds and an optional callback");
|
||||
const receiver = coerceToHandle(lowerer, access.expression, HTTPREQ_T);
|
||||
const ms = lowerer.lowerExprExpecting(args[0]!, F64);
|
||||
if (args.length === 1) return { kind: "libCall", fn: "http.reqSetTimeout", args: [receiver, ms], type: VOID, loc };
|
||||
const { cb } = lowerCallbackArg(lowerer, args[1]!, "message timeout callbacks", 0, () => false, "use ()", []);
|
||||
return { kind: "libCall", fn: "http.reqSetTimeoutCb", args: [receiver, ms, cb], type: VOID, loc };
|
||||
}
|
||||
if (name === "resume" || name === "destroy") {
|
||||
requireStatementPosition(lowerer, call, `req.${name}()`);
|
||||
if (args.length !== 0) {
|
||||
@@ -4999,10 +5087,14 @@ function lowerHttpResMethodCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
const { cb } = lowerCallbackArg(lowerer, args[1]!, "close listeners", 0, () => false, "use ()", []);
|
||||
return { kind: "libCall", fn: "http.resOnClose", args: [receiver, cb, once], type: VOID, loc };
|
||||
}
|
||||
if (event === "finish") {
|
||||
const { cb } = lowerCallbackArg(lowerer, args[1]!, "finish listeners", 0, () => false, "use ()", []);
|
||||
return { kind: "libCall", fn: "http.resOnFinish", args: [receiver, cb], type: VOID, loc };
|
||||
}
|
||||
lowerer.noLowering(
|
||||
`res.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`,
|
||||
args[0]!,
|
||||
'"close" is the supported response event (as a literal)',
|
||||
'"close" and "finish" are the supported response events (as literals)',
|
||||
);
|
||||
}
|
||||
lowerer.noLowering(
|
||||
|
||||
@@ -10141,6 +10141,12 @@ export class Lowerer {
|
||||
if (bi.module === "module" && bi.member === "builtinModules") {
|
||||
return builtinModulesArrayLit(loc);
|
||||
}
|
||||
if (bi.module === "http" && bi.member === "METHODS") {
|
||||
return { kind: "libCall", fn: "http.methods", args: [], type: arrayOf(STRING), loc };
|
||||
}
|
||||
if (bi.module === "http" && bi.member === "STATUS_CODES") {
|
||||
return { kind: "libCall", fn: "http.statusCodes", args: [], type: DYN, loc };
|
||||
}
|
||||
// tls.rootCertificates through the namespace: the same runtime-valued
|
||||
// constant the named-import read lowers to.
|
||||
{
|
||||
|
||||
@@ -3,7 +3,8 @@ import { numLit, varRef } from "../../ir/build.js";
|
||||
import type { Lowerer } from "./lowerer.js";
|
||||
|
||||
/** Intern a helper that materializes a pure string-index record from a flat
|
||||
* `[key, value, ...]` array returned by a runtime call. */
|
||||
* `[key, value, ...]` array. Distinct HTTP records use the pair keys and
|
||||
* look up each key's full string[] value. */
|
||||
export function pairsSnapshotHelper(
|
||||
lowerer: Lowerer,
|
||||
shapeId: string,
|
||||
@@ -14,6 +15,7 @@ export function pairsSnapshotHelper(
|
||||
params?: IrParam[];
|
||||
callArgs?: IrExpr[];
|
||||
indexValueOk?: (indexValue: IrType) => boolean;
|
||||
lookupValue?: "http.reqHeaderValues" | "http.reqTrailerValues";
|
||||
},
|
||||
): string | null {
|
||||
const shape = lowerer.shapes.get(shapeId);
|
||||
@@ -21,8 +23,11 @@ export function pairsSnapshotHelper(
|
||||
const indexValue = shape.indexValue;
|
||||
if (options.indexValueOk && !options.indexValueOk(indexValue)) return null;
|
||||
if (indexValue.kind !== "union") return null;
|
||||
const stringTag = lowerer.armTag(indexValue.unionId, STRING);
|
||||
if (stringTag < 0) return null;
|
||||
const stringTag = options.lookupValue ? -1 : lowerer.armTag(indexValue.unionId, STRING);
|
||||
if (options.lookupValue) {
|
||||
const arrayValue = lowerer.withUndefinedArm(arrayOf(STRING));
|
||||
if (arrayValue.kind !== "union" || indexValue.unionId !== arrayValue.unionId) return null;
|
||||
} else if (stringTag < 0) return null;
|
||||
const key = `${options.keyPrefix}.snapshot:${shapeId}`;
|
||||
const existing = lowerer.widthHelpers.get(key);
|
||||
if (existing) return existing;
|
||||
@@ -80,7 +85,9 @@ export function pairsSnapshotHelper(
|
||||
obj: varRef("out.0", recordType, loc),
|
||||
shapeId,
|
||||
key: pairAt(0),
|
||||
value: { kind: "unionWrap", unionId: indexValue.unionId, tag: stringTag, value: pairAt(1), type: indexValue, loc },
|
||||
value: options.lookupValue
|
||||
? { kind: "libCall", fn: options.lookupValue, args: [...(options.callArgs ?? []), pairAt(0)], type: indexValue, loc }
|
||||
: { kind: "unionWrap", unionId: indexValue.unionId, tag: stringTag, value: pairAt(1), type: indexValue, loc },
|
||||
loc,
|
||||
}],
|
||||
loc,
|
||||
|
||||
@@ -938,6 +938,7 @@ export const BUILTIN_MODULE_FNS: Record<string, Record<string, BuiltinModuleFn |
|
||||
* thread machinery) and never runs as a cluster worker (cluster forks the
|
||||
* node binary itself) — Node's own answers for a directly-run script. */
|
||||
export const BUILTIN_MODULE_CONSTS: Record<string, Record<string, string | number | boolean | undefined> | undefined> = {
|
||||
http: { maxHeaderSize: 16384 },
|
||||
path: { sep: "/", delimiter: ":" },
|
||||
"path/posix": { sep: "/", delimiter: ":" },
|
||||
"path/win32": { sep: "\\", delimiter: ";" },
|
||||
|
||||
@@ -3561,8 +3561,17 @@ function mapRecordTypeInner(widened: ts.Type, ctx: TypeMapperCtx): IrType | Reco
|
||||
const armOk = (a: IrType): boolean =>
|
||||
a.kind === "f64" || a.kind === "string" || a.kind === "undefinedT" ||
|
||||
(a.kind === "array" && a.elem.kind === "string");
|
||||
// A pure Dict<string[]> is the distinct-header shape, not a general
|
||||
// outgoing-header slot: retain its precise string[] | undefined value
|
||||
// so reads from a materialized headersDistinct/trailersDistinct record
|
||||
// can use array methods without an assertion.
|
||||
const distinctOnly = slotDef !== undefined &&
|
||||
checker.getPropertiesOfType(widened).length === 0 &&
|
||||
slotDef.arms.length === 2 &&
|
||||
slotDef.arms.some((a) => a.kind === "array" && a.elem.kind === "string") &&
|
||||
slotDef.arms.some((a) => a.kind === "undefinedT");
|
||||
if (
|
||||
slotDef !== undefined &&
|
||||
slotDef !== undefined && !distinctOnly &&
|
||||
slotDef.arms.some((a) => a.kind === "array" && a.elem.kind === "string") &&
|
||||
slotDef.arms.every(armOk)
|
||||
) {
|
||||
|
||||
@@ -2752,6 +2752,11 @@ export type IrLibFn =
|
||||
* The constructor-option setter takes dyn so explicit undefined remains
|
||||
* distinguishable from a numeric value until its Node validation ladder. */
|
||||
| "http.serverTimeoutGet"
|
||||
| "http.serverSetTimeout"
|
||||
| "http.serverSetTimeoutCb"
|
||||
| "http.serverOnTimeout"
|
||||
| "http.serverCloseAllConnections"
|
||||
| "http.serverCloseIdleConnections"
|
||||
| "http.serverTimeoutSet"
|
||||
| "http.serverTimeoutOptionSet"
|
||||
/** server.on("listening", cb) — the deferred listen-callback list. */
|
||||
@@ -3212,17 +3217,33 @@ export type IrLibFn =
|
||||
| "http.clientProtocol"
|
||||
| "http.clientHeadersSent"
|
||||
| "http.clientWritableEnded"
|
||||
| "http.clientWritableFinished"
|
||||
| "http.clientSocket"
|
||||
| "http.clientReusedSocket"
|
||||
| "http.clientSetNoDelay"
|
||||
| "http.clientSetSocketKeepAlive"
|
||||
| "http.clientSetTimeout"
|
||||
| "http.clientSetTimeoutCb"
|
||||
| "http.statusCodes"
|
||||
| "http.methods"
|
||||
| "http.reqSetTimeout"
|
||||
| "http.reqSetTimeoutCb"
|
||||
/** request/get with a URL-STRING first argument: the runtime parses it
|
||||
* (WHATWG) and dials — throws catchably on an unparsable input or a
|
||||
* non-http scheme. */
|
||||
| "http.requestUrl"
|
||||
| "http.requestUrlCb"
|
||||
| "http.clientDestroy"
|
||||
| "http.clientAbort"
|
||||
| "http.clientAborted"
|
||||
| "http.clientDestroyed"
|
||||
| "http.clientOnResponse"
|
||||
| "http.clientOnSocket"
|
||||
| "http.clientOnFinish"
|
||||
| "http.clientOnError"
|
||||
| "http.clientOnTimeout"
|
||||
| "http.clientOnClose"
|
||||
| "http.clientOnAbort"
|
||||
/** fs/promises (scr_lib.c over scr_async.c's settled minting): the SAME
|
||||
* sync syscalls, wrapped in an ALREADY-SETTLED promise — failure
|
||||
* REJECTS (catchable at the await) instead of throwing, so none of
|
||||
|
||||
@@ -509,6 +509,11 @@ export const LIB_FN_SIGS: Record<IrLibFn, { argTypes: (IrType | null)[]; result:
|
||||
"http.serverJoinDupHeaders": { argTypes: [NETSERVER_T], result: VOID },
|
||||
"http.serverAllowMissingHostHeader": { argTypes: [NETSERVER_T], result: VOID },
|
||||
"http.serverTimeoutGet": { argTypes: [NETSERVER_T, F64], result: F64 },
|
||||
"http.serverSetTimeout": { argTypes: [NETSERVER_T, F64], result: VOID },
|
||||
"http.serverSetTimeoutCb": { argTypes: [NETSERVER_T, F64, null], result: VOID },
|
||||
"http.serverOnTimeout": { argTypes: [NETSERVER_T, null, BOOL], result: VOID },
|
||||
"http.serverCloseAllConnections": { argTypes: [NETSERVER_T], result: VOID },
|
||||
"http.serverCloseIdleConnections": { argTypes: [NETSERVER_T], result: VOID },
|
||||
"http.serverTimeoutSet": { argTypes: [NETSERVER_T, F64, F64], result: VOID },
|
||||
"http.serverTimeoutOptionSet": { argTypes: [NETSERVER_T, F64, DYN], result: VOID },
|
||||
"net.serverOnListening": { argTypes: [NETSERVER_T, { kind: "func", params: [], ret: VOID }, BOOL], result: VOID },
|
||||
@@ -785,12 +790,28 @@ export const LIB_FN_SIGS: Record<IrLibFn, { argTypes: (IrType | null)[]; result:
|
||||
"http.clientProtocol": { argTypes: [HTTPCLIENTREQ_T], result: STRING },
|
||||
"http.clientHeadersSent": { argTypes: [HTTPCLIENTREQ_T], result: BOOL },
|
||||
"http.clientWritableEnded": { argTypes: [HTTPCLIENTREQ_T], result: BOOL },
|
||||
"http.clientWritableFinished": { argTypes: [HTTPCLIENTREQ_T], result: BOOL },
|
||||
"http.clientSocket": { argTypes: [HTTPCLIENTREQ_T], result: NETSOCKET_T },
|
||||
"http.clientReusedSocket": { argTypes: [HTTPCLIENTREQ_T], result: BOOL },
|
||||
"http.clientSetNoDelay": { argTypes: [HTTPCLIENTREQ_T, BOOL], result: VOID },
|
||||
"http.clientSetSocketKeepAlive": { argTypes: [HTTPCLIENTREQ_T, BOOL, F64], result: VOID },
|
||||
"http.clientSetTimeout": { argTypes: [HTTPCLIENTREQ_T, F64], result: VOID },
|
||||
"http.clientSetTimeoutCb": { argTypes: [HTTPCLIENTREQ_T, F64, { kind: "func", params: [], ret: VOID }], result: VOID },
|
||||
"http.statusCodes": { argTypes: [], result: DYN },
|
||||
"http.methods": { argTypes: [], result: arrayOf(STRING) },
|
||||
"http.reqSetTimeout": { argTypes: [HTTPREQ_T, F64], result: VOID },
|
||||
"http.reqSetTimeoutCb": { argTypes: [HTTPREQ_T, F64, { kind: "func", params: [], ret: VOID }], result: VOID },
|
||||
"http.clientDestroy": { argTypes: [HTTPCLIENTREQ_T], result: VOID },
|
||||
"http.clientAbort": { argTypes: [HTTPCLIENTREQ_T], result: VOID },
|
||||
"http.clientAborted": { argTypes: [HTTPCLIENTREQ_T], result: BOOL },
|
||||
"http.clientDestroyed": { argTypes: [HTTPCLIENTREQ_T], result: BOOL },
|
||||
"http.clientOnResponse": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID },
|
||||
"http.clientOnSocket": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID },
|
||||
"http.clientOnFinish": { argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], result: VOID },
|
||||
"http.clientOnError": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID },
|
||||
"http.clientOnTimeout": { argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], result: VOID },
|
||||
"http.clientOnClose": { argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], result: VOID },
|
||||
"http.clientOnAbort": { argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], result: VOID },
|
||||
"cp.execSync": {
|
||||
argTypes: [STRING, arrayOf(STRING), BOOL, STRING, BOOL, STRING, BOOL, arrayOf(STRING), F64, F64, F64],
|
||||
result: STRING,
|
||||
@@ -4301,13 +4322,15 @@ function validateFunction(
|
||||
}
|
||||
if (e.fn === "net.createServerCb" || e.fn === "net.serverOnConnection" ||
|
||||
e.fn === "net.serverOnSecureConnection" ||
|
||||
e.fn === "http.serverSetTimeoutCb" || e.fn === "http.serverOnTimeout" ||
|
||||
e.fn === "http.clientOnSocket" ||
|
||||
e.fn === "net.sockOnData" || e.fn === "net.serverOnError" ||
|
||||
e.fn === "net.sockOnError") {
|
||||
// The program-dependent listener shapes: a void closure with no
|
||||
// params, or exactly the one supported parameter per event
|
||||
// (socket handle / data chunk bytes / error %Error). The
|
||||
// callback slot is arg 0 for createServerCb, arg 1 otherwise.
|
||||
const cbT = e.args[e.fn === "net.createServerCb" ? 0 : 1]?.type;
|
||||
const cbT = e.args[e.fn === "net.createServerCb" ? 0 : e.fn === "http.serverSetTimeoutCb" ? 2 : 1]?.type;
|
||||
let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
|
||||
if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
|
||||
const p = cbT.params[0]!;
|
||||
|
||||
@@ -1123,6 +1123,13 @@
|
||||
"status": "static",
|
||||
"note": "recognized module (bare and node:-prefixed specifiers)"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.http.maxHeaderSize",
|
||||
"kind": "node-builtin",
|
||||
"name": "http.maxHeaderSize",
|
||||
"status": "static",
|
||||
"note": "constant value read"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.http2",
|
||||
"kind": "node-builtin",
|
||||
|
||||
@@ -391,7 +391,7 @@ exit 99
|
||||
expect(invocations.some((line) => /^cc .*vendor.*zlib/.test(line))).toBe(true);
|
||||
expect(invocations.some((line) => /^ar rcs .*libqjs\.a/.test(line))).toBe(true);
|
||||
expect(invocations.some((line) => /^ar rcs .*libmbedtls\.a/.test(line))).toBe(true);
|
||||
expect(invocations.some((line) => line.includes("-lz"))).toBe(false);
|
||||
expect(invocations.some((line) => /(?:^|\s)-lz(?:\s|$)/.test(line))).toBe(false);
|
||||
expect(await readFile(unexpectedToolPath).catch(() => "")).toBe("");
|
||||
} finally {
|
||||
if (oldPath === undefined) delete process.env["PATH"];
|
||||
|
||||
@@ -6685,12 +6685,24 @@
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2972-http-static-distinct-snapshots.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2972-http-static-distinct-snapshots.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2972-math-receiver-borrow.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2972-math-receiver-borrow.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2973-http-static-agent.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2973-http-static-agent.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2973-integer-bitwise-arithmetic.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2973-integer-bitwise-arithmetic.ts"
|
||||
@@ -6703,6 +6715,12 @@
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2974-http-static-module-values.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2974-http-static-module-values.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2974-numeric-remainder.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2974-numeric-remainder.ts"
|
||||
@@ -6715,18 +6733,42 @@
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2975-http-static-client-controls.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2975-http-static-client-controls.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2976-http-static-incoming-state.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2976-http-static-incoming-state.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2976-json-stringify-no-arguments.js": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2976-json-stringify-no-arguments.js"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2977-http-static-incoming-timeout.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2977-http-static-incoming-timeout.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2977-nested-array-binding-defaults.js": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2977-nested-array-binding-defaults.js"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2978-http-static-client-timeout.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2978-http-static-client-timeout.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2978-regexp-optional-subject.js": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2978-regexp-optional-subject.js"
|
||||
@@ -6739,6 +6781,78 @@
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2979-http-static-server-timeout.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2979-http-static-server-timeout.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2980-http-static-server-timeout-default.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2980-http-static-server-timeout-default.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2981-http-static-events.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2981-http-static-events.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2982-http-static-close-all.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2982-http-static-close-all.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2983-http-static-close-idle.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2983-http-static-close-idle.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2984-http-static-close-upgrade.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2984-http-static-close-upgrade.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2985-http-static-message-destroy.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2985-http-static-message-destroy.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2986-http-static-client-socket-finish.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2986-http-static-client-socket-finish.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2987-http-static-timeout-errors.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2987-http-static-timeout-errors.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2988-http-static-client-abort.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2988-http-static-client-abort.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2989-http-static-response-timeout-handled.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2989-http-static-response-timeout-handled.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/2990-http-static-request-timeout-handled.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/2990-http-static-request-timeout-handled.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/300-if-else.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/300-if-else.ts"
|
||||
|
||||
+312
-52
@@ -66,44 +66,107 @@ static void scr_http_oom(void) {
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Node's STATUS_CODES reason phrases (the slice's subset; everything the
|
||||
* fixtures and portless's handlers send, plus the common neighbors). */
|
||||
static bool scr_http_timeout_valid(double ms) {
|
||||
if (isfinite(ms) && ms >= 0) return true;
|
||||
char recv[48], msg[176];
|
||||
scr_num_received(ms, recv);
|
||||
int len = snprintf(msg, sizeof msg,
|
||||
"The value of \"msecs\" is out of range. It must be a non-negative finite number. Received %s", recv);
|
||||
scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Node v24.15.0's STATUS_CODES table, shared by the module export and the
|
||||
* default ServerResponse reason phrase. */
|
||||
static const struct { int code; const char *reason; } scr_http_status_codes_table[] = {
|
||||
{100, "Continue"}, {101, "Switching Protocols"}, {102, "Processing"},
|
||||
{103, "Early Hints"}, {200, "OK"}, {201, "Created"}, {202, "Accepted"},
|
||||
{203, "Non-Authoritative Information"}, {204, "No Content"},
|
||||
{205, "Reset Content"}, {206, "Partial Content"}, {207, "Multi-Status"},
|
||||
{208, "Already Reported"}, {226, "IM Used"}, {300, "Multiple Choices"},
|
||||
{301, "Moved Permanently"}, {302, "Found"}, {303, "See Other"},
|
||||
{304, "Not Modified"}, {305, "Use Proxy"}, {307, "Temporary Redirect"},
|
||||
{308, "Permanent Redirect"}, {400, "Bad Request"}, {401, "Unauthorized"},
|
||||
{402, "Payment Required"}, {403, "Forbidden"}, {404, "Not Found"},
|
||||
{405, "Method Not Allowed"}, {406, "Not Acceptable"},
|
||||
{407, "Proxy Authentication Required"}, {408, "Request Timeout"},
|
||||
{409, "Conflict"}, {410, "Gone"}, {411, "Length Required"},
|
||||
{412, "Precondition Failed"}, {413, "Payload Too Large"},
|
||||
{414, "URI Too Long"}, {415, "Unsupported Media Type"},
|
||||
{416, "Range Not Satisfiable"}, {417, "Expectation Failed"},
|
||||
{418, "I'm a Teapot"}, {421, "Misdirected Request"},
|
||||
{422, "Unprocessable Entity"}, {423, "Locked"},
|
||||
{424, "Failed Dependency"}, {425, "Too Early"},
|
||||
{426, "Upgrade Required"}, {428, "Precondition Required"},
|
||||
{429, "Too Many Requests"}, {431, "Request Header Fields Too Large"},
|
||||
{451, "Unavailable For Legal Reasons"}, {500, "Internal Server Error"},
|
||||
{501, "Not Implemented"}, {502, "Bad Gateway"},
|
||||
{503, "Service Unavailable"}, {504, "Gateway Timeout"},
|
||||
{505, "HTTP Version Not Supported"}, {506, "Variant Also Negotiates"},
|
||||
{507, "Insufficient Storage"}, {508, "Loop Detected"},
|
||||
{509, "Bandwidth Limit Exceeded"}, {510, "Not Extended"},
|
||||
{511, "Network Authentication Required"},
|
||||
};
|
||||
|
||||
static const char *scr_http_reason(int code) {
|
||||
switch (code) {
|
||||
case 100: return "Continue";
|
||||
case 101: return "Switching Protocols";
|
||||
case 200: return "OK";
|
||||
case 201: return "Created";
|
||||
case 202: return "Accepted";
|
||||
case 204: return "No Content";
|
||||
case 206: return "Partial Content";
|
||||
case 301: return "Moved Permanently";
|
||||
case 302: return "Found";
|
||||
case 303: return "See Other";
|
||||
case 304: return "Not Modified";
|
||||
case 307: return "Temporary Redirect";
|
||||
case 308: return "Permanent Redirect";
|
||||
case 400: return "Bad Request";
|
||||
case 401: return "Unauthorized";
|
||||
case 403: return "Forbidden";
|
||||
case 404: return "Not Found";
|
||||
case 405: return "Method Not Allowed";
|
||||
case 408: return "Request Timeout";
|
||||
case 409: return "Conflict";
|
||||
case 410: return "Gone";
|
||||
case 413: return "Payload Too Large";
|
||||
case 414: return "URI Too Long";
|
||||
case 415: return "Unsupported Media Type";
|
||||
case 429: return "Too Many Requests";
|
||||
case 431: return "Request Header Fields Too Large";
|
||||
case 500: return "Internal Server Error";
|
||||
case 501: return "Not Implemented";
|
||||
case 502: return "Bad Gateway";
|
||||
case 503: return "Service Unavailable";
|
||||
case 504: return "Gateway Timeout";
|
||||
case 508: return "Loop Detected";
|
||||
default: return "unknown";
|
||||
for (size_t i = 0; i < sizeof scr_http_status_codes_table / sizeof scr_http_status_codes_table[0]; i++) {
|
||||
if (scr_http_status_codes_table[i].code == code) return scr_http_status_codes_table[i].reason;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static ScrDyn *scr_http_status_codes_value;
|
||||
|
||||
static void scr_http_status_codes_cleanup(void) {
|
||||
scr_dyn_release(scr_http_status_codes_value);
|
||||
scr_http_status_codes_value = NULL;
|
||||
}
|
||||
|
||||
ScrDyn *scr_http_status_codes(void) {
|
||||
if (!scr_http_status_codes_value) {
|
||||
ScrDyn *codes = scr_dyn_new_obj();
|
||||
for (size_t i = 0; i < sizeof scr_http_status_codes_table / sizeof scr_http_status_codes_table[0]; i++) {
|
||||
const int code = scr_http_status_codes_table[i].code;
|
||||
const char *reason = scr_http_status_codes_table[i].reason;
|
||||
char key[4];
|
||||
const int key_len = snprintf(key, sizeof key, "%d", code);
|
||||
ScrStr *value = scr_str_new(reason, strlen(reason));
|
||||
scr_dyn_obj_set(codes, key, (size_t)key_len, scr_dyn_new_str(value));
|
||||
scr_str_release(value);
|
||||
}
|
||||
scr_http_status_codes_value = codes;
|
||||
atexit(scr_http_status_codes_cleanup);
|
||||
}
|
||||
return scr_dyn_retain(scr_http_status_codes_value);
|
||||
}
|
||||
|
||||
static const char *const scr_http_methods_table[] = {
|
||||
"ACL", "BIND", "CHECKOUT", "CONNECT", "COPY", "DELETE", "GET", "HEAD",
|
||||
"LINK", "LOCK", "M-SEARCH", "MERGE", "MKACTIVITY", "MKCALENDAR",
|
||||
"MKCOL", "MOVE", "NOTIFY", "OPTIONS", "PATCH", "POST", "PROPFIND",
|
||||
"PROPPATCH", "PURGE", "PUT", "QUERY", "REBIND", "REPORT", "SEARCH",
|
||||
"SOURCE", "SUBSCRIBE", "TRACE", "UNBIND", "UNLINK", "UNLOCK", "UNSUBSCRIBE",
|
||||
};
|
||||
|
||||
static ScrArr *scr_http_methods_value;
|
||||
|
||||
static void scr_http_methods_cleanup(void) {
|
||||
scr_arr_release(scr_http_methods_value);
|
||||
scr_http_methods_value = NULL;
|
||||
}
|
||||
|
||||
ScrArr *scr_http_methods(void) {
|
||||
if (!scr_http_methods_value) {
|
||||
const size_t n = sizeof scr_http_methods_table / sizeof scr_http_methods_table[0];
|
||||
ScrArr *methods = scr_arr_new(SCR_ELEM_STR, n);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
const char *name = scr_http_methods_table[i];
|
||||
scr_arr_push_ref(methods, scr_str_new(name, strlen(name)));
|
||||
}
|
||||
scr_http_methods_value = methods;
|
||||
atexit(scr_http_methods_cleanup);
|
||||
}
|
||||
return scr_arr_retain(scr_http_methods_value);
|
||||
}
|
||||
|
||||
/* ── the h2 compat transport seam ────────────────────────────────────────
|
||||
@@ -156,7 +219,7 @@ struct ScrHttpReq {
|
||||
ScrStr **tvalues;
|
||||
size_t ntrailers;
|
||||
ScrStr *status_msg; /* client responses' reason phrase; NULL on server requests */
|
||||
ScrNetLs data_ls, end_ls, err_ls, close_ls;
|
||||
ScrNetLs data_ls, end_ls, err_ls, close_ls, timeout_ls;
|
||||
/* pipe destinations (req.pipe(...) — one of each kind, +1; released at
|
||||
* finish, so a piped destination never outlives the body) */
|
||||
ScrHttpRes *pipe_res;
|
||||
@@ -247,6 +310,7 @@ void scr_http_req_release(ScrHttpReq *r) {
|
||||
scr_net_ls_drop(&r->end_ls);
|
||||
scr_net_ls_drop(&r->err_ls);
|
||||
scr_net_ls_drop(&r->close_ls);
|
||||
scr_net_ls_drop(&r->timeout_ls);
|
||||
scr_net_ls_drop(&r->aborted_ls);
|
||||
scr_http_res_release(r->pipe_res);
|
||||
scr_http_client_release(r->pipe_client);
|
||||
@@ -573,17 +637,28 @@ void scr_http_req_pause(ScrHttpReq *r) {
|
||||
if (!r->ended) r->paused = true;
|
||||
}
|
||||
|
||||
/* req.setTimeout(ms[, cb]): the underlying socket's idle timer — the cb
|
||||
* registers once('timeout') there, Node's delegation. Finished/destroyed
|
||||
* messages skip (Node no-ops once the stream is done). */
|
||||
/* req.setTimeout(ms[, cb]): Node registers the callback on the message,
|
||||
* then arms the socket's idle timer. An incomplete server request can
|
||||
* handle the timeout and keep its connection alive. */
|
||||
void scr_http_req_set_timeout(ScrHttpReq *r, double ms, ScrClosure *cb /*moves, nullable*/) {
|
||||
if (!scr_http_timeout_valid(ms)) {
|
||||
if (cb) scr_closure_release(cb);
|
||||
return;
|
||||
}
|
||||
if (r->ended || r->destroyed || r->close_emitted || !r->sock) {
|
||||
/* the message is done — Node no-ops there (never arms, never fires) */
|
||||
if (cb) scr_closure_release(cb);
|
||||
return;
|
||||
}
|
||||
scr_net_sock_set_timeout(r->sock, ms);
|
||||
if (cb) scr_net_sock_on_timeout(r->sock, cb, true);
|
||||
if (cb) {
|
||||
if (r->status < 0 && !r->h2_stream) scr_net_ls_add(&r->timeout_ls, cb, NULL, false);
|
||||
else scr_net_sock_on_timeout(r->sock, cb, true);
|
||||
}
|
||||
}
|
||||
|
||||
void scr_http_req_set_timeout_plain(ScrHttpReq *r, double ms) {
|
||||
scr_http_req_set_timeout(r, ms, NULL);
|
||||
}
|
||||
|
||||
bool scr_http_req_destroyed_flag(ScrHttpReq *r) { return r->destroyed; }
|
||||
@@ -830,7 +905,7 @@ struct ScrHttpRes {
|
||||
* plain-property write. */
|
||||
ScrHttpReq *req_ref;
|
||||
bool req_cleared;
|
||||
ScrNetLs close_ls;
|
||||
ScrNetLs close_ls, timeout_ls;
|
||||
ScrNetLs finish_ls; /* res.end(cb) — fires deferred once the body went out */
|
||||
ScrNetLs wcb_ls; /* res.write(chunk, cb) — fires from the queue */
|
||||
bool finish_queued;
|
||||
@@ -856,6 +931,7 @@ void scr_http_res_release(ScrHttpRes *r) {
|
||||
scr_http_trailers_clear(&r->trailers);
|
||||
scr_str_release(r->status_msg);
|
||||
scr_net_ls_drop(&r->close_ls);
|
||||
scr_net_ls_drop(&r->timeout_ls);
|
||||
scr_net_ls_drop(&r->finish_ls);
|
||||
scr_net_ls_drop(&r->wcb_ls);
|
||||
free(r->cork_buf);
|
||||
@@ -1476,14 +1552,18 @@ void scr_http_res_set_req(ScrHttpRes *r, ScrHttpReq *req /*borrowed*/) {
|
||||
r->req_ref = req ? scr_http_req_retain(req) : NULL;
|
||||
}
|
||||
|
||||
/* res.setTimeout(ms[, cb]): the socket's idle timer, Node's delegation. */
|
||||
/* res.setTimeout(ms[, cb]): a server response handles its own timeout
|
||||
* event before the server decides whether to destroy the socket. */
|
||||
void scr_http_res_set_timeout(ScrHttpRes *r, double ms, ScrClosure *cb /*moves, nullable*/) {
|
||||
if (r->finished || r->close_emitted || !r->sock) {
|
||||
if (cb) scr_closure_release(cb);
|
||||
return;
|
||||
}
|
||||
scr_net_sock_set_timeout(r->sock, ms);
|
||||
if (cb) scr_net_sock_on_timeout(r->sock, cb, true);
|
||||
if (cb) {
|
||||
if (!r->h2_stream) scr_net_ls_add(&r->timeout_ls, cb, NULL, false);
|
||||
else scr_net_sock_on_timeout(r->sock, cb, true);
|
||||
}
|
||||
}
|
||||
|
||||
void scr_http_res_set_timeout_plain(ScrHttpRes *r, double ms) {
|
||||
@@ -1699,7 +1779,10 @@ enum {
|
||||
SCR_HTTP_EMIT_CLIENT_CLOSE = 4, /* ScrHttpClientReq */
|
||||
SCR_HTTP_EMIT_RES_FINISH = 5, /* ScrHttpRes: the end(cb) callbacks */
|
||||
SCR_HTTP_EMIT_REQ_DRAIN = SCR_HTTP_EMIT_REQ_DRAIN_K, /* ScrHttpReq: resume()'s drain */
|
||||
SCR_HTTP_EMIT_RES_WCB = 7 /* ScrHttpRes: write(chunk, cb) callbacks */
|
||||
SCR_HTTP_EMIT_RES_WCB = 7, /* ScrHttpRes: write(chunk, cb) callbacks */
|
||||
SCR_HTTP_EMIT_CLIENT_SOCKET = 8, /* ScrHttpClientReq: assigned socket */
|
||||
SCR_HTTP_EMIT_CLIENT_FINISH = 9, /* ScrHttpClientReq: outgoing body flushed */
|
||||
SCR_HTTP_EMIT_CLIENT_ABORT = 10 /* ScrHttpClientReq: abort() notification */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -1712,6 +1795,9 @@ static size_t scr_http_emits_head = 0, scr_http_emits_len = 0, scr_http_emits_ca
|
||||
|
||||
static void scr_http_client_release_internal(struct ScrHttpClientReq *c);
|
||||
static void scr_http_client_settle(struct ScrHttpClientReq *c);
|
||||
static void scr_http_client_emit_socket(struct ScrHttpClientReq *c);
|
||||
static void scr_http_client_emit_finish(struct ScrHttpClientReq *c);
|
||||
static void scr_http_client_emit_abort(struct ScrHttpClientReq *c);
|
||||
|
||||
/* Exit-time flag (set by the atexit cleanup, which runs BEFORE the net
|
||||
* unit's — atexit LIFO, http installs after net): once the emits queue
|
||||
@@ -1756,6 +1842,9 @@ static void scr_http_emit_release(ScrHttpEmit *e) {
|
||||
case SCR_HTTP_EMIT_REQ_DRAIN:
|
||||
case SCR_HTTP_EMIT_REQ_ABORTED: scr_http_req_release((ScrHttpReq *)e->h); break;
|
||||
case SCR_HTTP_EMIT_CLIENT_CLOSE:
|
||||
case SCR_HTTP_EMIT_CLIENT_SOCKET:
|
||||
case SCR_HTTP_EMIT_CLIENT_FINISH:
|
||||
case SCR_HTTP_EMIT_CLIENT_ABORT:
|
||||
scr_http_client_release_internal((struct ScrHttpClientReq *)e->h);
|
||||
break;
|
||||
}
|
||||
@@ -1821,6 +1910,7 @@ static void scr_http_proto_sweep(void) {
|
||||
res->socket_detached = true;
|
||||
scr_net_fire0_this(&res->close_ls, res, SCR_DYNH_HTTP_RES);
|
||||
scr_net_ls_drop(&res->close_ls);
|
||||
scr_net_ls_drop(&res->timeout_ls);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1838,6 +1928,7 @@ static void scr_http_proto_sweep(void) {
|
||||
scr_net_fire0_this(&req->close_ls, req, SCR_DYNH_HTTP_REQ);
|
||||
scr_net_ls_drop(&req->err_ls);
|
||||
scr_net_ls_drop(&req->close_ls);
|
||||
scr_net_ls_drop(&req->timeout_ls);
|
||||
scr_net_ls_drop(&req->aborted_ls);
|
||||
}
|
||||
break;
|
||||
@@ -1874,6 +1965,15 @@ static void scr_http_proto_sweep(void) {
|
||||
case SCR_HTTP_EMIT_CLIENT_CLOSE:
|
||||
scr_http_client_settle((struct ScrHttpClientReq *)e.h);
|
||||
break;
|
||||
case SCR_HTTP_EMIT_CLIENT_SOCKET:
|
||||
scr_http_client_emit_socket((struct ScrHttpClientReq *)e.h);
|
||||
break;
|
||||
case SCR_HTTP_EMIT_CLIENT_FINISH:
|
||||
scr_http_client_emit_finish((struct ScrHttpClientReq *)e.h);
|
||||
break;
|
||||
case SCR_HTTP_EMIT_CLIENT_ABORT:
|
||||
scr_http_client_emit_abort((struct ScrHttpClientReq *)e.h);
|
||||
break;
|
||||
case SCR_HTTP_EMIT_RES_FINISH: {
|
||||
ScrHttpRes *res = (ScrHttpRes *)e.h;
|
||||
res->finish_queued = false; /* a later end(cb) on the finished res re-queues */
|
||||
@@ -2736,6 +2836,37 @@ static void scr_http_conn_free(void *ctx) {
|
||||
free(conn);
|
||||
}
|
||||
|
||||
static bool scr_http_conn_is_idle(void *ctx) {
|
||||
ScrHttpConn *conn = (ScrHttpConn *)ctx;
|
||||
return !conn->client_mode && conn->state == SCR_HTTP_HEAD &&
|
||||
conn->req == NULL && conn->len == 0;
|
||||
}
|
||||
|
||||
/* Node's server socketOnTimeout emits on an incomplete request, then on
|
||||
* the active response. Listener presence, including a once listener
|
||||
* removed by the emit, prevents the server's unhandled auto-destroy. */
|
||||
static bool scr_http_conn_server_timeout(void *ctx) {
|
||||
ScrHttpConn *conn = (ScrHttpConn *)ctx;
|
||||
bool handled = false;
|
||||
if (conn->client_mode) return false;
|
||||
ScrHttpReq *req = conn->req;
|
||||
if (req && !req->ended && !req->destroyed && req->timeout_ls.n > 0) {
|
||||
handled = true;
|
||||
scr_http_req_retain(req);
|
||||
scr_net_fire0_this(&req->timeout_ls, req, SCR_DYNH_HTTP_REQ);
|
||||
scr_http_req_release(req);
|
||||
}
|
||||
if (scr_exc_pending()) return handled;
|
||||
ScrHttpRes *res = conn->res;
|
||||
if (res && !res->close_emitted && res->timeout_ls.n > 0) {
|
||||
handled = true;
|
||||
scr_http_res_retain(res);
|
||||
scr_net_fire0_this(&res->timeout_ls, res, SCR_DYNH_HTTP_RES);
|
||||
scr_http_res_release(res);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
/* The server's native connection hook: one parser per accepted socket. */
|
||||
static void scr_http_on_connection(void *ctx, ScrNetSocket *sock) {
|
||||
ScrHttpSrvCtx *srv = (ScrHttpSrvCtx *)ctx;
|
||||
@@ -2745,7 +2876,9 @@ static void scr_http_on_connection(void *ctx, ScrNetSocket *sock) {
|
||||
conn->srv = scr_http_srv_ctx_retain(srv);
|
||||
scr_net_sock_set_native_reader(sock, &scr_http_conn_data, &scr_http_conn_eof,
|
||||
&scr_http_conn_closed, conn, &scr_http_conn_free);
|
||||
scr_net_sock_set_native_idle_checker(sock, &scr_http_conn_is_idle);
|
||||
scr_net_sock_set_native_events(sock, NULL, &scr_http_conn_err);
|
||||
scr_net_sock_set_native_http_timeout(sock, &scr_http_conn_server_timeout);
|
||||
}
|
||||
|
||||
/* The unguarded h2-only stream call (`req.stream.on(...)`): stream IS
|
||||
@@ -2886,7 +3019,7 @@ ScrStr *scr_http_req_http_version(ScrHttpReq *r) {
|
||||
double scr_http_req_http_version_major(ScrHttpReq *r) { return r->http2 ? 2 : 1; }
|
||||
double scr_http_req_http_version_minor(ScrHttpReq *r) { return r->http2 || r->http10 ? 0 : 1; }
|
||||
bool scr_http_req_aborted_flag(ScrHttpReq *r) { return r->aborted; }
|
||||
bool scr_http_req_complete(ScrHttpReq *r) { return r->ended; }
|
||||
bool scr_http_req_complete(ScrHttpReq *r) { return r->ended && !r->aborted; }
|
||||
|
||||
/* The stream died with the response side open: 'aborted' fires NOW (the
|
||||
* teardown macrotask, Node's position), then the close rides the sweep. */
|
||||
@@ -3033,13 +3166,19 @@ struct ScrHttpClientReq {
|
||||
size_t cork_len, cork_cap;
|
||||
bool ended;
|
||||
bool destroyed;
|
||||
bool aborted;
|
||||
bool abort_emitted;
|
||||
bool sock_ready;
|
||||
bool socket_emitted;
|
||||
bool finish_queued;
|
||||
bool writable_finished;
|
||||
bool response_started; /* head parsed, res exists */
|
||||
bool response_done;
|
||||
bool had_error;
|
||||
bool close_queued;
|
||||
bool close_emitted; /* settled: listeners dropped, off the registry */
|
||||
ScrHttpReq *res; /* +1 once the head parses */
|
||||
ScrNetLs resp_ls, err_ls, timeout_ls, close_ls, upgrade_ls;
|
||||
ScrNetLs resp_ls, err_ls, timeout_ls, close_ls, upgrade_ls, socket_ls, finish_ls, abort_ls;
|
||||
/* the owning Agent (+1; the agent's entry holds this client +1 too —
|
||||
* the cycle breaks at settle, or at the atexit agent sweep) */
|
||||
struct ScrHttpAgent *agent;
|
||||
@@ -3062,6 +3201,9 @@ void scr_http_client_release(ScrHttpClientReq *c) {
|
||||
scr_net_ls_drop(&c->timeout_ls);
|
||||
scr_net_ls_drop(&c->close_ls);
|
||||
scr_net_ls_drop(&c->upgrade_ls);
|
||||
scr_net_ls_drop(&c->socket_ls);
|
||||
scr_net_ls_drop(&c->finish_ls);
|
||||
scr_net_ls_drop(&c->abort_ls);
|
||||
scr_str_release(c->host);
|
||||
scr_str_release(c->path);
|
||||
scr_str_release(c->method);
|
||||
@@ -3128,6 +3270,8 @@ static void scr_http_client_settle(struct ScrHttpClientReq *c) {
|
||||
scr_net_ls_drop(&c->err_ls);
|
||||
scr_net_ls_drop(&c->timeout_ls);
|
||||
scr_net_ls_drop(&c->close_ls);
|
||||
scr_net_ls_drop(&c->socket_ls);
|
||||
scr_net_ls_drop(&c->finish_ls);
|
||||
scr_http_client_unregister(c);
|
||||
}
|
||||
|
||||
@@ -3137,6 +3281,45 @@ static void scr_http_client_queue_close(ScrHttpClientReq *c) {
|
||||
scr_http_emit_push(SCR_HTTP_EMIT_CLIENT_CLOSE, scr_http_client_retain(c));
|
||||
}
|
||||
|
||||
static void scr_http_client_queue_finish(ScrHttpClientReq *c) {
|
||||
if (!c->ended || !c->sock_ready || c->destroyed || c->close_emitted || c->finish_queued || c->writable_finished) return;
|
||||
c->finish_queued = true;
|
||||
scr_http_emit_push(SCR_HTTP_EMIT_CLIENT_FINISH, scr_http_client_retain(c));
|
||||
}
|
||||
|
||||
static void scr_http_client_emit_socket(ScrHttpClientReq *c) {
|
||||
if (c->socket_emitted) return;
|
||||
if (c->destroyed) {
|
||||
scr_net_ls_drop(&c->socket_ls);
|
||||
return;
|
||||
}
|
||||
c->socket_emitted = true;
|
||||
ScrNetL *snap;
|
||||
size_t count = scr_net_ls_snapshot(&c->socket_ls, &snap);
|
||||
scr_dyn_this_push(c, SCR_DYNH_HTTP_CLIENT);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (!scr_exc_pending()) ((ScrNetConnFn)snap[i].fn)(snap[i].cb, scr_net_sock_retain(c->sock));
|
||||
scr_closure_release(snap[i].cb);
|
||||
}
|
||||
scr_dyn_this_pop();
|
||||
free(snap);
|
||||
scr_net_ls_drop(&c->socket_ls);
|
||||
}
|
||||
|
||||
static void scr_http_client_emit_finish(ScrHttpClientReq *c) {
|
||||
c->finish_queued = false;
|
||||
if (c->destroyed || c->close_emitted || !c->ended || !c->sock_ready || c->writable_finished) return;
|
||||
c->writable_finished = true;
|
||||
scr_net_fire0_this(&c->finish_ls, c, SCR_DYNH_HTTP_CLIENT);
|
||||
scr_net_ls_drop(&c->finish_ls);
|
||||
}
|
||||
|
||||
static void scr_http_client_emit_abort(ScrHttpClientReq *c) {
|
||||
c->abort_emitted = true;
|
||||
scr_net_fire0_this(&c->abort_ls, c, SCR_DYNH_HTTP_CLIENT);
|
||||
scr_net_ls_drop(&c->abort_ls);
|
||||
}
|
||||
|
||||
/* 'error' on the request handle: fires NOW (the callers sit in the net
|
||||
* sweep / dispatch, Node's own emit spots); no listener exits 1, the
|
||||
* unhandled-'error' story. The close follows through the queue. */
|
||||
@@ -3202,6 +3385,17 @@ ScrStr *scr_http_client_protocol(ScrHttpClientReq *c) {
|
||||
}
|
||||
bool scr_http_client_headers_sent(ScrHttpClientReq *c) { return c->head_sent; }
|
||||
bool scr_http_client_writable_ended(ScrHttpClientReq *c) { return c->ended; }
|
||||
bool scr_http_client_writable_finished(ScrHttpClientReq *c) { return c->writable_finished; }
|
||||
ScrNetSocket *scr_http_client_socket(ScrHttpClientReq *c) { return scr_net_sock_retain(c->sock); }
|
||||
bool scr_http_client_reused_socket(ScrHttpClientReq *c) { (void)c; return false; }
|
||||
void scr_http_client_set_nodelay(ScrHttpClientReq *c, bool enable) {
|
||||
if (!c->sock) return;
|
||||
scr_net_sock_release(scr_net_sock_set_nodelay(c->sock, enable));
|
||||
}
|
||||
void scr_http_client_set_socket_keepalive(ScrHttpClientReq *c, bool enable, double delay_ms) {
|
||||
if (!c->sock) return;
|
||||
scr_net_sock_set_keepalive(c->sock, enable, delay_ms);
|
||||
}
|
||||
|
||||
static bool scr_http_client_header_mutable(ScrHttpClientReq *c, const char *op) {
|
||||
if (!c->head_sent) return true;
|
||||
@@ -3404,6 +3598,7 @@ static void scr_http_client_end_raw(ScrHttpClientReq *c, const char *data, size_
|
||||
if (c->chunked && c->sock) scr_http_send_chunk_end(c->sock, &c->trailers);
|
||||
}
|
||||
c->ended = true;
|
||||
scr_http_client_queue_finish(c);
|
||||
}
|
||||
|
||||
void scr_http_client_end(ScrHttpClientReq *c) { scr_http_client_end_raw(c, "", 0); }
|
||||
@@ -3428,9 +3623,19 @@ void scr_http_client_add_trailers(ScrHttpClientReq *c, ScrArr *pairs /*borrowed*
|
||||
/* req.setTimeout(ms) after construction (the island bridge's late arm —
|
||||
* the constructor's timeout_ms is the static lane's route). */
|
||||
void scr_http_client_set_timeout(ScrHttpClientReq *c, double ms) {
|
||||
if (!scr_http_timeout_valid(ms)) return;
|
||||
if (c->sock) scr_net_sock_set_timeout(c->sock, ms);
|
||||
}
|
||||
|
||||
void scr_http_client_set_timeout_cb(ScrHttpClientReq *c, double ms, ScrClosure *cb /*moves*/) {
|
||||
scr_http_client_set_timeout(c, ms);
|
||||
if (scr_exc_pending()) {
|
||||
scr_closure_release(cb);
|
||||
return;
|
||||
}
|
||||
scr_http_client_on_timeout(c, cb, false);
|
||||
}
|
||||
|
||||
/* destroy(): tears the connection down NOW. A destroy after the response
|
||||
* completed is a quiet no-op past the socket close (Node: just 'close');
|
||||
* before it, the teardown surfaces as 'socket hang up' — both flow
|
||||
@@ -3441,6 +3646,24 @@ void scr_http_client_destroy(ScrHttpClientReq *c) {
|
||||
if (c->sock) scr_net_sock_destroy(c->sock);
|
||||
}
|
||||
|
||||
void scr_http_client_abort(ScrHttpClientReq *c) {
|
||||
if (c->aborted) return;
|
||||
c->aborted = true;
|
||||
bool early_or_complete = !c->socket_emitted || c->response_done;
|
||||
/* A request whose socket was already handed to JS emits abort before
|
||||
* teardown; an early abort reports close first. The queued emits keep
|
||||
* both paths off the caller's stack. */
|
||||
if (!early_or_complete)
|
||||
scr_http_emit_push(SCR_HTTP_EMIT_CLIENT_ABORT, scr_http_client_retain(c));
|
||||
scr_http_client_destroy(c);
|
||||
if (early_or_complete) {
|
||||
scr_http_client_queue_close(c);
|
||||
scr_http_emit_push(SCR_HTTP_EMIT_CLIENT_ABORT, scr_http_client_retain(c));
|
||||
}
|
||||
}
|
||||
|
||||
bool scr_http_client_aborted(ScrHttpClientReq *c) { return c->aborted; }
|
||||
|
||||
bool scr_http_client_destroyed(ScrHttpClientReq *c) {
|
||||
return c->destroyed || c->close_emitted;
|
||||
}
|
||||
@@ -3454,6 +3677,30 @@ void scr_http_client_on_response(ScrHttpClientReq *c, ScrClosure *cb /*moves*/,
|
||||
scr_net_ls_add(&c->resp_ls, cb, (void *)fn, once);
|
||||
}
|
||||
|
||||
void scr_http_client_on_socket(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, ScrNetConnFn fn, bool once) {
|
||||
if (c->socket_emitted || c->close_emitted) {
|
||||
scr_closure_release(cb);
|
||||
return;
|
||||
}
|
||||
scr_net_ls_add(&c->socket_ls, cb, (void *)fn, once);
|
||||
}
|
||||
|
||||
void scr_http_client_on_finish(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, bool once) {
|
||||
if (c->writable_finished || c->close_emitted) {
|
||||
scr_closure_release(cb);
|
||||
return;
|
||||
}
|
||||
scr_net_ls_add(&c->finish_ls, cb, NULL, once);
|
||||
}
|
||||
|
||||
void scr_http_client_on_abort(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, bool once) {
|
||||
if (c->abort_emitted) {
|
||||
scr_closure_release(cb);
|
||||
return;
|
||||
}
|
||||
scr_net_ls_add(&c->abort_ls, cb, NULL, once);
|
||||
}
|
||||
|
||||
void scr_http_client_on_error(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, ScrChildErrFn fn, bool once) {
|
||||
if (c->close_emitted) {
|
||||
scr_closure_release(cb);
|
||||
@@ -3713,7 +3960,7 @@ static void scr_http_client_premature(ScrHttpConn *conn) {
|
||||
if (!c || c->response_done || c->close_emitted) return;
|
||||
c->response_done = true; /* the exchange is over, one way or another */
|
||||
if (!c->response_started) {
|
||||
if (!c->had_error) {
|
||||
if (!c->had_error && (!c->aborted || c->socket_emitted)) {
|
||||
ScrStr *msg = scr_str_new("socket hang up", 14);
|
||||
scr_http_client_error(c, msg);
|
||||
scr_str_release(msg);
|
||||
@@ -3721,12 +3968,14 @@ static void scr_http_client_premature(ScrHttpConn *conn) {
|
||||
}
|
||||
scr_http_client_queue_close(c);
|
||||
} else {
|
||||
/* mid-head-to-body death: req close, then 'aborted' on the res, then
|
||||
* res close (the queue preserves push order) */
|
||||
/* An incomplete client response fires 'aborted' before 'close'. A
|
||||
* caller-initiated response.destroy() does not emit an 'error'; a
|
||||
* premature peer close still does. */
|
||||
scr_http_client_queue_close(c);
|
||||
if (conn->req) {
|
||||
ScrHttpReq *res = conn->req;
|
||||
scr_http_queue_req_aborted(res);
|
||||
scr_http_h2_req_aborted(res);
|
||||
if (!res->destroyed) scr_http_queue_req_aborted(res);
|
||||
scr_http_queue_req_close(res);
|
||||
scr_http_req_finish(res, false); /* body never completes */
|
||||
conn->req = NULL; /* break the res→sock→ctx→res cycle */
|
||||
@@ -3772,7 +4021,7 @@ static void scr_http_client_closed(ScrHttpConn *conn) {
|
||||
static bool scr_http_client_sock_err(ScrHttpConn *conn, ScrStr *msg) {
|
||||
ScrHttpClientReq *c = conn->client;
|
||||
if (!c) return true;
|
||||
if (c->response_done || c->close_emitted) return true; /* teardown noise */
|
||||
if (c->response_done || c->close_emitted || (c->aborted && !c->socket_emitted)) return true; /* teardown noise */
|
||||
if (!c->response_started) {
|
||||
/* connect/read failure before any response: the socket's message IS
|
||||
* Node's ('connect ECONNREFUSED ip:port') — fire it on the request */
|
||||
@@ -3803,6 +4052,14 @@ static void scr_http_client_sock_timeout(void *ctx) {
|
||||
scr_net_fire0(&c->timeout_ls);
|
||||
}
|
||||
|
||||
static void scr_http_client_sock_established(void *ctx) {
|
||||
ScrHttpConn *conn = (ScrHttpConn *)ctx;
|
||||
ScrHttpClientReq *c = conn->client;
|
||||
if (!c) return;
|
||||
c->sock_ready = true;
|
||||
scr_http_client_queue_finish(c);
|
||||
}
|
||||
|
||||
static void scr_http_client_conn_free(ScrHttpConn *conn) {
|
||||
if (conn->req) {
|
||||
scr_http_req_finish(conn->req, false);
|
||||
@@ -3929,8 +4186,11 @@ static ScrHttpClientReq *scr_http_request_impl(ScrStr *host /*borrowed*/, double
|
||||
/* the transport (scr_tls.c's https) wraps the dialed socket before any
|
||||
* bytes go out — everything below buffers until its handshake ends */
|
||||
if (wrap) wrap(c->sock, wrap_ctx);
|
||||
scr_net_sock_set_native_established(c->sock, &scr_http_client_sock_established);
|
||||
c->sock_ready = scr_net_sock_established(c->sock);
|
||||
if (timeout_ms > 0) scr_net_sock_set_timeout(c->sock, timeout_ms);
|
||||
scr_http_client_register(c);
|
||||
scr_http_emit_push(SCR_HTTP_EMIT_CLIENT_SOCKET, scr_http_client_retain(c));
|
||||
if (auto_end) scr_http_client_end(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
#include "scr_runtime.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
@@ -472,7 +473,7 @@ struct ScrNetServer {
|
||||
* address().address answers) */
|
||||
ScrStr *pending_err; /* deferred listen failure */
|
||||
size_t nconns;
|
||||
ScrNetLs conn_ls, err_ls, close_ls, listening_cbs;
|
||||
ScrNetLs conn_ls, err_ls, close_ls, listening_cbs, timeout_ls;
|
||||
/* protocol layer (scr_http.c): a C-level connection consumer + its
|
||||
* context, freed with the handle */
|
||||
ScrNetNativeConnFn native_conn;
|
||||
@@ -585,12 +586,14 @@ struct ScrNetSocket {
|
||||
ScrNetNativeEventFn native_eof;
|
||||
ScrNetNativeEventFn native_closed;
|
||||
ScrNetNativeEventFn native_timeout;
|
||||
ScrNetNativeTimeoutHandledFn native_http_timeout; /* HTTP req/res timeout handled */
|
||||
ScrNetNativeEventFn native_established; /* client connect completed (the
|
||||
* h2 session's 'connect' moment;
|
||||
* fires before conn_ls) */
|
||||
ScrNetNativeErrFn native_err; /* true = consumed (the protocol layer owns
|
||||
* the error story); false falls through to
|
||||
* this socket's own err_ls */
|
||||
bool (*native_idle)(void *); /* HTTP parser: no active request or partial head */
|
||||
void *native_ctx;
|
||||
void (*native_ctx_free)(void *);
|
||||
/* transport layer (scr_tls.c): reads/writes redirect through the ops
|
||||
@@ -631,6 +634,7 @@ void scr_net_server_release(ScrNetServer *s) {
|
||||
scr_net_ls_drop(&s->err_ls);
|
||||
scr_net_ls_drop(&s->close_ls);
|
||||
scr_net_ls_drop(&s->listening_cbs);
|
||||
scr_net_ls_drop(&s->timeout_ls);
|
||||
scr_closure_release(s->close_override);
|
||||
for (size_t i = 0; i < 5; i++) scr_dyn_release(s->http_timeout_dyn[i]);
|
||||
scr_str_release(s->bound_host);
|
||||
@@ -1549,6 +1553,16 @@ void scr_net_server_timeout_set(ScrNetServer *s, double field, double value) {
|
||||
s->http_timeouts[i] = value;
|
||||
}
|
||||
|
||||
void scr_net_server_set_timeout_plain(ScrNetServer *s, double ms) {
|
||||
scr_net_server_timeout_set(s, 0, ms);
|
||||
}
|
||||
|
||||
void scr_net_server_set_timeout_cb(ScrNetServer *s, double ms, ScrClosure *cb /*moves*/,
|
||||
ScrNetConnFn fn) {
|
||||
scr_net_server_timeout_set(s, 0, ms);
|
||||
scr_net_server_on_timeout(s, cb, fn, false);
|
||||
}
|
||||
|
||||
void scr_net_server_enable_http_timeout_surface(ScrNetServer *s) {
|
||||
s->http_timeout_surface = true;
|
||||
}
|
||||
@@ -1655,6 +1669,28 @@ void scr_net_server_close(ScrNetServer *s, ScrClosure *cb /*moves, nullable*/) {
|
||||
scr_net_server_close_direct(s, cb);
|
||||
}
|
||||
|
||||
static void scr_net_server_close_http_connections(ScrNetServer *s, bool idle_only) {
|
||||
ScrNetSocket *sock = scr_net_socks;
|
||||
while (sock) {
|
||||
ScrNetSocket *next = sock->next;
|
||||
if (sock->server == s && sock->native_idle != NULL && sock->fd >= 0 &&
|
||||
(!idle_only || sock->native_idle(sock->native_ctx))) {
|
||||
scr_net_sock_retain(sock);
|
||||
scr_net_sock_destroy(sock);
|
||||
scr_net_sock_release(sock);
|
||||
}
|
||||
sock = next;
|
||||
}
|
||||
}
|
||||
|
||||
void scr_net_server_close_all_connections(ScrNetServer *s) {
|
||||
scr_net_server_close_http_connections(s, false);
|
||||
}
|
||||
|
||||
void scr_net_server_close_idle_connections(ScrNetServer *s) {
|
||||
scr_net_server_close_http_connections(s, true);
|
||||
}
|
||||
|
||||
/* wrapper.close = fn: the override MOVES in (a compiler-emitted zero-arg
|
||||
* wrapper — see the struct comment); reassignment releases the old one,
|
||||
* matching JS's last-write-wins. */
|
||||
@@ -1715,6 +1751,15 @@ void scr_net_server_on_connection(ScrNetServer *s, ScrClosure *cb /*moves*/, Scr
|
||||
scr_net_ls_add(&s->conn_ls, cb, (void *)fn, once);
|
||||
}
|
||||
|
||||
void scr_net_server_on_timeout(ScrNetServer *s, ScrClosure *cb /*moves*/, ScrNetConnFn fn,
|
||||
bool once) {
|
||||
if (s->close_emitted) {
|
||||
scr_closure_release(cb);
|
||||
return;
|
||||
}
|
||||
scr_net_ls_add(&s->timeout_ls, cb, (void *)fn, once);
|
||||
}
|
||||
|
||||
/* Accept until EAGAIN; each connection fires the 'connection' listeners
|
||||
* directly (the accepted socket passes +1 per listener via the adapter). */
|
||||
static void scr_net_server_accept(ScrNetServer *srv) {
|
||||
@@ -1733,6 +1778,8 @@ static void scr_net_server_accept(ScrNetServer *srv) {
|
||||
sock->server = scr_net_server_retain(srv);
|
||||
srv->nconns++;
|
||||
scr_net_sock_register(sock);
|
||||
if (srv->http_timeout_surface && srv->http_timeouts[0] > 0)
|
||||
scr_net_sock_set_timeout(sock, srv->http_timeouts[0]);
|
||||
if (srv->native_conn) {
|
||||
/* the protocol layer (scr_http.c / scr_tls.c) claims the connection */
|
||||
srv->native_conn(srv->native_ctx, sock);
|
||||
@@ -2229,6 +2276,19 @@ ScrNetSocket *scr_net_sock_set_nodelay(ScrNetSocket *s, bool enable) {
|
||||
return scr_net_sock_retain(s);
|
||||
}
|
||||
|
||||
void scr_net_sock_set_keepalive(ScrNetSocket *s, bool enable, double delay_ms) {
|
||||
if (s->fd < 0) return;
|
||||
int value = enable ? 1 : 0;
|
||||
setsockopt(s->fd, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof value);
|
||||
if (!enable || !(delay_ms > 0) || !isfinite(delay_ms)) return;
|
||||
int seconds = (int)fmin((double)INT_MAX, fmax(1.0, floor(delay_ms / 1000.0)));
|
||||
#if defined(TCP_KEEPIDLE)
|
||||
setsockopt(s->fd, IPPROTO_TCP, TCP_KEEPIDLE, &seconds, sizeof seconds);
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
setsockopt(s->fd, IPPROTO_TCP, TCP_KEEPALIVE, &seconds, sizeof seconds);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* socket.destroySoon(): end the write half now, destroy once the FIN is
|
||||
* actually out (buffered bytes flush first — Node's 'finish'-then-destroy). */
|
||||
void scr_net_sock_destroy_soon(ScrNetSocket *s) {
|
||||
@@ -2575,11 +2635,16 @@ void scr_net_sock_set_native_reader(ScrNetSocket *s, ScrNetNativeDataFn data,
|
||||
s->native_data = data;
|
||||
s->native_eof = eof;
|
||||
s->native_closed = closed;
|
||||
s->native_idle = NULL;
|
||||
s->native_ctx = ctx;
|
||||
s->native_ctx_free = ctx_free;
|
||||
scr_net_sock_update_read(s);
|
||||
}
|
||||
|
||||
void scr_net_sock_set_native_idle_checker(ScrNetSocket *s, bool (*fn)(void *)) {
|
||||
s->native_idle = fn;
|
||||
}
|
||||
|
||||
/* The upgrade handover: clear the native reader's FN POINTERS but keep
|
||||
* the ctx (still freed at socket death as registered) — the protocol
|
||||
* parser steps aside mid-call and 'data'/pipe consumers take the raw
|
||||
@@ -2588,6 +2653,8 @@ void scr_net_sock_clear_native_reader(ScrNetSocket *s) {
|
||||
s->native_data = NULL;
|
||||
s->native_eof = NULL;
|
||||
s->native_closed = NULL;
|
||||
s->native_idle = NULL; /* upgraded and CONNECT sockets are outside HTTP close sweeps */
|
||||
s->native_http_timeout = NULL;
|
||||
scr_net_sock_update_read(s);
|
||||
}
|
||||
|
||||
@@ -2602,6 +2669,10 @@ bool scr_net_sock_writable(ScrNetSocket *s) {
|
||||
return s->fd >= 0 && !s->wr_ending && !s->wr_done;
|
||||
}
|
||||
|
||||
bool scr_net_sock_established(ScrNetSocket *s) {
|
||||
return s->fd >= 0 && !s->connecting && (!s->tops || s->t_est);
|
||||
}
|
||||
|
||||
/* The protocol layer's timeout/error hooks (scr_http.c's client and the
|
||||
* server parser's error swallowing). */
|
||||
void scr_net_sock_set_native_events(ScrNetSocket *s, ScrNetNativeEventFn timeout,
|
||||
@@ -2610,6 +2681,10 @@ void scr_net_sock_set_native_events(ScrNetSocket *s, ScrNetNativeEventFn timeout
|
||||
s->native_err = err;
|
||||
}
|
||||
|
||||
void scr_net_sock_set_native_http_timeout(ScrNetSocket *s, ScrNetNativeTimeoutHandledFn fn) {
|
||||
s->native_http_timeout = fn;
|
||||
}
|
||||
|
||||
/* Client connect completion for the protocol layer (the h2 session's
|
||||
* 'connect' moment) — fires before the socket's own conn_ls. */
|
||||
void scr_net_sock_set_native_established(ScrNetSocket *s, ScrNetNativeEventFn fn) {
|
||||
@@ -2771,6 +2846,7 @@ static void scr_net_server_settle(ScrNetServer *srv) {
|
||||
scr_net_ls_drop(&srv->err_ls);
|
||||
scr_net_ls_drop(&srv->close_ls);
|
||||
scr_net_ls_drop(&srv->listening_cbs);
|
||||
scr_net_ls_drop(&srv->timeout_ls);
|
||||
if (srv->proto_settle && srv->http_ctx) srv->proto_settle(srv->http_ctx);
|
||||
scr_net_server_unregister(srv);
|
||||
}
|
||||
@@ -2913,6 +2989,7 @@ static void scr_net_sweep(void) {
|
||||
scr_net_ls_drop(&srv->err_ls);
|
||||
scr_net_ls_drop(&srv->close_ls);
|
||||
scr_net_ls_drop(&srv->listening_cbs);
|
||||
scr_net_ls_drop(&srv->timeout_ls);
|
||||
scr_net_server_unregister(srv);
|
||||
}
|
||||
if (scr_exc_pending()) {
|
||||
@@ -2984,7 +3061,34 @@ static void scr_net_dispatch(void) {
|
||||
s->native_timeout(s->native_ctx);
|
||||
if (scr_exc_pending()) return;
|
||||
}
|
||||
if (s->server && s->server->http_timeout_surface &&
|
||||
s->native_http_timeout) {
|
||||
ScrNetServer *srv = scr_net_server_retain(s->server);
|
||||
bool handled = s->native_http_timeout(s->native_ctx);
|
||||
if (scr_exc_pending()) {
|
||||
scr_net_server_release(srv);
|
||||
return;
|
||||
}
|
||||
bool server_handled = srv->timeout_ls.n > 0;
|
||||
if (server_handled) {
|
||||
ScrNetL *snap;
|
||||
size_t count = scr_net_ls_snapshot(&srv->timeout_ls, &snap);
|
||||
scr_dyn_this_push(srv, SCR_DYNH_NET_SERVER);
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
if (!scr_exc_pending()) ((ScrNetConnFn)snap[j].fn)(snap[j].cb, scr_net_sock_retain(s));
|
||||
scr_closure_release(snap[j].cb);
|
||||
}
|
||||
scr_dyn_this_pop();
|
||||
free(snap);
|
||||
}
|
||||
if (!handled && !server_handled && !scr_exc_pending())
|
||||
scr_net_sock_destroy(s); /* Node's unhandled server timeout */
|
||||
scr_net_server_release(srv);
|
||||
if (scr_exc_pending()) return;
|
||||
}
|
||||
scr_net_fire0_this(&s->timeout_ls, s, SCR_DYNH_NET_SOCKET);
|
||||
if (scr_exc_pending()) return;
|
||||
if (s->fd < 0) continue;
|
||||
}
|
||||
/* kqueue delivers one direction per event (today's exact order);
|
||||
* epoll may coalesce both into one — writes first (connect
|
||||
@@ -3043,6 +3147,7 @@ static void scr_net_cleanup_atexit(void) {
|
||||
s->native_eof = NULL;
|
||||
s->native_closed = NULL;
|
||||
s->native_timeout = NULL;
|
||||
s->native_http_timeout = NULL;
|
||||
s->native_established = NULL;
|
||||
s->native_err = NULL;
|
||||
ctx_free(ctx);
|
||||
|
||||
@@ -5584,6 +5584,7 @@ void scr_net_fire_err_this(ScrNetLs *l, ScrStr *msg, void *self, ScrDynHandleTag
|
||||
typedef void (*ScrNetNativeConnFn)(void *ctx, ScrNetSocket *sock);
|
||||
typedef void (*ScrNetNativeDataFn)(void *ctx, const char *buf, size_t n);
|
||||
typedef void (*ScrNetNativeEventFn)(void *ctx);
|
||||
typedef bool (*ScrNetNativeTimeoutHandledFn)(void *ctx);
|
||||
typedef bool (*ScrNetNativeErrFn)(void *ctx, ScrStr *msg); /* true = consumed */
|
||||
void scr_net_server_set_native_conn(ScrNetServer *s, ScrNetNativeConnFn fn, void *ctx, void (*ctx_free)(void *));
|
||||
/* The HTTP-parser ctx ALIAS: scr_http.c stamps its server ctx here so
|
||||
@@ -5607,6 +5608,7 @@ bool scr_net_server_settled(ScrNetServer *s); /* 'close' already emitted */
|
||||
* event the http layer does not model (the caller fences loudly). */
|
||||
void scr_net_set_dynh_http_on(bool (*fn)(ScrNetServer *, const char *, const ScrDyn *, bool));
|
||||
void scr_net_sock_set_native_reader(ScrNetSocket *s, ScrNetNativeDataFn data, ScrNetNativeEventFn eof, ScrNetNativeEventFn closed, void *ctx, void (*ctx_free)(void *));
|
||||
void scr_net_sock_set_native_idle_checker(ScrNetSocket *s, bool (*fn)(void *));
|
||||
/* The upgrade handover: clear the reader's fn pointers, keep the ctx. */
|
||||
void scr_net_sock_clear_native_reader(ScrNetSocket *s);
|
||||
/* The accepting server (BORROWED; NULL on client sockets) — the protocol
|
||||
@@ -5618,7 +5620,9 @@ ScrNetServer *scr_net_sock_server(ScrNetSocket *s);
|
||||
void scr_net_sock_set_encoding(ScrNetSocket *s, ScrStr *enc /*borrowed*/);
|
||||
bool scr_net_sock_destroyed(ScrNetSocket *s); /* socket.destroyed */
|
||||
bool scr_net_sock_writable(ScrNetSocket *s); /* socket.writable */
|
||||
bool scr_net_sock_established(ScrNetSocket *s); /* connected, including TLS handshake */
|
||||
void scr_net_sock_set_native_events(ScrNetSocket *s, ScrNetNativeEventFn timeout, ScrNetNativeErrFn err);
|
||||
void scr_net_sock_set_native_http_timeout(ScrNetSocket *s, ScrNetNativeTimeoutHandledFn fn);
|
||||
void scr_net_sock_write_native(ScrNetSocket *s, const char *buf, size_t n);
|
||||
/* The protocol layer's deferred-emit hook: `pending` joins the loop's
|
||||
* liveness test, `sweep` runs at every net sweep top. */
|
||||
@@ -5656,6 +5660,9 @@ bool scr_net_server_listening(ScrNetServer *s);
|
||||
* a non-number in the ordinary JS property slot. */
|
||||
double scr_net_server_timeout_get(ScrNetServer *s, double field);
|
||||
void scr_net_server_timeout_set(ScrNetServer *s, double field, double value);
|
||||
void scr_net_server_set_timeout_plain(ScrNetServer *s, double ms);
|
||||
void scr_net_server_set_timeout_cb(ScrNetServer *s, double ms, ScrClosure *cb /*moves*/, ScrNetConnFn fn);
|
||||
void scr_net_server_on_timeout(ScrNetServer *s, ScrClosure *cb /*moves*/, ScrNetConnFn fn, bool once);
|
||||
/* Marks the shared net-server handle as an HTTP/1 or HTTPS server. The
|
||||
* dynamic handle uses this to keep HTTP-only fields off net/TLS/H2. */
|
||||
void scr_net_server_enable_http_timeout_surface(ScrNetServer *s);
|
||||
@@ -5667,6 +5674,8 @@ void scr_net_server_timeout_option_set(ScrNetServer *s, double field, const stru
|
||||
ScrStr *scr_net_server_addr_ip(ScrNetServer *s); /* +1 — address().address */
|
||||
ScrStr *scr_net_server_addr_family(ScrNetServer *s); /* +1 — address().family */
|
||||
void scr_net_server_close(ScrNetServer *s, ScrClosure *cb /*moves, nullable*/);
|
||||
void scr_net_server_close_all_connections(ScrNetServer *s);
|
||||
void scr_net_server_close_idle_connections(ScrNetServer *s);
|
||||
/* The REAL close behind `wrapper.close.bind(wrapper)` — never consults
|
||||
* the override (the proxy-through idiom cannot recurse). */
|
||||
void scr_net_server_close_direct(ScrNetServer *s, ScrClosure *cb /*moves, nullable*/);
|
||||
@@ -5727,6 +5736,7 @@ void scr_net_sock_destroy(ScrNetSocket *s);
|
||||
ScrNetSocket *scr_net_sock_pause(ScrNetSocket *s); /* +1: chaining */
|
||||
ScrNetSocket *scr_net_sock_resume(ScrNetSocket *s); /* +1: chaining */
|
||||
ScrNetSocket *scr_net_sock_set_nodelay(ScrNetSocket *s, bool enable); /* +1: chaining */
|
||||
void scr_net_sock_set_keepalive(ScrNetSocket *s, bool enable, double delay_ms);
|
||||
void scr_net_sock_destroy_soon(ScrNetSocket *s);
|
||||
void scr_net_sock_on_finish(ScrNetSocket *s, ScrClosure *cb /*moves*/);
|
||||
void scr_net_sock_on_write_flush(ScrNetSocket *s, ScrClosure *cb /*moves*/);
|
||||
@@ -6061,6 +6071,8 @@ bool scr_http_req_complete(ScrHttpReq *r);
|
||||
void scr_http_dyn_install(void);
|
||||
void scr_http_validate_header_name(ScrStr *name /*borrowed*/, ScrStr *label /*borrowed*/);
|
||||
void scr_http_validate_header_value(ScrStr *name /*borrowed*/, const ScrDyn *value /*borrowed*/);
|
||||
ScrDyn *scr_http_status_codes(void); /* +1, shared mutable Node v24 table */
|
||||
ScrArr *scr_http_methods(void); /* +1, shared mutable Node v24 array */
|
||||
|
||||
ScrNetServer *scr_http_create_server(ScrClosure *handler /*moves, nullable*/, ScrHttpReqFn fn); /* +1 */
|
||||
/* The unguarded h2-only stream call: throws Node's exact catchable
|
||||
@@ -6173,6 +6185,7 @@ void scr_http_req_resume(ScrHttpReq *r);
|
||||
* socket's idle timer; the flags back req.destroyed/req.readable. */
|
||||
void scr_http_req_pause(ScrHttpReq *r);
|
||||
void scr_http_req_set_timeout(ScrHttpReq *r, double ms, ScrClosure *cb /*moves, nullable*/);
|
||||
void scr_http_req_set_timeout_plain(ScrHttpReq *r, double ms);
|
||||
bool scr_http_req_destroyed_flag(ScrHttpReq *r);
|
||||
bool scr_http_req_readable(ScrHttpReq *r);
|
||||
/* flushHeaders/cork/uncork/writableCorked, the res.req backref, the
|
||||
@@ -6231,6 +6244,12 @@ ScrStr *scr_http_client_host(ScrHttpClientReq *c); /* +1 */
|
||||
ScrStr *scr_http_client_protocol(ScrHttpClientReq *c); /* +1 */
|
||||
bool scr_http_client_headers_sent(ScrHttpClientReq *c);
|
||||
bool scr_http_client_writable_ended(ScrHttpClientReq *c);
|
||||
bool scr_http_client_writable_finished(ScrHttpClientReq *c);
|
||||
ScrNetSocket *scr_http_client_socket(ScrHttpClientReq *c); /* +1 */
|
||||
bool scr_http_client_reused_socket(ScrHttpClientReq *c);
|
||||
void scr_http_client_set_nodelay(ScrHttpClientReq *c, bool enable);
|
||||
void scr_http_client_set_socket_keepalive(ScrHttpClientReq *c, bool enable, double delay_ms);
|
||||
void scr_http_client_set_timeout_cb(ScrHttpClientReq *c, double ms, ScrClosure *cb /*moves*/);
|
||||
void scr_http_client_add_trailers(ScrHttpClientReq *c, ScrArr *pairs /*borrowed*/);
|
||||
void scr_http_client_cork(ScrHttpClientReq *c);
|
||||
void scr_http_client_uncork(ScrHttpClientReq *c);
|
||||
@@ -6240,8 +6259,13 @@ void scr_http_client_write_dynv(ScrHttpClientReq *c, const ScrDyn *d /*borrowed*
|
||||
void scr_http_client_end_dynv(ScrHttpClientReq *c, const ScrDyn *d /*borrowed*/);
|
||||
void scr_http_client_set_timeout(ScrHttpClientReq *c, double ms);
|
||||
void scr_http_client_destroy(ScrHttpClientReq *c);
|
||||
void scr_http_client_abort(ScrHttpClientReq *c);
|
||||
bool scr_http_client_aborted(ScrHttpClientReq *c);
|
||||
bool scr_http_client_destroyed(ScrHttpClientReq *c);
|
||||
void scr_http_client_on_response(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, ScrHttpRespFn fn, bool once);
|
||||
void scr_http_client_on_socket(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, ScrNetConnFn fn, bool once);
|
||||
void scr_http_client_on_finish(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, bool once);
|
||||
void scr_http_client_on_abort(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, bool once);
|
||||
void scr_http_client_on_error(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, ScrChildErrFn fn, bool once);
|
||||
void scr_http_client_on_timeout(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, bool once);
|
||||
void scr_http_client_on_close(ScrHttpClientReq *c, ScrClosure *cb /*moves*/, bool once);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { createServer, request } from "node:http";
|
||||
|
||||
const server = createServer((incoming, outgoing) => {
|
||||
const headers = incoming.headersDistinct;
|
||||
const requestValue = headers["x-request"];
|
||||
console.log("request headers", requestValue === undefined ? "-" : requestValue.join("|"), Object.keys(headers).includes("host"), headers.missing === undefined);
|
||||
console.log("request raw headers", incoming.rawHeaders.includes("X-Request"));
|
||||
console.log("request early raw trailers", incoming.rawTrailers.length);
|
||||
incoming.resume();
|
||||
incoming.on("end", () => {
|
||||
const trailers = incoming.trailersDistinct;
|
||||
const trailerValue = trailers["x-tail"];
|
||||
console.log("request trailers", trailerValue === undefined ? "-" : trailerValue.join("|"), Object.keys(trailers).join(","));
|
||||
outgoing.writeHead(207, ["X-Reply", "first", "x-reply", "second", "Trailer", "X-Tail"]);
|
||||
outgoing.write("ok");
|
||||
outgoing.addTrailers([["X-Tail", "alpha"], ["x-tail", "beta"]]);
|
||||
outgoing.end();
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(0, () => {
|
||||
const outbound = request({ port: server.address().port, method: "POST", headers: { "X-Request": "one", Trailer: "X-Tail", "Transfer-Encoding": "chunked" } }, (response) => {
|
||||
const headers = response.headersDistinct;
|
||||
const replyValue = headers["x-reply"];
|
||||
console.log("response headers", replyValue === undefined ? "-" : replyValue.join("|"), Object.keys(headers).includes("x-reply"), headers.missing === undefined);
|
||||
console.log("response raw headers", response.rawHeaders.includes("X-Reply"), response.rawHeaders.includes("x-reply"));
|
||||
console.log("response early raw trailers", response.rawTrailers.length);
|
||||
response.resume();
|
||||
response.on("end", () => {
|
||||
const trailers = response.trailersDistinct;
|
||||
const trailerValue = trailers["x-tail"];
|
||||
console.log("response trailers", trailerValue === undefined ? "-" : trailerValue.join("|"), Object.keys(trailers).join(","));
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
outbound.write("ok");
|
||||
outbound.addTrailers([["X-Tail", "one"], ["x-tail", "two"]]);
|
||||
outbound.end();
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Agent, createServer, request } from "node:http";
|
||||
|
||||
const agent = new Agent({ maxSockets: 1 });
|
||||
console.log("agent defaults", agent.getName(), agent.maxSockets, agent.maxFreeSockets, agent.keepAlive, agent.protocol);
|
||||
console.log("agent name", agent.getName({ host: "example.test", port: 8080, family: 4 }));
|
||||
|
||||
const server = createServer((req, res) => { res.end(req.url); });
|
||||
server.listen(0, () => {
|
||||
const port = server.address().port;
|
||||
const name = agent.getName({ host: "127.0.0.1", port });
|
||||
const outbound = request({ hostname: "127.0.0.1", port, path: "/agent", agent }, (response) => {
|
||||
console.log("agent tables", agent.sockets[name].length, name in agent.requests, Object.keys(agent.freeSockets).length);
|
||||
let body = "";
|
||||
response.on("data", (chunk: Buffer) => { body += chunk.toString("utf8"); });
|
||||
response.on("end", () => {
|
||||
console.log("response", response.statusCode, body, agent.totalSocketCount);
|
||||
agent.destroy();
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
outbound.end();
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
import * as http from "node:http";
|
||||
import { METHODS, STATUS_CODES, maxHeaderSize } from "node:http";
|
||||
|
||||
console.log("methods", METHODS.join("|"));
|
||||
console.log("namespace", http.METHODS[0], http.METHODS[http.METHODS.length - 1]);
|
||||
console.log("header limit", maxHeaderSize, http.maxHeaderSize);
|
||||
console.log("status", STATUS_CODES[200], STATUS_CODES[418], http.STATUS_CODES[511], STATUS_CODES[299] === undefined);
|
||||
console.log("shared", METHODS === http.METHODS, STATUS_CODES === http.STATUS_CODES);
|
||||
const originalMethod = METHODS[0]!;
|
||||
METHODS[0] = "CUSTOM";
|
||||
console.log("method mutation", http.METHODS[0]);
|
||||
METHODS[0] = originalMethod;
|
||||
STATUS_CODES[299] = "Custom";
|
||||
console.log("status mutation", http.STATUS_CODES[299]);
|
||||
@@ -0,0 +1,21 @@
|
||||
import { createServer, request } from "node:http";
|
||||
|
||||
const server = createServer((req, res) => {
|
||||
res.statusCode = 418;
|
||||
res.end(req.method + " " + req.url);
|
||||
});
|
||||
server.listen(0, () => {
|
||||
const outbound = request({ port: server.address().port, path: "/controls", method: "POST" }, (response) => {
|
||||
let body = "";
|
||||
response.on("data", (chunk: Buffer) => { body += chunk.toString("utf8"); });
|
||||
response.on("end", () => {
|
||||
console.log("reply", response.statusCode, response.statusMessage, body, outbound.finished, outbound.reusedSocket);
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
console.log("initial", outbound.finished, outbound.reusedSocket);
|
||||
outbound.setNoDelay(false);
|
||||
outbound.setNoDelay();
|
||||
outbound.end();
|
||||
console.log("ended", outbound.finished, outbound.reusedSocket);
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { createServer, request } from "node:http";
|
||||
|
||||
const server = createServer((incoming, outgoing) => {
|
||||
outgoing.on("finish", () => { console.log("response finish", outgoing.finished); });
|
||||
outgoing.on("close", () => { console.log("response close", outgoing.finished); });
|
||||
const headers = incoming.headers;
|
||||
console.log("request", incoming.aborted, incoming.connection === incoming.socket, headers["x-test"], Object.keys(headers).includes("host"));
|
||||
incoming.setTimeout(500);
|
||||
let body = "";
|
||||
incoming.on("data", (chunk: Buffer) => { body += chunk.toString("utf8"); });
|
||||
incoming.on("end", () => {
|
||||
console.log("request body", body, incoming.complete, incoming.aborted);
|
||||
outgoing.end("ok");
|
||||
console.log("response finished", outgoing.finished);
|
||||
});
|
||||
incoming.on("close", () => { console.log("request close", incoming.complete); });
|
||||
});
|
||||
|
||||
server.listen(0, () => {
|
||||
const outbound = request({ port: server.address().port, method: "POST", headers: { "X-Test": "one" } }, (response) => {
|
||||
const headers = response.headers;
|
||||
console.log("reply", response.statusMessage, response.connection === response.socket, response.aborted, headers["content-length"]);
|
||||
response.setTimeout(500);
|
||||
response.on("close", () => { console.log("reply close", response.complete); });
|
||||
response.resume();
|
||||
response.on("end", () => { server.close(); });
|
||||
});
|
||||
outbound.end("ping");
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { createServer, get } from "node:http";
|
||||
|
||||
const server = createServer((_request, response) => {
|
||||
response.flushHeaders();
|
||||
setTimeout(() => { response.end("late"); }, 120);
|
||||
});
|
||||
|
||||
server.listen(0, () => {
|
||||
get({ port: server.address().port }, (response) => {
|
||||
response.setTimeout(15, () => { console.log("timed out", response.complete); });
|
||||
let body = "";
|
||||
response.on("data", (chunk: Buffer) => { body += chunk.toString("utf8"); });
|
||||
response.on("end", () => {
|
||||
console.log("body", body, response.complete);
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
import * as http from "node:http";
|
||||
|
||||
const server = http.createServer((_incoming, outgoing) => {
|
||||
setTimeout(() => outgoing.end("late"), 120);
|
||||
});
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const client = http.request({ host: "127.0.0.1", port: server.address().port }, (response) => {
|
||||
console.log("response", response.statusCode);
|
||||
response.on("data", (chunk) => console.log("body", chunk.toString()));
|
||||
response.on("end", () => server.close());
|
||||
});
|
||||
client.setSocketKeepAlive(false);
|
||||
client.setSocketKeepAlive(true, 1000);
|
||||
client.setSocketKeepAlive();
|
||||
console.log("destroyed initially", client.destroyed);
|
||||
client.on("close", () => console.log("destroyed on close", client.destroyed));
|
||||
client.setTimeout(1000);
|
||||
console.log("same request", client.setTimeout(20, () => console.log("timeout")) === client);
|
||||
client.end();
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
import * as http from "node:http";
|
||||
|
||||
const server = http.createServer(() => {});
|
||||
server.on("timeout", (socket) => console.log("listener", socket.destroyed));
|
||||
console.log("same server", server.setTimeout(20, (socket) => {
|
||||
console.log("callback", socket.destroyed);
|
||||
socket.destroy();
|
||||
server.close();
|
||||
}) === server);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const client = http.request({ host: "127.0.0.1", port: server.address().port });
|
||||
client.on("error", () => console.log("client error"));
|
||||
client.end();
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import * as http from "node:http";
|
||||
|
||||
const server = http.createServer(() => {});
|
||||
server.setTimeout(20);
|
||||
console.log("timeout", server.timeout);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const client = http.request({ host: "127.0.0.1", port: server.address().port });
|
||||
client.on("error", () => {
|
||||
console.log("closed on timeout");
|
||||
server.close();
|
||||
});
|
||||
client.end();
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import * as http from "node:http";
|
||||
|
||||
const server = http.createServer();
|
||||
server.on("connection", (socket) => console.log("connection", socket.destroyed));
|
||||
server.on("request", (incoming, outgoing) => {
|
||||
console.log("request", incoming.method);
|
||||
outgoing.end("ok");
|
||||
});
|
||||
server.on("close", () => console.log("server close"));
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const client = http.request({ host: "127.0.0.1", port: server.address().port });
|
||||
client.on("response", (incoming) => {
|
||||
console.log("response", incoming.statusCode);
|
||||
incoming.on("data", (chunk: Buffer) => console.log("data", chunk.toString()));
|
||||
incoming.on("end", () => server.close());
|
||||
});
|
||||
client.on("close", () => console.log("client close"));
|
||||
client.end();
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
import * as http from "node:http";
|
||||
|
||||
const server = http.createServer(() => {
|
||||
console.log("request started");
|
||||
server.closeAllConnections();
|
||||
server.close();
|
||||
});
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const client = http.request({ host: "127.0.0.1", port: server.address().port });
|
||||
client.on("error", () => console.log("client error"));
|
||||
client.on("close", () => console.log("client close"));
|
||||
client.end();
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import * as http from "node:http";
|
||||
import * as net from "node:net";
|
||||
|
||||
const server = http.createServer((_incoming, outgoing) => outgoing.end("ok"));
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const socket = net.connect(server.address().port, "127.0.0.1");
|
||||
let wire = "";
|
||||
socket.on("connect", () => socket.write("GET / HTTP/1.1\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n"));
|
||||
socket.on("data", (chunk: Buffer) => {
|
||||
wire += chunk.toString();
|
||||
if (wire.includes("\r\n\r\nok")) {
|
||||
console.log("response received");
|
||||
server.closeIdleConnections();
|
||||
}
|
||||
});
|
||||
socket.on("close", () => {
|
||||
console.log("idle socket closed");
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import * as http from "node:http";
|
||||
import * as net from "node:net";
|
||||
|
||||
const server = http.createServer();
|
||||
server.on("upgrade", (_request, socket) => {
|
||||
server.closeAllConnections();
|
||||
console.log("upgraded socket open", !socket.destroyed);
|
||||
socket.end("ALIVE");
|
||||
server.close();
|
||||
});
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const client = net.connect(server.address().port, "127.0.0.1");
|
||||
let body = "";
|
||||
client.on("connect", () => client.write("GET / HTTP/1.1\r\nHost: localhost\r\nConnection: Upgrade\r\nUpgrade: scr\r\n\r\n"));
|
||||
client.on("data", (chunk: Buffer) => { body += chunk.toString(); });
|
||||
client.on("end", () => console.log("received", body));
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import * as http from "node:http";
|
||||
|
||||
const server = http.createServer((_incoming, outgoing) => {
|
||||
outgoing.writeHead(200);
|
||||
outgoing.write("first");
|
||||
});
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const client = http.request({ host: "127.0.0.1", port: server.address().port }, (response) => {
|
||||
response.on("data", (chunk: Buffer) => {
|
||||
console.log("body", chunk.toString());
|
||||
response.destroy();
|
||||
});
|
||||
response.on("error", () => console.log("error"));
|
||||
response.on("aborted", () => console.log("aborted", response.aborted));
|
||||
response.on("close", () => {
|
||||
console.log("closed", response.complete);
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
client.on("error", () => console.log("client error"));
|
||||
client.end();
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import * as http from "node:http";
|
||||
|
||||
const server = http.createServer((incoming, outgoing) => {
|
||||
incoming.resume();
|
||||
incoming.on("end", () => outgoing.end("ok"));
|
||||
});
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const outbound = http.request({ host: "127.0.0.1", port: server.address().port, method: "POST" }, (response) => {
|
||||
response.resume();
|
||||
response.on("end", () => server.close());
|
||||
});
|
||||
console.log("initial", outbound.socket === outbound.connection, outbound.writableFinished, outbound.destroyed);
|
||||
outbound.on("socket", (socket) => {
|
||||
console.log("socket", socket === outbound.socket, socket.destroyed, outbound.writableFinished);
|
||||
});
|
||||
outbound.once("socket", () => console.log("socket once"));
|
||||
outbound.once("finish", () => {
|
||||
console.log("finish", outbound.writableEnded, outbound.writableFinished, outbound.destroyed);
|
||||
});
|
||||
outbound.on("close", () => {
|
||||
console.log("close", outbound.writableFinished, outbound.destroyed);
|
||||
});
|
||||
outbound.end("hi");
|
||||
console.log("ended", outbound.writableEnded, outbound.writableFinished);
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import * as http from "node:http";
|
||||
|
||||
function result(action: () => void): string {
|
||||
try {
|
||||
action();
|
||||
return "ok";
|
||||
} catch (error) {
|
||||
if (error instanceof Error) return `${error.name}:${(error as NodeJS.ErrnoException).code}:${error.message}`;
|
||||
return "unexpected error";
|
||||
}
|
||||
}
|
||||
|
||||
const server = http.createServer((incoming, outgoing) => {
|
||||
console.log("message negative", result(() => incoming.setTimeout(-1)));
|
||||
console.log("message infinite", result(() => incoming.setTimeout(Infinity, () => {})));
|
||||
incoming.resume();
|
||||
outgoing.end("ok");
|
||||
});
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const client = http.request({ host: "127.0.0.1", port: server.address().port, method: "POST" }, (response) => {
|
||||
response.resume();
|
||||
response.on("end", () => server.close());
|
||||
});
|
||||
console.log("client negative", result(() => client.setTimeout(-1)));
|
||||
console.log("client infinite", result(() => client.setTimeout(Infinity, () => {})));
|
||||
client.end("ping");
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
import * as http from "node:http";
|
||||
|
||||
const server = http.createServer((incoming, outgoing) => {
|
||||
incoming.resume();
|
||||
outgoing.end("ok");
|
||||
});
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const port = server.address().port;
|
||||
const early = http.request({ host: "127.0.0.1", port });
|
||||
console.log("early before", early.aborted, early.destroyed);
|
||||
early.on("socket", () => console.log("early socket"));
|
||||
early.on("error", (error) => console.log("early error", error.message));
|
||||
early.on("close", () => console.log("early close", early.aborted, early.destroyed));
|
||||
early.on("abort", () => {
|
||||
console.log("early abort", early.aborted, early.destroyed);
|
||||
const late = http.get({ host: "127.0.0.1", port });
|
||||
late.on("socket", () => {
|
||||
console.log("late socket", late.aborted, late.destroyed);
|
||||
late.abort();
|
||||
console.log("late after", late.aborted, late.destroyed);
|
||||
});
|
||||
late.on("abort", () => console.log("late abort", late.aborted, late.destroyed));
|
||||
late.on("error", (error) => console.log("late error", error.message));
|
||||
late.on("close", () => {
|
||||
console.log("late close", late.aborted, late.destroyed);
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
early.abort();
|
||||
console.log("early after", early.aborted, early.destroyed);
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import { createServer, get } from "node:http";
|
||||
|
||||
const server = createServer((_request, response) => {
|
||||
response.setTimeout(30, () => {
|
||||
console.log("response timeout");
|
||||
response.end("ok");
|
||||
});
|
||||
});
|
||||
server.setTimeout(30);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
get({ host: "127.0.0.1", port: server.address().port }, (response) => {
|
||||
let body = "";
|
||||
response.on("data", (chunk: Buffer) => { body += chunk.toString("utf8"); });
|
||||
response.on("end", () => {
|
||||
console.log("response body", response.statusCode, body);
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { createServer, request } from "node:http";
|
||||
|
||||
const server = createServer((incoming, outgoing) => {
|
||||
incoming.setTimeout(30, () => {
|
||||
console.log("request timeout", incoming.complete, incoming.aborted);
|
||||
outgoing.end("ok");
|
||||
});
|
||||
});
|
||||
server.setTimeout(30);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const client = request({ host: "127.0.0.1", port: server.address().port, method: "POST", headers: { "Content-Length": "5" } }, (response) => {
|
||||
let body = "";
|
||||
response.on("data", (chunk: Buffer) => { body += chunk.toString("utf8"); });
|
||||
response.on("end", () => {
|
||||
console.log("request body", response.statusCode, body);
|
||||
client.destroy();
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
client.on("error", () => {
|
||||
console.log("client error");
|
||||
server.close();
|
||||
});
|
||||
client.write("x");
|
||||
});
|
||||
Reference in New Issue
Block a user