@amritk/nish-x86_64-linux 0.23.1 → 0.25.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 (51) hide show
  1. package/bin/nish +0 -0
  2. package/docs/AI.md +50 -23
  3. package/package.json +1 -1
  4. package/runtime/browser.mjs +4 -3
  5. package/runtime/core/arrays.d.ts +0 -2
  6. package/runtime/core/arrays.mjs +0 -2
  7. package/runtime/core/host.d.ts +8 -0
  8. package/runtime/core/host.mjs +50 -2
  9. package/runtime/core/numbers.mjs +2 -3
  10. package/runtime/nish.d.ts +100 -4
  11. package/runtime/nish.h +34 -0
  12. package/runtime/nish.mjs +23 -5
  13. package/runtime/node.mjs +57 -6
  14. package/runtime/runtime-net.c +45 -4
  15. package/runtime/runtime-os.c +115 -12
  16. package/runtime/runtime-term.c +2 -2
  17. package/runtime/runtime.c +1 -1
  18. package/scripts/build.sh +13 -3
  19. package/std/README.md +44 -7
  20. package/std/cli-args.ts +1216 -0
  21. package/std/cli-flags.ts +585 -0
  22. package/std/cli.ts +308 -19
  23. package/std/compress/checksum.ts +290 -0
  24. package/std/compress/deflate.ts +2790 -0
  25. package/std/compress/gzip.ts +761 -0
  26. package/std/compress/zlib.ts +168 -0
  27. package/std/crypto/LICENSE-fiat-crypto-p384 +21 -0
  28. package/std/crypto/p256.ts +63 -1
  29. package/std/crypto/p384.ts +6044 -0
  30. package/std/crypto/pki-roots.ts +322 -0
  31. package/std/crypto/pki.ts +1207 -0
  32. package/std/crypto/rsa.ts +663 -0
  33. package/std/crypto/sha256.ts +2 -3
  34. package/std/crypto/x25519.ts +3 -4
  35. package/std/crypto/x509.ts +1054 -58
  36. package/std/net/dns-config.ts +734 -0
  37. package/std/net/dns-message.ts +517 -0
  38. package/std/net/dns-resolver.ts +1015 -0
  39. package/std/net/dns.ts +478 -0
  40. package/std/net/http-compress.ts +393 -0
  41. package/std/net/http1-client.ts +1227 -0
  42. package/std/net/http1-server.ts +101 -1
  43. package/std/net/http1.ts +9 -9
  44. package/std/net/tls/client.ts +1094 -0
  45. package/std/net/tls/codec.ts +585 -3
  46. package/std/net/tls/record-client.ts +1192 -0
  47. package/std/net/tls/verify.ts +221 -0
  48. package/std/net/tls-tcp.ts +642 -11
  49. package/std/net/tls.ts +2 -2
  50. package/std/net/url.ts +559 -4
  51. package/std/yaml-write.ts +415 -0
@@ -114,6 +114,12 @@
114
114
  */
115
115
  import { Secret } from "nish:secret"
116
116
  import { copyBytes } from "nish/bytes"
117
+ import {
118
+ HTTP_CODING_IDENTITY,
119
+ HTTP_OFFER_GZIP,
120
+ HttpCompressor,
121
+ httpAcceptEncoding,
122
+ } from "nish/net/http-compress"
117
123
  import { netClose, netRead, netWrite, tcpAccept } from "nish:net"
