Comparing version 4.0.0-rc.4 to 4.0.0-rc.5
@@ -235,1 +235,5 @@ # Class: Client | ||
``` | ||
### Event: `'error'` | ||
Invoked for users errors such as throwing in the `onError` handler. |
@@ -205,3 +205,3 @@ # Dispatcher | ||
* **onConnect** `(abort: () => void, context: object) => void` - Invoked before request is dispatched on socket. May be invoked multiple times when a request is retried when the request at the head of the pipeline fails. | ||
* **onError** `(error: Error) => void` - Invoked when an error has occurred. | ||
* **onError** `(error: Error) => void` - Invoked when an error has occurred. May not throw. | ||
* **onUpgrade** `(statusCode: number, headers: Buffer[], socket: Duplex) => void` (optional) - Invoked when request is upgraded. Required if `DispatchOptions.upgrade` is defined or `DispatchOptions.method === 'CONNECT'`. | ||
@@ -208,0 +208,0 @@ * **onHeaders** `(statusCode: number, headers: Buffer[], resume: () => void) => boolean` - Invoked when statusCode and headers have been received. May be invoked multiple times due to 1xx informational headers. Not required for `upgrade` requests. |
@@ -23,3 +23,4 @@ 'use strict' | ||
InformationalError, | ||
BodyTimeoutError | ||
BodyTimeoutError, | ||
HTTPParserError | ||
} = require('./core/errors') | ||
@@ -333,4 +334,3 @@ const makeConnect = require('./core/connect') | ||
const request = requests[i] | ||
request.onError(err) | ||
assert(request.aborted) | ||
errorRequest(this, request, err) | ||
} | ||
@@ -360,12 +360,2 @@ | ||
class HTTPParserError extends Error { | ||
constructor (message, code, data) { | ||
super(message) | ||
Error.captureStackTrace(this, HTTPParserError) | ||
this.name = 'HTTPParserError' | ||
this.code = code ? `HPE_${code}` : undefined | ||
this.data = data.toString() | ||
} | ||
} | ||
let mod, build | ||
@@ -454,2 +444,6 @@ const { resolve } = require('path') | ||
this.resume = this.resume.bind(this) | ||
this.currentMessage = { | ||
request: null, | ||
trailers: null | ||
} | ||
@@ -528,37 +522,82 @@ this.bytesRead = 0 | ||
// The return value is an error code or `constants.ERROR.OK`. | ||
currentBufferRef = data | ||
currentParser = this | ||
const ret = llhttp.exports.llhttp_execute(this.ptr, currentBufferPtr, data.length) | ||
currentParser = null | ||
currentBufferRef = null | ||
try { | ||
let ret | ||
try { | ||
currentBufferRef = data | ||
currentParser = this | ||
ret = llhttp.exports.llhttp_execute(this.ptr, currentBufferPtr, data.length) | ||
} finally { | ||
currentParser = null | ||
currentBufferRef = null | ||
} | ||
if (ret === constants.ERROR.PAUSED_UPGRADE) { | ||
const offset = llhttp.exports.llhttp_get_error_pos(this.ptr) - currentBufferPtr | ||
this.onUpgrade(data.slice(offset)) | ||
} else if (ret === constants.ERROR.PAUSED) { | ||
const offset = llhttp.exports.llhttp_get_error_pos(this.ptr) - currentBufferPtr | ||
this.paused = true | ||
socket.pause() | ||
socket.unshift(data.slice(offset)) | ||
} else if (ret !== constants.ERROR.OK) { | ||
const ptr = llhttp.exports.llhttp_get_error_reason(this.ptr) | ||
let message = '' | ||
if (ptr) { | ||
const len = new Uint8Array(llhttp.exports.memory.buffer, ptr).indexOf(0) | ||
message = Buffer.from(llhttp.exports.memory.buffer, ptr, len).toString() | ||
if (ret === constants.ERROR.PAUSED_UPGRADE) { | ||
this.onUpgrade(data.slice(offset)) | ||
} else if (ret === constants.ERROR.PAUSED) { | ||
this.paused = true | ||
socket.pause() | ||
socket.unshift(data.slice(offset)) | ||
} else if (ret !== constants.ERROR.OK) { | ||
const ptr = llhttp.exports.llhttp_get_error_reason(this.ptr) | ||
let message = '' | ||
if (ptr) { | ||
const len = new Uint8Array(llhttp.exports.memory.buffer, ptr).indexOf(0) | ||
message = Buffer.from(llhttp.exports.memory.buffer, ptr, len).toString() | ||
} | ||
throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset)) | ||
} | ||
util.destroy(socket, new HTTPParserError(message, constants.ERROR[ret], data)) | ||
this.flush() | ||
} catch (err) { | ||
util.destroy(socket, err) | ||
} | ||
} | ||
flush () { | ||
const { client, request, trailers } = this.currentMessage | ||
if (!request) { | ||
return | ||
} | ||
try { | ||
request.onComplete(trailers) | ||
} catch (err) { | ||
errorRequest(client, request, err) | ||
} | ||
this.currentMessage.request = null | ||
this.currentMessage.trailers = null | ||
} | ||
finish () { | ||
currentParser = this | ||
llhttp.exports.llhttp_finish(this.ptr) | ||
currentParser = null | ||
try { | ||
try { | ||
currentParser = this | ||
const ret = llhttp.exports.llhttp_finish(this.ptr) | ||
// TODO: ret == INVALID_EOF_STATE? | ||
assert(ret === constants.ERROR.OK || ret === constants.ERROR.INVALID_EOF_STATE) | ||
} finally { | ||
currentParser = null | ||
} | ||
this.flush() | ||
} catch (err) { | ||
util.destroy(this.socket, err) | ||
} | ||
} | ||
destroy () { | ||
destroy (err) { | ||
assert(this.ptr != null) | ||
assert(currentParser == null) | ||
if (err && err.code !== 'UND_ERR_INFO' && this.currentMessage.request) { | ||
this.currentMessage.request.onError(err) | ||
this.currentMessage.request = null | ||
} | ||
assert(!this.currentMessage.request) | ||
llhttp.exports.llhttp_free(this.ptr) | ||
@@ -858,8 +897,6 @@ this.ptr = null | ||
try { | ||
request.onComplete(headers) | ||
} catch (err) { | ||
request.onError(err) | ||
assert(request.aborted) | ||
} | ||
this.flush() | ||
assert(!this.currentMessage.request && !this.currentMessage.trailers) | ||
this.currentMessage.request = request | ||
this.currentMessage.trailers = headers | ||
@@ -942,4 +979,3 @@ client[kQueue][client[kRunningIdx]++] = null | ||
const request = client[kQueue][client[kPendingIdx]++] | ||
request.onError(err) | ||
assert(request.aborted) | ||
errorRequest(client, request, err) | ||
} | ||
@@ -951,11 +987,11 @@ } else if ( | ||
) { | ||
assert(client[kPendingIdx] === client[kRunningIdx]) | ||
// Error is not caused by running request and not a recoverable | ||
// socket error. | ||
assert(client[kPendingIdx] === client[kRunningIdx]) | ||
const requests = client[kQueue].splice(client[kRunningIdx]) | ||
for (let i = 0; i < requests.length; i++) { | ||
const request = requests[i] | ||
request.onError(err) | ||
assert(request.aborted) | ||
errorRequest(client, request, err) | ||
} | ||
@@ -970,3 +1006,3 @@ assert(client[kSize] === 0) | ||
if (parser.statusCode && !parser.shouldKeepAlive) { | ||
// We treat all incoming data so for as a valid response. | ||
// We treat all incoming data so far as a valid response. | ||
parser.finish() | ||
@@ -982,7 +1018,7 @@ return | ||
this[kParser].destroy(this[kError]) | ||
this[kParser] = null | ||
const err = this[kError] || new SocketError('closed') | ||
this[kParser].destroy() | ||
this[kParser] = null | ||
client[kSocket] = null | ||
@@ -997,4 +1033,3 @@ | ||
const request = requests[i] | ||
request.onError(err) | ||
assert(request.aborted) | ||
errorRequest(client, request, err) | ||
} | ||
@@ -1006,4 +1041,3 @@ } else if (client[kRunning] > 0 && err.code !== 'UND_ERR_INFO') { | ||
request.onError(err) | ||
assert(request.aborted) | ||
errorRequest(client, request, err) | ||
} | ||
@@ -1195,4 +1229,3 @@ | ||
.on('error', function (err) { | ||
request.onError(err) | ||
assert(request.aborted) | ||
errorRequest(client, request, err) | ||
}) | ||
@@ -1266,4 +1299,3 @@ .on('end', function () { | ||
if (client[kStrictContentLength]) { | ||
request.onError(new RequestContentLengthMismatchError()) | ||
assert(request.aborted) | ||
errorRequest(client, request, new RequestContentLengthMismatchError()) | ||
return false | ||
@@ -1283,4 +1315,3 @@ } | ||
request.onError(err || new RequestAbortedError()) | ||
assert(request.aborted) | ||
errorRequest(client, request, err || new RequestAbortedError()) | ||
@@ -1290,4 +1321,3 @@ util.destroy(socket, new InformationalError('aborted')) | ||
} catch (err) { | ||
request.onError(err) | ||
assert(request.aborted) | ||
errorRequest(client, request, err) | ||
} | ||
@@ -1505,2 +1535,11 @@ | ||
function errorRequest (client, request, err) { | ||
try { | ||
request.onError(err) | ||
assert(request.aborted) | ||
} catch (err) { | ||
client.emit('error', err) | ||
} | ||
} | ||
module.exports = Client |
@@ -161,3 +161,14 @@ 'use strict' | ||
class HTTPParserError extends Error { | ||
constructor (message, code, data) { | ||
super(message) | ||
Error.captureStackTrace(this, HTTPParserError) | ||
this.name = 'HTTPParserError' | ||
this.code = code ? `HPE_${code}` : undefined | ||
this.data = data.toString() | ||
} | ||
} | ||
module.exports = { | ||
HTTPParserError, | ||
UndiciError, | ||
@@ -164,0 +175,0 @@ HeadersTimeoutError, |
{ | ||
"name": "undici", | ||
"version": "4.0.0-rc.4", | ||
"version": "4.0.0-rc.5", | ||
"description": "An HTTP/1.1 client, written from scratch for Node.js", | ||
@@ -5,0 +5,0 @@ "homepage": "https://undici.nodejs.org", |
@@ -17,3 +17,3 @@ import { URL, UrlObject } from 'url' | ||
options?: { dispatcher?: Dispatcher } & Omit<Dispatcher.RequestOptions, 'origin' | 'path'>, | ||
): PromiseLike<Dispatcher.ResponseData>; | ||
): Promise<Dispatcher.ResponseData>; | ||
@@ -25,3 +25,3 @@ /** A faster version of `request`. */ | ||
factory: Dispatcher.StreamFactory | ||
): PromiseLike<Dispatcher.StreamData>; | ||
): Promise<Dispatcher.StreamData>; | ||
@@ -39,3 +39,3 @@ /** For easy use with `stream.pipeline`. */ | ||
options?: { dispatcher?: Dispatcher } & Omit<Dispatcher.ConnectOptions, 'origin' | 'path'> | ||
): PromiseLike<Dispatcher.ConnectData>; | ||
): Promise<Dispatcher.ConnectData>; | ||
@@ -46,2 +46,2 @@ /** Upgrade to a different protocol. */ | ||
options?: { dispatcher?: Dispatcher } & Omit<Dispatcher.UpgradeOptions, 'origin' | 'path'> | ||
): PromiseLike<Dispatcher.UpgradeData>; | ||
): Promise<Dispatcher.UpgradeData>; |
@@ -16,6 +16,6 @@ import { URL } from 'url' | ||
/** Starts two-way communications with the requested resource. */ | ||
connect(options: Dispatcher.ConnectOptions): PromiseLike<Dispatcher.ConnectData>; | ||
connect(options: Dispatcher.ConnectOptions): Promise<Dispatcher.ConnectData>; | ||
connect(options: Dispatcher.ConnectOptions, callback: (err: Error | null, data: Dispatcher.ConnectData) => void): void; | ||
/** Performs an HTTP request. */ | ||
request(options: Dispatcher.RequestOptions): PromiseLike<Dispatcher.ResponseData>; | ||
request(options: Dispatcher.RequestOptions): Promise<Dispatcher.ResponseData>; | ||
request(options: Dispatcher.RequestOptions, callback: (err: Error | null, data: Dispatcher.ResponseData) => void): void; | ||
@@ -25,13 +25,13 @@ /** For easy use with `stream.pipeline`. */ | ||
/** A faster version of `Dispatcher.request`. */ | ||
stream(options: Dispatcher.RequestOptions, factory: Dispatcher.StreamFactory): PromiseLike<Dispatcher.StreamData>; | ||
stream(options: Dispatcher.RequestOptions, factory: Dispatcher.StreamFactory): Promise<Dispatcher.StreamData>; | ||
stream(options: Dispatcher.RequestOptions, factory: Dispatcher.StreamFactory, callback: (err: Error | null, data: Dispatcher.StreamData) => void): void; | ||
/** Upgrade to a different protocol. */ | ||
upgrade(options: Dispatcher.UpgradeOptions): PromiseLike<Dispatcher.UpgradeData>; | ||
upgrade(options: Dispatcher.UpgradeOptions): Promise<Dispatcher.UpgradeData>; | ||
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). */ | ||
close(): PromiseLike<void>; | ||
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(): PromiseLike<void>; | ||
destroy(err: Error | null): PromiseLike<void>; | ||
destroy(): Promise<void>; | ||
destroy(err: Error | null): Promise<void>; | ||
destroy(callback: () => void): void; | ||
@@ -38,0 +38,0 @@ destroy(err: Error | null, callback: () => void): void; |
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
418989
64
4859