Socket
Socket
Sign inDemoInstall

undici

Package Overview
Dependencies
Maintainers
2
Versions
212
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

undici - npm Package Compare versions

Comparing version 4.0.0 to 4.1.0

2

docs/api/Dispatcher.md

@@ -197,3 +197,3 @@ # Dispatcher

* **method** `string`
* **body** `string | Buffer | Uint8Array | stream.Readable | null` (optional) - Default: `null`
* **body** `string | Buffer | Uint8Array | stream.Readable | Iterable | AsyncIterable | null` (optional) - Default: `null`
* **headers** `UndiciHeaders` (optional) - Default: `null`

@@ -200,0 +200,0 @@ * **idempotent** `boolean` (optional) - Default: `true` if `method` is `'HEAD'` or `'GET'` - Whether the requests can be safely retried or not. If `false` the request won't be sent until all preceding requests in the pipeline has completed.

@@ -36,3 +36,3 @@ # Class: MockAgent

'use strict'
const { MockAgent } = require('undici')
const { Agent, MockAgent } = require('undici')

@@ -73,3 +73,3 @@ const agent = new Agent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')

@@ -102,3 +102,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, request } = require('undici')

@@ -129,3 +129,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, request } = require('undici')

@@ -156,3 +156,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, request } = require('undici')

@@ -183,3 +183,3 @@ const mockAgent = new MockAgent({ connections: 1 })

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')

@@ -211,3 +211,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')

@@ -230,3 +230,3 @@ const mockAgent = new MockAgent()

headers,
tailers,
trailers,
body

@@ -252,3 +252,3 @@ } = await request('http://localhost:3000/foo?hello=there&see=ya', {

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')

@@ -280,3 +280,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')

@@ -286,6 +286,6 @@ const mockAgent = new MockAgent()

const mockPool = mockAgent.get((origin) => 'http://localhost:3000' === origin))
const mockPool = mockAgent.get((origin) => origin === 'http://localhost:3000')
mockPool.intercept({
path: '/foo',
method: 'GET',
method: 'GET'
}).reply(200, 'foo')

@@ -315,3 +315,3 @@

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher } = require('undici')

@@ -343,3 +343,3 @@ const mockAgent = new MockAgent()

path: '/foo',
method: 'GET',
method: 'GET'
}).reply(200, 'foo')

@@ -367,3 +367,3 @@

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher } = require('undici')

@@ -386,3 +386,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher } = require('undici')

@@ -415,3 +415,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')

@@ -431,3 +431,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')

@@ -454,3 +454,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')

@@ -470,3 +470,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')

@@ -492,3 +492,3 @@ const mockAgent = new MockAgent()

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, request } = require('undici')

@@ -495,0 +495,0 @@ const mockAgent = new MockAgent()

@@ -91,5 +91,5 @@ # Class: MockPool

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -121,5 +121,5 @@

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -131,3 +131,3 @@

path: '/foo',
method: 'GET',
method: 'GET'
}).reply(200, 'foo')

@@ -137,6 +137,5 @@

path: '/hello',
method: 'GET',
method: 'GET'
}).reply(200, 'hello')
const result1 = await request('http://localhost:3000/foo')

@@ -151,5 +150,5 @@

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -174,3 +173,3 @@

headers,
tailers,
trailers,
body

@@ -201,5 +200,5 @@ } = await request('http://localhost:3000/foo?hello=there&see=ya', {

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -235,5 +234,5 @@

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -244,8 +243,8 @@

mockPool.intercept({
path: '/foo',
method: 'GET'
}).replyWithError(new Error('kaboom'))
path: '/foo',
method: 'GET'
}).replyWithError(new Error('kaboom'))
await request('http://localhost:3000/foo', {
method: 'GET',
method: 'GET'
})

@@ -259,5 +258,5 @@ // Will throw new Error('kaboom')

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -269,3 +268,3 @@

path: '/foo',
method: 'GET',
method: 'GET'
}).defaultReplyHeaders({ foo: 'bar' })

@@ -282,5 +281,5 @@ .reply(200, 'foo')

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -292,3 +291,3 @@

