@amritk/nish-x86_64-linux 0.18.0 → 0.21.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 (104) hide show
  1. package/INSTALL.md +58 -28
  2. package/bin/nish +0 -0
  3. package/docs/AI.md +2759 -0
  4. package/package.json +3 -2
  5. package/runtime/browser.d.ts +14 -0
  6. package/runtime/browser.mjs +88 -0
  7. package/runtime/core/arrays.d.ts +18 -0
  8. package/runtime/core/arrays.mjs +125 -0
  9. package/runtime/core/checks.mjs +20 -0
  10. package/runtime/core/host.d.ts +70 -0
  11. package/runtime/core/host.mjs +311 -0
  12. package/runtime/core/numbers.d.ts +53 -0
  13. package/runtime/core/numbers.mjs +316 -0
  14. package/runtime/core/result.d.ts +41 -0
  15. package/runtime/core/result.mjs +127 -0
  16. package/runtime/core/strings.d.ts +14 -0
  17. package/runtime/core/strings.mjs +169 -0
  18. package/runtime/core.d.ts +9 -0
  19. package/runtime/core.mjs +55 -0
  20. package/runtime/host.d.ts +6 -0
  21. package/runtime/nish.d.ts +99 -5
  22. package/runtime/nish.h +289 -19
  23. package/runtime/nish.mjs +39 -3
  24. package/runtime/node.mjs +383 -0
  25. package/runtime/runtime-aes.c +490 -0
  26. package/runtime/runtime-bytes.c +401 -0
  27. package/runtime/runtime-cross.c +366 -0
  28. package/runtime/runtime-host.c +8 -7
  29. package/runtime/runtime-net.c +93 -34
  30. package/runtime/runtime-os.c +214 -16
  31. package/runtime/runtime-parallel.c +590 -107
  32. package/runtime/runtime-simd.c +235 -11
  33. package/runtime/runtime-term.c +504 -0
  34. package/runtime/runtime-wasm.c +5 -14
  35. package/runtime/runtime.c +257 -17
  36. package/runtime/shim.mjs +6 -915
  37. package/runtime/sqlite/LICENSE.md +85 -0
  38. package/runtime/sqlite/README.md +45 -0
  39. package/runtime/sqlite/nish-sqlite.c +359 -0
  40. package/runtime/sqlite/sqlite3.c +271131 -0
  41. package/runtime/sqlite/sqlite3.h +14447 -0
  42. package/scripts/build.sh +437 -28
  43. package/std/LICENSE-fast-float +23 -0
  44. package/std/LICENSE-fdlibm +8 -0
  45. package/std/README.md +108 -58
  46. package/std/base64.ts +116 -0
  47. package/std/bytes.ts +419 -0
  48. package/std/cli.ts +328 -0
  49. package/std/collections.ts +6 -5
  50. package/std/crypto/LICENSE-crypt_blowfish +26 -0
  51. package/std/crypto/LICENSE-libsecp256k1 +19 -0
  52. package/std/crypto/aes.ts +238 -76
  53. package/std/crypto/base64url.ts +125 -0
  54. package/std/crypto/bcrypt.ts +760 -0
  55. package/std/crypto/chacha20poly1305.ts +43 -9
  56. package/std/crypto/ed25519.ts +840 -0
  57. package/std/crypto/hkdf.ts +304 -12
  58. package/std/crypto/hmac.ts +382 -54
  59. package/std/crypto/p256.ts +932 -61
  60. package/std/crypto/x25519.ts +55 -37
  61. package/std/crypto/x509-random.ts +71 -0
  62. package/std/crypto/x509.ts +20 -131
  63. package/std/json-tokenizer.ts +4237 -0
  64. package/std/json-typed.ts +1014 -0
  65. package/std/json-value.ts +1182 -0
  66. package/std/json.ts +1202 -34
  67. package/std/math.ts +608 -0
  68. package/std/net/buffer-pool.ts +151 -0
  69. package/std/net/hpack.ts +416 -112
  70. package/std/net/http-fields.ts +93 -0
  71. package/std/net/http1-server.ts +501 -62
  72. package/std/net/http1.ts +31 -6
  73. package/std/net/http2-tls.ts +112 -24
  74. package/std/net/http2.ts +333 -75
  75. package/std/net/http3-server.ts +261 -43
  76. package/std/net/http3.ts +187 -28
  77. package/std/net/postgres.ts +1875 -0
  78. package/std/net/prefork.ts +412 -0
  79. package/std/net/quic-listener.ts +108 -11
  80. package/std/net/quic-packet.ts +243 -82
  81. package/std/net/quic-recovery.ts +361 -30
  82. package/std/net/quic-stream.ts +424 -24
  83. package/std/net/quic.ts +519 -167
  84. package/std/net/router.ts +676 -0
  85. package/std/net/tls/codec.ts +426 -27
  86. package/std/net/tls/record-server.ts +478 -132
  87. package/std/net/tls/record.ts +133 -42
  88. package/std/net/tls/schedule.ts +464 -55
  89. package/std/net/tls/ticket.ts +610 -0
  90. package/std/net/tls-tcp.ts +196 -53
  91. package/std/net/tls.ts +1018 -260
  92. package/std/net/url.ts +571 -0
  93. package/std/random.ts +94 -0
  94. package/std/regex.ts +4274 -0
  95. package/std/sqlite.ts +391 -0
  96. package/std/term-io.ts +978 -0
  97. package/std/term-pixels.ts +874 -0
  98. package/std/term-probe.ts +459 -0
  99. package/std/term-rate.ts +993 -0
  100. package/std/term.ts +2453 -0
  101. package/std/text.ts +90 -7
  102. package/std/threads.ts +438 -14
  103. package/std/yaml-lines.ts +141 -0
  104. package/std/yaml.ts +4675 -0
@@ -22,7 +22,7 @@
22
22
  * }
23
23
  * wants = server.flush(slot);
24
24
  * if ((wants & H1_DONE) !== 0) { server.close(slot); }
25
- * else { pollModify(loop, server.fd(slot), wants & 3, slot); }
25
+ * else if (server.rearm(slot, wants)) { pollModify(loop, server.fd(slot), wants & 3, slot); }
26
26
  *
27
27
  * **Events.** `next()` answers `H1_REQUEST` (a request's head: the parser's
28
28
  * spans and `...Is` methods read it), `H1_BODY` (some of its body, de-chunked,
@@ -65,6 +65,13 @@
65
65
  * §15.4.5). A 1xx before the final response (100 Continue) is allowed; 101 is
