@amritk/nish-aarch64-darwin 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/INSTALL.md +73 -59
  2. package/bin/nish +0 -0
  3. package/docs/AI.md +50 -4
  4. package/package.json +1 -1
  5. package/runtime/async.d.mts +2 -0
  6. package/runtime/async.mjs +7 -0
  7. package/runtime/nish.d.ts +4849 -430
  8. package/runtime/nish.h +25 -0
  9. package/runtime/page.d.ts +53 -0
  10. package/runtime/page.mjs +146 -0
  11. package/runtime/runtime-async.c +557 -0
  12. package/runtime/runtime-wasm.c +63 -7
  13. package/runtime/vite.d.ts +30 -0
  14. package/runtime/vite.mjs +150 -0
  15. package/scripts/build.sh +252 -15
  16. package/std/README.md +107 -82
  17. package/std/base64.ts +34 -5
  18. package/std/bytes.ts +279 -59
  19. package/std/cli-args.ts +296 -70
  20. package/std/cli-flags.ts +184 -19
  21. package/std/cli.ts +475 -54
  22. package/std/collections.ts +121 -23
  23. package/std/compress/checksum.ts +44 -14
  24. package/std/compress/deflate.ts +224 -111
  25. package/std/compress/gzip.ts +217 -53
  26. package/std/compress/zlib.ts +63 -7
  27. package/std/crypto/aes.ts +128 -52
  28. package/std/crypto/base64url.ts +29 -5
  29. package/std/crypto/bcrypt-batch.ts +101 -34
  30. package/std/crypto/bcrypt.ts +93 -27
  31. package/std/crypto/chacha20poly1305.ts +69 -14
  32. package/std/crypto/ct.ts +32 -13
  33. package/std/crypto/ed25519.ts +66 -16
  34. package/std/crypto/hkdf.ts +198 -13
  35. package/std/crypto/hmac.ts +242 -37
  36. package/std/crypto/jwt.ts +204 -72
  37. package/std/crypto/p256.ts +222 -72
  38. package/std/crypto/p384.ts +51 -23
  39. package/std/crypto/pki-roots.ts +32 -2
  40. package/std/crypto/pki.ts +99 -30
  41. package/std/crypto/rsa.ts +56 -22
  42. package/std/crypto/sha1.ts +3 -0
  43. package/std/crypto/sha256.ts +24 -1
  44. package/std/crypto/sha512.ts +99 -14
  45. package/std/crypto/x25519.ts +163 -24
  46. package/std/crypto/x509-random.ts +10 -0
  47. package/std/crypto/x509.ts +133 -66
  48. package/std/host/ring.ts +124 -0
  49. package/std/json-equal.ts +31 -11
  50. package/std/json-format.ts +112 -13
  51. package/std/json-number.ts +76 -26
  52. package/std/json-pointer.ts +23 -1
  53. package/std/json-tokenizer.ts +126 -51
  54. package/std/json-typed.ts +757 -96
  55. package/std/json-value.ts +438 -157
  56. package/std/json.ts +170 -38
  57. package/std/map.ts +25 -7
  58. package/std/math.ts +36 -4
  59. package/std/net/buffer-pool.ts +42 -11
  60. package/std/net/dns-config.ts +109 -23
  61. package/std/net/dns-message.ts +62 -7
  62. package/std/net/dns-resolver.ts +247 -53
  63. package/std/net/dns.ts +203 -35
  64. package/std/net/fetch.ts +1267 -290
  65. package/std/net/handler.ts +296 -80
  66. package/std/net/hpack.ts +290 -77
  67. package/std/net/http-compress.ts +152 -36
  68. package/std/net/http-fields.ts +85 -9
  69. package/std/net/http1-client-codec.ts +129 -44
  70. package/std/net/http1-codec.ts +279 -114
  71. package/std/net/http1-server.ts +409 -139
  72. package/std/net/http2-frame.ts +289 -51
  73. package/std/net/http2-tls.ts +152 -49
  74. package/std/net/http2.ts +314 -160
  75. package/std/net/http3-frame.ts +165 -27
  76. package/std/net/http3-server.ts +282 -131
  77. package/std/net/http3.ts +377 -173
  78. package/std/net/outbound.ts +37 -3
  79. package/std/net/postgres-carrier.ts +144 -8
  80. package/std/net/postgres.ts +898 -260
  81. package/std/net/prefork.ts +202 -65
  82. package/std/net/qpack.ts +120 -32
  83. package/std/net/quic-conn-ack.ts +60 -12
  84. package/std/net/quic-conn-cid.ts +135 -27
  85. package/std/net/quic-conn-params.ts +109 -22
  86. package/std/net/quic-datagram.ts +50 -3
  87. package/std/net/quic-frame.ts +333 -23
  88. package/std/net/quic-listener.ts +161 -75
  89. package/std/net/quic-packet.ts +373 -73
  90. package/std/net/quic-recovery.ts +287 -65
  91. package/std/net/quic-stream.ts +436 -146
  92. package/std/net/quic.ts +693 -323
  93. package/std/net/router.ts +87 -40
  94. package/std/net/tls/client.ts +167 -51
  95. package/std/net/tls/codec.ts +494 -68
  96. package/std/net/tls/record-client.ts +140 -73
  97. package/std/net/tls/record-server.ts +233 -105
  98. package/std/net/tls/record.ts +142 -36
  99. package/std/net/tls/schedule.ts +235 -26
  100. package/std/net/tls/ticket.ts +161 -40
  101. package/std/net/tls/verify.ts +57 -10
  102. package/std/net/tls-tcp.ts +308 -95
  103. package/std/net/tls.ts +276 -102
  104. package/std/net/upstream.ts +81 -45
  105. package/std/net/url.ts +109 -22
  106. package/std/net/websocket.ts +140 -26
  107. package/std/net/webtransport.ts +243 -106
  108. package/std/pair.ts +10 -2
  109. package/std/random.ts +42 -15
  110. package/std/regex.ts +422 -257
  111. package/std/region.ts +70 -15
  112. package/std/secret.ts +52 -11
  113. package/std/sort.ts +17 -2
  114. package/std/sqlite.ts +256 -35
  115. package/std/sync/ring.ts +229 -56
  116. package/std/sync/shm.ts +203 -23
  117. package/std/term-io.ts +154 -78
  118. package/std/term-pixels.ts +144 -19
  119. package/std/term-probe.ts +77 -35
  120. package/std/term-rate.ts +199 -118
  121. package/std/term.ts +400 -175
  122. package/std/testing.ts +130 -32
  123. package/std/text.ts +84 -17
  124. package/std/threads.ts +248 -56
  125. package/std/yaml-json.ts +111 -97
  126. package/std/yaml-lines.ts +47 -15
  127. package/std/yaml-write.ts +45 -30
  128. package/std/yaml.ts +764 -384