path: '/foo',
method: 'GET',
method: 'GET'
}).defaultReplyTrailers({ foo: 'bar' })

@@ -305,5 +304,5 @@ .reply(200, 'foo')

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -314,5 +313,5 @@

mockPool.intercept({
path: '/foo',
method: 'GET'
}).replyContentLength().reply(200, 'foo')
path: '/foo',
method: 'GET'
}).replyContentLength().reply(200, 'foo')

@@ -327,5 +326,5 @@ const { headers } = await request('http://localhost:3000/foo')

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -336,8 +335,8 @@

mockPool.intercept({
path: '/foo',
method: 'GET'
}).replyContentLength().reply(200, 'foo')
path: '/foo',
method: 'GET'
}).replyContentLength().reply(200, { foo: 'bar' })
const { headers } = await request('http://localhost:3000/foo')
// headers: {"content-length":"3"}
// headers: {"content-length":"13"}
```

@@ -349,5 +348,5 @@

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -358,5 +357,5 @@

mockPool.intercept({
path: '/foo',
method: 'GET'
}).reply(200, 'foo').persist()
path: '/foo',
method: 'GET'
}).reply(200, 'foo').persist()

@@ -376,5 +375,5 @@ const result1 = await request('http://localhost:3000/foo')

'use strict'
const { MockAgent } = require('undici')
const { MockAgent, setGlobalDispatcher, request } = require('undici')
const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)

@@ -385,5 +384,5 @@

mockPool.intercept({
path: '/foo',
method: 'GET'
}).reply(200, 'foo').times(2)
path: '/foo',
method: 'GET'
}).reply(200, 'foo').times(2)

@@ -412,3 +411,3 @@ const result1 = await request('http://localhost:3000/foo')

const mockAgent = new MockAgent({ connections: 1 })
const mockAgent = new MockAgent()
const mockPool = mockAgent.get('http://localhost:3000')

@@ -435,4 +434,4 @@

const mockClient = mockAgent.get('http://localhost:3000')
mockClient.intercept({
const mockPool = mockAgent.get('http://localhost:3000')
mockPool.intercept({
path: '/foo',

@@ -445,3 +444,3 @@ method: 'GET',

body
} = await mockClient.request({
} = await mockPool.request({
origin: 'http://localhost:3000',

@@ -448,0 +447,0 @@ path: '/foo',

@@ -77,2 +77,3 @@ 'use strict'

const client = ref.deref()
/* istanbul ignore next: gc is undeterministic */
if (client) {

@@ -120,3 +121,3 @@ ret += client[kRunning]

const { maxRedirections = this[kMaxRedirections] } = opts
let { maxRedirections = this[kMaxRedirections] } = opts

@@ -127,22 +128,24 @@ if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) {

if (!maxRedirections) {
return dispatcher.dispatch(opts, handler)
}
if (util.isStream(opts.body) && util.bodyLength(opts.body) !== 0) {
if (maxRedirections && util.isStream(opts.body) && util.bodyLength(opts.body) !== 0) {
// TODO (fix): Provide some way for the user to cache the file to e.g. /tmp
// so that it can be dispatched again?
// TODO (fix): Do we need 100-expect support to provide a way to do this properly?
return dispatcher.dispatch(opts, handler)
maxRedirections = 0
}
/* istanbul ignore next */
if (util.isStream(opts.body)) {
opts.body
.on('data', function () {
assert(false)
})
if (maxRedirections) {
opts = { ...opts, maxRedirections: 0 }
handler = new RedirectHandler(this, maxRedirections, opts, handler)
/* istanbul ignore next */
// TODO (fix): Write a comment why this is needed?
if (util.isStream(opts.body)) {
opts.body
.on('data', function () {
assert(false)
})
}
}
return dispatcher.dispatch(opts, new RedirectHandler(this, opts, handler))
return dispatcher.dispatch(opts, handler)
} catch (err) {

@@ -149,0 +152,0 @@ if (typeof handler.onError !== 'function') {

@@ -120,5 +120,3 @@ 'use strict'

if (trailers) {
util.parseHeaders(trailers, this.trailers)
}
util.parseHeaders(trailers, this.trailers)

@@ -125,0 +123,0 @@ res.push(null)

@@ -135,3 +135,3 @@ 'use strict'

this.trailers = trailers ? util.parseHeaders(trailers) : {}
this.trailers = util.parseHeaders(trailers)

@@ -138,0 +138,0 @@ res.end()

@@ -10,2 +10,3 @@ 'use strict'

const Dispatcher = require('./dispatcher')
const RedirectHandler = require('./handler/redirect')
const {

@@ -65,5 +66,8 @@ RequestContentLengthMismatchError,

kStrictContentLength,
kConnector
kConnector,
kMaxRedirections
} = require('./core/symbols')
function noop () {}
class Client extends Dispatcher {

@@ -88,2 +92,3 @@ constructor (url, {

maxCachedSessions,
maxRedirections,
[kConnect]: connect

@@ -149,2 +154,6 @@ } = {}) {

if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) {
throw new InvalidArgumentError('maxRedirections must be a positive number')
}
this[kUrl] = util.parseOrigin(url)

@@ -170,2 +179,3 @@ this[kConnector] = connect || makeConnect({ tls, socketPath, maxCachedSessions })

this[kStrictContentLength] = strictContentLength == null ? true : strictContentLength
this[kMaxRedirections] = maxRedirections

@@ -242,2 +252,17 @@ // kQueue is built up of 3 sections separated by

try {
let { maxRedirections = this[kMaxRedirections] } = opts
if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) {
throw new InvalidArgumentError('maxRedirections must be a positive number')
}
if (maxRedirections && util.isStream(opts.body) && util.bodyLength(opts.body) !== 0) {
maxRedirections = 0
}
if (maxRedirections) {
opts = { ...opts, maxRedirections: 0 }
handler = new RedirectHandler(this, maxRedirections, opts, handler)
}
const request = new Request(opts, handler)

@@ -256,4 +281,4 @@

// Do nothing.
} else if (util.isStream(request.body)) {
// Wait a tick in case stream is ended in the same tick.
} else if (util.isStream(request.body) || util.isStrictIterable(request.body)) {
// Wait a tick in case stream/iterator is ended in the same tick.
this[kResuming] = 1

@@ -365,3 +390,2 @@ process.nextTick(resume, this)

let mod, build
const { resolve } = require('path')

@@ -372,7 +396,8 @@ const { readFileSync } = require('fs')

let mod
try {
build = resolve(__dirname, './llhttp/llhttp_simd.wasm')
const bin = readFileSync(build)
mod = new WebAssembly.Module(bin)
mod = new WebAssembly.Module(readFileSync(resolve(__dirname, './llhttp/llhttp_simd.wasm')))
} catch (e) {
/* istanbul ignore next */
// We could check if the error was caused by the simd option not

@@ -382,5 +407,3 @@ // being enabled, but the occurring of this other error

// got me to remove that check to avoid breaking Node 12.
build = resolve(__dirname, './llhttp/llhttp.wasm')
const bin = readFileSync(build)
mod = new WebAssembly.Module(bin)
mod = new WebAssembly.Module(readFileSync(resolve(__dirname, './llhttp/llhttp.wasm')))
}

@@ -392,2 +415,9 @@

wasm_on_url: (p, at, len) => {
/* istanbul ignore next */
return 0
},
wasm_on_status: (p, at, len) => {
return 0
},
wasm_on_message_begin: (p) => {

@@ -560,2 +590,3 @@ assert.strictEqual(currentParser.ptr, p)

let message = ''
/* istanbul ignore else: difficult to make a test case for */
if (ptr) {

@@ -751,2 +782,4 @@ const len = new Uint8Array(llhttp.exports.memory.buffer, ptr).indexOf(0)

const request = client[kQueue][client[kRunningIdx]]
/* istanbul ignore next: difficult to make a test case for */
if (!request) {

@@ -1268,4 +1301,5 @@ return -1

if (client[kRunning] > 0 && util.isStream(request.body)) {
// Request with stream body can error while other requests
if (client[kRunning] > 0 &&
(util.isStream(request.body) || util.isStrictIterable(request.body))) {
// Request with stream or iterator body can error while other requests
// are inflight and indirectly error those as well.

@@ -1275,3 +1309,3 @@ // Ensure this doesn't happen by waiting for inflight

// Request with stream body cannot be retried.
// Request with stream or iterator body cannot be retried.
// Ensure that no other requests are inflight and

@@ -1397,2 +1431,3 @@ // could cause failure.

/* istanbul ignore else: assertion */
if (!body) {

@@ -1417,146 +1452,283 @@ if (contentLength === 0) {

}
} else if (util.isStream(body)) {
writeStream({ client, request, socket, contentLength, header, expectsPayload })
} else if (util.isStrictIterable(body)) {
writeIterable({ client, request, socket, contentLength, header, expectsPayload })
} else {
socket[kWriting] = true
assert(false)
}
assert(util.isStream(body))
assert(contentLength !== 0 || client[kRunning] === 0, 'stream body cannot be pipelined')
return true
}
let finished = false
let bytesWritten = 0
function writeStream ({ client, request, socket, contentLength, header, expectsPayload }) {
const { body } = request
const onData = function (chunk) {
try {
assert(!finished)
socket[kWriting] = true
const len = Buffer.byteLength(chunk)
if (!len) {
return
}
assert(contentLength !== 0 || client[kRunning] === 0, 'stream body cannot be pipelined')
// TODO: What if not ended and bytesWritten === contentLength?
// We should defer writing chunks.
if (contentLength !== null && bytesWritten + len > contentLength) {
if (client[kStrictContentLength]) {
util.destroy(socket, new RequestContentLengthMismatchError())
return
}
let finished = false
let bytesWritten = 0
process.emitWarning(new RequestContentLengthMismatchError())
const onData = function (chunk) {
try {
assert(!finished)
const len = Buffer.byteLength(chunk)
if (!len) {
return
}
// TODO: What if not ended and bytesWritten === contentLength?
// We should defer writing chunks.
if (contentLength !== null && bytesWritten + len > contentLength) {
if (client[kStrictContentLength]) {
util.destroy(socket, new RequestContentLengthMismatchError())
return
}
if (bytesWritten === 0) {
if (!expectsPayload) {
socket[kReset] = true
}
process.emitWarning(new RequestContentLengthMismatchError())
}
if (contentLength === null) {
socket.write(`${header}transfer-encoding: chunked\r\n`, 'ascii')
} else {
socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'ascii')
}
if (bytesWritten === 0) {
if (!expectsPayload) {
socket[kReset] = true
}
if (contentLength === null) {
socket.write(`\r\n${len.toString(16)}\r\n`, 'ascii')
socket.write(`${header}transfer-encoding: chunked\r\n`, 'ascii')
} else {
socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'ascii')
}
}
bytesWritten += len
if (contentLength === null) {
socket.write(`\r\n${len.toString(16)}\r\n`, 'ascii')
}
if (!socket.write(chunk) && this.pause) {
this.pause()
}
} catch (err) {
util.destroy(this, err)
bytesWritten += len
if (!socket.write(chunk) && this.pause) {
this.pause()
}
} catch (err) {
util.destroy(this, err)
}
const onDrain = function () {
assert(!finished)
}
const onDrain = function () {
assert(!finished)
if (body.resume) {
body.resume()
}
if (body.resume) {
body.resume()
}
const onAbort = function () {
onFinished(new RequestAbortedError())
}
const onAbort = function () {
onFinished(new RequestAbortedError())
}
const onFinished = function (err) {
if (finished) {
return
}
const onFinished = function (err) {
if (finished) {
return
}
finished = true
finished = true
assert(socket.destroyed || (socket[kWriting] && client[kRunning] <= 1))
socket[kWriting] = false
assert(socket.destroyed || (socket[kWriting] && client[kRunning] <= 1))
socket[kWriting] = false
if (!err && contentLength !== null && bytesWritten !== contentLength) {
if (client[kStrictContentLength]) {
err = new RequestContentLengthMismatchError()
} else {
process.emitWarning(new RequestContentLengthMismatchError())
}
if (!err && contentLength !== null && bytesWritten !== contentLength) {
if (client[kStrictContentLength]) {
err = new RequestContentLengthMismatchError()
} else {
process.emitWarning(new RequestContentLengthMismatchError())
}
}
socket
.removeListener('drain', onDrain)
.removeListener('error', onFinished)
body
.removeListener('data', onData)
.removeListener('end', onFinished)
.removeListener('error', onFinished)
.removeListener('close', onAbort)
socket
.removeListener('drain', onDrain)
.removeListener('error', onFinished)
body
.removeListener('data', onData)
.removeListener('end', onFinished)
.removeListener('error', onFinished)
.removeListener('close', onAbort)
// TODO (fix): Avoid using err.message for logic.
if (err && (err.code !== 'UND_ERR_INFO' || err.message !== 'reset')) {
util.destroy(body, err)
// TODO (fix): Avoid using err.message for logic.
if (err && (err.code !== 'UND_ERR_INFO' || err.message !== 'reset')) {
util.destroy(body, err)
} else {
util.destroy(body)
}
if (err) {
assert(client[kRunning] <= 1, 'pipeline should only contain this request')
util.destroy(socket, err)
}
if (socket.destroyed) {
return
}
if (bytesWritten === 0) {
if (expectsPayload) {
// https://tools.ietf.org/html/rfc7230#section-3.3.2
// A user agent SHOULD send a Content-Length in a request message when
// no Transfer-Encoding is sent and the request method defines a meaning
// for an enclosed payload body.
socket.write(`${header}content-length: 0\r\n\r\n\r\n`, 'ascii')
} else {
util.destroy(body)
socket.write(`${header}\r\n`, 'ascii')
}
} else if (contentLength === null) {
socket.write('\r\n0\r\n\r\n', 'ascii')
}
if (err) {
assert(client[kRunning] <= 1, 'pipeline should only contain this request')
util.destroy(socket, err)
// TODO (fix): Add comment clarifying what this does?
if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) {
// istanbul ignore else: only for jest
if (socket[kParser].timeout.refresh) {
socket[kParser].timeout.refresh()
}
}
if (socket.destroyed) {
return
resume(client)
}
body
.on('data', onData)
.on('end', onFinished)
.on('error', onFinished)
.on('close', onAbort)
socket
.on('drain', onDrain)
.on('error', onFinished)
}
async function writeIterable ({ client, request, socket, contentLength, header, expectsPayload }) {
const { body } = request
assert(contentLength !== 0 || client[kRunning] === 0, 'iterator body cannot be pipelined')
let callback = noop
function onDrain () {
const cb = callback
callback = noop
cb()
}
const waitForDrain = () => new Promise((resolve) => {
/* istanbul ignore next: assertion */
assert(callback === noop)
/* istanbul ignore else: only for Node 12 */
if (!socket[kError]) {
callback = resolve
} else {
resolve()
}
})
socket[kWriting] = true
socket
.on('close', onDrain)
.on('drain', onDrain)
let bytesWritten = 0
try {
// TODO (fix): What if socket errors while waiting for body?
// It's up to the user to somehow abort the async iterable.
for await (const chunk of body) {
if (socket[kError]) {
throw socket[kError]
}
const len = Buffer.byteLength(chunk)
if (!len) {
continue
}
// TODO: What if not ended and bytesWritten === contentLength?
// We should defer writing chunks.
if (contentLength !== null && bytesWritten + len > contentLength) {
if (client[kStrictContentLength]) {
throw new RequestContentLengthMismatchError()
}
process.emitWarning(new RequestContentLengthMismatchError())
}
if (bytesWritten === 0) {
if (expectsPayload) {
// https://tools.ietf.org/html/rfc7230#section-3.3.2
// A user agent SHOULD send a Content-Length in a request message when
// no Transfer-Encoding is sent and the request method defines a meaning
// for an enclosed payload body.
if (!expectsPayload) {
socket[kReset] = true
}
socket.write(`${header}content-length: 0\r\n\r\n\r\n`, 'ascii')
if (contentLength === null) {
socket.write(`${header}transfer-encoding: chunked\r\n`, 'ascii')
} else {
socket.write(`${header}\r\n`, 'ascii')
socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'ascii')
}
} else if (contentLength === null) {
socket.write('\r\n0\r\n\r\n', 'ascii')
}
if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) {
// istanbul ignore else: only for jest
if (socket[kParser].timeout.refresh) {
socket[kParser].timeout.refresh()
}
if (contentLength === null) {
socket.write(`\r\n${len.toString(16)}\r\n`, 'ascii')
}
resume(client)
bytesWritten += len
if (!socket.write(chunk)) {
await waitForDrain()
}
if (socket[kError]) {
throw socket[kError]
}
}
body
.on('data', onData)
.on('end', onFinished)
.on('error', onFinished)
.on('close', onAbort)
if (socket[kError]) {
throw socket[kError]
}
if (bytesWritten === 0) {
if (expectsPayload) {
// https://tools.ietf.org/html/rfc7230#section-3.3.2
// A user agent SHOULD send a Content-Length in a request message when
// no Transfer-Encoding is sent and the request method defines a meaning
// for an enclosed payload body.
socket.write(`${header}content-length: 0\r\n\r\n\r\n`, 'ascii')
} else {
socket.write(`${header}\r\n`, 'ascii')
}
} else if (contentLength === null) {
socket.write('\r\n0\r\n\r\n', 'ascii')
}
if (contentLength !== null && bytesWritten !== contentLength) {
if (client[kStrictContentLength]) {
throw new RequestContentLengthMismatchError()
} else {
process.emitWarning(new RequestContentLengthMismatchError())
}
}
// TODO (fix): Add comment clarifying what this does?
if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) {
// istanbul ignore else: only for jest
if (socket[kParser].timeout.refresh) {
socket[kParser].timeout.refresh()
}
}
resume(client)
} catch (err) {
assert(client[kRunning] <= 1, 'pipeline should only contain this request')
util.destroy(socket, err)
} finally {
socket[kWriting] = false
socket
.on('drain', onDrain)
.on('error', onFinished)
.off('close', onDrain)
.off('drain', onDrain)
}
return true
}

@@ -1563,0 +1735,0 @@

@@ -59,4 +59,6 @@ 'use strict'

this.body = body.length ? Buffer.from(body) : null
} else if (util.isIterable(body)) {
this.body = body
} else {
throw new InvalidArgumentError('body must be a string, a Buffer or a Readable stream')
throw new InvalidArgumentError('body must be a string, a Buffer, a Readable stream, an iterable, or an async iterable')
}

@@ -134,3 +136,3 @@

return this[kHandler].onConnect(abort, this.context)
return this[kHandler].onConnect(abort)
}

@@ -137,0 +139,0 @@

@@ -40,3 +40,4 @@ module.exports = {

kConnector: Symbol('connector'),
kStrictContentLength: Symbol('strict content length')
kStrictContentLength: Symbol('strict content length'),
kMaxRedirections: Symbol('maxRedirections')
}

@@ -110,2 +110,10 @@ 'use strict'

function isIterable (obj) {
return !!(obj != null && (typeof obj[Symbol.iterator] === 'function' || typeof obj[Symbol.asyncIterator] === 'function'))
}
function isStrictIterable (obj) {
return obj && !isStream(obj) && typeof obj !== 'string' && !isBuffer(obj) && isIterable(obj)
}
function bodyLength (body) {

@@ -117,2 +125,4 @@ if (body && typeof body.on === 'function') {

: null
} else if (isStrictIterable(body)) {
return null
}

@@ -186,2 +196,4 @@

isReadable,
isIterable,
isStrictIterable,
isDestroyed,

@@ -188,0 +200,0 @@ parseHeaders,

'use strict'
const { InvalidArgumentError } = require('../core/errors')
const util = require('../core/util')
const assert = require('assert')

@@ -9,3 +9,3 @@ const redirectableStatusCodes = [300, 301, 302, 303, 307, 308]

class RedirectHandler {
constructor (dispatcher, { maxRedirections, ...opts }, handler) {
constructor (dispatcher, maxRedirections, opts, handler) {
this.dispatcher = dispatcher

@@ -20,7 +20,5 @@ this.location = null

onConnect (abort, context = {}) {
context.history = this.history
onConnect (abort) {
this.abort = abort
this.handler.onConnect(abort, context)
this.handler.onConnect(abort, { history: this.history })
}

@@ -50,2 +48,4 @@

this.opts = { ...this.opts }
// Remove headers referring to the original URL.

@@ -57,2 +57,3 @@ // By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers.

this.opts.origin = origin
this.opts.maxRedirections = 0

@@ -149,4 +150,4 @@ // https://tools.ietf.org/html/rfc7231#section-6.4.4

}
} else if (headers != null) {
throw new InvalidArgumentError('headers must be an object or an array')
} else {
assert(headers == null, 'headers must be an object or an array')
}

@@ -153,0 +154,0 @@ return ret

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

@@ -55,6 +55,6 @@ "homepage": "https://undici.nodejs.org",

"cronometro": "^0.8.0",
"docsify-cli": "^4.4.3",
"docsify-cli": "^4.4.2",
"https-pem": "^2.0.0",
"husky": "^6.0.0",
"jest": "^26.6.3",
"jest": "^27.0.5",
"jsfuzz": "^1.0.15",

@@ -65,3 +65,3 @@ "pre-commit": "^1.2.2",

"semver": "^7.3.5",
"sinon": "^10.0.0",
"sinon": "^11.1.1",
"snazzy": "^9.0.0",

@@ -68,0 +68,0 @@ "standard": "^16.0.3",

@@ -29,6 +29,6 @@ import { URL } from 'url'

upgrade(options: Dispatcher.UpgradeOptions, callback: (err: Error | null, data: Dispatcher.UpgradeData) => void): void;
/** Closes the client and gracefully waits for enqueued requests to complete before invoking the callback (or returnning a promise if no callback is provided). */
/** Closes the client and gracefully waits for enqueued requests to complete before invoking the callback (or returning a promise if no callback is provided). */
close(): Promise<void>;
close(callback: () => void): void;
/** Destroy the client abruptly with the given err. All the pending and running requests will be asynchronously aborted and error. Waits until socket is closed before invoking the callback (or returnning a promise if no callback is provided). Since this operation is asynchronously dispatched there might still be some progress on dispatched requests. */
/** Destroy the client abruptly with the given err. All the pending and running requests will be asynchronously aborted and error. Waits until socket is closed before invoking the callback (or returning a promise if no callback is provided). Since this operation is asynchronously dispatched there might still be some progress on dispatched requests. */
destroy(): Promise<void>;

@@ -48,4 +48,4 @@ destroy(err: Error | null): Promise<void>;

/** Default: `null` */
headers?: IncomingHttpHeaders | null;
/** Whether the requests can be safely retried or not. If `false` the request won't be sent until all preceeding requests in the pipeline has completed. Default: `true` if `method` is `HEAD` or `GET`. */
headers?: IncomingHttpHeaders | string[] | null;
/** Whether the requests can be safely retried or not. If `false` the request won't be sent until all preceding requests in the pipeline have completed. Default: `true` if `method` is `HEAD` or `GET`. */
idempotent?: boolean;

@@ -58,3 +58,3 @@ /** Upgrade the request. Should be used to specify the kind of upgrade i.e. `'Websocket'`. Default: `method === 'CONNECT' || null`. */

/** Default: `null` */
headers?: IncomingHttpHeaders | null;
headers?: IncomingHttpHeaders | string[] | null;
/** Default: `null` */

@@ -80,3 +80,3 @@ signal?: AbortSignal | EventEmitter | null;

/** Default: `null` */
headers?: IncomingHttpHeaders | null;
headers?: IncomingHttpHeaders | string[] | null;
/** A string of comma separated protocols, in descending preference order. Default: `'Websocket'` */

@@ -83,0 +83,0 @@ protocol?: string;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc