summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNode.js GitHub Bot <github-bot@iojs.org>2023-05-16 17:36:34 +0100
committerGitHub <noreply@github.com>2023-05-16 16:36:34 +0000
commit7a57d1fb942467a4aa255ee11e09a4ca0003ce85 (patch)
tree7b0a557f6dc7567020f24e42efd274da20dd9ee3
parentd2c4518ce65e48c1f32f435c1f06519723873f0c (diff)
downloadnode-new-7a57d1fb942467a4aa255ee11e09a4ca0003ce85.tar.gz
deps: update undici to 5.22.1
PR-URL: https://github.com/nodejs/node/pull/47994 Reviewed-By: Matthew Aitken <maitken033380023@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com> Reviewed-By: Mestery <mestery@protonmail.com>
-rw-r--r--deps/undici/src/docs/api/CacheStorage.md30
-rw-r--r--deps/undici/src/docs/api/Errors.md32
-rw-r--r--deps/undici/src/docs/api/Fetch.md2
-rw-r--r--deps/undici/src/docs/api/WebSocket.md29
-rw-r--r--deps/undici/src/index.d.ts2
-rw-r--r--deps/undici/src/index.js7
-rw-r--r--deps/undici/src/lib/cache/cache.js842
-rw-r--r--deps/undici/src/lib/cache/cachestorage.js144
-rw-r--r--deps/undici/src/lib/cache/symbols.js5
-rw-r--r--deps/undici/src/lib/cache/util.js49
-rw-r--r--deps/undici/src/lib/client.js15
-rw-r--r--deps/undici/src/lib/fetch/body.js10
-rw-r--r--deps/undici/src/lib/fetch/dataURL.js95
-rw-r--r--deps/undici/src/lib/fetch/index.js2
-rw-r--r--deps/undici/src/lib/fetch/response.js5
-rw-r--r--deps/undici/src/lib/fetch/util.js3
-rw-r--r--deps/undici/src/lib/fetch/webidl.js7
-rw-r--r--deps/undici/src/lib/websocket/connection.js14
-rw-r--r--deps/undici/src/lib/websocket/frame.js2
-rw-r--r--deps/undici/src/lib/websocket/websocket.js38
-rw-r--r--deps/undici/src/package.json8
-rw-r--r--deps/undici/src/types/cache.d.ts36
-rw-r--r--deps/undici/src/types/errors.d.ts11
-rw-r--r--deps/undici/src/types/webidl.d.ts2
-rw-r--r--deps/undici/src/types/websocket.d.ts10
-rw-r--r--deps/undici/undici.js98
-rw-r--r--src/undici_version.h2
27 files changed, 1422 insertions, 78 deletions
diff --git a/deps/undici/src/docs/api/CacheStorage.md b/deps/undici/src/docs/api/CacheStorage.md
new file mode 100644
index 0000000000..08ee99fab1
--- /dev/null
+++ b/deps/undici/src/docs/api/CacheStorage.md
@@ -0,0 +1,30 @@
+# CacheStorage
+
+Undici exposes a W3C spec-compliant implementation of [CacheStorage](https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage) and [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache).
+
+## Opening a Cache
+
+Undici exports a top-level CacheStorage instance. You can open a new Cache, or duplicate a Cache with an existing name, by using `CacheStorage.prototype.open`. If you open a Cache with the same name as an already-existing Cache, its list of cached Responses will be shared between both instances.
+
+```mjs
+import { caches } from 'undici'
+
+const cache_1 = await caches.open('v1')
+const cache_2 = await caches.open('v1')
+
+// Although .open() creates a new instance,
+assert(cache_1 !== cache_2)
+// The same Response is matched in both.
+assert.deepStrictEqual(await cache_1.match('/req'), await cache_2.match('/req'))
+```
+
+## Deleting a Cache
+
+If a Cache is deleted, the cached Responses/Requests can still be used.
+
+```mjs
+const response = await cache_1.match('/req')
+await caches.delete('v1')
+
+await response.text() // the Response's body
+```
diff --git a/deps/undici/src/docs/api/Errors.md b/deps/undici/src/docs/api/Errors.md
index fba0e8c7ce..917e45df9f 100644
--- a/deps/undici/src/docs/api/Errors.md
+++ b/deps/undici/src/docs/api/Errors.md
@@ -7,19 +7,25 @@ You can find all the error objects inside the `errors` key.
import { errors } from 'undici'
```
-| Error | Error Codes | Description |
-| ------------------------------------ | ------------------------------------- | -------------------------------------------------- |
-| `InvalidArgumentError` | `UND_ERR_INVALID_ARG` | passed an invalid argument. |
-| `InvalidReturnValueError` | `UND_ERR_INVALID_RETURN_VALUE` | returned an invalid value. |
-| `RequestAbortedError` | `UND_ERR_ABORTED` | the request has been aborted by the user |
-| `ClientDestroyedError` | `UND_ERR_DESTROYED` | trying to use a destroyed client. |
-| `ClientClosedError` | `UND_ERR_CLOSED` | trying to use a closed client. |
-| `SocketError` | `UND_ERR_SOCKET` | there is an error with the socket. |
-| `NotSupportedError` | `UND_ERR_NOT_SUPPORTED` | encountered unsupported functionality. |
-| `RequestContentLengthMismatchError` | `UND_ERR_REQ_CONTENT_LENGTH_MISMATCH` | request body does not match content-length header |
-| `ResponseContentLengthMismatchError` | `UND_ERR_RES_CONTENT_LENGTH_MISMATCH` | response body does not match content-length header |
-| `InformationalError` | `UND_ERR_INFO` | expected error with reason |
-| `ResponseExceededMaxSizeError` | `UND_ERR_RES_EXCEEDED_MAX_SIZE` | response body exceed the max size allowed |
+| Error | Error Codes | Description |
+| ------------------------------------ | ------------------------------------- | ------------------------------------------------------------------------- |
+| `UndiciError` | `UND_ERR` | all errors below are extended from `UndiciError`. |
+| `ConnectTimeoutError` | `UND_ERR_CONNECT_TIMEOUT` | socket is destroyed due to connect timeout. |
+| `HeadersTimeoutError` | `UND_ERR_HEADERS_TIMEOUT` | socket is destroyed due to headers timeout. |
+| `HeadersOverflowError` | `UND_ERR_HEADERS_OVERFLOW` | socket is destroyed due to headers' max size being exceeded. |
+| `BodyTimeoutError` | `UND_ERR_BODY_TIMEOUT` | socket is destroyed due to body timeout. |
+| `ResponseStatusCodeError` | `UND_ERR_RESPONSE_STATUS_CODE` | an error is thrown when `throwOnError` is `true` for status codes >= 400. |
+| `InvalidArgumentError` | `UND_ERR_INVALID_ARG` | passed an invalid argument. |
+| `InvalidReturnValueError` | `UND_ERR_INVALID_RETURN_VALUE` | returned an invalid value. |
+| `RequestAbortedError` | `UND_ERR_ABORTED` | the request has been aborted by the user |
+| `ClientDestroyedError` | `UND_ERR_DESTROYED` | trying to use a destroyed client. |
+| `ClientClosedError` | `UND_ERR_CLOSED` | trying to use a closed client. |
+| `SocketError` | `UND_ERR_SOCKET` | there is an error with the socket. |
+| `NotSupportedError` | `UND_ERR_NOT_SUPPORTED` | encountered unsupported functionality. |
+| `RequestContentLengthMismatchError` | `UND_ERR_REQ_CONTENT_LENGTH_MISMATCH` | request body does not match content-length header |
+| `ResponseContentLengthMismatchError` | `UND_ERR_RES_CONTENT_LENGTH_MISMATCH` | response body does not match content-length header |
+| `InformationalError` | `UND_ERR_INFO` | expected error with reason |
+| `ResponseExceededMaxSizeError` | `UND_ERR_RES_EXCEEDED_MAX_SIZE` | response body exceed the max size allowed |
### `SocketError`
diff --git a/deps/undici/src/docs/api/Fetch.md b/deps/undici/src/docs/api/Fetch.md
index 0a5c3d0969..b5a62422a2 100644
--- a/deps/undici/src/docs/api/Fetch.md
+++ b/deps/undici/src/docs/api/Fetch.md
@@ -8,6 +8,8 @@ Documentation and examples can be found on [MDN](https://developer.mozilla.org/e
This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/File)
+In Node versions v18.13.0 and above and v19.2.0 and above, undici will default to using Node's [File](https://nodejs.org/api/buffer.html#class-file) class. In versions where it's not available, it will default to the undici one.
+
## FormData
This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
diff --git a/deps/undici/src/docs/api/WebSocket.md b/deps/undici/src/docs/api/WebSocket.md
index 639a5333a1..9d374f4046 100644
--- a/deps/undici/src/docs/api/WebSocket.md
+++ b/deps/undici/src/docs/api/WebSocket.md
@@ -1,17 +1,40 @@
# Class: WebSocket
-> ⚠️ Warning: the WebSocket API is experimental and has known bugs.
+> ⚠️ Warning: the WebSocket API is experimental.
Extends: [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
-The WebSocket object provides a way to manage a WebSocket connection to a server, allowing bidirectional communication. The API follows the [WebSocket spec](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket).
+The WebSocket object provides a way to manage a WebSocket connection to a server, allowing bidirectional communication. The API follows the [WebSocket spec](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) and [RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455).
## `new WebSocket(url[, protocol])`
Arguments:
* **url** `URL | string` - The url's protocol *must* be `ws` or `wss`.
-* **protocol** `string | string[]` (optional) - Subprotocol(s) to request the server use.
+* **protocol** `string | string[] | WebSocketInit` (optional) - Subprotocol(s) to request the server use, or a [`Dispatcher`](./Dispatcher.md).
+
+### Example:
+
+This example will not work in browsers or other platforms that don't allow passing an object.
+
+```mjs
+import { WebSocket, ProxyAgent } from 'undici'
+
+const proxyAgent = new ProxyAgent('my.proxy.server')
+
+const ws = new WebSocket('wss://echo.websocket.events', {
+ dispatcher: proxyAgent,
+ protocols: ['echo', 'chat']
+})
+```
+
+If you do not need a custom Dispatcher, it's recommended to use the following pattern:
+
+```mjs
+import { WebSocket } from 'undici'
+
+const ws = new WebSocket('wss://echo.websocket.events', ['echo', 'chat'])
+```
## Read More
diff --git a/deps/undici/src/index.d.ts b/deps/undici/src/index.d.ts
index d67de97241..0730677b29 100644
--- a/deps/undici/src/index.d.ts
+++ b/deps/undici/src/index.d.ts
@@ -24,6 +24,7 @@ export * from './types/formdata'
export * from './types/diagnostics-channel'
export * from './types/websocket'
export * from './types/content-type'
+export * from './types/cache'
export { Interceptable } from './types/mock-interceptor'
export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, RedirectHandler, DecoratorHandler }
@@ -52,4 +53,5 @@ declare namespace Undici {
var MockAgent: typeof import('./types/mock-agent').default;
var mockErrors: typeof import('./types/mock-errors').default;
var fetch: typeof import('./types/fetch').fetch;
+ var caches: typeof import('./types/cache').caches;
}
diff --git a/deps/undici/src/index.js b/deps/undici/src/index.js
index 02ac246fa4..7e8831ceee 100644
--- a/deps/undici/src/index.js
+++ b/deps/undici/src/index.js
@@ -121,6 +121,13 @@ if (util.nodeMajor > 16 || (util.nodeMajor === 16 && util.nodeMinor >= 8)) {
module.exports.setGlobalOrigin = setGlobalOrigin
module.exports.getGlobalOrigin = getGlobalOrigin
+
+ const { CacheStorage } = require('./lib/cache/cachestorage')
+ const { kConstruct } = require('./lib/cache/symbols')
+
+ // Cache & CacheStorage are tightly coupled with fetch. Even if it may run
+ // in an older version of Node, it doesn't have any use without fetch.
+ module.exports.caches = new CacheStorage(kConstruct)
}
if (util.nodeMajor >= 16) {
diff --git a/deps/undici/src/lib/cache/cache.js b/deps/undici/src/lib/cache/cache.js
new file mode 100644
index 0000000000..18f06a348a
--- /dev/null
+++ b/deps/undici/src/lib/cache/cache.js
@@ -0,0 +1,842 @@
+'use strict'
+
+const { kConstruct } = require('./symbols')
+const { urlEquals, fieldValues: getFieldValues } = require('./util')
+const { kEnumerableProperty, isDisturbed } = require('../core/util')
+const { kHeadersList } = require('../core/symbols')
+const { webidl } = require('../fetch/webidl')
+const { Response, cloneResponse } = require('../fetch/response')
+const { Request } = require('../fetch/request')
+const { kState, kHeaders, kGuard, kRealm } = require('../fetch/symbols')
+const { fetching } = require('../fetch/index')
+const { urlIsHttpHttpsScheme, createDeferredPromise, readAllBytes } = require('../fetch/util')
+const assert = require('assert')
+const { getGlobalDispatcher } = require('../global')
+
+/**
+ * @see https://w3c.github.io/ServiceWorker/#dfn-cache-batch-operation
+ * @typedef {Object} CacheBatchOperation
+ * @property {'delete' | 'put'} type
+ * @property {any} request
+ * @property {any} response
+ * @property {import('../../types/cache').CacheQueryOptions} options
+ */
+
+/**
+ * @see https://w3c.github.io/ServiceWorker/#dfn-request-response-list
+ * @typedef {[any, any][]} requestResponseList
+ */
+
+class Cache {
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#dfn-relevant-request-response-list
+ * @type {requestResponseList}
+ */
+ #relevantRequestResponseList
+
+ constructor () {
+ if (arguments[0] !== kConstruct) {
+ webidl.illegalConstructor()
+ }
+
+ this.#relevantRequestResponseList = arguments[1]
+ }
+
+ async match (request, options = {}) {
+ webidl.brandCheck(this, Cache)
+ webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.match' })
+
+ request = webidl.converters.RequestInfo(request)
+ options = webidl.converters.CacheQueryOptions(options)
+
+ const p = await this.matchAll(request, options)
+
+ if (p.length === 0) {
+ return
+ }
+
+ return p[0]
+ }
+
+ async matchAll (request = undefined, options = {}) {
+ webidl.brandCheck(this, Cache)
+
+ if (request !== undefined) request = webidl.converters.RequestInfo(request)
+ options = webidl.converters.CacheQueryOptions(options)
+
+ // 1.
+ let r = null
+
+ // 2.
+ if (request !== undefined) {
+ if (request instanceof Request) {
+ // 2.1.1
+ r = request[kState]
+
+ // 2.1.2
+ if (r.method !== 'GET' && !options.ignoreMethod) {
+ return []
+ }
+ } else if (typeof request === 'string') {
+ // 2.2.1
+ r = new Request(request)[kState]
+ }
+ }
+
+ // 5.
+ // 5.1
+ const responses = []
+
+ // 5.2
+ if (request === undefined) {
+ // 5.2.1
+ for (const requestResponse of this.#relevantRequestResponseList) {
+ responses.push(requestResponse[1])
+ }
+ } else { // 5.3
+ // 5.3.1
+ const requestResponses = this.#queryCache(r, options)
+
+ // 5.3.2
+ for (const requestResponse of requestResponses) {
+ responses.push(requestResponse[1])
+ }
+ }
+
+ // 5.4
+ // We don't implement CORs so we don't need to loop over the responses, yay!
+
+ // 5.5.1
+ const responseList = []
+
+ // 5.5.2
+ for (const response of responses) {
+ // 5.5.2.1
+ const responseObject = new Response(response.body?.source ?? null)
+ const body = responseObject[kState].body
+ responseObject[kState] = response
+ responseObject[kState].body = body
+ responseObject[kHeaders][kHeadersList] = response.headersList
+ responseObject[kHeaders][kGuard] = 'immutable'
+
+ responseList.push(responseObject)
+ }
+
+ // 6.
+ return Object.freeze(responseList)
+ }
+
+ async add (request) {
+ webidl.brandCheck(this, Cache)
+ webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.add' })
+
+ request = webidl.converters.RequestInfo(request)
+
+ // 1.
+ const requests = [request]
+
+ // 2.
+ const responseArrayPromise = this.addAll(requests)
+
+ // 3.
+ return await responseArrayPromise
+ }
+
+ async addAll (requests) {
+ webidl.brandCheck(this, Cache)
+ webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.addAll' })
+
+ requests = webidl.converters['sequence<RequestInfo>'](requests)
+
+ // 1.
+ const responsePromises = []
+
+ // 2.
+ const requestList = []
+
+ // 3.
+ for (const request of requests) {
+ if (typeof request === 'string') {
+ continue
+ }
+
+ // 3.1
+ const r = request[kState]
+
+ // 3.2
+ if (!urlIsHttpHttpsScheme(r.url) || r.method !== 'GET') {
+ throw webidl.errors.exception({
+ header: 'Cache.addAll',
+ message: 'Expected http/s scheme when method is not GET.'
+ })
+ }
+ }
+
+ // 4.
+ /** @type {ReturnType<typeof fetching>[]} */
+ const fetchControllers = []
+
+ // 5.
+ for (const request of requests) {
+ // 5.1
+ const r = new Request(request)[kState]
+
+ // 5.2
+ if (!urlIsHttpHttpsScheme(r.url)) {
+ throw webidl.errors.exception({
+ header: 'Cache.addAll',
+ message: 'Expected http/s scheme.'
+ })
+ }
+
+ // 5.4
+ r.initiator = 'fetch'
+ r.destination = 'subresource'
+
+ // 5.5
+ requestList.push(r)
+
+ // 5.6
+ const responsePromise = createDeferredPromise()
+
+ // 5.7
+ fetchControllers.push(fetching({
+ request: r,
+ dispatcher: getGlobalDispatcher(),
+ processResponse (response) {
+ // 1.
+ if (response.type === 'error' || response.status === 206 || response.status < 200 || response.status > 299) {
+ responsePromise.reject(webidl.errors.exception({
+ header: 'Cache.addAll',
+ message: 'Received an invalid status code or the request failed.'
+ }))
+ } else if (response.headersList.contains('vary')) { // 2.
+ // 2.1
+ const fieldValues = getFieldValues(response.headersList.get('vary'))
+
+ // 2.2
+ for (const fieldValue of fieldValues) {
+ // 2.2.1
+ if (fieldValue === '*') {
+ responsePromise.reject(webidl.errors.exception({
+ header: 'Cache.addAll',
+ message: 'invalid vary field value'
+ }))
+
+ for (const controller of fetchControllers) {
+ controller.abort()
+ }
+
+ return
+ }
+ }
+ }
+ },
+ processResponseEndOfBody (response) {
+ // 1.
+ if (response.aborted) {
+ responsePromise.reject(new DOMException('aborted', 'AbortError'))
+ return
+ }
+
+ // 2.
+ responsePromise.resolve(response)
+ }
+ }))
+
+ // 5.8
+ responsePromises.push(responsePromise.promise)
+ }
+
+ // 6.
+ const p = Promise.all(responsePromises)
+
+ // 7.
+ const responses = await p
+
+ // 7.1
+ const operations = []
+
+ // 7.2
+ let index = 0
+
+ // 7.3
+ for (const response of responses) {
+ // 7.3.1
+ /** @type {CacheBatchOperation} */
+ const operation = {
+ type: 'put', // 7.3.2
+ request: requestList[index], // 7.3.3
+ response // 7.3.4
+ }
+
+ operations.push(operation) // 7.3.5
+
+ index++ // 7.3.6
+ }
+
+ // 7.5
+ const cacheJobPromise = createDeferredPromise()
+
+ // 7.6.1
+ let errorData = null
+
+ // 7.6.2
+ try {
+ this.#batchCacheOperations(operations)
+ } catch (e) {
+ errorData = e
+ }
+
+ // 7.6.3
+ queueMicrotask(() => {
+ // 7.6.3.1
+ if (errorData === null) {
+ cacheJobPromise.resolve(undefined)
+ } else {
+ // 7.6.3.2
+ cacheJobPromise.reject(errorData)
+ }
+ })
+
+ // 7.7
+ return cacheJobPromise.promise
+ }
+
+ async put (request, response) {
+ webidl.brandCheck(this, Cache)
+ webidl.argumentLengthCheck(arguments, 2, { header: 'Cache.put' })
+
+ request = webidl.converters.RequestInfo(request)
+ response = webidl.converters.Response(response)
+
+ // 1.
+ let innerRequest = null
+
+ // 2.
+ if (request instanceof Request) {
+ innerRequest = request[kState]
+ } else { // 3.
+ innerRequest = new Request(request)[kState]
+ }
+
+ // 4.
+ if (!urlIsHttpHttpsScheme(innerRequest.url) || innerRequest.method !== 'GET') {
+ throw webidl.errors.exception({
+ header: 'Cache.put',
+ message: 'Expected an http/s scheme when method is not GET'
+ })
+ }
+
+ // 5.
+ const innerResponse = response[kState]
+
+ // 6.
+ if (innerResponse.status === 206) {
+ throw webidl.errors.exception({
+ header: 'Cache.put',
+ message: 'Got 206 status'
+ })
+ }
+
+ // 7.
+ if (innerResponse.headersList.contains('vary')) {
+ // 7.1.
+ const fieldValues = getFieldValues(innerResponse.headersList.get('vary'))
+
+ // 7.2.
+ for (const fieldValue of fieldValues) {
+ // 7.2.1
+ if (fieldValue === '*') {
+ throw webidl.errors.exception({
+ header: 'Cache.put',
+ message: 'Got * vary field value'
+ })
+ }
+ }
+ }
+
+ // 8.
+ if (innerResponse.body && (isDisturbed(innerResponse.body.stream) || innerResponse.body.stream.locked)) {
+ throw webidl.errors.exception({
+ header: 'Cache.put',
+ message: 'Response body is locked or disturbed'
+ })
+ }
+
+ // 9.
+ const clonedResponse = cloneResponse(innerResponse)
+
+ // 10.
+ const bodyReadPromise = createDeferredPromise()
+
+ // 11.
+ if (innerResponse.body != null) {
+ // 11.1
+ const stream = innerResponse.body.stream
+
+ // 11.2
+ const reader = stream.getReader()
+
+ // 11.3
+ readAllBytes(
+ reader,
+ (bytes) => bodyReadPromise.resolve(bytes),
+ (error) => bodyReadPromise.reject(error)
+ )
+ } else {
+ bodyReadPromise.resolve(undefined)
+ }
+
+ // 12.
+ /** @type {CacheBatchOperation[]} */
+ const operations = []
+
+ // 13.
+ /** @type {CacheBatchOperation} */
+ const operation = {
+ type: 'put', // 14.
+ request: innerRequest, // 15.
+ response: clonedResponse // 16.
+ }
+
+ // 17.
+ operations.push(operation)
+
+ // 19.
+ const bytes = await bodyReadPromise.promise
+
+ if (clonedResponse.body != null) {
+ clonedResponse.body.source = bytes
+ }
+
+ // 19.1
+ const cacheJobPromise = createDeferredPromise()
+
+ // 19.2.1
+ let errorData = null
+
+ // 19.2.2
+ try {
+ this.#batchCacheOperations(operations)
+ } catch (e) {
+ errorData = e
+ }
+
+ // 19.2.3
+ queueMicrotask(() => {
+ // 19.2.3.1
+ if (errorData === null) {
+ cacheJobPromise.resolve()
+ } else { // 19.2.3.2
+ cacheJobPromise.reject(errorData)
+ }
+ })
+
+ return cacheJobPromise.promise
+ }
+
+ async delete (request, options = {}) {
+ webidl.brandCheck(this, Cache)
+ webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.delete' })
+
+ request = webidl.converters.RequestInfo(request)
+ options = webidl.converters.CacheQueryOptions(options)
+
+ /**
+ * @type {Request}
+ */
+ let r = null
+
+ if (request instanceof Request) {
+ r = request[kState]
+
+ if (r.method !== 'GET' && !options.ignoreMethod) {
+ return false
+ }
+ } else {
+ assert(typeof request === 'string')
+
+ r = new Request(request)[kState]
+ }
+
+ /** @type {CacheBatchOperation[]} */
+ const operations = []
+
+ /** @type {CacheBatchOperation} */
+ const operation = {
+ type: 'delete',
+ request: r,
+ options
+ }
+
+ operations.push(operation)
+
+ const cacheJobPromise = createDeferredPromise()
+
+ let errorData = null
+ let requestResponses
+
+ try {
+ requestResponses = this.#batchCacheOperations(operations)
+ } catch (e) {
+ errorData = e
+ }
+
+ queueMicrotask(() => {
+ if (errorData === null) {
+ cacheJobPromise.resolve(!!requestResponses?.length)
+ } else {
+ cacheJobPromise.reject(errorData)
+ }
+ })
+
+ return cacheJobPromise.promise
+ }
+
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#dom-cache-keys
+ * @param {any} request
+ * @param {import('../../types/cache').CacheQueryOptions} options
+ * @returns {readonly Request[]}
+ */
+ async keys (request = undefined, options = {}) {
+ webidl.brandCheck(this, Cache)
+
+ if (request !== undefined) request = webidl.converters.RequestInfo(request)
+ options = webidl.converters.CacheQueryOptions(options)
+
+ // 1.
+ let r = null
+
+ // 2.
+ if (request !== undefined) {
+ // 2.1
+ if (request instanceof Request) {
+ // 2.1.1
+ r = request[kState]
+
+ // 2.1.2
+ if (r.method !== 'GET' && !options.ignoreMethod) {
+ return []
+ }
+ } else if (typeof request === 'string') { // 2.2
+ r = new Request(request)[kState]
+ }
+ }
+
+ // 4.
+ const promise = createDeferredPromise()
+
+ // 5.
+ // 5.1
+ const requests = []
+
+ // 5.2
+ if (request === undefined) {
+ // 5.2.1
+ for (const requestResponse of this.#relevantRequestResponseList) {
+ // 5.2.1.1
+ requests.push(requestResponse[0])
+ }
+ } else { // 5.3
+ // 5.3.1
+ const requestResponses = this.#queryCache(r, options)
+
+ // 5.3.2
+ for (const requestResponse of requestResponses) {
+ // 5.3.2.1
+ requests.push(requestResponse[0])
+ }
+ }
+
+ // 5.4
+ queueMicrotask(() => {
+ // 5.4.1
+ const requestList = []
+
+ // 5.4.2
+ for (const request of requests) {
+ const requestObject = new Request('https://a')
+ requestObject[kState] = request
+ requestObject[kHeaders][kHeadersList] = request.headersList
+ requestObject[kHeaders][kGuard] = 'immutable'
+ requestObject[kRealm] = request.client
+
+ // 5.4.2.1
+ requestList.push(requestObject)
+ }
+
+ // 5.4.3
+ promise.resolve(Object.freeze(requestList))
+ })
+
+ return promise.promise
+ }
+
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#batch-cache-operations-algorithm
+ * @param {CacheBatchOperation[]} operations
+ * @returns {requestResponseList}
+ */
+ #batchCacheOperations (operations) {
+ // 1.
+ const cache = this.#relevantRequestResponseList
+
+ // 2.
+ const backupCache = [...cache]
+
+ // 3.
+ const addedItems = []
+
+ // 4.1
+ const resultList = []
+
+ try {
+ // 4.2
+ for (const operation of operations) {
+ // 4.2.1
+ if (operation.type !== 'delete' && operation.type !== 'put') {
+ throw webidl.errors.exception({
+ header: 'Cache.#batchCacheOperations',
+ message: 'operation type does not match "delete" or "put"'
+ })
+ }
+
+ // 4.2.2
+ if (operation.type === 'delete' && operation.response != null) {
+ throw webidl.errors.exception({
+ header: 'Cache.#batchCacheOperations',
+ message: 'delete operation should not have an associated response'
+ })
+ }
+
+ // 4.2.3
+ if (this.#queryCache(operation.request, operation.options, addedItems).length) {
+ throw new DOMException('???', 'InvalidStateError')
+ }
+
+ // 4.2.4
+ let requestResponses
+
+ // 4.2.5
+ if (operation.type === 'delete') {
+ // 4.2.5.1
+ requestResponses = this.#queryCache(operation.request, operation.options)
+
+ // TODO: the spec is wrong, this is needed to pass WPTs
+ if (requestResponses.length === 0) {
+ return []
+ }
+
+ // 4.2.5.2
+ for (const requestResponse of requestResponses) {
+ const idx = cache.indexOf(requestResponse)
+ assert(idx !== -1)
+
+ // 4.2.5.2.1
+ cache.splice(idx, 1)
+ }
+ } else if (operation.type === 'put') { // 4.2.6
+ // 4.2.6.1
+ if (operation.response == null) {
+ throw webidl.errors.exception({
+ header: 'Cache.#batchCacheOperations',
+ message: 'put operation should have an associated response'
+ })
+ }
+
+ // 4.2.6.2
+ const r = operation.request
+
+ // 4.2.6.3
+ if (!urlIsHttpHttpsScheme(r.url)) {
+ throw webidl.errors.exception({
+ header: 'Cache.#batchCacheOperations',
+ message: 'expected http or https scheme'
+ })
+ }
+
+ // 4.2.6.4
+ if (r.method !== 'GET') {
+ throw webidl.errors.exception({
+ header: 'Cache.#batchCacheOperations',
+ message: 'not get method'
+ })
+ }
+
+ // 4.2.6.5
+ if (operation.options != null) {
+ throw webidl.errors.exception({
+ header: 'Cache.#batchCacheOperations',
+ message: 'options must not be defined'
+ })
+ }
+
+ // 4.2.6.6
+ requestResponses = this.#queryCache(operation.request)
+
+ // 4.2.6.7
+ for (const requestResponse of requestResponses) {
+ const idx = cache.indexOf(requestResponse)
+ assert(idx !== -1)
+
+ // 4.2.6.7.1
+ cache.splice(idx, 1)
+ }
+
+ // 4.2.6.8
+ cache.push([operation.request, operation.response])
+
+ // 4.2.6.10
+ addedItems.push([operation.request, operation.response])
+ }
+
+ // 4.2.7
+ resultList.push([operation.request, operation.response])
+ }
+
+ // 4.3
+ return resultList
+ } catch (e) { // 5.
+ // 5.1
+ this.#relevantRequestResponseList.length = 0
+
+ // 5.2
+ this.#relevantRequestResponseList = backupCache
+
+ // 5.3
+ throw e
+ }
+ }
+
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#query-cache
+ * @param {any} requestQuery
+ * @param {import('../../types/cache').CacheQueryOptions} options
+ * @param {requestResponseList} targetStorage
+ * @returns {requestResponseList}
+ */
+ #queryCache (requestQuery, options, targetStorage) {
+ /** @type {requestResponseList} */
+ const resultList = []
+
+ const storage = targetStorage ?? this.#relevantRequestResponseList
+
+ for (const requestResponse of storage) {
+ const [cachedRequest, cachedResponse] = requestResponse
+ if (this.#requestMatchesCachedItem(requestQuery, cachedRequest, cachedResponse, options)) {
+ resultList.push(requestResponse)
+ }
+ }
+
+ return resultList
+ }
+
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#request-matches-cached-item-algorithm
+ * @param {any} requestQuery
+ * @param {any} request
+ * @param {any | null} response
+ * @param {import('../../types/cache').CacheQueryOptions | undefined} options
+ * @returns {boolean}
+ */
+ #requestMatchesCachedItem (requestQuery, request, response = null, options) {
+ // if (options?.ignoreMethod === false && request.method === 'GET') {
+ // return false
+ // }
+
+ const queryURL = new URL(requestQuery.url)
+
+ const cachedURL = new URL(request.url)
+
+ if (options?.ignoreSearch) {
+ cachedURL.search = ''
+
+ queryURL.search = ''
+ }
+
+ if (!urlEquals(queryURL, cachedURL, true)) {
+ return false
+ }
+
+ if (
+ response == null ||
+ options?.ignoreVary ||
+ !response.headersList.contains('vary')
+ ) {
+ return true
+ }
+
+ const fieldValues = getFieldValues(response.headersList.get('vary'))
+
+ for (const fieldValue of fieldValues) {
+ if (fieldValue === '*') {
+ return false
+ }
+
+ const requestValue = request.headersList.get(fieldValue)
+ const queryValue = requestQuery.headersList.get(fieldValue)
+
+ // If one has the header and the other doesn't, or one has
+ // a different value than the other, return false
+ if (requestValue !== queryValue) {
+ return false
+ }
+ }
+
+ return true
+ }
+}
+
+Object.defineProperties(Cache.prototype, {
+ [Symbol.toStringTag]: {
+ value: 'Cache',
+ configurable: true
+ },
+ match: kEnumerableProperty,
+ matchAll: kEnumerableProperty,
+ add: kEnumerableProperty,
+ addAll: kEnumerableProperty,
+ put: kEnumerableProperty,
+ delete: kEnumerableProperty,
+ keys: kEnumerableProperty
+})
+
+const cacheQueryOptionConverters = [
+ {
+ key: 'ignoreSearch',
+ converter: webidl.converters.boolean,
+ defaultValue: false
+ },
+ {
+ key: 'ignoreMethod',
+ converter: webidl.converters.boolean,
+ defaultValue: false
+ },
+ {
+ key: 'ignoreVary',
+ converter: webidl.converters.boolean,
+ defaultValue: false
+ }
+]
+
+webidl.converters.CacheQueryOptions = webidl.dictionaryConverter(cacheQueryOptionConverters)
+
+webidl.converters.MultiCacheQueryOptions = webidl.dictionaryConverter([
+ ...cacheQueryOptionConverters,
+ {
+ key: 'cacheName',
+ converter: webidl.converters.DOMString
+ }
+])
+
+webidl.converters.Response = webidl.interfaceConverter(Response)
+
+webidl.converters['sequence<RequestInfo>'] = webidl.sequenceConverter(
+ webidl.converters.RequestInfo
+)
+
+module.exports = {
+ Cache
+}
diff --git a/deps/undici/src/lib/cache/cachestorage.js b/deps/undici/src/lib/cache/cachestorage.js
new file mode 100644
index 0000000000..7e7f0cff2b
--- /dev/null
+++ b/deps/undici/src/lib/cache/cachestorage.js
@@ -0,0 +1,144 @@
+'use strict'
+
+const { kConstruct } = require('./symbols')
+const { Cache } = require('./cache')
+const { webidl } = require('../fetch/webidl')
+const { kEnumerableProperty } = require('../core/util')
+
+class CacheStorage {
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#dfn-relevant-name-to-cache-map
+ * @type {Map<string, import('./cache').requestResponseList}
+ */
+ #caches = new Map()
+
+ constructor () {
+ if (arguments[0] !== kConstruct) {
+ webidl.illegalConstructor()
+ }
+ }
+
+ async match (request, options = {}) {
+ webidl.brandCheck(this, CacheStorage)
+ webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.match' })
+
+ request = webidl.converters.RequestInfo(request)
+ options = webidl.converters.MultiCacheQueryOptions(options)
+
+ // 1.
+ if (options.cacheName != null) {
+ // 1.1.1.1
+ if (this.#caches.has(options.cacheName)) {
+ // 1.1.1.1.1
+ const cacheList = this.#caches.get(options.cacheName)
+ const cache = new Cache(kConstruct, cacheList)
+
+ return await cache.match(request, options)
+ }
+ } else { // 2.
+ // 2.2
+ for (const cacheList of this.#caches.values()) {
+ const cache = new Cache(kConstruct, cacheList)
+
+ // 2.2.1.2
+ const response = await cache.match(request, options)
+
+ if (response !== undefined) {
+ return response
+ }
+ }
+ }
+ }
+
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#cache-storage-has
+ * @param {string} cacheName
+ * @returns {Promise<boolean>}
+ */
+ async has (cacheName) {
+ webidl.brandCheck(this, CacheStorage)
+ webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.has' })
+
+ cacheName = webidl.converters.DOMString(cacheName)
+
+ // 2.1.1
+ // 2.2
+ return this.#caches.has(cacheName)
+ }
+
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#dom-cachestorage-open
+ * @param {string} cacheName
+ * @returns {Promise<Cache>}
+ */
+ async open (cacheName) {
+ webidl.brandCheck(this, CacheStorage)
+ webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.open' })
+
+ cacheName = webidl.converters.DOMString(cacheName)
+
+ // 2.1
+ if (this.#caches.has(cacheName)) {
+ // await caches.open('v1') !== await caches.open('v1')
+
+ // 2.1.1
+ const cache = this.#caches.get(cacheName)
+
+ // 2.1.1.1
+ return new Cache(kConstruct, cache)
+ }
+
+ // 2.2
+ const cache = []
+
+ // 2.3
+ this.#caches.set(cacheName, cache)
+
+ // 2.4
+ return new Cache(kConstruct, cache)
+ }
+
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#cache-storage-delete
+ * @param {string} cacheName
+ * @returns {Promise<boolean>}
+ */
+ async delete (cacheName) {
+ webidl.brandCheck(this, CacheStorage)
+ webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.delete' })
+
+ cacheName = webidl.converters.DOMString(cacheName)
+
+ return this.#caches.delete(cacheName)
+ }
+
+ /**
+ * @see https://w3c.github.io/ServiceWorker/#cache-storage-keys
+ * @returns {string[]}
+ */
+ async keys () {
+ webidl.brandCheck(this, CacheStorage)
+
+ // 2.1
+ const keys = this.#caches.keys()
+
+ // 2.2
+ return [...keys]
+ }
+}
+
+Object.defineProperties(CacheStorage.prototype, {
+ [Symbol.toStringTag]: {
+ value: 'CacheStorage',
+ configurable: true
+ },
+ match: kEnumerableProperty,
+ has: kEnumerableProperty,
+ open: kEnumerableProperty,
+ delete: kEnumerableProperty,
+ keys: kEnumerableProperty
+})
+
+module.exports = {
+ CacheStorage
+}
diff --git a/deps/undici/src/lib/cache/symbols.js b/deps/undici/src/lib/cache/symbols.js
new file mode 100644
index 0000000000..f9b19740af
--- /dev/null
+++ b/deps/undici/src/lib/cache/symbols.js
@@ -0,0 +1,5 @@
+'use strict'
+
+module.exports = {
+ kConstruct: Symbol('constructable')
+}
diff --git a/deps/undici/src/lib/cache/util.js b/deps/undici/src/lib/cache/util.js
new file mode 100644
index 0000000000..44d52b789e
--- /dev/null
+++ b/deps/undici/src/lib/cache/util.js
@@ -0,0 +1,49 @@
+'use strict'
+
+const assert = require('assert')
+const { URLSerializer } = require('../fetch/dataURL')
+const { isValidHeaderName } = require('../fetch/util')
+
+/**
+ * @see https://url.spec.whatwg.org/#concept-url-equals
+ * @param {URL} A
+ * @param {URL} B
+ * @param {boolean | undefined} excludeFragment
+ * @returns {boolean}
+ */
+function urlEquals (A, B, excludeFragment = false) {
+ const serializedA = URLSerializer(A, excludeFragment)
+
+ const serializedB = URLSerializer(B, excludeFragment)
+
+ return serializedA === serializedB
+}
+
+/**
+ * @see https://github.com/chromium/chromium/blob/694d20d134cb553d8d89e5500b9148012b1ba299/content/browser/cache_storage/cache_storage_cache.cc#L260-L262
+ * @param {string} header
+ */
+function fieldValues (header) {
+ assert(header !== null)
+
+ const values = []
+
+ for (let value of header.split(',')) {
+ value = value.trim()
+
+ if (!value.length) {
+ continue
+ } else if (!isValidHeaderName(value)) {
+ continue
+ }
+
+ values.push(value)
+ }
+
+ return values
+}
+
+module.exports = {
+ urlEquals,
+ fieldValues
+}
diff --git a/deps/undici/src/lib/client.js b/deps/undici/src/lib/client.js
index 688df9e615..7d9ec8d7c2 100644
--- a/deps/undici/src/lib/client.js
+++ b/deps/undici/src/lib/client.js
@@ -569,7 +569,10 @@ class Parser {
/* istanbul ignore else: difficult to make a test case for */
if (ptr) {
const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
- message = Buffer.from(llhttp.memory.buffer, ptr, len).toString()
+ message =
+ 'Response does not match the HTTP/1.1 protocol (' +
+ Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
+ ')'
}
throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset))
}
@@ -1494,9 +1497,11 @@ function writeStream ({ body, client, request, socket, contentLength, header, ex
const writer = new AsyncWriter({ socket, request, contentLength, client, expectsPayload, header })
const onData = function (chunk) {
- try {
- assert(!finished)
+ if (finished) {
+ return
+ }
+ try {
if (!writer.write(chunk) && this.pause) {
this.pause()
}
@@ -1505,7 +1510,9 @@ function writeStream ({ body, client, request, socket, contentLength, header, ex
}
}
const onDrain = function () {
- assert(!finished)
+ if (finished) {
+ return
+ }
if (body.resume) {
body.resume()
diff --git a/deps/undici/src/lib/fetch/body.js b/deps/undici/src/lib/fetch/body.js
index c291afa936..db450ee6bd 100644
--- a/deps/undici/src/lib/fetch/body.js
+++ b/deps/undici/src/lib/fetch/body.js
@@ -123,6 +123,7 @@ function extractBody (object, keepalive = false) {
const blobParts = []
const rn = new Uint8Array([13, 10]) // '\r\n'
length = 0
+ let hasUnknownSizeValue = false
for (const [name, value] of object) {
if (typeof value === 'string') {
@@ -138,13 +139,20 @@ function extractBody (object, keepalive = false) {
value.type || 'application/octet-stream'
}\r\n\r\n`)
blobParts.push(chunk, value, rn)
- length += chunk.byteLength + value.size + rn.byteLength
+ if (typeof value.size === 'number') {
+ length += chunk.byteLength + value.size + rn.byteLength
+ } else {
+ hasUnknownSizeValue = true
+ }
}
}
const chunk = enc.encode(`--${boundary}--`)
blobParts.push(chunk)
length += chunk.byteLength
+ if (hasUnknownSizeValue) {
+ length = null
+ }
// Set source to object.
source = object
diff --git a/deps/undici/src/lib/fetch/dataURL.js b/deps/undici/src/lib/fetch/dataURL.js
index beefad1548..6df4fcc8cc 100644
--- a/deps/undici/src/lib/fetch/dataURL.js
+++ b/deps/undici/src/lib/fetch/dataURL.js
@@ -1,14 +1,18 @@
const assert = require('assert')
const { atob } = require('buffer')
-const { isValidHTTPToken, isomorphicDecode } = require('./util')
+const { isomorphicDecode } = require('./util')
const encoder = new TextEncoder()
-// Regex
-const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-z0-9]+$/
+/**
+ * @see https://mimesniff.spec.whatwg.org/#http-token-code-point
+ */
+const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-Za-z0-9]+$/
const HTTP_WHITESPACE_REGEX = /(\u000A|\u000D|\u0009|\u0020)/ // eslint-disable-line
-// https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point
-const HTTP_QUOTED_STRING_TOKENS = /^(\u0009|\x{0020}-\x{007E}|\x{0080}-\x{00FF})+$/ // eslint-disable-line
+/**
+ * @see https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point
+ */
+const HTTP_QUOTED_STRING_TOKENS = /[\u0009|\u0020-\u007E|\u0080-\u00FF]/ // eslint-disable-line
// https://fetch.spec.whatwg.org/#data-url-processor
/** @param {URL} dataURL */
@@ -38,14 +42,12 @@ function dataURLProcessor (dataURL) {
// 6. Strip leading and trailing ASCII whitespace
// from mimeType.
- // Note: This will only remove U+0020 SPACE code
- // points, if any.
// Undici implementation note: we need to store the
// length because if the mimetype has spaces removed,
// the wrong amount will be sliced from the input in
// step #9
const mimeTypeLength = mimeType.length
- mimeType = mimeType.replace(/^(\u0020)+|(\u0020)+$/g, '')
+ mimeType = removeASCIIWhitespace(mimeType, true, true)
// 7. If position is past the end of input, then
// return failure
@@ -233,7 +235,7 @@ function percentDecode (input) {
function parseMIMEType (input) {
// 1. Remove any leading and trailing HTTP whitespace
// from input.
- input = input.trim()
+ input = removeHTTPWhitespace(input, true, true)
// 2. Let position be a position variable for input,
// initially pointing at the start of input.
@@ -274,7 +276,7 @@ function parseMIMEType (input) {
)
// 8. Remove any trailing HTTP whitespace from subtype.
- subtype = subtype.trimEnd()
+ subtype = removeHTTPWhitespace(subtype, false, true)
// 9. If subtype is the empty string or does not solely
// contain HTTP token code points, then return failure.
@@ -282,17 +284,20 @@ function parseMIMEType (input) {
return 'failure'
}
+ const typeLowercase = type.toLowerCase()
+ const subtypeLowercase = subtype.toLowerCase()
+
// 10. Let mimeType be a new MIME type record whose type
// is type, in ASCII lowercase, and subtype is subtype,
// in ASCII lowercase.
// https://mimesniff.spec.whatwg.org/#mime-type
const mimeType = {
- type: type.toLowerCase(),
- subtype: subtype.toLowerCase(),
+ type: typeLowercase,
+ subtype: subtypeLowercase,
/** @type {Map<string, string>} */
parameters: new Map(),
// https://mimesniff.spec.whatwg.org/#mime-type-essence
- essence: `${type}/${subtype}`
+ essence: `${typeLowercase}/${subtypeLowercase}`
}
// 11. While position is not past the end of input:
@@ -370,8 +375,7 @@ function parseMIMEType (input) {
)
// 2. Remove any trailing HTTP whitespace from parameterValue.
- // Note: it says "trailing" whitespace; leading is fine.
- parameterValue = parameterValue.trimEnd()
+ parameterValue = removeHTTPWhitespace(parameterValue, false, true)
// 3. If parameterValue is the empty string, then continue.
if (parameterValue.length === 0) {
@@ -388,7 +392,7 @@ function parseMIMEType (input) {
if (
parameterName.length !== 0 &&
HTTP_TOKEN_CODEPOINTS.test(parameterName) &&
- !HTTP_QUOTED_STRING_TOKENS.test(parameterValue) &&
+ (parameterValue.length === 0 || HTTP_QUOTED_STRING_TOKENS.test(parameterValue)) &&
!mimeType.parameters.has(parameterName)
) {
mimeType.parameters.set(parameterName, parameterValue)
@@ -522,11 +526,11 @@ function collectAnHTTPQuotedString (input, position, extractValue) {
*/
function serializeAMimeType (mimeType) {
assert(mimeType !== 'failure')
- const { type, subtype, parameters } = mimeType
+ const { parameters, essence } = mimeType
// 1. Let serialization be the concatenation of mimeType’s
// type, U+002F (/), and mimeType’s subtype.
- let serialization = `${type}/${subtype}`
+ let serialization = essence
// 2. For each name → value of mimeType’s parameters:
for (let [name, value] of parameters.entries()) {
@@ -541,7 +545,7 @@ function serializeAMimeType (mimeType) {
// 4. If value does not solely contain HTTP token code
// points or value is the empty string, then:
- if (!isValidHTTPToken(value)) {
+ if (!HTTP_TOKEN_CODEPOINTS.test(value)) {
// 1. Precede each occurence of U+0022 (") or
// U+005C (\) in value with U+005C (\).
value = value.replace(/(\\|")/g, '\\$1')
@@ -561,6 +565,59 @@ function serializeAMimeType (mimeType) {
return serialization
}
+/**
+ * @see https://fetch.spec.whatwg.org/#http-whitespace
+ * @param {string} char
+ */
+function isHTTPWhiteSpace (char) {
+ return char === '\r' || char === '\n' || char === '\t' || char === ' '
+}
+
+/**
+ * @see https://fetch.spec.whatwg.org/#http-whitespace
+ * @param {string} str
+ */
+function removeHTTPWhitespace (str, leading = true, trailing = true) {
+ let lead = 0
+ let trail = str.length - 1
+
+ if (leading) {
+ for (; lead < str.length && isHTTPWhiteSpace(str[lead]); lead++);
+ }
+
+ if (trailing) {
+ for (; trail > 0 && isHTTPWhiteSpace(str[trail]); trail--);
+ }
+
+ return str.slice(lead, trail + 1)
+}
+
+/**
+ * @see https://infra.spec.whatwg.org/#ascii-whitespace
+ * @param {string} char
+ */
+function isASCIIWhitespace (char) {
+ return char === '\r' || char === '\n' || char === '\t' || char === '\f' || char === ' '
+}
+
+/**
+ * @see https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace
+ */
+function removeASCIIWhitespace (str, leading = true, trailing = true) {
+ let lead = 0
+ let trail = str.length - 1
+
+ if (leading) {
+ for (; lead < str.length && isASCIIWhitespace(str[lead]); lead++);
+ }
+
+ if (trailing) {
+ for (; trail > 0 && isASCIIWhitespace(str[trail]); trail--);
+ }
+
+ return str.slice(lead, trail + 1)
+}
+
module.exports = {
dataURLProcessor,
URLSerializer,
diff --git a/deps/undici/src/lib/fetch/index.js b/deps/undici/src/lib/fetch/index.js
index f3016c60dd..5199873242 100644
--- a/deps/undici/src/lib/fetch/index.js
+++ b/deps/undici/src/lib/fetch/index.js
@@ -318,7 +318,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') {
// https://w3c.github.io/resource-timing/#dfn-mark-resource-timing
function markResourceTiming (timingInfo, originalURL, initiatorType, globalThis, cacheState) {
- if (nodeMajor >= 18 && nodeMinor >= 2) {
+ if (nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 2)) {
performance.markResourceTiming(timingInfo, originalURL, initiatorType, globalThis, cacheState)
}
}
diff --git a/deps/undici/src/lib/fetch/response.js b/deps/undici/src/lib/fetch/response.js
index ff06bfb47d..1029dbef53 100644
--- a/deps/undici/src/lib/fetch/response.js
+++ b/deps/undici/src/lib/fetch/response.js
@@ -467,7 +467,7 @@ function initializeResponse (response, init, body) {
// 5. If init["headers"] exists, then fill response’s headers with init["headers"].
if ('headers' in init && init.headers != null) {
- fill(response[kState].headersList, init.headers)
+ fill(response[kHeaders], init.headers)
}
// 6. If body was given, then:
@@ -569,5 +569,6 @@ module.exports = {
makeResponse,
makeAppropriateNetworkError,
filterResponse,
- Response
+ Response,
+ cloneResponse
}
diff --git a/deps/undici/src/lib/fetch/util.js b/deps/undici/src/lib/fetch/util.js
index 23023262d1..400687ba2e 100644
--- a/deps/undici/src/lib/fetch/util.js
+++ b/deps/undici/src/lib/fetch/util.js
@@ -1028,5 +1028,6 @@ module.exports = {
isomorphicDecode,
urlIsLocal,
urlHasHttpsScheme,
- urlIsHttpHttpsScheme
+ urlIsHttpHttpsScheme,
+ readAllBytes
}
diff --git a/deps/undici/src/lib/fetch/webidl.js b/deps/undici/src/lib/fetch/webidl.js
index e55de13950..38a05e6575 100644
--- a/deps/undici/src/lib/fetch/webidl.js
+++ b/deps/undici/src/lib/fetch/webidl.js
@@ -51,6 +51,13 @@ webidl.argumentLengthCheck = function ({ length }, min, ctx) {
}
}
+webidl.illegalConstructor = function () {
+ throw webidl.errors.exception({
+ header: 'TypeError',
+ message: 'Illegal constructor'
+ })
+}
+
// https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values
webidl.util.Type = function (V) {
switch (typeof V) {
diff --git a/deps/undici/src/lib/websocket/connection.js b/deps/undici/src/lib/websocket/connection.js
index 09770247e3..8c821899f6 100644
--- a/deps/undici/src/lib/websocket/connection.js
+++ b/deps/undici/src/lib/websocket/connection.js
@@ -13,7 +13,9 @@ const { fireEvent, failWebsocketConnection } = require('./util')
const { CloseEvent } = require('./events')
const { makeRequest } = require('../fetch/request')
const { fetching } = require('../fetch/index')
+const { Headers } = require('../fetch/headers')
const { getGlobalDispatcher } = require('../global')
+const { kHeadersList } = require('../core/symbols')
const channels = {}
channels.open = diagnosticsChannel.channel('undici:websocket:open')
@@ -26,8 +28,9 @@ channels.socketError = diagnosticsChannel.channel('undici:websocket:socket_error
* @param {string|string[]} protocols
* @param {import('./websocket').WebSocket} ws
* @param {(response: any) => void} onEstablish
+ * @param {Partial<import('../../types/websocket').WebSocketInit>} options
*/
-function establishWebSocketConnection (url, protocols, ws, onEstablish) {
+function establishWebSocketConnection (url, protocols, ws, onEstablish, options) {
// 1. Let requestURL be a copy of url, with its scheme set to "http", if url’s
// scheme is "ws", and to "https" otherwise.
const requestURL = url
@@ -48,6 +51,13 @@ function establishWebSocketConnection (url, protocols, ws, onEstablish) {
redirect: 'error'
})
+ // Note: undici extension, allow setting custom headers.
+ if (options.headers) {
+ const headersList = new Headers(options.headers)[kHeadersList]
+
+ request.headersList = headersList
+ }
+
// 3. Append (`Upgrade`, `websocket`) to request’s header list.
// 4. Append (`Connection`, `Upgrade`) to request’s header list.
// Note: both of these are handled by undici currently.
@@ -88,7 +98,7 @@ function establishWebSocketConnection (url, protocols, ws, onEstablish) {
const controller = fetching({
request,
useParallelQueue: true,
- dispatcher: getGlobalDispatcher(),
+ dispatcher: options.dispatcher ?? getGlobalDispatcher(),
processResponse (response) {
// 1. If response is a network error or its status is not 101,
// fail the WebSocket connection.
diff --git a/deps/undici/src/lib/websocket/frame.js b/deps/undici/src/lib/websocket/frame.js
index 1df5e16934..61bfd3915c 100644
--- a/deps/undici/src/lib/websocket/frame.js
+++ b/deps/undici/src/lib/websocket/frame.js
@@ -43,7 +43,7 @@ class WebsocketFrameSend {
buffer[1] = payloadLength
if (payloadLength === 126) {
- new DataView(buffer.buffer).setUint16(2, bodyLength)
+ buffer.writeUInt16BE(bodyLength, 2)
} else if (payloadLength === 127) {
// Clear extended payload length
buffer[2] = buffer[3] = 0
diff --git a/deps/undici/src/lib/websocket/websocket.js b/deps/undici/src/lib/websocket/websocket.js
index 164d24c6f8..22ad2fb11a 100644
--- a/deps/undici/src/lib/websocket/websocket.js
+++ b/deps/undici/src/lib/websocket/websocket.js
@@ -18,6 +18,7 @@ const { establishWebSocketConnection } = require('./connection')
const { WebsocketFrameSend } = require('./frame')
const { ByteParser } = require('./receiver')
const { kEnumerableProperty, isBlobLike } = require('../core/util')
+const { getGlobalDispatcher } = require('../global')
const { types } = require('util')
let experimentalWarned = false
@@ -51,8 +52,10 @@ class WebSocket extends EventTarget {
})
}
+ const options = webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'](protocols)
+
url = webidl.converters.USVString(url)
- protocols = webidl.converters['DOMString or sequence<DOMString>'](protocols)
+ protocols = options.protocols
// 1. Let urlRecord be the result of applying the URL parser to url.
let urlRecord
@@ -110,7 +113,8 @@ class WebSocket extends EventTarget {
urlRecord,
protocols,
this,
- (response) => this.#onConnectionEstablished(response)
+ (response) => this.#onConnectionEstablished(response),
+ options
)
// Each WebSocket object has an associated ready state, which is a
@@ -577,6 +581,36 @@ webidl.converters['DOMString or sequence<DOMString>'] = function (V) {
return webidl.converters.DOMString(V)
}
+// This implements the propsal made in https://github.com/whatwg/websockets/issues/42
+webidl.converters.WebSocketInit = webidl.dictionaryConverter([
+ {
+ key: 'protocols',
+ converter: webidl.converters['DOMString or sequence<DOMString>'],
+ get defaultValue () {
+ return []
+ }
+ },
+ {
+ key: 'dispatcher',
+ converter: (V) => V,
+ get defaultValue () {
+ return getGlobalDispatcher()
+ }
+ },
+ {
+ key: 'headers',
+ converter: webidl.nullableConverter(webidl.converters.HeadersInit)
+ }
+])
+
+webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'] = function (V) {
+ if (webidl.util.Type(V) === 'Object' && !(Symbol.iterator in V)) {
+ return webidl.converters.WebSocketInit(V)
+ }
+
+ return { protocols: webidl.converters['DOMString or sequence<DOMString>'](V) }
+}
+
webidl.converters.WebSocketSendData = function (V) {
if (webidl.util.Type(V) === 'Object') {
if (isBlobLike(V)) {
diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json
index 481a6c8810..49b657fded 100644
--- a/deps/undici/src/package.json
+++ b/deps/undici/src/package.json
@@ -1,6 +1,6 @@
{
"name": "undici",
- "version": "5.22.0",
+ "version": "5.22.1",
"description": "An HTTP/1.1 client, written from scratch for Node.js",
"homepage": "https://undici.nodejs.org",
"bugs": {
@@ -42,13 +42,13 @@
],
"scripts": {
"build:node": "npx esbuild@0.14.38 index-fetch.js --bundle --platform=node --outfile=undici-fetch.js",
- "prebuild:wasm": "docker build -t llhttp_wasm_builder -f build/Dockerfile .",
+ "prebuild:wasm": "node build/wasm.js --prebuild",
"build:wasm": "node build/wasm.js --docker",
"lint": "standard | snazzy",
"lint:fix": "standard --fix | snazzy",
"test": "npm run test:tap && npm run test:node-fetch && npm run test:fetch && npm run test:cookies && npm run test:wpt && npm run test:websocket && npm run test:jest && npm run test:typescript",
"test:cookies": "node scripts/verifyVersion 16 || tap test/cookie/*.js",
- "test:node-fetch": "node scripts/verifyVersion.js 16 || mocha test/node-fetch",
+ "test:node-fetch": "node scripts/verifyVersion.js 16 || mocha --exit test/node-fetch",
"test:fetch": "node scripts/verifyVersion.js 16 || (npm run build:node && tap --expose-gc test/fetch/*.js && tap test/webidl/*.js)",
"test:jest": "node scripts/verifyVersion.js 14 || jest",
"test:tap": "tap test/*.js test/diagnostics-channel/*.js",
@@ -61,7 +61,7 @@
"bench": "PORT=3042 concurrently -k -s first npm:bench:server npm:bench:run",
"bench:server": "node benchmarks/server.js",
"prebench:run": "node benchmarks/wait.js",
- "bench:run": "CONNECTIONS=1 node --experimental-wasm-simd benchmarks/benchmark.js; CONNECTIONS=50 node --experimental-wasm-simd benchmarks/benchmark.js",
+ "bench:run": "CONNECTIONS=1 node benchmarks/benchmark.js; CONNECTIONS=50 node benchmarks/benchmark.js",
"serve:website": "docsify serve .",
"prepare": "husky install",
"fuzz": "jsfuzz test/fuzzing/fuzz.js corpus"
diff --git a/deps/undici/src/types/cache.d.ts b/deps/undici/src/types/cache.d.ts
new file mode 100644
index 0000000000..4c33335766
--- /dev/null
+++ b/deps/undici/src/types/cache.d.ts
@@ -0,0 +1,36 @@
+import type { RequestInfo, Response, Request } from './fetch'
+
+export interface CacheStorage {
+ match (request: RequestInfo, options?: MultiCacheQueryOptions): Promise<Response | undefined>,
+ has (cacheName: string): Promise<boolean>,
+ open (cacheName: string): Promise<Cache>,
+ delete (cacheName: string): Promise<boolean>,
+ keys (): Promise<string[]>
+}
+
+declare const CacheStorage: {
+ prototype: CacheStorage
+ new(): CacheStorage
+}
+
+export interface Cache {
+ match (request: RequestInfo, options?: CacheQueryOptions): Promise<Response | undefined>,
+ matchAll (request?: RequestInfo, options?: CacheQueryOptions): Promise<readonly Response[]>,
+ add (request: RequestInfo): Promise<undefined>,
+ addAll (requests: RequestInfo[]): Promise<undefined>,
+ put (request: RequestInfo, response: Response): Promise<undefined>,
+ delete (request: RequestInfo, options?: CacheQueryOptions): Promise<boolean>,
+ keys (request?: RequestInfo, options?: CacheQueryOptions): Promise<readonly Request[]>
+}
+
+export interface CacheQueryOptions {
+ ignoreSearch?: boolean,
+ ignoreMethod?: boolean,
+ ignoreVary?: boolean
+}
+
+export interface MultiCacheQueryOptions extends CacheQueryOptions {
+ cacheName?: string
+}
+
+export declare const caches: CacheStorage
diff --git a/deps/undici/src/types/errors.d.ts b/deps/undici/src/types/errors.d.ts
index fd2ce7c3a9..7923ddd979 100644
--- a/deps/undici/src/types/errors.d.ts
+++ b/deps/undici/src/types/errors.d.ts
@@ -4,7 +4,10 @@ import Client from './client'
export default Errors
declare namespace Errors {
- export class UndiciError extends Error { }
+ export class UndiciError extends Error {
+ name: string;
+ code: string;
+ }
/** Connect timeout error. */
export class ConnectTimeoutError extends UndiciError {
@@ -31,6 +34,12 @@ declare namespace Errors {
}
export class ResponseStatusCodeError extends UndiciError {
+ constructor (
+ message?: string,
+ statusCode?: number,
+ headers?: IncomingHttpHeaders | string[] | null,
+ body?: null | Record<string, any> | string
+ );
name: 'ResponseStatusCodeError';
code: 'UND_ERR_RESPONSE_STATUS_CODE';
body: null | Record<string, any> | string
diff --git a/deps/undici/src/types/webidl.d.ts b/deps/undici/src/types/webidl.d.ts
index 182d18e0d4..40cfe064f8 100644
--- a/deps/undici/src/types/webidl.d.ts
+++ b/deps/undici/src/types/webidl.d.ts
@@ -170,6 +170,8 @@ export interface Webidl {
*/
sequenceConverter <Type>(C: Converter<Type>): SequenceConverter<Type>
+ illegalConstructor (): never
+
/**
* @see https://webidl.spec.whatwg.org/#es-to-record
* @description Convert a value, V, to a WebIDL record type.
diff --git a/deps/undici/src/types/websocket.d.ts b/deps/undici/src/types/websocket.d.ts
index 7524cbda6c..15a357d36d 100644
--- a/deps/undici/src/types/websocket.d.ts
+++ b/deps/undici/src/types/websocket.d.ts
@@ -10,6 +10,8 @@ import {
AddEventListenerOptions,
EventListenerOrEventListenerObject
} from './patch'
+import Dispatcher from './dispatcher'
+import { HeadersInit } from './fetch'
export type BinaryType = 'blob' | 'arraybuffer'
@@ -67,7 +69,7 @@ interface WebSocket extends EventTarget {
export declare const WebSocket: {
prototype: WebSocket
- new (url: string | URL, protocols?: string | string[]): WebSocket
+ new (url: string | URL, protocols?: string | string[] | WebSocketInit): WebSocket
readonly CLOSED: number
readonly CLOSING: number
readonly CONNECTING: number
@@ -121,3 +123,9 @@ export declare const MessageEvent: {
prototype: MessageEvent
new<T>(type: string, eventInitDict?: MessageEventInit<T>): MessageEvent<T>
}
+
+interface WebSocketInit {
+ protocols?: string | string[],
+ dispatcher?: Dispatcher,
+ headers?: HeadersInit
+}
diff --git a/deps/undici/undici.js b/deps/undici/undici.js
index 8eacb283d3..8b0bfaef59 100644
--- a/deps/undici/undici.js
+++ b/deps/undici/undici.js
@@ -1356,7 +1356,8 @@ var require_util2 = __commonJS({
isomorphicDecode,
urlIsLocal,
urlHasHttpsScheme,
- urlIsHttpHttpsScheme
+ urlIsHttpHttpsScheme,
+ readAllBytes
};
}
});
@@ -1403,6 +1404,12 @@ var require_webidl = __commonJS({
});
}
};
+ webidl.illegalConstructor = function() {
+ throw webidl.errors.exception({
+ header: "TypeError",
+ message: "Illegal constructor"
+ });
+ };
webidl.util.Type = function(V) {
switch (typeof V) {
case "undefined":
@@ -5734,11 +5741,11 @@ var require_dataURL = __commonJS({
"lib/fetch/dataURL.js"(exports2, module2) {
var assert = require("assert");
var { atob: atob2 } = require("buffer");
- var { isValidHTTPToken, isomorphicDecode } = require_util2();
+ var { isomorphicDecode } = require_util2();
var encoder = new TextEncoder();
- var HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-z0-9]+$/;
+ var HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-Za-z0-9]+$/;
var HTTP_WHITESPACE_REGEX = /(\u000A|\u000D|\u0009|\u0020)/;
- var HTTP_QUOTED_STRING_TOKENS = /^(\u0009|\x{0020}-\x{007E}|\x{0080}-\x{00FF})+$/;
+ var HTTP_QUOTED_STRING_TOKENS = /[\u0009|\u0020-\u007E|\u0080-\u00FF]/;
function dataURLProcessor(dataURL) {
assert(dataURL.protocol === "data:");
let input = URLSerializer(dataURL, true);
@@ -5746,7 +5753,7 @@ var require_dataURL = __commonJS({
const position = { position: 0 };
let mimeType = collectASequenceOfCodePointsFast(",", input, position);
const mimeTypeLength = mimeType.length;
- mimeType = mimeType.replace(/^(\u0020)+|(\u0020)+$/g, "");
+ mimeType = removeASCIIWhitespace(mimeType, true, true);
if (position.position >= input.length) {
return "failure";
}
@@ -5823,7 +5830,7 @@ var require_dataURL = __commonJS({
return Uint8Array.from(output);
}
function parseMIMEType(input) {
- input = input.trim();
+ input = removeHTTPWhitespace(input, true, true);
const position = { position: 0 };
const type = collectASequenceOfCodePointsFast("/", input, position);
if (type.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(type)) {
@@ -5834,15 +5841,17 @@ var require_dataURL = __commonJS({
}
position.position++;
let subtype = collectASequenceOfCodePointsFast(";", input, position);
- subtype = subtype.trimEnd();
+ subtype = removeHTTPWhitespace(subtype, false, true);
if (subtype.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(subtype)) {
return "failure";
}
+ const typeLowercase = type.toLowerCase();
+ const subtypeLowercase = subtype.toLowerCase();
const mimeType = {
- type: type.toLowerCase(),
- subtype: subtype.toLowerCase(),
+ type: typeLowercase,
+ subtype: subtypeLowercase,
parameters: /* @__PURE__ */ new Map(),
- essence: `${type}/${subtype}`
+ essence: `${typeLowercase}/${subtypeLowercase}`
};
while (position.position < input.length) {
position.position++;
@@ -5864,12 +5873,12 @@ var require_dataURL = __commonJS({
collectASequenceOfCodePointsFast(";", input, position);
} else {
parameterValue = collectASequenceOfCodePointsFast(";", input, position);
- parameterValue = parameterValue.trimEnd();
+ parameterValue = removeHTTPWhitespace(parameterValue, false, true);
if (parameterValue.length === 0) {
continue;
}
}
- if (parameterName.length !== 0 && HTTP_TOKEN_CODEPOINTS.test(parameterName) && !HTTP_QUOTED_STRING_TOKENS.test(parameterValue) && !mimeType.parameters.has(parameterName)) {
+ if (parameterName.length !== 0 && HTTP_TOKEN_CODEPOINTS.test(parameterName) && (parameterValue.length === 0 || HTTP_QUOTED_STRING_TOKENS.test(parameterValue)) && !mimeType.parameters.has(parameterName)) {
mimeType.parameters.set(parameterName, parameterValue);
}
}
@@ -5924,13 +5933,13 @@ var require_dataURL = __commonJS({
}
function serializeAMimeType(mimeType) {
assert(mimeType !== "failure");
- const { type, subtype, parameters } = mimeType;
- let serialization = `${type}/${subtype}`;
+ const { parameters, essence } = mimeType;
+ let serialization = essence;
for (let [name, value] of parameters.entries()) {
serialization += ";";
serialization += name;
serialization += "=";
- if (!isValidHTTPToken(value)) {
+ if (!HTTP_TOKEN_CODEPOINTS.test(value)) {
value = value.replace(/(\\|")/g, "\\$1");
value = '"' + value;
value += '"';
@@ -5939,6 +5948,38 @@ var require_dataURL = __commonJS({
}
return serialization;
}
+ function isHTTPWhiteSpace(char) {
+ return char === "\r" || char === "\n" || char === " " || char === " ";
+ }
+ function removeHTTPWhitespace(str, leading = true, trailing = true) {
+ let lead = 0;
+ let trail = str.length - 1;
+ if (leading) {
+ for (; lead < str.length && isHTTPWhiteSpace(str[lead]); lead++)
+ ;
+ }
+ if (trailing) {
+ for (; trail > 0 && isHTTPWhiteSpace(str[trail]); trail--)
+ ;
+ }
+ return str.slice(lead, trail + 1);
+ }
+ function isASCIIWhitespace(char) {
+ return char === "\r" || char === "\n" || char === " " || char === "\f" || char === " ";
+ }
+ function removeASCIIWhitespace(str, leading = true, trailing = true) {
+ let lead = 0;
+ let trail = str.length - 1;
+ if (leading) {
+ for (; lead < str.length && isASCIIWhitespace(str[lead]); lead++)
+ ;
+ }
+ if (trailing) {
+ for (; trail > 0 && isASCIIWhitespace(str[trail]); trail--)
+ ;
+ }
+ return str.slice(lead, trail + 1);
+ }
module2.exports = {
dataURLProcessor,
URLSerializer,
@@ -6339,6 +6380,7 @@ Content-Disposition: form-data`;
const blobParts = [];
const rn = new Uint8Array([13, 10]);
length = 0;
+ let hasUnknownSizeValue = false;
for (const [name, value] of object) {
if (typeof value === "string") {
const chunk2 = enc.encode(prefix + `; name="${escape(normalizeLinefeeds(name))}"\r
@@ -6353,12 +6395,19 @@ Content-Type: ${value.type || "application/octet-stream"}\r
\r
`);
blobParts.push(chunk2, value, rn);
- length += chunk2.byteLength + value.size + rn.byteLength;
+ if (typeof value.size === "number") {
+ length += chunk2.byteLength + value.size + rn.byteLength;
+ } else {
+ hasUnknownSizeValue = true;
+ }
}
}
const chunk = enc.encode(`--${boundary}--`);
blobParts.push(chunk);
length += chunk.byteLength;
+ if (hasUnknownSizeValue) {
+ length = null;
+ }
source = object;
action = async function* () {
for (const part of blobParts) {
@@ -6912,7 +6961,7 @@ var require_response = __commonJS({
response[kState].statusText = init.statusText;
}
if ("headers" in init && init.headers != null) {
- fill(response[kState].headersList, init.headers);
+ fill(response[kHeaders], init.headers);
}
if (body) {
if (nullBodyStatus.includes(response.status)) {
@@ -6978,7 +7027,8 @@ var require_response = __commonJS({
makeResponse,
makeAppropriateNetworkError,
filterResponse,
- Response
+ Response,
+ cloneResponse
};
}
});
@@ -9439,7 +9489,7 @@ var require_client = __commonJS({
let message = "";
if (ptr) {
const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0);
- message = Buffer.from(llhttp.memory.buffer, ptr, len).toString();
+ message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")";
}
throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset));
}
@@ -10108,8 +10158,10 @@ upgrade: ${upgrade}\r
let finished = false;
const writer = new AsyncWriter({ socket, request, contentLength, client, expectsPayload, header });
const onData = function(chunk) {
+ if (finished) {
+ return;
+ }
try {
- assert(!finished);
if (!writer.write(chunk) && this.pause) {
this.pause();
}
@@ -10118,7 +10170,9 @@ upgrade: ${upgrade}\r
}
};
const onDrain = function() {
- assert(!finished);
+ if (finished) {
+ return;
+ }
if (body.resume) {
body.resume();
}
@@ -10739,7 +10793,7 @@ var require_fetch = __commonJS({
markResourceTiming(timingInfo, originalURL, initiatorType, globalThis, cacheState);
}
function markResourceTiming(timingInfo, originalURL, initiatorType, globalThis2, cacheState) {
- if (nodeMajor >= 18 && nodeMinor >= 2) {
+ if (nodeMajor > 18 || nodeMajor === 18 && nodeMinor >= 2) {
performance.markResourceTiming(timingInfo, originalURL, initiatorType, globalThis2, cacheState);
}
}
diff --git a/src/undici_version.h b/src/undici_version.h
index db62dda4e1..af56664e3f 100644
--- a/src/undici_version.h
+++ b/src/undici_version.h
@@ -2,5 +2,5 @@
// Refer to tools/update-undici.sh
#ifndef SRC_UNDICI_VERSION_H_
#define SRC_UNDICI_VERSION_H_
-#define UNDICI_VERSION "5.22.0"
+#define UNDICI_VERSION "5.22.1"
#endif // SRC_UNDICI_VERSION_H_