@@ -162,7 +162,10 @@ export class HandlerLimits {
162
162
  http: Http1Config
163
163
  /** The most connections at once. */
164
164
  slots: i32 = 256
165
- /** The JSON scratch buffer's size: the largest body `json` and `problem` can write. */
165
+ /**
166
+ * Bytes in the JSON scratch buffer: the largest body `json` and `problem`
167
+ * can write. A value past it makes `sendJson` answer 500. At least 256.
168
+ */
166
169
  jsonBytes: i32 = 65536
167
170
  /** The most readiness events one `wait` takes. */
168
171
  maxEvents: i32 = 256
@@ -176,6 +179,11 @@ export class HandlerLimits {
176
179
  */
177
180
  bodyTimeout: i32 = 30000
178
181
 
182
+ /**
183
+ * The defaults: 256 slots, a 64 KiB JSON buffer, 256 events a turn, a 30
184
+ * second body timeout, and the carrier's own defaults with the body cap
185
+ * lowered to one MiB. Change a field after construction to tune one.
186
+ */
179
187
  constructor() {
180
188
  this.http = new Http1Config()
181
189
  this.http.maxBody = HANDLER_ONE_MIB
@@ -190,37 +198,85 @@ export class HandlerLimits {
190
198
  export class HttpRequest {
191
199
  /** The method, the target and the header section, as the parser kept them (field names lowercased). */
192
200
  head: u8[]
193
- /** Four per field, into `head`: name start and end, value start and end. */
201
+ /**
202
+ * Four per field, into `head`: name start and end, value start and end.
203
+ * @internal Filled by `HttpHandler` in this module when it copies the head, and read by `header`, `valueStart` and `valueEnd`.
204
+ */
194
205
  spans: i32[]
195
- /** The route parameters as `[start, end)` pairs into `head`, in the pattern's order. */
206
+ /**
207
+ * The route parameters as `[start, end)` pairs into `head`, in the pattern's order.
208
+ * @internal Filled by `HttpHandler` in this module from `Router.match`; programs read them through `paramStart`, `param` and the rest.
209
+ */
196
210
  params: i32[]
197
211
  /** The body, `body[0 .. bodyLength)`. */
198
212
  body: u8[]
199
- /** What the carrier had no room for yet: `pending[pendingStart .. pendingEnd)`. */
213
+ /**
214
+ * What the carrier had no room for yet: `pending[pendingStart .. pendingEnd)`.
215
+ * @internal Written and flushed by `HttpHandler` in this module while it streams the response.
216
+ */
200
217
  pending: u8[]
201
- /** When the head was read, as the handler's turn saw it (`monotonicNanos`); `bodyTimeout` runs from here. */
218
+ /**
219
+ * When the head was read, as the handler's turn saw it (`monotonicNanos`); `bodyTimeout` runs from here.
220
+ * @internal Stamped and checked by `HttpHandler` in this module to close a connection whose body trickles past `bodyTimeout`.
221
+ */
202
222
  since: i64 = 0
203
223
  /** The index `Router.add` answered for the route, or a negative `ROUTER_*` code. */
204
224
  route: i32 = 0
205
- /** How many parameter pairs `params` holds. */
225
+ /**
226
+ * How many parameter pairs `params` holds.
227
+ * @internal Set by `HttpHandler` in this module after routing; the param accessors check `k` against it.
228
+ */
206
229
  paramCount: i32 = 0
230
+ /** Where the method starts in `head`; the method is `head[methodStart .. methodEnd)`, for a log line or a `Router.match`. */
207
231
  methodStart: i32 = 0
232
+ /** Where the method ends in `head`, one past its last byte. */
208
233
  methodEnd: i32 = 0
234
+ /** Where the request target (path and query) starts in `head`; the target is `head[targetStart .. targetEnd)`. */
209
235
  targetStart: i32 = 0
236
+ /** Where the request target ends in `head`, one past its last byte. */
210
237
  targetEnd: i32 = 0
211
- /** Where the path ends: the target's first `?`, or its end. */
238
+ /**
239
+ * Where the path ends: the target's first `?`, or its end.
240
+ * @internal Set by `HttpHandler` in this module when it copies the head, and read by `pathIs` and `queryIndex`.
241
+ */
212
242
  pathEnd: i32 = 0
243
+ /**
244
+ * How many fields `spans` describes.
245
+ * @internal Set by `HttpHandler` in this module when it copies the head, and read by `header`.
246
+ */
213
247
  headerCount: i32 = 0
248
+ /** How many bytes of `body` are the request's body, 0 for none; read the body as `body[0 .. bodyLength)`. */
214
249
  bodyLength: i32 = 0
215
250
  /** The connection's slot, and its generation when this request was read. */
216
251
  slot: i32 = 0
252
+ /**
253
+ * The slot's generation when this request was read.
254
+ * @internal Read by `HttpHandler` in this module, which drops a reply to a slot that has since closed and been reused.
255
+ */
217
256
  gen: i32 = 0
218
257
  /** Its index in the handler's pool. */
219
258
  index: i32 = 0
259
+ /**
260
+ * Where the request is in its life, one of the module's private `HANDLER_*` states.
261
+ * @internal Moved by `HttpHandler` in this module from the free list through reading, queued, held and streaming, and back.
262
+ */
220
263
  state: i32 = 0
264
+ /**
265
+ * Where the unsent bytes in `pending` start.
266
+ * @internal Advanced by `HttpHandler` in this module as the carrier takes pending bytes.
267
+ */
221
268
  pendingStart: i32 = 0
269
+ /**
270
+ * Where the unsent bytes in `pending` end.
271
+ * @internal Advanced by `HttpHandler` in this module as `write` keeps what the carrier had no room for.
272
+ */
222
273
  pendingEnd: i32 = 0
223
274
 
275
+ /**
276
+ * An empty request for the handler's pool; its buffers grow to the first
277
+ * request it holds and are kept for the ones after.
278
+ * @param index its place in the handler's pool, which the free list and the queue name it by
279
+ */
224
280
  constructor(index: i32) {
225
281
  this.index = index
226
282
  this.head = []
@@ -230,29 +286,50 @@ export class HttpRequest {
230
286
  this.pending = []
231
287
  }
232
288
 
233
- /** Whether the method is exactly `method` (methods are case-sensitive, RFC 9110 §9.1). */
289
+ /**
290
+ * Whether the method is exactly `method` (methods are case-sensitive, RFC 9110 §9.1).
291
+ * @param method the method name to compare with, such as `"GET"`
292
+ * @returns true when the request's method is byte for byte `method`
293
+ */
234
294
  methodIs(method: string): boolean {
235
295
  return handlerSpanIs(this.head, this.methodStart, this.methodEnd, method)
236
296
  }
237
297
 
238
- /** Whether the path, the target up to its `?`, is exactly `path`. */
298
+ /**
299
+ * Whether the path, the target up to its `?`, is exactly `path`.
300
+ * @param path the raw path to compare with, still percent-encoded as it came on the wire
301
+ * @returns true when the target's path, without its query, is byte for byte `path`
302
+ */
239
303
  pathIs(path: string): boolean {
240
304
  return handlerSpanIs(this.head, this.targetStart, this.pathEnd, path)
241
305
  }
242
306
 
243
- /** Where parameter `k` starts in `head`. Panics on a parameter the route does not have. */
307
+ /**
308
+ * Where parameter `k` starts in `head`. Panics on a parameter the route does not have.
309
+ * @param k the parameter's position in the route pattern, from 0
310
+ * @returns the byte offset in `head` of the parameter's first raw byte
311
+ */
244
312
  paramStart(k: i32): i32 {
245
313
  this.checkParam(k)
246
314
  return this.params[2 * k]
247
315
  }
248
316
 
249
- /** Where parameter `k` ends in `head`. */
317
+ /**
318
+ * Where parameter `k` ends in `head`.
319
+ * @param k the parameter's position in the route pattern, from 0
320
+ * @returns the byte offset in `head` just past the parameter's last raw byte
321
+ */
250
322
  paramEnd(k: i32): i32 {
251
323
  this.checkParam(k)
252
324
  return this.params[2 * k + 1]
253
325
  }
254
326
 
255
- /** Whether parameter `k`, raw, is exactly `text`. */
327
+ /**
328
+ * Whether parameter `k`, raw, is exactly `text`.
329
+ * @param k the parameter's position in the route pattern, from 0
330
+ * @param text the value to compare with, as it would appear still percent-encoded
331
+ * @returns true when the raw parameter bytes are exactly `text`
332
+ */
256
333
  paramIs(k: i32, text: string): boolean {
257
334
  this.checkParam(k)
258
335
  return handlerSpanIs(this.head, this.params[2 * k], this.params[2 * k + 1], text)
@@ -262,19 +339,26 @@ export class HttpRequest {
262
339
  * Parameter `k` percent-decoded into `out` from 0 (`routerDecode`): its
263
340
  * length, `ROUTER_BAD_ESCAPE` for a malformed escape, or `ROUTER_NO_ROOM`
264
341
  * when `out` is too short. Nothing is written on a code.
342
+ * @param k the parameter's position in the route pattern, from 0
343
+ * @param out where the decoded bytes go, from index 0; the caller's buffer
344
+ * @returns how many decoded bytes were written, or a negative `ROUTER_*` code
265
345
  */
266
346
  param(k: i32, out: u8[]): i32 {
267
347
  this.checkParam(k)
268
348
  return routerDecode(this.head, this.params[2 * k], this.params[2 * k + 1], out)
269
349
  }
270
350
 
271
- /** Parameter `k` read as a decimal number that is not negative and fits an `i32`, or -1. */
351
+ /**
352
+ * Parameter `k` read as a decimal number that is not negative and fits an `i32`, or -1.
353
+ * @param k the parameter's position in the route pattern, from 0
354
+ * @returns the number the parameter's digits spell, or -1 when it is empty, holds a non-digit or overflows
355
+ */
272
356
  paramDecimal(k: i32): i32 {
273
357
  this.checkParam(k)
274
358
  return handlerDecimal(this.head, this.params[2 * k], this.params[2 * k + 1])
275
359
  }
276
360
 
277
- checkParam(k: i32): void {
361
+ private checkParam(k: i32): void {
278
362
  if (k < 0 || k >= this.paramCount) {
279
363
  panic(`HttpRequest.param: the route has ${this.paramCount} parameter(s), not one at ${k}`)
280
364
  }
@@ -287,6 +371,9 @@ export class HttpRequest {
287
371
  * decoded too. `HANDLER_ABSENT` when no parameter has the name,
288
372
  * `ROUTER_BAD_ESCAPE` for a malformed escape in its value, `ROUTER_NO_ROOM`
289
373
  * when `out` is too short. A name with no `=` has an empty value.
374
+ * @param name the parameter name to look for, compared with each name after decoding
375
+ * @param out where the decoded value goes, from index 0; the caller's buffer
376
+ * @returns how many decoded bytes were written, or `HANDLER_ABSENT` or a negative `ROUTER_*` code
290
377
  */
291
378
  query(name: string, out: u8[]): i32 {
292
379
  const at: i32 = this.queryIndex(name)
@@ -296,16 +383,25 @@ export class HttpRequest {
296
383
  return handlerFormDecode(this.head, this.queryValueStart, this.queryValueEnd, out)
297
384
  }
298
385
 
299
- /** Whether the query holds a parameter named `name`. */
386
+ /**
387
+ * Whether the query holds a parameter named `name`.
388
+ * @param name the parameter name to look for, compared with each name after decoding
389
+ * @returns true when some pair in the query has that name, even with an empty value
390
+ */
300
391
  hasQuery(name: string): boolean {
301
392
  return this.queryIndex(name) >= 0
302
393
  }
303
394
 
304
395
  /** The span `queryIndex` found, raw. */
305
396
  queryValueStart: i32 = 0
397
+ /** Where the raw value `queryIndex` found ends in `head`, one past its last byte; it starts at `queryValueStart`. */
306
398
  queryValueEnd: i32 = 0
307
399
 
308
- /** Finds the first parameter named `name`: where its pair starts, or -1; its raw value goes to `queryValue...`. */
400
+ /**
401
+ * Finds the first parameter named `name`: where its pair starts, or -1; its raw value goes to `queryValue...`.
402
+ * @param name the parameter name to look for, compared with each name after decoding
403
+ * @returns the byte offset in `head` where the matching `name=value` pair starts, or -1 when none matches
404
+ */
309
405
  queryIndex(name: string): i32 {
310
406
  let at: i32 = this.pathEnd + 1
311
407
  const end: i32 = this.targetEnd
@@ -328,7 +424,11 @@ export class HttpRequest {
328
424
  return -1
329
425
  }
330
426
 
331
- /** The index of the first field named `name`, which is lowercase, or `HANDLER_ABSENT`. */
427
+ /**
428
+ * The index of the first field named `name`, which is lowercase, or `HANDLER_ABSENT`.
429
+ * @param name the field name in lowercase, since the parser lowercased every name it kept
430
+ * @returns the field's index for `valueStart` and `valueEnd`, or `HANDLER_ABSENT` when no field has the name
431
+ */
332
432
  header(name: string): i32 {
333
433
  for (let i: i32 = 0; i < this.headerCount; i++) {
334
434
  if (handlerSpanIs(this.head, this.spans[4 * i], this.spans[4 * i + 1], name)) {
@@ -338,17 +438,30 @@ export class HttpRequest {
338
438
  return HANDLER_ABSENT
339
439
  }
340
440
 
341
- /** Where field `i`'s value starts in `head`. */
441
+ /**
442
+ * Where field `i`'s value starts in `head`.
443
+ * @param i a field index, as `header` answered it
444
+ * @returns the byte offset in `head` of the value's first byte
445
+ */
342
446
  valueStart(i: i32): i32 {
343
447
  return this.spans[4 * i + 2]
344
448
  }
345
449
 
346
- /** Where field `i`'s value ends in `head`. */
450
+ /**
451
+ * Where field `i`'s value ends in `head`.
452
+ * @param i a field index, as `header` answered it
453
+ * @returns the byte offset in `head` just past the value's last byte
454
+ */
347
455
  valueEnd(i: i32): i32 {
348
456
  return this.spans[4 * i + 3]
349
457
  }
350
458
 
351
- /** Whether the first field named `name` (lowercase) has exactly the value `value`. */
459
+ /**
460
+ * Whether the first field named `name` (lowercase) has exactly the value `value`.
461
+ * @param name the field name in lowercase
462
+ * @param value the value to compare with, byte for byte and case-sensitive
463
+ * @returns true when the field is present and its first occurrence has exactly that value
464
+ */
352
465
  headerIs(name: string, value: string): boolean {
353
466
  const i: i32 = this.header(name)
354
467
  return i >= 0 && handlerSpanIs(this.head, this.spans[4 * i + 2], this.spans[4 * i + 3], value)
@@ -360,64 +473,85 @@ export class HttpRequest {
360
473
  * requests. One per thread; nothing in it is shared.
361
474
  */
362
475
  export class HttpHandler {
476
+ /**
477
+ * The HTTP/1.1 carrier the handler drives.
478
+ * @internal Read only by this class, which accepts, reads, flushes and closes connections through it.
479
+ */
363
480
  server: Http1Server
364
- router: Router
481
+ private router: Router
365
482
  /** Every request the pool has made, and the indices of the free ones. */
366
- requests: HttpRequest[]
367
- free: i32[]
483
+ private requests: HttpRequest[]
484
+ private free: i32[]
368
485
  /** Whole requests waiting for `take`, a ring of `queue.length` with `queueCount` from `queueStart`. */
369
- queue: i32[]
486
+ private queue: i32[]
370
487
  /** Per slot: its generation, its request (-1 for none), and whether it holds a connection. */
371
- slotGen: i32[]
372
- current: i32[]
373
- open: boolean[]
488
+ private slotGen: i32[]
489
+ private current: i32[]
490
+ private open: boolean[]
374
491
  /** `pollWait`'s output. */
375
- readyFds: i32[]
492
+ private readyFds: i32[]
376
493
  /** Per watched id: whether its descriptor was ready in the last `wait`. */
377
- watchedFired: boolean[]
494
+ private watchedFired: boolean[]
378
495
  /** `json` and `problem` write here. */
379
496
  scratch: u8[]
497
+ /**
498
+ * The JSON writer over `scratch`.
499
+ * @internal Read only by this class; programs get it from `json`.
500
+ */
380
501
  writer: JsonWriter
381
502
  /** `refuse`'s scratch for `Router.match`. */
382
- probe: i32[]
503
+ private probe: i32[]
383
504
  /** One field for `send`; two for a 405. */
384
- typeName: u8[][]
385
- typeValue: u8[][]
386
- allowNames: u8[][]
387
- allowValues: u8[][]
505
+ private typeName: u8[][]
506
+ private typeValue: u8[][]
507
+ private allowNames: u8[][]
508
+ private allowValues: u8[][]
388
509
  /** Each `Allow` value made, by the bit mask of the methods it lists: made once a mask and kept. */
389
- allowMasks: i64[]
390
- allowBytes: u8[][]
391
- jsonType: u8[]
392
- problemType: u8[]
393
- noFields: u8[][]
510
+ private allowMasks: i64[]
511
+ private allowBytes: u8[][]
512
+ private jsonType: u8[]
513
+ private problemType: u8[]
514
+ private noFields: u8[][]
394
515
  /**
395
516
  * When an accept failed for want of a resource (EMFILE, ENFILE, ENOMEM):
396
517
  * the listener is out of the loop until then, which it would otherwise wake
397
518
  * every turn while its connection waits. 0 while it is in the loop.
398
519
  */
399
- acceptRestUntil: i64 = 0
520
+ private acceptRestUntil: i64 = 0
400
521
  /** `bodyTimeout` in nanoseconds. */
401
- bodyTimeout: i64 = 0
402
- /** When the current turn's sockets were ready (`monotonicNanos`): a head read in it is stamped with this. */
522
+ private bodyTimeout: i64 = 0
523
+ /**
524
+ * When the current turn's sockets were ready (`monotonicNanos`): a head read in it is stamped with this.
525
+ * @internal Read by std/net/upstream.ts, whose `pump` compares it with the last turn it saw to run once per handler turn.
526
+ */
403
527
  turnAt: i64 = 0
404
528
  /** When `wait` next looks for a body past `bodyTimeout`. */
405
- bodyCheckAt: i64 = 0
406
- listener: i32 = 0
529
+ private bodyCheckAt: i64 = 0
530
+ private listener: i32 = 0
531
+ /**
532
+ * The readiness loop's descriptor, from `pollCreate`.
533
+ * @internal Read by std/net/upstream.ts to add its upstream sockets to the same loop, so one `wait` serves both.
534
+ */
407
535
  loop: i32 = 0
408
- queueStart: i32 = 0
409
- queueCount: i32 = 0
410
- outputSize: i32 = 0
536
+ private queueStart: i32 = 0
537
+ private queueCount: i32 = 0
538
+ private outputSize: i32 = 0
411
539
  /** Set by `drain`: accept nothing more and close each connection once it is idle. */
412
- draining: boolean = false
540
+ private draining: boolean = false
413
541
  /** Whether `json` gave out the writer for a value `sendJson` has not yet sent. */
414
- jsonBegun: boolean = false
542
+ private jsonBegun: boolean = false
415
543
 
416
544
  /**
417
545
  * A handler over `listener`, a listening socket the program made
418
546
  * (`tcpListen`, or `tcpListenFlags` with SO_REUSEPORT for a worker of
419
547
  * `nish/net/prefork`), routing through `router`, whose routes are added
420
548
  * before the first `wait`.
549
+ * @param limits the caps and timeouts. `slots`, `jsonBytes`, `maxEvents`
550
+ * and `bodyTimeout` are read once here, so changing them later has no
551
+ * effect; `http` is kept by the carrier, which reads its timeouts and
552
+ * caps live
553
+ * @param listener the listening socket's descriptor, still the program's to close
554
+ * @param router the routes, which the handler keeps and consults at each request head
421
555
  */
422
556
  constructor(limits: HandlerLimits, listener: i32, router: Router) {
423
557
  if (limits.slots < 1 || limits.jsonBytes < 256 || limits.maxEvents < 1 || limits.bodyTimeout < 1) {
@@ -469,6 +603,8 @@ export class HttpHandler {
469
603
  * `HANDLER_MAX_WATCHED - 1`): `fired(id)` says whether it was ready in the
470
604
  * last `wait`. For a program's own descriptors — `signalFd()` for a
471
605
  * graceful stop, a pipe from another thread.
606
+ * @param fd the program's descriptor to watch for reading; it stays the program's to read and close
607
+ * @param id the name `fired` asks about it by, from 0 to `HANDLER_MAX_WATCHED - 1`
472
608
  */
473
609
  watch(fd: i32, id: i32): void {
474
610
  if (id < 0 || id >= HANDLER_MAX_WATCHED) {
@@ -477,7 +613,11 @@ export class HttpHandler {
477
613
  pollAdd(this.loop, fd, H1_WANT_READ, -2 - id)
478
614
  }
479
615
 
480
- /** Whether watched descriptor `id` was ready in the last `wait`. */
616
+ /**
617
+ * Whether watched descriptor `id` was ready in the last `wait`.
618
+ * @param id the name the descriptor was given to `watch`
619
+ * @returns true when it was readable in the last turn; false for an id outside the range
620
+ */
481
621
  fired(id: i32): boolean {
482
622
  return id >= 0 && id < HANDLER_MAX_WATCHED && this.watchedFired[id]
483
623
  }
@@ -487,6 +627,8 @@ export class HttpHandler {
487
627
  * socket to be ready, accepts, reads and writes what is, closes the
488
628
  * connections past their timeouts, and answers how many whole requests
489
629
  * are waiting for `take`.
630
+ * @param timeoutMs the longest to block, in milliseconds, or -1 to block until something is ready
631
+ * @returns how many whole requests are queued for `take` after this turn
490
632
  */
491
633
  wait(timeoutMs: i32): i32 {
492
634
  for (let id: i32 = 0; id < HANDLER_MAX_WATCHED; id++) {
@@ -569,7 +711,7 @@ export class HttpHandler {
569
711
  }
570
712
 
571
713
  /** Takes every waiting connection. */
572
- acceptAll(): void {
714
+ private acceptAll(): void {
573
715
  if (this.draining) {
574
716
  return
575
717
  }
@@ -594,7 +736,7 @@ export class HttpHandler {
594
736
  * Takes `slot`'s events until it needs the socket again, then sends what it
595
737
  * holds and re-arms it, or closes it once it is over.
596
738
  */
597
- drive(slot: i32): void {
739
+ private drive(slot: i32): void {
598
740
  const conn: Http1Connection = this.server.connection(slot)
599
741
  let event: i32 = this.server.next(slot)
600
742
  while (event !== H1_NEED_MORE && event !== H1_ERROR) {
@@ -633,12 +775,12 @@ export class HttpHandler {
633
775
  }
634
776
 
635
777
  /** Whether `conn`'s output holds at most half its size unsent, so a response head fits behind it. */
636
- roomy(conn: Http1Connection): boolean {
778
+ private roomy(conn: Http1Connection): boolean {
637
779
  return (conn.outputEnd - conn.outputStart) * 2 <= this.outputSize
638
780
  }
639
781
 
640
782
  /** A head: a request from the free list, the head copied into it, and its route. */
641
- begin(slot: i32, conn: Http1Connection): void {
783
+ private begin(slot: i32, conn: Http1Connection): void {
642
784
  if (this.draining) {
643
785
  // A head read during the drain is the connection's last.
644
786
  conn.closeAfter = true
@@ -683,7 +825,7 @@ export class HttpHandler {
683
825
  * that route, since a GET resource answers HEAD (RFC 9110 §9.3.2) and the
684
826
  * carrier sends no body for it.
685
827
  */
686
- route(r: HttpRequest): void {
828
+ private route(r: HttpRequest): void {
687
829
  const params: i32[] = r.params
688
830
  let route: i32 = this.router.match(
689
831
  r.head,
@@ -716,7 +858,7 @@ export class HttpHandler {
716
858
  }
717
859
 
718
860
  /** Body bytes: appended to the request's body, which the carrier's cap bounds. */
719
- gather(slot: i32, conn: Http1Connection): void {
861
+ private gather(slot: i32, conn: Http1Connection): void {
720
862
  const at: i32 = this.current[slot]
721
863
  if (at < 0) {
722
864
  return
@@ -734,7 +876,7 @@ export class HttpHandler {
734
876
  }
735
877
 
736
878
  /** The request is whole: queued for `take`, or parked while the response before it is still mostly unsent. */
737
- whole(slot: i32, conn: Http1Connection): void {
879
+ private whole(slot: i32, conn: Http1Connection): void {
738
880
  const at: i32 = this.current[slot]
739
881
  if (at < 0) {
740
882
  return
@@ -747,7 +889,7 @@ export class HttpHandler {
747
889
  }
748
890
  }
749
891
 
750
- enqueue(r: HttpRequest): void {
892
+ private enqueue(r: HttpRequest): void {
751
893
  r.state = HANDLER_QUEUED
752
894
  const size: i32 = toI32(this.queue.length)
753
895
  if (this.queueCount === size) {
@@ -763,7 +905,7 @@ export class HttpHandler {
763
905
  }
764
906
 
765
907
  /** `H1_WRITE`: the carrier has room again for the response under way. */
766
- resume(slot: i32, conn: Http1Connection): void {
908
+ private resume(slot: i32, conn: Http1Connection): void {
767
909
  const at: i32 = this.current[slot]
768
910
  if (at < 0) {
769
911
  return
@@ -779,7 +921,7 @@ export class HttpHandler {
779
921
  }
780
922
 
781
923
  /** Hands the carrier as much of `r`'s pending bytes as it takes. */
782
- pushPending(r: HttpRequest, conn: Http1Connection): void {
924
+ private pushPending(r: HttpRequest, conn: Http1Connection): void {
783
925
  const left: i32 = r.pendingEnd - r.pendingStart
784
926
  if (left === 0) {
785
927
  return
@@ -795,7 +937,7 @@ export class HttpHandler {
795
937
  }
796
938
 
797
939
  /** Ends `r`'s response once nothing is pending, and hands `r` back; otherwise leaves it flushing. */
798
- finish(r: HttpRequest, conn: Http1Connection): void {
940
+ private finish(r: HttpRequest, conn: Http1Connection): void {
799
941
  r.state = HANDLER_FLUSHING
800
942
  if (r.pendingEnd > r.pendingStart) {
801
943
  return
@@ -809,7 +951,7 @@ export class HttpHandler {
809
951
  }
810
952
 
811
953
  /** A free request, or a new one. */
812
- obtain(): HttpRequest {
954
+ private obtain(): HttpRequest {
813
955
  const count: i32 = toI32(this.free.length)
814
956
  if (count > 0) {
815
957
  const at: i32 = this.free[count - 1]
@@ -822,7 +964,7 @@ export class HttpHandler {
822
964
  return r
823
965
  }
824
966
 
825
- release(r: HttpRequest): void {
967
+ private release(r: HttpRequest): void {
826
968
  if (r.state === HANDLER_FREE) {
827
969
  return
828
970
  }
@@ -831,7 +973,7 @@ export class HttpHandler {
831
973
  }
832
974
 
833
975
  /** Hands back the request `slot` was reading when the carrier refused it. */
834
- releaseReading(slot: i32): void {
976
+ private releaseReading(slot: i32): void {
835
977
  const at: i32 = this.current[slot]
836
978
  if (at >= 0 && this.requests[at].state === HANDLER_READING) {
837
979
  this.current[slot] = -1
@@ -844,13 +986,13 @@ export class HttpHandler {
844
986
  * dropped. A request the handler alone holds goes back now; one queued or
845
987
  * taken goes back when `ready` passes it or the program answers it.
846
988
  */
847
- closeSlot(slot: i32): void {
989
+ private closeSlot(slot: i32): void {
848
990
  this.server.close(slot)
849
991
  this.forget(slot)
850
992
  }
851
993
 
852
994
  /** The bookkeeping of a slot the carrier has closed. */
853
- forget(slot: i32): void {
995
+ private forget(slot: i32): void {
854
996
  this.open[slot] = false
855
997
  this.slotGen[slot] = this.slotGen[slot] + 1
856
998
  const at: i32 = this.current[slot]
@@ -864,7 +1006,7 @@ export class HttpHandler {
864
1006
  }
865
1007
 
866
1008
  /** Closes every connection whose request has been reading its body for longer than `bodyTimeout` at `now`. */
867
- expireBodies(now: i64): void {
1009
+ private expireBodies(now: i64): void {
868
1010
  for (let s: i32 = 0; s < toI32(this.current.length) && s < toI32(this.open.length); s++) {
869
1011
  const at: i32 = this.current[s]
870
1012
  if (this.open[s] && at >= 0 && at < toI32(this.requests.length)) {
@@ -877,7 +1019,7 @@ export class HttpHandler {
877
1019
  }
878
1020
 
879
1021
  /** Every slot the carrier's `expire` closed. */
880
- sweep(): void {
1022
+ private sweep(): void {
881
1023
  for (let s: i32 = 0; s < toI32(this.open.length); s++) {
882
1024
  if (this.open[s] && !this.server.holds(s)) {
883
1025
  this.forget(s)
@@ -887,7 +1029,10 @@ export class HttpHandler {
887
1029
 
888
1030
  // ---- Requests -------------------------------------------------------------------
889
1031
 
890
- /** Whether a whole request is waiting for `take`. Requests whose connection closed while queued are handed back here. */
1032
+ /**
1033
+ * Whether a whole request is waiting for `take`. Requests whose connection closed while queued are handed back here.
1034
+ * @returns true when `take` will give out a request whose connection is still open
1035
+ */
891
1036
  ready(): boolean {
892
1037
  while (this.queueCount > 0) {
893
1038
  const r: HttpRequest = this.requests[this.queue[this.queueStart]]
@@ -901,7 +1046,10 @@ export class HttpHandler {
901
1046
  return false
902
1047
  }
903
1048
 
904
- /** The next whole request, which the program now owes an answer. Panics when none is `ready`. */
1049
+ /**
1050
+ * The next whole request, which the program now owes an answer. Panics when none is `ready`.
1051
+ * @returns the oldest queued request, the program's until it answers it
1052
+ */
905
1053
  take(): HttpRequest {
906
1054
  if (!this.ready()) {
907
1055
  panic("HttpHandler.take: no request is ready")
@@ -914,16 +1062,22 @@ export class HttpHandler {
914
1062
  }
915
1063
 
916
1064
  /** Whether `r`'s connection is the one it was read on, still open. */
917
- live(r: HttpRequest): boolean {
1065
+ private live(r: HttpRequest): boolean {
918
1066
  return this.server.holds(r.slot) && this.slotGen[r.slot] === r.gen
919
1067
  }
920
1068
 
921
- /** How many requests the pool has made: the most ever in flight at once. */
1069
+ /**
1070
+ * How many requests the pool has made: the most ever in flight at once.
1071
+ * @returns the pool's size, which only grows, so a flat count shows nothing leaks
1072
+ */
922
1073
  pooled(): i32 {
923
1074
  return toI32(this.requests.length)
924
1075
  }
925
1076
 
926
- /** How many connections are open. */
1077
+ /**
1078
+ * How many connections are open.
1079
+ * @returns the number of carrier slots holding a connection, which falls to 0 after `drain`
1080
+ */
927
1081
  connections(): i32 {
928
1082
  return this.server.busy()
929
1083
  }
@@ -936,6 +1090,14 @@ export class HttpHandler {
936
1090
  * `write` the body and `end`. Answers `HANDLER_SENT`, or `HANDLER_DROPPED`
937
1091
  * when `r`'s connection has closed — every later `write` and `end` for it
938
1092
  * then does nothing, and `end` hands it back.
1093
+ * @param r a request taken and not yet answered
1094
+ * @param status the response status, from 200 to 599
1095
+ * @param names the field names, as bytes, beside `values`
1096
+ * @param values each field's value, `values[k]` for `names[k]`
1097
+ * @param bodyLength how many body bytes will follow, or `HTTP1_CHUNKED` for a body of unknown length
1098
+ * @returns `HANDLER_SENT`, or `HANDLER_DROPPED` when the connection closed
1099
+ * first, or when the carrier's output was too full to take the head and
1100
+ * the connection was closed for it
939
1101
  */
940
1102
  start(r: HttpRequest, status: i32, names: u8[][], values: u8[][], bodyLength: i32): i32 {
941
1103
  if (r.state !== HANDLER_HELD) {
@@ -974,6 +1136,11 @@ export class HttpHandler {
974
1136
  * Writes `buf[off .. off + len)` of `r`'s body. What the carrier has no room
975
1137
  * for is copied and sent as room comes, so `buf` is the caller's again on
976
1138
  * return. Answers `HANDLER_SENT` or `HANDLER_DROPPED`.
1139
+ * @param r a request whose response `start` began
1140
+ * @param buf the bytes to send from; the caller's again on return
1141
+ * @param off where in `buf` the body bytes start
1142
+ * @param len how many bytes to send
1143
+ * @returns `HANDLER_SENT`, or `HANDLER_DROPPED` when the connection closed first
977
1144
  */
978
1145
  write(r: HttpRequest, buf: u8[], off: i32, len: i32): i32 {
979
1146
  if (r.state !== HANDLER_STREAMING) {
@@ -1013,7 +1180,7 @@ export class HttpHandler {
1013
1180
  }
1014
1181
 
1015
1182
  /** Appends bytes to `r`'s pending buffer, growing it once to the largest response it has held. */
1016
- keep(r: HttpRequest, buf: u8[], off: i32, len: i32): void {
1183
+ private keep(r: HttpRequest, buf: u8[], off: i32, len: i32): void {
1017
1184
  const live: i32 = r.pendingEnd - r.pendingStart
1018
1185
  if (toI32(r.pending.length) - r.pendingEnd < len) {
1019
1186
  if (r.pendingStart > 0 || toI32(r.pending.length) < live + len) {
@@ -1035,6 +1202,8 @@ export class HttpHandler {
1035
1202
  * Ends `r`'s response. `r` is the handler's again: it goes back once the
1036
1203
  * carrier has taken every byte, and the connection's next request is read.
1037
1204
  * Answers `HANDLER_SENT` or `HANDLER_DROPPED`.
1205
+ * @param r a request whose response `start` began; the handler's again after this call
1206
+ * @returns `HANDLER_SENT`, or `HANDLER_DROPPED` when the connection closed first
1038
1207
  */
1039
1208
  end(r: HttpRequest): i32 {
1040
1209
  if (r.state !== HANDLER_STREAMING) {
@@ -1055,13 +1224,36 @@ export class HttpHandler {
1055
1224
  return HANDLER_SENT
1056
1225
  }
1057
1226
 
1058
- /** Answers `r` with `status`, a `Content-Type` of `contentType` and the body `body[off .. off + len)`, in one call. */
1227
+ /**
1228
+ * Answers `r` with `status`, a `Content-Type` of `contentType` and the body `body[off .. off + len)`, in one call.
1229
+ * @param r a request taken and not yet answered; the handler's again after this call
1230
+ * @param status the response status, from 200 to 599
1231
+ * @param contentType the `Content-Type` value, as bytes
1232
+ * @param body the buffer holding the body; the caller's again on return
1233
+ * @param off where in `body` the body bytes start
1234
+ * @param len how many body bytes to send
1235
+ * @returns `HANDLER_SENT`, or `HANDLER_DROPPED` when the connection closed
1236
+ * first, or when the carrier's output was too full to take the head and
1237
+ * the connection was closed for it
1238
+ */
1059
1239
  send(r: HttpRequest, status: i32, contentType: u8[], body: u8[], off: i32, len: i32): i32 {
1060
1240
  this.typeValue[0] = contentType
1061
1241
  return this.sendFields(r, status, this.typeName, this.typeValue, body, off, len)
1062
1242
  }
1063
1243
 
1064
- /** Answers `r` with `status`, the fields `names[k]`: `values[k]` and the body `body[off .. off + len)`, in one call. */
1244
+ /**
1245
+ * Answers `r` with `status`, the fields `names[k]`: `values[k]` and the body `body[off .. off + len)`, in one call.
1246
+ * @param r a request taken and not yet answered; the handler's again after this call
1247
+ * @param status the response status, from 200 to 599
1248
+ * @param names the field names, as bytes, beside `values`
1249
+ * @param values each field's value, `values[k]` for `names[k]`
1250
+ * @param body the buffer holding the body; the caller's again on return
1251
+ * @param off where in `body` the body bytes start
1252
+ * @param len how many body bytes to send
1253
+ * @returns `HANDLER_SENT`, or `HANDLER_DROPPED` when the connection closed
1254
+ * first, or when the carrier's output was too full to take the head and
1255
+ * the connection was closed for it
1256
+ */
1065
1257
  sendFields(
1066
1258
  r: HttpRequest,
1067
1259
  status: i32,
@@ -1082,7 +1274,14 @@ export class HttpHandler {
1082
1274
  return this.end(r)
1083
1275
  }
1084
1276
 
1085
- /** Answers `r` with `status` and no body: a 204, or a status whose meaning is all there is to say. */
1277
+ /**
1278
+ * Answers `r` with `status` and no body: a 204, or a status whose meaning is all there is to say.
1279
+ * @param r a request taken and not yet answered; the handler's again after this call
1280
+ * @param status the response status, from 200 to 599
1281
+ * @returns `HANDLER_SENT`, or `HANDLER_DROPPED` when the connection closed
1282
+ * first, or when the carrier's output was too full to take the head and
1283
+ * the connection was closed for it
1284
+ */
1086
1285
  empty(r: HttpRequest, status: i32): i32 {
1087
1286
  return this.sendFields(r, status, this.noFields, this.noFields, this.scratch, HANDLER_ZERO, HANDLER_ZERO)
1088
1287
  }
@@ -1091,6 +1290,7 @@ export class HttpHandler {
1091
1290
  * The JSON writer, reset onto the handler's scratch buffer: write one value
1092
1291
  * with it, then `sendJson`. One JSON body at a time, since every request
1093
1292
  * shares the buffer.
1293
+ * @returns the handler's own writer, empty, valid until the next `json`, `sendJson` or `problem`
1094
1294
  */
1095
1295
  json(): JsonWriter {
1096
1296
  this.writer.reset(this.scratch, HANDLER_ZERO)
@@ -1102,6 +1302,11 @@ export class HttpHandler {
1102
1302
  * Answers `r` with `status` and the value `json`'s writer holds, as
1103
1303
  * `application/json`. A value the writer refused or did not finish — it
1104
1304
  * outgrew `jsonBytes`, say — is answered as a 500 problem instead.
1305
+ * @param r a request taken and not yet answered; the handler's again after this call
1306
+ * @param status the response status for a value that fit, from 200 to 599
1307
+ * @returns `HANDLER_SENT`, or `HANDLER_DROPPED` when the connection closed
1308
+ * first, or when the carrier's output was too full to take the head and
1309
+ * the connection was closed for it
1105
1310
  */
1106
1311
  sendJson(r: HttpRequest, status: i32): i32 {
1107
1312
  if (!this.jsonBegun) {
@@ -1120,6 +1325,13 @@ export class HttpHandler {
1120
1325
  * `status` and, when not empty, `detail`, a sentence for a person about
1121
1326
  * this occurrence. Nothing of the request is echoed, so a detail is the
1122
1327
  * program's own words.
1328
+ * @param r a request taken and not yet answered; the handler's again after this call
1329
+ * @param status the response status, from 200 to 599, also written into the object
1330
+ * @param title the status's reason phrase, or empty to leave it out
1331
+ * @param detail a sentence for a person about this occurrence, or empty to leave it out
1332
+ * @returns `HANDLER_SENT`, or `HANDLER_DROPPED` when the connection closed
1333
+ * first, or when the carrier's output was too full to take the head and
1334
+ * the connection was closed for it
1123
1335
  */
1124
1336
  problem(r: HttpRequest, status: i32, title: string, detail: string): i32 {
1125
1337
  const length: i32 = this.writeProblem(status, title, detail)
@@ -1131,7 +1343,7 @@ export class HttpHandler {
1131
1343
  * One too large for it is written without its detail, and then without its
1132
1344
  * title, which leaves room enough in the least `jsonBytes`.
1133
1345
  */
1134
- writeProblem(status: i32, title: string, detail: string): i32 {
1346
+ private writeProblem(status: i32, title: string, detail: string): i32 {
1135
1347
  let length: i32 = this.writeProblemObject(status, title, detail)
1136
1348
  if (length < 0) {
1137
1349
  length = this.writeProblemObject(status, title, "")
@@ -1144,7 +1356,7 @@ export class HttpHandler {
1144
1356
  }
1145
1357
 
1146
1358
  /** `writeProblem`'s one try: the object's length, or -1 when it did not fit. */
1147
- writeProblemObject(status: i32, title: string, detail: string): i32 {
1359
+ private writeProblemObject(status: i32, title: string, detail: string): i32 {
1148
1360
  const w: JsonWriter = this.json()
1149
1361
  w.beginObject()
1150
1362
  w.key("type")
@@ -1168,6 +1380,10 @@ export class HttpHandler {
1168
1380
  * field naming the methods the path has (RFC 9110 §15.5.6), and 404 for
1169
1381
  * anything else. A parameter's malformed escape is the program's to refuse,
1170
1382
  * when it decodes the parameter.
1383
+ * @param r a request whose `route` is negative, taken and not yet answered; the handler's again after this call
1384
+ * @returns `HANDLER_SENT`, or `HANDLER_DROPPED` when the connection closed
1385
+ * first, or when the carrier's output was too full to take the head and
1386
+ * the connection was closed for it
1171
1387
  */
1172
1388
  refuse(r: HttpRequest): i32 {
1173
1389
  if (r.route === ROUTER_METHOD_NOT_ALLOWED) {
@@ -1191,7 +1407,7 @@ export class HttpHandler {
1191
1407
  * HEAD wherever GET is, since a GET route answers HEAD too. Made once for
1192
1408
  * each set of methods.
1193
1409
  */
1194
- allowFor(r: HttpRequest): u8[] {
1410
+ private allowFor(r: HttpRequest): u8[] {
1195
1411
  const router: Router = this.router
1196
1412
  const methods: i32 = toI32(router.methodStart.length)
1197
1413
  let mask: i64 = 0