66
66
  * `acceptWebSocket`'s.
67
67
  *
68
+ * **The Date.** Every final response, an error included, carries a `Date`
69
+ * field (RFC 9110 §6.6.1) from `HttpDate`, which formats the IMF-fixdate at
70
+ * most once a second; a 1xx carries none. The pool's slots share one, so a
71
+ * busy server formats a second once, not once a slot. A program that sets its
72
+ * own `date` field sends that one instead, so a response has one `Date`.
73
+ * `date.pin(unixMs)` fixes it, for a test that compares bytes.
74
+ *
68
75
  * **Refusals.** Every refusal of `nish/net/http1`'s parser — the smuggling
69
76
  * shapes, a `Content-Length` with a `Transfer-Encoding`, two that disagree,
70
77
  * a malformed chunk size — is answered with its status (400, 413, 414, 431,
@@ -81,11 +88,23 @@
81
88
  *
82
89
  * **Caps are start-up numbers**, all in `Http1Config`: the request target,
83
90
  * the header section and its field count, a request body, the chunk handed
84
- * over, the output buffer, a WebSocket message and the idle timeout; the
85
- * slots are the pool's size. Every buffer is allocated by the constructor or
86
- * grown to its cap on first use and kept, so a warmed slot serves request
87
- * after request with `Arena.used()` flat. Accepting a WebSocket allocates
88
- * (the accept key), once a connection.
91
+ * over, the output buffer, a WebSocket message, the idle timeout and the
92
+ * deadline for a whole request head (`headTimeout`, against slowloris); the
93
+ * slots are the pool's size. `Http1Server` builds a slot's connection on the
94
+ * first accept into it and keeps it, so a pool sized for its peak costs at
95
+ * start-up only what does not depend on the size, and holds at most `size`
96
+ * connections once the peak has come; `Http1TlsServer` does the same for a
97
+ * slot's connection and, through `TlsTcpServer`, its TLS state. Every buffer
98
+ * is allocated with its slot or grown to its cap on first use and kept, so a
99
+ * warmed slot serves request after request with `Arena.used()` flat.
100
+ * Accepting a WebSocket allocates (the accept key), once a connection.
101
+ *
102
+ * **Output is borrowed.** The pools' slots share an `Http1OutputPool`: a
103
+ * connection takes an `outputSize` buffer when it first needs room to write
104
+ * and gives it back once its carrier has sent everything, so the output
105
+ * memory a pool holds follows the connections the socket is holding back,
106
+ * not its size. A pool that ever had `n` connections writing at once keeps
107
+ * `n` buffers and allocates no more.
89
108
  *
90
109
  * Private helpers share the importing program's flat symbol namespace
91
110
  * (`docs/wp26-stdlib.md` §3e), which is why each one carries the module's name.
@@ -128,6 +147,7 @@ import {
128
147
  websocketWriteFrame,
129
148
  } from "nish/net/websocket"
130
149
  import { TlsServerConfig } from "nish/net/tls"
150
+ import { HTTP_DATE_LAST_SECOND, HTTP_DATE_SIZE, httpDateWrite } from "nish/net/http-fields"
131
151
  import { TLS_RECORD_DONE, TLS_RECORD_STATE_OPEN, TLS_RECORD_WANT_WRITE } from "nish/net/tls/record-server"
132
152
  import { TlsTcpServer } from "nish/net/tls-tcp"
133
153
 
@@ -228,6 +248,82 @@ const http1ServerCopy = (out: u8[], at: i32, src: u8[], off: i32, n: i32): i32 =
228
248
  return at + n
229
249
  }
230
250
 
251
+ /**
252
+ * The `Date` field an origin server with a clock sends on every final
253
+ * response (RFC 9110 §6.6.1): the IMF-fixdate of now, in 29 bytes the object
254
+ * owns and rewrites in place, at most once a second.
255
+ *
256
+ * It reads the wall clock, `Date.now()`, which a wasm32 build has no host for,
257
+ * so it lives here, in a module that is native already, while the formatting
258
+ * it calls, `httpDateWrite`, stays in `nish/net/http-fields`, which compiles
259
+ * for wasm32 (the split `nish/crypto/x509` and `x509-random` make). `pin`
260
+ * replaces the clock with one instant, which is how a test asserts a response
261
+ * byte for byte.
262
+ */
263
+ export class HttpDate {
264
+ /** The IMF-fixdate of `second`: what `current` answers, made once. */
265
+ bytes: u8[]
266
+ /** The second `bytes` holds, since 1970; -1 before the first `current`. */
267
+ second: i64 = -1
268
+ /** The instant `pin` fixed, in milliseconds since 1970, while `pinned`. */
269
+ pinnedMs: i64 = 0
270
+ /** How many times `bytes` has been rewritten. */
271
+ rewrites: i64 = 0
272
+ pinned: boolean = false
273
+
274
+ /** A date on the wall clock, with nothing formatted yet. */
275
+ constructor() {
276
+ this.bytes = new Array<u8>(HTTP_DATE_SIZE)
277
+ }
278
+
279
+ /**
280
+ * The 29 bytes for now, which are rewritten only when the second differs
281
+ * from the one they hold — earlier as well as later, since a corrected clock
282
+ * steps back. It allocates nothing, and the array is the same one each time,
283
+ * so a caller copies it out rather than keeping it. A wall clock before 1970
284
+ * or past 9999 answers the nearer of the two ends.
285
+ */
286
+ current(): u8[] {
287
+ const ms: i64 = this.pinned ? this.pinnedMs : toI64(Date.now())
288
+ let second: i64 = ms / 1000
289
+ if (ms < 0) {
290
+ second = 0
291
+ } else if (second > HTTP_DATE_LAST_SECOND) {
292
+ second = HTTP_DATE_LAST_SECOND
293
+ }
294
+ if (second !== this.second) {
295
+ httpDateWrite(this.bytes, 0, second)
296
+ this.second = second
297
+ this.rewrites += 1
298
+ }
299
+ return this.bytes
300
+ }
301
+
302
+ /**
303
+ * Makes `current` answer `unixMs`, milliseconds since 1970, until `unpin`.
304
+ * False, and nothing changed, for an instant before 1970-01-01T00:00:00Z or
305
+ * after 9999-12-31T23:59:59.999Z, which an IMF-fixdate cannot name.
306
+ */
307
+ pin(unixMs: i64): boolean {
308
+ if (unixMs < 0 || unixMs / 1000 > HTTP_DATE_LAST_SECOND) {
309
+ return false
310
+ }
311
+ this.pinnedMs = unixMs
312
+ this.pinned = true
313
+ return true
314
+ }
315
+
316
+ /** Puts `current` back on the wall clock. */
317
+ unpin(): void {
318
+ this.pinned = false
319
+ }
320
+
321
+ /** How many times the bytes have been rewritten: one per second that `current` was asked for, at most. */
322
+ formats(): i64 {
323
+ return this.rewrites
324
+ }
325
+ }
326
+
231
327
  /**
232
328
  * The caps of every connection made from it, fixed when the connection is
233
329
  * made. Each is a number the program sets once, at start-up.
@@ -249,6 +345,13 @@ export class Http1Config {
249
345
  maxMessage: i32 = 1048576
250
346
  /** Milliseconds without a byte read or written after which `expire` closes a slot. */