118
124
  import {
119
125
  HTTP1_BODY,
@@ -1205,6 +1211,98 @@ export class Http1Connection {
1205
1211
  return 0
1206
1212
  }
1207
1213
 
1214
+ // ---- Content coding -----------------------------------------------------------
1215
+
1216
+ /**
1217
+ * The content coding to answer the current request with, read from its
1218
+ * `Accept-Encoding` with gzip offered (`httpAcceptEncoding`):
1219
+ * `HTTP_CODING_GZIP`, `HTTP_CODING_IDENTITY` (also with no such field), or
1220
+ * `HTTP_CODING_NONE` when the client refuses identity and does not take
1221
+ * gzip. Allocates nothing.
1222
+ */
1223
+ acceptEncoding(): i32 {
1224
+ const parser: Http1Parser = this.parser
1225
+ const i: i32 = parser.headerIndex("accept-encoding")
1226
+ const spans: i32[] = parser.spans
1227
+ if (i < 0 || 4 * i + 3 >= toI32(spans.length)) {
1228
+ return HTTP_CODING_IDENTITY
1229
+ }
1230
+ const start: i32 = spans[4 * i + 2]
1231
+ const end: i32 = spans[4 * i + 3]
1232
+ if (start < 0 || start > end || end > toI32(parser.head.length)) {
1233
+ return HTTP_CODING_IDENTITY
1234
+ }
1235
+ return httpAcceptEncoding(parser.head, start, end, HTTP_OFFER_GZIP)
1236
+ }
1237
+
1238
+ /**
1239
+ * Answers the current request with all of `body[off .. off + len)` in one
1240
+ * call: `respond`, `write` and `end`, the body compressed by `enc` when
1241
+ * `coding` (from `acceptEncoding`) is gzip and `enc.compress` takes it,
1242
+ * with `Content-Encoding: gzip` and the compressed `Content-Length`, and
1243
+ * otherwise sent as it is; `Vary: Accept-Encoding` either way while
1244
+ * `enc.vary` is set. The program's fields may not name `Content-Encoding`
1245
+ * or, with `enc.vary`, `Vary`. The whole response is written or none of
1246
+ * it: `H1_AGAIN` when the output has no room for it yet (`H1_WRITE` says
1247
+ * when to try again, compressing again), `H1_INVALID` for a response
1248
+ * larger than the output could ever hold or one `respond` refuses,
1249
+ * `H1_CLOSED` with no request to answer; 0 once it is queued. A window
1250
+ * outside `body` panics.
1251
+ */
1252
+ respondEncoded(
1253
+ status: i32,
1254
+ names: u8[][],
1255
+ values: u8[][],
1256
+ body: u8[],
1257
+ off: i32,
1258
+ len: i32,
1259
+ enc: HttpCompressor,
1260
+ coding: i32
1261
+ ): i32 {
1262
+ http1ServerCheckWindow("Http1Connection.respondEncoded", body, off, len)
1263
+ if (!this.answerable()) {
1264
+ return H1_CLOSED
1265
+ }
1266
+ const packed: i32 = enc.compress(coding, body, off, len)
1267
+ let n: i32 = len
1268
+ if (packed >= 0) {
1269
+ enc.addFields(names, values)
1270
+ n = packed
1271
+ } else {
1272
+ enc.identityFields(names, values)
1273
+ }
1274
+ // `respond` and the body together, or neither: what `respond` sets is
1275
+ // put back when the body does not fit behind the head. `room` first, so
1276
+ // that what was sent is already moved out of the way and the `outputEnd`
1277
+ // put back is one `respond` did not move.
1278
+ this.room()
1279
+ const outputEnd: i32 = this.outputEnd
1280
+ const closeAfter: boolean = this.closeAfter
1281
+ const r: i32 = this.respond(status, enc.names, enc.values, n)
1282
+ if (r !== 0) {
1283
+ return r
1284
+ }
1285
+ if (!this.responseEmpty && n > this.bodyRoom()) {
1286
+ const fits: boolean = this.outputEnd - outputEnd + n <= this.config.outputSize - H1_CONTROL_RESERVE
1287
+ this.outputEnd = outputEnd
1288
+ this.closeAfter = closeAfter
1289
+ this.response = H1_R_NONE
1290
+ this.responseFraming = 0
1291
+ this.responseLeft = 0
1292
+ this.responseEmpty = false
1293
+ if (!fits) {
1294
+ return H1_INVALID
1295
+ }
1296
+ this.writeHeld = true
1297
+ return H1_AGAIN
1298
+ }
1299
+ const w: i32 = packed >= 0 ? this.write(enc.output, toI32(0), n) : this.write(body, off, n)
1300
+ if (w !== n) {
1301
+ panic("Http1Connection.respondEncoded: a body the room was checked for did not fit")
1302
+ }
1303
+ return this.end()
1304
+ }
1305
+
1208
1306
  // ---- WebSocket ----------------------------------------------------------------
1209
1307
 
1210
1308
  /**
@@ -1859,7 +1957,9 @@ export class Http1TlsServer {
1859
1957
  readable(slot: i32): i32 {
1860
1958
  const live: boolean = this.live(slot)
1861
1959
  const now: i64 = monotonicNanos()
1862
- if (live) {
1960
+ // What a lingering slot drains is not activity, so `idleTimeout` bounds
1961
+ // how long a client that trickles bytes after the close can hold it.
1962
+ if (live && !this.tls.lingering(slot)) {
1863
1963
  this.connections[slot].lastActive = now
1864
1964
  }
1865
1965
  this.tls.readable(slot)
package/std/net/http1.ts CHANGED
@@ -524,7 +524,7 @@ const http1TakeLine = (p: Http1Parser, limit: i32, overStatus: i32): i32 => {
524
524
  }
525
525
 
526
526
  /** Whether `c` is a tchar of RFC 9110 §5.6.2, the bytes a token is made of. */
527
- const http1IsTokenByte = (c: i32): boolean =>
527
+ export const http1IsTokenByte = (c: i32): boolean =>
528
528
  (c >= 97 && c <= 122) ||
529
529
  (c >= 65 && c <= 90) ||
530
530
  (c >= 48 && c <= 57) ||
@@ -541,10 +541,10 @@ const http1IsTokenByte = (c: i32): boolean =>
541
541
  c === 126
542
542
 
543
543
  /** Whether `c` may appear in a field value (RFC 9110 §5.5): HTAB, SP, VCHAR or obs-text. */
544
- const http1IsValueByte = (c: i32): boolean => c === 9 || (c >= 32 && c !== 127)
544
+ export const http1IsValueByte = (c: i32): boolean => c === 9 || (c >= 32 && c !== 127)
545
545
 
546
546
  /** `buf[from .. to)` as a string, each upper-case ASCII letter lowered when `lower`. */
547
- const http1Text = (buf: u8[], from: i32, to: i32, lower: boolean): string => {
547
+ export const http1Text = (buf: u8[], from: i32, to: i32, lower: boolean): string => {
548
548
  const parts: string[] = []
549
549
  for (let k: i32 = from; k >= 0 && k < to && k < toI32(buf.length); k += 1) {
550
550
  let c: i32 = toI32(buf[k])
@@ -557,10 +557,10 @@ const http1Text = (buf: u8[], from: i32, to: i32, lower: boolean): string => {
557
557
  }
558
558
 
559
559
  /** Whether `c` is optional whitespace, a space or a tab (OWS, RFC 9110 §5.6.3). */
560
- const http1IsOws = (c: i32): boolean => c === 32 || c === 9
560
+ export const http1IsOws = (c: i32): boolean => c === 32 || c === 9
561
561
 
562
562
  /** Whether `text[a .. b)` is `word`, which is lowercase, in any ASCII case. */
563
- const http1SameWord = (text: string, a: i32, b: i32, word: string): boolean => {
563
+ export const http1SameWord = (text: string, a: i32, b: i32, word: string): boolean => {
564
564
  const n: i32 = toI32(word.length)
565
565
  if (a < 0 || b - a !== n || b > toI32(text.length)) {
566
566
  return false
@@ -989,7 +989,7 @@ const http1ContentLength = (bytes: u8[], from: i32, to: i32, limit: i32): i32 =>
989
989
  }
990
990
 
991
991
  /** The value of the hex digit `c`, or -1. */
992
- const http1HexValue = (c: i32): i32 => {
992
+ export const http1HexValue = (c: i32): i32 => {
993
993
  if (c >= 48 && c <= 57) {
994
994
  return c - 48
995
995
  }
@@ -1190,7 +1190,7 @@ const http1BytesOf = (text: string): u8[] => {
1190
1190
  }
1191
1191
 
1192
1192
  /** Whether every byte of `text` is a tchar, and there is at least one. */
1193
- const http1IsToken = (text: string): boolean => {
1193
+ export const http1IsToken = (text: string): boolean => {
1194
1194
  const n: i32 = toI32(text.length)
1195
1195
  if (n === 0) {
1196
1196
  return false
@@ -1204,7 +1204,7 @@ const http1IsToken = (text: string): boolean => {
1204
1204
  }
1205
1205
 
1206
1206
  /** Whether every byte of `text` may stand in a field value or a reason phrase. */
1207
- const http1IsFieldText = (text: string): boolean => {
1207
+ export const http1IsFieldText = (text: string): boolean => {
1208
1208
  const n: i32 = toI32(text.length)
1209
1209
  for (let k: i32 = 0; k < n; k += 1) {
1210
1210
  if (!http1IsValueByte(toI32(text.charCodeAt(k)))) {
@@ -1395,7 +1395,7 @@ const http1DecimalDigits = (n: i32): i32 => {
1395
1395
  }
1396
1396
 
1397
1397
  /** Writes `text` at `out[at ..)`, which the caller has made sure holds it, and answers where it ends. */
1398
- const http1PutText = (out: u8[], at: i32, text: string): i32 => {
1398
+ export const http1PutText = (out: u8[], at: i32, text: string): i32 => {
1399
1399
  const n: i32 = toI32(text.length)
1400
1400
  for (let k: i32 = 0; k < n && at + k < toI32(out.length); k += 1) {
1401
1401
  if (at + k >= 0) {