tsoa
This commit is contained in:
366
node_modules/@hapi/wreck/lib/index.d.ts
generated
vendored
Executable file
366
node_modules/@hapi/wreck/lib/index.d.ts
generated
vendored
Executable file
@@ -0,0 +1,366 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import * as Http from 'http';
|
||||
import * as Https from 'https';
|
||||
import * as Stream from 'stream';
|
||||
import * as Url from 'url';
|
||||
import { LookupFunction } from "node:net"
|
||||
|
||||
import { Boom } from '@hapi/boom';
|
||||
|
||||
|
||||
/**
|
||||
* An HTTP request client.
|
||||
*/
|
||||
declare class Client {
|
||||
|
||||
/**
|
||||
* An object containing the node agents used for pooling connections for `http` and `https`.
|
||||
*/
|
||||
agents: Client.Agents;
|
||||
|
||||
/**
|
||||
* An event emitter used to deliver events when the `events` option is set.
|
||||
*/
|
||||
events?: Client.Events;
|
||||
|
||||
/**
|
||||
* Creates a new client.
|
||||
*
|
||||
* @param options - the client default options.
|
||||
*/
|
||||
constructor(options?: Client.Options);
|
||||
|
||||
/**
|
||||
* Creates a new client using the current client options as defaults and the provided options as override.
|
||||
*
|
||||
* @param options - the client override options.
|
||||
*
|
||||
* @returns a new client.
|
||||
*/
|
||||
defaults(options: Client.Options): Client;
|
||||
|
||||
/**
|
||||
* Request an HTTP resource.
|
||||
*
|
||||
* @param method - a string specifying the HTTP request method. Defaults to 'GET'.
|
||||
* @param url - the URI of the requested resource.
|
||||
* @param options - default options override.
|
||||
*
|
||||
* @returns a promise resolving into an HTTP response object with a 'req' property holding a reference to the HTTP request object.
|
||||
*/
|
||||
request(method: string, url: string, options?: Client.request.Options): Promise<Http.IncomingMessage> & { req: Http.ClientRequest };
|
||||
|
||||
/**
|
||||
* Reads a readable stream and returns the parsed payload.
|
||||
*
|
||||
* @param res - the readable stream.
|
||||
* @param options - default options override.
|
||||
*
|
||||
* @returns the parsed payload based on the provided options.
|
||||
*/
|
||||
read<T = Buffer>(res: Stream.Readable | Http.IncomingMessage, options?: Client.read.Options): Promise<T>;
|
||||
|
||||
/**
|
||||
* Converts a buffer, string, or an array of them into a readable stream.
|
||||
*
|
||||
* @param payload - a string, buffer, or an array of them.
|
||||
* @param encoding - the payload encoding.
|
||||
*
|
||||
* @returns a readable stream.
|
||||
*/
|
||||
toReadableStream(payload: Client.toReadableStream.Payload, encoding?: string): Stream.Readable;
|
||||
|
||||
/**
|
||||
* Parses the HTTP Cache-Control header.
|
||||
*
|
||||
* @param field - the header content.
|
||||
*
|
||||
* @returns an object with the header parameters or null if invalid.
|
||||
*/
|
||||
parseCacheControl(field: string): Client.parseCacheControl.Parameters | null;
|
||||
|
||||
/**
|
||||
* Performs an HTTP GET request.
|
||||
*
|
||||
* @param uri - the resource URI.
|
||||
* @param options - default options override.
|
||||
*
|
||||
* @returns the received payload Buffer or parsed payload based on the options.
|
||||
*/
|
||||
get<T>(uri: string, options?: Client.request.Options & Client.read.Options): Promise<Client.request.Response<T>>;
|
||||
|
||||
/**
|
||||
* Performs an HTTP POST request.
|
||||
*
|
||||
* @param uri - the resource URI.
|
||||
* @param options - default options override.
|
||||
*
|
||||
* @returns the received payload Buffer or parsed payload based on the options.
|
||||
*/
|
||||
post<T>(uri: string, options?: Client.request.Options & Client.read.Options): Promise<Client.request.Response<T>>;
|
||||
|
||||
/**
|
||||
* Performs an HTTP PATCH request.
|
||||
*
|
||||
* @param uri - the resource URI.
|
||||
* @param options - default options override.
|
||||
*
|
||||
* @returns the received payload Buffer or parsed payload based on the options.
|
||||
*/
|
||||
patch<T>(uri: string, options?: Client.request.Options & Client.read.Options): Promise<Client.request.Response<T>>;
|
||||
|
||||
/**
|
||||
* Performs an HTTP PUT request.
|
||||
*
|
||||
* @param uri - the resource URI.
|
||||
* @param options - default options override.
|
||||
*
|
||||
* @returns the received payload Buffer or parsed payload based on the options.
|
||||
*/
|
||||
put<T>(uri: string, options?: Client.request.Options & Client.read.Options): Promise<Client.request.Response<T>>;
|
||||
|
||||
/**
|
||||
* Performs an HTTP DELETE request.
|
||||
*
|
||||
* @param uri - the resource URI.
|
||||
* @param options - default options override.
|
||||
*
|
||||
* @returns the received payload Buffer or parsed payload based on the options.
|
||||
*/
|
||||
delete<T>(uri: string, options?: Client.request.Options & Client.read.Options): Promise<Client.request.Response<T>>;
|
||||
}
|
||||
|
||||
|
||||
declare namespace Client {
|
||||
|
||||
interface Options extends request.Options, read.Options {
|
||||
|
||||
/**
|
||||
* An object containing the node agents used for pooling connections for `http` and `https`.
|
||||
*/
|
||||
readonly agents?: Agents;
|
||||
|
||||
/**
|
||||
* Enables events.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly events?: boolean;
|
||||
}
|
||||
|
||||
interface Agents {
|
||||
|
||||
/**
|
||||
* The agent used for HTTP requests.
|
||||
*/
|
||||
readonly http: Http.Agent;
|
||||
|
||||
/**
|
||||
* The agent used for HTTPS requests.
|
||||
*/
|
||||
readonly https: Https.Agent;
|
||||
|
||||
/**
|
||||
* The agent used for HTTPS requests which ignores unauthorized requests.
|
||||
*/
|
||||
readonly httpsAllowUnauthorized: Https.Agent;
|
||||
}
|
||||
|
||||
class Events extends EventEmitter {
|
||||
|
||||
on(event: 'preRequest', litener: Events.preRequest): this;
|
||||
once(event: 'preRequest', litener: Events.preRequest): this;
|
||||
addListener(event: 'preRequest', litener: Events.preRequest): this;
|
||||
|
||||
on(event: 'request', listener: Events.request): this;
|
||||
once(event: 'request', listener: Events.request): this;
|
||||
addListener(event: 'request', listener: Events.request): this;
|
||||
|
||||
on(event: 'response', listener: Events.response): this;
|
||||
once(event: 'response', listener: Events.response): this;
|
||||
addListener(event: 'response', listener: Events.response): this;
|
||||
}
|
||||
|
||||
namespace Events {
|
||||
|
||||
type preRequest = (uri: string, options: Client.Options) => void;
|
||||
type request = (req: Http.ClientRequest) => void;
|
||||
type response = (err: Boom | undefined, details: { req: Http.ClientRequest, res: Http.IncomingMessage | undefined, start: number, url: Url.URL }) => void;
|
||||
}
|
||||
|
||||
namespace request {
|
||||
|
||||
interface Options {
|
||||
|
||||
/**
|
||||
* Node HTTP or HTTPS Agent object (false disables agent pooling).
|
||||
*/
|
||||
readonly agent?: Http.Agent | Https.Agent | false;
|
||||
|
||||
/**
|
||||
* Custom lookup function. Default: dns.lookup().
|
||||
*/
|
||||
readonly lookup?: LookupFunction;
|
||||
|
||||
/**
|
||||
* IP address family to use when resolving host or hostname. Valid values are 4 or 6. When unspecified, both IP v4 and v6 will be used.
|
||||
*/
|
||||
readonly family?: number;
|
||||
|
||||
/**
|
||||
* Optional dns.lookup() hints.
|
||||
*/
|
||||
readonly hints?: number;
|
||||
|
||||
/**
|
||||
* Fully qualified URL string used as the base URL.
|
||||
*/
|
||||
readonly baseUrl?: string;
|
||||
|
||||
/**
|
||||
* A function to call before a redirect is triggered.
|
||||
*
|
||||
* @param redirectMethod - a string specifying the redirect method.
|
||||
* @param statusCode - HTTP status code of the response that triggered the redirect.
|
||||
* @param location - The redirect location string.
|
||||
* @param resHeaders - An object with the headers received as part of the redirection response.
|
||||
* @param redirectOptions - Options that will be applied to the redirect request. Changes to this object are applied to the redirection request.
|
||||
* @param next - the callback function called to perform the redirection.
|
||||
*/
|
||||
readonly beforeRedirect?: (redirectMethod: string, statusCode: number, location: string, resHeaders: Record<string, string>, redirectOptions: Client.request.Options, next: () => void) => void;
|
||||
|
||||
/**
|
||||
* TLS list of TLS ciphers to override node's default.
|
||||
*/
|
||||
readonly ciphers?: string;
|
||||
|
||||
/**
|
||||
* An object containing the request headers.
|
||||
*/
|
||||
readonly headers?: Record<string, string>;
|
||||
|
||||
/**
|
||||
* Determines how to handle gzipped payloads.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly gunzip?: boolean | 'force';
|
||||
|
||||
/**
|
||||
* The request body as a string, Buffer, readable stream, or an object that can be serialized using `JSON.stringify()`.
|
||||
*/
|
||||
readonly payload?: Payload;
|
||||
|
||||
/**
|
||||
* Enables redirects on 303 responses (using GET).
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly redirect303?: boolean;
|
||||
|
||||
/**
|
||||
* Overrides the HTTP method used when following 301 and 302 redirections. Defaults to the original method.
|
||||
*/
|
||||
readonly redirectMethod?: string;
|
||||
|
||||
/**
|
||||
* The maximum number of redirects to follow.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly redirects?: number | false;
|
||||
|
||||
/**
|
||||
* A function to call when a redirect was triggered.
|
||||
*
|
||||
* @param statusCode - HTTP status code of the response that triggered the redirect.
|
||||
* @param location - the redirected location string.
|
||||
* @param req - the new ClientRequest object which replaces the one initially returned.
|
||||
*/
|
||||
readonly redirected?: (statusCode: number, location: string, req: Http.ClientRequest) => void;
|
||||
|
||||
/**
|
||||
* TLS flag indicating whether the client should reject a response from a server with invalid certificates.
|
||||
*/
|
||||
readonly rejectUnauthorized?: boolean;
|
||||
|
||||
/**
|
||||
* TLS flag indicating the SSL method to use, e.g. `SSLv3_method` to force SSL version 3.
|
||||
*/
|
||||
readonly secureProtocol?: string;
|
||||
|
||||
/**
|
||||
* A UNIX socket path string for direct server connection.
|
||||
*/
|
||||
readonly socketPath?: string;
|
||||
|
||||
/**
|
||||
* Number of milliseconds to wait without receiving a response before aborting the request.
|
||||
*
|
||||
* @default 0
|
||||
*/
|
||||
readonly timeout?: number;
|
||||
}
|
||||
|
||||
type Payload = string | Buffer | Stream.Readable | object;
|
||||
|
||||
interface Response<T = Buffer> {
|
||||
|
||||
res: Http.IncomingMessage;
|
||||
payload: T;
|
||||
}
|
||||
}
|
||||
|
||||
namespace read {
|
||||
|
||||
interface Options {
|
||||
|
||||
/**
|
||||
* Determines how to handle gzipped payloads.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly gunzip?: boolean | 'force';
|
||||
|
||||
/**
|
||||
* Determines how to parse the payload as JSON.
|
||||
*/
|
||||
readonly json?: boolean | 'strict' | 'force';
|
||||
|
||||
/**
|
||||
* The maximum allowed response payload size.
|
||||
*
|
||||
* @default 0
|
||||
*/
|
||||
readonly maxBytes?: number;
|
||||
|
||||
/**
|
||||
* The number of milliseconds to wait while reading data before aborting handling of the response.
|
||||
*
|
||||
* @default 0
|
||||
*/
|
||||
readonly timeout?: number;
|
||||
}
|
||||
}
|
||||
|
||||
namespace toReadableStream {
|
||||
|
||||
type Item = string | Buffer;
|
||||
type Payload = Item | Item[];
|
||||
}
|
||||
|
||||
namespace parseCacheControl {
|
||||
|
||||
interface Parameters {
|
||||
|
||||
'max-age'?: number;
|
||||
[key: string]: string | number | undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
declare const client: Client;
|
||||
export = client;
|
||||
688
node_modules/@hapi/wreck/lib/index.js
generated
vendored
Executable file
688
node_modules/@hapi/wreck/lib/index.js
generated
vendored
Executable file
@@ -0,0 +1,688 @@
|
||||
'use strict';
|
||||
|
||||
const Events = require('events');
|
||||
const Http = require('http');
|
||||
const Https = require('https');
|
||||
const Stream = require('stream');
|
||||
const Url = require('url');
|
||||
const Zlib = require('zlib');
|
||||
|
||||
const Boom = require('@hapi/boom');
|
||||
const Bourne = require('@hapi/bourne');
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Payload = require('./payload');
|
||||
const Recorder = require('./recorder');
|
||||
const Tap = require('./tap');
|
||||
|
||||
|
||||
const internals = {
|
||||
jsonRegex: /^application\/([a-z0-9.]*[+-]json|json)$/,
|
||||
shallowOptions: ['agent', 'agents', 'beforeRedirect', 'payload', 'redirected'],
|
||||
httpOptions: ['secureProtocol', 'ciphers', 'lookup', 'family', 'hints']
|
||||
};
|
||||
|
||||
|
||||
// New instance is exported as module.exports
|
||||
|
||||
internals.Client = class {
|
||||
|
||||
constructor(options = {}) {
|
||||
|
||||
Hoek.assert(!options.agents || options.agents.https && options.agents.http && options.agents.httpsAllowUnauthorized, 'Option agents must include "http", "https", and "httpsAllowUnauthorized"');
|
||||
|
||||
this._defaults = Hoek.clone(options, { shallow: internals.shallowOptions });
|
||||
|
||||
this.agents = this._defaults.agents || {
|
||||
https: new Https.Agent({ maxSockets: Infinity }),
|
||||
http: new Http.Agent({ maxSockets: Infinity }),
|
||||
httpsAllowUnauthorized: new Https.Agent({ maxSockets: Infinity, rejectUnauthorized: false })
|
||||
};
|
||||
|
||||
if (this._defaults.events) {
|
||||
this.events = new Events.EventEmitter();
|
||||
}
|
||||
}
|
||||
|
||||
defaults(options) {
|
||||
|
||||
Hoek.assert(options && typeof options === 'object', 'options must be provided to defaults');
|
||||
|
||||
options = Hoek.applyToDefaults(this._defaults, options, { shallow: internals.shallowOptions });
|
||||
return new internals.Client(options);
|
||||
}
|
||||
|
||||
request(method, url, options = {}) {
|
||||
|
||||
try {
|
||||
options = Hoek.applyToDefaults(this._defaults, options, { shallow: internals.shallowOptions });
|
||||
|
||||
Hoek.assert(options.payload === undefined || typeof options.payload === 'string' || typeof options.payload === 'object', 'options.payload must be a string, a Buffer, a Stream, or an Object');
|
||||
Hoek.assert(internals.isNullOrUndefined(options.agent) || typeof options.rejectUnauthorized !== 'boolean', 'options.agent cannot be set to an Agent at the same time as options.rejectUnauthorized is set');
|
||||
Hoek.assert(internals.isNullOrUndefined(options.beforeRedirect) || typeof options.beforeRedirect === 'function', 'options.beforeRedirect must be a function');
|
||||
Hoek.assert(internals.isNullOrUndefined(options.redirected) || typeof options.redirected === 'function', 'options.redirected must be a function');
|
||||
Hoek.assert(options.gunzip === undefined || typeof options.gunzip === 'boolean' || options.gunzip === 'force', 'options.gunzip must be a boolean or "force"');
|
||||
}
|
||||
catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
if (options.baseUrl) {
|
||||
url = internals.resolveUrl(options.baseUrl, url);
|
||||
delete options.baseUrl;
|
||||
}
|
||||
|
||||
const relay = {};
|
||||
const req = this._request(method, url, options, relay);
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
|
||||
relay.callback = (err, res) => {
|
||||
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(res);
|
||||
return;
|
||||
};
|
||||
});
|
||||
|
||||
promise.req = req;
|
||||
return promise;
|
||||
}
|
||||
|
||||
_request(method, url, options, relay, _trace) {
|
||||
|
||||
const uri = {};
|
||||
if (options.socketPath) {
|
||||
uri.socketPath = options.socketPath;
|
||||
|
||||
const parsedUri = new Url.URL(url, `unix://${options.socketPath}`);
|
||||
internals.applyUrlToOptions(uri, {
|
||||
host: '', // host must be empty according to https://tools.ietf.org/html/rfc2616#section-14.23
|
||||
protocol: 'http:',
|
||||
hash: parsedUri.hash,
|
||||
search: parsedUri.search,
|
||||
searchParams: parsedUri.searchParams,
|
||||
pathname: parsedUri.pathname,
|
||||
href: parsedUri.href
|
||||
});
|
||||
}
|
||||
else {
|
||||
uri.setHost = false;
|
||||
const parsedUri = new Url.URL(url);
|
||||
internals.applyUrlToOptions(uri, parsedUri);
|
||||
}
|
||||
|
||||
uri.method = method.toUpperCase();
|
||||
uri.headers = Object.create(null);
|
||||
|
||||
const usedHeaders = new Set();
|
||||
if (options.headers) {
|
||||
for (const [key, value] of Object.entries(options.headers)) {
|
||||
if (value !== undefined) {
|
||||
uri.headers[key] = value;
|
||||
usedHeaders.add(key.toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!usedHeaders.has('host')) {
|
||||
uri.headers.host = uri.host;
|
||||
}
|
||||
|
||||
if (options.payload && typeof options.payload === 'object' && !(options.payload instanceof Stream) && !Buffer.isBuffer(options.payload)) {
|
||||
options.payload = JSON.stringify(options.payload);
|
||||
if (!usedHeaders.has('content-type')) {
|
||||
uri.headers['content-type'] = 'application/json';
|
||||
}
|
||||
}
|
||||
|
||||
if (options.gunzip &&
|
||||
!usedHeaders.has('accept-encoding')) {
|
||||
|
||||
uri.headers['accept-encoding'] = 'gzip';
|
||||
}
|
||||
|
||||
const payloadSupported = uri.method !== 'GET' && uri.method !== 'HEAD' && !internals.isNullOrUndefined(options.payload);
|
||||
if (payloadSupported &&
|
||||
(typeof options.payload === 'string' || Buffer.isBuffer(options.payload)) &&
|
||||
!usedHeaders.has('content-length')) {
|
||||
|
||||
uri.headers['content-length'] = Buffer.isBuffer(options.payload) ? options.payload.length : Buffer.byteLength(options.payload);
|
||||
}
|
||||
|
||||
let redirects = options.hasOwnProperty('redirects') ? options.redirects : false; // Needed to allow 0 as valid value when passed recursively
|
||||
|
||||
_trace = _trace ?? [];
|
||||
_trace.push({ method: uri.method, url });
|
||||
|
||||
const client = uri.protocol === 'https:' ? Https : Http;
|
||||
|
||||
for (const option of internals.httpOptions) {
|
||||
if (options[option] !== undefined) {
|
||||
uri[option] = options[option];
|
||||
}
|
||||
}
|
||||
|
||||
if (options.rejectUnauthorized !== undefined &&
|
||||
uri.protocol === 'https:') {
|
||||
|
||||
uri.agent = options.rejectUnauthorized ? this.agents.https : this.agents.httpsAllowUnauthorized;
|
||||
}
|
||||
else if (options.agent ||
|
||||
options.agent === false) {
|
||||
|
||||
uri.agent = options.agent;
|
||||
}
|
||||
else {
|
||||
uri.agent = uri.protocol === 'https:' ? this.agents.https : this.agents.http;
|
||||
}
|
||||
|
||||
this._emit('preRequest', uri, options);
|
||||
|
||||
const start = Date.now();
|
||||
const req = client.request(uri);
|
||||
|
||||
this._emit('request', req);
|
||||
|
||||
let shadow = null; // A copy of the streamed request payload when redirects are enabled
|
||||
let timeoutId;
|
||||
|
||||
const onError = (err) => {
|
||||
|
||||
err.trace = _trace;
|
||||
return finishOnce(Boom.badGateway('Client request error', err));
|
||||
};
|
||||
|
||||
const onAbort = () => {
|
||||
|
||||
if (!req.socket) {
|
||||
// Fake an ECONNRESET error on early abort
|
||||
|
||||
const error = new Error('socket hang up');
|
||||
error.code = 'ECONNRESET';
|
||||
finishOnce(error);
|
||||
}
|
||||
};
|
||||
|
||||
req.once('error', onError);
|
||||
|
||||
const onResponse = (res) => {
|
||||
|
||||
// Pass-through response
|
||||
|
||||
const statusCode = res.statusCode;
|
||||
const redirectMethod = internals.redirectMethod(statusCode, uri.method, options);
|
||||
|
||||
if (redirects === false ||
|
||||
!redirectMethod) {
|
||||
|
||||
return finishOnce(null, res);
|
||||
}
|
||||
|
||||
// Redirection
|
||||
|
||||
res.destroy();
|
||||
|
||||
if (redirects === 0) {
|
||||
return finishOnce(Boom.badGateway('Maximum redirections reached', _trace));
|
||||
}
|
||||
|
||||
let location = res.headers.location;
|
||||
if (!location) {
|
||||
return finishOnce(Boom.badGateway('Received redirection without location', _trace));
|
||||
}
|
||||
|
||||
if (!/^https?:/i.test(location)) {
|
||||
location = Url.resolve(uri.href, location);
|
||||
}
|
||||
|
||||
const redirectOptions = Hoek.clone(options, { shallow: internals.shallowOptions });
|
||||
redirectOptions.payload = shadow ?? options.payload; // shadow must be ready at this point if set
|
||||
redirectOptions.redirects = --redirects;
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
const elapsed = Date.now() - start;
|
||||
redirectOptions.timeout = (redirectOptions.timeout - elapsed).toString(); // stringify to not drop timeout when === 0
|
||||
}
|
||||
|
||||
// When redirecting to a new hostname, remove the authorization and cookie headers
|
||||
if (redirectOptions.headers) {
|
||||
const parsedLocation = new URL(location);
|
||||
if (uri.hostname !== parsedLocation.hostname) {
|
||||
for (const header of Object.keys(redirectOptions.headers)) {
|
||||
const lowerHeader = header.toLowerCase();
|
||||
if (lowerHeader === 'authorization' || lowerHeader === 'cookie') {
|
||||
delete redirectOptions.headers[header];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const followRedirect = (err) => {
|
||||
|
||||
if (err) {
|
||||
err.trace = _trace;
|
||||
return finishOnce(Boom.badGateway('Invalid redirect', err));
|
||||
}
|
||||
|
||||
const redirectReq = this._request(redirectMethod, location, redirectOptions, { callback: finishOnce }, _trace);
|
||||
if (options.redirected) {
|
||||
options.redirected(statusCode, location, redirectReq);
|
||||
}
|
||||
};
|
||||
|
||||
if (!options.beforeRedirect) {
|
||||
return followRedirect();
|
||||
}
|
||||
|
||||
return options.beforeRedirect(redirectMethod, statusCode, location, res.headers, redirectOptions, followRedirect);
|
||||
};
|
||||
|
||||
// Register handlers
|
||||
|
||||
const finish = (err, res) => {
|
||||
|
||||
if (err) {
|
||||
req.abort();
|
||||
}
|
||||
|
||||
req.removeListener('response', onResponse);
|
||||
req.removeListener('error', onError);
|
||||
req.removeListener('abort', onAbort);
|
||||
req.on('error', Hoek.ignore);
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
this._emit('response', err, { req, res, start, uri });
|
||||
|
||||
return relay.callback(err, res);
|
||||
};
|
||||
|
||||
const finishOnce = Hoek.once(finish);
|
||||
|
||||
req.once('response', onResponse);
|
||||
|
||||
if (options.timeout) {
|
||||
timeoutId = setTimeout(() => finishOnce(Boom.gatewayTimeout('Client request timeout')), options.timeout);
|
||||
}
|
||||
|
||||
req.on('abort', onAbort);
|
||||
|
||||
// Write payload
|
||||
|
||||
if (payloadSupported) {
|
||||
if (options.payload instanceof Stream) {
|
||||
let stream = options.payload;
|
||||
|
||||
if (redirects) {
|
||||
const collector = new Tap();
|
||||
collector.once('finish', () => {
|
||||
|
||||
shadow = collector.collect();
|
||||
});
|
||||
|
||||
stream = options.payload.pipe(collector);
|
||||
}
|
||||
|
||||
internals.deferPipeUntilSocketConnects(req, stream);
|
||||
return req;
|
||||
}
|
||||
|
||||
req.write(options.payload);
|
||||
}
|
||||
|
||||
// Finalize request
|
||||
|
||||
req.end();
|
||||
return req;
|
||||
}
|
||||
|
||||
_emit(...args) {
|
||||
|
||||
if (this.events) {
|
||||
this.events.emit(...args);
|
||||
}
|
||||
}
|
||||
|
||||
read(res, options = {}) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
this._read(res, options, (err, payload) => {
|
||||
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(payload);
|
||||
return;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_read(res, options, callback) {
|
||||
|
||||
options = Hoek.applyToDefaults(this._defaults, options, { shallow: internals.shallowOptions });
|
||||
|
||||
// Finish once
|
||||
|
||||
let clientTimeoutId = null;
|
||||
|
||||
const finish = (err, buffer) => {
|
||||
|
||||
clearTimeout(clientTimeoutId);
|
||||
reader.removeListener('error', onReaderError);
|
||||
reader.removeListener('finish', onReaderFinish);
|
||||
res.removeListener('error', onResError);
|
||||
res.removeListener('close', onResAborted);
|
||||
res.removeListener('aborted', onResAborted);
|
||||
res.on('error', Hoek.ignore);
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!options.json) {
|
||||
return callback(null, buffer);
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
|
||||
if (options.json === 'force') {
|
||||
return internals.tryParseBuffer(buffer, callback);
|
||||
}
|
||||
|
||||
// 'strict' or true
|
||||
|
||||
const contentType = res.headers?.['content-type'] ?? '';
|
||||
const mime = contentType.split(';')[0].trim().toLowerCase();
|
||||
|
||||
if (!internals.jsonRegex.test(mime)) {
|
||||
if (options.json === 'strict') {
|
||||
return callback(Boom.notAcceptable('The content-type is not JSON compatible'));
|
||||
}
|
||||
|
||||
return callback(null, buffer);
|
||||
}
|
||||
|
||||
return internals.tryParseBuffer(buffer, callback);
|
||||
};
|
||||
|
||||
const finishOnce = Hoek.once(finish);
|
||||
|
||||
const clientTimeout = options.timeout;
|
||||
if (clientTimeout &&
|
||||
clientTimeout > 0) {
|
||||
|
||||
clientTimeoutId = setTimeout(() => finishOnce(Boom.clientTimeout()), clientTimeout);
|
||||
}
|
||||
|
||||
// Hander errors
|
||||
|
||||
const onResError = (err) => {
|
||||
|
||||
return finishOnce(err.isBoom ? err : Boom.internal('Payload stream error', err));
|
||||
};
|
||||
|
||||
const onResAborted = () => {
|
||||
|
||||
if (!res.complete) {
|
||||
finishOnce(Boom.internal('Payload stream closed prematurely'));
|
||||
}
|
||||
};
|
||||
|
||||
res.once('error', onResError);
|
||||
res.once('close', onResAborted);
|
||||
res.once('aborted', onResAborted);
|
||||
|
||||
// Read payload
|
||||
|
||||
const reader = new Recorder({ maxBytes: options.maxBytes });
|
||||
|
||||
const onReaderError = (err) => {
|
||||
|
||||
if (res.destroy) { // GZip stream has no destroy() method
|
||||
res.destroy();
|
||||
}
|
||||
|
||||
return finishOnce(err);
|
||||
};
|
||||
|
||||
reader.once('error', onReaderError);
|
||||
|
||||
const onReaderFinish = () => {
|
||||
|
||||
return finishOnce(null, reader.collect());
|
||||
};
|
||||
|
||||
reader.once('finish', onReaderFinish);
|
||||
|
||||
if (options.gunzip) {
|
||||
const contentEncoding = options.gunzip === 'force' ?
|
||||
'gzip' :
|
||||
res.headers?.['content-encoding'] ?? '';
|
||||
|
||||
if (/^(x-)?gzip(\s*,\s*identity)?$/.test(contentEncoding)) {
|
||||
const gunzip = Zlib.createGunzip();
|
||||
gunzip.once('error', onReaderError);
|
||||
res.pipe(gunzip).pipe(reader);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
res.pipe(reader);
|
||||
}
|
||||
|
||||
toReadableStream(payload, encoding) {
|
||||
|
||||
return new Payload(payload, encoding);
|
||||
}
|
||||
|
||||
parseCacheControl(field) {
|
||||
|
||||
/*
|
||||
Cache-Control = 1#cache-directive
|
||||
cache-directive = token [ "=" ( token / quoted-string ) ]
|
||||
token = [^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+
|
||||
quoted-string = "(?:[^"\\]|\\.)*"
|
||||
*/
|
||||
|
||||
// 1: directive = 2: token 3: quoted-string
|
||||
const regex = /(?:^|(?:\s*\,\s*))([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\]|\\.)*)\")))?/g;
|
||||
|
||||
const header = {};
|
||||
const error = field.replace(regex, ($0, $1, $2, $3) => {
|
||||
|
||||
const value = $2 || $3;
|
||||
header[$1] = value ? value.toLowerCase() : true;
|
||||
return '';
|
||||
});
|
||||
|
||||
if (header['max-age']) {
|
||||
try {
|
||||
const maxAge = parseInt(header['max-age'], 10);
|
||||
if (isNaN(maxAge)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
header['max-age'] = maxAge;
|
||||
}
|
||||
catch (err) { }
|
||||
}
|
||||
|
||||
return error ? null : header;
|
||||
}
|
||||
|
||||
// Shortcuts
|
||||
|
||||
get(uri, options) {
|
||||
|
||||
return this._shortcut('GET', uri, options);
|
||||
}
|
||||
|
||||
post(uri, options) {
|
||||
|
||||
return this._shortcut('POST', uri, options);
|
||||
}
|
||||
|
||||
patch(uri, options) {
|
||||
|
||||
return this._shortcut('PATCH', uri, options);
|
||||
}
|
||||
|
||||
put(uri, options) {
|
||||
|
||||
return this._shortcut('PUT', uri, options);
|
||||
}
|
||||
|
||||
delete(uri, options) {
|
||||
|
||||
return this._shortcut('DELETE', uri, options);
|
||||
}
|
||||
|
||||
async _shortcut(method, uri, options = {}) {
|
||||
|
||||
const res = await this.request(method, uri, options);
|
||||
|
||||
let payload;
|
||||
try {
|
||||
payload = await this.read(res, options);
|
||||
}
|
||||
catch (err) {
|
||||
err.data = err.data ?? {};
|
||||
err.data.res = res;
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (res.statusCode < 400) {
|
||||
return { res, payload };
|
||||
}
|
||||
|
||||
// Response error
|
||||
|
||||
const data = {
|
||||
isResponseError: true,
|
||||
headers: res.headers,
|
||||
res,
|
||||
payload
|
||||
};
|
||||
|
||||
throw new Boom.Boom(`Response Error: ${res.statusCode} ${res.statusMessage}`, { statusCode: res.statusCode, data });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// baseUrl needs to end in a trailing / if it contains paths that need to be preserved
|
||||
|
||||
internals.resolveUrl = function (baseUrl, path) {
|
||||
|
||||
if (!path) {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
// Will default to path if it's not a relative URL
|
||||
const url = new Url.URL(path, baseUrl);
|
||||
return Url.format(url);
|
||||
};
|
||||
|
||||
|
||||
internals.deferPipeUntilSocketConnects = function (req, stream) {
|
||||
|
||||
const onSocket = (socket) => {
|
||||
|
||||
if (!socket.connecting) {
|
||||
return onSocketConnect();
|
||||
}
|
||||
|
||||
socket.once('connect', onSocketConnect);
|
||||
};
|
||||
|
||||
const onSocketConnect = () => {
|
||||
|
||||
stream.pipe(req);
|
||||
stream.removeListener('error', onStreamError);
|
||||
};
|
||||
|
||||
const onStreamError = (err) => {
|
||||
|
||||
req.emit('error', err);
|
||||
};
|
||||
|
||||
req.once('socket', onSocket);
|
||||
stream.on('error', onStreamError);
|
||||
};
|
||||
|
||||
|
||||
internals.redirectMethod = function (code, method, options) {
|
||||
|
||||
switch (code) {
|
||||
case 301:
|
||||
case 302:
|
||||
return options.redirectMethod || method;
|
||||
|
||||
case 303:
|
||||
if (options.redirect303) {
|
||||
return 'GET';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 307:
|
||||
case 308:
|
||||
return method;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
internals.tryParseBuffer = function (buffer, next) {
|
||||
|
||||
if (buffer.length === 0) {
|
||||
return next(null, null);
|
||||
}
|
||||
|
||||
let payload;
|
||||
try {
|
||||
payload = Bourne.parse(buffer.toString());
|
||||
}
|
||||
catch (err) {
|
||||
return next(Boom.badGateway(err.message, { payload: buffer }));
|
||||
}
|
||||
|
||||
return next(null, payload);
|
||||
};
|
||||
|
||||
|
||||
internals.applyUrlToOptions = (options, url) => {
|
||||
|
||||
options.host = url.host;
|
||||
options.origin = url.origin;
|
||||
options.searchParams = url.searchParams;
|
||||
options.protocol = url.protocol;
|
||||
options.hostname = typeof url.hostname === 'string' && url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname;
|
||||
options.hash = url.hash;
|
||||
options.search = url.search;
|
||||
options.pathname = url.pathname;
|
||||
options.path = `${url.pathname}${url.search}`;
|
||||
options.href = url.href;
|
||||
if (url.port !== '') {
|
||||
options.port = Number(url.port);
|
||||
}
|
||||
|
||||
if (url.username || url.password) {
|
||||
options.auth = `${url.username}:${url.password}`;
|
||||
options.username = url.username;
|
||||
options.password = url.password;
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
internals.isNullOrUndefined = (val) => [null, undefined].includes(val);
|
||||
|
||||
module.exports = new internals.Client();
|
||||
38
node_modules/@hapi/wreck/lib/payload.js
generated
vendored
Executable file
38
node_modules/@hapi/wreck/lib/payload.js
generated
vendored
Executable file
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
const Stream = require('stream');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = internals.Payload = class extends Stream.Readable {
|
||||
|
||||
constructor(payload, encoding) {
|
||||
|
||||
super();
|
||||
|
||||
const data = [].concat(payload || '');
|
||||
let size = 0;
|
||||
for (let i = 0; i < data.length; ++i) {
|
||||
const chunk = data[i];
|
||||
size = size + chunk.length;
|
||||
data[i] = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
||||
}
|
||||
|
||||
this._data = Buffer.concat(data, size);
|
||||
this._position = 0;
|
||||
this._encoding = encoding || 'utf8';
|
||||
}
|
||||
|
||||
_read(size) {
|
||||
|
||||
const chunk = this._data.slice(this._position, this._position + size);
|
||||
this.push(chunk, this._encoding);
|
||||
this._position = this._position + chunk.length;
|
||||
|
||||
if (this._position >= this._data.length) {
|
||||
this.push(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
40
node_modules/@hapi/wreck/lib/recorder.js
generated
vendored
Executable file
40
node_modules/@hapi/wreck/lib/recorder.js
generated
vendored
Executable file
@@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
const Stream = require('stream');
|
||||
|
||||
const Boom = require('@hapi/boom');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = internals.Recorder = class extends Stream.Writable {
|
||||
|
||||
constructor(options) {
|
||||
|
||||
super();
|
||||
|
||||
this.settings = options; // No need to clone since called internally with new object
|
||||
this.buffers = [];
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
_write(chunk, encoding, next) {
|
||||
|
||||
if (this.settings.maxBytes &&
|
||||
this.length + chunk.length > this.settings.maxBytes) {
|
||||
|
||||
return this.emit('error', Boom.entityTooLarge('Payload content length greater than maximum allowed: ' + this.settings.maxBytes));
|
||||
}
|
||||
|
||||
this.length = this.length + chunk.length;
|
||||
this.buffers.push(chunk);
|
||||
next();
|
||||
}
|
||||
|
||||
collect() {
|
||||
|
||||
const buffer = (this.buffers.length === 0 ? Buffer.alloc(0) : (this.buffers.length === 1 ? this.buffers[0] : Buffer.concat(this.buffers, this.length)));
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
29
node_modules/@hapi/wreck/lib/tap.js
generated
vendored
Executable file
29
node_modules/@hapi/wreck/lib/tap.js
generated
vendored
Executable file
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const Stream = require('stream');
|
||||
|
||||
const Payload = require('./payload');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = internals.Tap = class extends Stream.Transform {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this.buffers = [];
|
||||
}
|
||||
|
||||
_transform(chunk, encoding, next) {
|
||||
|
||||
this.buffers.push(chunk);
|
||||
next(null, chunk);
|
||||
}
|
||||
|
||||
collect() {
|
||||
|
||||
return new Payload(this.buffers);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user