251
347
  idleTimeout: i32 = 60000
348
+ /**
349
+ * Milliseconds a request head may take, from its first byte to its blank
350
+ * line, before `expire` closes the slot however steadily its bytes come. The
351
+ * idle timeout alone restarts on every byte, so a client that sends one byte
352
+ * of its head each `idleTimeout` would hold its slot for good (slowloris).
353
+ */
354
+ headTimeout: i32 = 30000
252
355
  }
253
356
 
254
357
  /** The reason phrase a status is sent with; RFC 9112 §4 lets a client ignore it. */
@@ -311,6 +414,44 @@ const http1ServerReserved = (name: u8[]): boolean =>
311
414
  http1BytesAre(name, "transfer-encoding") ||
312
415
  http1BytesAre(name, "content-length")
313
416
 
417
+ /**
418
+ * Output buffers shared by the connections of one pool, each `size` bytes. A
419
+ * connection borrows one when it has something to write and gives it back
420
+ * once its carrier has sent everything, so a pool's output memory follows the
421
+ * connections the socket is holding back, not the slots: Go's `net/http`
422
+ * pools its writers the same way, and uWebSockets shares one per loop. A
423
+ * buffer is made only when none is free, so the pool grows to the most
424
+ * connections ever writing at once and then allocates nothing.
425
+ */
426
+ export class Http1OutputPool {
427
+ // Widest first, so the layout packs without padding.
428
+ free: u8[][]
429
+ size: i32 = 0
430
+ /** How many buffers the pool has made. */
431
+ made: i32 = 0
432
+
433
+ constructor(size: i32) {
434
+ this.size = size
435
+ this.free = []
436
+ }
437
+
438
+ /** A buffer of `size` bytes: the one given back last, or a new one. */
439
+ take(): u8[] {
440
+ if (this.free.length > 0) {
441
+ const buf: u8[] = this.free[this.free.length - 1]
442
+ this.free.pop()
443
+ return buf
444
+ }
445
+ this.made = this.made + 1
446
+ return new Array<u8>(this.size)
447
+ }
448
+
449
+ /** Takes back a buffer `take` gave. */
450
+ give(buf: u8[]): void {
451
+ this.free.push(buf)
452
+ }
453
+ }
454
+
314
455
  /**
315
456
  * One connection's HTTP/1.1 server, sans-IO: bytes in through `feed`, events
316
457
  * out of `next`, and the response the program writes in
@@ -320,12 +461,27 @@ export class Http1Connection {
320
461
  // References, then 64-bit fields, then 32-bit ones, then flags: the order
321
462
  // the layout packs without padding.
322
463
  config: Http1Config
464
+ /**
465
+ * The `Date` every final response carries. The connection makes its own;
466
+ * `Http1Server` and `Http1TlsServer` put theirs here, so that every slot of a
467
+ * pool shares one and the pool formats at most once a second. A program may
468
+ * put another, to share it or to pin its clock.
469
+ */
470
+ date: HttpDate
323
471
  /** The request parser: its head (`methodIs`, `targetIs`, `header`, spans) is the last `H1_REQUEST`'s. */
324
472
  parser: Http1Parser
325
473
  /** The frame decoder, once the slot has switched to WebSocket. */
326
474
  ws: WsDecoder
327
- /** Bytes to send are `output[outputStart .. outputEnd)`. */
475
+ /**
476
+ * Bytes to send are `output[outputStart .. outputEnd)`. Empty until the
477
+ * connection first needs room to write: then its own buffer, made once, or
478
+ * one borrowed from `pool` and given back by `release` once sent.
479
+ */
328
480
  output: u8[]
481
+ /** The empty array `output` is while the connection holds no buffer. */
482
+ noOutput: u8[]
483
+ /** Where `output` is borrowed from, for a connection of a pool; null for one that keeps its own. */
484
+ pool: Http1OutputPool | null
329
485
  /** `H1_BODY`'s and `H1_WS_MESSAGE`'s bytes. */
330
486
  data: u8[]
331
487
  /** A ping's payload, kept until its pong fits. */
