goscript 0.2.2 → 0.2.4
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/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
- package/compiler/lowering.go +279 -16
- package/compiler/override-registry_test.go +175 -0
- package/compiler/protobuf-ts-binding.go +154 -6
- package/compiler/protobuf-ts-binding_test.go +7 -2
- package/compiler/runtime-contract.go +2 -0
- package/compiler/runtime-contract_test.go +1 -0
- package/compiler/semantic-model.go +16 -0
- package/compiler/semantic-model_test.go +38 -0
- package/compiler/skeleton_test.go +522 -17
- package/compiler/typescript-emitter.go +4 -0
- package/dist/gs/builtin/builtin.js +7 -9
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/defer.js +2 -2
- package/dist/gs/builtin/hostio.js +5 -5
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/map.js +2 -1
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +3 -0
- package/dist/gs/builtin/slice.js +39 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +49 -0
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/compress/gzip/index.d.ts +41 -0
- package/dist/gs/compress/gzip/index.js +235 -0
- package/dist/gs/compress/gzip/index.js.map +1 -0
- package/dist/gs/compress/zlib/index.js +5 -2
- package/dist/gs/compress/zlib/index.js.map +1 -1
- package/dist/gs/crypto/ecdh/index.js +27 -8
- package/dist/gs/crypto/ecdh/index.js.map +1 -1
- package/dist/gs/crypto/ed25519/index.js +3 -3
- package/dist/gs/crypto/ed25519/index.js.map +1 -1
- package/dist/gs/crypto/rand/index.js +6 -3
- package/dist/gs/crypto/rand/index.js.map +1 -1
- package/dist/gs/embed/index.js +9 -3
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
- package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
- package/dist/gs/hash/fnv/index.js +13 -5
- package/dist/gs/hash/fnv/index.js.map +1 -1
- package/dist/gs/io/fs/glob.d.ts +3 -3
- package/dist/gs/io/fs/glob.js +9 -9
- package/dist/gs/io/fs/glob.js.map +1 -1
- package/dist/gs/io/fs/readdir.d.ts +2 -2
- package/dist/gs/io/fs/readdir.js +13 -74
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readlink.d.ts +1 -1
- package/dist/gs/io/fs/readlink.js +2 -2
- package/dist/gs/io/fs/readlink.js.map +1 -1
- package/dist/gs/io/fs/stat.d.ts +4 -2
- package/dist/gs/io/fs/stat.js +12 -73
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.d.ts +2 -2
- package/dist/gs/io/fs/sub.js +11 -11
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/fs/walk.js +2 -2
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/maps/iter.js.map +1 -1
- package/dist/gs/maps/maps.js.map +1 -1
- package/dist/gs/mime/index.js +5 -2
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.js +6 -3
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +34 -18
- package/dist/gs/net/http/index.js +280 -63
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/net/http/pprof/index.d.ts +5 -5
- package/dist/gs/net/http/pprof/index.js +21 -21
- package/dist/gs/net/http/pprof/index.js.map +1 -1
- package/dist/gs/reflect/iter.js +1 -1
- package/dist/gs/reflect/iter.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -0
- package/dist/gs/reflect/type.js +53 -21
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/runtime/pprof/index.js.map +1 -1
- package/dist/gs/runtime/runtime.js +2 -2
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/runtime/trace/index.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +1 -1
- package/dist/gs/slices/slices.js +37 -4
- package/dist/gs/slices/slices.js.map +1 -1
- package/gs/builtin/builtin.ts +11 -14
- package/gs/builtin/defer.ts +2 -2
- package/gs/builtin/hostio.ts +5 -5
- package/gs/builtin/map.ts +4 -1
- package/gs/builtin/runtime-contract.test.ts +25 -0
- package/gs/builtin/slice.test.ts +14 -0
- package/gs/builtin/slice.ts +64 -0
- package/gs/builtin/type.ts +72 -0
- package/gs/bytes/bytes.test.ts +14 -13
- package/gs/compress/gzip/index.test.ts +86 -0
- package/gs/compress/gzip/index.ts +297 -0
- package/gs/compress/gzip/meta.json +6 -0
- package/gs/compress/gzip/parity.json +45 -0
- package/gs/compress/zlib/index.test.ts +19 -5
- package/gs/compress/zlib/index.ts +16 -7
- package/gs/context/context.test.ts +3 -1
- package/gs/crypto/ecdh/index.test.ts +6 -2
- package/gs/crypto/ecdh/index.ts +49 -12
- package/gs/crypto/ed25519/index.ts +20 -7
- package/gs/crypto/rand/index.ts +6 -3
- package/gs/embed/index.test.ts +4 -4
- package/gs/embed/index.ts +9 -3
- package/gs/fmt/fmt.test.ts +29 -4
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
- package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
- package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
- package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
- package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
- package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
- package/gs/hash/fnv/index.test.ts +1 -8
- package/gs/hash/fnv/index.ts +27 -10
- package/gs/io/fs/glob.ts +14 -11
- package/gs/io/fs/meta.json +5 -0
- package/gs/io/fs/readdir.test.ts +63 -2
- package/gs/io/fs/readdir.ts +33 -30
- package/gs/io/fs/readlink.test.ts +2 -2
- package/gs/io/fs/readlink.ts +5 -2
- package/gs/io/fs/stat.test.ts +79 -0
- package/gs/io/fs/stat.ts +24 -10
- package/gs/io/fs/sub.test.ts +93 -0
- package/gs/io/fs/sub.ts +13 -13
- package/gs/io/fs/walk.ts +2 -2
- package/gs/maps/iter.ts +9 -9
- package/gs/maps/maps.ts +4 -4
- package/gs/math/bits/index.test.ts +10 -1
- package/gs/mime/index.test.ts +33 -15
- package/gs/mime/index.ts +9 -2
- package/gs/net/http/httptest/index.test.ts +17 -3
- package/gs/net/http/httptest/index.ts +8 -3
- package/gs/net/http/index.test.ts +851 -124
- package/gs/net/http/index.ts +612 -146
- package/gs/net/http/meta.json +3 -1
- package/gs/net/http/pprof/index.test.ts +4 -4
- package/gs/net/http/pprof/index.ts +43 -22
- package/gs/os/file_unix_js.test.ts +22 -0
- package/gs/reflect/iter.ts +4 -2
- package/gs/reflect/map.test.ts +56 -1
- package/gs/reflect/type.ts +76 -37
- package/gs/runtime/pprof/index.test.ts +7 -1
- package/gs/runtime/pprof/index.ts +5 -1
- package/gs/runtime/runtime.test.ts +7 -0
- package/gs/runtime/runtime.ts +2 -4
- package/gs/runtime/trace/index.test.ts +9 -1
- package/gs/runtime/trace/index.ts +5 -1
- package/gs/slices/meta.json +3 -0
- package/gs/slices/slices.test.ts +59 -21
- package/gs/slices/slices.ts +61 -20
- package/gs/strconv/complex.test.ts +17 -3
- package/gs/sync/atomic/doc_64.test.ts +2 -9
- package/gs/sync/sync.test.ts +18 -8
- package/gs/syscall/js/index.test.ts +9 -4
- package/package.json +5 -4
package/gs/net/http/index.ts
CHANGED
|
@@ -4,6 +4,8 @@ import * as context from '@goscript/context/index.js'
|
|
|
4
4
|
import * as errors from '@goscript/errors/index.js'
|
|
5
5
|
import * as fs from '@goscript/io/fs/fs.js'
|
|
6
6
|
import * as io from '@goscript/io/index.js'
|
|
7
|
+
import * as mime from '@goscript/mime/index.js'
|
|
8
|
+
import * as path from '@goscript/path/index.js'
|
|
7
9
|
import * as strings from '@goscript/strings/index.js'
|
|
8
10
|
import * as time from '@goscript/time/index.js'
|
|
9
11
|
|
|
@@ -110,33 +112,55 @@ export class MaxBytesError {
|
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
export const ErrNotSupported = new ProtocolError('feature not supported')
|
|
113
|
-
export const ErrUnexpectedTrailer = new ProtocolError(
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
export const ErrUnexpectedTrailer = new ProtocolError(
|
|
116
|
+
'trailer header without chunked transfer encoding',
|
|
117
|
+
)
|
|
118
|
+
export const ErrMissingBoundary = new ProtocolError(
|
|
119
|
+
'no multipart boundary param in Content-Type',
|
|
120
|
+
)
|
|
121
|
+
export const ErrNotMultipart = new ProtocolError(
|
|
122
|
+
"request Content-Type isn't multipart/form-data",
|
|
123
|
+
)
|
|
116
124
|
export const ErrHeaderTooLong = new ProtocolError('header too long')
|
|
117
125
|
export const ErrShortBody = new ProtocolError('entity body too short')
|
|
118
|
-
export const ErrMissingContentLength = new ProtocolError(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
export const
|
|
126
|
+
export const ErrMissingContentLength = new ProtocolError(
|
|
127
|
+
'missing ContentLength in HEAD response',
|
|
128
|
+
)
|
|
129
|
+
export const ErrBodyNotAllowed = errors.New(
|
|
130
|
+
'http: request method or response status code does not allow body',
|
|
131
|
+
)
|
|
132
|
+
export const ErrBodyReadAfterClose = errors.New(
|
|
133
|
+
'http: invalid Read on closed Body',
|
|
134
|
+
)
|
|
135
|
+
export const ErrContentLength = errors.New(
|
|
136
|
+
'http: wrote more than the declared Content-Length',
|
|
137
|
+
)
|
|
122
138
|
export const ErrHandlerTimeout = errors.New('http: Handler timeout')
|
|
123
139
|
export const ErrHijacked = errors.New('http: connection has been hijacked')
|
|
124
140
|
export const ErrLineTooLong = errors.New('header line too long')
|
|
125
141
|
export const ErrMissingFile = errors.New('http: no such file')
|
|
126
142
|
export const ErrNoCookie = errors.New('http: named cookie not present')
|
|
127
143
|
export const ErrNoLocation = errors.New('http: no Location header in response')
|
|
128
|
-
export const ErrSchemeMismatch = errors.New(
|
|
144
|
+
export const ErrSchemeMismatch = errors.New(
|
|
145
|
+
'http: server gave HTTP response to HTTPS client',
|
|
146
|
+
)
|
|
129
147
|
export const ErrServerClosed = errors.New('http: Server closed')
|
|
130
148
|
export const ErrAbortHandler = errors.New('net/http: abort Handler')
|
|
131
|
-
export const ErrSkipAltProtocol = errors.New(
|
|
149
|
+
export const ErrSkipAltProtocol = errors.New(
|
|
150
|
+
'net/http: skip alternate protocol',
|
|
151
|
+
)
|
|
132
152
|
export const ErrUseLastResponse = errors.New('net/http: use last response')
|
|
133
153
|
export const ErrWriteAfterFlush = errors.New('unused')
|
|
134
154
|
const errBlankCookie = errors.New('http: blank cookie')
|
|
135
155
|
const errEqualNotFoundInCookie = errors.New("http: '=' not found in cookie")
|
|
136
156
|
const errInvalidCookieName = errors.New('http: invalid cookie name')
|
|
137
157
|
const errInvalidCookieValue = errors.New('http: invalid cookie value')
|
|
138
|
-
const errCookieNumLimitExceeded = errors.New(
|
|
139
|
-
|
|
158
|
+
const errCookieNumLimitExceeded = errors.New(
|
|
159
|
+
'http: number of cookies exceeded limit',
|
|
160
|
+
)
|
|
161
|
+
const errCrossOriginRequest = errors.New(
|
|
162
|
+
'cross-origin request detected from Sec-Fetch-Site header',
|
|
163
|
+
)
|
|
140
164
|
const errCrossOriginRequestFromOldBrowser = errors.New(
|
|
141
165
|
'cross-origin request detected, and/or browser is out of date: Sec-Fetch-Site is missing, and Origin does not match Host',
|
|
142
166
|
)
|
|
@@ -226,53 +250,73 @@ export function StatusText(code: number): string {
|
|
|
226
250
|
}
|
|
227
251
|
|
|
228
252
|
export type Header = Map<string, $.Slice<string>>
|
|
253
|
+
type HeaderBox = { __goValue: HeaderValue }
|
|
254
|
+
type HeaderValue = Header | $.VarRef<Header> | HeaderBox
|
|
229
255
|
|
|
230
256
|
export const Header = Map as {
|
|
231
|
-
new(entries?: Iterable<readonly [string, $.Slice<string>]> | null): Header
|
|
257
|
+
new (entries?: Iterable<readonly [string, $.Slice<string>]> | null): Header
|
|
232
258
|
}
|
|
233
259
|
|
|
234
260
|
export function CanonicalHeaderKey(s: string): string {
|
|
235
261
|
return canonicalMIMEHeaderKey(s)
|
|
236
262
|
}
|
|
237
263
|
|
|
238
|
-
|
|
264
|
+
function headerMap(h: HeaderValue): Header {
|
|
265
|
+
let value: unknown = $.pointerValue(h as Header | $.VarRef<Header>)
|
|
266
|
+
while (
|
|
267
|
+
value !== null &&
|
|
268
|
+
value !== undefined &&
|
|
269
|
+
typeof value === 'object' &&
|
|
270
|
+
'__goValue' in value
|
|
271
|
+
) {
|
|
272
|
+
value = $.pointerValue((value as HeaderBox).__goValue)
|
|
273
|
+
}
|
|
274
|
+
return value as Header
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export function Header_Add(h: HeaderValue, key: string, value: string): void {
|
|
278
|
+
const headers = headerMap(h)
|
|
239
279
|
key = canonicalMIMEHeaderKey(key)
|
|
240
|
-
const values = Array.from(
|
|
280
|
+
const values = Array.from(headers.get(key) ?? [])
|
|
241
281
|
values.push(value)
|
|
242
|
-
|
|
282
|
+
headers.set(key, $.arrayToSlice(values))
|
|
243
283
|
}
|
|
244
284
|
|
|
245
|
-
export function Header_Del(h:
|
|
246
|
-
h.delete(canonicalMIMEHeaderKey(key))
|
|
285
|
+
export function Header_Del(h: HeaderValue, key: string): void {
|
|
286
|
+
headerMap(h).delete(canonicalMIMEHeaderKey(key))
|
|
247
287
|
}
|
|
248
288
|
|
|
249
|
-
export function Header_Get(h:
|
|
250
|
-
const values = h.get(canonicalMIMEHeaderKey(key))
|
|
289
|
+
export function Header_Get(h: HeaderValue, key: string): string {
|
|
290
|
+
const values = headerMap(h).get(canonicalMIMEHeaderKey(key))
|
|
251
291
|
return values == null || values.length === 0 ? '' : String(values[0])
|
|
252
292
|
}
|
|
253
293
|
|
|
254
|
-
export function Header_Set(h:
|
|
255
|
-
h.set(canonicalMIMEHeaderKey(key), $.arrayToSlice([value]))
|
|
294
|
+
export function Header_Set(h: HeaderValue, key: string, value: string): void {
|
|
295
|
+
headerMap(h).set(canonicalMIMEHeaderKey(key), $.arrayToSlice([value]))
|
|
256
296
|
}
|
|
257
297
|
|
|
258
|
-
export function Header_Values(h:
|
|
259
|
-
return h.get(canonicalMIMEHeaderKey(key)) ?? null
|
|
298
|
+
export function Header_Values(h: HeaderValue, key: string): $.Slice<string> {
|
|
299
|
+
return headerMap(h).get(canonicalMIMEHeaderKey(key)) ?? null
|
|
260
300
|
}
|
|
261
301
|
|
|
262
|
-
export function Header_Clone(h:
|
|
302
|
+
export function Header_Clone(h: HeaderValue): Header {
|
|
263
303
|
const cloned = new Header()
|
|
264
|
-
for (const [key, values] of h.entries()) {
|
|
304
|
+
for (const [key, values] of headerMap(h).entries()) {
|
|
265
305
|
cloned.set(key, $.arrayToSlice(Array.from(values ?? [])))
|
|
266
306
|
}
|
|
267
307
|
return cloned
|
|
268
308
|
}
|
|
269
309
|
|
|
270
|
-
export function Header_Write(h:
|
|
310
|
+
export function Header_Write(h: HeaderValue, w: io.Writer): $.GoError {
|
|
271
311
|
return Header_WriteSubset(h, w, null)
|
|
272
312
|
}
|
|
273
313
|
|
|
274
|
-
export function Header_WriteSubset(
|
|
275
|
-
|
|
314
|
+
export function Header_WriteSubset(
|
|
315
|
+
h: HeaderValue,
|
|
316
|
+
w: io.Writer,
|
|
317
|
+
exclude: Map<string, boolean> | null,
|
|
318
|
+
): $.GoError {
|
|
319
|
+
for (const [key, values] of headerMap(h).entries()) {
|
|
276
320
|
if (exclude?.get(key) === true) {
|
|
277
321
|
continue
|
|
278
322
|
}
|
|
@@ -377,12 +421,15 @@ function parseRequestURL(rawURL: string): [RequestURL | null, $.GoError] {
|
|
|
377
421
|
}
|
|
378
422
|
const parsed = new URL(rawURL, 'http://goscript.invalid')
|
|
379
423
|
const hasHost = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(rawURL)
|
|
380
|
-
return [
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
424
|
+
return [
|
|
425
|
+
new RequestURL(
|
|
426
|
+
parsed.pathname,
|
|
427
|
+
parsed.search.startsWith('?') ? parsed.search.slice(1) : parsed.search,
|
|
428
|
+
hasHost ? parsed.protocol.replace(/:$/, '') : '',
|
|
429
|
+
hasHost ? parsed.host : '',
|
|
430
|
+
),
|
|
431
|
+
null,
|
|
432
|
+
]
|
|
386
433
|
} catch {
|
|
387
434
|
return [null, errors.New(`parse "${rawURL}": invalid URL`)]
|
|
388
435
|
}
|
|
@@ -404,6 +451,50 @@ class responseBody implements io.ReadCloser {
|
|
|
404
451
|
}
|
|
405
452
|
}
|
|
406
453
|
|
|
454
|
+
class fetchResponseBody {
|
|
455
|
+
private reader: bytes.Reader | null = null
|
|
456
|
+
private closed = false
|
|
457
|
+
|
|
458
|
+
constructor(
|
|
459
|
+
private fetched: globalThis.Response,
|
|
460
|
+
private requestContext: context.Context,
|
|
461
|
+
private abortFetch: () => void,
|
|
462
|
+
private stopContextWatch: () => void,
|
|
463
|
+
) {}
|
|
464
|
+
|
|
465
|
+
public async Read(p: $.Bytes): Promise<[number, $.GoError]> {
|
|
466
|
+
if (this.closed) {
|
|
467
|
+
return [0, ErrBodyReadAfterClose]
|
|
468
|
+
}
|
|
469
|
+
if (this.reader == null) {
|
|
470
|
+
const [data, err] = await readFetchBody(
|
|
471
|
+
this.fetched,
|
|
472
|
+
this.requestContext,
|
|
473
|
+
this.abortFetch,
|
|
474
|
+
)
|
|
475
|
+
if (err != null) {
|
|
476
|
+
this.stopContextWatch()
|
|
477
|
+
return [0, err]
|
|
478
|
+
}
|
|
479
|
+
this.stopContextWatch()
|
|
480
|
+
this.reader = bytes.NewReader(data)
|
|
481
|
+
}
|
|
482
|
+
return this.reader.Read(p)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
public Close(): $.GoError {
|
|
486
|
+
if (this.closed) {
|
|
487
|
+
return null
|
|
488
|
+
}
|
|
489
|
+
this.closed = true
|
|
490
|
+
this.stopContextWatch()
|
|
491
|
+
if (this.reader == null) {
|
|
492
|
+
this.abortFetch()
|
|
493
|
+
}
|
|
494
|
+
return null
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
407
498
|
class noBody implements io.ReadCloser {
|
|
408
499
|
public Read(_p: $.Bytes): [number, $.GoError] {
|
|
409
500
|
return [0, io.EOF]
|
|
@@ -454,7 +545,9 @@ export class Cookie {
|
|
|
454
545
|
}
|
|
455
546
|
|
|
456
547
|
public String(): string {
|
|
457
|
-
const parts = [
|
|
548
|
+
const parts = [
|
|
549
|
+
`${this.Name}=${this.Quoted ? quoteCookieValue(this.Value) : this.Value}`,
|
|
550
|
+
]
|
|
458
551
|
if (this.Path !== '') {
|
|
459
552
|
parts.push(`Path=${this.Path}`)
|
|
460
553
|
}
|
|
@@ -499,13 +592,27 @@ function isToken(value: string): boolean {
|
|
|
499
592
|
}
|
|
500
593
|
|
|
501
594
|
function validCookieValueByte(code: number): boolean {
|
|
502
|
-
return
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
595
|
+
return (
|
|
596
|
+
code >= 0x20 &&
|
|
597
|
+
code < 0x7f &&
|
|
598
|
+
code !== 0x22 &&
|
|
599
|
+
code !== 0x3b &&
|
|
600
|
+
code !== 0x5c
|
|
601
|
+
)
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function parseCookieValue(
|
|
605
|
+
raw: string,
|
|
606
|
+
allowDoubleQuote: boolean,
|
|
607
|
+
): [string, boolean, boolean] {
|
|
506
608
|
let value = raw
|
|
507
609
|
let quoted = false
|
|
508
|
-
if (
|
|
610
|
+
if (
|
|
611
|
+
allowDoubleQuote &&
|
|
612
|
+
value.length > 1 &&
|
|
613
|
+
value[0] === '"' &&
|
|
614
|
+
value[value.length - 1] === '"'
|
|
615
|
+
) {
|
|
509
616
|
value = value.slice(1, -1)
|
|
510
617
|
quoted = true
|
|
511
618
|
}
|
|
@@ -526,12 +633,15 @@ function asciiLower(value: string): [string, boolean] {
|
|
|
526
633
|
return [value.toLowerCase(), true]
|
|
527
634
|
}
|
|
528
635
|
|
|
529
|
-
export function SetCookie(
|
|
636
|
+
export async function SetCookie(
|
|
637
|
+
w: ResponseWriter | null,
|
|
638
|
+
cookie: Cookie | $.VarRef<Cookie> | null,
|
|
639
|
+
): Promise<void> {
|
|
530
640
|
const c = $.pointerValue<Cookie | null>(cookie)
|
|
531
641
|
if (w == null || c == null) {
|
|
532
642
|
return
|
|
533
643
|
}
|
|
534
|
-
Header_Add(w.Header(), 'Set-Cookie', c.String())
|
|
644
|
+
Header_Add(await w.Header(), 'Set-Cookie', c.String())
|
|
535
645
|
}
|
|
536
646
|
|
|
537
647
|
class memoryResponseWriter implements ResponseWriter {
|
|
@@ -592,7 +702,7 @@ function inProcessServerRequest(request: Request): Request {
|
|
|
592
702
|
const rawQuery = request.URL?.RawQuery ?? ''
|
|
593
703
|
const query = rawQuery === '' ? '' : `?${rawQuery}`
|
|
594
704
|
req.RequestURI = `${request.URL?.Path ?? '/'}${query}`
|
|
595
|
-
req.Host = request.Host === '' ? request.URL?.Host ?? '' : request.Host
|
|
705
|
+
req.Host = request.Host === '' ? (request.URL?.Host ?? '') : request.Host
|
|
596
706
|
if (req.URL?.clone != null) {
|
|
597
707
|
req.URL = req.URL.clone()
|
|
598
708
|
req.URL.Scheme = ''
|
|
@@ -602,9 +712,9 @@ function inProcessServerRequest(request: Request): Request {
|
|
|
602
712
|
}
|
|
603
713
|
|
|
604
714
|
export interface ResponseWriter {
|
|
605
|
-
Header(): Header
|
|
606
|
-
Write(p: $.Slice<number>): [number, $.GoError]
|
|
607
|
-
WriteHeader(statusCode: number): void
|
|
715
|
+
Header(): Header | Promise<Header>
|
|
716
|
+
Write(p: $.Slice<number>): [number, $.GoError] | Promise<[number, $.GoError]>
|
|
717
|
+
WriteHeader(statusCode: number): void | Promise<void>
|
|
608
718
|
}
|
|
609
719
|
|
|
610
720
|
export class Request {
|
|
@@ -653,7 +763,9 @@ export class Request {
|
|
|
653
763
|
this.Cancel = init?.Cancel ?? null
|
|
654
764
|
this.Response = init?.Response ?? null
|
|
655
765
|
this.Pattern = init?.Pattern ?? ''
|
|
656
|
-
this.ctx =
|
|
766
|
+
this.ctx =
|
|
767
|
+
(init as { ctx?: context.Context } | undefined)?.ctx ??
|
|
768
|
+
context.Background()
|
|
657
769
|
}
|
|
658
770
|
|
|
659
771
|
public Context(): context.Context {
|
|
@@ -667,7 +779,10 @@ export class Request {
|
|
|
667
779
|
public Clone(ctx: context.Context): Request {
|
|
668
780
|
return new Request({
|
|
669
781
|
Method: this.Method,
|
|
670
|
-
URL:
|
|
782
|
+
URL:
|
|
783
|
+
this.URL?.clone != null ? this.URL.clone()
|
|
784
|
+
: this.URL == null ? null
|
|
785
|
+
: { ...this.URL },
|
|
671
786
|
Proto: this.Proto,
|
|
672
787
|
ProtoMajor: this.ProtoMajor,
|
|
673
788
|
ProtoMinor: this.ProtoMinor,
|
|
@@ -700,7 +815,10 @@ export class Request {
|
|
|
700
815
|
}
|
|
701
816
|
|
|
702
817
|
public ProtoAtLeast(major: number, minor: number): boolean {
|
|
703
|
-
return
|
|
818
|
+
return (
|
|
819
|
+
this.ProtoMajor > major ||
|
|
820
|
+
(this.ProtoMajor === major && this.ProtoMinor >= minor)
|
|
821
|
+
)
|
|
704
822
|
}
|
|
705
823
|
|
|
706
824
|
public Cookie(name: string): [Cookie | null, $.GoError] {
|
|
@@ -785,7 +903,8 @@ export class Response {
|
|
|
785
903
|
this.TLS = init?.TLS ?? null
|
|
786
904
|
if (this.Status === '' && this.StatusCode !== 0) {
|
|
787
905
|
const text = StatusText(this.StatusCode)
|
|
788
|
-
this.Status =
|
|
906
|
+
this.Status =
|
|
907
|
+
text === '' ? String(this.StatusCode) : `${this.StatusCode} ${text}`
|
|
789
908
|
}
|
|
790
909
|
}
|
|
791
910
|
|
|
@@ -836,7 +955,10 @@ export class Response {
|
|
|
836
955
|
}
|
|
837
956
|
|
|
838
957
|
public ProtoAtLeast(major: number, minor: number): boolean {
|
|
839
|
-
return
|
|
958
|
+
return (
|
|
959
|
+
this.ProtoMajor > major ||
|
|
960
|
+
(this.ProtoMajor === major && this.ProtoMinor >= minor)
|
|
961
|
+
)
|
|
840
962
|
}
|
|
841
963
|
|
|
842
964
|
public Write(w: io.Writer): $.GoError {
|
|
@@ -910,7 +1032,11 @@ export class Client {
|
|
|
910
1032
|
return await this.Do(req)
|
|
911
1033
|
}
|
|
912
1034
|
|
|
913
|
-
public async Post(
|
|
1035
|
+
public async Post(
|
|
1036
|
+
url: string,
|
|
1037
|
+
contentType: string,
|
|
1038
|
+
body: io.Reader | null,
|
|
1039
|
+
): Promise<[Response | null, $.GoError]> {
|
|
914
1040
|
const [req, err] = NewRequest(MethodPost, url, body)
|
|
915
1041
|
if (err != null || req == null) {
|
|
916
1042
|
return [null, err]
|
|
@@ -919,12 +1045,21 @@ export class Client {
|
|
|
919
1045
|
return await this.Do(req)
|
|
920
1046
|
}
|
|
921
1047
|
|
|
922
|
-
public async PostForm(
|
|
923
|
-
|
|
1048
|
+
public async PostForm(
|
|
1049
|
+
url: string,
|
|
1050
|
+
data: any,
|
|
1051
|
+
): Promise<[Response | null, $.GoError]> {
|
|
1052
|
+
return await this.Post(
|
|
1053
|
+
url,
|
|
1054
|
+
'application/x-www-form-urlencoded',
|
|
1055
|
+
bytes.NewReader($.stringToBytes(encodeFormData(data))),
|
|
1056
|
+
)
|
|
924
1057
|
}
|
|
925
1058
|
|
|
926
1059
|
public CloseIdleConnections(): void {
|
|
927
|
-
const closer = this.Transport as {
|
|
1060
|
+
const closer = this.Transport as {
|
|
1061
|
+
CloseIdleConnections?: () => void
|
|
1062
|
+
} | null
|
|
928
1063
|
closer?.CloseIdleConnections?.()
|
|
929
1064
|
}
|
|
930
1065
|
}
|
|
@@ -944,10 +1079,8 @@ function encodeFormData(data: any): string {
|
|
|
944
1079
|
return data.toString()
|
|
945
1080
|
}
|
|
946
1081
|
const entries =
|
|
947
|
-
data instanceof Map ?
|
|
948
|
-
|
|
949
|
-
: typeof data === 'object' ?
|
|
950
|
-
Object.entries(data)
|
|
1082
|
+
data instanceof Map ? Array.from(data.entries())
|
|
1083
|
+
: typeof data === 'object' ? Object.entries(data)
|
|
951
1084
|
: []
|
|
952
1085
|
entries.sort(([a], [b]) => String(a).localeCompare(String(b)))
|
|
953
1086
|
const params = new URLSearchParams()
|
|
@@ -957,7 +1090,11 @@ function encodeFormData(data: any): string {
|
|
|
957
1090
|
return params.toString()
|
|
958
1091
|
}
|
|
959
1092
|
|
|
960
|
-
function appendFormValue(
|
|
1093
|
+
function appendFormValue(
|
|
1094
|
+
params: URLSearchParams,
|
|
1095
|
+
key: string,
|
|
1096
|
+
value: unknown,
|
|
1097
|
+
): void {
|
|
961
1098
|
const unwrapped = unwrapFormValue(value)
|
|
962
1099
|
if (unwrapped == null) {
|
|
963
1100
|
return
|
|
@@ -982,7 +1119,9 @@ function unwrapFormValue(value: unknown): unknown {
|
|
|
982
1119
|
}
|
|
983
1120
|
|
|
984
1121
|
export interface RoundTripper {
|
|
985
|
-
RoundTrip(
|
|
1122
|
+
RoundTrip(
|
|
1123
|
+
req: Request | $.VarRef<Request> | null,
|
|
1124
|
+
): [Response | null, $.GoError] | Promise<[Response | null, $.GoError]>
|
|
986
1125
|
}
|
|
987
1126
|
|
|
988
1127
|
export class Protocols {
|
|
@@ -1051,8 +1190,17 @@ export class HTTP2Config {
|
|
|
1051
1190
|
}
|
|
1052
1191
|
|
|
1053
1192
|
export class Transport implements RoundTripper {
|
|
1054
|
-
public Proxy:
|
|
1055
|
-
|
|
1193
|
+
public Proxy:
|
|
1194
|
+
| ((req: Request | $.VarRef<Request> | null) => [any, $.GoError])
|
|
1195
|
+
| null = null
|
|
1196
|
+
public OnProxyConnectResponse:
|
|
1197
|
+
| ((
|
|
1198
|
+
ctx: context.Context,
|
|
1199
|
+
proxyURL: any,
|
|
1200
|
+
connectReq: Request,
|
|
1201
|
+
connectRes: Response,
|
|
1202
|
+
) => $.GoError)
|
|
1203
|
+
| null = null
|
|
1056
1204
|
public DialContext: any = null
|
|
1057
1205
|
public Dial: any = null
|
|
1058
1206
|
public DialTLSContext: any = null
|
|
@@ -1069,7 +1217,13 @@ export class Transport implements RoundTripper {
|
|
|
1069
1217
|
public ExpectContinueTimeout = 0
|
|
1070
1218
|
public TLSNextProto: Map<string, any> | null = null
|
|
1071
1219
|
public ProxyConnectHeader = new Header()
|
|
1072
|
-
public GetProxyConnectHeader:
|
|
1220
|
+
public GetProxyConnectHeader:
|
|
1221
|
+
| ((
|
|
1222
|
+
ctx: context.Context,
|
|
1223
|
+
proxyURL: any,
|
|
1224
|
+
target: string,
|
|
1225
|
+
) => [Header | null, $.GoError])
|
|
1226
|
+
| null = null
|
|
1073
1227
|
public MaxResponseHeaderBytes = 0
|
|
1074
1228
|
public WriteBufferSize = 0
|
|
1075
1229
|
public ReadBufferSize = 0
|
|
@@ -1081,7 +1235,9 @@ export class Transport implements RoundTripper {
|
|
|
1081
1235
|
Object.assign(this, init)
|
|
1082
1236
|
}
|
|
1083
1237
|
|
|
1084
|
-
public async RoundTrip(
|
|
1238
|
+
public async RoundTrip(
|
|
1239
|
+
req: Request | $.VarRef<Request> | null,
|
|
1240
|
+
): Promise<[Response | null, $.GoError]> {
|
|
1085
1241
|
const request = $.pointerValue<Request | null>(req)
|
|
1086
1242
|
if (request == null) {
|
|
1087
1243
|
return [null, errors.New('net/http: nil Request')]
|
|
@@ -1094,7 +1250,10 @@ export class Transport implements RoundTripper {
|
|
|
1094
1250
|
const recorder = new memoryResponseWriter()
|
|
1095
1251
|
let closeErr: $.GoError | undefined
|
|
1096
1252
|
try {
|
|
1097
|
-
const served = handler.ServeHTTP(
|
|
1253
|
+
const served = handler.ServeHTTP(
|
|
1254
|
+
recorder,
|
|
1255
|
+
inProcessServerRequest(request),
|
|
1256
|
+
)
|
|
1098
1257
|
if (served instanceof Promise) {
|
|
1099
1258
|
await served
|
|
1100
1259
|
}
|
|
@@ -1117,7 +1276,11 @@ export class Transport implements RoundTripper {
|
|
|
1117
1276
|
|
|
1118
1277
|
public RegisterProtocol(_scheme: string, _rt: RoundTripper): void {}
|
|
1119
1278
|
|
|
1120
|
-
public NewClientConn(
|
|
1279
|
+
public NewClientConn(
|
|
1280
|
+
_ctx: context.Context,
|
|
1281
|
+
_scheme: string,
|
|
1282
|
+
_address: string,
|
|
1283
|
+
): [ClientConn | null, $.GoError] {
|
|
1121
1284
|
return [null, ErrNotSupported]
|
|
1122
1285
|
}
|
|
1123
1286
|
|
|
@@ -1131,7 +1294,9 @@ export const DefaultTransport: RoundTripper = new Transport()
|
|
|
1131
1294
|
class fileTransport implements RoundTripper {
|
|
1132
1295
|
constructor(private root: FileSystem | null) {}
|
|
1133
1296
|
|
|
1134
|
-
public async RoundTrip(
|
|
1297
|
+
public async RoundTrip(
|
|
1298
|
+
req: Request | $.VarRef<Request> | null,
|
|
1299
|
+
): Promise<[Response | null, $.GoError]> {
|
|
1135
1300
|
const request = $.pointerValue<Request | null>(req)
|
|
1136
1301
|
const recorder = new memoryResponseWriter()
|
|
1137
1302
|
let closeErr: $.GoError | undefined
|
|
@@ -1155,7 +1320,9 @@ export function NewFileTransportFS(fsys: fs.FS): RoundTripper {
|
|
|
1155
1320
|
return NewFileTransport(FS(fsys))
|
|
1156
1321
|
}
|
|
1157
1322
|
|
|
1158
|
-
async function fetchRoundTrip(
|
|
1323
|
+
async function fetchRoundTrip(
|
|
1324
|
+
request: Request,
|
|
1325
|
+
): Promise<[Response | null, $.GoError]> {
|
|
1159
1326
|
const requestBody = request.Body
|
|
1160
1327
|
const closeRequestBody = (): $.GoError => {
|
|
1161
1328
|
if (requestBody == null) {
|
|
@@ -1165,7 +1332,10 @@ async function fetchRoundTrip(request: Request): Promise<[Response | null, $.GoE
|
|
|
1165
1332
|
}
|
|
1166
1333
|
if (typeof globalThis.fetch !== 'function') {
|
|
1167
1334
|
closeRequestBody()
|
|
1168
|
-
return [
|
|
1335
|
+
return [
|
|
1336
|
+
null,
|
|
1337
|
+
errors.New('net/http: Client.Do is not implemented in GoScript'),
|
|
1338
|
+
]
|
|
1169
1339
|
}
|
|
1170
1340
|
const ctxErr = request.Context()?.Err?.()
|
|
1171
1341
|
if (ctxErr != null) {
|
|
@@ -1179,7 +1349,11 @@ async function fetchRoundTrip(request: Request): Promise<[Response | null, $.GoE
|
|
|
1179
1349
|
}
|
|
1180
1350
|
}
|
|
1181
1351
|
let body: Uint8Array | undefined
|
|
1182
|
-
if (
|
|
1352
|
+
if (
|
|
1353
|
+
requestBody != null &&
|
|
1354
|
+
request.Method !== MethodGet &&
|
|
1355
|
+
request.Method !== MethodHead
|
|
1356
|
+
) {
|
|
1183
1357
|
const [data, err] = await io.ReadAll(requestBody)
|
|
1184
1358
|
const closeErr = closeRequestBody()
|
|
1185
1359
|
if (err != null) {
|
|
@@ -1195,21 +1369,40 @@ async function fetchRoundTrip(request: Request): Promise<[Response | null, $.GoE
|
|
|
1195
1369
|
return [null, closeErr]
|
|
1196
1370
|
}
|
|
1197
1371
|
}
|
|
1372
|
+
const fetchContext = newFetchContext(request.Context())
|
|
1198
1373
|
try {
|
|
1199
1374
|
const bodyInit = body == null ? undefined : Uint8Array.from(body).buffer
|
|
1200
|
-
const fetched = await
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1375
|
+
const [fetched, fetchErr] = await fetchContext.wait(
|
|
1376
|
+
globalThis.fetch(request.URL?.String?.() ?? '', {
|
|
1377
|
+
method: request.Method || MethodGet,
|
|
1378
|
+
headers,
|
|
1379
|
+
body: bodyInit,
|
|
1380
|
+
signal: fetchContext.signal,
|
|
1381
|
+
}),
|
|
1382
|
+
)
|
|
1383
|
+
if (fetchErr != null || fetched == null) {
|
|
1384
|
+
fetchContext.stop()
|
|
1385
|
+
return [null, fetchErr]
|
|
1386
|
+
}
|
|
1206
1387
|
const respHeader = new Header()
|
|
1207
1388
|
fetched.headers.forEach((value, key) => Header_Add(respHeader, key, value))
|
|
1389
|
+
const responseBody: io.ReadCloser =
|
|
1390
|
+
request.Method === MethodHead ?
|
|
1391
|
+
NoBody
|
|
1392
|
+
: (new fetchResponseBody(
|
|
1393
|
+
fetched,
|
|
1394
|
+
request.Context(),
|
|
1395
|
+
fetchContext.abort,
|
|
1396
|
+
fetchContext.stop,
|
|
1397
|
+
) as unknown as io.ReadCloser)
|
|
1398
|
+
if (request.Method === MethodHead) {
|
|
1399
|
+
fetchContext.stop()
|
|
1400
|
+
}
|
|
1208
1401
|
return [
|
|
1209
1402
|
new Response({
|
|
1210
1403
|
Status: `${fetched.status} ${fetched.statusText}`,
|
|
1211
1404
|
StatusCode: fetched.status,
|
|
1212
|
-
Body:
|
|
1405
|
+
Body: responseBody,
|
|
1213
1406
|
Header: respHeader,
|
|
1214
1407
|
ContentLength: Number(fetched.headers.get('content-length') ?? -1),
|
|
1215
1408
|
Request: request,
|
|
@@ -1217,27 +1410,130 @@ async function fetchRoundTrip(request: Request): Promise<[Response | null, $.GoE
|
|
|
1217
1410
|
null,
|
|
1218
1411
|
]
|
|
1219
1412
|
} catch (err) {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1413
|
+
fetchContext.stop()
|
|
1414
|
+
return [null, errorFromUnknown(err)]
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function newFetchContext(requestContext: context.Context): {
|
|
1419
|
+
signal: AbortSignal | undefined
|
|
1420
|
+
abort: () => void
|
|
1421
|
+
stop: () => void
|
|
1422
|
+
wait: <T>(promise: Promise<T>) => Promise<[T | null, $.GoError]>
|
|
1423
|
+
} {
|
|
1424
|
+
let stopped = false
|
|
1425
|
+
const watchController =
|
|
1426
|
+
typeof AbortController === 'undefined' ? null : new AbortController()
|
|
1427
|
+
const controller =
|
|
1428
|
+
typeof AbortController === 'undefined' ? null : new AbortController()
|
|
1429
|
+
const abort = () => {
|
|
1430
|
+
if (controller != null && !controller.signal.aborted) {
|
|
1431
|
+
controller.abort(requestContext?.Err?.() ?? context.Canceled)
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
const donePromise =
|
|
1435
|
+
requestContext == null ? null : (
|
|
1436
|
+
(async (): Promise<$.GoError> => {
|
|
1437
|
+
try {
|
|
1438
|
+
await requestContext.Done().selectReceive(0, watchController?.signal)
|
|
1439
|
+
} catch {
|
|
1440
|
+
// Closed channels and receive wakeups both mean the context is done.
|
|
1441
|
+
}
|
|
1442
|
+
const err = requestContext.Err() ?? context.Canceled
|
|
1443
|
+
if (!stopped) {
|
|
1444
|
+
abort()
|
|
1445
|
+
}
|
|
1446
|
+
return err
|
|
1447
|
+
})()
|
|
1448
|
+
)
|
|
1449
|
+
return {
|
|
1450
|
+
signal: controller?.signal,
|
|
1451
|
+
abort,
|
|
1452
|
+
stop: () => {
|
|
1453
|
+
stopped = true
|
|
1454
|
+
watchController?.abort()
|
|
1455
|
+
},
|
|
1456
|
+
wait: async <T>(promise: Promise<T>): Promise<[T | null, $.GoError]> => {
|
|
1457
|
+
const settle = promise.then(
|
|
1458
|
+
(value) => ({ value }),
|
|
1459
|
+
(thrown) => ({ thrown }),
|
|
1460
|
+
)
|
|
1461
|
+
if (donePromise == null) {
|
|
1462
|
+
const result = await settle
|
|
1463
|
+
if ('thrown' in result) {
|
|
1464
|
+
return [null, errorFromUnknown(result.thrown)]
|
|
1465
|
+
}
|
|
1466
|
+
return [result.value, null]
|
|
1467
|
+
}
|
|
1468
|
+
const result = await Promise.race<
|
|
1469
|
+
{ value: T } | { err: $.GoError } | { thrown: unknown }
|
|
1470
|
+
>([settle, donePromise.then((err) => ({ err }))])
|
|
1471
|
+
if ('err' in result) {
|
|
1472
|
+
abort()
|
|
1473
|
+
return [null, result.err]
|
|
1474
|
+
}
|
|
1475
|
+
if ('thrown' in result) {
|
|
1476
|
+
return [
|
|
1477
|
+
null,
|
|
1478
|
+
requestContext?.Err?.() ?? errorFromUnknown(result.thrown),
|
|
1479
|
+
]
|
|
1480
|
+
}
|
|
1481
|
+
return [result.value, null]
|
|
1482
|
+
},
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
function errorFromUnknown(err: unknown): $.GoError {
|
|
1487
|
+
const message =
|
|
1488
|
+
typeof err === 'object' && err != null && 'message' in err ?
|
|
1489
|
+
String((err as { message: unknown }).message)
|
|
1490
|
+
: String(err)
|
|
1491
|
+
return errors.New(message)
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
async function readFetchBody(
|
|
1495
|
+
fetched: globalThis.Response,
|
|
1496
|
+
requestContext: context.Context,
|
|
1497
|
+
abortFetch: () => void,
|
|
1498
|
+
): Promise<[Uint8Array, $.GoError]> {
|
|
1499
|
+
const fetchContext = newFetchContext(requestContext)
|
|
1500
|
+
const [buffer, err] = await fetchContext.wait(fetched.arrayBuffer())
|
|
1501
|
+
fetchContext.stop()
|
|
1502
|
+
if (err != null) {
|
|
1503
|
+
abortFetch()
|
|
1504
|
+
return [new Uint8Array(), err]
|
|
1224
1505
|
}
|
|
1506
|
+
return [new Uint8Array(buffer ?? new ArrayBuffer(0)), null]
|
|
1225
1507
|
}
|
|
1226
1508
|
|
|
1509
|
+
type maybePromise<T> = T | Promise<T>
|
|
1510
|
+
|
|
1227
1511
|
export interface FileSystem {
|
|
1228
|
-
Open(name: string): [File | null, $.GoError]
|
|
1512
|
+
Open(name: string): maybePromise<[File | null, $.GoError]>
|
|
1229
1513
|
}
|
|
1230
1514
|
|
|
1231
1515
|
export interface File extends io.Closer, io.Reader, io.Seeker {
|
|
1232
|
-
Readdir(count: number): [$.Slice<fs.FileInfo
|
|
1233
|
-
Stat(): [fs.FileInfo, $.GoError]
|
|
1516
|
+
Readdir(count: number): [$.Slice<fs.FileInfo> | null, $.GoError]
|
|
1517
|
+
Stat(): [fs.FileInfo | null, $.GoError]
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
interface fileServerFileSystem {
|
|
1521
|
+
Open(name: string): maybePromise<[fileServerFile | null, $.GoError]>
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
interface fileServerFile {
|
|
1525
|
+
Close(): maybePromise<$.GoError>
|
|
1526
|
+
Read(p: $.Bytes): maybePromise<[number, $.GoError]>
|
|
1527
|
+
Seek(offset: number, whence: number): maybePromise<[number, $.GoError]>
|
|
1528
|
+
Readdir(count: number): maybePromise<[$.Slice<fs.FileInfo> | null, $.GoError]>
|
|
1529
|
+
Stat(): maybePromise<[fs.FileInfo | null, $.GoError]>
|
|
1234
1530
|
}
|
|
1235
1531
|
|
|
1236
1532
|
export function FS(fsys: fs.FS): FileSystem {
|
|
1237
1533
|
return {
|
|
1238
|
-
Open(name: string): [File | null, $.GoError] {
|
|
1534
|
+
async Open(name: string): Promise<[File | null, $.GoError]> {
|
|
1239
1535
|
const cleaned = cleanFileServerPath(name)
|
|
1240
|
-
const [file, err] = fsys?.Open(cleaned) ?? [null, fs.ErrInvalid]
|
|
1536
|
+
const [file, err] = (await fsys?.Open(cleaned)) ?? [null, fs.ErrInvalid]
|
|
1241
1537
|
if (err != null || file == null) {
|
|
1242
1538
|
return [null, err]
|
|
1243
1539
|
}
|
|
@@ -1248,17 +1544,23 @@ export function FS(fsys: fs.FS): FileSystem {
|
|
|
1248
1544
|
|
|
1249
1545
|
function httpFileFromFSFile(file: Exclude<fs.File, null>): File {
|
|
1250
1546
|
const seek = (file as Partial<io.Seeker>).Seek
|
|
1251
|
-
const readdir = (
|
|
1547
|
+
const readdir = (
|
|
1548
|
+
file as { Readdir?: (count: number) => [$.Slice<fs.FileInfo>, $.GoError] }
|
|
1549
|
+
).Readdir
|
|
1252
1550
|
return {
|
|
1253
|
-
Read: (p) =>
|
|
1551
|
+
Read: (p) =>
|
|
1552
|
+
file.Read(p instanceof Uint8Array ? p : Uint8Array.from(p ?? [])),
|
|
1254
1553
|
Close: () => file.Close(),
|
|
1255
1554
|
Stat: () => file.Stat(),
|
|
1256
|
-
Seek:
|
|
1555
|
+
Seek:
|
|
1556
|
+
seek == null ?
|
|
1557
|
+
() => [0, errors.New('net/http: file does not support seek')]
|
|
1558
|
+
: seek.bind(file),
|
|
1257
1559
|
Readdir: readdir == null ? () => [null, io.EOF] : readdir.bind(file),
|
|
1258
1560
|
}
|
|
1259
1561
|
}
|
|
1260
1562
|
|
|
1261
|
-
export function FileServer(root:
|
|
1563
|
+
export function FileServer(root: fileServerFileSystem | null): Handler {
|
|
1262
1564
|
return {
|
|
1263
1565
|
async ServeHTTP(w, r): Promise<void> {
|
|
1264
1566
|
const req = $.pointerValue<Request | null>(r)
|
|
@@ -1269,13 +1571,15 @@ export function FileServer(root: FileSystem | null): Handler {
|
|
|
1269
1571
|
Error(w, 'method not allowed', StatusMethodNotAllowed)
|
|
1270
1572
|
return
|
|
1271
1573
|
}
|
|
1272
|
-
const [file, err] = root?.Open(
|
|
1574
|
+
const [file, err] = (await root?.Open(
|
|
1575
|
+
cleanFileServerPath(req.URL?.Path ?? ''),
|
|
1576
|
+
)) ?? [null, fs.ErrInvalid]
|
|
1273
1577
|
if (err != null || file == null) {
|
|
1274
1578
|
NotFound(w, req)
|
|
1275
1579
|
return
|
|
1276
1580
|
}
|
|
1277
1581
|
try {
|
|
1278
|
-
const [info, statErr] = file.Stat()
|
|
1582
|
+
const [info, statErr] = await file.Stat()
|
|
1279
1583
|
if (statErr != null) {
|
|
1280
1584
|
Error(w, statErr.Error(), StatusInternalServerError)
|
|
1281
1585
|
return
|
|
@@ -1284,20 +1588,30 @@ export function FileServer(root: FileSystem | null): Handler {
|
|
|
1284
1588
|
NotFound(w, req)
|
|
1285
1589
|
return
|
|
1286
1590
|
}
|
|
1287
|
-
const
|
|
1288
|
-
if (
|
|
1289
|
-
|
|
1290
|
-
|
|
1591
|
+
const header = await w.Header()
|
|
1592
|
+
if (Header_Get(header, 'Content-Type') === '') {
|
|
1593
|
+
const contentType = mime.TypeByExtension(
|
|
1594
|
+
path.Ext(info?.Name?.() || req.URL?.Path || ''),
|
|
1595
|
+
)
|
|
1596
|
+
if (contentType !== '') {
|
|
1597
|
+
Header_Set(header, 'Content-Type', contentType)
|
|
1598
|
+
}
|
|
1291
1599
|
}
|
|
1292
1600
|
if (info?.Size != null) {
|
|
1293
|
-
Header_Set(
|
|
1601
|
+
Header_Set(header, 'Content-Length', String(info.Size()))
|
|
1294
1602
|
}
|
|
1295
|
-
w.WriteHeader(StatusOK)
|
|
1603
|
+
await w.WriteHeader(StatusOK)
|
|
1296
1604
|
if (req.Method !== MethodHead) {
|
|
1297
|
-
|
|
1605
|
+
const [, copyErr] = await io.Copy(
|
|
1606
|
+
w as unknown as io.Writer,
|
|
1607
|
+
file as io.Reader,
|
|
1608
|
+
)
|
|
1609
|
+
if (copyErr != null) {
|
|
1610
|
+
return
|
|
1611
|
+
}
|
|
1298
1612
|
}
|
|
1299
1613
|
} finally {
|
|
1300
|
-
file.Close()
|
|
1614
|
+
await file.Close()
|
|
1301
1615
|
}
|
|
1302
1616
|
},
|
|
1303
1617
|
}
|
|
@@ -1348,8 +1662,25 @@ function cleanFileServerPath(name: string): string {
|
|
|
1348
1662
|
}
|
|
1349
1663
|
|
|
1350
1664
|
export interface Handler {
|
|
1351
|
-
ServeHTTP(
|
|
1352
|
-
|
|
1665
|
+
ServeHTTP(
|
|
1666
|
+
w: ResponseWriter | null,
|
|
1667
|
+
r: Request | $.VarRef<Request> | null,
|
|
1668
|
+
): void | Promise<void>
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
$.registerInterfaceType('http.Handler', null, [
|
|
1672
|
+
{
|
|
1673
|
+
name: 'ServeHTTP',
|
|
1674
|
+
args: [
|
|
1675
|
+
{ name: 'w', type: 'http.ResponseWriter' },
|
|
1676
|
+
{
|
|
1677
|
+
name: 'r',
|
|
1678
|
+
type: { kind: $.TypeKind.Pointer, elemType: 'http.Request' },
|
|
1679
|
+
},
|
|
1680
|
+
],
|
|
1681
|
+
returns: [],
|
|
1682
|
+
},
|
|
1683
|
+
])
|
|
1353
1684
|
|
|
1354
1685
|
export type HandlerFunc = (
|
|
1355
1686
|
w: ResponseWriter | null,
|
|
@@ -1357,10 +1688,13 @@ export type HandlerFunc = (
|
|
|
1357
1688
|
) => void | Promise<void>
|
|
1358
1689
|
|
|
1359
1690
|
export function HandlerFunc_ServeHTTP(
|
|
1360
|
-
h: HandlerFunc,
|
|
1691
|
+
h: HandlerFunc | null,
|
|
1361
1692
|
w: ResponseWriter | null,
|
|
1362
1693
|
r: Request | $.VarRef<Request> | null,
|
|
1363
1694
|
): void | Promise<void> {
|
|
1695
|
+
if (!h) {
|
|
1696
|
+
throw new globalThis.Error('http: nil HandlerFunc')
|
|
1697
|
+
}
|
|
1364
1698
|
return h(w, r)
|
|
1365
1699
|
}
|
|
1366
1700
|
|
|
@@ -1512,7 +1846,9 @@ function wildcardPatternMatches(pattern: string, path: string): boolean {
|
|
|
1512
1846
|
export class Server {
|
|
1513
1847
|
public Addr: string
|
|
1514
1848
|
public BaseContext: ((listener: any) => context.Context) | null
|
|
1515
|
-
public ConnContext:
|
|
1849
|
+
public ConnContext:
|
|
1850
|
+
| ((ctx: context.Context, conn: any) => context.Context)
|
|
1851
|
+
| null
|
|
1516
1852
|
public Handler: Handler | null
|
|
1517
1853
|
public DisableGeneralOptionsHandler: boolean
|
|
1518
1854
|
public TLSConfig: any
|
|
@@ -1533,7 +1869,8 @@ export class Server {
|
|
|
1533
1869
|
this.BaseContext = init?.BaseContext ?? null
|
|
1534
1870
|
this.ConnContext = init?.ConnContext ?? null
|
|
1535
1871
|
this.Handler = init?.Handler ?? null
|
|
1536
|
-
this.DisableGeneralOptionsHandler =
|
|
1872
|
+
this.DisableGeneralOptionsHandler =
|
|
1873
|
+
init?.DisableGeneralOptionsHandler ?? false
|
|
1537
1874
|
this.TLSConfig = init?.TLSConfig ?? null
|
|
1538
1875
|
this.ReadTimeout = init?.ReadTimeout ?? 0
|
|
1539
1876
|
this.ReadTimeoutHandler = (init as any)?.ReadTimeoutHandler ?? null
|
|
@@ -1549,11 +1886,15 @@ export class Server {
|
|
|
1549
1886
|
}
|
|
1550
1887
|
|
|
1551
1888
|
public ListenAndServe(): $.GoError {
|
|
1552
|
-
return errors.New(
|
|
1889
|
+
return errors.New(
|
|
1890
|
+
'net/http: Server.ListenAndServe is not implemented in GoScript',
|
|
1891
|
+
)
|
|
1553
1892
|
}
|
|
1554
1893
|
|
|
1555
1894
|
public ListenAndServeTLS(_certFile: string, _keyFile: string): $.GoError {
|
|
1556
|
-
return errors.New(
|
|
1895
|
+
return errors.New(
|
|
1896
|
+
'net/http: Server.ListenAndServeTLS is not implemented in GoScript',
|
|
1897
|
+
)
|
|
1557
1898
|
}
|
|
1558
1899
|
|
|
1559
1900
|
public Close(): $.GoError {
|
|
@@ -1568,11 +1909,18 @@ export class Server {
|
|
|
1568
1909
|
return ErrNotSupported
|
|
1569
1910
|
}
|
|
1570
1911
|
|
|
1571
|
-
public ServeTLS(
|
|
1912
|
+
public ServeTLS(
|
|
1913
|
+
_listener: any,
|
|
1914
|
+
_certFile: string,
|
|
1915
|
+
_keyFile: string,
|
|
1916
|
+
): $.GoError {
|
|
1572
1917
|
return ErrNotSupported
|
|
1573
1918
|
}
|
|
1574
1919
|
|
|
1575
|
-
public ServeHTTP(
|
|
1920
|
+
public ServeHTTP(
|
|
1921
|
+
w: ResponseWriter | null,
|
|
1922
|
+
r: Request | $.VarRef<Request> | null,
|
|
1923
|
+
): void | Promise<void> {
|
|
1576
1924
|
return (this.Handler ?? DefaultServeMux).ServeHTTP(w, r)
|
|
1577
1925
|
}
|
|
1578
1926
|
|
|
@@ -1581,7 +1929,10 @@ export class Server {
|
|
|
1581
1929
|
public SetKeepAlivesEnabled(_v: boolean): void {}
|
|
1582
1930
|
}
|
|
1583
1931
|
|
|
1584
|
-
export function ListenAndServe(
|
|
1932
|
+
export function ListenAndServe(
|
|
1933
|
+
_addr: string,
|
|
1934
|
+
_handler: Handler | null,
|
|
1935
|
+
): $.GoError {
|
|
1585
1936
|
return ErrNotSupported
|
|
1586
1937
|
}
|
|
1587
1938
|
|
|
@@ -1624,7 +1975,10 @@ export interface Hijacker {
|
|
|
1624
1975
|
}
|
|
1625
1976
|
|
|
1626
1977
|
export interface Pusher {
|
|
1627
|
-
Push(
|
|
1978
|
+
Push(
|
|
1979
|
+
target: string,
|
|
1980
|
+
opts: PushOptions | $.VarRef<PushOptions> | null,
|
|
1981
|
+
): $.GoError
|
|
1628
1982
|
}
|
|
1629
1983
|
|
|
1630
1984
|
export class ResponseController {
|
|
@@ -1657,7 +2011,9 @@ export class ResponseController {
|
|
|
1657
2011
|
}
|
|
1658
2012
|
}
|
|
1659
2013
|
|
|
1660
|
-
export function NewResponseController(
|
|
2014
|
+
export function NewResponseController(
|
|
2015
|
+
rw: ResponseWriter | null,
|
|
2016
|
+
): ResponseController {
|
|
1661
2017
|
return new ResponseController(rw)
|
|
1662
2018
|
}
|
|
1663
2019
|
|
|
@@ -1666,7 +2022,10 @@ class maxBytesReader implements io.ReadCloser {
|
|
|
1666
2022
|
private remaining: number
|
|
1667
2023
|
private err: $.GoError = null
|
|
1668
2024
|
|
|
1669
|
-
constructor(
|
|
2025
|
+
constructor(
|
|
2026
|
+
private reader: io.ReadCloser,
|
|
2027
|
+
limit: number,
|
|
2028
|
+
) {
|
|
1670
2029
|
this.initialLimit = Math.max(0, limit)
|
|
1671
2030
|
this.remaining = this.initialLimit
|
|
1672
2031
|
}
|
|
@@ -1719,14 +2078,19 @@ export class ServeMux implements Handler {
|
|
|
1719
2078
|
this.Handle(pattern, { ServeHTTP: handler })
|
|
1720
2079
|
}
|
|
1721
2080
|
|
|
1722
|
-
public Handler(
|
|
2081
|
+
public Handler(
|
|
2082
|
+
r: Request | $.VarRef<Request> | null,
|
|
2083
|
+
): [Handler | null, string] {
|
|
1723
2084
|
const req = $.pointerValue<Request | null>(r)
|
|
1724
2085
|
const path = req?.URL?.Path ?? ''
|
|
1725
2086
|
const handler = this.handlers.get(path) ?? null
|
|
1726
2087
|
return [handler, handler == null ? '' : path]
|
|
1727
2088
|
}
|
|
1728
2089
|
|
|
1729
|
-
public ServeHTTP(
|
|
2090
|
+
public ServeHTTP(
|
|
2091
|
+
w: ResponseWriter | null,
|
|
2092
|
+
r: Request | $.VarRef<Request> | null,
|
|
2093
|
+
): void | Promise<void> {
|
|
1730
2094
|
const [handler] = this.Handler(r)
|
|
1731
2095
|
if (handler == null) {
|
|
1732
2096
|
NotFound(w, r)
|
|
@@ -1754,7 +2118,11 @@ export function StripPrefix(prefix: string, handler: Handler | null): Handler {
|
|
|
1754
2118
|
return {
|
|
1755
2119
|
ServeHTTP(w, r) {
|
|
1756
2120
|
const req = $.pointerValue<Request | null>(r)
|
|
1757
|
-
if (
|
|
2121
|
+
if (
|
|
2122
|
+
req?.URL != null &&
|
|
2123
|
+
typeof req.URL.Path === 'string' &&
|
|
2124
|
+
req.URL.Path.startsWith(prefix)
|
|
2125
|
+
) {
|
|
1758
2126
|
req.URL = { ...req.URL, Path: req.URL.Path.slice(prefix.length) || '/' }
|
|
1759
2127
|
}
|
|
1760
2128
|
return handler?.ServeHTTP(w, req)
|
|
@@ -1791,12 +2159,16 @@ export function NotFoundHandler(): Handler {
|
|
|
1791
2159
|
export function RedirectHandler(url: string, code: number): Handler {
|
|
1792
2160
|
return {
|
|
1793
2161
|
ServeHTTP(w, r) {
|
|
1794
|
-
Redirect(w, r, url, code)
|
|
2162
|
+
return Redirect(w, r, url, code)
|
|
1795
2163
|
},
|
|
1796
2164
|
}
|
|
1797
2165
|
}
|
|
1798
2166
|
|
|
1799
|
-
export function TimeoutHandler(
|
|
2167
|
+
export function TimeoutHandler(
|
|
2168
|
+
handler: Handler | null,
|
|
2169
|
+
_dt: number,
|
|
2170
|
+
msg: string,
|
|
2171
|
+
): Handler {
|
|
1800
2172
|
return {
|
|
1801
2173
|
ServeHTTP(w, r) {
|
|
1802
2174
|
if (handler == null) {
|
|
@@ -1808,32 +2180,45 @@ export function TimeoutHandler(handler: Handler | null, _dt: number, msg: string
|
|
|
1808
2180
|
}
|
|
1809
2181
|
}
|
|
1810
2182
|
|
|
1811
|
-
export function Error(
|
|
2183
|
+
export function Error(
|
|
2184
|
+
w: ResponseWriter | null,
|
|
2185
|
+
error: string,
|
|
2186
|
+
code: number,
|
|
2187
|
+
): void {
|
|
1812
2188
|
w?.WriteHeader(code)
|
|
1813
2189
|
w?.Write($.stringToBytes(error + '\n'))
|
|
1814
2190
|
}
|
|
1815
2191
|
|
|
1816
|
-
export function NotFound(
|
|
2192
|
+
export function NotFound(
|
|
2193
|
+
w: ResponseWriter | null,
|
|
2194
|
+
_r: Request | $.VarRef<Request> | null,
|
|
2195
|
+
): void {
|
|
1817
2196
|
Error(w, '404 page not found', StatusNotFound)
|
|
1818
2197
|
}
|
|
1819
2198
|
|
|
1820
|
-
export function Redirect(
|
|
2199
|
+
export async function Redirect(
|
|
1821
2200
|
w: ResponseWriter | null,
|
|
1822
2201
|
_r: Request | $.VarRef<Request> | null,
|
|
1823
2202
|
url: string,
|
|
1824
2203
|
code: number,
|
|
1825
|
-
): void {
|
|
1826
|
-
|
|
2204
|
+
): Promise<void> {
|
|
2205
|
+
if (w == null) {
|
|
2206
|
+
return
|
|
2207
|
+
}
|
|
2208
|
+
const header = await w.Header()
|
|
1827
2209
|
if (header != null) {
|
|
1828
2210
|
Header_Set(header, 'Location', url)
|
|
1829
2211
|
}
|
|
1830
|
-
w
|
|
2212
|
+
await w.WriteHeader(code)
|
|
1831
2213
|
}
|
|
1832
2214
|
|
|
1833
2215
|
export function ParseTime(text: string): [time.Time, $.GoError] {
|
|
1834
2216
|
const date = new globalThis.Date(text)
|
|
1835
2217
|
if (isNaN(date.getTime())) {
|
|
1836
|
-
return [
|
|
2218
|
+
return [
|
|
2219
|
+
new time.Time(),
|
|
2220
|
+
$.newError(`parsing time "${text}" as HTTP-date: cannot parse`),
|
|
2221
|
+
]
|
|
1837
2222
|
}
|
|
1838
2223
|
return [time.UnixMilli(date.getTime()), null]
|
|
1839
2224
|
}
|
|
@@ -1881,7 +2266,10 @@ export function DetectContentType(data: $.Slice<number>): string {
|
|
|
1881
2266
|
if (startsWithBytes(bytes, new Uint8Array([0xef, 0xbb, 0xbf]))) {
|
|
1882
2267
|
return 'text/plain; charset=utf-8'
|
|
1883
2268
|
}
|
|
1884
|
-
if (
|
|
2269
|
+
if (
|
|
2270
|
+
startsWithBytes(bytes, new Uint8Array([0x00, 0x00, 0x01, 0x00])) ||
|
|
2271
|
+
startsWithBytes(bytes, new Uint8Array([0x00, 0x00, 0x02, 0x00]))
|
|
2272
|
+
) {
|
|
1885
2273
|
return 'image/x-icon'
|
|
1886
2274
|
}
|
|
1887
2275
|
if (startsWithASCII(bytes, 'BM')) {
|
|
@@ -1893,7 +2281,12 @@ export function DetectContentType(data: $.Slice<number>): string {
|
|
|
1893
2281
|
if (isRIFFSignature(bytes, 'WEBPVP')) {
|
|
1894
2282
|
return 'image/webp'
|
|
1895
2283
|
}
|
|
1896
|
-
if (
|
|
2284
|
+
if (
|
|
2285
|
+
startsWithBytes(
|
|
2286
|
+
bytes,
|
|
2287
|
+
new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
|
|
2288
|
+
)
|
|
2289
|
+
) {
|
|
1897
2290
|
return 'image/png'
|
|
1898
2291
|
}
|
|
1899
2292
|
if (startsWithBytes(bytes, new Uint8Array([0xff, 0xd8, 0xff]))) {
|
|
@@ -1908,7 +2301,12 @@ export function DetectContentType(data: $.Slice<number>): string {
|
|
|
1908
2301
|
if (startsWithBytes(bytes, new Uint8Array([0x4f, 0x67, 0x67, 0x53, 0x00]))) {
|
|
1909
2302
|
return 'application/ogg'
|
|
1910
2303
|
}
|
|
1911
|
-
if (
|
|
2304
|
+
if (
|
|
2305
|
+
startsWithBytes(
|
|
2306
|
+
bytes,
|
|
2307
|
+
new Uint8Array([0x4d, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06]),
|
|
2308
|
+
)
|
|
2309
|
+
) {
|
|
1912
2310
|
return 'audio/midi'
|
|
1913
2311
|
}
|
|
1914
2312
|
if (isRIFFSignature(bytes, 'AVI ')) {
|
|
@@ -1947,17 +2345,32 @@ export function DetectContentType(data: $.Slice<number>): string {
|
|
|
1947
2345
|
if (startsWithBytes(bytes, new Uint8Array([0x50, 0x4b, 0x03, 0x04]))) {
|
|
1948
2346
|
return 'application/zip'
|
|
1949
2347
|
}
|
|
1950
|
-
if (
|
|
2348
|
+
if (
|
|
2349
|
+
startsWithBytes(
|
|
2350
|
+
bytes,
|
|
2351
|
+
new Uint8Array([0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00]),
|
|
2352
|
+
)
|
|
2353
|
+
) {
|
|
1951
2354
|
return 'application/x-rar-compressed'
|
|
1952
2355
|
}
|
|
1953
|
-
if (
|
|
2356
|
+
if (
|
|
2357
|
+
startsWithBytes(
|
|
2358
|
+
bytes,
|
|
2359
|
+
new Uint8Array([0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00]),
|
|
2360
|
+
)
|
|
2361
|
+
) {
|
|
1954
2362
|
return 'application/x-rar-compressed'
|
|
1955
2363
|
}
|
|
1956
2364
|
if (startsWithBytes(bytes, new Uint8Array([0x00, 0x61, 0x73, 0x6d]))) {
|
|
1957
2365
|
return 'application/wasm'
|
|
1958
2366
|
}
|
|
1959
2367
|
for (const byte of afterWS) {
|
|
1960
|
-
if (
|
|
2368
|
+
if (
|
|
2369
|
+
byte <= 0x08 ||
|
|
2370
|
+
byte === 0x0b ||
|
|
2371
|
+
(byte >= 0x0e && byte <= 0x1a) ||
|
|
2372
|
+
(byte >= 0x1c && byte <= 0x1f)
|
|
2373
|
+
) {
|
|
1961
2374
|
return 'application/octet-stream'
|
|
1962
2375
|
}
|
|
1963
2376
|
}
|
|
@@ -1967,7 +2380,13 @@ export function DetectContentType(data: $.Slice<number>): string {
|
|
|
1967
2380
|
function firstNonWhitespace(data: Uint8Array): number {
|
|
1968
2381
|
for (let i = 0; i < data.length; i++) {
|
|
1969
2382
|
const byte = data[i]
|
|
1970
|
-
if (
|
|
2383
|
+
if (
|
|
2384
|
+
byte !== 0x09 &&
|
|
2385
|
+
byte !== 0x0a &&
|
|
2386
|
+
byte !== 0x0c &&
|
|
2387
|
+
byte !== 0x0d &&
|
|
2388
|
+
byte !== 0x20
|
|
2389
|
+
) {
|
|
1971
2390
|
return i
|
|
1972
2391
|
}
|
|
1973
2392
|
}
|
|
@@ -1990,7 +2409,11 @@ function startsWithASCII(data: Uint8Array, prefix: string): boolean {
|
|
|
1990
2409
|
return asciiMatchesAt(data, 0, prefix)
|
|
1991
2410
|
}
|
|
1992
2411
|
|
|
1993
|
-
function asciiMatchesAt(
|
|
2412
|
+
function asciiMatchesAt(
|
|
2413
|
+
data: Uint8Array,
|
|
2414
|
+
offset: number,
|
|
2415
|
+
text: string,
|
|
2416
|
+
): boolean {
|
|
1994
2417
|
if (data.length < offset + text.length) {
|
|
1995
2418
|
return false
|
|
1996
2419
|
}
|
|
@@ -2102,7 +2525,12 @@ export function ParseSetCookie(line: string): [Cookie | null, $.GoError] {
|
|
|
2102
2525
|
if (!ok) {
|
|
2103
2526
|
return [null, errInvalidCookieValue]
|
|
2104
2527
|
}
|
|
2105
|
-
const cookie = new Cookie({
|
|
2528
|
+
const cookie = new Cookie({
|
|
2529
|
+
Name: name,
|
|
2530
|
+
Value: value,
|
|
2531
|
+
Quoted: quoted,
|
|
2532
|
+
Raw: line,
|
|
2533
|
+
})
|
|
2106
2534
|
const unparsed: string[] = []
|
|
2107
2535
|
for (const raw of parts.slice(1)) {
|
|
2108
2536
|
const part = raw.trim()
|
|
@@ -2158,7 +2586,10 @@ export function ParseSetCookie(line: string): [Cookie | null, $.GoError] {
|
|
|
2158
2586
|
break
|
|
2159
2587
|
}
|
|
2160
2588
|
let secs = Number.parseInt(attrValue, 10)
|
|
2161
|
-
if (
|
|
2589
|
+
if (
|
|
2590
|
+
(secs !== 0 && attrValue[0] === '0') ||
|
|
2591
|
+
!Number.isSafeInteger(secs)
|
|
2592
|
+
) {
|
|
2162
2593
|
break
|
|
2163
2594
|
}
|
|
2164
2595
|
if (secs <= 0) {
|
|
@@ -2207,7 +2638,10 @@ export function NewRequestWithContext(
|
|
|
2207
2638
|
method = MethodGet
|
|
2208
2639
|
}
|
|
2209
2640
|
if (!isToken(method)) {
|
|
2210
|
-
return [
|
|
2641
|
+
return [
|
|
2642
|
+
null,
|
|
2643
|
+
errors.New(`net/http: invalid method ${JSON.stringify(method)}`),
|
|
2644
|
+
]
|
|
2211
2645
|
}
|
|
2212
2646
|
if (ctx == null) {
|
|
2213
2647
|
return [null, errors.New('net/http: nil Context')]
|
|
@@ -2217,7 +2651,17 @@ export function NewRequestWithContext(
|
|
|
2217
2651
|
return [null, err]
|
|
2218
2652
|
}
|
|
2219
2653
|
const bodyInfo = requestBodyInfo(body, 0)
|
|
2220
|
-
return [
|
|
2654
|
+
return [
|
|
2655
|
+
new Request({
|
|
2656
|
+
Method: method,
|
|
2657
|
+
URL: parsedURL,
|
|
2658
|
+
Body: bodyInfo.Body,
|
|
2659
|
+
ContentLength: bodyInfo.ContentLength,
|
|
2660
|
+
Host: parsedURL.Host,
|
|
2661
|
+
ctx,
|
|
2662
|
+
}),
|
|
2663
|
+
null,
|
|
2664
|
+
]
|
|
2221
2665
|
}
|
|
2222
2666
|
|
|
2223
2667
|
export async function Get(_url: string): Promise<[Response | null, $.GoError]> {
|
|
@@ -2228,7 +2672,9 @@ export async function Get(_url: string): Promise<[Response | null, $.GoError]> {
|
|
|
2228
2672
|
return await DefaultClient.Do(req)
|
|
2229
2673
|
}
|
|
2230
2674
|
|
|
2231
|
-
export async function Head(
|
|
2675
|
+
export async function Head(
|
|
2676
|
+
_url: string,
|
|
2677
|
+
): Promise<[Response | null, $.GoError]> {
|
|
2232
2678
|
const [req, err] = NewRequest(MethodHead, _url, null)
|
|
2233
2679
|
if (err != null) {
|
|
2234
2680
|
return [null, err]
|
|
@@ -2249,15 +2695,22 @@ export async function Post(
|
|
|
2249
2695
|
return await DefaultClient.Do(req)
|
|
2250
2696
|
}
|
|
2251
2697
|
|
|
2252
|
-
export async function PostForm(
|
|
2698
|
+
export async function PostForm(
|
|
2699
|
+
_url: string,
|
|
2700
|
+
data: any,
|
|
2701
|
+
): Promise<[Response | null, $.GoError]> {
|
|
2253
2702
|
return await DefaultClient.PostForm(_url, data)
|
|
2254
2703
|
}
|
|
2255
2704
|
|
|
2256
|
-
export function ProxyFromEnvironment(
|
|
2705
|
+
export function ProxyFromEnvironment(
|
|
2706
|
+
_req: Request | $.VarRef<Request> | null,
|
|
2707
|
+
): [any, $.GoError] {
|
|
2257
2708
|
return [null, null]
|
|
2258
2709
|
}
|
|
2259
2710
|
|
|
2260
|
-
export function ProxyURL(
|
|
2711
|
+
export function ProxyURL(
|
|
2712
|
+
fixedURL: any,
|
|
2713
|
+
): (req: Request | $.VarRef<Request> | null) => [any, $.GoError] {
|
|
2261
2714
|
return () => [fixedURL, null]
|
|
2262
2715
|
}
|
|
2263
2716
|
|
|
@@ -2265,7 +2718,10 @@ export function ReadRequest(_reader: any): [Request | null, $.GoError] {
|
|
|
2265
2718
|
return [null, ErrNotSupported]
|
|
2266
2719
|
}
|
|
2267
2720
|
|
|
2268
|
-
export function ReadResponse(
|
|
2721
|
+
export function ReadResponse(
|
|
2722
|
+
_reader: any,
|
|
2723
|
+
_req: Request | $.VarRef<Request> | null,
|
|
2724
|
+
): [Response | null, $.GoError] {
|
|
2269
2725
|
return [null, ErrNotSupported]
|
|
2270
2726
|
}
|
|
2271
2727
|
|
|
@@ -2303,7 +2759,10 @@ function readCloserForBody(body: io.Reader | null): io.ReadCloser | null {
|
|
|
2303
2759
|
return io.NopCloser(body)
|
|
2304
2760
|
}
|
|
2305
2761
|
|
|
2306
|
-
function requestBodyInfo(
|
|
2762
|
+
function requestBodyInfo(
|
|
2763
|
+
body: io.Reader | null,
|
|
2764
|
+
unknownLength: number,
|
|
2765
|
+
): { Body: io.ReadCloser | null; ContentLength: number } {
|
|
2307
2766
|
if (body == null) {
|
|
2308
2767
|
return { Body: null, ContentLength: 0 }
|
|
2309
2768
|
}
|
|
@@ -2311,9 +2770,16 @@ function requestBodyInfo(body: io.Reader | null, unknownLength: number): { Body:
|
|
|
2311
2770
|
if (value === NoBody) {
|
|
2312
2771
|
return { Body: NoBody, ContentLength: 0 }
|
|
2313
2772
|
}
|
|
2314
|
-
if (
|
|
2773
|
+
if (
|
|
2774
|
+
value instanceof bytes.Buffer ||
|
|
2775
|
+
value instanceof bytes.Reader ||
|
|
2776
|
+
value instanceof strings.Reader
|
|
2777
|
+
) {
|
|
2315
2778
|
const length = value.Len()
|
|
2316
|
-
return {
|
|
2779
|
+
return {
|
|
2780
|
+
Body: length === 0 ? NoBody : readCloserForBody(body),
|
|
2781
|
+
ContentLength: length,
|
|
2782
|
+
}
|
|
2317
2783
|
}
|
|
2318
2784
|
return { Body: readCloserForBody(body), ContentLength: unknownLength }
|
|
2319
2785
|
}
|