urllib
Version:
Help in opening URLs (mostly HTTP) in a complex world — basic and digest authentication, redirections, timeout and more. Base undici API.
239 lines • 17.7 kB
JavaScript
import { AsyncLocalStorage } from 'node:async_hooks';
import { debuglog } from 'node:util';
import { fetch as UndiciFetch, Request, getGlobalDispatcher, } from 'undici';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import undiciSymbols from 'undici/lib/core/symbols.js';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { getResponseState } from 'undici/lib/web/fetch/response.js';
import { channels, } from './HttpClient.js';
import { HttpAgent, } from './HttpAgent.js';
import { initDiagnosticsChannel } from './diagnosticsChannel.js';
import { convertHeader, globalId, performanceTime, updateSocketInfo } from './utils.js';
import symbols from './symbols.js';
import { BaseAgent } from './BaseAgent.js';
const debug = debuglog('urllib/fetch');
export class FetchFactory {
static
setClientOptions(clientOptions) {
let dispatcherOption = {
opaqueLocalStorage: this.
};
let dispatcherClazz = BaseAgent;
if (clientOptions?.lookup || clientOptions?.checkAddress) {
dispatcherOption = {
...dispatcherOption,
lookup: clientOptions.lookup,
checkAddress: clientOptions.checkAddress,
connect: clientOptions.connect,
allowH2: clientOptions.allowH2,
};
dispatcherClazz = HttpAgent;
}
else if (clientOptions?.connect) {
dispatcherOption = {
...dispatcherOption,
connect: clientOptions.connect,
allowH2: clientOptions.allowH2,
};
dispatcherClazz = BaseAgent;
}
else if (clientOptions?.allowH2) {
// Support HTTP2
dispatcherOption = {
...dispatcherOption,
allowH2: clientOptions.allowH2,
};
dispatcherClazz = BaseAgent;
}
this.
initDiagnosticsChannel();
}
getDispatcher() {
return this.
}
setDispatcher(dispatcher) {
this.
}
getDispatcherPoolStats() {
const agent = this.getDispatcher();
// origin => Pool Instance
const clients = Reflect.get(agent, undiciSymbols.kClients);
const poolStatsMap = {};
if (!clients) {
return poolStatsMap;
}
for (const [key, ref] of clients) {
const pool = (typeof ref.deref === 'function' ? ref.deref() : ref);
// NOTE: pool become to { dispatcher: Pool } in undici@v7
const stats = pool?.stats ?? pool?.dispatcher?.stats;
if (!stats)
continue;
poolStatsMap[key] = {
connected: stats.connected,
free: stats.free,
pending: stats.pending,
queued: stats.queued,
running: stats.running,
size: stats.size,
};
}
return poolStatsMap;
}
static setClientOptions(clientOptions) {
FetchFactory.
}
static getDispatcherPoolStats() {
return FetchFactory.
}
async fetch(input, init) {
const requestStartTime = performance.now();
init = init ?? {};
init.dispatcher = init.dispatcher ?? this.
const request = new Request(input, init);
const requestId = globalId('HttpClientRequest');
// https://developer.chrome.com/docs/devtools/network/reference/?utm_source=devtools#timing-explanation
const timing = {
// socket assigned
queuing: 0,
// dns lookup time
dnslookup: 0,
// socket connected
connected: 0,
// request headers sent
requestHeadersSent: 0,
// request sent, including headers and body
requestSent: 0,
// Time to first byte (TTFB), the response headers have been received
waiting: 0,
// the response body and trailers have been received
contentDownload: 0,
};
// using opaque to diagnostics channel, binding request and socket
const internalOpaque = {
[]: requestId,
[]: requestStartTime,
[]: !!(init.timing ?? true),
[]: timing,
// [symbols.kRequestOriginalOpaque]: originalOpaque,
};
const reqMeta = {
requestId,
url: request.url,
args: {
method: request.method,
type: request.method,
data: request.body,
headers: convertHeader(request.headers),
},
retries: 0,
};
const fetchMeta = {
requestId,
request,
};
const socketInfo = {
id: 0,
localAddress: '',
localPort: 0,
remoteAddress: '',
remotePort: 0,
remoteFamily: '',
bytesWritten: 0,
bytesRead: 0,
handledRequests: 0,
handledResponses: 0,
};
channels.request.publish({
request: reqMeta,
isSentByFetch: true,
fetchOpaque: internalOpaque,
});
channels.fetchRequest.publish({
fetch: fetchMeta,
fetchOpaque: internalOpaque,
});
let res;
// keep urllib createCallbackResponse style
const resHeaders = {};
const urllibResponse = {
status: -1,
statusCode: -1,
statusText: '',
statusMessage: '',
headers: resHeaders,
size: 0,
aborted: false,
rt: 0,
keepAliveSocket: true,
requestUrls: [
request.url,
],
timing,
socket: socketInfo,
retries: 0,
socketErrorRetries: 0,
};
try {
await this.
res = await UndiciFetch(request);
});
}
catch (e) {
updateSocketInfo(socketInfo, internalOpaque, e);
urllibResponse.rt = performanceTime(requestStartTime);
debug('Request#%d throw error: %s', requestId, e);
channels.fetchResponse.publish({
fetch: fetchMeta,
error: e,
fetchOpaque: internalOpaque,
});
channels.response.publish({
request: reqMeta,
response: urllibResponse,
error: e,
isSentByFetch: true,
fetchOpaque: internalOpaque,
});
throw e;
}
// get undici internal response
const state = getResponseState(res);
updateSocketInfo(socketInfo, internalOpaque);
urllibResponse.headers = convertHeader(res.headers);
urllibResponse.status = urllibResponse.statusCode = res.status;
urllibResponse.statusMessage = res.statusText;
if (urllibResponse.headers['content-length']) {
urllibResponse.size = parseInt(urllibResponse.headers['content-length']);
}
urllibResponse.rt = performanceTime(requestStartTime);
debug('Request#%d got response, status: %s, headers: %j, timing: %j, socket: %j', requestId, urllibResponse.status, urllibResponse.headers, timing, urllibResponse.socket);
channels.fetchResponse.publish({
fetch: fetchMeta,
timingInfo: state.timingInfo,
response: res,
fetchOpaque: internalOpaque,
});
channels.response.publish({
request: reqMeta,
response: urllibResponse,
isSentByFetch: true,
fetchOpaque: internalOpaque,
});
return res;
}
static getDispatcher() {
return FetchFactory.
}
static setDispatcher(dispatcher) {
FetchFactory.
}
static async fetch(input, init) {
return FetchFactory.
}
}
export const fetch = FetchFactory.fetch;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmV0Y2guanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmV0Y2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDckQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLEVBQ0wsS0FBSyxJQUFJLFdBQVcsRUFHcEIsT0FBTyxFQUdQLG1CQUFtQixHQUdwQixNQUFNLFFBQVEsQ0FBQztBQUNoQiw2REFBNkQ7QUFDN0QsYUFBYTtBQUNiLE9BQU8sYUFBYSxNQUFNLDRCQUE0QixDQUFDO0FBQ3ZELDZEQUE2RDtBQUM3RCxhQUFhO0FBQ2IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDcEUsT0FBTyxFQUNMLFFBQVEsR0FNVCxNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFDTCxTQUFTLEdBRVYsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxlQUFlLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDeEYsT0FBTyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBU25DLE9BQU8sRUFBRSxTQUFTLEVBQW9CLE1BQU0sZ0JBQWdCLENBQUM7QUFFN0QsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0FBb0J2QyxNQUFNLE9BQU8sWUFBWTtJQUN2QixXQUFXLENBQWlDO0lBQzVDLG1CQUFtQixHQUFHLElBQUksaUJBQWlCLEVBQWUsQ0FBQztJQUUzRCxNQUFNLENBQUMsU0FBUyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7SUFFdEMsZ0JBQWdCLENBQUMsYUFBNEI7UUFDM0MsSUFBSSxnQkFBZ0IsR0FBcUI7WUFDdkMsa0JBQWtCLEVB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