@@ -334,6 +490,8 @@ export class Http1Connection {
334
490
  noFields: u8[][]
335
491
  /** When the carrier last moved a byte for the connection, in `monotonicNanos`. */
336
492
  lastActive: i64 = 0
493
+ /** When the head being read began to arrive, in `monotonicNanos`; meaningful while `headTimed`. */
494
+ headSince: i64 = 0
337
495
  outputStart: i32 = 0
338
496
  outputEnd: i32 = 0
339
497
  dataStart: i32 = 0
@@ -369,6 +527,8 @@ export class Http1Connection {
369
527
  pongPending: boolean = false
370
528
  /** The peer's byte stream has ended. */
371
529
  inputEnded: boolean = false
530
+ /** A head has begun to arrive and is not read whole yet: `headSince` is its deadline's start. */
531
+ headTimed: boolean = false
372
532
 
373
533
  /** A connection under `config`. A cap outside what the connection can work with panics. */
374
534
  constructor(config: Http1Config) {
@@ -384,6 +544,7 @@ export class Http1Connection {
384
544
  http1ServerCheckCap("outputSize", config.outputSize, output, big)
385
545
  http1ServerCheckCap("maxMessage", config.maxMessage, H1_ZERO, big - H1_FRAME_HEADER)
386
546
  http1ServerCheckCap("idleTimeout", config.idleTimeout, one, big)
547
+ http1ServerCheckCap("headTimeout", config.headTimeout, one, big)
387
548
  // The buffers the peer's bytes fill grow by doubling and stop at 2^30
388
549
  // (`Http1Parser`'s input and head, `WsDecoder`'s input), so a cap whose
389
550
  // buffer could need more is refused here rather than reached by a peer:
@@ -396,12 +557,15 @@ export class Http1Connection {
396
557
  big - H1_LINE_OVERHEAD
397
558
  )
398
559
  this.config = config
560
+ this.date = new HttpDate()
399
561
  this.parser = new Http1Parser(config.maxTarget, config.maxHeaderBytes, config.maxHeaders, config.maxBody)
400
562
  this.parser.keepText = false
401
563
  this.parser.maxChunk = config.chunkSize
402
564
  this.ws = new WsDecoder(true, config.maxMessage)
403
- this.output = new Array<u8>(config.outputSize)
404
- this.data = this.output
565
+ this.noOutput = []
566
+ this.output = this.noOutput
567
+ this.pool = null
568
+ this.data = this.noOutput
405
569
  this.pong = new Array<u8>(WS_MAX_CONTROL)
406
570
  this.noFields = []
407
571
  // A line must fit whole before the parser can read it, so the buffer
@@ -423,7 +587,7 @@ export class Http1Connection {
423
587
  this.ws.reset()
424
588
  this.outputStart = 0
425
589
  this.outputEnd = 0
426
- this.data = this.output
590
+ this.data = this.noOutput
427
591
  this.dataStart = 0
428
592
  this.dataLength = 0
429
593
  this.opcode = 0
@@ -441,6 +605,9 @@ export class Http1Connection {
441
605
  this.writeHeld = false
442
606
  this.pongPending = false
443
607
  this.inputEnded = false
608
+ this.headTimed = false
609
+ this.headSince = 0
610
+ this.release()
444
611
  }
445
612
 
446
613
  // ---- Bytes in and out ---------------------------------------------------------
@@ -492,6 +659,44 @@ export class Http1Connection {
492
659
  this.outputEnd = 0
493
660
  this.pongPending = false
494
661
  this.writeHeld = false
662
+ this.release()
663
+ }
664
+
665
+ /**
666
+ * Borrows `output` from the pool between connections of one, for a
667
+ * connection that keeps its own makes it the first time: before anything
668
+ * is written into it, which is why `room` calls it. It allocates only when
669
+ * the pool has no free buffer, or for a connection's own, once.
670
+ */
671
+ acquire(): void {
672
+ if (toI32(this.output.length) > 0) {
673
+ return
674
+ }
675
+ const pool: Http1OutputPool | null = this.pool
676
+ this.output = pool !== null ? pool.take() : new Array<u8>(this.config.outputSize)
677
+ this.outputStart = 0
678
+ this.outputEnd = 0
679
+ }
680
+
681
+ /**
682
+ * Gives `output` back to the pool once nothing in it is waiting: no bytes
683
+ * to send, no write held back for room. The carrier calls it after each
684
+ * send; a connection that keeps its own buffer keeps it.
685
+ */
686
+ release(): void {
687
+ const pool: Http1OutputPool | null = this.pool
688
+ if (
689
+ pool === null ||
690
+ toI32(this.output.length) === 0 ||
691
+ this.outputEnd > this.outputStart ||
692
+ this.writeHeld
693
+ ) {
694
+ return
695
+ }
696
+ pool.give(this.output)
697
+ this.output = this.noOutput
698
+ this.outputStart = 0
699
+ this.outputEnd = 0
495
700
  }
496
701
 
497
702
  /** Marks the first `n` bytes of the output sent. */
@@ -518,6 +723,7 @@ export class Http1Connection {
518
723
 
519
724
  /** The room at the end of the output, once what was sent is moved out of the way. */
520
725
  room(): i32 {
726
+ this.acquire()
521
727
  const output: u8[] = this.output
522
728
  const live: i32 = this.outputEnd - this.outputStart
523
729
  if (this.outputStart > 0) {
@@ -550,7 +756,7 @@ export class Http1Connection {
550
756
  if (this.writeHeld) {
551
757
  // Half the output free before the program is asked to write again, so
552
758
  // that a slow reader is not answered one small write at a time.
553
- if (this.bodyRoom() * 2 < toI32(this.output.length) - H1_CONTROL_RESERVE) {
759
+ if (this.bodyRoom() * 2 < this.config.outputSize - H1_CONTROL_RESERVE) {
554
760
  return H1_NEED_MORE
555
761
  }
556
762
  this.writeHeld = false
@@ -587,9 +793,16 @@ export class Http1Connection {
587
793
  this.state = H1_S_CLOSING
588
794
  return H1_NEED_MORE
589
795
  }
796
+ // A pipelined head that waited behind the exchange starts its clock
797
+ // now that it is the one being read. The carrier stamped `lastActive`
798
+ // when it last moved a byte, which is no earlier than these bytes came.
799
+ this.headArrived(this.lastActive)
590
800
  }
591
801
  const event: i32 = this.parser.next()
592
802
  if (event === HTTP1_HEAD) {
803
+ // The head is whole, so its deadline is met; the next head's starts
804
+ // when its first byte is fed (`headArrived`).
805
+ this.headTimed = false
593
806
  this.requestOpen = true
594
807
  this.response = H1_R_NONE
595
808
  this.closeAfter = !this.parser.keepAlive
@@ -642,7 +855,8 @@ export class Http1Connection {
642
855
  this.noFields,
643
856
  this.noFields,
644
857
  H1_ZERO,
645
- "close"
858
+ "close",
859
+ this.date.current()
646
860
  )
647
861
  if (end >= 0) {
648
862
  this.outputEnd = end
@@ -794,14 +1008,15 @@ export class Http1Connection {
794
1008
  names,
795
1009
  values,
796
1010
  framing,
797
- connection
1011
+ connection,
1012
+ this.date.current()
798
1013
  )
799
1014
  if (end === HTTP1_REFUSED) {
800
1015
  return H1_INVALID
801
1016
  }
802
1017
  if (end < 0 || end - this.outputEnd > room) {
803
1018
  // The head was not written, or ate into the reserve: take it back.
804
- if (end - this.outputEnd > toI32(this.output.length) - H1_CONTROL_RESERVE) {
1019
+ if (end - this.outputEnd > this.config.outputSize - H1_CONTROL_RESERVE) {
805
1020
  return H1_INVALID
806
1021
  }
807
1022
  if (this.outputEnd === 0) {
@@ -950,7 +1165,7 @@ export class Http1Connection {
950
1165
  if (this.state !== H1_S_WEBSOCKET) {
951
1166
  return H1_CLOSED
952
1167
  }
953
- if (opcode === WS_OP_CLOSE || len > toI32(this.output.length) - H1_CONTROL_RESERVE - 14) {
1168
+ if (opcode === WS_OP_CLOSE || len > this.config.outputSize - H1_CONTROL_RESERVE - 14) {
954
1169
  return H1_INVALID
955
1170
  }
956
1171
  if (websocketFrameSize(len, false) > this.bodyRoom()) {
@@ -992,6 +1207,44 @@ export class Http1Connection {
992
1207
  idle(now: i64): boolean {
993
1208
  return now - this.lastActive > toI64(this.config.idleTimeout) * toI64(1000000)
994
1209
  }
1210
+
1211
+ /**
1212
+ * Starts the head deadline at `now` (`monotonicNanos`) when bytes of a
1213
+ * request head wait to be read and its clock has not started. The carriers
1214
+ * call it after each `feed`; a program that feeds a connection itself calls
1215
+ * it the same way. Bytes that wait while the previous exchange is still
1216
+ * open start no clock: they count from when it is over (`nextRequest`).
1217
+ */
1218
+ headArrived(now: i64): void {
1219
+ if (this.parser.buffered() > 0) {
1220
+ this.headAwaited(now)
1221
+ }
1222
+ }
1223
+
1224
+ /**
1225
+ * Starts the head deadline at `now` (`monotonicNanos`) when the connection
1226
+ * waits for a head and its clock has not started, whether or not a byte of
1227
+ * it has been read. `Http1TlsServer` calls it when ciphertext arrives after
1228
+ * the handshake: a record trickled a byte at a time hands no plaintext to
1229
+ * `headArrived` until it is whole, so its bytes would otherwise only keep
1230
+ * the slot from going idle.
1231
+ */
1232
+ headAwaited(now: i64): void {
1233
+ if (!this.headTimed && this.state === H1_S_HTTP && !this.requestOpen) {
1234
+ this.headTimed = true
1235
+ this.headSince = now
1236
+ }
1237
+ }
1238
+
1239
+ /** Whether a head has been arriving for longer than `headTimeout` at `now` (`monotonicNanos`). */
1240
+ headLate(now: i64): boolean {
1241
+ return this.headTimed && now - this.headSince > toI64(this.config.headTimeout) * toI64(1000000)
1242
+ }
1243
+
1244
+ /** Whether `expire` closes the slot at `now`: idle, or a head past its deadline. */
1245
+ expired(now: i64): boolean {
1246
+ return this.idle(now) || this.headLate(now)
1247
+ }
995
1248
  }
996
1249
 
997
1250
  // ---- Carriers -------------------------------------------------------------------
@@ -1003,34 +1256,72 @@ export class Http1Connection {
1003
1256
  */
1004
1257
  export class Http1Server {
1005
1258
  config: Http1Config
1259
+ /**
1260
+ * The connections built so far, slot `k`'s at `k`: one per slot ever
1261
+ * accepted into, and slot 0's once `connection` has asked for it.
1262
+ */
1006
1263
  connections: Http1Connection[]
1007
- /** Each slot's descriptor, or -1 while it is free. */
1264
+ /** The `Date` every slot's responses carry, formatted once a second for all of them. `date.pin` fixes its clock. */
1265
+ date: HttpDate
1266
+ /**
1267
+ * Each slot's descriptor, or -1 while it is free, for the slots accepted
1268
+ * into so far: its length is the high-water mark, and a slot past it has
1269
+ * never been used.
1270
+ */
1008
1271
  fds: i32[]
1272
+ /** Each used slot's interest as the loop last armed it, for `rearm`. */
1273
+ armed: i32[]
1274
+ /** The output buffers the slots borrow while they write. */
1275
+ outputs: Http1OutputPool
1276
+ /**
1277
+ * The slots closed since they were used, a stack whose top `accept` takes
1278
+ * before it builds a slot past the high-water mark: finding one costs the
1279
+ * same with every slot free as with all but one busy, where a scan of
1280
+ * `fds` walked the busy ones.
1281
+ */
1282
+ free: i32[]
1009
1283
  /** Where the socket is read into before the connection takes the bytes. */
1010
1284
  scratch: u8[]
1011
1285
  /** The last accepted peer's address, in `nish:net`'s 18-byte form. */
1012
1286
  peer: u8[]
1287
+ /** How many slots the pool may hold, which `size` answers. */
1288
+ slots: i32 = 1
1013
1289
  /** The listening socket, which the program made with `tcpListen` and still owns. */
1014
1290
  listener: i32 = -1
1015
1291
 
1016
- /** A pool of `size` slots, at least one, serving `config` on `listener`. Every slot's buffers are allocated here. */
1292
+ /**
1293
+ * A pool of `size` slots, at least one, serving `config` on `listener`.
1294
+ * No slot is built here: a slot's connection and its buffers are
1295
+ * allocated by the first `accept` into it and kept, so a pool sized for a
1296
+ * peak costs at start-up only the read scratch, the shared `Date` and the
1297
+ * output pool, and at most `size` connections once the peak has come.
1298
+ */
1017
1299
  constructor(config: Http1Config, listener: i32, size: i32) {
1018
1300
  this.config = config
1019
1301
  this.listener = listener
1020
1302
  this.connections = []
1021
1303
  this.fds = []
1022
- const slots: i32 = size < 1 ? 1 : size
1023
- for (let k: i32 = 0; k < slots; k++) {
1024
- this.connections.push(new Http1Connection(config))
1025
- this.fds.push(H1_FREE)
1026
- }
1304
+ this.armed = []
1305
+ this.free = []
1306
+ this.slots = size < 1 ? 1 : size
1307
+ this.outputs = new Http1OutputPool(config.outputSize)
1308
+ this.date = new HttpDate()
1027
1309
  this.scratch = new Array<u8>(config.chunkSize)
1028
1310
  this.peer = new Array<u8>(H1_ADDRESS_SIZE)
1029
1311
  }
1030
1312
 
1031
- /** How many slots the pool has. */
1313
+ /** A new connection on this pool's outputs and `Date`, for the next slot built. */
1314
+ build(): Http1Connection {
1315
+ const conn: Http1Connection = new Http1Connection(this.config)
1316
+ conn.pool = this.outputs
1317
+ conn.date = this.date
1318
+ this.connections.push(conn)
1319
+ return conn
1320
+ }
1321
+
1322
+ /** How many slots the pool has, built or not. */
1032
1323
  size(): i32 {
1033
- return toI32(this.fds.length)
1324
+ return this.slots
1034
1325
  }
1035
1326
 
1036
1327
  /** How many slots hold a connection. */
@@ -1054,36 +1345,57 @@ export class Http1Server {
1054
1345
  return this.holds(slot) ? this.fds[slot] : -1
1055
1346
  }
1056
1347
 
1057
- /** The connection of `slot`; a slot out of range names the first. */
1348
+ /**
1349
+ * The connection of `slot`. A slot never accepted into, or out of range,
1350
+ * names slot 0's connection, which this builds when no slot has been yet
1351
+ * (the first `accept` then takes it, restarted).
1352
+ */
1058
1353
  connection(slot: i32): Http1Connection {
1059
- const at: i32 = slot >= 0 && slot < toI32(this.connections.length) ? slot : H1_ZERO
1060
- return this.connections[at]
1354
+ if (slot >= 0 && slot < toI32(this.connections.length)) {
1355
+ return this.connections[slot]
1356
+ }
1357
+ return this.connections.length > 0 ? this.connections[0] : this.build()
1061
1358
  }
1062
1359
 
1063
1360
  /**
1064
1361
  * Accepts the next waiting connection into a free slot and answers the
1065
- * slot; -11 when none is waiting, `H1_POOL_FULL` when every slot is busy
1066
- * (the connection is closed), or `tcpAccept`'s own failure.
1362
+ * slot, which the program adds to its loop with `H1_WANT_READ`; -11 when
1363
+ * none is waiting, `H1_POOL_FULL` when every slot is busy (the connection
1364
+ * is closed), or `tcpAccept`'s own failure.
1067
1365
  */
1068
1366
  accept(): i32 {
1069
1367
  const fd: i32 = tcpAccept(this.listener, this.peer)
1070
1368
  if (fd < 0) {
1071
1369
  return fd
1072
1370
  }
1073
- for (let k: i32 = 0; k < toI32(this.fds.length) && k < toI32(this.connections.length); k++) {
1074
- if (this.fds[k] < 0) {
1075
- this.fds[k] = fd
1076
- const conn: Http1Connection = this.connections[k]
1077
- conn.restart()
1078
- conn.lastActive = monotonicNanos()
1079
- return k
1080
- }
1081
- }
1082
- netClose(fd)
1083
- return H1_POOL_FULL
1371
+ // A slot closed before is taken first, then the next never used, so the
1372
+ // first accepts take slots 0, 1, 2 ... and a pool that never fills never
1373
+ // builds its last slots.
1374
+ let k: i32 = H1_POOL_FULL
1375
+ if (this.free.length > 0) {
1376
+ k = this.free[this.free.length - 1]
1377
+ this.free.pop()
1378
+ } else if (toI32(this.fds.length) < this.slots) {
1379
+ k = toI32(this.fds.length)
1380
+ this.fds.push(H1_FREE)
1381
+ this.armed.push(H1_WANT_READ)
1382
+ }
1383
+ if (k < 0 || k >= toI32(this.fds.length) || k >= toI32(this.armed.length)) {
1384
+ netClose(fd)
1385
+ return H1_POOL_FULL
1386
+ }
1387
+ const conn: Http1Connection = k < toI32(this.connections.length) ? this.connections[k] : this.build()
1388
+ this.fds[k] = fd
1389
+ this.armed[k] = H1_WANT_READ
1390
+ conn.restart()
1391
+ conn.lastActive = monotonicNanos()
1392
+ return k
1084
1393
  }
1085
1394
 
1086
- /** The socket of `slot` is readable: reads it while the connection has room, then sends. Answers the interest. */
1395
+ /**
1396
+ * The socket of `slot` is readable: reads it while the connection has room
1397
+ * and the socket has more, then sends. Answers the interest.
1398
+ */
1087
1399
  readable(slot: i32): i32 {
1088
1400
  if (!this.holds(slot)) {
1089
1401
  return H1_DONE
@@ -1108,9 +1420,18 @@ export class Http1Server {
1108
1420
  }
1109
1421
  moved = true
1110
1422
  conn.feed(this.scratch, H1_ZERO, n)
1423
+ // A short read emptied the socket. The loop's readiness is
1424
+ // level-triggered, so more input, or the peer's close, wakes it again;
1425
+ // reading once more here would only answer -11, at the price of a
1426
+ // system call on every request.
1427
+ if (n < want) {
1428
+ break
1429
+ }
1111
1430
  }
1112
1431
  if (moved) {
1113
- conn.lastActive = monotonicNanos()
1432
+ const now: i64 = monotonicNanos()
1433
+ conn.lastActive = now
1434
+ conn.headArrived(now)
1114
1435
  }
1115
1436
  return this.flush(slot)
1116
1437
  }
@@ -1180,6 +1501,23 @@ export class Http1Server {
1180
1501
  if (conn.outputEnd - conn.outputStart < pending) {
1181
1502
  conn.lastActive = monotonicNanos()
1182
1503
  }
1504
+ conn.release()
1505
+ }
1506
+
1507
+ /**
1508
+ * Whether the program must `pollModify` `slot`'s descriptor to `wants`, the
1509
+ * interest `readable`, `writable` or `flush` answered, and records it as
1510
+ * armed when it must. A keep-alive connection answers the same interest
1511
+ * request after request, and each `pollModify` is a system call
1512
+ * (`epoll_ctl`) that changes nothing.
1513
+ */
1514
+ rearm(slot: i32, wants: i32): boolean {
1515
+ const interest: i32 = wants & (H1_WANT_READ | H1_WANT_WRITE)
1516
+ if (!this.holds(slot) || slot >= toI32(this.armed.length) || this.armed[slot] === interest) {
1517
+ return false
1518
+ }
1519
+ this.armed[slot] = interest
1520
+ return true
1183
1521
  }
1184
1522
 
1185
1523
  /** Closes `slot`'s socket, whatever is left unsent, and frees the slot. */
@@ -1189,13 +1527,20 @@ export class Http1Server {
1189
1527
  }
1190
1528
  netClose(this.fds[slot])
1191
1529
  this.fds[slot] = H1_FREE
1530
+ this.free.push(slot)
1531
+ if (slot < toI32(this.connections.length)) {
1532
+ this.connections[slot].abort()
1533
+ }
1192
1534
  }
1193
1535
 
1194
- /** Closes every slot that has been idle past `idleTimeout` at `now` (`monotonicNanos`); answers how many. */
1536
+ /**
1537
+ * Closes every slot that has been idle past `idleTimeout`, or reading one
1538
+ * head for longer than `headTimeout`, at `now` (`monotonicNanos`); answers how many.
1539
+ */
1195
1540
  expire(now: i64): i32 {
1196
1541
  let n: i32 = 0
1197
1542
  for (let k: i32 = 0; k < toI32(this.fds.length) && k < toI32(this.connections.length); k++) {
1198
- if (this.fds[k] >= 0 && this.connections[k].idle(now)) {
1543
+ if (this.fds[k] >= 0 && this.connections[k].expired(now)) {
1199
1544
  this.close(k)
1200
1545
  n = n + 1
1201
1546
  }
@@ -1209,25 +1554,69 @@ export class Http1Server {
1209
1554
  * `Http1Connection` beside each slot of a `TlsTcpServer`, run the way
1210
1555
  * `nish/net/http2-tls` runs HTTP/2. A handshake that chose ALPN `http/1.1`,
1211
1556
  * or none (a client that does not send ALPN speaks HTTP/1.1), reaches its
1212
- * connection; any other protocol is shut down with `close_notify`.
1557
+ * connection; any other protocol is shut down with `close_notify`. A slot's
1558
+ * connection is built on the first accept into it and kept, as
1559
+ * `Http1Server`'s is.
1213
1560
  */
1214
1561
  export class Http1TlsServer {
1562
+ config: Http1Config
1215
1563
  tls: TlsTcpServer
1564
+ /**
1565
+ * The connections built so far, slot `k`'s at `k`: one per slot ever
1566
+ * accepted into. `connection` never adds to it; a slot never built reads
1567
+ * `vacant` instead.
1568
+ */
1216
1569
  connections: Http1Connection[]
1570
+ /**
1571
+ * What `connection` answers for every slot never built: one connection no
1572
+ * slot holds and every such slot shares, so the slot never reads as
1573
+ * another slot's live request. Its first read allocates it, once per
1574
+ * server, and a caller must not change it.
1575
+ */
1576
+ vacant: Http1Connection | null = null
1577
+ /** The `Date` every slot's responses carry, as `Http1Server.date` is. */
1578
+ date: HttpDate
1217
1579
  /** Where TLS decrypts into before the connection takes the bytes. */
1218
1580
  scratch: u8[]
1581
+ /** The output buffers the slots borrow while they write. */
1582
+ outputs: Http1OutputPool
1219
1583
 
1220
- /** A pool of `size` slots, at least one, serving `config` over TLS under `tlsConfig` on `listener`. */
1584
+ /**
1585
+ * A pool of `size` slots, at least one, serving `config` over TLS under
1586
+ * `tlsConfig` on `listener`. No slot is built here: the first `accept` into
1587
+ * a slot builds its connection and, in `tls`, its handshake state, and
1588
+ * keeps them, so a pool sized for a peak costs at start-up only the read
1589
+ * scratches, the shared `Date` and the empty pools.
1590
+ */
1221
1591
  constructor(tlsConfig: TlsServerConfig, config: Http1Config, listener: i32, size: i32) {
1592
+ this.config = config
1222
1593
  this.tls = new TlsTcpServer(tlsConfig, listener, size)
1223
1594
  this.connections = []
1224
- for (let k: i32 = 0; k < this.tls.size(); k++) {
1225
- this.connections.push(new Http1Connection(config))
1226
- }
1595
+ this.outputs = new Http1OutputPool(config.outputSize)
1596
+ this.date = new HttpDate()
1227
1597
  this.scratch = new Array<u8>(config.chunkSize)
1228
1598
  }
1229
1599
 
1230
- /** How many slots the pool has. */
1600
+ /**
1601
+ * A new connection on this pool's outputs and `Date`, for the next slot
1602
+ * built. Called by `accept` alone, as `tls` builds slots: slot `k`'s
1603
+ * connection must sit at index `k` of `connections`.
1604
+ */
1605
+ build(): Http1Connection {
1606
+ const conn: Http1Connection = this.make()
1607
+ this.connections.push(conn)
1608
+ return conn
1609
+ }
1610
+
1611
+ /** A connection on this pool's outputs and `Date` that no slot holds yet. */
1612
+ make(): Http1Connection {
1613
+ const conn: Http1Connection = new Http1Connection(this.config)
1614
+ conn.pool = this.outputs
1615
+ conn.date = this.date
1616
+ return conn
1617
+ }
1618
+
1619
+ /** How many slots the pool has, built or not. */
1231
1620
  size(): i32 {
1232
1621
  return this.tls.size()
1233
1622
  }
@@ -1247,10 +1636,32 @@ export class Http1TlsServer {
1247
1636
  return this.tls.fd(slot)
1248
1637
  }
1249
1638
 
1250
- /** The HTTP/1.1 connection of `slot`; a slot out of range names the first. */
1639
+ /**
1640
+ * Whether `slot` holds a connection and has its HTTP/1.1 connection built,
1641
+ * as `Http2TlsServer.live` asks: a slot accepted on `tls` directly holds a
1642
+ * TLS session and no `Http1Connection`, and reads as free here.
1643
+ */
1644
+ live(slot: i32): boolean {
1645
+ return this.tls.holds(slot) && slot < toI32(this.connections.length)
1646
+ }
1647
+
1648
+ /**
1649
+ * The HTTP/1.1 connection of `slot`. A slot never accepted into answers
1650
+ * `vacant`, as a free slot answers a connection that holds nothing, and
1651
+ * builds no slot; a slot out of range names slot 0's.
1652
+ */
1251
1653
  connection(slot: i32): Http1Connection {
1252
- const at: i32 = slot >= 0 && slot < toI32(this.connections.length) ? slot : H1_ZERO
1253
- return this.connections[at]
1654
+ const index: i32 = slot >= 0 && slot < this.tls.size() ? slot : 0
1655
+ if (index >= 0 && index < toI32(this.connections.length)) {
1656
+ return this.connections[index]
1657
+ }
1658
+ const vacant: Http1Connection | null = this.vacant
1659
+ if (vacant !== null) {
1660
+ return vacant
1661
+ }
1662
+ const made: Http1Connection = this.make()
1663
+ this.vacant = made
1664
+ return made
1254
1665
  }
1255
1666
 
1256
1667
  /** The ALPN protocol `slot`'s handshake chose, or empty. */
@@ -1267,11 +1678,17 @@ export class Http1TlsServer {
1267
1678
  /**
1268
1679
  * Accepts the next waiting connection as `TlsTcpServer.accept` does, with
1269
1680
  * the caller's 32-byte server random and x25519 key, and gives it a fresh
1270
- * connection. Answers the slot, or what `TlsTcpServer.accept` answers.
1681
+ * connection, building the slot's on its first accept. Answers the slot, or
1682
+ * what `TlsTcpServer.accept` answers.
1271
1683
  */
1272
1684
  accept(serverRandom: u8[], ephemeralPrivate: u8[]): i32 {
1273
1685
  const slot: i32 = this.tls.accept(serverRandom, ephemeralPrivate)
1274
- if (slot >= 0 && slot < toI32(this.connections.length)) {
1686
+ if (slot >= 0) {
1687
+ // `tls` builds a slot past its high-water mark one at a time, so this
1688
+ // builds at most the one connection, keeping slot `k`'s at `k`.
1689
+ while (toI32(this.connections.length) <= slot) {
1690
+ this.build()
1691
+ }
1275
1692
  const conn: Http1Connection = this.connections[slot]
1276
1693
  conn.restart()
1277
1694
  conn.lastActive = monotonicNanos()
@@ -1281,10 +1698,19 @@ export class Http1TlsServer {
1281
1698
 
1282
1699
  /** The socket of `slot` is readable: TLS reads it, and what the connection has to send goes after. Answers the interest. */
1283
1700
  readable(slot: i32): i32 {
1284
- if (this.holds(slot)) {
1285
- this.connections[slot].lastActive = monotonicNanos()
1701
+ const live: boolean = this.live(slot)
1702
+ const now: i64 = monotonicNanos()
1703
+ if (live) {
1704
+ this.connections[slot].lastActive = now
1286
1705
  }
1287
1706
  this.tls.readable(slot)
1707
+ // Ciphertext after the handshake is the start of a head, or of a record
1708
+ // that will hold one, so the head's clock starts here; a record trickled
1709
+ // a byte at a time would hand `next` no plaintext until it is whole. The
1710
+ // handshake itself is bounded by `idleTimeout` alone (TLS-4).
1711
+ if (live && this.tls.connection(slot).state === TLS_RECORD_STATE_OPEN) {
1712
+ this.connections[slot].headAwaited(now)
1713
+ }
1288
1714
  return this.flush(slot)
1289
1715
  }
1290
1716
 
@@ -1306,7 +1732,7 @@ export class Http1TlsServer {
1306
1732
  * slot, or one whose ALPN was another protocol, answers `H1_ERROR`.
1307
1733
  */
1308
1734
  next(slot: i32): i32 {
1309
- if (!this.holds(slot) || this.refused(slot)) {
1735
+ if (!this.live(slot) || this.refused(slot)) {
1310
1736
  return H1_ERROR
1311
1737
  }
1312
1738
  const conn: Http1Connection = this.connections[slot]
@@ -1339,7 +1765,7 @@ export class Http1TlsServer {
1339
1765
  * connection still holds bytes.
1340
1766
  */
1341
1767
  flush(slot: i32): i32 {
1342
- if (!this.holds(slot)) {
1768
+ if (!this.live(slot)) {
1343
1769
  return TLS_RECORD_DONE
1344
1770
  }
1345
1771
  if (this.refused(slot)) {
@@ -1354,8 +1780,14 @@ export class Http1TlsServer {
1354
1780
  return conn.wantsWrite() && (wants & TLS_RECORD_DONE) === 0 ? wants | TLS_RECORD_WANT_WRITE : wants
1355
1781
  }
1356
1782
 
1357
- /** Writes what `slot`'s connection holds into TLS, as far as TLS takes it. */
1783
+ /**
1784
+ * Writes what `slot`'s connection holds into TLS, as far as TLS takes it;
1785
+ * a slot never built has nothing to write.
1786
+ */
1358
1787
  send(slot: i32): void {
1788
+ if (slot < 0 || slot >= toI32(this.connections.length)) {
1789
+ return
1790
+ }
1359
1791
  const conn: Http1Connection = this.connections[slot]
1360
1792
  const pending: i32 = conn.outputEnd - conn.outputStart
1361
1793
  while (conn.wantsWrite()) {
@@ -1368,18 +1800,25 @@ export class Http1TlsServer {
1368
1800
  if (conn.outputEnd - conn.outputStart < pending) {
1369
1801
  conn.lastActive = monotonicNanos()
1370
1802
  }
1803
+ conn.release()
1371
1804
  }
1372
1805
 
1373
1806
  /** Ends `slot`'s connection and frees the slot at once, as `TlsTcpServer.close` does. */
1374
1807
  close(slot: i32): void {
1375
1808
  this.tls.close(slot)
1809
+ if (slot >= 0 && slot < toI32(this.connections.length)) {
1810
+ this.connections[slot].abort()
1811
+ }
1376
1812
  }
1377
1813
 
1378
- /** Closes every slot that has been idle past `idleTimeout` at `now` (`monotonicNanos`); answers how many. */
1814
+ /**
1815
+ * Closes every slot that has been idle past `idleTimeout`, or reading one
1816
+ * head for longer than `headTimeout`, at `now` (`monotonicNanos`); answers how many.
1817
+ */
1379
1818
  expire(now: i64): i32 {
1380
1819
  let n: i32 = 0
1381
1820
  for (let k: i32 = 0; k < this.tls.size() && k < toI32(this.connections.length); k++) {
1382
- if (this.tls.holds(k) && this.connections[k].idle(now)) {
1821
+ if (this.tls.holds(k) && this.connections[k].expired(now)) {
1383
1822
  this.tls.close(k)
1384
1823
  n = n + 1
1385
1824
  }