Comparing version 6.7.0 to 6.7.1
@@ -22,5 +22,5 @@ # Diagnostics Channel Support | ||
console.log('path', request.path) | ||
console.log('headers') // raw text, e.g: 'bar: bar\r\n' | ||
console.log('headers') // array of strings, e.g: ['foo', 'bar'] | ||
request.addHeader('hello', 'world') | ||
console.log('headers', request.headers) // e.g. 'bar: bar\r\nhello: world\r\n' | ||
console.log('headers', request.headers) // e.g. ['foo', 'bar', 'hello', 'world'] | ||
}) | ||
@@ -27,0 +27,0 @@ ``` |
@@ -20,2 +20,4 @@ # Class: ProxyAgent | ||
* **uri** `string | URL` (required) - The URI of the proxy server. This can be provided as a string, as an instance of the URL class, or as an object with a `uri` property of type string. | ||
If the `uri` is provided as a string or `uri` is an object with an `uri` property of type string, then it will be parsed into a `URL` object according to the [WHATWG URL Specification](https://url.spec.whatwg.org). | ||
For detailed information on the parsing process and potential validation errors, please refer to the ["Writing" section](https://url.spec.whatwg.org/#writing) of the WHATWG URL Specification. | ||
* **token** `string` (optional) - It can be passed by a string of token for authentication. | ||
@@ -22,0 +24,0 @@ * **auth** `string` (**deprecated**) - Use token. |
'use strict' | ||
const Readable = require('./readable') | ||
const { Readable } = require('./readable') | ||
const { | ||
@@ -5,0 +5,0 @@ InvalidArgumentError, |
@@ -19,3 +19,3 @@ // Ported from https://github.com/nodejs/undici/pull/907 | ||
module.exports = class BodyReadable extends Readable { | ||
class BodyReadable extends Readable { | ||
constructor ({ | ||
@@ -288,12 +288,13 @@ resume, | ||
const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks, length) | ||
const bufferLength = buffer.length | ||
// Skip BOM. | ||
const start = | ||
buffer.length >= 3 && | ||
// Skip BOM. | ||
buffer[0] === 0xef && | ||
buffer[1] === 0xbb && | ||
buffer[2] === 0xbf | ||
? 3 | ||
: 0 | ||
return buffer.utf8Slice(start, buffer.length - start) | ||
bufferLength > 2 && | ||
buffer[0] === 0xef && | ||
buffer[1] === 0xbb && | ||
buffer[2] === 0xbf | ||
? 3 | ||
: 0 | ||
return buffer.utf8Slice(start, bufferLength) | ||
} | ||
@@ -352,1 +353,3 @@ | ||
} | ||
module.exports = { Readable: BodyReadable, chunksDecode } |
@@ -5,4 +5,6 @@ const assert = require('node:assert') | ||
} = require('../core/errors') | ||
const { toUSVString } = require('../core/util') | ||
const { chunksDecode } = require('./readable') | ||
const CHUNK_LIMIT = 128 * 1024 | ||
async function getResolveErrorBodyCallback ({ callback, body, contentType, statusCode, statusMessage, headers }) { | ||
@@ -12,8 +14,8 @@ assert(body) | ||
let chunks = [] | ||
let limit = 0 | ||
let length = 0 | ||
for await (const chunk of body) { | ||
chunks.push(chunk) | ||
limit += chunk.length | ||
if (limit > 128 * 1024) { | ||
length += chunk.length | ||
if (length > CHUNK_LIMIT) { | ||
chunks = null | ||
@@ -31,3 +33,3 @@ break | ||
if (contentType.startsWith('application/json')) { | ||
const payload = JSON.parse(toUSVString(Buffer.concat(chunks))) | ||
const payload = JSON.parse(chunksDecode(chunks, length)) | ||
process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers, payload)) | ||
@@ -38,3 +40,3 @@ return | ||
if (contentType.startsWith('text/')) { | ||
const payload = toUSVString(Buffer.concat(chunks)) | ||
const payload = chunksDecode(chunks, length) | ||
process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers, payload)) | ||
@@ -41,0 +43,0 @@ return |
@@ -77,4 +77,17 @@ 'use strict' | ||
async function lazyllhttp () { | ||
const mod = await WebAssembly.compile(require('../llhttp/llhttp_simd-wasm.js')) | ||
const llhttpWasmData = process.env.JEST_WORKER_ID ? require('../llhttp/llhttp-wasm.js') : undefined | ||
let mod | ||
try { | ||
mod = await WebAssembly.compile(require('../llhttp/llhttp_simd-wasm.js')) | ||
} catch (e) { | ||
/* istanbul ignore next */ | ||
// We could check if the error was caused by the simd option not | ||
// being enabled, but the occurring of this other error | ||
// * https://github.com/emscripten-core/emscripten/issues/11495 | ||
// got me to remove that check to avoid breaking Node 12. | ||
mod = await WebAssembly.compile(llhttpWasmData || require('../llhttp/llhttp-wasm.js')) | ||
} | ||
return await WebAssembly.instantiate(mod, { | ||
@@ -81,0 +94,0 @@ env: { |
'use strict' | ||
const Busboy = require('@fastify/busboy') | ||
const util = require('../../core/util') | ||
@@ -12,3 +11,4 @@ const { | ||
fullyReadBody, | ||
extractMimeType | ||
extractMimeType, | ||
utf8DecodeBytes | ||
} = require('./util') | ||
@@ -18,14 +18,10 @@ const { FormData } = require('./formdata') | ||
const { webidl } = require('./webidl') | ||
const { Blob, File: NativeFile } = require('node:buffer') | ||
const { Blob } = require('node:buffer') | ||
const assert = require('node:assert') | ||
const { isErrored } = require('../../core/util') | ||
const { isArrayBuffer } = require('node:util/types') | ||
const { File: UndiciFile } = require('./file') | ||
const { serializeAMimeType } = require('./data-url') | ||
const { Readable } = require('node:stream') | ||
const { multipartFormDataParser } = require('./formdata-parser') | ||
/** @type {globalThis['File']} */ | ||
const File = NativeFile ?? UndiciFile | ||
const textEncoder = new TextEncoder() | ||
const textDecoder = new TextDecoder() | ||
@@ -343,112 +339,52 @@ // https://fetch.spec.whatwg.org/#concept-bodyinit-extract | ||
async formData () { | ||
webidl.brandCheck(this, instance) | ||
formData () { | ||
// The formData() method steps are to return the result of running | ||
// consume body with this and the following step given a byte sequence bytes: | ||
return consumeBody(this, (value) => { | ||
// 1. Let mimeType be the result of get the MIME type with this. | ||
const mimeType = bodyMimeType(this) | ||
throwIfAborted(this[kState]) | ||
// 2. If mimeType is non-null, then switch on mimeType’s essence and run | ||
// the corresponding steps: | ||
if (mimeType !== null) { | ||
switch (mimeType.essence) { | ||
case 'multipart/form-data': { | ||
// 1. ... [long step] | ||
const parsed = multipartFormDataParser(value, mimeType) | ||
// 1. Let mimeType be the result of get the MIME type with this. | ||
const mimeType = bodyMimeType(this) | ||
// 2. If that fails for some reason, then throw a TypeError. | ||
if (parsed === 'failure') { | ||
throw new TypeError('Failed to parse body as FormData.') | ||
} | ||
// If mimeType’s essence is "multipart/form-data", then: | ||
if (mimeType !== null && mimeType.essence === 'multipart/form-data') { | ||
const responseFormData = new FormData() | ||
// 3. Return a new FormData object, appending each entry, | ||
// resulting from the parsing operation, to its entry list. | ||
const fd = new FormData() | ||
fd[kState] = parsed | ||
let busboy | ||
return fd | ||
} | ||
case 'application/x-www-form-urlencoded': { | ||
// 1. Let entries be the result of parsing bytes. | ||
const entries = new URLSearchParams(value.toString()) | ||
try { | ||
busboy = new Busboy({ | ||
headers: { | ||
'content-type': serializeAMimeType(mimeType) | ||
}, | ||
preservePath: true | ||
}) | ||
} catch (err) { | ||
throw new DOMException(`${err}`, 'AbortError') | ||
} | ||
// 2. If entries is failure, then throw a TypeError. | ||
busboy.on('field', (name, value) => { | ||
responseFormData.append(name, value) | ||
}) | ||
busboy.on('file', (name, value, filename, encoding, mimeType) => { | ||
const chunks = [] | ||
// 3. Return a new FormData object whose entry list is entries. | ||
const fd = new FormData() | ||
if (encoding === 'base64' || encoding.toLowerCase() === 'base64') { | ||
let base64chunk = '' | ||
for (const [name, value] of entries) { | ||
fd.append(name, value) | ||
} | ||
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 })) | ||
}) | ||
return fd | ||
} | ||
} | ||
}) | ||
const busboyResolve = new Promise((resolve, reject) => { | ||
busboy.on('finish', resolve) | ||
busboy.on('error', (err) => reject(new TypeError(err))) | ||
}) | ||
if (this.body !== null) { | ||
Readable.from(this[kState].body.stream).pipe(busboy) | ||
} | ||
await busboyResolve | ||
return responseFormData | ||
} else if (mimeType !== null && mimeType.essence === 'application/x-www-form-urlencoded') { | ||
// Otherwise, if mimeType’s essence is "application/x-www-form-urlencoded", then: | ||
// 1. Let entries be the result of parsing bytes. | ||
let entries | ||
try { | ||
let text = '' | ||
// application/x-www-form-urlencoded parser will keep the BOM. | ||
// https://url.spec.whatwg.org/#concept-urlencoded-parser | ||
// Note that streaming decoder is stateful and cannot be reused | ||
const stream = this[kState].body.stream.pipeThrough(new TextDecoderStream('utf-8', { ignoreBOM: true })) | ||
for await (const chunk of stream) { | ||
text += chunk | ||
} | ||
entries = new URLSearchParams(text) | ||
} catch (err) { | ||
// istanbul ignore next: Unclear when new URLSearchParams can fail on a string. | ||
// 2. If entries is failure, then throw a TypeError. | ||
throw new TypeError(err) | ||
} | ||
// 3. Return a new FormData object whose entries are entries. | ||
const formData = new FormData() | ||
for (const [name, value] of entries) { | ||
formData.append(name, value) | ||
} | ||
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. | ||
throw webidl.errors.exception({ | ||
header: `${instance.name}.formData`, | ||
message: 'Could not parse content as FormData.' | ||
}) | ||
} | ||
// 3. Throw a TypeError. | ||
throw new TypeError( | ||
'Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".' | ||
) | ||
}, instance) | ||
} | ||
@@ -523,28 +459,2 @@ } | ||
/** | ||
* @see https://encoding.spec.whatwg.org/#utf-8-decode | ||
* @param {Buffer} buffer | ||
*/ | ||
function utf8DecodeBytes (buffer) { | ||
if (buffer.length === 0) { | ||
return '' | ||
} | ||
// 1. Let buffer be the result of peeking three bytes from | ||
// ioQueue, converted to a byte sequence. | ||
// 2. If buffer is 0xEF 0xBB 0xBF, then read three | ||
// bytes from ioQueue. (Do nothing with those bytes.) | ||
if (buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) { | ||
buffer = buffer.subarray(3) | ||
} | ||
// 3. Process a queue with an instance of UTF-8’s | ||
// decoder, ioQueue, output, and "replacement". | ||
const output = textDecoder.decode(buffer) | ||
// 4. Return output. | ||
return output | ||
} | ||
/** | ||
* @see https://infra.spec.whatwg.org/#parse-json-bytes-to-a-javascript-value | ||
@@ -551,0 +461,0 @@ * @param {Uint8Array} bytes |
@@ -631,3 +631,2 @@ 'use strict' | ||
/** | ||
* | ||
* @param {string} str | ||
@@ -742,3 +741,5 @@ * @param {boolean} leading | ||
removeChars, | ||
minimizeSupportedMimeType | ||
minimizeSupportedMimeType, | ||
HTTP_TOKEN_CODEPOINTS, | ||
isomorphicDecode | ||
} |
'use strict' | ||
const { EOL } = require('node:os') | ||
const { Blob, File: NativeFile } = require('node:buffer') | ||
@@ -10,2 +11,3 @@ const { types } = require('node:util') | ||
const { kEnumerableProperty } = require('../../core/util') | ||
const encoder = new TextEncoder() | ||
@@ -311,4 +313,2 @@ | ||
// 1. Let native line ending be be the code point U+000A LF. | ||
let nativeLineEnding = '\n' | ||
// 2. If the underlying platform’s conventions are to | ||
@@ -318,7 +318,6 @@ // represent newlines as a carriage return and line feed | ||
// U+000D CR followed by the code point U+000A LF. | ||
if (process.platform === 'win32') { | ||
nativeLineEnding = '\r\n' | ||
} | ||
// NOTE: We are using the native line ending for the current | ||
// platform, provided by node's os module. | ||
return s.replace(/\r?\n/g, nativeLineEnding) | ||
return s.replace(/\r?\n/g, EOL) | ||
} | ||
@@ -325,0 +324,0 @@ |
@@ -219,2 +219,2 @@ 'use strict' | ||
module.exports = { FormData } | ||
module.exports = { FormData, makeEntry } |
@@ -106,3 +106,3 @@ /* globals AbortController */ | ||
} else { | ||
this[kDispatcher] = input[kDispatcher] | ||
this[kDispatcher] = init.dispatcher || input[kDispatcher] | ||
@@ -708,3 +708,3 @@ // 6. Otherwise: | ||
// Returns a boolean indicating whether or not request is for a history | ||
// navigation (a.k.a. back-foward navigation). | ||
// navigation (a.k.a. back-forward navigation). | ||
get isHistoryNavigation () { | ||
@@ -711,0 +711,0 @@ webidl.brandCheck(this, Request) |
@@ -1431,2 +1431,30 @@ 'use strict' | ||
const textDecoder = new TextDecoder() | ||
/** | ||
* @see https://encoding.spec.whatwg.org/#utf-8-decode | ||
* @param {Buffer} buffer | ||
*/ | ||
function utf8DecodeBytes (buffer) { | ||
if (buffer.length === 0) { | ||
return '' | ||
} | ||
// 1. Let buffer be the result of peeking three bytes from | ||
// ioQueue, converted to a byte sequence. | ||
// 2. If buffer is 0xEF 0xBB 0xBF, then read three | ||
// bytes from ioQueue. (Do nothing with those bytes.) | ||
if (buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) { | ||
buffer = buffer.subarray(3) | ||
} | ||
// 3. Process a queue with an instance of UTF-8’s | ||
// decoder, ioQueue, output, and "replacement". | ||
const output = textDecoder.decode(buffer) | ||
// 4. Return output. | ||
return output | ||
} | ||
module.exports = { | ||
@@ -1481,3 +1509,4 @@ isAborted, | ||
extractMimeType, | ||
getDecodeSplit | ||
getDecodeSplit, | ||
utf8DecodeBytes | ||
} |
{ | ||
"name": "undici", | ||
"version": "6.7.0", | ||
"version": "6.7.1", | ||
"description": "An HTTP/1.1 client, written from scratch for Node.js", | ||
@@ -75,3 +75,3 @@ "homepage": "https://undici.nodejs.org", | ||
"test:eventsource": "npm run build:node && borp --expose-gc -p \"test/eventsource/*.js\"", | ||
"test:fetch": "npm run build:node && borp --expose-gc -p \"test/fetch/*.js\" && borp -p \"test/webidl/*.js\"", | ||
"test:fetch": "npm run build:node && borp --expose-gc -p \"test/fetch/*.js\" && borp -p \"test/webidl/*.js\" && borp -p \"test/busboy/*.js\"", | ||
"test:jest": "cross-env NODE_V8_COVERAGE= jest", | ||
@@ -90,4 +90,4 @@ "test:unit": "borp --expose-gc -p \"test/*.js\"", | ||
"coverage:report:ci": "c8 report", | ||
"bench": "echo \"Error: Benchmarks have been moved to '\/benchmarks'\" && exit 1", | ||
"serve:website": "echo \"Error: Documentation has been moved to '\/docs'\" && exit 1", | ||
"bench": "echo \"Error: Benchmarks have been moved to '/benchmarks'\" && exit 1", | ||
"serve:website": "echo \"Error: Documentation has been moved to '/docs'\" && exit 1", | ||
"prepare": "husky install && node ./scripts/platform-shell.js", | ||
@@ -146,6 +146,3 @@ "fuzz": "jsfuzz test/fuzzing/fuzz.js corpus" | ||
] | ||
}, | ||
"dependencies": { | ||
"@fastify/busboy": "^2.0.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
1114723
0
169
23173
451
1
2
7
- Removed@fastify/busboy@^2.0.0
- Removed@fastify/busboy@2.1.1(transitive)