mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 13:48:44 +02:00
deps: update undici to 5.11.0
PR-URL: https://github.com/nodejs/node/pull/44929 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
This commit is contained in:
parent
87d2ca9b07
commit
d654b27d1b
72 changed files with 10479 additions and 858 deletions
44
deps/undici/src/README.md
vendored
44
deps/undici/src/README.md
vendored
|
@ -185,12 +185,12 @@ Help us improve the test coverage by following instructions at [nodejs/undici/#9
|
|||
Basic usage example:
|
||||
|
||||
```js
|
||||
import { fetch } from 'undici';
|
||||
import { fetch } from 'undici'
|
||||
|
||||
|
||||
const res = await fetch('https://example.com')
|
||||
const json = await res.json()
|
||||
console.log(json);
|
||||
console.log(json)
|
||||
```
|
||||
|
||||
You can pass an optional dispatcher to `fetch` as:
|
||||
|
@ -225,16 +225,16 @@ A body can be of the following types:
|
|||
In this implementation of fetch, ```request.body``` now accepts ```Async Iterables```. It is not present in the [Fetch Standard.](https://fetch.spec.whatwg.org)
|
||||
|
||||
```js
|
||||
import { fetch } from "undici";
|
||||
import { fetch } from 'undici'
|
||||
|
||||
const data = {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
yield "hello";
|
||||
yield "world";
|
||||
yield 'hello'
|
||||
yield 'world'
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
await fetch("https://example.com", { body: data, method: 'POST' });
|
||||
await fetch('https://example.com', { body: data, method: 'POST' })
|
||||
```
|
||||
|
||||
#### `response.body`
|
||||
|
@ -242,12 +242,12 @@ await fetch("https://example.com", { body: data, method: 'POST' });
|
|||
Nodejs has two kinds of streams: [web streams](https://nodejs.org/dist/latest-v16.x/docs/api/webstreams.html), which follow the API of the WHATWG web standard found in browsers, and an older Node-specific [streams API](https://nodejs.org/api/stream.html). `response.body` returns a readable web stream. If you would prefer to work with a Node stream you can convert a web stream using `.fromWeb()`.
|
||||
|
||||
```js
|
||||
import { fetch } from 'undici';
|
||||
import { Readable } from 'node:stream';
|
||||
import { fetch } from 'undici'
|
||||
import { Readable } from 'node:stream'
|
||||
|
||||
const response = await fetch('https://example.com')
|
||||
const readableWebStream = response.body;
|
||||
const readableNodeStream = Readable.fromWeb(readableWebStream);
|
||||
const readableWebStream = response.body
|
||||
const readableNodeStream = Readable.fromWeb(readableWebStream)
|
||||
```
|
||||
|
||||
#### Specification Compliance
|
||||
|
@ -329,6 +329,28 @@ Gets the global dispatcher used by Common API Methods.
|
|||
|
||||
Returns: `Dispatcher`
|
||||
|
||||
### `undici.setGlobalOrigin(origin)`
|
||||
|
||||
* origin `string | URL | undefined`
|
||||
|
||||
Sets the global origin used in `fetch`.
|
||||
|
||||
If `undefined` is passed, the global origin will be reset. This will cause `Response.redirect`, `new Request()`, and `fetch` to throw an error when a relative path is passed.
|
||||
|
||||
```js
|
||||
setGlobalOrigin('http://localhost:3000')
|
||||
|
||||
const response = await fetch('/api/ping')
|
||||
|
||||
console.log(response.url) // http://localhost:3000/api/ping
|
||||
```
|
||||
|
||||
### `undici.getGlobalOrigin()`
|
||||
|
||||
Gets the global origin used in `fetch`.
|
||||
|
||||
Returns: `URL`
|
||||
|
||||
### `UrlObject`
|
||||
|
||||
* **port** `string | number` (optional)
|
||||
|
|
3
deps/undici/src/docs/api/Agent.md
vendored
3
deps/undici/src/docs/api/Agent.md
vendored
|
@ -16,10 +16,11 @@ Returns: `Agent`
|
|||
|
||||
### Parameter: `AgentOptions`
|
||||
|
||||
Extends: [`ClientOptions`](Pool.md#parameter-pooloptions)
|
||||
Extends: [`PoolOptions`](Pool.md#parameter-pooloptions)
|
||||
|
||||
* **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Pool(origin, opts)`
|
||||
* **maxRedirections** `Integer` - Default: `0`. The number of HTTP redirection to follow unless otherwise specified in `DispatchOptions`.
|
||||
* **interceptors** `{ Agent: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). Note that the behavior of interceptors is Experimental and might change at any given time.
|
||||
|
||||
## Instance Properties
|
||||
|
||||
|
|
1
deps/undici/src/docs/api/Client.md
vendored
1
deps/undici/src/docs/api/Client.md
vendored
|
@ -26,6 +26,7 @@ Returns: `Client`
|
|||
* **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections.
|
||||
* **connect** `ConnectOptions | Function | null` (optional) - Default: `null`.
|
||||
* **strictContentLength** `Boolean` (optional) - Default: `true` - Whether to treat request content length mismatches as errors. If true, an error is thrown when the request content-length header doesn't match the length of the request body.
|
||||
* **interceptors** `{ Client: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching). Note that the behavior of interceptors is Experimental and might change at any given time.
|
||||
|
||||
#### Parameter: `ConnectOptions`
|
||||
|
||||
|
|
60
deps/undici/src/docs/api/DispatchInterceptor.md
vendored
Normal file
60
deps/undici/src/docs/api/DispatchInterceptor.md
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
#Interface: DispatchInterceptor
|
||||
|
||||
Extends: `Function`
|
||||
|
||||
A function that can be applied to the `Dispatcher.Dispatch` function before it is invoked with a dispatch request.
|
||||
|
||||
This allows one to write logic to intercept both the outgoing request, and the incoming response.
|
||||
|
||||
### Parameter: `Dispatcher.Dispatch`
|
||||
|
||||
The base dispatch function you are decorating.
|
||||
|
||||
### ReturnType: `Dispatcher.Dispatch`
|
||||
|
||||
A dispatch function that has been altered to provide additional logic
|
||||
|
||||
### Basic Example
|
||||
|
||||
Here is an example of an interceptor being used to provide a JWT bearer token
|
||||
|
||||
```js
|
||||
'use strict'
|
||||
|
||||
const insertHeaderInterceptor = dispatch => {
|
||||
return function InterceptedDispatch(opts, handler){
|
||||
opts.headers.push('Authorization', 'Bearer [Some token]')
|
||||
return dispatch(opts, handler)
|
||||
}
|
||||
}
|
||||
|
||||
const client = new Client('https://localhost:3000', {
|
||||
interceptors: { Client: [insertHeaderInterceptor] }
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### Basic Example 2
|
||||
|
||||
Here is a contrived example of an interceptor stripping the headers from a response.
|
||||
|
||||
```js
|
||||
'use strict'
|
||||
|
||||
const clearHeadersInterceptor = dispatch => {
|
||||
const { DecoratorHandler } = require('undici')
|
||||
class ResultInterceptor extends DecoratorHandler {
|
||||
onHeaders (statusCode, headers, resume) {
|
||||
return super.onHeaders(statusCode, [], resume)
|
||||
}
|
||||
}
|
||||
return function InterceptedDispatch(opts, handler){
|
||||
return dispatch(opts, new ResultInterceptor(handler))
|
||||
}
|
||||
}
|
||||
|
||||
const client = new Client('https://localhost:3000', {
|
||||
interceptors: { Client: [clearHeadersInterceptor] }
|
||||
})
|
||||
|
||||
```
|
2
deps/undici/src/docs/api/MockPool.md
vendored
2
deps/undici/src/docs/api/MockPool.md
vendored
|
@ -54,7 +54,7 @@ Returns: `MockInterceptor` corresponding to the input options.
|
|||
### Parameter: `MockPoolInterceptOptions`
|
||||
|
||||
* **path** `string | RegExp | (path: string) => boolean` - a matcher for the HTTP request path.
|
||||
* **method** `string | RegExp | (method: string) => boolean` - a matcher for the HTTP request method.
|
||||
* **method** `string | RegExp | (method: string) => boolean` - (optional) - a matcher for the HTTP request method. Defaults to `GET`.
|
||||
* **body** `string | RegExp | (body: string) => boolean` - (optional) - a matcher for the HTTP request body.
|
||||
* **headers** `Record<string, string | RegExp | (body: string) => boolean`> - (optional) - a matcher for the HTTP request headers. To be intercepted, a request must match all defined headers. Extra headers not defined here may (or may not) be included in the request and do not affect the interception in any way.
|
||||
* **query** `Record<string, any> | null` - (optional) - a matcher for the HTTP request query string params.
|
||||
|
|
1
deps/undici/src/docs/api/Pool.md
vendored
1
deps/undici/src/docs/api/Pool.md
vendored
|
@ -19,6 +19,7 @@ Extends: [`ClientOptions`](Client.md#parameter-clientoptions)
|
|||
|
||||
* **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Client(origin, opts)`
|
||||
* **connections** `number | null` (optional) - Default: `null` - The number of `Client` instances to create. When set to `null`, the `Pool` instance will create an unlimited amount of `Client` instances.
|
||||
* **interceptors** `{ Pool: DispatchInterceptor[] } }` - Default: `{ Pool: [] }` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching).
|
||||
|
||||
## Instance Properties
|
||||
|
||||
|
|
9
deps/undici/src/index-fetch.js
vendored
9
deps/undici/src/index-fetch.js
vendored
|
@ -1,11 +1,16 @@
|
|||
'use strict'
|
||||
|
||||
const { getGlobalDispatcher } = require('./lib/global')
|
||||
const fetchImpl = require('./lib/fetch')
|
||||
const fetchImpl = require('./lib/fetch').fetch
|
||||
|
||||
module.exports.fetch = async function fetch (resource) {
|
||||
const dispatcher = (arguments[1] && arguments[1].dispatcher) || getGlobalDispatcher()
|
||||
return fetchImpl.apply(dispatcher, arguments)
|
||||
try {
|
||||
return await fetchImpl.apply(dispatcher, arguments)
|
||||
} catch (err) {
|
||||
Error.captureStackTrace(err, this)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
module.exports.FormData = require('./lib/fetch/formdata').FormData
|
||||
module.exports.Headers = require('./lib/fetch/headers').Headers
|
||||
|
|
10
deps/undici/src/index.d.ts
vendored
10
deps/undici/src/index.d.ts
vendored
|
@ -1,6 +1,9 @@
|
|||
import Dispatcher = require('./types/dispatcher')
|
||||
import { setGlobalDispatcher, getGlobalDispatcher } from './types/global-dispatcher'
|
||||
import { setGlobalOrigin, getGlobalOrigin } from './types/global-origin'
|
||||
import Pool = require('./types/pool')
|
||||
import { RedirectHandler, DecoratorHandler } from './types/handlers'
|
||||
|
||||
import BalancedPool = require('./types/balanced-pool')
|
||||
import Client = require('./types/client')
|
||||
import buildConnector = require('./types/connector')
|
||||
|
@ -19,14 +22,15 @@ export * from './types/formdata'
|
|||
export * from './types/diagnostics-channel'
|
||||
export { Interceptable } from './types/mock-interceptor'
|
||||
|
||||
export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent }
|
||||
export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, MockClient, MockPool, MockAgent, mockErrors, ProxyAgent, RedirectHandler, DecoratorHandler }
|
||||
export default Undici
|
||||
|
||||
declare function Undici(url: string, opts: Pool.Options): Pool
|
||||
|
||||
declare namespace Undici {
|
||||
var Dispatcher: typeof import('./types/dispatcher')
|
||||
var Pool: typeof import('./types/pool');
|
||||
var RedirectHandler: typeof import ('./types/handlers').RedirectHandler
|
||||
var DecoratorHandler: typeof import ('./types/handlers').DecoratorHandler
|
||||
var createRedirectInterceptor: typeof import ('./types/interceptors').createRedirectInterceptor
|
||||
var BalancedPool: typeof import('./types/balanced-pool');
|
||||
var Client: typeof import('./types/client');
|
||||
var buildConnector: typeof import('./types/connector');
|
||||
|
|
21
deps/undici/src/index.js
vendored
21
deps/undici/src/index.js
vendored
|
@ -16,6 +16,9 @@ const MockPool = require('./lib/mock/mock-pool')
|
|||
const mockErrors = require('./lib/mock/mock-errors')
|
||||
const ProxyAgent = require('./lib/proxy-agent')
|
||||
const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global')
|
||||
const DecoratorHandler = require('./lib/handler/DecoratorHandler')
|
||||
const RedirectHandler = require('./lib/handler/RedirectHandler')
|
||||
const createRedirectInterceptor = require('./lib/interceptor/redirectInterceptor')
|
||||
|
||||
const nodeVersion = process.versions.node.split('.')
|
||||
const nodeMajor = Number(nodeVersion[0])
|
||||
|
@ -30,6 +33,10 @@ module.exports.BalancedPool = BalancedPool
|
|||
module.exports.Agent = Agent
|
||||
module.exports.ProxyAgent = ProxyAgent
|
||||
|
||||
module.exports.DecoratorHandler = DecoratorHandler
|
||||
module.exports.RedirectHandler = RedirectHandler
|
||||
module.exports.createRedirectInterceptor = createRedirectInterceptor
|
||||
|
||||
module.exports.buildConnector = buildConnector
|
||||
module.exports.errors = errors
|
||||
|
||||
|
@ -89,16 +96,26 @@ if (nodeMajor > 16 || (nodeMajor === 16 && nodeMinor >= 8)) {
|
|||
let fetchImpl = null
|
||||
module.exports.fetch = async function fetch (resource) {
|
||||
if (!fetchImpl) {
|
||||
fetchImpl = require('./lib/fetch')
|
||||
fetchImpl = require('./lib/fetch').fetch
|
||||
}
|
||||
const dispatcher = (arguments[1] && arguments[1].dispatcher) || getGlobalDispatcher()
|
||||
return fetchImpl.apply(dispatcher, arguments)
|
||||
try {
|
||||
return await fetchImpl.apply(dispatcher, arguments)
|
||||
} catch (err) {
|
||||
Error.captureStackTrace(err, this)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
module.exports.Headers = require('./lib/fetch/headers').Headers
|
||||
module.exports.Response = require('./lib/fetch/response').Response
|
||||
module.exports.Request = require('./lib/fetch/request').Request
|
||||
module.exports.FormData = require('./lib/fetch/formdata').FormData
|
||||
module.exports.File = require('./lib/fetch/file').File
|
||||
|
||||
const { setGlobalOrigin, getGlobalOrigin } = require('./lib/fetch/global')
|
||||
|
||||
module.exports.setGlobalOrigin = setGlobalOrigin
|
||||
module.exports.getGlobalOrigin = getGlobalOrigin
|
||||
}
|
||||
|
||||
module.exports.request = makeDispatcher(api.request)
|
||||
|
|
17
deps/undici/src/lib/agent.js
vendored
17
deps/undici/src/lib/agent.js
vendored
|
@ -1,12 +1,12 @@
|
|||
'use strict'
|
||||
|
||||
const { InvalidArgumentError } = require('./core/errors')
|
||||
const { kClients, kRunning, kClose, kDestroy, kDispatch } = require('./core/symbols')
|
||||
const { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = require('./core/symbols')
|
||||
const DispatcherBase = require('./dispatcher-base')
|
||||
const Pool = require('./pool')
|
||||
const Client = require('./client')
|
||||
const util = require('./core/util')
|
||||
const RedirectHandler = require('./handler/redirect')
|
||||
const createRedirectInterceptor = require('./interceptor/redirectInterceptor')
|
||||
const { WeakRef, FinalizationRegistry } = require('./compat/dispatcher-weakref')()
|
||||
|
||||
const kOnConnect = Symbol('onConnect')
|
||||
|
@ -44,7 +44,14 @@ class Agent extends DispatcherBase {
|
|||
connect = { ...connect }
|
||||
}
|
||||
|
||||
this[kInterceptors] = options.interceptors && options.interceptors.Agent && Array.isArray(options.interceptors.Agent)
|
||||
? options.interceptors.Agent
|
||||
: [createRedirectInterceptor({ maxRedirections })]
|
||||
|
||||
this[kOptions] = { ...util.deepClone(options), connect }
|
||||
this[kOptions].interceptors = options.interceptors
|
||||
? { ...options.interceptors }
|
||||
: undefined
|
||||
this[kMaxRedirections] = maxRedirections
|
||||
this[kFactory] = factory
|
||||
this[kClients] = new Map()
|
||||
|
@ -108,12 +115,6 @@ class Agent extends DispatcherBase {
|
|||
this[kFinalizer].register(dispatcher, key)
|
||||
}
|
||||
|
||||
const { maxRedirections = this[kMaxRedirections] } = opts
|
||||
if (maxRedirections != null && maxRedirections !== 0) {
|
||||
opts = { ...opts, maxRedirections: 0 } // Stop sub dispatcher from also redirecting.
|
||||
handler = new RedirectHandler(this, maxRedirections, opts, handler)
|
||||
}
|
||||
|
||||
return dispatcher.dispatch(opts, handler)
|
||||
}
|
||||
|
||||
|
|
5
deps/undici/src/lib/balanced-pool.js
vendored
5
deps/undici/src/lib/balanced-pool.js
vendored
|
@ -13,7 +13,7 @@ const {
|
|||
kGetDispatcher
|
||||
} = require('./pool-base')
|
||||
const Pool = require('./pool')
|
||||
const { kUrl } = require('./core/symbols')
|
||||
const { kUrl, kInterceptors } = require('./core/symbols')
|
||||
const { parseOrigin } = require('./core/util')
|
||||
const kFactory = Symbol('factory')
|
||||
|
||||
|
@ -53,6 +53,9 @@ class BalancedPool extends PoolBase {
|
|||
throw new InvalidArgumentError('factory must be a function.')
|
||||
}
|
||||
|
||||
this[kInterceptors] = opts.interceptors && opts.interceptors.BalancedPool && Array.isArray(opts.interceptors.BalancedPool)
|
||||
? opts.interceptors.BalancedPool
|
||||
: []
|
||||
this[kFactory] = factory
|
||||
|
||||
for (const upstream of upstreams) {
|
||||
|
|
14
deps/undici/src/lib/client.js
vendored
14
deps/undici/src/lib/client.js
vendored
|
@ -7,7 +7,6 @@ const net = require('net')
|
|||
const util = require('./core/util')
|
||||
const Request = require('./core/request')
|
||||
const DispatcherBase = require('./dispatcher-base')
|
||||
const RedirectHandler = require('./handler/redirect')
|
||||
const {
|
||||
RequestContentLengthMismatchError,
|
||||
ResponseContentLengthMismatchError,
|
||||
|
@ -60,7 +59,8 @@ const {
|
|||
kCounter,
|
||||
kClose,
|
||||
kDestroy,
|
||||
kDispatch
|
||||
kDispatch,
|
||||
kInterceptors
|
||||
} = require('./core/symbols')
|
||||
|
||||
const kClosedResolve = Symbol('kClosedResolve')
|
||||
|
@ -82,6 +82,7 @@ try {
|
|||
|
||||
class Client extends DispatcherBase {
|
||||
constructor (url, {
|
||||
interceptors,
|
||||
maxHeaderSize,
|
||||
headersTimeout,
|
||||
socketTimeout,
|
||||
|
@ -179,6 +180,9 @@ class Client extends DispatcherBase {
|
|||
})
|
||||
}
|
||||
|
||||
this[kInterceptors] = interceptors && interceptors.Client && Array.isArray(interceptors.Client)
|
||||
? interceptors.Client
|
||||
: [createRedirectInterceptor({ maxRedirections })]
|
||||
this[kUrl] = util.parseOrigin(url)
|
||||
this[kConnector] = connect
|
||||
this[kSocket] = null
|
||||
|
@ -254,11 +258,6 @@ class Client extends DispatcherBase {
|
|||
}
|
||||
|
||||
[kDispatch] (opts, handler) {
|
||||
const { maxRedirections = this[kMaxRedirections] } = opts
|
||||
if (maxRedirections) {
|
||||
handler = new RedirectHandler(this, maxRedirections, opts, handler)
|
||||
}
|
||||
|
||||
const origin = opts.origin || this[kUrl].origin
|
||||
|
||||
const request = new Request(origin, opts, handler)
|
||||
|
@ -319,6 +318,7 @@ class Client extends DispatcherBase {
|
|||
}
|
||||
|
||||
const constants = require('./llhttp/constants')
|
||||
const createRedirectInterceptor = require('./interceptor/redirectInterceptor')
|
||||
const EMPTY_BUF = Buffer.alloc(0)
|
||||
|
||||
async function lazyllhttp () {
|
||||
|
|
3
deps/undici/src/lib/core/symbols.js
vendored
3
deps/undici/src/lib/core/symbols.js
vendored
|
@ -48,5 +48,6 @@ module.exports = {
|
|||
kMaxRedirections: Symbol('maxRedirections'),
|
||||
kMaxRequests: Symbol('maxRequestsPerClient'),
|
||||
kProxy: Symbol('proxy agent options'),
|
||||
kCounter: Symbol('socket request counter')
|
||||
kCounter: Symbol('socket request counter'),
|
||||
kInterceptors: Symbol('dispatch interceptors')
|
||||
}
|
||||
|
|
38
deps/undici/src/lib/core/util.js
vendored
38
deps/undici/src/lib/core/util.js
vendored
|
@ -8,6 +8,7 @@ const net = require('net')
|
|||
const { InvalidArgumentError } = require('./errors')
|
||||
const { Blob } = require('buffer')
|
||||
const nodeUtil = require('util')
|
||||
const { stringify } = require('querystring')
|
||||
|
||||
function nop () {}
|
||||
|
||||
|
@ -26,46 +27,15 @@ function isBlobLike (object) {
|
|||
)
|
||||
}
|
||||
|
||||
function isObject (val) {
|
||||
return val !== null && typeof val === 'object'
|
||||
}
|
||||
|
||||
// this escapes all non-uri friendly characters
|
||||
function encode (val) {
|
||||
return encodeURIComponent(val)
|
||||
}
|
||||
|
||||
// based on https://github.com/axios/axios/blob/63e559fa609c40a0a460ae5d5a18c3470ffc6c9e/lib/helpers/buildURL.js (MIT license)
|
||||
function buildURL (url, queryParams) {
|
||||
if (url.includes('?') || url.includes('#')) {
|
||||
throw new Error('Query params cannot be passed when url already contains "?" or "#".')
|
||||
}
|
||||
if (!isObject(queryParams)) {
|
||||
throw new Error('Query params must be an object')
|
||||
}
|
||||
|
||||
const parts = []
|
||||
for (let [key, val] of Object.entries(queryParams)) {
|
||||
if (val === null || typeof val === 'undefined') {
|
||||
continue
|
||||
}
|
||||
const stringified = stringify(queryParams)
|
||||
|
||||
if (!Array.isArray(val)) {
|
||||
val = [val]
|
||||
}
|
||||
|
||||
for (const v of val) {
|
||||
if (isObject(v)) {
|
||||
throw new Error('Passing object as a query param is not supported, please serialize to string up-front')
|
||||
}
|
||||
parts.push(encode(key) + '=' + encode(v))
|
||||
}
|
||||
}
|
||||
|
||||
const serializedParams = parts.join('&')
|
||||
|
||||
if (serializedParams) {
|
||||
url += '?' + serializedParams
|
||||
if (stringified) {
|
||||
url += '?' + stringified
|
||||
}
|
||||
|
||||
return url
|
||||
|
|
36
deps/undici/src/lib/dispatcher-base.js
vendored
36
deps/undici/src/lib/dispatcher-base.js
vendored
|
@ -6,12 +6,13 @@ const {
|
|||
ClientClosedError,
|
||||
InvalidArgumentError
|
||||
} = require('./core/errors')
|
||||
const { kDestroy, kClose, kDispatch } = require('./core/symbols')
|
||||
const { kDestroy, kClose, kDispatch, kInterceptors } = require('./core/symbols')
|
||||
|
||||
const kDestroyed = Symbol('destroyed')
|
||||
const kClosed = Symbol('closed')
|
||||
const kOnDestroyed = Symbol('onDestroyed')
|
||||
const kOnClosed = Symbol('onClosed')
|
||||
const kInterceptedDispatch = Symbol('Intercepted Dispatch')
|
||||
|
||||
class DispatcherBase extends Dispatcher {
|
||||
constructor () {
|
||||
|
@ -31,6 +32,23 @@ class DispatcherBase extends Dispatcher {
|
|||
return this[kClosed]
|
||||
}
|
||||
|
||||
get interceptors () {
|
||||
return this[kInterceptors]
|
||||
}
|
||||
|
||||
set interceptors (newInterceptors) {
|
||||
if (newInterceptors) {
|
||||
for (let i = newInterceptors.length - 1; i >= 0; i--) {
|
||||
const interceptor = this[kInterceptors][i]
|
||||
if (typeof interceptor !== 'function') {
|
||||
throw new InvalidArgumentError('interceptor must be an function')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this[kInterceptors] = newInterceptors
|
||||
}
|
||||
|
||||
close (callback) {
|
||||
if (callback === undefined) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -125,6 +143,20 @@ class DispatcherBase extends Dispatcher {
|
|||
})
|
||||
}
|
||||
|
||||
[kInterceptedDispatch] (opts, handler) {
|
||||
if (!this[kInterceptors] || this[kInterceptors].length === 0) {
|
||||
this[kInterceptedDispatch] = this[kDispatch]
|
||||
return this[kDispatch](opts, handler)
|
||||
}
|
||||
|
||||
let dispatch = this[kDispatch].bind(this)
|
||||
for (let i = this[kInterceptors].length - 1; i >= 0; i--) {
|
||||
dispatch = this[kInterceptors][i](dispatch)
|
||||
}
|
||||
this[kInterceptedDispatch] = dispatch
|
||||
return dispatch(opts, handler)
|
||||
}
|
||||
|
||||
dispatch (opts, handler) {
|
||||
if (!handler || typeof handler !== 'object') {
|
||||
throw new InvalidArgumentError('handler must be an object')
|
||||
|
@ -143,7 +175,7 @@ class DispatcherBase extends Dispatcher {
|
|||
throw new ClientClosedError()
|
||||
}
|
||||
|
||||
return this[kDispatch](opts, handler)
|
||||
return this[kInterceptedDispatch](opts, handler)
|
||||
} catch (err) {
|
||||
if (typeof handler.onError !== 'function') {
|
||||
throw new InvalidArgumentError('invalid onError method')
|
||||
|
|
93
deps/undici/src/lib/fetch/body.js
vendored
93
deps/undici/src/lib/fetch/body.js
vendored
|
@ -1,16 +1,18 @@
|
|||
'use strict'
|
||||
|
||||
const Busboy = require('busboy')
|
||||
const util = require('../core/util')
|
||||
const { ReadableStreamFrom, toUSVString, isBlobLike } = require('./util')
|
||||
const { FormData } = require('./formdata')
|
||||
const { kState } = require('./symbols')
|
||||
const { webidl } = require('./webidl')
|
||||
const { DOMException } = require('./constants')
|
||||
const { Blob } = require('buffer')
|
||||
const { kBodyUsed } = require('../core/symbols')
|
||||
const assert = require('assert')
|
||||
const { NotSupportedError } = require('../core/errors')
|
||||
const { isErrored } = require('../core/util')
|
||||
const { isUint8Array, isArrayBuffer } = require('util/types')
|
||||
const { File } = require('./file')
|
||||
|
||||
let ReadableStream
|
||||
|
||||
|
@ -230,9 +232,9 @@ function safelyExtractBody (object, keepalive = false) {
|
|||
if (object instanceof ReadableStream) {
|
||||
// Assert: object is neither disturbed nor locked.
|
||||
// istanbul ignore next
|
||||
assert(!util.isDisturbed(object), 'disturbed')
|
||||
assert(!util.isDisturbed(object), 'The body has already been consumed.')
|
||||
// istanbul ignore next
|
||||
assert(!object.locked, 'locked')
|
||||
assert(!object.locked, 'The stream is locked.')
|
||||
}
|
||||
|
||||
// 2. Return the results of extracting object.
|
||||
|
@ -266,11 +268,11 @@ async function * consumeBody (body) {
|
|||
const stream = body.stream
|
||||
|
||||
if (util.isDisturbed(stream)) {
|
||||
throw new TypeError('disturbed')
|
||||
throw new TypeError('The body has already been consumed.')
|
||||
}
|
||||
|
||||
if (stream.locked) {
|
||||
throw new TypeError('locked')
|
||||
throw new TypeError('The stream is locked.')
|
||||
}
|
||||
|
||||
// Compat.
|
||||
|
@ -281,6 +283,12 @@ async function * consumeBody (body) {
|
|||
}
|
||||
}
|
||||
|
||||
function throwIfAborted (state) {
|
||||
if (state.aborted) {
|
||||
throw new DOMException('The operation was aborted.', 'AbortError')
|
||||
}
|
||||
}
|
||||
|
||||
function bodyMixinMethods (instance) {
|
||||
const methods = {
|
||||
async blob () {
|
||||
|
@ -288,6 +296,8 @@ function bodyMixinMethods (instance) {
|
|||
throw new TypeError('Illegal invocation')
|
||||
}
|
||||
|
||||
throwIfAborted(this[kState])
|
||||
|
||||
const chunks = []
|
||||
|
||||
for await (const chunk of consumeBody(this[kState].body)) {
|
||||
|
@ -308,6 +318,8 @@ function bodyMixinMethods (instance) {
|
|||
throw new TypeError('Illegal invocation')
|
||||
}
|
||||
|
||||
throwIfAborted(this[kState])
|
||||
|
||||
const contentLength = this.headers.get('content-length')
|
||||
const encoded = this.headers.has('content-encoding')
|
||||
|
||||
|
@ -363,6 +375,8 @@ function bodyMixinMethods (instance) {
|
|||
throw new TypeError('Illegal invocation')
|
||||
}
|
||||
|
||||
throwIfAborted(this[kState])
|
||||
|
||||
let result = ''
|
||||
const textDecoder = new TextDecoder()
|
||||
|
||||
|
@ -385,6 +399,8 @@ function bodyMixinMethods (instance) {
|
|||
throw new TypeError('Illegal invocation')
|
||||
}
|
||||
|
||||
throwIfAborted(this[kState])
|
||||
|
||||
return JSON.parse(await this.text())
|
||||
},
|
||||
|
||||
|
@ -393,11 +409,68 @@ function bodyMixinMethods (instance) {
|
|||
throw new TypeError('Illegal invocation')
|
||||
}
|
||||
|
||||
throwIfAborted(this[kState])
|
||||
|
||||
const contentType = this.headers.get('Content-Type')
|
||||
|
||||
// If mimeType’s essence is "multipart/form-data", then:
|
||||
if (/multipart\/form-data/.test(contentType)) {
|
||||
throw new NotSupportedError('multipart/form-data not supported')
|
||||
const headers = {}
|
||||
for (const [key, value] of this.headers) headers[key.toLowerCase()] = value
|
||||
|
||||
const responseFormData = new FormData()
|
||||
|
||||
let busboy
|
||||
|
||||
try {
|
||||
busboy = Busboy({ headers })
|
||||
} catch (err) {
|
||||
// Error due to headers:
|
||||
throw Object.assign(new TypeError(), { cause: err })
|
||||
}
|
||||
|
||||
busboy.on('field', (name, value) => {
|
||||
responseFormData.append(name, value)
|
||||
})
|
||||
busboy.on('file', (name, value, info) => {
|
||||
const { filename, encoding, mimeType } = info
|
||||
const chunks = []
|
||||
|
||||
if (encoding.toLowerCase() === 'base64') {
|
||||
let base64chunk = ''
|
||||
|
||||
value.on('data', (chunk) => {
|
||||
base64chunk += chunk.toString().replace(/[\r\n]/gm, '')
|
||||
|
||||
const end = base64chunk.length - base64chunk.length % 4
|
||||
chunks.push(Buffer.from(base64chunk.slice(0, end), 'base64'))
|
||||
|
||||
base64chunk = base64chunk.slice(end)
|
||||
})
|
||||
value.on('end', () => {
|
||||
chunks.push(Buffer.from(base64chunk, 'base64'))
|
||||
responseFormData.append(name, new File(chunks, filename, { type: mimeType }))
|
||||
})
|
||||
} else {
|
||||
value.on('data', (chunk) => {
|
||||
chunks.push(chunk)
|
||||
})
|
||||
value.on('end', () => {
|
||||
responseFormData.append(name, new File(chunks, filename, { type: mimeType }))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const busboyResolve = new Promise((resolve, reject) => {
|
||||
busboy.on('finish', resolve)
|
||||
busboy.on('error', (err) => reject(err))
|
||||
})
|
||||
|
||||
if (this.body !== null) for await (const chunk of consumeBody(this[kState].body)) busboy.write(chunk)
|
||||
busboy.end()
|
||||
await busboyResolve
|
||||
|
||||
return responseFormData
|
||||
} else if (/application\/x-www-form-urlencoded/.test(contentType)) {
|
||||
// Otherwise, if mimeType’s essence is "application/x-www-form-urlencoded", then:
|
||||
|
||||
|
@ -429,10 +502,16 @@ function bodyMixinMethods (instance) {
|
|||
}
|
||||
return formData
|
||||
} else {
|
||||
// Wait a tick before checking if the request has been aborted.
|
||||
// Otherwise, a TypeError can be thrown when an AbortError should.
|
||||
await Promise.resolve()
|
||||
|
||||
throwIfAborted(this[kState])
|
||||
|
||||
// Otherwise, throw a TypeError.
|
||||
webidl.errors.exception({
|
||||
header: `${instance.name}.formData`,
|
||||
value: 'Could not parse content as FormData.'
|
||||
message: 'Could not parse content as FormData.'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
55
deps/undici/src/lib/fetch/dataURL.js
vendored
55
deps/undici/src/lib/fetch/dataURL.js
vendored
|
@ -1,5 +1,6 @@
|
|||
const assert = require('assert')
|
||||
const { atob } = require('buffer')
|
||||
const { isValidHTTPToken } = require('./util')
|
||||
|
||||
const encoder = new TextEncoder()
|
||||
|
||||
|
@ -376,9 +377,7 @@ function parseMIMEType (input) {
|
|||
// 1. Set parameterValue to the result of collecting
|
||||
// an HTTP quoted string from input, given position
|
||||
// and the extract-value flag.
|
||||
// Undici implementation note: extract-value is never
|
||||
// defined or mentioned anywhere.
|
||||
parameterValue = collectAnHTTPQuotedString(input, position/*, extractValue */)
|
||||
parameterValue = collectAnHTTPQuotedString(input, position, true)
|
||||
|
||||
// 2. Collect a sequence of code points that are not
|
||||
// U+003B (;) from input, given position.
|
||||
|
@ -400,7 +399,8 @@ function parseMIMEType (input) {
|
|||
)
|
||||
|
||||
// 2. Remove any trailing HTTP whitespace from parameterValue.
|
||||
parameterValue = parameterValue.trim()
|
||||
// Note: it says "trailing" whitespace; leading is fine.
|
||||
parameterValue = parameterValue.trimEnd()
|
||||
|
||||
// 3. If parameterValue is the empty string, then continue.
|
||||
if (parameterValue.length === 0) {
|
||||
|
@ -547,11 +547,56 @@ function collectAnHTTPQuotedString (input, position, extractValue) {
|
|||
return input.slice(positionStart, position.position)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://mimesniff.spec.whatwg.org/#serialize-a-mime-type
|
||||
*/
|
||||
function serializeAMimeType (mimeType) {
|
||||
assert(mimeType !== 'failure')
|
||||
const { type, subtype, parameters } = mimeType
|
||||
|
||||
// 1. Let serialization be the concatenation of mimeType’s
|
||||
// type, U+002F (/), and mimeType’s subtype.
|
||||
let serialization = `${type}/${subtype}`
|
||||
|
||||
// 2. For each name → value of mimeType’s parameters:
|
||||
for (let [name, value] of parameters.entries()) {
|
||||
// 1. Append U+003B (;) to serialization.
|
||||
serialization += ';'
|
||||
|
||||
// 2. Append name to serialization.
|
||||
serialization += name
|
||||
|
||||
// 3. Append U+003D (=) to serialization.
|
||||
serialization += '='
|
||||
|
||||
// 4. If value does not solely contain HTTP token code
|
||||
// points or value is the empty string, then:
|
||||
if (!isValidHTTPToken(value)) {
|
||||
// 1. Precede each occurence of U+0022 (") or
|
||||
// U+005C (\) in value with U+005C (\).
|
||||
value = value.replace(/(\\|")/g, '\\$1')
|
||||
|
||||
// 2. Prepend U+0022 (") to value.
|
||||
value = '"' + value
|
||||
|
||||
// 3. Append U+0022 (") to value.
|
||||
value += '"'
|
||||
}
|
||||
|
||||
// 5. Append value to serialization.
|
||||
serialization += value
|
||||
}
|
||||
|
||||
// 3. Return serialization.
|
||||
return serialization
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
dataURLProcessor,
|
||||
URLSerializer,
|
||||
collectASequenceOfCodePoints,
|
||||
stringPercentDecode,
|
||||
parseMIMEType,
|
||||
collectAnHTTPQuotedString
|
||||
collectAnHTTPQuotedString,
|
||||
serializeAMimeType
|
||||
}
|
||||
|
|
14
deps/undici/src/lib/fetch/file.js
vendored
14
deps/undici/src/lib/fetch/file.js
vendored
|
@ -312,4 +312,16 @@ function convertLineEndingsNative (s) {
|
|||
return s.replace(/\r?\n/g, nativeLineEnding)
|
||||
}
|
||||
|
||||
module.exports = { File, FileLike }
|
||||
// If this function is moved to ./util.js, some tools (such as
|
||||
// rollup) will warn about circular dependencies. See:
|
||||
// https://github.com/nodejs/undici/issues/1629
|
||||
function isFileLike (object) {
|
||||
return object instanceof File || (
|
||||
object &&
|
||||
(typeof object.stream === 'function' ||
|
||||
typeof object.arrayBuffer === 'function') &&
|
||||
object[Symbol.toStringTag] === 'File'
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = { File, FileLike, isFileLike }
|
||||
|
|
4
deps/undici/src/lib/fetch/formdata.js
vendored
4
deps/undici/src/lib/fetch/formdata.js
vendored
|
@ -1,8 +1,8 @@
|
|||
'use strict'
|
||||
|
||||
const { isBlobLike, isFileLike, toUSVString, makeIterator } = require('./util')
|
||||
const { isBlobLike, toUSVString, makeIterator } = require('./util')
|
||||
const { kState } = require('./symbols')
|
||||
const { File, FileLike } = require('./file')
|
||||
const { File, FileLike, isFileLike } = require('./file')
|
||||
const { webidl } = require('./webidl')
|
||||
const { Blob } = require('buffer')
|
||||
|
||||
|
|
48
deps/undici/src/lib/fetch/global.js
vendored
Normal file
48
deps/undici/src/lib/fetch/global.js
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
'use strict'
|
||||
|
||||
// In case of breaking changes, increase the version
|
||||
// number to avoid conflicts.
|
||||
const globalOrigin = Symbol.for('undici.globalOrigin.1')
|
||||
|
||||
function getGlobalOrigin () {
|
||||
return globalThis[globalOrigin]
|
||||
}
|
||||
|
||||
function setGlobalOrigin (newOrigin) {
|
||||
if (
|
||||
newOrigin !== undefined &&
|
||||
typeof newOrigin !== 'string' &&
|
||||
!(newOrigin instanceof URL)
|
||||
) {
|
||||
throw new Error('Invalid base url')
|
||||
}
|
||||
|
||||
if (newOrigin === undefined) {
|
||||
Object.defineProperty(globalThis, globalOrigin, {
|
||||
value: undefined,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: false
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const parsedURL = new URL(newOrigin)
|
||||
|
||||
if (parsedURL.protocol !== 'http:' && parsedURL.protocol !== 'https:') {
|
||||
throw new TypeError(`Only http & https urls are allowed, received ${parsedURL.protocol}`)
|
||||
}
|
||||
|
||||
Object.defineProperty(globalThis, globalOrigin, {
|
||||
value: parsedURL,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: false
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getGlobalOrigin,
|
||||
setGlobalOrigin
|
||||
}
|
4
deps/undici/src/lib/fetch/headers.js
vendored
4
deps/undici/src/lib/fetch/headers.js
vendored
|
@ -402,7 +402,9 @@ class Headers {
|
|||
}
|
||||
|
||||
get [kHeadersSortedMap] () {
|
||||
this[kHeadersList][kHeadersSortedMap] ??= new Map([...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1))
|
||||
if (!this[kHeadersList][kHeadersSortedMap]) {
|
||||
this[kHeadersList][kHeadersSortedMap] = new Map([...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1))
|
||||
}
|
||||
return this[kHeadersList][kHeadersSortedMap]
|
||||
}
|
||||
|
||||
|
|
41
deps/undici/src/lib/fetch/index.js
vendored
41
deps/undici/src/lib/fetch/index.js
vendored
|
@ -52,7 +52,7 @@ const { kHeadersList } = require('../core/symbols')
|
|||
const EE = require('events')
|
||||
const { Readable, pipeline } = require('stream')
|
||||
const { isErrored, isReadable } = require('../core/util')
|
||||
const { dataURLProcessor } = require('./dataURL')
|
||||
const { dataURLProcessor, serializeAMimeType } = require('./dataURL')
|
||||
const { TransformStream } = require('stream/web')
|
||||
|
||||
/** @type {import('buffer').resolveObjectURL} */
|
||||
|
@ -832,25 +832,7 @@ async function schemeFetch (fetchParams) {
|
|||
}
|
||||
|
||||
// 3. Let mimeType be dataURLStruct’s MIME type, serialized.
|
||||
const { mimeType } = dataURLStruct
|
||||
|
||||
/** @type {string} */
|
||||
let contentType = `${mimeType.type}/${mimeType.subtype}`
|
||||
const contentTypeParams = []
|
||||
|
||||
if (mimeType.parameters.size > 0) {
|
||||
contentType += ';'
|
||||
}
|
||||
|
||||
for (const [key, value] of mimeType.parameters) {
|
||||
if (value.length > 0) {
|
||||
contentTypeParams.push(`${key}=${value}`)
|
||||
} else {
|
||||
contentTypeParams.push(key)
|
||||
}
|
||||
}
|
||||
|
||||
contentType += contentTypeParams.join(',')
|
||||
const mimeType = serializeAMimeType(dataURLStruct.mimeType)
|
||||
|
||||
// 4. Return a response whose status message is `OK`,
|
||||
// header list is « (`Content-Type`, mimeType) »,
|
||||
|
@ -858,7 +840,7 @@ async function schemeFetch (fetchParams) {
|
|||
return makeResponse({
|
||||
statusText: 'OK',
|
||||
headersList: [
|
||||
['content-type', contentType]
|
||||
['content-type', mimeType]
|
||||
],
|
||||
body: extractBody(dataURLStruct.body)[0]
|
||||
})
|
||||
|
@ -1048,7 +1030,9 @@ async function httpFetch (fetchParams) {
|
|||
// and the connection uses HTTP/2, then user agents may, and are even
|
||||
// encouraged to, transmit an RST_STREAM frame.
|
||||
// See, https://github.com/whatwg/fetch/issues/1288
|
||||
fetchParams.controller.connection.destroy()
|
||||
if (request.redirect !== 'manual') {
|
||||
fetchParams.controller.connection.destroy()
|
||||
}
|
||||
|
||||
// 2. Switch on request’s redirect mode:
|
||||
if (request.redirect === 'error') {
|
||||
|
@ -1956,8 +1940,12 @@ async function httpNetworkFetch (
|
|||
|
||||
const decoders = []
|
||||
|
||||
const willFollow = request.redirect === 'follow' &&
|
||||
location &&
|
||||
redirectStatus.includes(status)
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
|
||||
if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !(request.redirect === 'follow' && location)) {
|
||||
if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
|
||||
for (const coding of codings) {
|
||||
if (/(x-)?gzip/.test(coding)) {
|
||||
decoders.push(zlib.createGunzip())
|
||||
|
@ -2033,4 +2021,9 @@ async function httpNetworkFetch (
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = fetch
|
||||
module.exports = {
|
||||
fetch,
|
||||
Fetch,
|
||||
fetching,
|
||||
finalizeAndReportTiming
|
||||
}
|
||||
|
|
7
deps/undici/src/lib/fetch/request.js
vendored
7
deps/undici/src/lib/fetch/request.js
vendored
|
@ -23,6 +23,7 @@ const {
|
|||
const { kEnumerableProperty } = util
|
||||
const { kHeaders, kSignal, kState, kGuard, kRealm } = require('./symbols')
|
||||
const { webidl } = require('./webidl')
|
||||
const { getGlobalOrigin } = require('./global')
|
||||
const { kHeadersList } = require('../core/symbols')
|
||||
const assert = require('assert')
|
||||
|
||||
|
@ -52,7 +53,11 @@ class Request {
|
|||
init = webidl.converters.RequestInit(init)
|
||||
|
||||
// TODO
|
||||
this[kRealm] = { settingsObject: {} }
|
||||
this[kRealm] = {
|
||||
settingsObject: {
|
||||
baseUrl: getGlobalOrigin()
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Let request be null.
|
||||
let request = null
|
||||
|
|
9
deps/undici/src/lib/fetch/response.js
vendored
9
deps/undici/src/lib/fetch/response.js
vendored
|
@ -21,6 +21,7 @@ const {
|
|||
const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
|
||||
const { webidl } = require('./webidl')
|
||||
const { FormData } = require('./formdata')
|
||||
const { getGlobalOrigin } = require('./global')
|
||||
const { kHeadersList } = require('../core/symbols')
|
||||
const assert = require('assert')
|
||||
const { types } = require('util')
|
||||
|
@ -100,7 +101,7 @@ class Response {
|
|||
// TODO: base-URL?
|
||||
let parsedURL
|
||||
try {
|
||||
parsedURL = new URL(url)
|
||||
parsedURL = new URL(url, getGlobalOrigin())
|
||||
} catch (err) {
|
||||
throw Object.assign(new TypeError('Failed to parse URL from ' + url), {
|
||||
cause: err
|
||||
|
@ -518,7 +519,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) {
|
|||
}
|
||||
|
||||
if (isBlobLike(V)) {
|
||||
return webidl.converters.Blob(V)
|
||||
return webidl.converters.Blob(V, { strict: false })
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -529,8 +530,8 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) {
|
|||
return webidl.converters.BufferSource(V)
|
||||
}
|
||||
|
||||
if (V instanceof FormData) {
|
||||
return webidl.converters.FormData(V)
|
||||
if (util.isFormDataLike(V)) {
|
||||
return webidl.converters.FormData(V, { strict: false })
|
||||
}
|
||||
|
||||
if (V instanceof URLSearchParams) {
|
||||
|
|
187
deps/undici/src/lib/fetch/util.js
vendored
187
deps/undici/src/lib/fetch/util.js
vendored
|
@ -6,8 +6,6 @@ const { isBlobLike, toUSVString, ReadableStreamFrom } = require('../core/util')
|
|||
const assert = require('assert')
|
||||
const { isUint8Array } = require('util/types')
|
||||
|
||||
let File
|
||||
|
||||
// https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable
|
||||
/** @type {import('crypto')|undefined} */
|
||||
let crypto
|
||||
|
@ -81,18 +79,6 @@ function requestBadPort (request) {
|
|||
return 'allowed'
|
||||
}
|
||||
|
||||
function isFileLike (object) {
|
||||
if (!File) {
|
||||
File = require('./file').File
|
||||
}
|
||||
return object instanceof File || (
|
||||
object &&
|
||||
(typeof object.stream === 'function' ||
|
||||
typeof object.arrayBuffer === 'function') &&
|
||||
/^(File)$/.test(object[Symbol.toStringTag])
|
||||
)
|
||||
}
|
||||
|
||||
function isErrorLike (object) {
|
||||
return object instanceof Error || (
|
||||
object?.constructor?.name === 'Error' ||
|
||||
|
@ -346,8 +332,175 @@ function clonePolicyContainer () {
|
|||
|
||||
// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
|
||||
function determineRequestsReferrer (request) {
|
||||
// TODO
|
||||
return 'no-referrer'
|
||||
// 1. Let policy be request's referrer policy.
|
||||
const policy = request.referrerPolicy
|
||||
|
||||
// Return no-referrer when empty or policy says so
|
||||
if (policy == null || policy === '' || policy === 'no-referrer') {
|
||||
return 'no-referrer'
|
||||
}
|
||||
|
||||
// 2. Let environment be the request client
|
||||
const environment = request.client
|
||||
let referrerSource = null
|
||||
|
||||
/**
|
||||
* 3, Switch on request’s referrer:
|
||||
"client"
|
||||
If environment’s global object is a Window object, then
|
||||
Let document be the associated Document of environment’s global object.
|
||||
If document’s origin is an opaque origin, return no referrer.
|
||||
While document is an iframe srcdoc document,
|
||||
let document be document’s browsing context’s browsing context container’s node document.
|
||||
Let referrerSource be document’s URL.
|
||||
|
||||
Otherwise, let referrerSource be environment’s creation URL.
|
||||
|
||||
a URL
|
||||
Let referrerSource be request’s referrer.
|
||||
*/
|
||||
if (request.referrer === 'client') {
|
||||
// Not defined in Node but part of the spec
|
||||
if (request.client?.globalObject?.constructor?.name === 'Window' ) { // eslint-disable-line
|
||||
const origin = environment.globalObject.self?.origin ?? environment.globalObject.location?.origin
|
||||
|
||||
// If document’s origin is an opaque origin, return no referrer.
|
||||
if (origin == null || origin === 'null') return 'no-referrer'
|
||||
|
||||
// Let referrerSource be document’s URL.
|
||||
referrerSource = new URL(environment.globalObject.location.href)
|
||||
} else {
|
||||
// 3(a)(II) If environment's global object is not Window,
|
||||
// Let referrerSource be environments creationURL
|
||||
if (environment?.globalObject?.location == null) {
|
||||
return 'no-referrer'
|
||||
}
|
||||
|
||||
referrerSource = new URL(environment.globalObject.location.href)
|
||||
}
|
||||
} else if (request.referrer instanceof URL) {
|
||||
// 3(b) If requests's referrer is a URL instance, then make
|
||||
// referrerSource be requests's referrer.
|
||||
referrerSource = request.referrer
|
||||
} else {
|
||||
// If referrerSource neither client nor instance of URL
|
||||
// then return "no-referrer".
|
||||
return 'no-referrer'
|
||||
}
|
||||
|
||||
const urlProtocol = referrerSource.protocol
|
||||
|
||||
// If url's scheme is a local scheme (i.e. one of "about", "data", "javascript", "file")
|
||||
// then return "no-referrer".
|
||||
if (
|
||||
urlProtocol === 'about:' || urlProtocol === 'data:' ||
|
||||
urlProtocol === 'blob:'
|
||||
) {
|
||||
return 'no-referrer'
|
||||
}
|
||||
|
||||
let temp
|
||||
let referrerOrigin
|
||||
// 4. Let requests's referrerURL be the result of stripping referrer
|
||||
// source for use as referrer (using util function, without origin only)
|
||||
const referrerUrl = (temp = stripURLForReferrer(referrerSource)).length > 4096
|
||||
// 5. Let referrerOrigin be the result of stripping referrer
|
||||
// source for use as referrer (using util function, with originOnly true)
|
||||
? (referrerOrigin = stripURLForReferrer(referrerSource, true))
|
||||
// 6. If result of seralizing referrerUrl is a string whose length is greater than
|
||||
// 4096, then set referrerURL to referrerOrigin
|
||||
: temp
|
||||
const areSameOrigin = sameOrigin(request, referrerUrl)
|
||||
const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerUrl) &&
|
||||
!isURLPotentiallyTrustworthy(request.url)
|
||||
|
||||
// NOTE: How to treat step 7?
|
||||
// 8. Execute the switch statements corresponding to the value of policy:
|
||||
switch (policy) {
|
||||
case 'origin': return referrerOrigin != null ? referrerOrigin : stripURLForReferrer(referrerSource, true)
|
||||
case 'unsafe-url': return referrerUrl
|
||||
case 'same-origin':
|
||||
return areSameOrigin ? referrerOrigin : 'no-referrer'
|
||||
case 'origin-when-cross-origin':
|
||||
return areSameOrigin ? referrerUrl : referrerOrigin
|
||||
case 'strict-origin-when-cross-origin':
|
||||
/**
|
||||
* 1. If the origin of referrerURL and the origin of request’s current URL are the same,
|
||||
* then return referrerURL.
|
||||
* 2. If referrerURL is a potentially trustworthy URL and request’s current URL is not a
|
||||
* potentially trustworthy URL, then return no referrer.
|
||||
* 3. Return referrerOrigin
|
||||
*/
|
||||
if (areSameOrigin) return referrerOrigin
|
||||
// else return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin
|
||||
case 'strict-origin': // eslint-disable-line
|
||||
/**
|
||||
* 1. If referrerURL is a potentially trustworthy URL and
|
||||
* request’s current URL is not a potentially trustworthy URL,
|
||||
* then return no referrer.
|
||||
* 2. Return referrerOrigin
|
||||
*/
|
||||
case 'no-referrer-when-downgrade': // eslint-disable-line
|
||||
/**
|
||||
* 1. If referrerURL is a potentially trustworthy URL and
|
||||
* request’s current URL is not a potentially trustworthy URL,
|
||||
* then return no referrer.
|
||||
* 2. Return referrerOrigin
|
||||
*/
|
||||
|
||||
default: // eslint-disable-line
|
||||
return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin
|
||||
}
|
||||
|
||||
function stripURLForReferrer (url, originOnly = false) {
|
||||
const urlObject = new URL(url.href)
|
||||
urlObject.username = ''
|
||||
urlObject.password = ''
|
||||
urlObject.hash = ''
|
||||
|
||||
return originOnly ? urlObject.origin : urlObject.href
|
||||
}
|
||||
}
|
||||
|
||||
function isURLPotentiallyTrustworthy (url) {
|
||||
if (!(url instanceof URL)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If child of about, return true
|
||||
if (url.href === 'about:blank' || url.href === 'about:srcdoc') {
|
||||
return true
|
||||
}
|
||||
|
||||
// If scheme is data, return true
|
||||
if (url.protocol === 'data:') return true
|
||||
|
||||
// If file, return true
|
||||
if (url.protocol === 'file:') return true
|
||||
|
||||
return isOriginPotentiallyTrustworthy(url.origin)
|
||||
|
||||
function isOriginPotentiallyTrustworthy (origin) {
|
||||
// If origin is explicitly null, return false
|
||||
if (origin == null || origin === 'null') return false
|
||||
|
||||
const originAsURL = new URL(origin)
|
||||
|
||||
// If secure, return true
|
||||
if (originAsURL.protocol === 'https:' || originAsURL.protocol === 'wss:') {
|
||||
return true
|
||||
}
|
||||
|
||||
// If localhost or variants, return true
|
||||
if (/^127(?:\.[0-9]+){0,2}\.[0-9]+$|^\[(?:0*:)*?:?0*1\]$/.test(originAsURL.hostname) ||
|
||||
(originAsURL.hostname === 'localhost' || originAsURL.hostname.includes('localhost.')) ||
|
||||
(originAsURL.hostname.endsWith('.localhost'))) {
|
||||
return true
|
||||
}
|
||||
|
||||
// If any other, return false
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -631,7 +784,7 @@ module.exports = {
|
|||
responseURL,
|
||||
responseLocationURL,
|
||||
isBlobLike,
|
||||
isFileLike,
|
||||
isURLPotentiallyTrustworthy,
|
||||
isValidReasonPhrase,
|
||||
sameOrigin,
|
||||
normalizeMethod,
|
||||
|
|
35
deps/undici/src/lib/handler/DecoratorHandler.js
vendored
Normal file
35
deps/undici/src/lib/handler/DecoratorHandler.js
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
'use strict'
|
||||
|
||||
module.exports = class DecoratorHandler {
|
||||
constructor (handler) {
|
||||
this.handler = handler
|
||||
}
|
||||
|
||||
onConnect (...args) {
|
||||
return this.handler.onConnect(...args)
|
||||
}
|
||||
|
||||
onError (...args) {
|
||||
return this.handler.onError(...args)
|
||||
}
|
||||
|
||||
onUpgrade (...args) {
|
||||
return this.handler.onUpgrade(...args)
|
||||
}
|
||||
|
||||
onHeaders (...args) {
|
||||
return this.handler.onHeaders(...args)
|
||||
}
|
||||
|
||||
onData (...args) {
|
||||
return this.handler.onData(...args)
|
||||
}
|
||||
|
||||
onComplete (...args) {
|
||||
return this.handler.onComplete(...args)
|
||||
}
|
||||
|
||||
onBodySent (...args) {
|
||||
return this.handler.onBodySent(...args)
|
||||
}
|
||||
}
|
|
@ -24,14 +24,14 @@ class BodyAsyncIterable {
|
|||
}
|
||||
|
||||
class RedirectHandler {
|
||||
constructor (dispatcher, maxRedirections, opts, handler) {
|
||||
constructor (dispatch, maxRedirections, opts, handler) {
|
||||
if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) {
|
||||
throw new InvalidArgumentError('maxRedirections must be a positive number')
|
||||
}
|
||||
|
||||
util.validateHandler(handler, opts.method, opts.upgrade)
|
||||
|
||||
this.dispatcher = dispatcher
|
||||
this.dispatch = dispatch
|
||||
this.location = null
|
||||
this.abort = null
|
||||
this.opts = { ...opts, maxRedirections: 0 } // opts must be a copy
|
||||
|
@ -156,7 +156,7 @@ class RedirectHandler {
|
|||
this.location = null
|
||||
this.abort = null
|
||||
|
||||
this.dispatcher.dispatch(this.opts, this)
|
||||
this.dispatch(this.opts, this)
|
||||
} else {
|
||||
this.handler.onComplete(trailers)
|
||||
}
|
21
deps/undici/src/lib/interceptor/redirectInterceptor.js
vendored
Normal file
21
deps/undici/src/lib/interceptor/redirectInterceptor.js
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
'use strict'
|
||||
|
||||
const RedirectHandler = require('../handler/RedirectHandler')
|
||||
|
||||
function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections }) {
|
||||
return (dispatch) => {
|
||||
return function Intercept (opts, handler) {
|
||||
const { maxRedirections = defaultMaxRedirections } = opts
|
||||
|
||||
if (!maxRedirections) {
|
||||
return dispatch(opts, handler)
|
||||
}
|
||||
|
||||
const redirectHandler = new RedirectHandler(dispatch, maxRedirections, opts, handler)
|
||||
opts = { ...opts, maxRedirections: 0 } // Stop sub dispatcher from also redirecting.
|
||||
return dispatch(opts, redirectHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = createRedirectInterceptor
|
68
deps/undici/src/lib/mock/mock-utils.js
vendored
68
deps/undici/src/lib/mock/mock-utils.js
vendored
|
@ -9,6 +9,7 @@ const {
|
|||
kGetNetConnect
|
||||
} = require('./mock-symbols')
|
||||
const { buildURL, nop } = require('../core/util')
|
||||
const { STATUS_CODES } = require('http')
|
||||
|
||||
function matchValue (match, value) {
|
||||
if (typeof match === 'string') {
|
||||
|
@ -190,72 +191,7 @@ function generateKeyValues (data) {
|
|||
* @param {number} statusCode
|
||||
*/
|
||||
function getStatusText (statusCode) {
|
||||
switch (statusCode) {
|
||||
case 100: return 'Continue'
|
||||
case 101: return 'Switching Protocols'
|
||||
case 102: return 'Processing'
|
||||
case 103: return 'Early Hints'
|
||||
case 200: return 'OK'
|
||||
case 201: return 'Created'
|
||||
case 202: return 'Accepted'
|
||||
case 203: return 'Non-Authoritative Information'
|
||||
case 204: return 'No Content'
|
||||
case 205: return 'Reset Content'
|
||||
case 206: return 'Partial Content'
|
||||
case 207: return 'Multi-Status'
|
||||
case 208: return 'Already Reported'
|
||||
case 226: return 'IM Used'
|
||||
case 300: return 'Multiple Choice'
|
||||
case 301: return 'Moved Permanently'
|
||||
case 302: return 'Found'
|
||||
case 303: return 'See Other'
|
||||
case 304: return 'Not Modified'
|
||||
case 305: return 'Use Proxy'
|
||||
case 306: return 'unused'
|
||||
case 307: return 'Temporary Redirect'
|
||||
case 308: return 'Permanent Redirect'
|
||||
case 400: return 'Bad Request'
|
||||
case 401: return 'Unauthorized'
|
||||
case 402: return 'Payment Required'
|
||||
case 403: return 'Forbidden'
|
||||
case 404: return 'Not Found'
|
||||
case 405: return 'Method Not Allowed'
|
||||
case 406: return 'Not Acceptable'
|
||||
case 407: return 'Proxy Authentication Required'
|
||||
case 408: return 'Request Timeout'
|
||||
case 409: return 'Conflict'
|
||||
case 410: return 'Gone'
|
||||
case 411: return 'Length Required'
|
||||
case 412: return 'Precondition Failed'
|
||||
case 413: return 'Payload Too Large'
|
||||
case 414: return 'URI Too Large'
|
||||
case 415: return 'Unsupported Media Type'
|
||||
case 416: return 'Range Not Satisfiable'
|
||||
case 417: return 'Expectation Failed'
|
||||
case 418: return 'I\'m a teapot'
|
||||
case 421: return 'Misdirected Request'
|
||||
case 422: return 'Unprocessable Entity'
|
||||
case 423: return 'Locked'
|
||||
case 424: return 'Failed Dependency'
|
||||
case 425: return 'Too Early'
|
||||
case 426: return 'Upgrade Required'
|
||||
case 428: return 'Precondition Required'
|
||||
case 429: return 'Too Many Requests'
|
||||
case 431: return 'Request Header Fields Too Large'
|
||||
case 451: return 'Unavailable For Legal Reasons'
|
||||
case 500: return 'Internal Server Error'
|
||||
case 501: return 'Not Implemented'
|
||||
case 502: return 'Bad Gateway'
|
||||
case 503: return 'Service Unavailable'
|
||||
case 504: return 'Gateway Timeout'
|
||||
case 505: return 'HTTP Version Not Supported'
|
||||
case 506: return 'Variant Also Negotiates'
|
||||
case 507: return 'Insufficient Storage'
|
||||
case 508: return 'Loop Detected'
|
||||
case 510: return 'Not Extended'
|
||||
case 511: return 'Network Authentication Required'
|
||||
default: return 'unknown'
|
||||
}
|
||||
return STATUS_CODES[statusCode] || 'unknown'
|
||||
}
|
||||
|
||||
async function getResponse (body) {
|
||||
|
|
8
deps/undici/src/lib/pool.js
vendored
8
deps/undici/src/lib/pool.js
vendored
|
@ -12,7 +12,7 @@ const {
|
|||
InvalidArgumentError
|
||||
} = require('./core/errors')
|
||||
const util = require('./core/util')
|
||||
const { kUrl } = require('./core/symbols')
|
||||
const { kUrl, kInterceptors } = require('./core/symbols')
|
||||
const buildConnector = require('./core/connect')
|
||||
|
||||
const kOptions = Symbol('options')
|
||||
|
@ -58,9 +58,15 @@ class Pool extends PoolBase {
|
|||
})
|
||||
}
|
||||
|
||||
this[kInterceptors] = options.interceptors && options.interceptors.Pool && Array.isArray(options.interceptors.Pool)
|
||||
? options.interceptors.Pool
|
||||
: []
|
||||
this[kConnections] = connections || null
|
||||
this[kUrl] = util.parseOrigin(origin)
|
||||
this[kOptions] = { ...util.deepClone(options), connect }
|
||||
this[kOptions].interceptors = options.interceptors
|
||||
? { ...options.interceptors }
|
||||
: undefined
|
||||
this[kFactory] = factory
|
||||
}
|
||||
|
||||
|
|
32
deps/undici/src/lib/proxy-agent.js
vendored
32
deps/undici/src/lib/proxy-agent.js
vendored
|
@ -1,8 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
const { kClose, kDestroy } = require('./core/symbols')
|
||||
const Client = require('./agent')
|
||||
const { kProxy, kClose, kDestroy, kInterceptors } = require('./core/symbols')
|
||||
const { URL } = require('url')
|
||||
const Agent = require('./agent')
|
||||
const Client = require('./client')
|
||||
const DispatcherBase = require('./dispatcher-base')
|
||||
const { InvalidArgumentError, RequestAbortedError } = require('./core/errors')
|
||||
const buildConnector = require('./core/connect')
|
||||
|
@ -18,9 +19,29 @@ function defaultProtocolPort (protocol) {
|
|||
return protocol === 'https:' ? 443 : 80
|
||||
}
|
||||
|
||||
function buildProxyOptions (opts) {
|
||||
if (typeof opts === 'string') {
|
||||
opts = { uri: opts }
|
||||
}
|
||||
|
||||
if (!opts || !opts.uri) {
|
||||
throw new InvalidArgumentError('Proxy opts.uri is mandatory')
|
||||
}
|
||||
|
||||
return {
|
||||
uri: opts.uri,
|
||||
protocol: opts.protocol || 'https'
|
||||
}
|
||||
}
|
||||
|
||||
class ProxyAgent extends DispatcherBase {
|
||||
constructor (opts) {
|
||||
super(opts)
|
||||
this[kProxy] = buildProxyOptions(opts)
|
||||
this[kAgent] = new Agent(opts)
|
||||
this[kInterceptors] = opts.interceptors && opts.interceptors.ProxyAgent && Array.isArray(opts.interceptors.ProxyAgent)
|
||||
? opts.interceptors.ProxyAgent
|
||||
: []
|
||||
|
||||
if (typeof opts === 'string') {
|
||||
opts = { uri: opts }
|
||||
|
@ -38,11 +59,12 @@ class ProxyAgent extends DispatcherBase {
|
|||
this[kProxyHeaders]['proxy-authorization'] = `Basic ${opts.auth}`
|
||||
}
|
||||
|
||||
const { origin, port } = new URL(opts.uri)
|
||||
const resolvedUrl = new URL(opts.uri)
|
||||
const { origin, port, host } = resolvedUrl
|
||||
|
||||
const connect = buildConnector({ ...opts.proxyTls })
|
||||
this[kConnectEndpoint] = buildConnector({ ...opts.requestTls })
|
||||
this[kClient] = new Client({ origin: opts.origin, connect })
|
||||
this[kClient] = new Client(resolvedUrl, { connect })
|
||||
this[kAgent] = new Agent({
|
||||
...opts,
|
||||
connect: async (opts, callback) => {
|
||||
|
@ -58,7 +80,7 @@ class ProxyAgent extends DispatcherBase {
|
|||
signal: opts.signal,
|
||||
headers: {
|
||||
...this[kProxyHeaders],
|
||||
host: opts.host
|
||||
host
|
||||
}
|
||||
})
|
||||
if (statusCode !== 200) {
|
||||
|
|
5
deps/undici/src/node_modules/busboy/.eslintrc.js
generated
vendored
Normal file
5
deps/undici/src/node_modules/busboy/.eslintrc.js
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
extends: '@mscdex/eslint-config',
|
||||
};
|
24
deps/undici/src/node_modules/busboy/.github/workflows/ci.yml
generated
vendored
Normal file
24
deps/undici/src/node_modules/busboy/.github/workflows/ci.yml
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
tests-linux:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [10.16.0, 10.x, 12.x, 14.x, 16.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install module
|
||||
run: npm install
|
||||
- name: Run tests
|
||||
run: npm test
|
23
deps/undici/src/node_modules/busboy/.github/workflows/lint.yml
generated
vendored
Normal file
23
deps/undici/src/node_modules/busboy/.github/workflows/lint.yml
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
name: lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
NODE_VERSION: 16.x
|
||||
|
||||
jobs:
|
||||
lint-js:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ env.NODE_VERSION }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
- name: Install ESLint + ESLint configs/plugins
|
||||
run: npm install --only=dev
|
||||
- name: Lint files
|
||||
run: npm run lint
|
19
deps/undici/src/node_modules/busboy/LICENSE
generated
vendored
Normal file
19
deps/undici/src/node_modules/busboy/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright Brian White. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
191
deps/undici/src/node_modules/busboy/README.md
generated
vendored
Normal file
191
deps/undici/src/node_modules/busboy/README.md
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
# Description
|
||||
|
||||
A node.js module for parsing incoming HTML form data.
|
||||
|
||||
Changes (breaking or otherwise) in v1.0.0 can be found [here](https://github.com/mscdex/busboy/issues/266).
|
||||
|
||||
# Requirements
|
||||
|
||||
* [node.js](http://nodejs.org/) -- v10.16.0 or newer
|
||||
|
||||
|
||||
# Install
|
||||
|
||||
npm install busboy
|
||||
|
||||
|
||||
# Examples
|
||||
|
||||
* Parsing (multipart) with default options:
|
||||
|
||||
```js
|
||||
const http = require('http');
|
||||
|
||||
const busboy = require('busboy');
|
||||
|
||||
http.createServer((req, res) => {
|
||||
if (req.method === 'POST') {
|
||||
console.log('POST request');
|
||||
const bb = busboy({ headers: req.headers });
|
||||
bb.on('file', (name, file, info) => {
|
||||
const { filename, encoding, mimeType } = info;
|
||||
console.log(
|
||||
`File [${name}]: filename: %j, encoding: %j, mimeType: %j`,
|
||||
filename,
|
||||
encoding,
|
||||
mimeType
|
||||
);
|
||||
file.on('data', (data) => {
|
||||
console.log(`File [${name}] got ${data.length} bytes`);
|
||||
}).on('close', () => {
|
||||
console.log(`File [${name}] done`);
|
||||
});
|
||||
});
|
||||
bb.on('field', (name, val, info) => {
|
||||
console.log(`Field [${name}]: value: %j`, val);
|
||||
});
|
||||
bb.on('close', () => {
|
||||
console.log('Done parsing form!');
|
||||
res.writeHead(303, { Connection: 'close', Location: '/' });
|
||||
res.end();
|
||||
});
|
||||
req.pipe(bb);
|
||||
} else if (req.method === 'GET') {
|
||||
res.writeHead(200, { Connection: 'close' });
|
||||
res.end(`
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<input type="file" name="filefield"><br />
|
||||
<input type="text" name="textfield"><br />
|
||||
<input type="submit">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
}
|
||||
}).listen(8000, () => {
|
||||
console.log('Listening for requests');
|
||||
});
|
||||
|
||||
// Example output:
|
||||
//
|
||||
// Listening for requests
|
||||
// < ... form submitted ... >
|
||||
// POST request
|
||||
// File [filefield]: filename: "logo.jpg", encoding: "binary", mime: "image/jpeg"
|
||||
// File [filefield] got 11912 bytes
|
||||
// Field [textfield]: value: "testing! :-)"
|
||||
// File [filefield] done
|
||||
// Done parsing form!
|
||||
```
|
||||
|
||||
* Save all incoming files to disk:
|
||||
|
||||
```js
|
||||
const { randomFillSync } = require('crypto');
|
||||
const fs = require('fs');
|
||||
const http = require('http');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const busboy = require('busboy');
|
||||
|
||||
const random = (() => {
|
||||
const buf = Buffer.alloc(16);
|
||||
return () => randomFillSync(buf).toString('hex');
|
||||
})();
|
||||
|
||||
http.createServer((req, res) => {
|
||||
if (req.method === 'POST') {
|
||||
const bb = busboy({ headers: req.headers });
|
||||
bb.on('file', (name, file, info) => {
|
||||
const saveTo = path.join(os.tmpdir(), `busboy-upload-${random()}`);
|
||||
file.pipe(fs.createWriteStream(saveTo));
|
||||
});
|
||||
bb.on('close', () => {
|
||||
res.writeHead(200, { 'Connection': 'close' });
|
||||
res.end(`That's all folks!`);
|
||||
});
|
||||
req.pipe(bb);
|
||||
return;
|
||||
}
|
||||
res.writeHead(404);
|
||||
res.end();
|
||||
}).listen(8000, () => {
|
||||
console.log('Listening for requests');
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
# API
|
||||
|
||||
## Exports
|
||||
|
||||
`busboy` exports a single function:
|
||||
|
||||
**( _function_ )**(< _object_ >config) - Creates and returns a new _Writable_ form parser stream.
|
||||
|
||||
* Valid `config` properties:
|
||||
|
||||
* **headers** - _object_ - These are the HTTP headers of the incoming request, which are used by individual parsers.
|
||||
|
||||
* **highWaterMark** - _integer_ - highWaterMark to use for the parser stream. **Default:** node's _stream.Writable_ default.
|
||||
|
||||
* **fileHwm** - _integer_ - highWaterMark to use for individual file streams. **Default:** node's _stream.Readable_ default.
|
||||
|
||||
* **defCharset** - _string_ - Default character set to use when one isn't defined. **Default:** `'utf8'`.
|
||||
|
||||
* **defParamCharset** - _string_ - For multipart forms, the default character set to use for values of part header parameters (e.g. filename) that are not extended parameters (that contain an explicit charset). **Default:** `'latin1'`.
|
||||
|
||||
* **preservePath** - _boolean_ - If paths in filenames from file parts in a `'multipart/form-data'` request shall be preserved. **Default:** `false`.
|
||||
|
||||
* **limits** - _object_ - Various limits on incoming data. Valid properties are:
|
||||
|
||||
* **fieldNameSize** - _integer_ - Max field name size (in bytes). **Default:** `100`.
|
||||
|
||||
* **fieldSize** - _integer_ - Max field value size (in bytes). **Default:** `1048576` (1MB).
|
||||
|
||||
* **fields** - _integer_ - Max number of non-file fields. **Default:** `Infinity`.
|
||||
|
||||
* **fileSize** - _integer_ - For multipart forms, the max file size (in bytes). **Default:** `Infinity`.
|
||||
|
||||
* **files** - _integer_ - For multipart forms, the max number of file fields. **Default:** `Infinity`.
|
||||
|
||||
* **parts** - _integer_ - For multipart forms, the max number of parts (fields + files). **Default:** `Infinity`.
|
||||
|
||||
* **headerPairs** - _integer_ - For multipart forms, the max number of header key-value pairs to parse. **Default:** `2000` (same as node's http module).
|
||||
|
||||
This function can throw exceptions if there is something wrong with the values in `config`. For example, if the Content-Type in `headers` is missing entirely, is not a supported type, or is missing the boundary for `'multipart/form-data'` requests.
|
||||
|
||||
## (Special) Parser stream events
|
||||
|
||||
* **file**(< _string_ >name, < _Readable_ >stream, < _object_ >info) - Emitted for each new file found. `name` contains the form field name. `stream` is a _Readable_ stream containing the file's data. No transformations/conversions (e.g. base64 to raw binary) are done on the file's data. `info` contains the following properties:
|
||||
|
||||
* `filename` - _string_ - If supplied, this contains the file's filename. **WARNING:** You should almost _never_ use this value as-is (especially if you are using `preservePath: true` in your `config`) as it could contain malicious input. You are better off generating your own (safe) filenames, or at the very least using a hash of the filename.
|
||||
|
||||
* `encoding` - _string_ - The file's `'Content-Transfer-Encoding'` value.
|
||||
|
||||
* `mimeType` - _string_ - The file's `'Content-Type'` value.
|
||||
|
||||
**Note:** If you listen for this event, you should always consume the `stream` whether you care about its contents or not (you can simply do `stream.resume();` if you want to discard/skip the contents), otherwise the `'finish'`/`'close'` event will never fire on the busboy parser stream.
|
||||
However, if you aren't accepting files, you can either simply not listen for the `'file'` event at all or set `limits.files` to `0`, and any/all files will be automatically skipped (these skipped files will still count towards any configured `limits.files` and `limits.parts` limits though).
|
||||
|
||||
**Note:** If a configured `limits.fileSize` limit was reached for a file, `stream` will both have a boolean property `truncated` set to `true` (best checked at the end of the stream) and emit a `'limit'` event to notify you when this happens.
|
||||
|
||||
* **field**(< _string_ >name, < _string_ >value, < _object_ >info) - Emitted for each new non-file field found. `name` contains the form field name. `value` contains the string value of the field. `info` contains the following properties:
|
||||
|
||||
* `nameTruncated` - _boolean_ - Whether `name` was truncated or not (due to a configured `limits.fieldNameSize` limit)
|
||||
|
||||
* `valueTruncated` - _boolean_ - Whether `value` was truncated or not (due to a configured `limits.fieldSize` limit)
|
||||
|
||||
* `encoding` - _string_ - The field's `'Content-Transfer-Encoding'` value.
|
||||
|
||||
* `mimeType` - _string_ - The field's `'Content-Type'` value.
|
||||
|
||||
* **partsLimit**() - Emitted when the configured `limits.parts` limit has been reached. No more `'file'` or `'field'` events will be emitted.
|
||||
|
||||
* **filesLimit**() - Emitted when the configured `limits.files` limit has been reached. No more `'file'` events will be emitted.
|
||||
|
||||
* **fieldsLimit**() - Emitted when the configured `limits.fields` limit has been reached. No more `'field'` events will be emitted.
|
149
deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-big.js
generated
vendored
Normal file
149
deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-big.js
generated
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
'use strict';
|
||||
|
||||
function createMultipartBuffers(boundary, sizes) {
|
||||
const bufs = [];
|
||||
for (let i = 0; i < sizes.length; ++i) {
|
||||
const mb = sizes[i] * 1024 * 1024;
|
||||
bufs.push(Buffer.from([
|
||||
`--${boundary}`,
|
||||
`content-disposition: form-data; name="field${i + 1}"`,
|
||||
'',
|
||||
'0'.repeat(mb),
|
||||
'',
|
||||
].join('\r\n')));
|
||||
}
|
||||
bufs.push(Buffer.from([
|
||||
`--${boundary}--`,
|
||||
'',
|
||||
].join('\r\n')));
|
||||
return bufs;
|
||||
}
|
||||
|
||||
const boundary = '-----------------------------168072824752491622650073';
|
||||
const buffers = createMultipartBuffers(boundary, [
|
||||
10,
|
||||
10,
|
||||
10,
|
||||
20,
|
||||
50,
|
||||
]);
|
||||
const calls = {
|
||||
partBegin: 0,
|
||||
headerField: 0,
|
||||
headerValue: 0,
|
||||
headerEnd: 0,
|
||||
headersEnd: 0,
|
||||
partData: 0,
|
||||
partEnd: 0,
|
||||
end: 0,
|
||||
};
|
||||
|
||||
const moduleName = process.argv[2];
|
||||
switch (moduleName) {
|
||||
case 'busboy': {
|
||||
const busboy = require('busboy');
|
||||
|
||||
const parser = busboy({
|
||||
limits: {
|
||||
fieldSizeLimit: Infinity,
|
||||
},
|
||||
headers: {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
},
|
||||
});
|
||||
parser.on('field', (name, val, info) => {
|
||||
++calls.partBegin;
|
||||
++calls.partData;
|
||||
++calls.partEnd;
|
||||
}).on('close', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
console.time(moduleName);
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'formidable': {
|
||||
const { MultipartParser } = require('formidable');
|
||||
|
||||
const parser = new MultipartParser();
|
||||
parser.initWithBoundary(boundary);
|
||||
parser.on('data', ({ name }) => {
|
||||
++calls[name];
|
||||
if (name === 'end')
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
console.time(moduleName);
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'multiparty': {
|
||||
const { Readable } = require('stream');
|
||||
|
||||
const { Form } = require('multiparty');
|
||||
|
||||
const form = new Form({
|
||||
maxFieldsSize: Infinity,
|
||||
maxFields: Infinity,
|
||||
maxFilesSize: Infinity,
|
||||
autoFields: false,
|
||||
autoFiles: false,
|
||||
});
|
||||
|
||||
const req = new Readable({ read: () => {} });
|
||||
req.headers = {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
};
|
||||
|
||||
function hijack(name, fn) {
|
||||
const oldFn = form[name];
|
||||
form[name] = function() {
|
||||
fn();
|
||||
return oldFn.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
hijack('onParseHeaderField', () => {
|
||||
++calls.headerField;
|
||||
});
|
||||
hijack('onParseHeaderValue', () => {
|
||||
++calls.headerValue;
|
||||
});
|
||||
hijack('onParsePartBegin', () => {
|
||||
++calls.partBegin;
|
||||
});
|
||||
hijack('onParsePartData', () => {
|
||||
++calls.partData;
|
||||
});
|
||||
hijack('onParsePartEnd', () => {
|
||||
++calls.partEnd;
|
||||
});
|
||||
|
||||
form.on('close', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
}).on('part', (p) => p.resume());
|
||||
|
||||
console.time(moduleName);
|
||||
form.parse(req);
|
||||
for (const buf of buffers)
|
||||
req.push(buf);
|
||||
req.push(null);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (moduleName === undefined)
|
||||
console.error('Missing parser module name');
|
||||
else
|
||||
console.error(`Invalid parser module name: ${moduleName}`);
|
||||
process.exit(1);
|
||||
}
|
143
deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-small.js
generated
vendored
Normal file
143
deps/undici/src/node_modules/busboy/bench/bench-multipart-fields-100mb-small.js
generated
vendored
Normal file
|
@ -0,0 +1,143 @@
|
|||
'use strict';
|
||||
|
||||
function createMultipartBuffers(boundary, sizes) {
|
||||
const bufs = [];
|
||||
for (let i = 0; i < sizes.length; ++i) {
|
||||
const mb = sizes[i] * 1024 * 1024;
|
||||
bufs.push(Buffer.from([
|
||||
`--${boundary}`,
|
||||
`content-disposition: form-data; name="field${i + 1}"`,
|
||||
'',
|
||||
'0'.repeat(mb),
|
||||
'',
|
||||
].join('\r\n')));
|
||||
}
|
||||
bufs.push(Buffer.from([
|
||||
`--${boundary}--`,
|
||||
'',
|
||||
].join('\r\n')));
|
||||
return bufs;
|
||||
}
|
||||
|
||||
const boundary = '-----------------------------168072824752491622650073';
|
||||
const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1));
|
||||
const calls = {
|
||||
partBegin: 0,
|
||||
headerField: 0,
|
||||
headerValue: 0,
|
||||
headerEnd: 0,
|
||||
headersEnd: 0,
|
||||
partData: 0,
|
||||
partEnd: 0,
|
||||
end: 0,
|
||||
};
|
||||
|
||||
const moduleName = process.argv[2];
|
||||
switch (moduleName) {
|
||||
case 'busboy': {
|
||||
const busboy = require('busboy');
|
||||
|
||||
const parser = busboy({
|
||||
limits: {
|
||||
fieldSizeLimit: Infinity,
|
||||
},
|
||||
headers: {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
},
|
||||
});
|
||||
parser.on('field', (name, val, info) => {
|
||||
++calls.partBegin;
|
||||
++calls.partData;
|
||||
++calls.partEnd;
|
||||
}).on('close', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
console.time(moduleName);
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'formidable': {
|
||||
const { MultipartParser } = require('formidable');
|
||||
|
||||
const parser = new MultipartParser();
|
||||
parser.initWithBoundary(boundary);
|
||||
parser.on('data', ({ name }) => {
|
||||
++calls[name];
|
||||
if (name === 'end')
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
console.time(moduleName);
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'multiparty': {
|
||||
const { Readable } = require('stream');
|
||||
|
||||
const { Form } = require('multiparty');
|
||||
|
||||
const form = new Form({
|
||||
maxFieldsSize: Infinity,
|
||||
maxFields: Infinity,
|
||||
maxFilesSize: Infinity,
|
||||
autoFields: false,
|
||||
autoFiles: false,
|
||||
});
|
||||
|
||||
const req = new Readable({ read: () => {} });
|
||||
req.headers = {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
};
|
||||
|
||||
function hijack(name, fn) {
|
||||
const oldFn = form[name];
|
||||
form[name] = function() {
|
||||
fn();
|
||||
return oldFn.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
hijack('onParseHeaderField', () => {
|
||||
++calls.headerField;
|
||||
});
|
||||
hijack('onParseHeaderValue', () => {
|
||||
++calls.headerValue;
|
||||
});
|
||||
hijack('onParsePartBegin', () => {
|
||||
++calls.partBegin;
|
||||
});
|
||||
hijack('onParsePartData', () => {
|
||||
++calls.partData;
|
||||
});
|
||||
hijack('onParsePartEnd', () => {
|
||||
++calls.partEnd;
|
||||
});
|
||||
|
||||
form.on('close', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
}).on('part', (p) => p.resume());
|
||||
|
||||
console.time(moduleName);
|
||||
form.parse(req);
|
||||
for (const buf of buffers)
|
||||
req.push(buf);
|
||||
req.push(null);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (moduleName === undefined)
|
||||
console.error('Missing parser module name');
|
||||
else
|
||||
console.error(`Invalid parser module name: ${moduleName}`);
|
||||
process.exit(1);
|
||||
}
|
154
deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-big.js
generated
vendored
Normal file
154
deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-big.js
generated
vendored
Normal file
|
@ -0,0 +1,154 @@
|
|||
'use strict';
|
||||
|
||||
function createMultipartBuffers(boundary, sizes) {
|
||||
const bufs = [];
|
||||
for (let i = 0; i < sizes.length; ++i) {
|
||||
const mb = sizes[i] * 1024 * 1024;
|
||||
bufs.push(Buffer.from([
|
||||
`--${boundary}`,
|
||||
`content-disposition: form-data; name="file${i + 1}"; `
|
||||
+ `filename="random${i + 1}.bin"`,
|
||||
'content-type: application/octet-stream',
|
||||
'',
|
||||
'0'.repeat(mb),
|
||||
'',
|
||||
].join('\r\n')));
|
||||
}
|
||||
bufs.push(Buffer.from([
|
||||
`--${boundary}--`,
|
||||
'',
|
||||
].join('\r\n')));
|
||||
return bufs;
|
||||
}
|
||||
|
||||
const boundary = '-----------------------------168072824752491622650073';
|
||||
const buffers = createMultipartBuffers(boundary, [
|
||||
10,
|
||||
10,
|
||||
10,
|
||||
20,
|
||||
50,
|
||||
]);
|
||||
const calls = {
|
||||
partBegin: 0,
|
||||
headerField: 0,
|
||||
headerValue: 0,
|
||||
headerEnd: 0,
|
||||
headersEnd: 0,
|
||||
partData: 0,
|
||||
partEnd: 0,
|
||||
end: 0,
|
||||
};
|
||||
|
||||
const moduleName = process.argv[2];
|
||||
switch (moduleName) {
|
||||
case 'busboy': {
|
||||
const busboy = require('busboy');
|
||||
|
||||
const parser = busboy({
|
||||
limits: {
|
||||
fieldSizeLimit: Infinity,
|
||||
},
|
||||
headers: {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
},
|
||||
});
|
||||
parser.on('file', (name, stream, info) => {
|
||||
++calls.partBegin;
|
||||
stream.on('data', (chunk) => {
|
||||
++calls.partData;
|
||||
}).on('end', () => {
|
||||
++calls.partEnd;
|
||||
});
|
||||
}).on('close', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
console.time(moduleName);
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'formidable': {
|
||||
const { MultipartParser } = require('formidable');
|
||||
|
||||
const parser = new MultipartParser();
|
||||
parser.initWithBoundary(boundary);
|
||||
parser.on('data', ({ name }) => {
|
||||
++calls[name];
|
||||
if (name === 'end')
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
console.time(moduleName);
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'multiparty': {
|
||||
const { Readable } = require('stream');
|
||||
|
||||
const { Form } = require('multiparty');
|
||||
|
||||
const form = new Form({
|
||||
maxFieldsSize: Infinity,
|
||||
maxFields: Infinity,
|
||||
maxFilesSize: Infinity,
|
||||
autoFields: false,
|
||||
autoFiles: false,
|
||||
});
|
||||
|
||||
const req = new Readable({ read: () => {} });
|
||||
req.headers = {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
};
|
||||
|
||||
function hijack(name, fn) {
|
||||
const oldFn = form[name];
|
||||
form[name] = function() {
|
||||
fn();
|
||||
return oldFn.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
hijack('onParseHeaderField', () => {
|
||||
++calls.headerField;
|
||||
});
|
||||
hijack('onParseHeaderValue', () => {
|
||||
++calls.headerValue;
|
||||
});
|
||||
hijack('onParsePartBegin', () => {
|
||||
++calls.partBegin;
|
||||
});
|
||||
hijack('onParsePartData', () => {
|
||||
++calls.partData;
|
||||
});
|
||||
hijack('onParsePartEnd', () => {
|
||||
++calls.partEnd;
|
||||
});
|
||||
|
||||
form.on('close', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
}).on('part', (p) => p.resume());
|
||||
|
||||
console.time(moduleName);
|
||||
form.parse(req);
|
||||
for (const buf of buffers)
|
||||
req.push(buf);
|
||||
req.push(null);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (moduleName === undefined)
|
||||
console.error('Missing parser module name');
|
||||
else
|
||||
console.error(`Invalid parser module name: ${moduleName}`);
|
||||
process.exit(1);
|
||||
}
|
148
deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-small.js
generated
vendored
Normal file
148
deps/undici/src/node_modules/busboy/bench/bench-multipart-files-100mb-small.js
generated
vendored
Normal file
|
@ -0,0 +1,148 @@
|
|||
'use strict';
|
||||
|
||||
function createMultipartBuffers(boundary, sizes) {
|
||||
const bufs = [];
|
||||
for (let i = 0; i < sizes.length; ++i) {
|
||||
const mb = sizes[i] * 1024 * 1024;
|
||||
bufs.push(Buffer.from([
|
||||
`--${boundary}`,
|
||||
`content-disposition: form-data; name="file${i + 1}"; `
|
||||
+ `filename="random${i + 1}.bin"`,
|
||||
'content-type: application/octet-stream',
|
||||
'',
|
||||
'0'.repeat(mb),
|
||||
'',
|
||||
].join('\r\n')));
|
||||
}
|
||||
bufs.push(Buffer.from([
|
||||
`--${boundary}--`,
|
||||
'',
|
||||
].join('\r\n')));
|
||||
return bufs;
|
||||
}
|
||||
|
||||
const boundary = '-----------------------------168072824752491622650073';
|
||||
const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1));
|
||||
const calls = {
|
||||
partBegin: 0,
|
||||
headerField: 0,
|
||||
headerValue: 0,
|
||||
headerEnd: 0,
|
||||
headersEnd: 0,
|
||||
partData: 0,
|
||||
partEnd: 0,
|
||||
end: 0,
|
||||
};
|
||||
|
||||
const moduleName = process.argv[2];
|
||||
switch (moduleName) {
|
||||
case 'busboy': {
|
||||
const busboy = require('busboy');
|
||||
|
||||
const parser = busboy({
|
||||
limits: {
|
||||
fieldSizeLimit: Infinity,
|
||||
},
|
||||
headers: {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
},
|
||||
});
|
||||
parser.on('file', (name, stream, info) => {
|
||||
++calls.partBegin;
|
||||
stream.on('data', (chunk) => {
|
||||
++calls.partData;
|
||||
}).on('end', () => {
|
||||
++calls.partEnd;
|
||||
});
|
||||
}).on('close', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
console.time(moduleName);
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'formidable': {
|
||||
const { MultipartParser } = require('formidable');
|
||||
|
||||
const parser = new MultipartParser();
|
||||
parser.initWithBoundary(boundary);
|
||||
parser.on('data', ({ name }) => {
|
||||
++calls[name];
|
||||
if (name === 'end')
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
console.time(moduleName);
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'multiparty': {
|
||||
const { Readable } = require('stream');
|
||||
|
||||
const { Form } = require('multiparty');
|
||||
|
||||
const form = new Form({
|
||||
maxFieldsSize: Infinity,
|
||||
maxFields: Infinity,
|
||||
maxFilesSize: Infinity,
|
||||
autoFields: false,
|
||||
autoFiles: false,
|
||||
});
|
||||
|
||||
const req = new Readable({ read: () => {} });
|
||||
req.headers = {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
};
|
||||
|
||||
function hijack(name, fn) {
|
||||
const oldFn = form[name];
|
||||
form[name] = function() {
|
||||
fn();
|
||||
return oldFn.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
hijack('onParseHeaderField', () => {
|
||||
++calls.headerField;
|
||||
});
|
||||
hijack('onParseHeaderValue', () => {
|
||||
++calls.headerValue;
|
||||
});
|
||||
hijack('onParsePartBegin', () => {
|
||||
++calls.partBegin;
|
||||
});
|
||||
hijack('onParsePartData', () => {
|
||||
++calls.partData;
|
||||
});
|
||||
hijack('onParsePartEnd', () => {
|
||||
++calls.partEnd;
|
||||
});
|
||||
|
||||
form.on('close', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
}).on('part', (p) => p.resume());
|
||||
|
||||
console.time(moduleName);
|
||||
form.parse(req);
|
||||
for (const buf of buffers)
|
||||
req.push(buf);
|
||||
req.push(null);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (moduleName === undefined)
|
||||
console.error('Missing parser module name');
|
||||
else
|
||||
console.error(`Invalid parser module name: ${moduleName}`);
|
||||
process.exit(1);
|
||||
}
|
101
deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js
generated
vendored
Normal file
101
deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js
generated
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
'use strict';
|
||||
|
||||
const buffers = [
|
||||
Buffer.from(
|
||||
(new Array(100)).fill('').map((_, i) => `key${i}=value${i}`).join('&')
|
||||
),
|
||||
];
|
||||
const calls = {
|
||||
field: 0,
|
||||
end: 0,
|
||||
};
|
||||
|
||||
let n = 3e3;
|
||||
|
||||
const moduleName = process.argv[2];
|
||||
switch (moduleName) {
|
||||
case 'busboy': {
|
||||
const busboy = require('busboy');
|
||||
|
||||
console.time(moduleName);
|
||||
(function next() {
|
||||
const parser = busboy({
|
||||
limits: {
|
||||
fieldSizeLimit: Infinity,
|
||||
},
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
|
||||
},
|
||||
});
|
||||
parser.on('field', (name, val, info) => {
|
||||
++calls.field;
|
||||
}).on('close', () => {
|
||||
++calls.end;
|
||||
if (--n === 0)
|
||||
console.timeEnd(moduleName);
|
||||
else
|
||||
process.nextTick(next);
|
||||
});
|
||||
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
parser.end();
|
||||
})();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'formidable': {
|
||||
const QuerystringParser =
|
||||
require('formidable/src/parsers/Querystring.js');
|
||||
|
||||
console.time(moduleName);
|
||||
(function next() {
|
||||
const parser = new QuerystringParser();
|
||||
parser.on('data', (obj) => {
|
||||
++calls.field;
|
||||
}).on('end', () => {
|
||||
++calls.end;
|
||||
if (--n === 0)
|
||||
console.timeEnd(moduleName);
|
||||
else
|
||||
process.nextTick(next);
|
||||
});
|
||||
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
parser.end();
|
||||
})();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'formidable-streaming': {
|
||||
const QuerystringParser =
|
||||
require('formidable/src/parsers/StreamingQuerystring.js');
|
||||
|
||||
console.time(moduleName);
|
||||
(function next() {
|
||||
const parser = new QuerystringParser();
|
||||
parser.on('data', (obj) => {
|
||||
++calls.field;
|
||||
}).on('end', () => {
|
||||
++calls.end;
|
||||
if (--n === 0)
|
||||
console.timeEnd(moduleName);
|
||||
else
|
||||
process.nextTick(next);
|
||||
});
|
||||
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
parser.end();
|
||||
})();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (moduleName === undefined)
|
||||
console.error('Missing parser module name');
|
||||
else
|
||||
console.error(`Invalid parser module name: ${moduleName}`);
|
||||
process.exit(1);
|
||||
}
|
84
deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js
generated
vendored
Normal file
84
deps/undici/src/node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
'use strict';
|
||||
|
||||
const buffers = [
|
||||
Buffer.from(
|
||||
(new Array(900)).fill('').map((_, i) => `key${i}=value${i}`).join('&')
|
||||
),
|
||||
];
|
||||
const calls = {
|
||||
field: 0,
|
||||
end: 0,
|
||||
};
|
||||
|
||||
const moduleName = process.argv[2];
|
||||
switch (moduleName) {
|
||||
case 'busboy': {
|
||||
const busboy = require('busboy');
|
||||
|
||||
console.time(moduleName);
|
||||
const parser = busboy({
|
||||
limits: {
|
||||
fieldSizeLimit: Infinity,
|
||||
},
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
|
||||
},
|
||||
});
|
||||
parser.on('field', (name, val, info) => {
|
||||
++calls.field;
|
||||
}).on('close', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
parser.end();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'formidable': {
|
||||
const QuerystringParser =
|
||||
require('formidable/src/parsers/Querystring.js');
|
||||
|
||||
console.time(moduleName);
|
||||
const parser = new QuerystringParser();
|
||||
parser.on('data', (obj) => {
|
||||
++calls.field;
|
||||
}).on('end', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
parser.end();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'formidable-streaming': {
|
||||
const QuerystringParser =
|
||||
require('formidable/src/parsers/StreamingQuerystring.js');
|
||||
|
||||
console.time(moduleName);
|
||||
const parser = new QuerystringParser();
|
||||
parser.on('data', (obj) => {
|
||||
++calls.field;
|
||||
}).on('end', () => {
|
||||
++calls.end;
|
||||
console.timeEnd(moduleName);
|
||||
});
|
||||
|
||||
for (const buf of buffers)
|
||||
parser.write(buf);
|
||||
parser.end();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (moduleName === undefined)
|
||||
console.error('Missing parser module name');
|
||||
else
|
||||
console.error(`Invalid parser module name: ${moduleName}`);
|
||||
process.exit(1);
|
||||
}
|
57
deps/undici/src/node_modules/busboy/lib/index.js
generated
vendored
Normal file
57
deps/undici/src/node_modules/busboy/lib/index.js
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
'use strict';
|
||||
|
||||
const { parseContentType } = require('./utils.js');
|
||||
|
||||
function getInstance(cfg) {
|
||||
const headers = cfg.headers;
|
||||
const conType = parseContentType(headers['content-type']);
|
||||
if (!conType)
|
||||
throw new Error('Malformed content type');
|
||||
|
||||
for (const type of TYPES) {
|
||||
const matched = type.detect(conType);
|
||||
if (!matched)
|
||||
continue;
|
||||
|
||||
const instanceCfg = {
|
||||
limits: cfg.limits,
|
||||
headers,
|
||||
conType,
|
||||
highWaterMark: undefined,
|
||||
fileHwm: undefined,
|
||||
defCharset: undefined,
|
||||
defParamCharset: undefined,
|
||||
preservePath: false,
|
||||
};
|
||||
if (cfg.highWaterMark)
|
||||
instanceCfg.highWaterMark = cfg.highWaterMark;
|
||||
if (cfg.fileHwm)
|
||||
instanceCfg.fileHwm = cfg.fileHwm;
|
||||
instanceCfg.defCharset = cfg.defCharset;
|
||||
instanceCfg.defParamCharset = cfg.defParamCharset;
|
||||
instanceCfg.preservePath = cfg.preservePath;
|
||||
return new type(instanceCfg);
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported content type: ${headers['content-type']}`);
|
||||
}
|
||||
|
||||
// Note: types are explicitly listed here for easier bundling
|
||||
// See: https://github.com/mscdex/busboy/issues/121
|
||||
const TYPES = [
|
||||
require('./types/multipart'),
|
||||
require('./types/urlencoded'),
|
||||
].filter(function(typemod) { return typeof typemod.detect === 'function'; });
|
||||
|
||||
module.exports = (cfg) => {
|
||||
if (typeof cfg !== 'object' || cfg === null)
|
||||
cfg = {};
|
||||
|
||||
if (typeof cfg.headers !== 'object'
|
||||
|| cfg.headers === null
|
||||
|| typeof cfg.headers['content-type'] !== 'string') {
|
||||
throw new Error('Missing Content-Type');
|
||||
}
|
||||
|
||||
return getInstance(cfg);
|
||||
};
|
653
deps/undici/src/node_modules/busboy/lib/types/multipart.js
generated
vendored
Normal file
653
deps/undici/src/node_modules/busboy/lib/types/multipart.js
generated
vendored
Normal file
|
@ -0,0 +1,653 @@
|
|||
'use strict';
|
||||
|
||||
const { Readable, Writable } = require('stream');
|
||||
|
||||
const StreamSearch = require('streamsearch');
|
||||
|
||||
const {
|
||||
basename,
|
||||
convertToUTF8,
|
||||
getDecoder,
|
||||
parseContentType,
|
||||
parseDisposition,
|
||||
} = require('../utils.js');
|
||||
|
||||
const BUF_CRLF = Buffer.from('\r\n');
|
||||
const BUF_CR = Buffer.from('\r');
|
||||
const BUF_DASH = Buffer.from('-');
|
||||
|
||||
function noop() {}
|
||||
|
||||
const MAX_HEADER_PAIRS = 2000; // From node
|
||||
const MAX_HEADER_SIZE = 16 * 1024; // From node (its default value)
|
||||
|
||||
const HPARSER_NAME = 0;
|
||||
const HPARSER_PRE_OWS = 1;
|
||||
const HPARSER_VALUE = 2;
|
||||
class HeaderParser {
|
||||
constructor(cb) {
|
||||
this.header = Object.create(null);
|
||||
this.pairCount = 0;
|
||||
this.byteCount = 0;
|
||||
this.state = HPARSER_NAME;
|
||||
this.name = '';
|
||||
this.value = '';
|
||||
this.crlf = 0;
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.header = Object.create(null);
|
||||
this.pairCount = 0;
|
||||
this.byteCount = 0;
|
||||
this.state = HPARSER_NAME;
|
||||
this.name = '';
|
||||
this.value = '';
|
||||
this.crlf = 0;
|
||||
}
|
||||
|
||||
push(chunk, pos, end) {
|
||||
let start = pos;
|
||||
while (pos < end) {
|
||||
switch (this.state) {
|
||||
case HPARSER_NAME: {
|
||||
let done = false;
|
||||
for (; pos < end; ++pos) {
|
||||
if (this.byteCount === MAX_HEADER_SIZE)
|
||||
return -1;
|
||||
++this.byteCount;
|
||||
const code = chunk[pos];
|
||||
if (TOKEN[code] !== 1) {
|
||||
if (code !== 58/* ':' */)
|
||||
return -1;
|
||||
this.name += chunk.latin1Slice(start, pos);
|
||||
if (this.name.length === 0)
|
||||
return -1;
|
||||
++pos;
|
||||
done = true;
|
||||
this.state = HPARSER_PRE_OWS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
this.name += chunk.latin1Slice(start, pos);
|
||||
break;
|
||||
}
|
||||
// FALLTHROUGH
|
||||
}
|
||||
case HPARSER_PRE_OWS: {
|
||||
// Skip optional whitespace
|
||||
let done = false;
|
||||
for (; pos < end; ++pos) {
|
||||
if (this.byteCount === MAX_HEADER_SIZE)
|
||||
return -1;
|
||||
++this.byteCount;
|
||||
const code = chunk[pos];
|
||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */) {
|
||||
start = pos;
|
||||
done = true;
|
||||
this.state = HPARSER_VALUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!done)
|
||||
break;
|
||||
// FALLTHROUGH
|
||||
}
|
||||
case HPARSER_VALUE:
|
||||
switch (this.crlf) {
|
||||
case 0: // Nothing yet
|
||||
for (; pos < end; ++pos) {
|
||||
if (this.byteCount === MAX_HEADER_SIZE)
|
||||
return -1;
|
||||
++this.byteCount;
|
||||
const code = chunk[pos];
|
||||
if (FIELD_VCHAR[code] !== 1) {
|
||||
if (code !== 13/* '\r' */)
|
||||
return -1;
|
||||
++this.crlf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.value += chunk.latin1Slice(start, pos++);
|
||||
break;
|
||||
case 1: // Received CR
|
||||
if (this.byteCount === MAX_HEADER_SIZE)
|
||||
return -1;
|
||||
++this.byteCount;
|
||||
if (chunk[pos++] !== 10/* '\n' */)
|
||||
return -1;
|
||||
++this.crlf;
|
||||
break;
|
||||
case 2: { // Received CR LF
|
||||
if (this.byteCount === MAX_HEADER_SIZE)
|
||||
return -1;
|
||||
++this.byteCount;
|
||||
const code = chunk[pos];
|
||||
if (code === 32/* ' ' */ || code === 9/* '\t' */) {
|
||||
// Folded value
|
||||
start = pos;
|
||||
this.crlf = 0;
|
||||
} else {
|
||||
if (++this.pairCount < MAX_HEADER_PAIRS) {
|
||||
this.name = this.name.toLowerCase();
|
||||
if (this.header[this.name] === undefined)
|
||||
this.header[this.name] = [this.value];
|
||||
else
|
||||
this.header[this.name].push(this.value);
|
||||
}
|
||||
if (code === 13/* '\r' */) {
|
||||
++this.crlf;
|
||||
++pos;
|
||||
} else {
|
||||
// Assume start of next header field name
|
||||
start = pos;
|
||||
this.crlf = 0;
|
||||
this.state = HPARSER_NAME;
|
||||
this.name = '';
|
||||
this.value = '';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: { // Received CR LF CR
|
||||
if (this.byteCount === MAX_HEADER_SIZE)
|
||||
return -1;
|
||||
++this.byteCount;
|
||||
if (chunk[pos++] !== 10/* '\n' */)
|
||||
return -1;
|
||||
// End of header
|
||||
const header = this.header;
|
||||
this.reset();
|
||||
this.cb(header);
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
class FileStream extends Readable {
|
||||
constructor(opts, owner) {
|
||||
super(opts);
|
||||
this.truncated = false;
|
||||
this._readcb = null;
|
||||
this.once('end', () => {
|
||||
// We need to make sure that we call any outstanding _writecb() that is
|
||||
// associated with this file so that processing of the rest of the form
|
||||
// can continue. This may not happen if the file stream ends right after
|
||||
// backpressure kicks in, so we force it here.
|
||||
this._read();
|
||||
if (--owner._fileEndsLeft === 0 && owner._finalcb) {
|
||||
const cb = owner._finalcb;
|
||||
owner._finalcb = null;
|
||||
// Make sure other 'end' event handlers get a chance to be executed
|
||||
// before busboy's 'finish' event is emitted
|
||||
process.nextTick(cb);
|
||||
}
|
||||
});
|
||||
}
|
||||
_read(n) {
|
||||
const cb = this._readcb;
|
||||
if (cb) {
|
||||
this._readcb = null;
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ignoreData = {
|
||||
push: (chunk, pos) => {},
|
||||
destroy: () => {},
|
||||
};
|
||||
|
||||
function callAndUnsetCb(self, err) {
|
||||
const cb = self._writecb;
|
||||
self._writecb = null;
|
||||
if (err)
|
||||
self.destroy(err);
|
||||
else if (cb)
|
||||
cb();
|
||||
}
|
||||
|
||||
function nullDecoder(val, hint) {
|
||||
return val;
|
||||
}
|
||||
|
||||
class Multipart extends Writable {
|
||||
constructor(cfg) {
|
||||
const streamOpts = {
|
||||
autoDestroy: true,
|
||||
emitClose: true,
|
||||
highWaterMark: (typeof cfg.highWaterMark === 'number'
|
||||
? cfg.highWaterMark
|
||||
: undefined),
|
||||
};
|
||||
super(streamOpts);
|
||||
|
||||
if (!cfg.conType.params || typeof cfg.conType.params.boundary !== 'string')
|
||||
throw new Error('Multipart: Boundary not found');
|
||||
|
||||
const boundary = cfg.conType.params.boundary;
|
||||
const paramDecoder = (typeof cfg.defParamCharset === 'string'
|
||||
&& cfg.defParamCharset
|
||||
? getDecoder(cfg.defParamCharset)
|
||||
: nullDecoder);
|
||||
const defCharset = (cfg.defCharset || 'utf8');
|
||||
const preservePath = cfg.preservePath;
|
||||
const fileOpts = {
|
||||
autoDestroy: true,
|
||||
emitClose: true,
|
||||
highWaterMark: (typeof cfg.fileHwm === 'number'
|
||||
? cfg.fileHwm
|
||||
: undefined),
|
||||
};
|
||||
|
||||
const limits = cfg.limits;
|
||||
const fieldSizeLimit = (limits && typeof limits.fieldSize === 'number'
|
||||
? limits.fieldSize
|
||||
: 1 * 1024 * 1024);
|
||||
const fileSizeLimit = (limits && typeof limits.fileSize === 'number'
|
||||
? limits.fileSize
|
||||
: Infinity);
|
||||
const filesLimit = (limits && typeof limits.files === 'number'
|
||||
? limits.files
|
||||
: Infinity);
|
||||
const fieldsLimit = (limits && typeof limits.fields === 'number'
|
||||
? limits.fields
|
||||
: Infinity);
|
||||
const partsLimit = (limits && typeof limits.parts === 'number'
|
||||
? limits.parts
|
||||
: Infinity);
|
||||
|
||||
let parts = -1; // Account for initial boundary
|
||||
let fields = 0;
|
||||
let files = 0;
|
||||
let skipPart = false;
|
||||
|
||||
this._fileEndsLeft = 0;
|
||||
this._fileStream = undefined;
|
||||
this._complete = false;
|
||||
let fileSize = 0;
|
||||
|
||||
let field;
|
||||
let fieldSize = 0;
|
||||
let partCharset;
|
||||
let partEncoding;
|
||||
let partType;
|
||||
let partName;
|
||||
let partTruncated = false;
|
||||
|
||||
let hitFilesLimit = false;
|
||||
let hitFieldsLimit = false;
|
||||
|
||||
this._hparser = null;
|
||||
const hparser = new HeaderParser((header) => {
|
||||
this._hparser = null;
|
||||
skipPart = false;
|
||||
|
||||
partType = 'text/plain';
|
||||
partCharset = defCharset;
|
||||
partEncoding = '7bit';
|
||||
partName = undefined;
|
||||
partTruncated = false;
|
||||
|
||||
let filename;
|
||||
if (!header['content-disposition']) {
|
||||
skipPart = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const disp = parseDisposition(header['content-disposition'][0],
|
||||
paramDecoder);
|
||||
if (!disp || disp.type !== 'form-data') {
|
||||
skipPart = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (disp.params) {
|
||||
if (disp.params.name)
|
||||
partName = disp.params.name;
|
||||
|
||||
if (disp.params['filename*'])
|
||||
filename = disp.params['filename*'];
|
||||
else if (disp.params.filename)
|
||||
filename = disp.params.filename;
|
||||
|
||||
if (filename !== undefined && !preservePath)
|
||||
filename = basename(filename);
|
||||
}
|
||||
|
||||
if (header['content-type']) {
|
||||
const conType = parseContentType(header['content-type'][0]);
|
||||
if (conType) {
|
||||
partType = `${conType.type}/${conType.subtype}`;
|
||||
if (conType.params && typeof conType.params.charset === 'string')
|
||||
partCharset = conType.params.charset.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
if (header['content-transfer-encoding'])
|
||||
partEncoding = header['content-transfer-encoding'][0].toLowerCase();
|
||||
|
||||
if (partType === 'application/octet-stream' || filename !== undefined) {
|
||||
// File
|
||||
|
||||
if (files === filesLimit) {
|
||||
if (!hitFilesLimit) {
|
||||
hitFilesLimit = true;
|
||||
this.emit('filesLimit');
|
||||
}
|
||||
skipPart = true;
|
||||
return;
|
||||
}
|
||||
++files;
|
||||
|
||||
if (this.listenerCount('file') === 0) {
|
||||
skipPart = true;
|
||||
return;
|
||||
}
|
||||
|
||||
fileSize = 0;
|
||||
this._fileStream = new FileStream(fileOpts, this);
|
||||
++this._fileEndsLeft;
|
||||
this.emit(
|
||||
'file',
|
||||
partName,
|
||||
this._fileStream,
|
||||
{ filename,
|
||||
encoding: partEncoding,
|
||||
mimeType: partType }
|
||||
);
|
||||
} else {
|
||||
// Non-file
|
||||
|
||||
if (fields === fieldsLimit) {
|
||||
if (!hitFieldsLimit) {
|
||||
hitFieldsLimit = true;
|
||||
this.emit('fieldsLimit');
|
||||
}
|
||||
skipPart = true;
|
||||
return;
|
||||
}
|
||||
++fields;
|
||||
|
||||
if (this.listenerCount('field') === 0) {
|
||||
skipPart = true;
|
||||
return;
|
||||
}
|
||||
|
||||
field = [];
|
||||
fieldSize = 0;
|
||||
}
|
||||
});
|
||||
|
||||
let matchPostBoundary = 0;
|
||||
const ssCb = (isMatch, data, start, end, isDataSafe) => {
|
||||
retrydata:
|
||||
while (data) {
|
||||
if (this._hparser !== null) {
|
||||
const ret = this._hparser.push(data, start, end);
|
||||
if (ret === -1) {
|
||||
this._hparser = null;
|
||||
hparser.reset();
|
||||
this.emit('error', new Error('Malformed part header'));
|
||||
break;
|
||||
}
|
||||
start = ret;
|
||||
}
|
||||
|
||||
if (start === end)
|
||||
break;
|
||||
|
||||
if (matchPostBoundary !== 0) {
|
||||
if (matchPostBoundary === 1) {
|
||||
switch (data[start]) {
|
||||
case 45: // '-'
|
||||
// Try matching '--' after boundary
|
||||
matchPostBoundary = 2;
|
||||
++start;
|
||||
break;
|
||||
case 13: // '\r'
|
||||
// Try matching CR LF before header
|
||||
matchPostBoundary = 3;
|
||||
++start;
|
||||
break;
|
||||
default:
|
||||
matchPostBoundary = 0;
|
||||
}
|
||||
if (start === end)
|
||||
return;
|
||||
}
|
||||
|
||||
if (matchPostBoundary === 2) {
|
||||
matchPostBoundary = 0;
|
||||
if (data[start] === 45/* '-' */) {
|
||||
// End of multipart data
|
||||
this._complete = true;
|
||||
this._bparser = ignoreData;
|
||||
return;
|
||||
}
|
||||
// We saw something other than '-', so put the dash we consumed
|
||||
// "back"
|
||||
const writecb = this._writecb;
|
||||
this._writecb = noop;
|
||||
ssCb(false, BUF_DASH, 0, 1, false);
|
||||
this._writecb = writecb;
|
||||
} else if (matchPostBoundary === 3) {
|
||||
matchPostBoundary = 0;
|
||||
if (data[start] === 10/* '\n' */) {
|
||||
++start;
|
||||
if (parts >= partsLimit)
|
||||
break;
|
||||
// Prepare the header parser
|
||||
this._hparser = hparser;
|
||||
if (start === end)
|
||||
break;
|
||||
// Process the remaining data as a header
|
||||
continue retrydata;
|
||||
} else {
|
||||
// We saw something other than LF, so put the CR we consumed
|
||||
// "back"
|
||||
const writecb = this._writecb;
|
||||
this._writecb = noop;
|
||||
ssCb(false, BUF_CR, 0, 1, false);
|
||||
this._writecb = writecb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipPart) {
|
||||
if (this._fileStream) {
|
||||
let chunk;
|
||||
const actualLen = Math.min(end - start, fileSizeLimit - fileSize);
|
||||
if (!isDataSafe) {
|
||||
chunk = Buffer.allocUnsafe(actualLen);
|
||||
data.copy(chunk, 0, start, start + actualLen);
|
||||
} else {
|
||||
chunk = data.slice(start, start + actualLen);
|
||||
}
|
||||
|
||||
fileSize += chunk.length;
|
||||
if (fileSize === fileSizeLimit) {
|
||||
if (chunk.length > 0)
|
||||
this._fileStream.push(chunk);
|
||||
this._fileStream.emit('limit');
|
||||
this._fileStream.truncated = true;
|
||||
skipPart = true;
|
||||
} else if (!this._fileStream.push(chunk)) {
|
||||
if (this._writecb)
|
||||
this._fileStream._readcb = this._writecb;
|
||||
this._writecb = null;
|
||||
}
|
||||
} else if (field !== undefined) {
|
||||
let chunk;
|
||||
const actualLen = Math.min(
|
||||
end - start,
|
||||
fieldSizeLimit - fieldSize
|
||||
);
|
||||
if (!isDataSafe) {
|
||||
chunk = Buffer.allocUnsafe(actualLen);
|
||||
data.copy(chunk, 0, start, start + actualLen);
|
||||
} else {
|
||||
chunk = data.slice(start, start + actualLen);
|
||||
}
|
||||
|
||||
fieldSize += actualLen;
|
||||
field.push(chunk);
|
||||
if (fieldSize === fieldSizeLimit) {
|
||||
skipPart = true;
|
||||
partTruncated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (isMatch) {
|
||||
matchPostBoundary = 1;
|
||||
|
||||
if (this._fileStream) {
|
||||
// End the active file stream if the previous part was a file
|
||||
this._fileStream.push(null);
|
||||
this._fileStream = null;
|
||||
} else if (field !== undefined) {
|
||||
let data;
|
||||
switch (field.length) {
|
||||
case 0:
|
||||
data = '';
|
||||
break;
|
||||
case 1:
|
||||
data = convertToUTF8(field[0], partCharset, 0);
|
||||
break;
|
||||
default:
|
||||
data = convertToUTF8(
|
||||
Buffer.concat(field, fieldSize),
|
||||
partCharset,
|
||||
0
|
||||
);
|
||||
}
|
||||
field = undefined;
|
||||
fieldSize = 0;
|
||||
this.emit(
|
||||
'field',
|
||||
partName,
|
||||
data,
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: partTruncated,
|
||||
encoding: partEncoding,
|
||||
mimeType: partType }
|
||||
);
|
||||
}
|
||||
|
||||
if (++parts === partsLimit)
|
||||
this.emit('partsLimit');
|
||||
}
|
||||
};
|
||||
this._bparser = new StreamSearch(`\r\n--${boundary}`, ssCb);
|
||||
|
||||
this._writecb = null;
|
||||
this._finalcb = null;
|
||||
|
||||
// Just in case there is no preamble
|
||||
this.write(BUF_CRLF);
|
||||
}
|
||||
|
||||
static detect(conType) {
|
||||
return (conType.type === 'multipart' && conType.subtype === 'form-data');
|
||||
}
|
||||
|
||||
_write(chunk, enc, cb) {
|
||||
this._writecb = cb;
|
||||
this._bparser.push(chunk, 0);
|
||||
if (this._writecb)
|
||||
callAndUnsetCb(this);
|
||||
}
|
||||
|
||||
_destroy(err, cb) {
|
||||
this._hparser = null;
|
||||
this._bparser = ignoreData;
|
||||
if (!err)
|
||||
err = checkEndState(this);
|
||||
const fileStream = this._fileStream;
|
||||
if (fileStream) {
|
||||
this._fileStream = null;
|
||||
fileStream.destroy(err);
|
||||
}
|
||||
cb(err);
|
||||
}
|
||||
|
||||
_final(cb) {
|
||||
this._bparser.destroy();
|
||||
if (!this._complete)
|
||||
return cb(new Error('Unexpected end of form'));
|
||||
if (this._fileEndsLeft)
|
||||
this._finalcb = finalcb.bind(null, this, cb);
|
||||
else
|
||||
finalcb(this, cb);
|
||||
}
|
||||
}
|
||||
|
||||
function finalcb(self, cb, err) {
|
||||
if (err)
|
||||
return cb(err);
|
||||
err = checkEndState(self);
|
||||
cb(err);
|
||||
}
|
||||
|
||||
function checkEndState(self) {
|
||||
if (self._hparser)
|
||||
return new Error('Malformed part header');
|
||||
const fileStream = self._fileStream;
|
||||
if (fileStream) {
|
||||
self._fileStream = null;
|
||||
fileStream.destroy(new Error('Unexpected end of file'));
|
||||
}
|
||||
if (!self._complete)
|
||||
return new Error('Unexpected end of form');
|
||||
}
|
||||
|
||||
const TOKEN = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
const FIELD_VCHAR = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
];
|
||||
|
||||
module.exports = Multipart;
|
350
deps/undici/src/node_modules/busboy/lib/types/urlencoded.js
generated
vendored
Normal file
350
deps/undici/src/node_modules/busboy/lib/types/urlencoded.js
generated
vendored
Normal file
|
@ -0,0 +1,350 @@
|
|||
'use strict';
|
||||
|
||||
const { Writable } = require('stream');
|
||||
|
||||
const { getDecoder } = require('../utils.js');
|
||||
|
||||
class URLEncoded extends Writable {
|
||||
constructor(cfg) {
|
||||
const streamOpts = {
|
||||
autoDestroy: true,
|
||||
emitClose: true,
|
||||
highWaterMark: (typeof cfg.highWaterMark === 'number'
|
||||
? cfg.highWaterMark
|
||||
: undefined),
|
||||
};
|
||||
super(streamOpts);
|
||||
|
||||
let charset = (cfg.defCharset || 'utf8');
|
||||
if (cfg.conType.params && typeof cfg.conType.params.charset === 'string')
|
||||
charset = cfg.conType.params.charset;
|
||||
|
||||
this.charset = charset;
|
||||
|
||||
const limits = cfg.limits;
|
||||
this.fieldSizeLimit = (limits && typeof limits.fieldSize === 'number'
|
||||
? limits.fieldSize
|
||||
: 1 * 1024 * 1024);
|
||||
this.fieldsLimit = (limits && typeof limits.fields === 'number'
|
||||
? limits.fields
|
||||
: Infinity);
|
||||
this.fieldNameSizeLimit = (
|
||||
limits && typeof limits.fieldNameSize === 'number'
|
||||
? limits.fieldNameSize
|
||||
: 100
|
||||
);
|
||||
|
||||
this._inKey = true;
|
||||
this._keyTrunc = false;
|
||||
this._valTrunc = false;
|
||||
this._bytesKey = 0;
|
||||
this._bytesVal = 0;
|
||||
this._fields = 0;
|
||||
this._key = '';
|
||||
this._val = '';
|
||||
this._byte = -2;
|
||||
this._lastPos = 0;
|
||||
this._encode = 0;
|
||||
this._decoder = getDecoder(charset);
|
||||
}
|
||||
|
||||
static detect(conType) {
|
||||
return (conType.type === 'application'
|
||||
&& conType.subtype === 'x-www-form-urlencoded');
|
||||
}
|
||||
|
||||
_write(chunk, enc, cb) {
|
||||
if (this._fields >= this.fieldsLimit)
|
||||
return cb();
|
||||
|
||||
let i = 0;
|
||||
const len = chunk.length;
|
||||
this._lastPos = 0;
|
||||
|
||||
// Check if we last ended mid-percent-encoded byte
|
||||
if (this._byte !== -2) {
|
||||
i = readPctEnc(this, chunk, i, len);
|
||||
if (i === -1)
|
||||
return cb(new Error('Malformed urlencoded form'));
|
||||
if (i >= len)
|
||||
return cb();
|
||||
if (this._inKey)
|
||||
++this._bytesKey;
|
||||
else
|
||||
++this._bytesVal;
|
||||
}
|
||||
|
||||
main:
|
||||
while (i < len) {
|
||||
if (this._inKey) {
|
||||
// Parsing key
|
||||
|
||||
i = skipKeyBytes(this, chunk, i, len);
|
||||
|
||||
while (i < len) {
|
||||
switch (chunk[i]) {
|
||||
case 61: // '='
|
||||
if (this._lastPos < i)
|
||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
||||
this._lastPos = ++i;
|
||||
this._key = this._decoder(this._key, this._encode);
|
||||
this._encode = 0;
|
||||
this._inKey = false;
|
||||
continue main;
|
||||
case 38: // '&'
|
||||
if (this._lastPos < i)
|
||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
||||
this._lastPos = ++i;
|
||||
this._key = this._decoder(this._key, this._encode);
|
||||
this._encode = 0;
|
||||
if (this._bytesKey > 0) {
|
||||
this.emit(
|
||||
'field',
|
||||
this._key,
|
||||
'',
|
||||
{ nameTruncated: this._keyTrunc,
|
||||
valueTruncated: false,
|
||||
encoding: this.charset,
|
||||
mimeType: 'text/plain' }
|
||||
);
|
||||
}
|
||||
this._key = '';
|
||||
this._val = '';
|
||||
this._keyTrunc = false;
|
||||
this._valTrunc = false;
|
||||
this._bytesKey = 0;
|
||||
this._bytesVal = 0;
|
||||
if (++this._fields >= this.fieldsLimit) {
|
||||
this.emit('fieldsLimit');
|
||||
return cb();
|
||||
}
|
||||
continue;
|
||||
case 43: // '+'
|
||||
if (this._lastPos < i)
|
||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
||||
this._key += ' ';
|
||||
this._lastPos = i + 1;
|
||||
break;
|
||||
case 37: // '%'
|
||||
if (this._encode === 0)
|
||||
this._encode = 1;
|
||||
if (this._lastPos < i)
|
||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
||||
this._lastPos = i + 1;
|
||||
this._byte = -1;
|
||||
i = readPctEnc(this, chunk, i + 1, len);
|
||||
if (i === -1)
|
||||
return cb(new Error('Malformed urlencoded form'));
|
||||
if (i >= len)
|
||||
return cb();
|
||||
++this._bytesKey;
|
||||
i = skipKeyBytes(this, chunk, i, len);
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
++this._bytesKey;
|
||||
i = skipKeyBytes(this, chunk, i, len);
|
||||
}
|
||||
if (this._lastPos < i)
|
||||
this._key += chunk.latin1Slice(this._lastPos, i);
|
||||
} else {
|
||||
// Parsing value
|
||||
|
||||
i = skipValBytes(this, chunk, i, len);
|
||||
|
||||
while (i < len) {
|
||||
switch (chunk[i]) {
|
||||
case 38: // '&'
|
||||
if (this._lastPos < i)
|
||||
this._val += chunk.latin1Slice(this._lastPos, i);
|
||||
this._lastPos = ++i;
|
||||
this._inKey = true;
|
||||
this._val = this._decoder(this._val, this._encode);
|
||||
this._encode = 0;
|
||||
if (this._bytesKey > 0 || this._bytesVal > 0) {
|
||||
this.emit(
|
||||
'field',
|
||||
this._key,
|
||||
this._val,
|
||||
{ nameTruncated: this._keyTrunc,
|
||||
valueTruncated: this._valTrunc,
|
||||
encoding: this.charset,
|
||||
mimeType: 'text/plain' }
|
||||
);
|
||||
}
|
||||
this._key = '';
|
||||
this._val = '';
|
||||
this._keyTrunc = false;
|
||||
this._valTrunc = false;
|
||||
this._bytesKey = 0;
|
||||
this._bytesVal = 0;
|
||||
if (++this._fields >= this.fieldsLimit) {
|
||||
this.emit('fieldsLimit');
|
||||
return cb();
|
||||
}
|
||||
continue main;
|
||||
case 43: // '+'
|
||||
if (this._lastPos < i)
|
||||
this._val += chunk.latin1Slice(this._lastPos, i);
|
||||
this._val += ' ';
|
||||
this._lastPos = i + 1;
|
||||
break;
|
||||
case 37: // '%'
|
||||
if (this._encode === 0)
|
||||
this._encode = 1;
|
||||
if (this._lastPos < i)
|
||||
this._val += chunk.latin1Slice(this._lastPos, i);
|
||||
this._lastPos = i + 1;
|
||||
this._byte = -1;
|
||||
i = readPctEnc(this, chunk, i + 1, len);
|
||||
if (i === -1)
|
||||
return cb(new Error('Malformed urlencoded form'));
|
||||
if (i >= len)
|
||||
return cb();
|
||||
++this._bytesVal;
|
||||
i = skipValBytes(this, chunk, i, len);
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
++this._bytesVal;
|
||||
i = skipValBytes(this, chunk, i, len);
|
||||
}
|
||||
if (this._lastPos < i)
|
||||
this._val += chunk.latin1Slice(this._lastPos, i);
|
||||
}
|
||||
}
|
||||
|
||||
cb();
|
||||
}
|
||||
|
||||
_final(cb) {
|
||||
if (this._byte !== -2)
|
||||
return cb(new Error('Malformed urlencoded form'));
|
||||
if (!this._inKey || this._bytesKey > 0 || this._bytesVal > 0) {
|
||||
if (this._inKey)
|
||||
this._key = this._decoder(this._key, this._encode);
|
||||
else
|
||||
this._val = this._decoder(this._val, this._encode);
|
||||
this.emit(
|
||||
'field',
|
||||
this._key,
|
||||
this._val,
|
||||
{ nameTruncated: this._keyTrunc,
|
||||
valueTruncated: this._valTrunc,
|
||||
encoding: this.charset,
|
||||
mimeType: 'text/plain' }
|
||||
);
|
||||
}
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
function readPctEnc(self, chunk, pos, len) {
|
||||
if (pos >= len)
|
||||
return len;
|
||||
|
||||
if (self._byte === -1) {
|
||||
// We saw a '%' but no hex characters yet
|
||||
const hexUpper = HEX_VALUES[chunk[pos++]];
|
||||
if (hexUpper === -1)
|
||||
return -1;
|
||||
|
||||
if (hexUpper >= 8)
|
||||
self._encode = 2; // Indicate high bits detected
|
||||
|
||||
if (pos < len) {
|
||||
// Both hex characters are in this chunk
|
||||
const hexLower = HEX_VALUES[chunk[pos++]];
|
||||
if (hexLower === -1)
|
||||
return -1;
|
||||
|
||||
if (self._inKey)
|
||||
self._key += String.fromCharCode((hexUpper << 4) + hexLower);
|
||||
else
|
||||
self._val += String.fromCharCode((hexUpper << 4) + hexLower);
|
||||
|
||||
self._byte = -2;
|
||||
self._lastPos = pos;
|
||||
} else {
|
||||
// Only one hex character was available in this chunk
|
||||
self._byte = hexUpper;
|
||||
}
|
||||
} else {
|
||||
// We saw only one hex character so far
|
||||
const hexLower = HEX_VALUES[chunk[pos++]];
|
||||
if (hexLower === -1)
|
||||
return -1;
|
||||
|
||||
if (self._inKey)
|
||||
self._key += String.fromCharCode((self._byte << 4) + hexLower);
|
||||
else
|
||||
self._val += String.fromCharCode((self._byte << 4) + hexLower);
|
||||
|
||||
self._byte = -2;
|
||||
self._lastPos = pos;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
function skipKeyBytes(self, chunk, pos, len) {
|
||||
// Skip bytes if we've truncated
|
||||
if (self._bytesKey > self.fieldNameSizeLimit) {
|
||||
if (!self._keyTrunc) {
|
||||
if (self._lastPos < pos)
|
||||
self._key += chunk.latin1Slice(self._lastPos, pos - 1);
|
||||
}
|
||||
self._keyTrunc = true;
|
||||
for (; pos < len; ++pos) {
|
||||
const code = chunk[pos];
|
||||
if (code === 61/* '=' */ || code === 38/* '&' */)
|
||||
break;
|
||||
++self._bytesKey;
|
||||
}
|
||||
self._lastPos = pos;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
function skipValBytes(self, chunk, pos, len) {
|
||||
// Skip bytes if we've truncated
|
||||
if (self._bytesVal > self.fieldSizeLimit) {
|
||||
if (!self._valTrunc) {
|
||||
if (self._lastPos < pos)
|
||||
self._val += chunk.latin1Slice(self._lastPos, pos - 1);
|
||||
}
|
||||
self._valTrunc = true;
|
||||
for (; pos < len; ++pos) {
|
||||
if (chunk[pos] === 38/* '&' */)
|
||||
break;
|
||||
++self._bytesVal;
|
||||
}
|
||||
self._lastPos = pos;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* eslint-disable no-multi-spaces */
|
||||
const HEX_VALUES = [
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
];
|
||||
/* eslint-enable no-multi-spaces */
|
||||
|
||||
module.exports = URLEncoded;
|
596
deps/undici/src/node_modules/busboy/lib/utils.js
generated
vendored
Normal file
596
deps/undici/src/node_modules/busboy/lib/utils.js
generated
vendored
Normal file
|
@ -0,0 +1,596 @@
|
|||
'use strict';
|
||||
|
||||
function parseContentType(str) {
|
||||
if (str.length === 0)
|
||||
return;
|
||||
|
||||
const params = Object.create(null);
|
||||
let i = 0;
|
||||
|
||||
// Parse type
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (TOKEN[code] !== 1) {
|
||||
if (code !== 47/* '/' */ || i === 0)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check for type without subtype
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
const type = str.slice(0, i).toLowerCase();
|
||||
|
||||
// Parse subtype
|
||||
const subtypeStart = ++i;
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (TOKEN[code] !== 1) {
|
||||
// Make sure we have a subtype
|
||||
if (i === subtypeStart)
|
||||
return;
|
||||
|
||||
if (parseContentTypeParams(str, i, params) === undefined)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Make sure we have a subtype
|
||||
if (i === subtypeStart)
|
||||
return;
|
||||
|
||||
const subtype = str.slice(subtypeStart, i).toLowerCase();
|
||||
|
||||
return { type, subtype, params };
|
||||
}
|
||||
|
||||
function parseContentTypeParams(str, i, params) {
|
||||
while (i < str.length) {
|
||||
// Consume whitespace
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
|
||||
break;
|
||||
}
|
||||
|
||||
// Ended on whitespace
|
||||
if (i === str.length)
|
||||
break;
|
||||
|
||||
// Check for malformed parameter
|
||||
if (str.charCodeAt(i++) !== 59/* ';' */)
|
||||
return;
|
||||
|
||||
// Consume whitespace
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
|
||||
break;
|
||||
}
|
||||
|
||||
// Ended on whitespace (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
let name;
|
||||
const nameStart = i;
|
||||
// Parse parameter name
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (TOKEN[code] !== 1) {
|
||||
if (code !== 61/* '=' */)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No value (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
name = str.slice(nameStart, i);
|
||||
++i; // Skip over '='
|
||||
|
||||
// No value (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
let value = '';
|
||||
let valueStart;
|
||||
if (str.charCodeAt(i) === 34/* '"' */) {
|
||||
valueStart = ++i;
|
||||
let escaping = false;
|
||||
// Parse quoted value
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (code === 92/* '\\' */) {
|
||||
if (escaping) {
|
||||
valueStart = i;
|
||||
escaping = false;
|
||||
} else {
|
||||
value += str.slice(valueStart, i);
|
||||
escaping = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (code === 34/* '"' */) {
|
||||
if (escaping) {
|
||||
valueStart = i;
|
||||
escaping = false;
|
||||
continue;
|
||||
}
|
||||
value += str.slice(valueStart, i);
|
||||
break;
|
||||
}
|
||||
if (escaping) {
|
||||
valueStart = i - 1;
|
||||
escaping = false;
|
||||
}
|
||||
// Invalid unescaped quoted character (malformed)
|
||||
if (QDTEXT[code] !== 1)
|
||||
return;
|
||||
}
|
||||
|
||||
// No end quote (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
++i; // Skip over double quote
|
||||
} else {
|
||||
valueStart = i;
|
||||
// Parse unquoted value
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (TOKEN[code] !== 1) {
|
||||
// No value (malformed)
|
||||
if (i === valueStart)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
value = str.slice(valueStart, i);
|
||||
}
|
||||
|
||||
name = name.toLowerCase();
|
||||
if (params[name] === undefined)
|
||||
params[name] = value;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function parseDisposition(str, defDecoder) {
|
||||
if (str.length === 0)
|
||||
return;
|
||||
|
||||
const params = Object.create(null);
|
||||
let i = 0;
|
||||
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (TOKEN[code] !== 1) {
|
||||
if (parseDispositionParams(str, i, params, defDecoder) === undefined)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const type = str.slice(0, i).toLowerCase();
|
||||
|
||||
return { type, params };
|
||||
}
|
||||
|
||||
function parseDispositionParams(str, i, params, defDecoder) {
|
||||
while (i < str.length) {
|
||||
// Consume whitespace
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
|
||||
break;
|
||||
}
|
||||
|
||||
// Ended on whitespace
|
||||
if (i === str.length)
|
||||
break;
|
||||
|
||||
// Check for malformed parameter
|
||||
if (str.charCodeAt(i++) !== 59/* ';' */)
|
||||
return;
|
||||
|
||||
// Consume whitespace
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
|
||||
break;
|
||||
}
|
||||
|
||||
// Ended on whitespace (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
let name;
|
||||
const nameStart = i;
|
||||
// Parse parameter name
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (TOKEN[code] !== 1) {
|
||||
if (code === 61/* '=' */)
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No value (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
let value = '';
|
||||
let valueStart;
|
||||
let charset;
|
||||
//~ let lang;
|
||||
name = str.slice(nameStart, i);
|
||||
if (name.charCodeAt(name.length - 1) === 42/* '*' */) {
|
||||
// Extended value
|
||||
|
||||
const charsetStart = ++i;
|
||||
// Parse charset name
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (CHARSET[code] !== 1) {
|
||||
if (code !== 39/* '\'' */)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Incomplete charset (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
charset = str.slice(charsetStart, i);
|
||||
++i; // Skip over the '\''
|
||||
|
||||
//~ const langStart = ++i;
|
||||
// Parse language name
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (code === 39/* '\'' */)
|
||||
break;
|
||||
}
|
||||
|
||||
// Incomplete language (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
//~ lang = str.slice(langStart, i);
|
||||
++i; // Skip over the '\''
|
||||
|
||||
// No value (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
valueStart = i;
|
||||
|
||||
let encode = 0;
|
||||
// Parse value
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (EXTENDED_VALUE[code] !== 1) {
|
||||
if (code === 37/* '%' */) {
|
||||
let hexUpper;
|
||||
let hexLower;
|
||||
if (i + 2 < str.length
|
||||
&& (hexUpper = HEX_VALUES[str.charCodeAt(i + 1)]) !== -1
|
||||
&& (hexLower = HEX_VALUES[str.charCodeAt(i + 2)]) !== -1) {
|
||||
const byteVal = (hexUpper << 4) + hexLower;
|
||||
value += str.slice(valueStart, i);
|
||||
value += String.fromCharCode(byteVal);
|
||||
i += 2;
|
||||
valueStart = i + 1;
|
||||
if (byteVal >= 128)
|
||||
encode = 2;
|
||||
else if (encode === 0)
|
||||
encode = 1;
|
||||
continue;
|
||||
}
|
||||
// '%' disallowed in non-percent encoded contexts (malformed)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value += str.slice(valueStart, i);
|
||||
value = convertToUTF8(value, charset, encode);
|
||||
if (value === undefined)
|
||||
return;
|
||||
} else {
|
||||
// Non-extended value
|
||||
|
||||
++i; // Skip over '='
|
||||
|
||||
// No value (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
if (str.charCodeAt(i) === 34/* '"' */) {
|
||||
valueStart = ++i;
|
||||
let escaping = false;
|
||||
// Parse quoted value
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (code === 92/* '\\' */) {
|
||||
if (escaping) {
|
||||
valueStart = i;
|
||||
escaping = false;
|
||||
} else {
|
||||
value += str.slice(valueStart, i);
|
||||
escaping = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (code === 34/* '"' */) {
|
||||
if (escaping) {
|
||||
valueStart = i;
|
||||
escaping = false;
|
||||
continue;
|
||||
}
|
||||
value += str.slice(valueStart, i);
|
||||
break;
|
||||
}
|
||||
if (escaping) {
|
||||
valueStart = i - 1;
|
||||
escaping = false;
|
||||
}
|
||||
// Invalid unescaped quoted character (malformed)
|
||||
if (QDTEXT[code] !== 1)
|
||||
return;
|
||||
}
|
||||
|
||||
// No end quote (malformed)
|
||||
if (i === str.length)
|
||||
return;
|
||||
|
||||
++i; // Skip over double quote
|
||||
} else {
|
||||
valueStart = i;
|
||||
// Parse unquoted value
|
||||
for (; i < str.length; ++i) {
|
||||
const code = str.charCodeAt(i);
|
||||
if (TOKEN[code] !== 1) {
|
||||
// No value (malformed)
|
||||
if (i === valueStart)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
value = str.slice(valueStart, i);
|
||||
}
|
||||
|
||||
value = defDecoder(value, 2);
|
||||
if (value === undefined)
|
||||
return;
|
||||
}
|
||||
|
||||
name = name.toLowerCase();
|
||||
if (params[name] === undefined)
|
||||
params[name] = value;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function getDecoder(charset) {
|
||||
let lc;
|
||||
while (true) {
|
||||
switch (charset) {
|
||||
case 'utf-8':
|
||||
case 'utf8':
|
||||
return decoders.utf8;
|
||||
case 'latin1':
|
||||
case 'ascii': // TODO: Make these a separate, strict decoder?
|
||||
case 'us-ascii':
|
||||
case 'iso-8859-1':
|
||||
case 'iso8859-1':
|
||||
case 'iso88591':
|
||||
case 'iso_8859-1':
|
||||
case 'windows-1252':
|
||||
case 'iso_8859-1:1987':
|
||||
case 'cp1252':
|
||||
case 'x-cp1252':
|
||||
return decoders.latin1;
|
||||
case 'utf16le':
|
||||
case 'utf-16le':
|
||||
case 'ucs2':
|
||||
case 'ucs-2':
|
||||
return decoders.utf16le;
|
||||
case 'base64':
|
||||
return decoders.base64;
|
||||
default:
|
||||
if (lc === undefined) {
|
||||
lc = true;
|
||||
charset = charset.toLowerCase();
|
||||
continue;
|
||||
}
|
||||
return decoders.other.bind(charset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const decoders = {
|
||||
utf8: (data, hint) => {
|
||||
if (data.length === 0)
|
||||
return '';
|
||||
if (typeof data === 'string') {
|
||||
// If `data` never had any percent-encoded bytes or never had any that
|
||||
// were outside of the ASCII range, then we can safely just return the
|
||||
// input since UTF-8 is ASCII compatible
|
||||
if (hint < 2)
|
||||
return data;
|
||||
|
||||
data = Buffer.from(data, 'latin1');
|
||||
}
|
||||
return data.utf8Slice(0, data.length);
|
||||
},
|
||||
|
||||
latin1: (data, hint) => {
|
||||
if (data.length === 0)
|
||||
return '';
|
||||
if (typeof data === 'string')
|
||||
return data;
|
||||
return data.latin1Slice(0, data.length);
|
||||
},
|
||||
|
||||
utf16le: (data, hint) => {
|
||||
if (data.length === 0)
|
||||
return '';
|
||||
if (typeof data === 'string')
|
||||
data = Buffer.from(data, 'latin1');
|
||||
return data.ucs2Slice(0, data.length);
|
||||
},
|
||||
|
||||
base64: (data, hint) => {
|
||||
if (data.length === 0)
|
||||
return '';
|
||||
if (typeof data === 'string')
|
||||
data = Buffer.from(data, 'latin1');
|
||||
return data.base64Slice(0, data.length);
|
||||
},
|
||||
|
||||
other: (data, hint) => {
|
||||
if (data.length === 0)
|
||||
return '';
|
||||
if (typeof data === 'string')
|
||||
data = Buffer.from(data, 'latin1');
|
||||
try {
|
||||
const decoder = new TextDecoder(this);
|
||||
return decoder.decode(data);
|
||||
} catch {}
|
||||
},
|
||||
};
|
||||
|
||||
function convertToUTF8(data, charset, hint) {
|
||||
const decode = getDecoder(charset);
|
||||
if (decode)
|
||||
return decode(data, hint);
|
||||
}
|
||||
|
||||
function basename(path) {
|
||||
if (typeof path !== 'string')
|
||||
return '';
|
||||
for (let i = path.length - 1; i >= 0; --i) {
|
||||
switch (path.charCodeAt(i)) {
|
||||
case 0x2F: // '/'
|
||||
case 0x5C: // '\'
|
||||
path = path.slice(i + 1);
|
||||
return (path === '..' || path === '.' ? '' : path);
|
||||
}
|
||||
}
|
||||
return (path === '..' || path === '.' ? '' : path);
|
||||
}
|
||||
|
||||
const TOKEN = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
const QDTEXT = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
];
|
||||
|
||||
const CHARSET = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
const EXTENDED_VALUE = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
/* eslint-disable no-multi-spaces */
|
||||
const HEX_VALUES = [
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
];
|
||||
/* eslint-enable no-multi-spaces */
|
||||
|
||||
module.exports = {
|
||||
basename,
|
||||
convertToUTF8,
|
||||
getDecoder,
|
||||
parseContentType,
|
||||
parseDisposition,
|
||||
};
|
22
deps/undici/src/node_modules/busboy/package.json
generated
vendored
Normal file
22
deps/undici/src/node_modules/busboy/package.json
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
{ "name": "busboy",
|
||||
"version": "1.6.0",
|
||||
"author": "Brian White <mscdex@mscdex.net>",
|
||||
"description": "A streaming parser for HTML form data for node.js",
|
||||
"main": "./lib/index.js",
|
||||
"dependencies": {
|
||||
"streamsearch": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mscdex/eslint-config": "^1.1.0",
|
||||
"eslint": "^7.32.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node test/test.js",
|
||||
"lint": "eslint --cache --report-unused-disable-directives --ext=.js .eslintrc.js lib test bench",
|
||||
"lint:fix": "npm run lint -- --fix"
|
||||
},
|
||||
"engines": { "node": ">=10.16.0" },
|
||||
"keywords": [ "uploads", "forms", "multipart", "form-data" ],
|
||||
"licenses": [ { "type": "MIT", "url": "http://github.com/mscdex/busboy/raw/master/LICENSE" } ],
|
||||
"repository": { "type": "git", "url": "http://github.com/mscdex/busboy.git" }
|
||||
}
|
109
deps/undici/src/node_modules/busboy/test/common.js
generated
vendored
Normal file
109
deps/undici/src/node_modules/busboy/test/common.js
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const { inspect } = require('util');
|
||||
|
||||
const mustCallChecks = [];
|
||||
|
||||
function noop() {}
|
||||
|
||||
function runCallChecks(exitCode) {
|
||||
if (exitCode !== 0) return;
|
||||
|
||||
const failed = mustCallChecks.filter((context) => {
|
||||
if ('minimum' in context) {
|
||||
context.messageSegment = `at least ${context.minimum}`;
|
||||
return context.actual < context.minimum;
|
||||
}
|
||||
context.messageSegment = `exactly ${context.exact}`;
|
||||
return context.actual !== context.exact;
|
||||
});
|
||||
|
||||
failed.forEach((context) => {
|
||||
console.error('Mismatched %s function calls. Expected %s, actual %d.',
|
||||
context.name,
|
||||
context.messageSegment,
|
||||
context.actual);
|
||||
console.error(context.stack.split('\n').slice(2).join('\n'));
|
||||
});
|
||||
|
||||
if (failed.length)
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function mustCall(fn, exact) {
|
||||
return _mustCallInner(fn, exact, 'exact');
|
||||
}
|
||||
|
||||
function mustCallAtLeast(fn, minimum) {
|
||||
return _mustCallInner(fn, minimum, 'minimum');
|
||||
}
|
||||
|
||||
function _mustCallInner(fn, criteria = 1, field) {
|
||||
if (process._exiting)
|
||||
throw new Error('Cannot use common.mustCall*() in process exit handler');
|
||||
|
||||
if (typeof fn === 'number') {
|
||||
criteria = fn;
|
||||
fn = noop;
|
||||
} else if (fn === undefined) {
|
||||
fn = noop;
|
||||
}
|
||||
|
||||
if (typeof criteria !== 'number')
|
||||
throw new TypeError(`Invalid ${field} value: ${criteria}`);
|
||||
|
||||
const context = {
|
||||
[field]: criteria,
|
||||
actual: 0,
|
||||
stack: inspect(new Error()),
|
||||
name: fn.name || '<anonymous>'
|
||||
};
|
||||
|
||||
// Add the exit listener only once to avoid listener leak warnings
|
||||
if (mustCallChecks.length === 0)
|
||||
process.on('exit', runCallChecks);
|
||||
|
||||
mustCallChecks.push(context);
|
||||
|
||||
function wrapped(...args) {
|
||||
++context.actual;
|
||||
return fn.call(this, ...args);
|
||||
}
|
||||
// TODO: remove origFn?
|
||||
wrapped.origFn = fn;
|
||||
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
function getCallSite(top) {
|
||||
const originalStackFormatter = Error.prepareStackTrace;
|
||||
Error.prepareStackTrace = (err, stack) =>
|
||||
`${stack[0].getFileName()}:${stack[0].getLineNumber()}`;
|
||||
const err = new Error();
|
||||
Error.captureStackTrace(err, top);
|
||||
// With the V8 Error API, the stack is not formatted until it is accessed
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
err.stack;
|
||||
Error.prepareStackTrace = originalStackFormatter;
|
||||
return err.stack;
|
||||
}
|
||||
|
||||
function mustNotCall(msg) {
|
||||
const callSite = getCallSite(mustNotCall);
|
||||
return function mustNotCall(...args) {
|
||||
args = args.map(inspect).join(', ');
|
||||
const argsInfo = (args.length > 0
|
||||
? `\ncalled with arguments: ${args}`
|
||||
: '');
|
||||
assert.fail(
|
||||
`${msg || 'function should not have been called'} at ${callSite}`
|
||||
+ argsInfo);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mustCall,
|
||||
mustCallAtLeast,
|
||||
mustNotCall,
|
||||
};
|
94
deps/undici/src/node_modules/busboy/test/test-types-multipart-charsets.js
generated
vendored
Normal file
94
deps/undici/src/node_modules/busboy/test/test-types-multipart-charsets.js
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const { inspect } = require('util');
|
||||
|
||||
const { mustCall } = require(`${__dirname}/common.js`);
|
||||
|
||||
const busboy = require('..');
|
||||
|
||||
const input = Buffer.from([
|
||||
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
|
||||
'Content-Disposition: form-data; '
|
||||
+ 'name="upload_file_0"; filename="テスト.dat"',
|
||||
'Content-Type: application/octet-stream',
|
||||
'',
|
||||
'A'.repeat(1023),
|
||||
'-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
|
||||
].join('\r\n'));
|
||||
const boundary = '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k';
|
||||
const expected = [
|
||||
{ type: 'file',
|
||||
name: 'upload_file_0',
|
||||
data: Buffer.from('A'.repeat(1023)),
|
||||
info: {
|
||||
filename: 'テスト.dat',
|
||||
encoding: '7bit',
|
||||
mimeType: 'application/octet-stream',
|
||||
},
|
||||
limited: false,
|
||||
},
|
||||
];
|
||||
const bb = busboy({
|
||||
defParamCharset: 'utf8',
|
||||
headers: {
|
||||
'content-type': `multipart/form-data; boundary=${boundary}`,
|
||||
}
|
||||
});
|
||||
const results = [];
|
||||
|
||||
bb.on('field', (name, val, info) => {
|
||||
results.push({ type: 'field', name, val, info });
|
||||
});
|
||||
|
||||
bb.on('file', (name, stream, info) => {
|
||||
const data = [];
|
||||
let nb = 0;
|
||||
const file = {
|
||||
type: 'file',
|
||||
name,
|
||||
data: null,
|
||||
info,
|
||||
limited: false,
|
||||
};
|
||||
results.push(file);
|
||||
stream.on('data', (d) => {
|
||||
data.push(d);
|
||||
nb += d.length;
|
||||
}).on('limit', () => {
|
||||
file.limited = true;
|
||||
}).on('close', () => {
|
||||
file.data = Buffer.concat(data, nb);
|
||||
assert.strictEqual(stream.truncated, file.limited);
|
||||
}).once('error', (err) => {
|
||||
file.err = err.message;
|
||||
});
|
||||
});
|
||||
|
||||
bb.on('error', (err) => {
|
||||
results.push({ error: err.message });
|
||||
});
|
||||
|
||||
bb.on('partsLimit', () => {
|
||||
results.push('partsLimit');
|
||||
});
|
||||
|
||||
bb.on('filesLimit', () => {
|
||||
results.push('filesLimit');
|
||||
});
|
||||
|
||||
bb.on('fieldsLimit', () => {
|
||||
results.push('fieldsLimit');
|
||||
});
|
||||
|
||||
bb.on('close', mustCall(() => {
|
||||
assert.deepStrictEqual(
|
||||
results,
|
||||
expected,
|
||||
'Results mismatch.\n'
|
||||
+ `Parsed: ${inspect(results)}\n`
|
||||
+ `Expected: ${inspect(expected)}`
|
||||
);
|
||||
}));
|
||||
|
||||
bb.end(input);
|
102
deps/undici/src/node_modules/busboy/test/test-types-multipart-stream-pause.js
generated
vendored
Normal file
102
deps/undici/src/node_modules/busboy/test/test-types-multipart-stream-pause.js
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const { randomFillSync } = require('crypto');
|
||||
const { inspect } = require('util');
|
||||
|
||||
const busboy = require('..');
|
||||
|
||||
const { mustCall } = require('./common.js');
|
||||
|
||||
const BOUNDARY = 'u2KxIV5yF1y+xUspOQCCZopaVgeV6Jxihv35XQJmuTx8X3sh';
|
||||
|
||||
function formDataSection(key, value) {
|
||||
return Buffer.from(
|
||||
`\r\n--${BOUNDARY}`
|
||||
+ `\r\nContent-Disposition: form-data; name="${key}"`
|
||||
+ `\r\n\r\n${value}`
|
||||
);
|
||||
}
|
||||
|
||||
function formDataFile(key, filename, contentType) {
|
||||
const buf = Buffer.allocUnsafe(100000);
|
||||
return Buffer.concat([
|
||||
Buffer.from(`\r\n--${BOUNDARY}\r\n`),
|
||||
Buffer.from(`Content-Disposition: form-data; name="${key}"`
|
||||
+ `; filename="${filename}"\r\n`),
|
||||
Buffer.from(`Content-Type: ${contentType}\r\n\r\n`),
|
||||
randomFillSync(buf)
|
||||
]);
|
||||
}
|
||||
|
||||
const reqChunks = [
|
||||
Buffer.concat([
|
||||
formDataFile('file', 'file.bin', 'application/octet-stream'),
|
||||
formDataSection('foo', 'foo value'),
|
||||
]),
|
||||
formDataSection('bar', 'bar value'),
|
||||
Buffer.from(`\r\n--${BOUNDARY}--\r\n`)
|
||||
];
|
||||
const bb = busboy({
|
||||
headers: {
|
||||
'content-type': `multipart/form-data; boundary=${BOUNDARY}`
|
||||
}
|
||||
});
|
||||
const expected = [
|
||||
{ type: 'file',
|
||||
name: 'file',
|
||||
info: {
|
||||
filename: 'file.bin',
|
||||
encoding: '7bit',
|
||||
mimeType: 'application/octet-stream',
|
||||
},
|
||||
},
|
||||
{ type: 'field',
|
||||
name: 'foo',
|
||||
val: 'foo value',
|
||||
info: {
|
||||
nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: '7bit',
|
||||
mimeType: 'text/plain',
|
||||
},
|
||||
},
|
||||
{ type: 'field',
|
||||
name: 'bar',
|
||||
val: 'bar value',
|
||||
info: {
|
||||
nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: '7bit',
|
||||
mimeType: 'text/plain',
|
||||
},
|
||||
},
|
||||
];
|
||||
const results = [];
|
||||
|
||||
bb.on('field', (name, val, info) => {
|
||||
results.push({ type: 'field', name, val, info });
|
||||
});
|
||||
|
||||
bb.on('file', (name, stream, info) => {
|
||||
results.push({ type: 'file', name, info });
|
||||
// Simulate a pipe where the destination is pausing (perhaps due to waiting
|
||||
// for file system write to finish)
|
||||
setTimeout(() => {
|
||||
stream.resume();
|
||||
}, 10);
|
||||
});
|
||||
|
||||
bb.on('close', mustCall(() => {
|
||||
assert.deepStrictEqual(
|
||||
results,
|
||||
expected,
|
||||
'Results mismatch.\n'
|
||||
+ `Parsed: ${inspect(results)}\n`
|
||||
+ `Expected: ${inspect(expected)}`
|
||||
);
|
||||
}));
|
||||
|
||||
for (const chunk of reqChunks)
|
||||
bb.write(chunk);
|
||||
bb.end();
|
1053
deps/undici/src/node_modules/busboy/test/test-types-multipart.js
generated
vendored
Normal file
1053
deps/undici/src/node_modules/busboy/test/test-types-multipart.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
488
deps/undici/src/node_modules/busboy/test/test-types-urlencoded.js
generated
vendored
Normal file
488
deps/undici/src/node_modules/busboy/test/test-types-urlencoded.js
generated
vendored
Normal file
|
@ -0,0 +1,488 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const { transcode } = require('buffer');
|
||||
const { inspect } = require('util');
|
||||
|
||||
const busboy = require('..');
|
||||
|
||||
const active = new Map();
|
||||
|
||||
const tests = [
|
||||
{ source: ['foo'],
|
||||
expected: [
|
||||
['foo',
|
||||
'',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Unassigned value'
|
||||
},
|
||||
{ source: ['foo=bar'],
|
||||
expected: [
|
||||
['foo',
|
||||
'bar',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Assigned value'
|
||||
},
|
||||
{ source: ['foo&bar=baz'],
|
||||
expected: [
|
||||
['foo',
|
||||
'',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['bar',
|
||||
'baz',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Unassigned and assigned value'
|
||||
},
|
||||
{ source: ['foo=bar&baz'],
|
||||
expected: [
|
||||
['foo',
|
||||
'bar',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['baz',
|
||||
'',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Assigned and unassigned value'
|
||||
},
|
||||
{ source: ['foo=bar&baz=bla'],
|
||||
expected: [
|
||||
['foo',
|
||||
'bar',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['baz',
|
||||
'bla',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Two assigned values'
|
||||
},
|
||||
{ source: ['foo&bar'],
|
||||
expected: [
|
||||
['foo',
|
||||
'',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['bar',
|
||||
'',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Two unassigned values'
|
||||
},
|
||||
{ source: ['foo&bar&'],
|
||||
expected: [
|
||||
['foo',
|
||||
'',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['bar',
|
||||
'',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Two unassigned values and ampersand'
|
||||
},
|
||||
{ source: ['foo+1=bar+baz%2Bquux'],
|
||||
expected: [
|
||||
['foo 1',
|
||||
'bar baz+quux',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Assigned key and value with (plus) space'
|
||||
},
|
||||
{ source: ['foo=bar%20baz%21'],
|
||||
expected: [
|
||||
['foo',
|
||||
'bar baz!',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Assigned value with encoded bytes'
|
||||
},
|
||||
{ source: ['foo%20bar=baz%20bla%21'],
|
||||
expected: [
|
||||
['foo bar',
|
||||
'baz bla!',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Assigned value with encoded bytes #2'
|
||||
},
|
||||
{ source: ['foo=bar%20baz%21&num=1000'],
|
||||
expected: [
|
||||
['foo',
|
||||
'bar baz!',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['num',
|
||||
'1000',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Two assigned values, one with encoded bytes'
|
||||
},
|
||||
{ source: [
|
||||
Array.from(transcode(Buffer.from('foo'), 'utf8', 'utf16le')).map(
|
||||
(n) => `%${n.toString(16).padStart(2, '0')}`
|
||||
).join(''),
|
||||
'=',
|
||||
Array.from(transcode(Buffer.from('😀!'), 'utf8', 'utf16le')).map(
|
||||
(n) => `%${n.toString(16).padStart(2, '0')}`
|
||||
).join(''),
|
||||
],
|
||||
expected: [
|
||||
['foo',
|
||||
'😀!',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'UTF-16LE',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
charset: 'UTF-16LE',
|
||||
what: 'Encoded value with multi-byte charset'
|
||||
},
|
||||
{ source: [
|
||||
'foo=<',
|
||||
Array.from(transcode(Buffer.from('©:^þ'), 'utf8', 'latin1')).map(
|
||||
(n) => `%${n.toString(16).padStart(2, '0')}`
|
||||
).join(''),
|
||||
],
|
||||
expected: [
|
||||
['foo',
|
||||
'<©:^þ',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'ISO-8859-1',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
charset: 'ISO-8859-1',
|
||||
what: 'Encoded value with single-byte, ASCII-compatible, non-UTF8 charset'
|
||||
},
|
||||
{ source: ['foo=bar&baz=bla'],
|
||||
expected: [],
|
||||
what: 'Limits: zero fields',
|
||||
limits: { fields: 0 }
|
||||
},
|
||||
{ source: ['foo=bar&baz=bla'],
|
||||
expected: [
|
||||
['foo',
|
||||
'bar',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Limits: one field',
|
||||
limits: { fields: 1 }
|
||||
},
|
||||
{ source: ['foo=bar&baz=bla'],
|
||||
expected: [
|
||||
['foo',
|
||||
'bar',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['baz',
|
||||
'bla',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Limits: field part lengths match limits',
|
||||
limits: { fieldNameSize: 3, fieldSize: 3 }
|
||||
},
|
||||
{ source: ['foo=bar&baz=bla'],
|
||||
expected: [
|
||||
['fo',
|
||||
'bar',
|
||||
{ nameTruncated: true,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['ba',
|
||||
'bla',
|
||||
{ nameTruncated: true,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Limits: truncated field name',
|
||||
limits: { fieldNameSize: 2 }
|
||||
},
|
||||
{ source: ['foo=bar&baz=bla'],
|
||||
expected: [
|
||||
['foo',
|
||||
'ba',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: true,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['baz',
|
||||
'bl',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: true,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Limits: truncated field value',
|
||||
limits: { fieldSize: 2 }
|
||||
},
|
||||
{ source: ['foo=bar&baz=bla'],
|
||||
expected: [
|
||||
['fo',
|
||||
'ba',
|
||||
{ nameTruncated: true,
|
||||
valueTruncated: true,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['ba',
|
||||
'bl',
|
||||
{ nameTruncated: true,
|
||||
valueTruncated: true,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Limits: truncated field name and value',
|
||||
limits: { fieldNameSize: 2, fieldSize: 2 }
|
||||
},
|
||||
{ source: ['foo=bar&baz=bla'],
|
||||
expected: [
|
||||
['fo',
|
||||
'',
|
||||
{ nameTruncated: true,
|
||||
valueTruncated: true,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['ba',
|
||||
'',
|
||||
{ nameTruncated: true,
|
||||
valueTruncated: true,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Limits: truncated field name and zero value limit',
|
||||
limits: { fieldNameSize: 2, fieldSize: 0 }
|
||||
},
|
||||
{ source: ['foo=bar&baz=bla'],
|
||||
expected: [
|
||||
['',
|
||||
'',
|
||||
{ nameTruncated: true,
|
||||
valueTruncated: true,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
['',
|
||||
'',
|
||||
{ nameTruncated: true,
|
||||
valueTruncated: true,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Limits: truncated zero field name and zero value limit',
|
||||
limits: { fieldNameSize: 0, fieldSize: 0 }
|
||||
},
|
||||
{ source: ['&'],
|
||||
expected: [],
|
||||
what: 'Ampersand'
|
||||
},
|
||||
{ source: ['&&&&&'],
|
||||
expected: [],
|
||||
what: 'Many ampersands'
|
||||
},
|
||||
{ source: ['='],
|
||||
expected: [
|
||||
['',
|
||||
'',
|
||||
{ nameTruncated: false,
|
||||
valueTruncated: false,
|
||||
encoding: 'utf-8',
|
||||
mimeType: 'text/plain' },
|
||||
],
|
||||
],
|
||||
what: 'Assigned value, empty name and value'
|
||||
},
|
||||
{ source: [''],
|
||||
expected: [],
|
||||
what: 'Nothing'
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
active.set(test, 1);
|
||||
|
||||
const { what } = test;
|
||||
const charset = test.charset || 'utf-8';
|
||||
const bb = busboy({
|
||||
limits: test.limits,
|
||||
headers: {
|
||||
'content-type': `application/x-www-form-urlencoded; charset=${charset}`,
|
||||
},
|
||||
});
|
||||
const results = [];
|
||||
|
||||
bb.on('field', (key, val, info) => {
|
||||
results.push([key, val, info]);
|
||||
});
|
||||
|
||||
bb.on('file', () => {
|
||||
throw new Error(`[${what}] Unexpected file`);
|
||||
});
|
||||
|
||||
bb.on('close', () => {
|
||||
active.delete(test);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
results,
|
||||
test.expected,
|
||||
`[${what}] Results mismatch.\n`
|
||||
+ `Parsed: ${inspect(results)}\n`
|
||||
+ `Expected: ${inspect(test.expected)}`
|
||||
);
|
||||
});
|
||||
|
||||
for (const src of test.source) {
|
||||
const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
|
||||
bb.write(buf);
|
||||
}
|
||||
bb.end();
|
||||
}
|
||||
|
||||
// Byte-by-byte versions
|
||||
for (let test of tests) {
|
||||
test = { ...test };
|
||||
test.what += ' (byte-by-byte)';
|
||||
active.set(test, 1);
|
||||
|
||||
const { what } = test;
|
||||
const charset = test.charset || 'utf-8';
|
||||
const bb = busboy({
|
||||
limits: test.limits,
|
||||
headers: {
|
||||
'content-type': `application/x-www-form-urlencoded; charset="${charset}"`,
|
||||
},
|
||||
});
|
||||
const results = [];
|
||||
|
||||
bb.on('field', (key, val, info) => {
|
||||
results.push([key, val, info]);
|
||||
});
|
||||
|
||||
bb.on('file', () => {
|
||||
throw new Error(`[${what}] Unexpected file`);
|
||||
});
|
||||
|
||||
bb.on('close', () => {
|
||||
active.delete(test);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
results,
|
||||
test.expected,
|
||||
`[${what}] Results mismatch.\n`
|
||||
+ `Parsed: ${inspect(results)}\n`
|
||||
+ `Expected: ${inspect(test.expected)}`
|
||||
);
|
||||
});
|
||||
|
||||
for (const src of test.source) {
|
||||
const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
|
||||
for (let i = 0; i < buf.length; ++i)
|
||||
bb.write(buf.slice(i, i + 1));
|
||||
}
|
||||
bb.end();
|
||||
}
|
||||
|
||||
{
|
||||
let exception = false;
|
||||
process.once('uncaughtException', (ex) => {
|
||||
exception = true;
|
||||
throw ex;
|
||||
});
|
||||
process.on('exit', () => {
|
||||
if (exception || active.size === 0)
|
||||
return;
|
||||
process.exitCode = 1;
|
||||
console.error('==========================');
|
||||
console.error(`${active.size} test(s) did not finish:`);
|
||||
console.error('==========================');
|
||||
console.error(Array.from(active.keys()).map((v) => v.what).join('\n'));
|
||||
});
|
||||
}
|
20
deps/undici/src/node_modules/busboy/test/test.js
generated
vendored
Normal file
20
deps/undici/src/node_modules/busboy/test/test.js
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
const { spawnSync } = require('child_process');
|
||||
const { readdirSync } = require('fs');
|
||||
const { join } = require('path');
|
||||
|
||||
const files = readdirSync(__dirname).sort();
|
||||
for (const filename of files) {
|
||||
if (filename.startsWith('test-')) {
|
||||
const path = join(__dirname, filename);
|
||||
console.log(`> Running ${filename} ...`);
|
||||
const result = spawnSync(`${process.argv0} ${path}`, {
|
||||
shell: true,
|
||||
stdio: 'inherit',
|
||||
windowsHide: true
|
||||
});
|
||||
if (result.status !== 0)
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
5
deps/undici/src/node_modules/streamsearch/.eslintrc.js
generated
vendored
Normal file
5
deps/undici/src/node_modules/streamsearch/.eslintrc.js
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
extends: '@mscdex/eslint-config',
|
||||
};
|
24
deps/undici/src/node_modules/streamsearch/.github/workflows/ci.yml
generated
vendored
Normal file
24
deps/undici/src/node_modules/streamsearch/.github/workflows/ci.yml
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
tests-linux:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x, 16.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install module
|
||||
run: npm install
|
||||
- name: Run tests
|
||||
run: npm test
|
23
deps/undici/src/node_modules/streamsearch/.github/workflows/lint.yml
generated
vendored
Normal file
23
deps/undici/src/node_modules/streamsearch/.github/workflows/lint.yml
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
name: lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
NODE_VERSION: 16.x
|
||||
|
||||
jobs:
|
||||
lint-js:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ env.NODE_VERSION }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
- name: Install ESLint + ESLint configs/plugins
|
||||
run: npm install --only=dev
|
||||
- name: Lint files
|
||||
run: npm run lint
|
19
deps/undici/src/node_modules/streamsearch/LICENSE
generated
vendored
Normal file
19
deps/undici/src/node_modules/streamsearch/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright Brian White. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
95
deps/undici/src/node_modules/streamsearch/README.md
generated
vendored
Normal file
95
deps/undici/src/node_modules/streamsearch/README.md
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
Description
|
||||
===========
|
||||
|
||||
streamsearch is a module for [node.js](http://nodejs.org/) that allows searching a stream using the Boyer-Moore-Horspool algorithm.
|
||||
|
||||
This module is based heavily on the Streaming Boyer-Moore-Horspool C++ implementation by Hongli Lai [here](https://github.com/FooBarWidget/boyer-moore-horspool).
|
||||
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
* [node.js](http://nodejs.org/) -- v10.0.0 or newer
|
||||
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
npm install streamsearch
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
```js
|
||||
const { inspect } = require('util');
|
||||
|
||||
const StreamSearch = require('streamsearch');
|
||||
|
||||
const needle = Buffer.from('\r\n');
|
||||
const ss = new StreamSearch(needle, (isMatch, data, start, end) => {
|
||||
if (data)
|
||||
console.log('data: ' + inspect(data.toString('latin1', start, end)));
|
||||
if (isMatch)
|
||||
console.log('match!');
|
||||
});
|
||||
|
||||
const chunks = [
|
||||
'foo',
|
||||
' bar',
|
||||
'\r',
|
||||
'\n',
|
||||
'baz, hello\r',
|
||||
'\n world.',
|
||||
'\r\n Node.JS rules!!\r\n\r\n',
|
||||
];
|
||||
for (const chunk of chunks)
|
||||
ss.push(Buffer.from(chunk));
|
||||
|
||||
// output:
|
||||
//
|
||||
// data: 'foo'
|
||||
// data: ' bar'
|
||||
// match!
|
||||
// data: 'baz, hello'
|
||||
// match!
|
||||
// data: ' world.'
|
||||
// match!
|
||||
// data: ' Node.JS rules!!'
|
||||
// match!
|
||||
// data: ''
|
||||
// match!
|
||||
```
|
||||
|
||||
|
||||
API
|
||||
===
|
||||
|
||||
Properties
|
||||
----------
|
||||
|
||||
* **maxMatches** - < _integer_ > - The maximum number of matches. Defaults to `Infinity`.
|
||||
|
||||
* **matches** - < _integer_ > - The current match count.
|
||||
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
* **(constructor)**(< _mixed_ >needle, < _function_ >callback) - Creates and returns a new instance for searching for a _Buffer_ or _string_ `needle`. `callback` is called any time there is non-matching data and/or there is a needle match. `callback` will be called with the following arguments:
|
||||
|
||||
1. `isMatch` - _boolean_ - Indicates whether a match has been found
|
||||
|
||||
2. `data` - _mixed_ - If set, this contains data that did not match the needle.
|
||||
|
||||
3. `start` - _integer_ - The index in `data` where the non-matching data begins (inclusive).
|
||||
|
||||
4. `end` - _integer_ - The index in `data` where the non-matching data ends (exclusive).
|
||||
|
||||
5. `isSafeData` - _boolean_ - Indicates if it is safe to store a reference to `data` (e.g. as-is or via `data.slice()`) or not, as in some cases `data` may point to a Buffer whose contents change over time.
|
||||
|
||||
* **destroy**() - _(void)_ - Emits any last remaining unmatched data that may still be buffered and then resets internal state.
|
||||
|
||||
* **push**(< _Buffer_ >chunk) - _integer_ - Processes `chunk`, searching for a match. The return value is the last processed index in `chunk` + 1.
|
||||
|
||||
* **reset**() - _(void)_ - Resets internal state. Useful for when you wish to start searching a new/different stream for example.
|
||||
|
267
deps/undici/src/node_modules/streamsearch/lib/sbmh.js
generated
vendored
Normal file
267
deps/undici/src/node_modules/streamsearch/lib/sbmh.js
generated
vendored
Normal file
|
@ -0,0 +1,267 @@
|
|||
'use strict';
|
||||
/*
|
||||
Based heavily on the Streaming Boyer-Moore-Horspool C++ implementation
|
||||
by Hongli Lai at: https://github.com/FooBarWidget/boyer-moore-horspool
|
||||
*/
|
||||
function memcmp(buf1, pos1, buf2, pos2, num) {
|
||||
for (let i = 0; i < num; ++i) {
|
||||
if (buf1[pos1 + i] !== buf2[pos2 + i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class SBMH {
|
||||
constructor(needle, cb) {
|
||||
if (typeof cb !== 'function')
|
||||
throw new Error('Missing match callback');
|
||||
|
||||
if (typeof needle === 'string')
|
||||
needle = Buffer.from(needle);
|
||||
else if (!Buffer.isBuffer(needle))
|
||||
throw new Error(`Expected Buffer for needle, got ${typeof needle}`);
|
||||
|
||||
const needleLen = needle.length;
|
||||
|
||||
this.maxMatches = Infinity;
|
||||
this.matches = 0;
|
||||
|
||||
this._cb = cb;
|
||||
this._lookbehindSize = 0;
|
||||
this._needle = needle;
|
||||
this._bufPos = 0;
|
||||
|
||||
this._lookbehind = Buffer.allocUnsafe(needleLen);
|
||||
|
||||
// Initialize occurrence table.
|
||||
this._occ = [
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen, needleLen, needleLen,
|
||||
needleLen, needleLen, needleLen, needleLen
|
||||
];
|
||||
|
||||
// Populate occurrence table with analysis of the needle, ignoring the last
|
||||
// letter.
|
||||
if (needleLen > 1) {
|
||||
for (let i = 0; i < needleLen - 1; ++i)
|
||||
this._occ[needle[i]] = needleLen - 1 - i;
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.matches = 0;
|
||||
this._lookbehindSize = 0;
|
||||
this._bufPos = 0;
|
||||
}
|
||||
|
||||
push(chunk, pos) {
|
||||
let result;
|
||||
if (!Buffer.isBuffer(chunk))
|
||||
chunk = Buffer.from(chunk, 'latin1');
|
||||
const chunkLen = chunk.length;
|
||||
this._bufPos = pos || 0;
|
||||
while (result !== chunkLen && this.matches < this.maxMatches)
|
||||
result = feed(this, chunk);
|
||||
return result;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
const lbSize = this._lookbehindSize;
|
||||
if (lbSize)
|
||||
this._cb(false, this._lookbehind, 0, lbSize, false);
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
|
||||
function feed(self, data) {
|
||||
const len = data.length;
|
||||
const needle = self._needle;
|
||||
const needleLen = needle.length;
|
||||
|
||||
// Positive: points to a position in `data`
|
||||
// pos == 3 points to data[3]
|
||||
// Negative: points to a position in the lookbehind buffer
|
||||
// pos == -2 points to lookbehind[lookbehindSize - 2]
|
||||
let pos = -self._lookbehindSize;
|
||||
const lastNeedleCharPos = needleLen - 1;
|
||||
const lastNeedleChar = needle[lastNeedleCharPos];
|
||||
const end = len - needleLen;
|
||||
const occ = self._occ;
|
||||
const lookbehind = self._lookbehind;
|
||||
|
||||
if (pos < 0) {
|
||||
// Lookbehind buffer is not empty. Perform Boyer-Moore-Horspool
|
||||
// search with character lookup code that considers both the
|
||||
// lookbehind buffer and the current round's haystack data.
|
||||
//
|
||||
// Loop until
|
||||
// there is a match.
|
||||
// or until
|
||||
// we've moved past the position that requires the
|
||||
// lookbehind buffer. In this case we switch to the
|
||||
// optimized loop.
|
||||
// or until
|
||||
// the character to look at lies outside the haystack.
|
||||
while (pos < 0 && pos <= end) {
|
||||
const nextPos = pos + lastNeedleCharPos;
|
||||
const ch = (nextPos < 0
|
||||
? lookbehind[self._lookbehindSize + nextPos]
|
||||
: data[nextPos]);
|
||||
|
||||
if (ch === lastNeedleChar
|
||||
&& matchNeedle(self, data, pos, lastNeedleCharPos)) {
|
||||
self._lookbehindSize = 0;
|
||||
++self.matches;
|
||||
if (pos > -self._lookbehindSize)
|
||||
self._cb(true, lookbehind, 0, self._lookbehindSize + pos, false);
|
||||
else
|
||||
self._cb(true, undefined, 0, 0, true);
|
||||
|
||||
return (self._bufPos = pos + needleLen);
|
||||
}
|
||||
|
||||
pos += occ[ch];
|
||||
}
|
||||
|
||||
// No match.
|
||||
|
||||
// There's too few data for Boyer-Moore-Horspool to run,
|
||||
// so let's use a different algorithm to skip as much as
|
||||
// we can.
|
||||
// Forward pos until
|
||||
// the trailing part of lookbehind + data
|
||||
// looks like the beginning of the needle
|
||||
// or until
|
||||
// pos == 0
|
||||
while (pos < 0 && !matchNeedle(self, data, pos, len - pos))
|
||||
++pos;
|
||||
|
||||
if (pos < 0) {
|
||||
// Cut off part of the lookbehind buffer that has
|
||||
// been processed and append the entire haystack
|
||||
// into it.
|
||||
const bytesToCutOff = self._lookbehindSize + pos;
|
||||
|
||||
if (bytesToCutOff > 0) {
|
||||
// The cut off data is guaranteed not to contain the needle.
|
||||
self._cb(false, lookbehind, 0, bytesToCutOff, false);
|
||||
}
|
||||
|
||||
self._lookbehindSize -= bytesToCutOff;
|
||||
lookbehind.copy(lookbehind, 0, bytesToCutOff, self._lookbehindSize);
|
||||
lookbehind.set(data, self._lookbehindSize);
|
||||
self._lookbehindSize += len;
|
||||
|
||||
self._bufPos = len;
|
||||
return len;
|
||||
}
|
||||
|
||||
// Discard lookbehind buffer.
|
||||
self._cb(false, lookbehind, 0, self._lookbehindSize, false);
|
||||
self._lookbehindSize = 0;
|
||||
}
|
||||
|
||||
pos += self._bufPos;
|
||||
|
||||
const firstNeedleChar = needle[0];
|
||||
|
||||
// Lookbehind buffer is now empty. Perform Boyer-Moore-Horspool
|
||||
// search with optimized character lookup code that only considers
|
||||
// the current round's haystack data.
|
||||
while (pos <= end) {
|
||||
const ch = data[pos + lastNeedleCharPos];
|
||||
|
||||
if (ch === lastNeedleChar
|
||||
&& data[pos] === firstNeedleChar
|
||||
&& memcmp(needle, 0, data, pos, lastNeedleCharPos)) {
|
||||
++self.matches;
|
||||
if (pos > 0)
|
||||
self._cb(true, data, self._bufPos, pos, true);
|
||||
else
|
||||
self._cb(true, undefined, 0, 0, true);
|
||||
|
||||
return (self._bufPos = pos + needleLen);
|
||||
}
|
||||
|
||||
pos += occ[ch];
|
||||
}
|
||||
|
||||
// There was no match. If there's trailing haystack data that we cannot
|
||||
// match yet using the Boyer-Moore-Horspool algorithm (because the trailing
|
||||
// data is less than the needle size) then match using a modified
|
||||
// algorithm that starts matching from the beginning instead of the end.
|
||||
// Whatever trailing data is left after running this algorithm is added to
|
||||
// the lookbehind buffer.
|
||||
while (pos < len) {
|
||||
if (data[pos] !== firstNeedleChar
|
||||
|| !memcmp(data, pos, needle, 0, len - pos)) {
|
||||
++pos;
|
||||
continue;
|
||||
}
|
||||
data.copy(lookbehind, 0, pos, len);
|
||||
self._lookbehindSize = len - pos;
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything until `pos` is guaranteed not to contain needle data.
|
||||
if (pos > 0)
|
||||
self._cb(false, data, self._bufPos, pos < len ? pos : len, true);
|
||||
|
||||
self._bufPos = len;
|
||||
return len;
|
||||
}
|
||||
|
||||
function matchNeedle(self, data, pos, len) {
|
||||
const lb = self._lookbehind;
|
||||
const lbSize = self._lookbehindSize;
|
||||
const needle = self._needle;
|
||||
|
||||
for (let i = 0; i < len; ++i, ++pos) {
|
||||
const ch = (pos < 0 ? lb[lbSize + pos] : data[pos]);
|
||||
if (ch !== needle[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = SBMH;
|
34
deps/undici/src/node_modules/streamsearch/package.json
generated
vendored
Normal file
34
deps/undici/src/node_modules/streamsearch/package.json
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "streamsearch",
|
||||
"version": "1.1.0",
|
||||
"author": "Brian White <mscdex@mscdex.net>",
|
||||
"description": "Streaming Boyer-Moore-Horspool searching for node.js",
|
||||
"main": "./lib/sbmh.js",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mscdex/eslint-config": "^1.1.0",
|
||||
"eslint": "^7.32.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node test/test.js",
|
||||
"lint": "eslint --cache --report-unused-disable-directives --ext=.js .eslintrc.js lib test",
|
||||
"lint:fix": "npm run lint -- --fix"
|
||||
},
|
||||
"keywords": [
|
||||
"stream",
|
||||
"horspool",
|
||||
"boyer-moore-horspool",
|
||||
"boyer-moore",
|
||||
"search"
|
||||
],
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/mscdex/streamsearch/raw/master/LICENSE"
|
||||
}],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/mscdex/streamsearch.git"
|
||||
}
|
||||
}
|
70
deps/undici/src/node_modules/streamsearch/test/test.js
generated
vendored
Normal file
70
deps/undici/src/node_modules/streamsearch/test/test.js
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
|
||||
const StreamSearch = require('../lib/sbmh.js');
|
||||
|
||||
[
|
||||
{
|
||||
needle: '\r\n',
|
||||
chunks: [
|
||||
'foo',
|
||||
' bar',
|
||||
'\r',
|
||||
'\n',
|
||||
'baz, hello\r',
|
||||
'\n world.',
|
||||
'\r\n Node.JS rules!!\r\n\r\n',
|
||||
],
|
||||
expect: [
|
||||
[false, 'foo'],
|
||||
[false, ' bar'],
|
||||
[ true, null],
|
||||
[false, 'baz, hello'],
|
||||
[ true, null],
|
||||
[false, ' world.'],
|
||||
[ true, null],
|
||||
[ true, ' Node.JS rules!!'],
|
||||
[ true, ''],
|
||||
],
|
||||
},
|
||||
{
|
||||
needle: '---foobarbaz',
|
||||
chunks: [
|
||||
'---foobarbaz',
|
||||
'asdf',
|
||||
'\r\n',
|
||||
'---foobarba',
|
||||
'---foobar',
|
||||
'ba',
|
||||
'\r\n---foobarbaz--\r\n',
|
||||
],
|
||||
expect: [
|
||||
[ true, null],
|
||||
[false, 'asdf'],
|
||||
[false, '\r\n'],
|
||||
[false, '---foobarba'],
|
||||
[false, '---foobarba'],
|
||||
[ true, '\r\n'],
|
||||
[false, '--\r\n'],
|
||||
],
|
||||
},
|
||||
].forEach((test, i) => {
|
||||
console.log(`Running test #${i + 1}`);
|
||||
const { needle, chunks, expect } = test;
|
||||
|
||||
const results = [];
|
||||
const ss = new StreamSearch(Buffer.from(needle),
|
||||
(isMatch, data, start, end) => {
|
||||
if (data)
|
||||
data = data.toString('latin1', start, end);
|
||||
else
|
||||
data = null;
|
||||
results.push([isMatch, data]);
|
||||
});
|
||||
|
||||
for (const chunk of chunks)
|
||||
ss.push(Buffer.from(chunk));
|
||||
|
||||
assert.deepStrictEqual(results, expect);
|
||||
});
|
21
deps/undici/src/package.json
vendored
21
deps/undici/src/package.json
vendored
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "undici",
|
||||
"version": "5.10.0",
|
||||
"version": "5.11.0",
|
||||
"description": "An HTTP/1.1 client, written from scratch for Node.js",
|
||||
"homepage": "https://undici.nodejs.org",
|
||||
"bugs": {
|
||||
|
@ -46,13 +46,14 @@
|
|||
"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:jest && tsd",
|
||||
"test": "npm run test:tap && npm run test:node-fetch && npm run test:fetch && npm run test:wpt && npm run test:jest && tsd",
|
||||
"test:node-fetch": "node scripts/verifyVersion.js 16 || mocha test/node-fetch",
|
||||
"test:fetch": "node scripts/verifyVersion.js 16 || (npm run build:node && tap test/fetch/*.js && tap test/webidl/*.js)",
|
||||
"test:jest": "jest",
|
||||
"test:jest": "node scripts/verifyVersion.js 14 || jest",
|
||||
"test:tap": "tap test/*.js test/diagnostics-channel/*.js",
|
||||
"test:tdd": "tap test/*.js test/diagnostics-channel/*.js -w",
|
||||
"test:typescript": "tsd",
|
||||
"test:wpt": "node scripts/verifyVersion 18 || node test/wpt/runner/start.mjs",
|
||||
"coverage": "nyc --reporter=text --reporter=html npm run test",
|
||||
"coverage:ci": "nyc --reporter=lcov npm run test",
|
||||
"bench": "PORT=3042 concurrently -k -s first npm:bench:server npm:bench:run",
|
||||
|
@ -65,10 +66,9 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@sinonjs/fake-timers": "^9.1.2",
|
||||
"@types/node": "^17.0.29",
|
||||
"@types/node": "^17.0.45",
|
||||
"abort-controller": "^3.0.0",
|
||||
"atomic-sleep": "^1.0.0",
|
||||
"busboy": "^1.6.0",
|
||||
"chai": "^4.3.4",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai-iterator": "^3.0.2",
|
||||
|
@ -81,7 +81,7 @@
|
|||
"https-pem": "^3.0.0",
|
||||
"husky": "^8.0.1",
|
||||
"import-fresh": "^3.3.0",
|
||||
"jest": "^28.0.1",
|
||||
"jest": "^29.0.2",
|
||||
"jsfuzz": "^1.0.15",
|
||||
"mocha": "^10.0.0",
|
||||
"p-timeout": "^3.2.0",
|
||||
|
@ -94,7 +94,7 @@
|
|||
"standard": "^17.0.0",
|
||||
"table": "^6.8.0",
|
||||
"tap": "^16.1.0",
|
||||
"tsd": "^0.22.0",
|
||||
"tsd": "^0.24.1",
|
||||
"wait-on": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -106,7 +106,9 @@
|
|||
],
|
||||
"ignore": [
|
||||
"lib/llhttp/constants.js",
|
||||
"lib/llhttp/utils.js"
|
||||
"lib/llhttp/utils.js",
|
||||
"test/wpt/tests",
|
||||
"test/wpt/runner/resources"
|
||||
]
|
||||
},
|
||||
"tsd": {
|
||||
|
@ -122,5 +124,8 @@
|
|||
"testMatch": [
|
||||
"<rootDir>/test/jest/**"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"busboy": "^1.6.0"
|
||||
}
|
||||
}
|
||||
|
|
3
deps/undici/src/types/agent.d.ts
vendored
3
deps/undici/src/types/agent.d.ts
vendored
|
@ -1,6 +1,7 @@
|
|||
import { URL } from 'url'
|
||||
import Dispatcher = require('./dispatcher')
|
||||
import Pool = require('./pool')
|
||||
import {DispatchInterceptor} from "./dispatcher";
|
||||
|
||||
export = Agent
|
||||
|
||||
|
@ -20,6 +21,8 @@ declare namespace Agent {
|
|||
factory?(origin: URL, opts: Object): Dispatcher;
|
||||
/** Integer. Default: `0` */
|
||||
maxRedirections?: number;
|
||||
|
||||
interceptors?: { Agent?: readonly DispatchInterceptor[] } & Pool.Options["interceptors"]
|
||||
}
|
||||
|
||||
export interface DispatchOptions extends Dispatcher.DispatchOptions {
|
||||
|
|
10
deps/undici/src/types/client.d.ts
vendored
10
deps/undici/src/types/client.d.ts
vendored
|
@ -1,8 +1,8 @@
|
|||
import { URL } from 'url'
|
||||
import { TlsOptions } from 'tls'
|
||||
import Dispatcher = require('./dispatcher')
|
||||
import { DispatchOptions, RequestOptions } from './dispatcher'
|
||||
import buildConnector = require('./connector')
|
||||
import {DispatchInterceptor} from './dispatcher'
|
||||
import buildConnector, {connector} from "./connector";
|
||||
|
||||
export = Client
|
||||
|
||||
|
@ -28,7 +28,7 @@ declare namespace Client {
|
|||
/** The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Default: `1`. */
|
||||
pipelining?: number | null;
|
||||
/** **/
|
||||
connect?: buildConnector.BuildOptions | Function | null;
|
||||
connect?: buildConnector.BuildOptions | connector | null;
|
||||
/** The maximum length of request headers in bytes. Default: `16384` (16KiB). */
|
||||
maxHeaderSize?: number | null;
|
||||
/** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Default: `30e3` milliseconds (30s). */
|
||||
|
@ -41,6 +41,8 @@ declare namespace Client {
|
|||
tls?: TlsOptions | null;
|
||||
/** */
|
||||
maxRequestsPerClient?: number;
|
||||
|
||||
interceptors?: {Client: readonly DispatchInterceptor[] | undefined}
|
||||
}
|
||||
|
||||
export interface SocketInfo {
|
||||
|
@ -53,4 +55,6 @@ declare namespace Client {
|
|||
bytesWritten?: number
|
||||
bytesRead?: number
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
15
deps/undici/src/types/connector.d.ts
vendored
15
deps/undici/src/types/connector.d.ts
vendored
|
@ -2,7 +2,7 @@ import {TLSSocket, ConnectionOptions} from 'tls'
|
|||
import {IpcNetConnectOpts, Socket, TcpNetConnectOpts} from 'net'
|
||||
|
||||
export = buildConnector
|
||||
declare function buildConnector (options?: buildConnector.BuildOptions): typeof buildConnector.connector
|
||||
declare function buildConnector (options?: buildConnector.BuildOptions): buildConnector.connector
|
||||
|
||||
declare namespace buildConnector {
|
||||
export type BuildOptions = (ConnectionOptions | TcpNetConnectOpts | IpcNetConnectOpts) & {
|
||||
|
@ -20,7 +20,16 @@ declare namespace buildConnector {
|
|||
servername?: string
|
||||
}
|
||||
|
||||
export type Callback = (err: Error | null, socket: Socket | TLSSocket | null) => void
|
||||
export type Callback = (...args: CallbackArgs) => void
|
||||
type CallbackArgs = [null, Socket | TLSSocket] | [Error, null]
|
||||
|
||||
export function connector (options: buildConnector.Options, callback: buildConnector.Callback): Socket | TLSSocket;
|
||||
export type connector = connectorAsync | connectorSync
|
||||
|
||||
interface connectorSync {
|
||||
(options: buildConnector.Options): Socket | TLSSocket
|
||||
}
|
||||
|
||||
interface connectorAsync {
|
||||
(options: buildConnector.Options, callback: buildConnector.Callback): void
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ declare namespace DiagnosticsChannel {
|
|||
port: URL["port"];
|
||||
servername: string | null;
|
||||
}
|
||||
type Connector = typeof connector;
|
||||
type Connector = connector;
|
||||
export interface RequestCreateMessage {
|
||||
request: Request;
|
||||
}
|
||||
|
|
64
deps/undici/src/types/dispatcher.d.ts
vendored
64
deps/undici/src/types/dispatcher.d.ts
vendored
|
@ -3,8 +3,9 @@ import { Duplex, Readable, Writable } from 'stream'
|
|||
import { EventEmitter } from 'events'
|
||||
import { IncomingHttpHeaders } from 'http'
|
||||
import { Blob } from 'buffer'
|
||||
import BodyReadable = require('./readable')
|
||||
import type BodyReadable from './readable'
|
||||
import { FormData } from './formdata'
|
||||
import { UndiciError } from './errors'
|
||||
|
||||
type AbortSignal = unknown;
|
||||
|
||||
|
@ -36,6 +37,59 @@ declare class Dispatcher extends EventEmitter {
|
|||
destroy(err: Error | null): Promise<void>;
|
||||
destroy(callback: () => void): void;
|
||||
destroy(err: Error | null, callback: () => void): void;
|
||||
|
||||
on(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
||||
on(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
on(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
on(eventName: 'drain', callback: (origin: URL) => void): this;
|
||||
|
||||
|
||||
once(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
||||
once(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
once(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
once(eventName: 'drain', callback: (origin: URL) => void): this;
|
||||
|
||||
|
||||
off(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
||||
off(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
off(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
off(eventName: 'drain', callback: (origin: URL) => void): this;
|
||||
|
||||
|
||||
addListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
||||
addListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
addListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
addListener(eventName: 'drain', callback: (origin: URL) => void): this;
|
||||
|
||||
removeListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
||||
removeListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
removeListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
removeListener(eventName: 'drain', callback: (origin: URL) => void): this;
|
||||
|
||||
prependListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
||||
prependListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
prependListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
prependListener(eventName: 'drain', callback: (origin: URL) => void): this;
|
||||
|
||||
prependOnceListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
||||
prependOnceListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
prependOnceListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void): this;
|
||||
prependOnceListener(eventName: 'drain', callback: (origin: URL) => void): this;
|
||||
|
||||
listeners(eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[]
|
||||
listeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[];
|
||||
listeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[];
|
||||
listeners(eventName: 'drain'): ((origin: URL) => void)[];
|
||||
|
||||
rawListeners(eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[]
|
||||
rawListeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[];
|
||||
rawListeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: UndiciError) => void)[];
|
||||
rawListeners(eventName: 'drain'): ((origin: URL) => void)[];
|
||||
|
||||
emit(eventName: 'connect', origin: URL, targets: readonly Dispatcher[]): boolean;
|
||||
emit(eventName: 'disconnect', origin: URL, targets: readonly Dispatcher[], error: UndiciError): boolean;
|
||||
emit(eventName: 'connectionError', origin: URL, targets: readonly Dispatcher[], error: UndiciError): boolean;
|
||||
emit(eventName: 'drain', origin: URL): boolean;
|
||||
}
|
||||
|
||||
declare namespace Dispatcher {
|
||||
|
@ -147,9 +201,9 @@ declare namespace Dispatcher {
|
|||
/** Invoked when an error has occurred. */
|
||||
onError?(err: Error): void;
|
||||
/** Invoked when request is upgraded either due to a `Upgrade` header or `CONNECT` method. */
|
||||
onUpgrade?(statusCode: number, headers: string[] | null, socket: Duplex): void;
|
||||
onUpgrade?(statusCode: number, headers: Buffer[] | string[] | null, socket: Duplex): void;
|
||||
/** Invoked when statusCode and headers have been received. May be invoked multiple times due to 1xx informational headers. */
|
||||
onHeaders?(statusCode: number, headers: string[] | null, resume: () => void): boolean;
|
||||
onHeaders?(statusCode: number, headers: Buffer[] | string[] | null, resume: () => void): boolean;
|
||||
/** Invoked when response payload data is received. */
|
||||
onData?(chunk: Buffer): boolean;
|
||||
/** Invoked when response payload and trailers have been received and the request has completed. */
|
||||
|
@ -172,4 +226,8 @@ declare namespace Dispatcher {
|
|||
json(): Promise<any>;
|
||||
text(): Promise<string>;
|
||||
}
|
||||
|
||||
export interface DispatchInterceptor {
|
||||
(dispatch: Dispatcher['dispatch']): Dispatcher['dispatch']
|
||||
}
|
||||
}
|
||||
|
|
7
deps/undici/src/types/global-origin.d.ts
vendored
Normal file
7
deps/undici/src/types/global-origin.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
export {
|
||||
setGlobalOrigin,
|
||||
getGlobalOrigin
|
||||
}
|
||||
|
||||
declare function setGlobalOrigin(origin: string | URL | undefined): void;
|
||||
declare function getGlobalOrigin(): URL | undefined;
|
9
deps/undici/src/types/handlers.d.ts
vendored
Normal file
9
deps/undici/src/types/handlers.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Dispatcher from "./dispatcher";
|
||||
|
||||
export declare class RedirectHandler implements Dispatcher.DispatchHandlers{
|
||||
constructor (dispatch: Dispatcher, maxRedirections: number, opts: Dispatcher.DispatchOptions, handler: Dispatcher.DispatchHandlers)
|
||||
}
|
||||
|
||||
export declare class DecoratorHandler implements Dispatcher.DispatchHandlers{
|
||||
constructor (handler: Dispatcher.DispatchHandlers)
|
||||
}
|
5
deps/undici/src/types/interceptors.d.ts
vendored
Normal file
5
deps/undici/src/types/interceptors.d.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
import {DispatchInterceptor} from "./dispatcher";
|
||||
|
||||
type RedirectInterceptorOpts = { maxRedirections?: number }
|
||||
|
||||
export declare function createRedirectInterceptor (opts: RedirectInterceptorOpts): DispatchInterceptor
|
3
deps/undici/src/types/pool.d.ts
vendored
3
deps/undici/src/types/pool.d.ts
vendored
|
@ -2,6 +2,7 @@ import Client = require('./client')
|
|||
import Dispatcher = require('./dispatcher')
|
||||
import TPoolStats = require('./pool-stats')
|
||||
import { URL } from 'url'
|
||||
import {DispatchInterceptor} from "./dispatcher";
|
||||
|
||||
export = Pool
|
||||
|
||||
|
@ -22,5 +23,7 @@ declare namespace Pool {
|
|||
factory?(origin: URL, opts: object): Dispatcher;
|
||||
/** The max number of clients to create. `null` if no limit. Default `null`. */
|
||||
connections?: number | null;
|
||||
|
||||
interceptors?: { Pool?: readonly DispatchInterceptor[] } & Client.Options["interceptors"]
|
||||
}
|
||||
}
|
||||
|
|
5180
deps/undici/undici.js
vendored
5180
deps/undici/undici.js
vendored
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue