Comparing version 4.4.4 to 4.4.5
@@ -15,4 +15,4 @@ 'use strict' | ||
const { AsyncResource } = require('async_hooks') | ||
const { assert } = require('console') | ||
const { addSignal, removeSignal } = require('./abort-signal') | ||
const assert = require('assert') | ||
@@ -19,0 +19,0 @@ const kResume = Symbol('resume') |
@@ -9,3 +9,3 @@ // Ported from https://github.com/nodejs/undici/pull/907 | ||
const util = require('../core/util') | ||
const { toWebReadable } = require('../fetch/util') | ||
const { ReadableStreamFrom } = require('../fetch/util') | ||
@@ -135,3 +135,3 @@ let Blob | ||
if (!this[kBody]) { | ||
this[kBody] = toWebReadable(this) | ||
this[kBody] = ReadableStreamFrom(this) | ||
if (this[kConsume]) { | ||
@@ -138,0 +138,0 @@ // TODO: Is this the best way to force a lock? |
@@ -179,20 +179,2 @@ 'use strict' | ||
class InvalidHTTPTokenError extends TypeError { | ||
constructor (name, token) { | ||
super(`${name} must be a valid HTTP token ["${token}"]`) | ||
Error.captureStackTrace(this, InvalidHTTPTokenError) | ||
this.name = 'InvalidHTTPToken' | ||
this.code = 'INVALID_HTTP_TOKEN' | ||
} | ||
} | ||
class HTTPInvalidHeaderValueError extends TypeError { | ||
constructor (name, value) { | ||
super(`Invalid value "${value}" for header "${name}"`) | ||
Error.captureStackTrace(this, HTTPInvalidHeaderValueError) | ||
this.name = 'HTTPInvalidHeaderValue' | ||
this.code = 'HTTP_INVALID_HEADER_VALUE' | ||
} | ||
} | ||
module.exports = { | ||
@@ -216,5 +198,3 @@ AbortError, | ||
NotSupportedError, | ||
ResponseContentLengthMismatchError, | ||
InvalidHTTPTokenError, | ||
HTTPInvalidHeaderValueError | ||
ResponseContentLengthMismatchError | ||
} |
'use strict' | ||
const util = require('../core/util') | ||
const { toWebReadable } = require('./util') | ||
const { ReadableStreamFrom } = require('./util') | ||
const { FormData } = require('./formdata') | ||
const { kState } = require('./symbols') | ||
const { Blob } = require('buffer') | ||
const { Readable } = require('stream') | ||
const { kBodyUsed } = require('../core/symbols') | ||
@@ -20,2 +19,3 @@ const assert = require('assert') | ||
} else { | ||
// istanbul ignore next: node < 16.7 | ||
yield await blob.arrayBuffer() | ||
@@ -76,10 +76,7 @@ } | ||
const boundary = '----formdata-undici-' + Math.random() | ||
const prefix = `--${boundary}\r\nContent-Disposition: form-data; name="` | ||
const prefix = `--${boundary}\r\nContent-Disposition: form-data` | ||
/*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */ | ||
const escape = (str, filename) => | ||
(filename ? str : str.replace(/\r?\n|\r/g, '\r\n')) | ||
.replace(/\n/g, '%0A') | ||
.replace(/\r/g, '%0D') | ||
.replace(/"/g, '%22') | ||
const escape = str => str.replace(/\n/g, '%0A').replace(/\r/g, '%0D').replace(/"/g, '%22') | ||
const normalizeLinefeeds = value => value.replace(/\r?\n|\r/g, '\r\n') | ||
@@ -95,4 +92,4 @@ // Set action to this step: run the multipart/form-data | ||
prefix + | ||
escape(name) + | ||
`"\r\n\r\n${value.replace(/\r(?!\n)|(?<!\r)\n/g, '\r\n')}\r\n` | ||
`; name="${escape(normalizeLinefeeds(name))}"` + | ||
`\r\n\r\n${normalizeLinefeeds(value)}\r\n` | ||
) | ||
@@ -102,4 +99,4 @@ } else { | ||
prefix + | ||
escape(name) + | ||
`"; filename="${escape(value.name, 1)}"\r\n` + | ||
`; name="${escape(normalizeLinefeeds(name))}"` + | ||
(value.filename ? `; filename="${escape(value.filename)}"` : '') + '\r\n' + | ||
`Content-Type: ${ | ||
@@ -133,7 +130,3 @@ value.type || 'application/octet-stream' | ||
// Set action to this step: read object. | ||
action = async function * (object) { | ||
for await (const chunk of blobGen(object)) { | ||
yield chunk | ||
} | ||
} | ||
action = blobGen | ||
@@ -151,5 +144,3 @@ // Set source to object. | ||
} | ||
} else if (object instanceof ReadableStream || object instanceof Readable) { | ||
// ReadableStream | ||
} else if (typeof object[Symbol.asyncIterator] === 'function') { | ||
// If keepalive is true, then throw a TypeError. | ||
@@ -167,10 +158,7 @@ if (keepalive) { | ||
if (util.isStream(object)) { | ||
stream = toWebReadable(object) | ||
} else { | ||
stream = object | ||
} | ||
stream = object instanceof ReadableStream | ||
? object | ||
: ReadableStreamFrom(object) | ||
} else { | ||
// TODO: byte sequence? | ||
// TODO: FormData? | ||
// TODO: scalar value string? | ||
@@ -243,2 +231,3 @@ // TODO: else? | ||
if (!ReadableStream) { | ||
// istanbul ignore next | ||
ReadableStream = require('stream/web').ReadableStream | ||
@@ -253,3 +242,5 @@ } | ||
// Assert: object is neither disturbed nor locked. | ||
// istanbul ignore next | ||
assert(!util.isDisturbed(object), 'disturbed') | ||
// istanbul ignore next | ||
assert(!object.locked, 'locked') | ||
@@ -335,2 +326,3 @@ } | ||
} catch (err) { | ||
// istanbul ignore next: Unclear when new URLSearchParams can fail on a string. | ||
// 2. If entries is failure, then throw a TypeError. | ||
@@ -369,11 +361,4 @@ throw Object.assign(new TypeError(), { cause: err }) | ||
function cancelBody (body, reason) { | ||
try { | ||
if (body.stream) { | ||
body.stream.cancel(reason) | ||
} | ||
} catch (err) { | ||
// Will throw TypeError if body is not readable. | ||
if (err.name !== 'TypeError') { | ||
throw err | ||
} | ||
if (body.stream && !/state: 'errored'/.test(nodeUtil.inspect(body.stream))) { | ||
body.stream.cancel(reason) | ||
} | ||
@@ -380,0 +365,0 @@ } |
@@ -169,5 +169,2 @@ 'use strict' | ||
* [Symbol.iterator] () { | ||
if (!(this instanceof FormData)) { | ||
throw new TypeError('Illegal invocation') | ||
} | ||
// The value pairs to iterate over are this’s entry list’s entries with | ||
@@ -174,0 +171,0 @@ // the key being the name and the value being the value. |
@@ -163,5 +163,7 @@ // https://github.com/Ethan-Arrowood/undici-fetch | ||
) { | ||
throw new TypeError("Failed to construct 'Headers': The provided value is not of type '(record<ByteString, ByteString> or sequence<sequence<ByteString>>") | ||
throw new TypeError( | ||
"Failed to construct 'Headers': The provided value is not of type '(record<ByteString, ByteString> or sequence<sequence<ByteString>>" | ||
) | ||
} | ||
const init = args.length >= 1 ? (args[0] ?? {}) : {} | ||
const init = args.length >= 1 ? args[0] ?? {} : {} | ||
@@ -315,6 +317,2 @@ this[kHeadersList] = new HeadersList() | ||
* keys () { | ||
if (!(this instanceof Headers)) { | ||
throw new TypeError('Illegal invocation') | ||
} | ||
for (let index = 0; index < this[kHeadersList].length; index += 2) { | ||
@@ -326,6 +324,2 @@ yield this[kHeadersList][index] | ||
* values () { | ||
if (!(this instanceof Headers)) { | ||
throw new TypeError('Illegal invocation') | ||
} | ||
for (let index = 1; index < this[kHeadersList].length; index += 2) { | ||
@@ -337,6 +331,2 @@ yield this[kHeadersList][index] | ||
* entries () { | ||
if (!(this instanceof Headers)) { | ||
throw new TypeError('Illegal invocation') | ||
} | ||
for (let index = 0; index < this[kHeadersList].length; index += 2) { | ||
@@ -397,2 +387,9 @@ yield [this[kHeadersList][index], this[kHeadersList][index + 1]] | ||
module.exports = { fill, Headers, HeadersList } | ||
module.exports = { | ||
fill, | ||
Headers, | ||
HeadersList, | ||
binarySearch, | ||
normalizeAndValidateHeaderName, | ||
normalizeAndValidateHeaderValue | ||
} |
@@ -47,3 +47,3 @@ // https://github.com/Ethan-Arrowood/undici-fetch | ||
const EE = require('events') | ||
const { PassThrough, pipeline } = require('stream') | ||
const { PassThrough, pipeline, compose } = require('stream') | ||
@@ -60,10 +60,18 @@ let ReadableStream | ||
if (args.length < 1) { | ||
throw new TypeError(`Failed to execute 'fetch' on 'Window': 1 argument required, but only ${args.length} present.`) | ||
throw new TypeError( | ||
`Failed to execute 'fetch' on 'Window': 1 argument required, but only ${args.length} present.` | ||
) | ||
} | ||
if (args.length >= 1 && typeof args[1] !== 'object' && args[1] !== undefined) { | ||
throw new TypeError("Failed to execute 'fetch' on 'Window': cannot convert to dictionary.") | ||
if ( | ||
args.length >= 1 && | ||
typeof args[1] !== 'object' && | ||
args[1] !== undefined | ||
) { | ||
throw new TypeError( | ||
"Failed to execute 'fetch' on 'Window': cannot convert to dictionary." | ||
) | ||
} | ||
const resource = args[0] | ||
const init = args.length >= 1 ? (args[1] ?? {}) : {} | ||
const init = args.length >= 1 ? args[1] ?? {} : {} | ||
@@ -274,3 +282,3 @@ const context = Object.assign(new EE(), { | ||
if (request.body !== null) { | ||
cancelBody(request.body) | ||
cancelBody(request.body, error) | ||
} | ||
@@ -1681,6 +1689,10 @@ | ||
if (decoders.length > 1) { | ||
this.decoder = new PassThrough() | ||
iterator = pipeline(this.decoder, ...decoders, () => {})[ | ||
Symbol.asyncIterator | ||
]() | ||
if (compose) { | ||
this.decoder = compose(...decoders) | ||
} else { | ||
this.decoder = new PassThrough() | ||
iterator = pipeline(this.decoder, ...decoders, () => {})[ | ||
Symbol.asyncIterator | ||
]() | ||
} | ||
} else if (decoders.length === 1) { | ||
@@ -1737,3 +1749,3 @@ this.decoder = decoders[0] | ||
// 5. Increase timingInfo’s decoded body size by bytes’s length. | ||
timingInfo.decodedBodySize += bytes ? bytes.byteLength : 0 | ||
timingInfo.decodedBodySize += bytes?.byteLength ?? 0 | ||
@@ -1740,0 +1752,0 @@ // 6. If bytes is failure, then terminate the ongoing fetch. |
@@ -36,9 +36,17 @@ /* globals AbortController */ | ||
if (args.length < 1) { | ||
throw new TypeError(`Failed to construct 'Request': 1 argument required, but only ${args.length} present.`) | ||
throw new TypeError( | ||
`Failed to construct 'Request': 1 argument required, but only ${args.length} present.` | ||
) | ||
} | ||
if (args.length >= 1 && typeof args[1] !== 'object' && args[1] !== undefined) { | ||
throw new TypeError("Failed to construct 'Request': cannot convert to dictionary.") | ||
if ( | ||
args.length >= 1 && | ||
typeof args[1] !== 'object' && | ||
args[1] !== undefined | ||
) { | ||
throw new TypeError( | ||
"Failed to construct 'Request': cannot convert to dictionary." | ||
) | ||
} | ||
const input = args[0] instanceof Request ? args[0] : String(args[0]) | ||
const init = args.length >= 1 ? (args[1] ?? {}) : {} | ||
const init = args.length >= 1 ? args[1] ?? {} : {} | ||
@@ -280,3 +288,3 @@ // TODO | ||
if (forbiddenMethods.indexOf(method.toUpperCase()) !== -1) { | ||
throw Error(`'${init.method}' HTTP method is unsupported.`) | ||
throw TypeError(`'${init.method}' HTTP method is unsupported.`) | ||
} | ||
@@ -667,3 +675,3 @@ | ||
if (this.bodyUsed || (this.body && this.body.locked)) { | ||
throw new TypeError() | ||
throw new TypeError('unusable') | ||
} | ||
@@ -670,0 +678,0 @@ |
@@ -90,8 +90,14 @@ 'use strict' | ||
constructor (...args) { | ||
if (args.length >= 1 && typeof args[1] !== 'object' && args[1] !== undefined) { | ||
throw new TypeError("Failed to construct 'Request': cannot convert to dictionary.") | ||
if ( | ||
args.length >= 1 && | ||
typeof args[1] !== 'object' && | ||
args[1] !== undefined | ||
) { | ||
throw new TypeError( | ||
"Failed to construct 'Request': cannot convert to dictionary." | ||
) | ||
} | ||
const body = args.length >= 1 ? args[0] : null | ||
const init = args.length >= 2 ? (args[1] ?? {}) : {} | ||
const init = args.length >= 2 ? args[1] ?? {} : {} | ||
@@ -98,0 +104,0 @@ // TODO |
'use strict' | ||
const { redirectStatus } = require('./constants') | ||
const { destroy, isDestroyed } = require('../../lib/core/util') | ||
const { AbortError } = require('../../lib/core/errors') | ||
const { finished } = require('stream') | ||
const { performance } = require('perf_hooks') | ||
let ReadableStream | ||
let CountQueuingStrategy | ||
@@ -137,72 +133,35 @@ // https://fetch.spec.whatwg.org/#block-bad-port | ||
function toWebReadable (streamReadable) { | ||
function ReadableStreamFrom (iterable) { | ||
if (!ReadableStream) { | ||
ReadableStream = require('stream/web').ReadableStream | ||
} | ||
if (!CountQueuingStrategy) { | ||
CountQueuingStrategy = require('stream/web').CountQueuingStrategy | ||
} | ||
if (isDestroyed(streamReadable)) { | ||
const readable = new ReadableStream() | ||
readable.cancel() | ||
return readable | ||
if (ReadableStream.from) { | ||
// https://github.com/whatwg/streams/pull/1083 | ||
return ReadableStream.from(iterable) | ||
} | ||
const objectMode = streamReadable.readableObjectMode | ||
const highWaterMark = streamReadable.readableHighWaterMark | ||
const strategy = objectMode | ||
? new CountQueuingStrategy({ highWaterMark }) | ||
: { highWaterMark } | ||
let controller | ||
function onData (chunk) { | ||
// Copy the Buffer to detach it from the pool. | ||
if (Buffer.isBuffer(chunk) && !objectMode) { | ||
chunk = new Uint8Array(chunk) | ||
} | ||
controller.enqueue(chunk) | ||
if (controller.desiredSize <= 0) { | ||
streamReadable.pause() | ||
} | ||
} | ||
streamReadable.pause() | ||
finished(streamReadable, (err) => { | ||
if (err && err.code === 'ERR_STREAM_PREMATURE_CLOSE') { | ||
const er = new AbortError() | ||
er.cause = er | ||
err = er | ||
} | ||
if (err) { | ||
controller.error(err) | ||
} else { | ||
queueMicrotask(() => { | ||
// Must not use `process.nextTick()`. | ||
// See https://github.com/nodejs/node/issues/39758 | ||
controller.close() | ||
}) | ||
} | ||
}) | ||
streamReadable.on('data', onData) | ||
let iterator | ||
return new ReadableStream( | ||
{ | ||
start (c) { | ||
controller = c | ||
async start () { | ||
iterator = iterable[Symbol.asyncIterator]() | ||
}, | ||
pull () { | ||
streamReadable.resume() | ||
async pull (controller) { | ||
const { done, value } = await iterator.next() | ||
if (done) { | ||
queueMicrotask(() => { | ||
controller.close() | ||
}) | ||
} else { | ||
const buf = Buffer.isBuffer(value) ? value : Buffer.from(value) | ||
controller.enqueue(new Uint8Array(buf)) | ||
} | ||
return controller.desiredSize > 0 | ||
}, | ||
cancel (reason) { | ||
destroy(streamReadable, reason) | ||
async cancel (reason) { | ||
await iterator.return() | ||
} | ||
}, | ||
strategy | ||
0 | ||
) | ||
@@ -346,3 +305,3 @@ } | ||
crossOriginResourcePolicyCheck, | ||
toWebReadable, | ||
ReadableStreamFrom, | ||
makeTimingInfo, | ||
@@ -349,0 +308,0 @@ setRequestReferrerPolicyOnRedirect, |
{ | ||
"name": "undici", | ||
"version": "4.4.4", | ||
"version": "4.4.5", | ||
"description": "An HTTP/1.1 client, written from scratch for Node.js", | ||
@@ -36,4 +36,5 @@ "homepage": "https://undici.nodejs.org", | ||
"lint:fix": "standard --fix | snazzy", | ||
"test": "npm run test:tap && npm run test:node-fetch && npm run test:jest", | ||
"test:node-fetch": "node scripts/test-node-fetch.js 16 && mocha test/node-fetch || echo Skipping", | ||
"test": "npm run test:tap && npm run test:node-fetch && npm run test:fetch && npm run test:jest && tsd", | ||
"test:node-fetch": "node scripts/verifyVersion.js 16 && mocha test/node-fetch || echo Skipping", | ||
"test:fetch": "node scripts/verifyVersion.js 16 && tap test/fetch/*.js || echo Skipping", | ||
"test:jest": "jest test/jest/test", | ||
@@ -44,3 +45,3 @@ "test:tap": "tap test/*.js", | ||
"coverage": "nyc npm run test", | ||
"coverage:ci": "npm run coverage -- --reporter=lcovonly", | ||
"coverage:ci": "nyc --reporter=lcov npm run test", | ||
"bench": "concurrently -k -s first npm:bench:server npm:bench:run", | ||
@@ -56,3 +57,3 @@ "bench:server": "node benchmarks/server.js", | ||
"@sinonjs/fake-timers": "^7.0.5", | ||
"@types/node": "^15.0.2", | ||
"@types/node": "^16.6.1", | ||
"abort-controller": "^3.0.0", | ||
@@ -64,9 +65,9 @@ "busboy": "^0.3.1", | ||
"chai-string": "^1.5.0", | ||
"concurrently": "^6.1.0", | ||
"concurrently": "^6.2.1", | ||
"cronometro": "^0.8.0", | ||
"delay": "^5.0.0", | ||
"docsify-cli": "^4.4.2", | ||
"docsify-cli": "^4.4.3", | ||
"https-pem": "^2.0.0", | ||
"husky": "^6.0.0", | ||
"jest": "^27.0.5", | ||
"husky": "^7.0.1", | ||
"jest": "^27.0.6", | ||
"jsfuzz": "^1.0.15", | ||
@@ -79,3 +80,3 @@ "mocha": "^9.0.3", | ||
"semver": "^7.3.5", | ||
"sinon": "^11.1.1", | ||
"sinon": "^11.1.2", | ||
"snazzy": "^9.0.0", | ||
@@ -85,3 +86,3 @@ "standard": "^16.0.3", | ||
"tsd": "^0.17.0", | ||
"wait-on": "^5.3.0" | ||
"wait-on": "^6.0.0" | ||
}, | ||
@@ -100,5 +101,2 @@ "engines": { | ||
}, | ||
"tap": { | ||
"check-coverage": false | ||
}, | ||
"tsd": { | ||
@@ -105,0 +103,0 @@ "directory": "test/types", |
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
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
590871
9282