Socket
Socket
Sign inDemoInstall

undici

Package Overview
Dependencies
0
Maintainers
3
Versions
198
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 6.12.0 to 6.13.0

4

lib/api/readable.js

@@ -66,5 +66,3 @@ // Ported from https://github.com/nodejs/undici/pull/907

// never get a chance and will always encounter an unhandled exception.
// - tick => process.nextTick(fn)
// - micro tick => queueMicrotask(fn)
queueMicrotask(() => {
setImmediate(() => {
callback(err)

@@ -71,0 +69,0 @@ })

@@ -101,24 +101,18 @@ 'use strict'

const { [kClient]: client } = this
const { [kSocket]: socket } = client
const err = this[kSocket][kError] || new SocketError('closed', util.getSocketInfo(this))
const err = this[kSocket][kError] || this[kError] || new SocketError('closed', util.getSocketInfo(socket))
client[kSocket] = null
client[kHTTP2Session] = null
assert(client[kPending] === 0)
if (client.destroyed) {
assert(client[kPending] === 0)
// Fail entire queue.
const requests = client[kQueue].splice(client[kRunningIdx])
for (let i = 0; i < requests.length; i++) {
const request = requests[i]
util.errorRequest(client, request, err)
// Fail entire queue.
const requests = client[kQueue].splice(client[kRunningIdx])
for (let i = 0; i < requests.length; i++) {
const request = requests[i]
util.errorRequest(client, request, err)
}
}
client[kPendingIdx] = client[kRunningIdx]
assert(client[kRunning] === 0)
client.emit('disconnect', client[kUrl], [client], err)
client[kResume]()
})

@@ -143,2 +137,20 @@

util.addListener(socket, 'close', function () {
const err = this[kError] || new SocketError('closed', util.getSocketInfo(this))
client[kSocket] = null
if (this[kHTTP2Session] != null) {
this[kHTTP2Session].destroy(err)
}
client[kPendingIdx] = client[kRunningIdx]
assert(client[kRunning] === 0)
client.emit('disconnect', client[kUrl], [client], err)
client[kResume]()
})
let closed = false

@@ -160,6 +172,6 @@ socket.on('close', () => {

destroy (err, callback) {
session.destroy(err)
if (closed) {
queueMicrotask(callback)
} else {
// Destroying the socket will trigger the session close
socket.destroy(err).on('close', callback)

@@ -263,23 +275,24 @@ }

try {
// We are already connected, streams are pending.
// We can call on connect, and wait for abort
request.onConnect((err) => {
if (request.aborted || request.completed) {
return
}
const abort = (err) => {
if (request.aborted || request.completed) {
return
}
err = err || new RequestAbortedError()
err = err || new RequestAbortedError()
if (stream != null) {
util.destroy(stream, err)
util.errorRequest(client, request, err)
session[kOpenStreams] -= 1
if (session[kOpenStreams] === 0) {
session.unref()
}
}
if (stream != null) {
util.destroy(stream, err)
}
util.errorRequest(client, request, err)
})
// We do not destroy the socket as we can continue using the session
// the stream get's destroyed and the session remains to create new streams
util.destroy(body, err)
}
try {
// We are already connected, streams are pending.
// We can call on connect, and wait for abort
request.onConnect(abort)
} catch (err) {

@@ -309,3 +322,2 @@ util.errorRequest(client, request, err)

session[kOpenStreams] -= 1
// TODO(HTTP/2): unref only if current streams count is 0
if (session[kOpenStreams] === 0) session.unref()

@@ -390,3 +402,3 @@ })

// Increment counter as we have new several streams open
// Increment counter as we have new streams open
++session[kOpenStreams]

@@ -403,3 +415,3 @@

// as there's no value to keep it open.
if (request.aborted || request.completed) {
if (request.aborted) {
const err = new RequestAbortedError()

@@ -434,3 +446,2 @@ util.errorRequest(client, request, err)

// have yet RST_STREAM support on client-side
session[kOpenStreams] -= 1
if (session[kOpenStreams] === 0) {

@@ -440,5 +451,3 @@ session.unref()

const err = new InformationalError('HTTP/2: stream half-closed (remote)')
util.errorRequest(client, request, err)
util.destroy(stream, err)
abort(new InformationalError('HTTP/2: stream half-closed (remote)'))
})

@@ -454,17 +463,7 @@

stream.once('error', function (err) {
if (client[kHTTP2Session] && !client[kHTTP2Session].destroyed && !this.closed && !this.destroyed) {
session[kOpenStreams] -= 1
util.errorRequest(client, request, err)
util.destroy(stream, err)
}
abort(err)
})
stream.once('frameError', (type, code) => {
const err = new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`)
util.errorRequest(client, request, err)
if (client[kHTTP2Session] && !client[kHTTP2Session].destroyed && !this.closed && !this.destroyed) {
session[kOpenStreams] -= 1
util.destroy(stream, err)
}
abort(new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`))
})

@@ -492,26 +491,39 @@

/* istanbul ignore else: assertion */
if (!body) {
request.onRequestSent()
if (!body || contentLength === 0) {
writeBuffer({
abort,
client,
request,
contentLength,
expectsPayload,
h2stream: stream,
body: null,
socket: client[kSocket]
})
} else if (util.isBuffer(body)) {
assert(contentLength === body.byteLength, 'buffer body must have content length')
stream.cork()
stream.write(body)
stream.uncork()
stream.end()
request.onBodySent(body)
request.onRequestSent()
writeBuffer({
abort,
client,
request,
contentLength,
body,
expectsPayload,
h2stream: stream,
socket: client[kSocket]
})
} else if (util.isBlobLike(body)) {
if (typeof body.stream === 'function') {
writeIterable({
abort,
client,
request,
contentLength,
expectsPayload,
h2stream: stream,
expectsPayload,
body: body.stream(),
socket: client[kSocket],
header: ''
socket: client[kSocket]
})
} else {
writeBlob({
abort,
body,

@@ -523,3 +535,2 @@ client,

h2stream: stream,
header: '',
socket: client[kSocket]

@@ -556,3 +567,26 @@ })

function writeStream ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) {
function writeBuffer ({ abort, h2stream, body, client, request, socket, contentLength, expectsPayload }) {
try {
if (body != null && util.isBuffer(body)) {
assert(contentLength === body.byteLength, 'buffer body must have content length')
h2stream.cork()
h2stream.write(body)
h2stream.uncork()
h2stream.end()
request.onBodySent(body)
}
if (!expectsPayload) {
socket[kReset] = true
}
request.onRequestSent()
client[kResume]()
} catch (error) {
abort(error)
}
}
function writeStream ({ abort, socket, expectsPayload, h2stream, body, client, request, contentLength }) {
assert(contentLength !== 0 || client[kRunning] === 0, 'stream body cannot be pipelined')

@@ -566,6 +600,13 @@

if (err) {
util.destroy(body, err)
util.destroy(h2stream, err)
util.destroy(pipe, err)
abort(err)
} else {
util.removeAllListeners(pipe)
request.onRequestSent()
if (!expectsPayload) {
socket[kReset] = true
}
client[kResume]()
}

@@ -575,7 +616,3 @@ }

pipe.on('data', onPipeData)
pipe.once('end', () => {
pipe.removeListener('data', onPipeData)
util.destroy(pipe)
})
util.addListener(pipe, 'data', onPipeData)

@@ -587,3 +624,3 @@ function onPipeData (chunk) {

async function writeBlob ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) {
async function writeBlob ({ abort, h2stream, body, client, request, socket, contentLength, expectsPayload }) {
assert(contentLength === body.size, 'blob body must have content length')

@@ -601,2 +638,3 @@

h2stream.uncork()
h2stream.end()

@@ -612,7 +650,7 @@ request.onBodySent(buffer)

} catch (err) {
util.destroy(h2stream)
abort(err)
}
}
async function writeIterable ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) {
async function writeIterable ({ abort, h2stream, body, client, request, socket, contentLength, expectsPayload }) {
assert(contentLength !== 0 || client[kRunning] === 0, 'iterator body cannot be pipelined')

@@ -656,7 +694,15 @@

}
h2stream.end()
request.onRequestSent()
if (!expectsPayload) {
socket[kReset] = true
}
client[kResume]()
} catch (err) {
h2stream.destroy(err)
abort(err)
} finally {
request.onRequestSent()
h2stream.end()
h2stream

@@ -663,0 +709,0 @@ .off('close', onDrain)

'use strict'
module.exports = class DecoratorHandler {
#handler
constructor (handler) {
this.handler = handler
if (typeof handler !== 'object' || handler === null) {
throw new TypeError('handler must be an object')
}
this.#handler = handler
}
onConnect (...args) {
return this.handler.onConnect(...args)
return this.#handler.onConnect?.(...args)
}
onError (...args) {
return this.handler.onError(...args)
return this.#handler.onError?.(...args)
}
onUpgrade (...args) {
return this.handler.onUpgrade(...args)
return this.#handler.onUpgrade?.(...args)
}
onResponseStarted (...args) {
return this.#handler.onResponseStarted?.(...args)
}
onHeaders (...args) {
return this.handler.onHeaders(...args)
return this.#handler.onHeaders?.(...args)
}
onData (...args) {
return this.handler.onData(...args)
return this.#handler.onData?.(...args)
}
onComplete (...args) {
return this.handler.onComplete(...args)
return this.#handler.onComplete?.(...args)
}
onBodySent (...args) {
return this.handler.onBodySent(...args)
return this.#handler.onBodySent?.(...args)
}
}

@@ -406,4 +406,2 @@ 'use strict'

throwIfAborted(object[kState])
// 1. If object is unusable, then return a promise rejected

@@ -415,2 +413,4 @@ // with a TypeError.

throwIfAborted(object[kState])
// 2. Let promise be a new promise.

@@ -417,0 +417,0 @@ const promise = createDeferredPromise()

'use strict'
const { toUSVString, isUSVString, bufferToLowerCasedHeaderName } = require('../../core/util')
const { isUSVString, bufferToLowerCasedHeaderName } = require('../../core/util')
const { utf8DecodeBytes } = require('./util')

@@ -64,39 +64,2 @@ const { HTTP_TOKEN_CODEPOINTS, isomorphicDecode } = require('./data-url')

/**
* @see https://andreubotella.github.io/multipart-form-data/#escape-a-multipart-form-data-name
* @param {string} name
* @param {string} [encoding='utf-8']
* @param {boolean} [isFilename=false]
*/
function escapeFormDataName (name, encoding = 'utf-8', isFilename = false) {
// 1. If isFilename is true:
if (isFilename) {
// 1.1. Set name to the result of converting name into a scalar value string.
name = toUSVString(name)
} else {
// 2. Otherwise:
// 2.1. Assert: name is a scalar value string.
assert(isUSVString(name))
// 2.2. Replace every occurrence of U+000D (CR) not followed by U+000A (LF),
// and every occurrence of U+000A (LF) not preceded by U+000D (CR), in
// name, by a string consisting of U+000D (CR) and U+000A (LF).
name = name.replace(/\r\n?|\r?\n/g, '\r\n')
}
// 3. Let encoded be the result of encoding name with encoding.
assert(Buffer.isEncoding(encoding))
// 4. Replace every 0x0A (LF) bytes in encoded with the byte sequence `%0A`,
// 0x0D (CR) with `%0D` and 0x22 (") with `%22`.
name = name
.replace(/\n/g, '%0A')
.replace(/\r/g, '%0D')
.replace(/"/g, '%22')
// 5. Return encoded.
return Buffer.from(name, encoding) // encoded
}
/**
* @see https://andreubotella.github.io/multipart-form-data/#multipart-form-data-parser

@@ -501,4 +464,3 @@ * @param {Buffer} input

multipartFormDataParser,
validateBoundary,
escapeFormDataName
validateBoundary
}

@@ -76,12 +76,11 @@ 'use strict'

function isValidEncodedURL (url) {
for (const c of url) {
const code = c.charCodeAt(0)
// Not used in US-ASCII
if (code >= 0x80) {
for (let i = 0; i < url.length; ++i) {
const code = url.charCodeAt(i)
if (
code > 0x7E || // Non-US-ASCII + DEL
code < 0x20 // Control characters NUL - US
) {
return false
}
// Control characters
if ((code >= 0x00 && code <= 0x1F) || code === 0x7F) {
return false
}
}

@@ -164,20 +163,11 @@ return true

// - Contains no 0x00 (NUL) or HTTP newline bytes.
if (
potentialValue.startsWith('\t') ||
potentialValue.startsWith(' ') ||
potentialValue.endsWith('\t') ||
potentialValue.endsWith(' ')
) {
return false
}
if (
potentialValue.includes('\0') ||
return (
potentialValue[0] === '\t' ||
potentialValue[0] === ' ' ||
potentialValue[potentialValue.length - 1] === '\t' ||
potentialValue[potentialValue.length - 1] === ' ' ||
potentialValue.includes('\n') ||
potentialValue.includes('\r') ||
potentialValue.includes('\n')
) {
return false
}
return true
potentialValue.includes('\0')
) === false
}

@@ -1174,9 +1164,17 @@

* @param {string|URL} url
* @returns {boolean}
*/
function urlHasHttpsScheme (url) {
if (typeof url === 'string') {
return url.startsWith('https:')
}
return url.protocol === 'https:'
return (
(
typeof url === 'string' &&
url[5] === ':' &&
url[0] === 'h' &&
url[1] === 't' &&
url[2] === 't' &&
url[3] === 'p' &&
url[4] === 's'
) ||
url.protocol === 'https:'
)
}

@@ -1573,2 +1571,3 @@

isCancelled,
isValidEncodedURL,
createDeferredPromise,

@@ -1575,0 +1574,0 @@ ReadableStreamFrom,

@@ -212,21 +212,18 @@ 'use strict'

*/
function utf8Decode (buffer) {
if (hasIntl) {
return fatalDecoder.decode(buffer)
} else {
if (!isUtf8?.(buffer)) {
// TODO: remove once node 18 or < node v18.14.0 is dropped
if (!isUtf8) {
const utf8Decode = hasIntl
? fatalDecoder.decode.bind(fatalDecoder)
: !isUtf8
? function () { // TODO: remove once node 18 or < node v18.14.0 is dropped
process.emitWarning('ICU is not supported and no fallback exists. Please upgrade to at least Node v18.14.0.', {
code: 'UNDICI-WS-NO-ICU'
})
throw new TypeError('Invalid utf-8 received.')
}
: function (buffer) {
if (isUtf8(buffer)) {
return buffer.toString('utf-8')
}
throw new TypeError('Invalid utf-8 received.')
}
throw new TypeError('Invalid utf-8 received.')
}
return buffer.toString('utf-8')
}
}
module.exports = {

@@ -233,0 +230,0 @@ isConnecting,

{
"name": "undici",
"version": "6.12.0",
"version": "6.13.0",
"description": "An HTTP/1.1 client, written from scratch for Node.js",

@@ -5,0 +5,0 @@ "homepage": "https://undici.nodejs.org",

@@ -251,2 +251,14 @@ # undici

[FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) besides text data and buffers can also utilize streams via [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) objects:
```js
import { openAsBlob } from 'node:fs'
const file = await openAsBlob('./big.csv')
const body = new FormData()
body.set('file', file, 'big.csv')
await fetch('http://example.com', { method: 'POST', body })
```
#### `request.duplex`

@@ -253,0 +265,0 @@

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc