@amritk/nish-x86_64-linux 0.20.0 → 0.22.1
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.
- package/INSTALL.md +52 -10
- package/bin/nish +0 -0
- package/docs/AI.md +2777 -0
- package/package.json +2 -1
- package/runtime/browser.d.ts +6 -0
- package/runtime/browser.mjs +77 -0
- package/runtime/core/arrays.d.ts +36 -0
- package/runtime/core/arrays.mjs +153 -0
- package/runtime/core/checks.mjs +20 -0
- package/runtime/core/host.d.ts +80 -0
- package/runtime/core/host.mjs +325 -0
- package/runtime/core/numbers.d.ts +66 -0
- package/runtime/core/numbers.mjs +343 -0
- package/runtime/core/result.d.ts +45 -0
- package/runtime/core/result.mjs +140 -0
- package/runtime/core/strings.d.ts +14 -0
- package/runtime/core/strings.mjs +169 -0
- package/runtime/core.d.ts +9 -0
- package/runtime/core.mjs +55 -0
- package/runtime/host.d.ts +6 -0
- package/runtime/nish.d.ts +46 -2
- package/runtime/nish.h +75 -2
- package/runtime/nish.mjs +23 -3
- package/runtime/node.mjs +386 -0
- package/runtime/runtime-bytes.c +401 -0
- package/runtime/runtime-cross.c +1 -1
- package/runtime/runtime-host.c +1 -1
- package/runtime/runtime-net.c +12 -1
- package/runtime/runtime-os.c +1 -1
- package/runtime/runtime-parallel.c +1 -1
- package/runtime/runtime-simd.c +231 -7
- package/runtime/runtime-term.c +504 -0
- package/runtime/runtime-wasm.c +0 -11
- package/runtime/runtime.c +190 -6
- package/runtime/shim.mjs +6 -985
- package/runtime/sqlite/LICENSE.md +85 -0
- package/runtime/sqlite/README.md +45 -0
- package/runtime/sqlite/nish-sqlite.c +359 -0
- package/runtime/sqlite/sqlite3.c +271131 -0
- package/runtime/sqlite/sqlite3.h +14447 -0
- package/scripts/build.sh +311 -59
- package/std/LICENSE-fast-float +23 -0
- package/std/LICENSE-fdlibm +8 -0
- package/std/README.md +32 -12
- package/std/base64.ts +116 -0
- package/std/bytes.ts +256 -0
- package/std/cli.ts +344 -0
- package/std/collections.ts +6 -5
- package/std/crypto/LICENSE-crypt_blowfish +26 -0
- package/std/crypto/base64url.ts +125 -0
- package/std/crypto/bcrypt.ts +1557 -0
- package/std/crypto/hmac.ts +138 -2
- package/std/crypto/x509.ts +11 -122
- package/std/json-tokenizer.ts +2998 -57
- package/std/json-value.ts +22 -3
- package/std/json.ts +87 -8
- package/std/math.ts +608 -0
- package/std/net/http1-server.ts +282 -40
- package/std/net/http1.ts +40 -21
- package/std/net/http3-server.ts +50 -12
- package/std/net/postgres.ts +2294 -0
- package/std/net/prefork.ts +23 -3
- package/std/net/quic-listener.ts +20 -4
- package/std/random.ts +66 -4
- package/std/regex.ts +4274 -0
- package/std/sqlite.ts +391 -0
- package/std/term-io.ts +978 -0
- package/std/term-pixels.ts +874 -0
- package/std/term-probe.ts +459 -0
- package/std/term-rate.ts +993 -0
- package/std/term.ts +2453 -0
- package/std/text.ts +90 -7
- package/std/yaml-lines.ts +141 -0
- package/std/yaml.ts +4675 -0
package/std/net/http1.ts
CHANGED
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
*
|
|
81
81
|
* Written from RFC 9112 and RFC 9110, not ported from another implementation.
|
|
82
82
|
*/
|
|
83
|
+
import { copyBytes } from "nish/bytes"
|
|
83
84
|
|
|
84
85
|
/** `next()`: the input so far holds no further event; feed more. */
|
|
85
86
|
export const HTTP1_NEED_MORE: i32 = 0
|
|
@@ -234,11 +235,15 @@ export class Http1Parser {
|
|
|
234
235
|
this.maxHeaderBytes = http1Clamp(maxHeaderBytes)
|
|
235
236
|
this.maxHeaders = http1Clamp(maxHeaders)
|
|
236
237
|
this.maxBody = http1Clamp(maxBody)
|
|
237
|
-
|
|
238
|
+
// The input and the head are made by the first byte fed and the first
|
|
239
|
+
// head kept, at HTTP1_FIRST_INPUT and HTTP1_FIRST_HEAD bytes: a parser
|
|
240
|
+
// that is built and never fed (a pool's spare slot) costs neither, and a
|
|
241
|
+
// caller that lends them out between requests puts empty ones here.
|
|
242
|
+
this.buf = []
|
|
238
243
|
this.body = this.buf
|
|
239
244
|
this.names = []
|
|
240
245
|
this.values = []
|
|
241
|
-
this.head =
|
|
246
|
+
this.head = []
|
|
242
247
|
this.spans = new Array<i32>(64)
|
|
243
248
|
this.tally = new Http1ListTally()
|
|
244
249
|
this.restart()
|
|
@@ -261,19 +266,9 @@ export class Http1Parser {
|
|
|
261
266
|
http1Reserve(this, len)
|
|
262
267
|
const buf: u8[] = this.buf
|
|
263
268
|
const at: i32 = this.end
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
|
|
267
|
-
buf.set(data, at)
|
|
268
|
-
this.end = at + len
|
|
269
|
-
return
|
|
270
|
-
}
|
|
271
|
-
for (let k: i32 = 0; k < len; k += 1) {
|
|
272
|
-
const to: i32 = at + k
|
|
273
|
-
if (to >= 0 && to < toI32(buf.length)) {
|
|
274
|
-
buf[to] = data[off + k]
|
|
275
|
-
}
|
|
276
|
-
}
|
|
269
|
+
// One move: http1Reserve made room for `len` bytes at `at`, and the
|
|
270
|
+
// window was checked above.
|
|
271
|
+
copyBytes(buf, at, data, off, len)
|
|
277
272
|
this.end = at + len
|
|
278
273
|
}
|
|
279
274
|
|
|
@@ -359,6 +354,16 @@ export class Http1Parser {
|
|
|
359
354
|
return http1HeadIs(this.head, spans[4 * found + 2], spans[4 * found + 3], protocol, true)
|
|
360
355
|
}
|
|
361
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Whether the parser waits for a request line with nothing fed and unread,
|
|
359
|
+
* so its input and head buffers hold nothing it needs: a caller may lend
|
|
360
|
+
* them out and leave empty arrays in `buf`, `body` and `head`, which the
|
|
361
|
+
* next feed and head make or the caller puts back first.
|
|
362
|
+
*/
|
|
363
|
+
resting(): boolean {
|
|
364
|
+
return this.state === HTTP1_S_REQUEST_LINE && this.end === this.start
|
|
365
|
+
}
|
|
366
|
+
|
|
362
367
|
/** How many bytes were fed and not consumed yet: what a caller bounds its reads by. */
|
|
363
368
|
buffered(): i32 {
|
|
364
369
|
return this.end - this.start
|
|
@@ -410,6 +415,11 @@ export class Http1Parser {
|
|
|
410
415
|
}
|
|
411
416
|
}
|
|
412
417
|
|
|
418
|
+
/** The input buffer a parser makes on its first feed, the smallest it grows from. */
|
|
419
|
+
export const HTTP1_FIRST_INPUT: i32 = 1024
|
|
420
|
+
/** The head buffer a parser makes for its first head. */
|
|
421
|
+
export const HTTP1_FIRST_HEAD: i32 = 256
|
|
422
|
+
|
|
413
423
|
/** Makes room for `len` more bytes at `p.end`, moving the live bytes down first. */
|
|
414
424
|
const http1Reserve = (p: Http1Parser, len: i32): void => {
|
|
415
425
|
const old: u8[] = p.buf
|
|
@@ -418,7 +428,7 @@ const http1Reserve = (p: Http1Parser, len: i32): void => {
|
|
|
418
428
|
return
|
|
419
429
|
}
|
|
420
430
|
const live: i32 = p.end - p.start
|
|
421
|
-
let size: i32 = capacity
|
|
431
|
+
let size: i32 = capacity < HTTP1_FIRST_INPUT ? HTTP1_FIRST_INPUT : capacity
|
|
422
432
|
while (size - live < len) {
|
|
423
433
|
if (size > 1073741823) {
|
|
424
434
|
panic("Http1Parser: more than 2^31 - 1 bytes buffered")
|
|
@@ -429,8 +439,9 @@ const http1Reserve = (p: Http1Parser, len: i32): void => {
|
|
|
429
439
|
// the live bytes move to the front, and every index into them moves too.
|
|
430
440
|
const buf: u8[] = size === capacity ? old : new Array<u8>(size)
|
|
431
441
|
const from: i32 = p.start
|
|
432
|
-
|
|
433
|
-
|
|
442
|
+
if (live > 0) {
|
|
443
|
+
// One move, overlapping when the buffer is the same one.
|
|
444
|
+
copyBytes(buf, 0, old, from, live)
|
|
434
445
|
}
|
|
435
446
|
p.buf = buf
|
|
436
447
|
p.lineStart -= from
|
|
@@ -601,6 +612,9 @@ const http1HeadAppend = (p: Http1Parser, from: i32, to: i32): i32 => {
|
|
|
601
612
|
const at: i32 = p.headLength
|
|
602
613
|
let size: i32 = toI32(p.head.length)
|
|
603
614
|
if (n > size - at) {
|
|
615
|
+
if (size < HTTP1_FIRST_HEAD) {
|
|
616
|
+
size = HTTP1_FIRST_HEAD
|
|
617
|
+
}
|
|
604
618
|
while (size - at < n) {
|
|
605
619
|
if (size > 1073741823) {
|
|
606
620
|
panic("Http1Parser: a head of more than 2^31 - 1 bytes")
|
|
@@ -616,9 +630,14 @@ const http1HeadAppend = (p: Http1Parser, from: i32, to: i32): i32 => {
|
|
|
616
630
|
}
|
|
617
631
|
const head: u8[] = p.head
|
|
618
632
|
const buf: u8[] = p.buf
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
633
|
+
if (n > 0 && from >= 0 && from <= toI32(buf.length) - n && at <= toI32(head.length) - n) {
|
|
634
|
+
// The line lies in `buf` and the head was grown to hold it: one move.
|
|
635
|
+
copyBytes(head, at, buf, from, n)
|
|
636
|
+
} else {
|
|
637
|
+
for (let k: i32 = 0; k < n && at + k < toI32(head.length) && from + k < toI32(buf.length); k += 1) {
|
|
638
|
+
if (from + k >= 0) {
|
|
639
|
+
head[at + k] = buf[from + k]
|
|
640
|
+
}
|
|
622
641
|
}
|
|
623
642
|
}
|
|
624
643
|
p.headLength = at + n
|
package/std/net/http3-server.ts
CHANGED
|
@@ -41,6 +41,14 @@
|
|
|
41
41
|
* **Sending.** `flush` writes each touched slot's datagrams with
|
|
42
42
|
* `quicListenerTakeFlight`, a paced flight at a time in one `udpSendTo` with
|
|
43
43
|
* GSO where the platform has it and one datagram at a time where it does not.
|
|
44
|
+
* Each flight goes with the ECN codepoint its connection marked it with
|
|
45
|
+
* (`QuicFlight.ecn`, RFC 9000 §13.4), so the peer's ACK_ECN counts are
|
|
46
|
+
* validated and a CE mark shrinks the window. Where the platform sends no
|
|
47
|
+
* ECN (Darwin, whose `udpSendTo` answers -95 to a marked send), the first
|
|
48
|
+
* marked send goes again unmarked and no slot marks after it. A -95 is also
|
|
49
|
+
* what a platform without segmentation offload answers, so a refused GSO
|
|
50
|
+
* send goes again one datagram at a time, still marked, and only a -95 to
|
|
51
|
+
* one of those turns marking off.
|
|
44
52
|
* The pacer counts the microseconds `clock` gives it, so on a path whose
|
|
45
53
|
* round trip is under a millisecond it neither waits for the next
|
|
46
54
|
* millisecond to earn credit nor holds a slot back for a whole one; without
|
|
@@ -122,8 +130,8 @@ export const H3_SERVER_ANSWER_INTERVAL: i64 = 100
|
|
|
122
130
|
/** The address form `nish:net` reads and writes. */
|
|
123
131
|
const H3_SERVER_ADDRESS: i32 = 18
|
|
124
132
|
|
|
125
|
-
/** What `udpSendTo` answers where the platform has no segmentation offload. */
|
|
126
|
-
const
|
|
133
|
+
/** What `udpSendTo` answers where the platform has no segmentation offload, or sends no ECN. */
|
|
134
|
+
const H3_SERVER_UNSUPPORTED: i32 = -95
|
|
127
135
|
|
|
128
136
|
/** The largest datagram read: a GRO receive of up to 64 KB. */
|
|
129
137
|
const H3_SERVER_RECEIVE_SIZE: i32 = 65536
|
|
@@ -484,6 +492,8 @@ export class Http3Server {
|
|
|
484
492
|
refused: i32 = 0
|
|
485
493
|
limited: i32 = 0
|
|
486
494
|
sendErrors: i32 = 0
|
|
495
|
+
/** Whether the platform sends ECN marks: true until a marked send answers -95, and every slot's `ecnMarking` with it. */
|
|
496
|
+
ecn: boolean = true
|
|
487
497
|
/**
|
|
488
498
|
* The stream buffers every slot's connection borrows from, made by the
|
|
489
499
|
* constructor for the stream table `quicConfig` gives every slot: `null`
|
|
@@ -578,6 +588,7 @@ export class Http3Server {
|
|
|
578
588
|
build(): void {
|
|
579
589
|
crypto.getRandomValues(this.entropy)
|
|
580
590
|
const quic = new QuicConnection(this.quicConfig, this.entropy)
|
|
591
|
+
quic.ecnMarking = this.ecn
|
|
581
592
|
this.quics.push(quic)
|
|
582
593
|
const pools: QuicStreamPools | null = this.streamPools
|
|
583
594
|
if (pools !== null && pools.data.size === quic.streams.bufferSize && quic.streams.slots.length > 0) {
|
|
@@ -751,7 +762,7 @@ export class Http3Server {
|
|
|
751
762
|
if (this.listener.handleWindow(buf, at, len, address, now, answer) !== QUIC_LISTEN_ACCEPT) {
|
|
752
763
|
const reply: i32 = toI32(answer.reply.length)
|
|
753
764
|
if (reply > 0) {
|
|
754
|
-
this.send(answer.reply, H3_SERVER_ZERO, reply, address, H3_SERVER_ZERO)
|
|
765
|
+
this.send(answer.reply, H3_SERVER_ZERO, reply, address, H3_SERVER_ZERO, H3_SERVER_ZERO)
|
|
755
766
|
}
|
|
756
767
|
return
|
|
757
768
|
}
|
|
@@ -904,21 +915,40 @@ export class Http3Server {
|
|
|
904
915
|
}
|
|
905
916
|
}
|
|
906
917
|
|
|
907
|
-
/**
|
|
908
|
-
|
|
909
|
-
|
|
918
|
+
/**
|
|
919
|
+
* Sends `buf[at .. at + len)` to `to` with the ECN codepoint `ecn`, cut
|
|
920
|
+
* into `segment`-byte datagrams when it is above 0; answers whether it went.
|
|
921
|
+
*/
|
|
922
|
+
send(buf: u8[], at: i32, len: i32, to: u8[], segment: i32, ecn: i32): boolean {
|
|
923
|
+
const sent: i32 = udpSendTo(this.fd, buf, at, len, to, segment, ecn)
|
|
910
924
|
if (sent >= 0) {
|
|
911
925
|
return true
|
|
912
926
|
}
|
|
913
|
-
if (sent !==
|
|
927
|
+
if (sent !== H3_SERVER_UNSUPPORTED || (segment <= 0 && ecn === 0)) {
|
|
914
928
|
this.sendErrors = h3Count(this.sendErrors)
|
|
915
929
|
return false
|
|
916
930
|
}
|
|
917
|
-
//
|
|
931
|
+
// -95: no segmentation offload, or no ECN, or both. One datagram at a
|
|
932
|
+
// time, still marked: a -95 to a datagram with no segment is the mark's.
|
|
933
|
+
let mark: i32 = ecn
|
|
934
|
+
if (segment <= 0) {
|
|
935
|
+
this.unmark()
|
|
936
|
+
mark = H3_SERVER_ZERO
|
|
937
|
+
}
|
|
938
|
+
const step: i32 = segment > 0 ? segment : len
|
|
918
939
|
let p: i32 = at
|
|
919
940
|
while (p < at + len) {
|
|
920
|
-
const n: i32 = at + len - p <
|
|
921
|
-
|
|
941
|
+
const n: i32 = at + len - p < step ? at + len - p : step
|
|
942
|
+
let one: i32 = udpSendTo(this.fd, buf, p, n, to, H3_SERVER_ZERO, mark)
|
|
943
|
+
if (one === H3_SERVER_UNSUPPORTED && mark !== 0) {
|
|
944
|
+
// No ECN here: this datagram and the rest go unmarked and no slot
|
|
945
|
+
// marks again. The packets just counted as marked fail their
|
|
946
|
+
// connection's validation.
|
|
947
|
+
this.unmark()
|
|
948
|
+
mark = H3_SERVER_ZERO
|
|
949
|
+
one = udpSendTo(this.fd, buf, p, n, to, H3_SERVER_ZERO, mark)
|
|
950
|
+
}
|
|
951
|
+
if (one < 0) {
|
|
922
952
|
this.sendErrors = h3Count(this.sendErrors)
|
|
923
953
|
return false
|
|
924
954
|
}
|
|
@@ -927,6 +957,14 @@ export class Http3Server {
|
|
|
927
957
|
return true
|
|
928
958
|
}
|
|
929
959
|
|
|
960
|
+
/** The platform sends no ECN: no slot's connection marks from now on. */
|
|
961
|
+
unmark(): void {
|
|
962
|
+
this.ecn = false
|
|
963
|
+
for (let slot: i32 = 0; slot < toI32(this.quics.length); slot++) {
|
|
964
|
+
this.quics[slot].ecnMarking = false
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
930
968
|
/**
|
|
931
969
|
* Sends what every touched slot has, as far as its pacer lets it, closes a
|
|
932
970
|
* slot whose HTTP/3 side is done after GOAWAY, frees a slot whose
|
|
@@ -972,7 +1010,7 @@ export class Http3Server {
|
|
|
972
1010
|
break
|
|
973
1011
|
}
|
|
974
1012
|
const segment: i32 = this.flight.count > 1 ? this.flight.segment : H3_SERVER_ZERO
|
|
975
|
-
if (!this.send(this.tx, H3_SERVER_ZERO, n, to, segment)) {
|
|
1013
|
+
if (!this.send(this.tx, H3_SERVER_ZERO, n, to, segment, this.flight.ecn)) {
|
|
976
1014
|
break
|
|
977
1015
|
}
|
|
978
1016
|
retried = false
|
|
@@ -981,7 +1019,7 @@ export class Http3Server {
|
|
|
981
1019
|
// The CONNECTION_CLOSE goes whatever the pacer says: nothing follows it.
|
|
982
1020
|
const n: i32 = quic.takeDatagramInto(this.tx, H3_SERVER_ZERO, now)
|
|
983
1021
|
if (n > 0) {
|
|
984
|
-
this.send(this.tx, H3_SERVER_ZERO, n, to, H3_SERVER_ZERO)
|
|
1022
|
+
this.send(this.tx, H3_SERVER_ZERO, n, to, H3_SERVER_ZERO, quic.datagramEcn)
|
|
985
1023
|
}
|
|
986
1024
|
this.release(slot)
|
|
987
1025
|
return
|