urllib 4.3.1 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/utils.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { randomBytes, createHash } from 'node:crypto';
2
2
  import { Readable } from 'node:stream';
3
3
  import { performance } from 'node:perf_hooks';
4
+ import symbols from './symbols.js';
4
5
  const JSONCtlCharsMap = {
5
6
  '"': '\\"', // \u0022
6
7
  '\\': '\\\\', // \u005c
@@ -139,4 +140,54 @@ export function isReadable(stream) {
139
140
  && typeof stream._read === 'function'
140
141
  && typeof stream._readableState === 'object';
141
142
  }
142
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDdEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN2QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFHOUMsTUFBTSxlQUFlLEdBQTJCO0lBQzlDLEdBQUcsRUFBRSxLQUFLLEVBQUUsU0FBUztJQUNyQixJQUFJLEVBQUUsTUFBTSxFQUFFLFNBQVM7SUFDdkIsSUFBSSxFQUFFLEtBQUssRUFBRSxTQUFTO0lBQ3RCLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUztJQUN0QixJQUFJLEVBQUUsS0FBSyxFQUFFLFNBQVM7SUFDdEIsSUFBSSxFQUFFLEtBQUssRUFBRSxTQUFTO0lBQ3RCLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUztDQUN2QixDQUFDO0FBQ0YsbUNBQW1DO0FBQ25DLE1BQU0sY0FBYyxHQUFHLHdCQUF3QixDQUFDO0FBRWhELFNBQVMsY0FBYyxDQUFDLENBQVM7SUFDL0IsT0FBTyxlQUFlLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsR0FBRyxPQUFPLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzdGLENBQUM7QUFFRCxTQUFTLG1CQUFtQixDQUFDLEtBQWE7SUFDeEMsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBRSxjQUFjLENBQUMsQ0FBQztBQUN2RCxDQUFDO0FBRUQsTUFBTSxVQUFVLFNBQVMsQ0FBQyxJQUFZLEVBQUUsZUFBaUM7SUFDdkUsSUFBSSxPQUFPLGVBQWUsS0FBSyxVQUFVLEVBQUUsQ0FBQztRQUMx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
143
+ export function updateSocketInfo(socketInfo, internalOpaque, err) {
144
+ const socket = internalOpaque[symbols.kRequestSocket] ?? err?.[symbols.kErrorSocket];
145
+ if (socket) {
146
+ socketInfo.id = socket[symbols.kSocketId];
147
+ socketInfo.handledRequests = socket[symbols.kHandledRequests];
148
+ socketInfo.handledResponses = socket[symbols.kHandledResponses];
149
+ if (socket[symbols.kSocketLocalAddress]) {
150
+ socketInfo.localAddress = socket[symbols.kSocketLocalAddress];
151
+ socketInfo.localPort = socket[symbols.kSocketLocalPort];
152
+ }
153
+ if (socket.remoteAddress) {
154
+ socketInfo.remoteAddress = socket.remoteAddress;
155
+ socketInfo.remotePort = socket.remotePort;
156
+ socketInfo.remoteFamily = socket.remoteFamily;
157
+ }
158
+ socketInfo.bytesRead = socket.bytesRead;
159
+ socketInfo.bytesWritten = socket.bytesWritten;
160
+ if (socket[symbols.kSocketConnectErrorTime]) {
161
+ socketInfo.connectErrorTime = socket[symbols.kSocketConnectErrorTime];
162
+ if (Array.isArray(socket.autoSelectFamilyAttemptedAddresses)) {
163
+ socketInfo.attemptedRemoteAddresses = socket.autoSelectFamilyAttemptedAddresses;
164
+ }
165
+ socketInfo.connectProtocol = socket[symbols.kSocketConnectProtocol];
166
+ socketInfo.connectHost = socket[symbols.kSocketConnectHost];
167
+ socketInfo.connectPort = socket[symbols.kSocketConnectPort];
168
+ }
169
+ if (socket[symbols.kSocketConnectedTime]) {
170
+ socketInfo.connectedTime = socket[symbols.kSocketConnectedTime];
171
+ }
172
+ if (socket[symbols.kSocketRequestEndTime]) {
173
+ socketInfo.lastRequestEndTime = socket[symbols.kSocketRequestEndTime];
174
+ }
175
+ socket[symbols.kSocketRequestEndTime] = new Date();
176
+ }
177
+ }
178
+ export function convertHeader(headers) {
179
+ const res = {};
180
+ for (const [key, value] of headers.entries()) {
181
+ if (res[key]) {
182
+ if (!Array.isArray(res[key])) {
183
+ res[key] = [res[key]];
184
+ }
185
+ res[key].push(value);
186
+ }
187
+ else {
188
+ res[key] = value;
189
+ }
190
+ }
191
+ return res;
192
+ }
193
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDdEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN2QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFHOUMsT0FBTyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBR25DLE1BQU0sZUFBZSxHQUEyQjtJQUM5QyxHQUFHLEVBQUUsS0FBSyxFQUFFLFNBQVM7SUFDckIsSUFBSSxFQUFFLE1BQU0sRUFBRSxTQUFTO0lBQ3ZCLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUztJQUN0QixJQUFJLEVBQUUsS0FBSyxFQUFFLFNBQVM7SUFDdEIsSUFBSSxFQUFFLEtBQUssRUFBRSxTQUFTO0lBQ3RCLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUztJQUN0QixJQUFJLEVBQUUsS0FBSyxFQUFFLFNBQVM7Q0FDdkIsQ0FBQztBQUNGLG1DQUFtQztBQUNuQyxNQUFNLGNBQWMsR0FBRyx3QkFBd0IsQ0FBQztBQUVoRCxTQUFTLGNBQWMsQ0FBQyxDQUFTO0lBQy9CLE9BQU8sZUFBZSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUcsT0FBTyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUM3RixDQUFDO0FBRUQsU0FBUyxtQkFBbUIsQ0FBQyxLQUFhO0lBQ3hDLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQUUsY0FBYyxDQUFDLENBQUM7QUFDdkQsQ0FBQztBQUVELE1BQU0sVUFBVSxTQUFTLENBQUMsSUFBWSxFQUFFLGVBQWlDO0lBQ3ZFLElBQUksT0FBTyxlQUFlLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDMUMsSUFBSSxHQUFHLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMvQixDQUFDO1NBQU0sSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUMzQixpREFBaUQ7UUFDakQsd0RBQXdEO1FBQ3hELElBQUksR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBQ0QsSUFBSSxDQUFDO1FBQ0gsSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUFDLE9BQU8sR0FBUSxFQUFFLENBQUM7UUFDbEIsSUFBSSxHQUFHLENBQUMsSUFBSSxLQUFLLGFBQWEsRUFBRSxDQUFDO1lBQy9CLEdBQUcsQ0FBQyxJQUFJLEdBQUcseUJBQXlCLENBQUM7UUFDdkMsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLEVBQUUsQ0FBQztZQUN2QiwrQkFBK0I7WUFDL0IsR0FBRyxDQUFDLE9BQU8sSUFBSSxzQkFBc0I7Z0JBQ25DLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxjQUFjLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUM7UUFDOUcsQ0FBQzthQUFNLENBQUM7WUFDTixHQUFHLENBQUMsT0FBTyxJQUFJLHNCQUFzQixHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEdBQUcsR0FBRyxDQUFDO1FBQ3JFLENBQUM7UUFDRCxNQUFNLEdBQUcsQ0FBQztJQUNaLENBQUM7SUFDRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRCxTQUFTLEdBQUcsQ0FBQyxDQUFTO0lBQ3BCLE1BQU0sR0FBRyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM5QixHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUN0QixPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDM0IsQ0FBQztBQUVELE1BQU0saUJBQWlCLEdBQUcsZ0NBQWdDLENBQUM7QUFDM0QsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQ1gsTUFBTSxNQUFNLEdBQUcsVUFBVSxDQUFDO0FBRTFCLE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxNQUFjLEVBQUUsR0FBVyxFQUFFLGVBQXVCLEVBQUUsUUFBZ0I7SUFDckcsdURBQXVEO0lBQ3ZELDZDQUE2QztJQUM3QyxvRUFBb0U7SUFDcEUsa0VBQWtFO0lBQ2xFLDJDQUEyQztJQUMzQyxpREFBaUQ7SUFDakQsaUVBQWlFO0lBQ2pFLDRDQUE0QztJQUM1QywrQkFBK0I7SUFDL0Isa0NBQWtDO0lBQ2xDLHdDQUF3QztJQUN4QyxrRUFBa0U7SUFDbEUsK0RBQStEO0lBQy9ELDBEQUEwRDtJQUMxRCwwQ0FBMEM7SUFDMUMsRUFBRTtJQUNGLHNDQUFzQztJQUN0QywwQ0FBMEM7SUFDMUMsRUFBRTtJQUNGLHVEQUF1RDtJQUN2RCx5REFBeUQ7SUFDekQsNkNBQTZDO0lBQzdDLHdEQUF3RDtJQUN4RCwrQ0FBK0M7SUFDL0MsTUFBTSxLQUFLLEdBQUcsZUFBZSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN6QyxNQUFNLElBQUksR0FBMkIsRUFBRSxDQUFDO0lBQ3hDLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7UUFDekIsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ3hDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDTixJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDekMsQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMvQixPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRCxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQztJQUN6QixNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3BDLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzFDLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBRTNDLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3RCLEVBQUUsR0FBRyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDO0lBQzNDLE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFOUMsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsSUFBSSxJQUFJLElBQUksQ0FBQyxLQUFLLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNqRCxNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsV0FBVyxFQUFFLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQztJQUNsRCxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDL0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNSLEdBQUcsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3hCLENBQUMsSUFBSSxJQUFJLEVBQUUsSUFBSSxNQUFNLElBQUksR0FBRyxFQUFFLENBQUM7SUFDakMsQ0FBQztJQUNELENBQUMsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQ2YsTUFBTSxRQUFRLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLElBQUksVUFBVSxHQUFHLG9CQUFvQixJQUFJLGFBQWEsSUFBSSxDQUFDLEtBQUssYUFBYSxJQUFJLENBQUMsS0FBSyxXQUFXLEdBQUcsZ0JBQWdCLFFBQVEsR0FBRyxDQUFDO0lBQ2pJLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ2hCLFVBQVUsSUFBSSxhQUFhLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQztJQUM1QyxDQUFDO0lBQ0QsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNSLFVBQVUsSUFBSSxTQUFTLEdBQUcsUUFBUSxFQUFFLGFBQWEsTUFBTSxHQUFHLENBQUM7SUFDN0QsQ0FBQztJQUNELE9BQU8sVUFBVSxDQUFDO0FBQ3BCLENBQUM7QUFFRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUM7QUFDMUMsTUFBTSxTQUFTLEdBQTJCLEVBQUUsQ0FBQztBQUU3QyxNQUFNLFVBQVUsUUFBUSxDQUFDLFFBQWdCO0lBQ3ZDLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ2hFLFNBQVMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUNELE9BQU8sRUFBRSxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDL0IsQ0FBQztBQUVELE1BQU0sVUFBVSxlQUFlLENBQUMsU0FBaUIsRUFBRSxHQUFZO0lBQzdELE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLFdBQVcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQztBQUM1RSxDQUFDO0FBRUQsTUFBTSxVQUFVLFVBQVUsQ0FBQyxNQUFXO0lBQ3BDLElBQUksT0FBTyxRQUFRLENBQUMsVUFBVSxLQUFLLFVBQVU7UUFBRSxPQUFPLFFBQVEsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDbEYsa0JBQWtCO0lBQ2xCLGtIQUFrSDtJQUNsSCwwRUFBMEU7SUFDMUUsT0FBTyxNQUFNLEtBQUssSUFBSTtXQUNqQixPQUFPLE1BQU0sS0FBSyxRQUFRO1dBQzFCLE9BQU8sTUFBTSxDQUFDLElBQUksS0FBSyxVQUFVO1dBQ2pDLE1BQU0sQ0FBQyxRQUFRLEtBQUssS0FBSztXQUN6QixPQUFPLE1BQU0sQ0FBQyxLQUFLLEtBQUssVUFBVTtXQUNsQyxPQUFPLE1BQU0sQ0FBQyxjQUFjLEtBQUssUUFBUSxDQUFDO0FBQ2pELENBQUM7QUFFRCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsVUFBc0IsRUFBRSxjQUFtQixFQUFFLEdBQVM7SUFDckYsTUFBTSxNQUFNLEdBQUcsY0FBYyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDckYsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUNYLFVBQVUsQ0FBQyxFQUFFLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMxQyxVQUFVLENBQUMsZUFBZSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUM5RCxVQUFVLENBQUMsZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ2hFLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUM7WUFDeEMsVUFBVSxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDOUQsVUFBVSxDQUFDLFNBQVMsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDMUQsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3pCLFVBQVUsQ0FBQyxhQUFhLEdBQUcsTUFBTSxDQUFDLGFBQWEsQ0FBQztZQUNoRCxVQUFVLENBQUMsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUM7WUFDMUMsVUFBVSxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDO1FBQ2hELENBQUM7UUFDRCxVQUFVLENBQUMsU0FBUyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUM7UUFDeEMsVUFBVSxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDO1FBQzlDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyx1QkFBdUIsQ0FBQyxFQUFFLENBQUM7WUFDNUMsVUFBVSxDQUFDLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsdUJBQXVCLENBQUMsQ0FBQztZQUN0RSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLGtDQUFrQyxDQUFDLEVBQUUsQ0FBQztnQkFDN0QsVUFBVSxDQUFDLHdCQUF3QixHQUFHLE1BQU0sQ0FBQyxrQ0FBa0MsQ0FBQztZQUNsRixDQUFDO1lBQ0QsVUFBVSxDQUFDLGVBQWUsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLHNCQUFzQixDQUFDLENBQUM7WUFDcEUsVUFBVSxDQUFDLFdBQVcsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLGtCQUFrQixDQUFDLENBQUM7WUFDNUQsVUFBVSxDQUFDLFdBQVcsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxFQUFFLENBQUM7WUFDekMsVUFBVSxDQUFDLGFBQWEsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDbEUsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLENBQUM7WUFDMUMsVUFBVSxDQUFDLGtCQUFrQixHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUN4RSxDQUFDO1FBQ0QsTUFBTSxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7SUFDckQsQ0FBQztBQUNILENBQUM7QUFFRCxNQUFNLFVBQVUsYUFBYSxDQUFDLE9BQWdCO0lBQzVDLE1BQU0sR0FBRyxHQUF3QixFQUFFLENBQUM7SUFDcEMsS0FBSyxNQUFNLENBQUUsR0FBRyxFQUFFLEtBQUssQ0FBRSxJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1FBQy9DLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDYixJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUM3QixHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBRSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUUsQ0FBQztZQUMxQixDQUFDO1lBQ0QsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2QixDQUFDO2FBQU0sQ0FBQztZQUNOLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUM7UUFDbkIsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUMifQ==
package/dist/package.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "name": "urllib",
3
- "version": "4.3.1"
3
+ "version": "4.4.0"
4
4
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "urllib",
3
- "version": "4.3.1",
3
+ "version": "4.4.0",
4
4
  "publishConfig": {
5
5
  "tag": "latest"
6
6
  },
@@ -0,0 +1,41 @@
1
+ // const { AsyncLocalStorage } = require('node:async_hooks');
2
+ import { AsyncLocalStorage } from 'node:async_hooks';
3
+ import symbols from './symbols.js';
4
+ import { Dispatcher } from 'undici';
5
+
6
+ // const RedirectHandler = require('../handler/redirect-handler')
7
+
8
+ export interface FetchOpaque {
9
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
10
+ // @ts-ignore
11
+ [symbols.kRequestId]: number;
12
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
13
+ // @ts-ignore
14
+ [symbols.kRequestStartTime]: number;
15
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
16
+ // @ts-ignore
17
+ [symbols.kEnableRequestTiming]: number;
18
+ }
19
+
20
+ // const internalOpaque = {
21
+ // [symbols.kRequestId]: requestId,
22
+ // [symbols.kRequestStartTime]: requestStartTime,
23
+ // [symbols.kEnableRequestTiming]: !!(init.timing ?? true),
24
+ // [symbols.kRequestTiming]: timing,
25
+ // // [symbols.kRequestOriginalOpaque]: originalOpaque,
26
+ // };
27
+
28
+ export interface OpaqueInterceptorOptions {
29
+ opaqueLocalStorage: AsyncLocalStorage<FetchOpaque>;
30
+ }
31
+
32
+ export function fetchOpaqueInterceptor(opts: OpaqueInterceptorOptions) {
33
+ const opaqueLocalStorage = opts?.opaqueLocalStorage;
34
+ return (dispatch: Dispatcher['dispatch']): Dispatcher['dispatch'] => {
35
+ return function redirectInterceptor(opts: Dispatcher.DispatchOptions, handler: Dispatcher.DispatchHandlers) {
36
+ const opaque = opaqueLocalStorage?.getStore();
37
+ (handler as any).opaque = opaque;
38
+ return dispatch(opts, handler);
39
+ };
40
+ };
41
+ }
package/src/HttpAgent.ts CHANGED
@@ -8,12 +8,12 @@ import {
8
8
 
9
9
  export type CheckAddressFunction = (ip: string, family: number | string, hostname: string) => boolean;
10
10
 
11
- export type HttpAgentOptions = {
11
+ export interface HttpAgentOptions extends Agent.Options {
12
12
  lookup?: LookupFunction;
13
13
  checkAddress?: CheckAddressFunction;
14
14
  connect?: buildConnector.BuildOptions,
15
15
  allowH2?: boolean;
16
- };
16
+ }
17
17
 
18
18
  class IllegalAddressError extends Error {
19
19
  hostname: string;
@@ -36,9 +36,10 @@ export class HttpAgent extends Agent {
36
36
 
37
37
  constructor(options: HttpAgentOptions) {
38
38
  /* eslint node/prefer-promises/dns: off*/
39
- const _lookup = options.lookup ?? dns.lookup;
40
- const lookup: LookupFunction = (hostname, dnsOptions, callback) => {
41
- _lookup(hostname, dnsOptions, (err, ...args: any[]) => {
39
+ const { lookup = dns.lookup, ...baseOpts } = options;
40
+
41
+ const lookupFunction: LookupFunction = (hostname, dnsOptions, callback) => {
42
+ lookup(hostname, dnsOptions, (err, ...args: any[]) => {
42
43
  // address will be array on Node.js >= 20
43
44
  const address = args[0];
44
45
  const family = args[1];
@@ -63,7 +64,8 @@ export class HttpAgent extends Agent {
63
64
  });
64
65
  };
65
66
  super({
66
- connect: { ...options.connect, lookup, allowH2: options.allowH2 },
67
+ ...baseOpts,
68
+ connect: { ...options.connect, lookup: lookupFunction, allowH2: options.allowH2 },
67
69
  });
68
70
  this.#checkAddress = options.checkAddress;
69
71
  }
package/src/HttpClient.ts CHANGED
@@ -37,7 +37,7 @@ import { HttpAgent, CheckAddressFunction } from './HttpAgent.js';
37
37
  import type { IncomingHttpHeaders } from './IncomingHttpHeaders.js';
38
38
  import { RequestURL, RequestOptions, HttpMethod, RequestMeta } from './Request.js';
39
39
  import { RawResponseWithMeta, HttpClientResponse, SocketInfo } from './Response.js';
40
- import { parseJSON, digestAuthHeader, globalId, performanceTime, isReadable } from './utils.js';
40
+ import { parseJSON, digestAuthHeader, globalId, performanceTime, isReadable, updateSocketInfo } from './utils.js';
41
41
  import symbols from './symbols.js';
42
42
  import { initDiagnosticsChannel } from './diagnosticsChannel.js';
43
43
  import { HttpClientConnectTimeoutError, HttpClientRequestTimeoutError } from './HttpClientError.js';
@@ -47,7 +47,28 @@ type UndiciRequestOption = Exists<Parameters<typeof undiciRequest>[1]>;
47
47
  type PropertyShouldBe<T, K extends keyof T, V> = Omit<T, K> & { [P in K]: V };
48
48
  type IUndiciRequestOption = PropertyShouldBe<UndiciRequestOption, 'headers', IncomingHttpHeaders>;
49
49
 
50
- const PROTO_RE = /^https?:\/\//i;
50
+ export const PROTO_RE = /^https?:\/\//i;
51
+
52
+ export interface UnidiciTimingInfo {
53
+ startTime: number;
54
+ redirectStartTime: number;
55
+ redirectEndTime: number;
56
+ postRedirectStartTime: number;
57
+ finalServiceWorkerStartTime: number;
58
+ finalNetworkResponseStartTime: number;
59
+ finalNetworkRequestStartTime: number;
60
+ endTime: number;
61
+ encodedBodySize: number;
62
+ decodedBodySize: number;
63
+ finalConnectionTimingInfo: {
64
+ domainLookupStartTime: number;
65
+ domainLookupEndTime: number;
66
+ connectionStartTime: number;
67
+ connectionEndTime: number;
68
+ secureConnectionStartTime: number;
69
+ // ALPNNegotiatedProtocol: undefined
70
+ };
71
+ }
51
72
 
52
73
  function noop() {
53
74
  // noop
@@ -137,9 +158,11 @@ export type RequestContext = {
137
158
  requestStartTime?: number;
138
159
  };
139
160
 
140
- const channels = {
161
+ export const channels = {
141
162
  request: diagnosticsChannel.channel('urllib:request'),
142
163
  response: diagnosticsChannel.channel('urllib:response'),
164
+ fetchRequest: diagnosticsChannel.channel('urllib:fetch:request'),
165
+ fetchResponse: diagnosticsChannel.channel('urllib:fetch:response'),
143
166
  };
144
167
 
145
168
  export type RequestDiagnosticsMessage = {
@@ -631,7 +654,7 @@ export class HttpClient extends EventEmitter {
631
654
  }
632
655
  res.rt = performanceTime(requestStartTime);
633
656
  // get real socket info from internalOpaque
634
- this.#updateSocketInfo(socketInfo, internalOpaque);
657
+ updateSocketInfo(socketInfo, internalOpaque);
635
658
 
636
659
  const clientResponse: HttpClientResponse = {
637
660
  opaque: originalOpaque,
@@ -707,7 +730,7 @@ export class HttpClient extends EventEmitter {
707
730
  res.requestUrls.push(requestUrl.href);
708
731
  }
709
732
  res.rt = performanceTime(requestStartTime);
710
- this.#updateSocketInfo(socketInfo, internalOpaque, rawError);
733
+ updateSocketInfo(socketInfo, internalOpaque, rawError);
711
734
 
712
735
  channels.response.publish({
713
736
  request: reqMeta,
@@ -729,40 +752,4 @@ export class HttpClient extends EventEmitter {
729
752
  throw err;
730
753
  }
731
754
  }
732
-
733
- #updateSocketInfo(socketInfo: SocketInfo, internalOpaque: any, err?: any) {
734
- const socket = internalOpaque[symbols.kRequestSocket] ?? err?.[symbols.kErrorSocket];
735
- if (socket) {
736
- socketInfo.id = socket[symbols.kSocketId];
737
- socketInfo.handledRequests = socket[symbols.kHandledRequests];
738
- socketInfo.handledResponses = socket[symbols.kHandledResponses];
739
- if (socket[symbols.kSocketLocalAddress]) {
740
- socketInfo.localAddress = socket[symbols.kSocketLocalAddress];
741
- socketInfo.localPort = socket[symbols.kSocketLocalPort];
742
- }
743
- if (socket.remoteAddress) {
744
- socketInfo.remoteAddress = socket.remoteAddress;
745
- socketInfo.remotePort = socket.remotePort;
746
- socketInfo.remoteFamily = socket.remoteFamily;
747
- }
748
- socketInfo.bytesRead = socket.bytesRead;
749
- socketInfo.bytesWritten = socket.bytesWritten;
750
- if (socket[symbols.kSocketConnectErrorTime]) {
751
- socketInfo.connectErrorTime = socket[symbols.kSocketConnectErrorTime];
752
- if (Array.isArray(socket.autoSelectFamilyAttemptedAddresses)) {
753
- socketInfo.attemptedRemoteAddresses = socket.autoSelectFamilyAttemptedAddresses;
754
- }
755
- socketInfo.connectProtocol = socket[symbols.kSocketConnectProtocol];
756
- socketInfo.connectHost = socket[symbols.kSocketConnectHost];
757
- socketInfo.connectPort = socket[symbols.kSocketConnectPort];
758
- }
759
- if (socket[symbols.kSocketConnectedTime]) {
760
- socketInfo.connectedTime = socket[symbols.kSocketConnectedTime];
761
- }
762
- if (socket[symbols.kSocketRequestEndTime]) {
763
- socketInfo.lastRequestEndTime = socket[symbols.kSocketRequestEndTime];
764
- }
765
- socket[symbols.kSocketRequestEndTime] = new Date();
766
- }
767
- }
768
755
  }
package/src/Request.ts CHANGED
@@ -3,6 +3,7 @@ import type { EventEmitter } from 'node:events';
3
3
  import type { Dispatcher } from 'undici';
4
4
  import type { IncomingHttpHeaders } from './IncomingHttpHeaders.js';
5
5
  import type { HttpClientResponse } from './Response.js';
6
+ import { Request } from 'undici';
6
7
 
7
8
  export type HttpMethod = Dispatcher.HttpMethod;
8
9
 
@@ -161,3 +162,8 @@ export type RequestMeta = {
161
162
  ctx?: unknown;
162
163
  retries: number;
163
164
  };
165
+
166
+ export type FetchMeta = {
167
+ requestId: number;
168
+ request: Request,
169
+ };
package/src/fetch.ts ADDED
@@ -0,0 +1,264 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import {
3
+ fetch as UndiciFetch,
4
+ RequestInfo,
5
+ RequestInit,
6
+ Request,
7
+ Response,
8
+ Agent,
9
+ getGlobalDispatcher,
10
+ Pool,
11
+ Dispatcher,
12
+ } from 'undici';
13
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
14
+ // @ts-ignore
15
+ import undiciSymbols from 'undici/lib/core/symbols.js';
16
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
17
+ // @ts-ignore
18
+ import undiciFetchSymbols from 'undici/lib/web/fetch/symbols.js';
19
+ import {
20
+ channels,
21
+ ClientOptions,
22
+ PoolStat,
23
+ RequestDiagnosticsMessage,
24
+ ResponseDiagnosticsMessage,
25
+ UnidiciTimingInfo,
26
+ } from './HttpClient.js';
27
+ import {
28
+ HttpAgent,
29
+ HttpAgentOptions,
30
+ } from './HttpAgent.js';
31
+ import { initDiagnosticsChannel } from './diagnosticsChannel.js';
32
+ import { convertHeader, globalId, performanceTime, updateSocketInfo } from './utils.js';
33
+ import symbols from './symbols.js';
34
+ import {
35
+ FetchMeta,
36
+ HttpMethod,
37
+ RequestMeta,
38
+ } from './Request.js';
39
+ import { FetchOpaque, fetchOpaqueInterceptor } from './FetchOpaqueInterceptor.js';
40
+ import { RawResponseWithMeta, SocketInfo } from './Response.js';
41
+ import { IncomingHttpHeaders } from './IncomingHttpHeaders.js';
42
+
43
+ export interface UrllibRequestInit extends RequestInit {
44
+ // default is true
45
+ timing?: boolean;
46
+ }
47
+
48
+ export type FetchDiagnosticsMessage = {
49
+ fetch: FetchMeta;
50
+ };
51
+
52
+ export type FetchResponseDiagnosticsMessage = {
53
+ fetch: FetchMeta;
54
+ timingInfo?: UnidiciTimingInfo;
55
+ response?: Response;
56
+ error?: Error;
57
+ };
58
+
59
+ export class FetchFactory {
60
+ static #dispatcher: Agent;
61
+ static #opaqueLocalStorage = new AsyncLocalStorage<FetchOpaque>();
62
+
63
+ static getDispatcher() {
64
+ return FetchFactory.#dispatcher ?? getGlobalDispatcher();
65
+ }
66
+
67
+ static setDispatcher(dispatcher: Agent) {
68
+ FetchFactory.#dispatcher = dispatcher;
69
+ }
70
+
71
+ static setClientOptions(clientOptions: ClientOptions) {
72
+ let dispatcherOption: Agent.Options = {
73
+ interceptors: {
74
+ Agent: [
75
+ fetchOpaqueInterceptor({
76
+ opaqueLocalStorage: FetchFactory.#opaqueLocalStorage,
77
+ }),
78
+ ],
79
+ Client: [],
80
+ },
81
+ };
82
+ let dispatcherClazz: new (options: Agent.Options) => Agent = Agent;
83
+ if (clientOptions?.lookup || clientOptions?.checkAddress) {
84
+ dispatcherOption = {
85
+ ...dispatcherOption,
86
+ lookup: clientOptions.lookup,
87
+ checkAddress: clientOptions.checkAddress,
88
+ connect: clientOptions.connect,
89
+ allowH2: clientOptions.allowH2,
90
+ } as HttpAgentOptions;
91
+ dispatcherClazz = HttpAgent as unknown as new (options: Agent.Options) => Agent;
92
+ } else if (clientOptions?.connect) {
93
+ dispatcherOption = {
94
+ ...dispatcherOption,
95
+ connect: clientOptions.connect,
96
+ allowH2: clientOptions.allowH2,
97
+ } as HttpAgentOptions;
98
+ dispatcherClazz = Agent;
99
+ } else if (clientOptions?.allowH2) {
100
+ // Support HTTP2
101
+ dispatcherOption = {
102
+ ...dispatcherOption,
103
+ allowH2: clientOptions.allowH2,
104
+ } as HttpAgentOptions;
105
+ dispatcherClazz = Agent;
106
+ }
107
+ FetchFactory.#dispatcher = new dispatcherClazz(dispatcherOption);
108
+ initDiagnosticsChannel();
109
+ }
110
+
111
+ static getDispatcherPoolStats() {
112
+ const agent = FetchFactory.getDispatcher();
113
+ // origin => Pool Instance
114
+ const clients: Map<string, WeakRef<Pool>> | undefined = Reflect.get(agent, undiciSymbols.kClients);
115
+ const poolStatsMap: Record<string, PoolStat> = {};
116
+ if (!clients) {
117
+ return poolStatsMap;
118
+ }
119
+ for (const [ key, ref ] of clients) {
120
+ const pool = typeof ref.deref === 'function' ? ref.deref() : ref as unknown as Pool;
121
+ const stats = pool?.stats;
122
+ if (!stats) continue;
123
+ poolStatsMap[key] = {
124
+ connected: stats.connected,
125
+ free: stats.free,
126
+ pending: stats.pending,
127
+ queued: stats.queued,
128
+ running: stats.running,
129
+ size: stats.size,
130
+ } satisfies PoolStat;
131
+ }
132
+ return poolStatsMap;
133
+ }
134
+
135
+ static async fetch(input: RequestInfo, init?: UrllibRequestInit): Promise<Response> {
136
+ const requestStartTime = performance.now();
137
+ init = init ?? {};
138
+ init.dispatcher = init.dispatcher ?? FetchFactory.#dispatcher;
139
+ const request = new Request(input, init);
140
+ const requestId = globalId('HttpClientRequest');
141
+ // https://developer.chrome.com/docs/devtools/network/reference/?utm_source=devtools#timing-explanation
142
+ const timing = {
143
+ // socket assigned
144
+ queuing: 0,
145
+ // dns lookup time
146
+ // dnslookup: 0,
147
+ // socket connected
148
+ connected: 0,
149
+ // request headers sent
150
+ requestHeadersSent: 0,
151
+ // request sent, including headers and body
152
+ requestSent: 0,
153
+ // Time to first byte (TTFB), the response headers have been received
154
+ waiting: 0,
155
+ // the response body and trailers have been received
156
+ contentDownload: 0,
157
+ };
158
+
159
+ // using opaque to diagnostics channel, binding request and socket
160
+ const internalOpaque = {
161
+ [symbols.kRequestId]: requestId,
162
+ [symbols.kRequestStartTime]: requestStartTime,
163
+ [symbols.kEnableRequestTiming]: !!(init.timing ?? true),
164
+ [symbols.kRequestTiming]: timing,
165
+ // [symbols.kRequestOriginalOpaque]: originalOpaque,
166
+ };
167
+ const reqMeta: RequestMeta = {
168
+ requestId,
169
+ url: request.url,
170
+ args: {
171
+ method: request.method as HttpMethod,
172
+ type: request.method as HttpMethod,
173
+ data: request.body,
174
+ headers: convertHeader(request.headers),
175
+ },
176
+ retries: 0,
177
+ };
178
+ const fetchMeta: FetchMeta = {
179
+ requestId,
180
+ request,
181
+ };
182
+ const socketInfo: SocketInfo = {
183
+ id: 0,
184
+ localAddress: '',
185
+ localPort: 0,
186
+ remoteAddress: '',
187
+ remotePort: 0,
188
+ remoteFamily: '',
189
+ bytesWritten: 0,
190
+ bytesRead: 0,
191
+ handledRequests: 0,
192
+ handledResponses: 0,
193
+ };
194
+ channels.request.publish({
195
+ request: reqMeta,
196
+ } as RequestDiagnosticsMessage);
197
+ channels.fetchRequest.publish({
198
+ fetch: fetchMeta,
199
+ } as FetchDiagnosticsMessage);
200
+
201
+ let res: Response;
202
+ // keep urllib createCallbackResponse style
203
+ const resHeaders: IncomingHttpHeaders = {};
204
+ const urllibResponse = {
205
+ status: -1,
206
+ statusCode: -1,
207
+ statusText: '',
208
+ statusMessage: '',
209
+ headers: resHeaders,
210
+ size: 0,
211
+ aborted: false,
212
+ rt: 0,
213
+ keepAliveSocket: true,
214
+ requestUrls: [
215
+ request.url,
216
+ ],
217
+ timing,
218
+ socket: socketInfo,
219
+ retries: 0,
220
+ socketErrorRetries: 0,
221
+ } as any as RawResponseWithMeta;
222
+ try {
223
+ await FetchFactory.#opaqueLocalStorage.run(internalOpaque, async () => {
224
+ res = await UndiciFetch(input, init);
225
+ });
226
+ } catch (e: any) {
227
+ channels.response.publish({
228
+ fetch: fetchMeta,
229
+ error: e,
230
+ } as FetchResponseDiagnosticsMessage);
231
+ channels.fetchResponse.publish({
232
+ request: reqMeta,
233
+ response: urllibResponse,
234
+ error: e,
235
+ } as ResponseDiagnosticsMessage);
236
+ throw e;
237
+ }
238
+
239
+ // get unidici internal response
240
+ const state = Reflect.get(res!, undiciFetchSymbols.kState) as Dispatcher.ResponseData;
241
+ updateSocketInfo(socketInfo, internalOpaque /* , rawError */);
242
+
243
+ urllibResponse.headers = convertHeader(res!.headers);
244
+ urllibResponse.status = urllibResponse.statusCode = res!.status;
245
+ urllibResponse!.statusMessage = res!.statusText;
246
+ if (urllibResponse.headers['content-length']) {
247
+ urllibResponse.size = parseInt(urllibResponse.headers['content-length']);
248
+ }
249
+ urllibResponse.rt = performanceTime(requestStartTime);
250
+
251
+ channels.fetchResponse.publish({
252
+ fetch: fetchMeta,
253
+ timingInfo: (state as any).timingInfo,
254
+ response: res!,
255
+ } as FetchResponseDiagnosticsMessage);
256
+ channels.response.publish({
257
+ request: reqMeta,
258
+ response: urllibResponse,
259
+ } as ResponseDiagnosticsMessage);
260
+ return res!;
261
+ }
262
+ }
263
+
264
+ export const fetch = FetchFactory.fetch;
package/src/index.ts CHANGED
@@ -39,6 +39,8 @@ export async function curl<T = any>(url: RequestURL, options?: RequestOptions) {
39
39
  export {
40
40
  MockAgent, ProxyAgent, Agent, Dispatcher,
41
41
  setGlobalDispatcher, getGlobalDispatcher,
42
+ Request, RequestInfo, RequestInit,
43
+ Response,
42
44
  } from 'undici';
43
45
  // HttpClient2 is keep compatible with urllib@2 HttpClient2
44
46
  export {
@@ -60,6 +62,7 @@ export {
60
62
  IncomingHttpHeaders,
61
63
  } from './IncomingHttpHeaders.js';
62
64
  export * from './HttpClientError.js';
65
+ export { FetchFactory, fetch } from './fetch.js';
63
66
 
64
67
  export default {
65
68
  request,
package/src/utils.ts CHANGED
@@ -2,6 +2,9 @@ import { randomBytes, createHash } from 'node:crypto';
2
2
  import { Readable } from 'node:stream';
3
3
  import { performance } from 'node:perf_hooks';
4
4
  import type { FixJSONCtlChars } from './Request.js';
5
+ import { SocketInfo } from './Response.js';
6
+ import symbols from './symbols.js';
7
+ import { IncomingHttpHeaders } from './IncomingHttpHeaders.js';
5
8
 
6
9
  const JSONCtlCharsMap: Record<string, string> = {
7
10
  '"': '\\"', // \u0022
@@ -151,3 +154,54 @@ export function isReadable(stream: any) {
151
154
  && typeof stream._read === 'function'
152
155
  && typeof stream._readableState === 'object';
153
156
  }
157
+
158
+ export function updateSocketInfo(socketInfo: SocketInfo, internalOpaque: any, err?: any) {
159
+ const socket = internalOpaque[symbols.kRequestSocket] ?? err?.[symbols.kErrorSocket];
160
+ if (socket) {
161
+ socketInfo.id = socket[symbols.kSocketId];
162
+ socketInfo.handledRequests = socket[symbols.kHandledRequests];
163
+ socketInfo.handledResponses = socket[symbols.kHandledResponses];
164
+ if (socket[symbols.kSocketLocalAddress]) {
165
+ socketInfo.localAddress = socket[symbols.kSocketLocalAddress];
166
+ socketInfo.localPort = socket[symbols.kSocketLocalPort];
167
+ }
168
+ if (socket.remoteAddress) {
169
+ socketInfo.remoteAddress = socket.remoteAddress;
170
+ socketInfo.remotePort = socket.remotePort;
171
+ socketInfo.remoteFamily = socket.remoteFamily;
172
+ }
173
+ socketInfo.bytesRead = socket.bytesRead;
174
+ socketInfo.bytesWritten = socket.bytesWritten;
175
+ if (socket[symbols.kSocketConnectErrorTime]) {
176
+ socketInfo.connectErrorTime = socket[symbols.kSocketConnectErrorTime];
177
+ if (Array.isArray(socket.autoSelectFamilyAttemptedAddresses)) {
178
+ socketInfo.attemptedRemoteAddresses = socket.autoSelectFamilyAttemptedAddresses;
179
+ }
180
+ socketInfo.connectProtocol = socket[symbols.kSocketConnectProtocol];
181
+ socketInfo.connectHost = socket[symbols.kSocketConnectHost];
182
+ socketInfo.connectPort = socket[symbols.kSocketConnectPort];
183
+ }
184
+ if (socket[symbols.kSocketConnectedTime]) {
185
+ socketInfo.connectedTime = socket[symbols.kSocketConnectedTime];
186
+ }
187
+ if (socket[symbols.kSocketRequestEndTime]) {
188
+ socketInfo.lastRequestEndTime = socket[symbols.kSocketRequestEndTime];
189
+ }
190
+ socket[symbols.kSocketRequestEndTime] = new Date();
191
+ }
192
+ }
193
+
194
+ export function convertHeader(headers: Headers): IncomingHttpHeaders {
195
+ const res: IncomingHttpHeaders = {};
196
+ for (const [ key, value ] of headers.entries()) {
197
+ if (res[key]) {
198
+ if (!Array.isArray(res[key])) {
199
+ res[key] = [ res[key] ];
200
+ }
201
+ res[key].push(value);
202
+ } else {
203
+ res[key] = value;
204
+ }
205
+ }
206
+ return res;
207
+ }