urllib 3.1.3 โ 3.2.1
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/History.md +15 -0
- package/README.md +6 -6
- package/package.json +8 -9
- package/src/HttpClient.ts +82 -35
- package/src/Request.ts +0 -1
- package/src/Response.ts +42 -18
- package/src/cjs/HttpClient.js +81 -31
- package/src/cjs/HttpClient.js.map +1 -1
- package/src/cjs/Request.d.ts +0 -1
- package/src/cjs/Response.d.ts +29 -13
- package/src/cjs/diagnosticsChannel.d.ts +1 -0
- package/src/cjs/diagnosticsChannel.js +132 -0
- package/src/cjs/diagnosticsChannel.js.map +1 -0
- package/src/cjs/symbols.d.ts +13 -0
- package/src/cjs/symbols.js +15 -0
- package/src/cjs/symbols.js.map +1 -0
- package/src/cjs/utils.d.ts +2 -0
- package/src/cjs/utils.js +15 -1
- package/src/cjs/utils.js.map +1 -1
- package/src/diagnosticsChannel.ts +123 -0
- package/src/esm/HttpClient.js +80 -30
- package/src/esm/HttpClient.js.map +1 -1
- package/src/esm/Request.d.ts +0 -1
- package/src/esm/Response.d.ts +29 -13
- package/src/esm/cjs/Response.d.ts +1 -0
- package/src/esm/cjs/Response.js +3 -0
- package/src/esm/cjs/Response.js.map +1 -0
- package/src/esm/diagnosticsChannel.d.ts +1 -0
- package/src/esm/diagnosticsChannel.js +127 -0
- package/src/esm/diagnosticsChannel.js.map +1 -0
- package/src/esm/symbols.d.ts +13 -0
- package/src/esm/symbols.js +13 -0
- package/src/esm/symbols.js.map +1 -0
- package/src/esm/utils.d.ts +2 -0
- package/src/esm/utils.js +12 -0
- package/src/esm/utils.js.map +1 -1
- package/src/symbols.ts +12 -0
- package/src/utils.ts +15 -0
package/History.md
CHANGED
@@ -1,4 +1,19 @@
|
|
1
1
|
|
2
|
+
3.2.1 / 2022-09-27
|
3
|
+
==================
|
4
|
+
|
5
|
+
**fixes**
|
6
|
+
* [[`456c73b`](http://github.com/node-modules/urllib/commit/456c73b3dc02e1323cb8db99b60ffd191e5d7abb)] - ๐ FIX: http default protocol for URL argument (#404) (fengmk2 <<fengmk2@gmail.com>>)
|
7
|
+
|
8
|
+
3.2.0 / 2022-09-26
|
9
|
+
==================
|
10
|
+
|
11
|
+
**others**
|
12
|
+
* [[`315f4a0`](http://github.com/node-modules/urllib/commit/315f4a0bf69abc2b29247fcf1a606c44412a86f3)] - ๐ฆ NEW: Support timing and socket info (#400) (fengmk2 <<fengmk2@gmail.com>>)
|
13
|
+
* [[`414692b`](http://github.com/node-modules/urllib/commit/414692b183fb205acfb163f8aef4f853ce1b97e1)] - ๐งช๏ธ TEST: Add diagnostics_channel test cases (#398) (fengmk2 <<fengmk2@gmail.com>>)
|
14
|
+
* [[`65abb60`](http://github.com/node-modules/urllib/commit/65abb6074e5098834dd964a2bedaffd64a703ef9)] - ๐ค TEST: Use vitest instead of jest (#399) (fengmk2 <<fengmk2@gmail.com>>)
|
15
|
+
* [[`5f0c4a8`](http://github.com/node-modules/urllib/commit/5f0c4a8da84ef9954942bcd78721a5445e0cb095)] - ๐ DOC: Update contributors (fengmk2 <<fengmk2@gmail.com>>)
|
16
|
+
|
2
17
|
3.1.3 / 2022-09-09
|
3
18
|
==================
|
4
19
|
|
package/README.md
CHANGED
@@ -251,7 +251,7 @@ Response is normal object, it contains:
|
|
251
251
|
## Run test with debug log
|
252
252
|
|
253
253
|
```bash
|
254
|
-
NODE_DEBUG=urllib npm test
|
254
|
+
NODE_DEBUG=urllib:* npm test
|
255
255
|
```
|
256
256
|
|
257
257
|
## Mocking Request
|
@@ -323,12 +323,12 @@ Fork [undici benchmarks script](https://github.com/fengmk2/undici/blob/urllib-be
|
|
323
323
|
| :---: | :---: | :---: | :---: | :---: | :---: |
|
324
324
|
|[<img src="https://avatars.githubusercontent.com/u/14790466?v=4" width="100px;"/><br/><sub><b>greenkeeperio-bot</b></sub>](https://github.com/greenkeeperio-bot)<br/>|[<img src="https://avatars.githubusercontent.com/u/227713?v=4" width="100px;"/><br/><sub><b>atian25</b></sub>](https://github.com/atian25)<br/>|[<img src="https://avatars.githubusercontent.com/u/5381764?v=4" width="100px;"/><br/><sub><b>paambaati</b></sub>](https://github.com/paambaati)<br/>|[<img src="https://avatars.githubusercontent.com/u/1433247?v=4" width="100px;"/><br/><sub><b>denghongcai</b></sub>](https://github.com/denghongcai)<br/>|[<img src="https://avatars.githubusercontent.com/u/2842176?v=4" width="100px;"/><br/><sub><b>XadillaX</b></sub>](https://github.com/XadillaX)<br/>|[<img src="https://avatars.githubusercontent.com/u/1147375?v=4" width="100px;"/><br/><sub><b>alsotang</b></sub>](https://github.com/alsotang)<br/>|
|
325
325
|
|[<img src="https://avatars.githubusercontent.com/u/546535?v=4" width="100px;"/><br/><sub><b>leoner</b></sub>](https://github.com/leoner)<br/>|[<img src="https://avatars.githubusercontent.com/u/19908330?v=4" width="100px;"/><br/><sub><b>hyj1991</b></sub>](https://github.com/hyj1991)<br/>|[<img src="https://avatars.githubusercontent.com/u/1747852?v=4" width="100px;"/><br/><sub><b>isayme</b></sub>](https://github.com/isayme)<br/>|[<img src="https://avatars.githubusercontent.com/u/6897780?v=4" width="100px;"/><br/><sub><b>killagu</b></sub>](https://github.com/killagu)<br/>|[<img src="https://avatars.githubusercontent.com/u/252317?v=4" width="100px;"/><br/><sub><b>cyjake</b></sub>](https://github.com/cyjake)<br/>|[<img src="https://avatars.githubusercontent.com/u/5856440?v=4" width="100px;"/><br/><sub><b>whxaxes</b></sub>](https://github.com/whxaxes)<br/>|
|
326
|
-
|[<img src="https://avatars.githubusercontent.com/u/309219?v=4" width="100px;"/><br/><sub><b>chadxz</b></sub>](https://github.com/chadxz)<br/>|[<img src="https://avatars.githubusercontent.com/u/
|
327
|
-
|[<img src="https://avatars.githubusercontent.com/u/
|
328
|
-
|[<img src="https://avatars.githubusercontent.com/
|
329
|
-
[<img src="https://avatars.githubusercontent.com/u/2196373?v=4" width="100px;"/><br/><sub><b>dickeylth</b></sub>](https://github.com/dickeylth)<br/>|[<img src="https://avatars.githubusercontent.com/u/13050025?v=4" width="100px;"/><br/><sub><b>aladdin-add</b></sub>](https://github.com/aladdin-add)<br/>
|
326
|
+
|[<img src="https://avatars.githubusercontent.com/u/309219?v=4" width="100px;"/><br/><sub><b>chadxz</b></sub>](https://github.com/chadxz)<br/>|[<img src="https://avatars.githubusercontent.com/u/2055702?v=4" width="100px;"/><br/><sub><b>adapt0</b></sub>](https://github.com/adapt0)<br/>|[<img src="https://avatars.githubusercontent.com/u/5139554?v=4" width="100px;"/><br/><sub><b>danielwpz</b></sub>](https://github.com/danielwpz)<br/>|[<img src="https://avatars.githubusercontent.com/u/5127897?v=4" width="100px;"/><br/><sub><b>danielsss</b></sub>](https://github.com/danielsss)<br/>|[<img src="https://avatars.githubusercontent.com/u/3367820?v=4" width="100px;"/><br/><sub><b>Jeff-Tian</b></sub>](https://github.com/Jeff-Tian)<br/>|[<img src="https://avatars.githubusercontent.com/u/32407?v=4" width="100px;"/><br/><sub><b>jedahan</b></sub>](https://github.com/jedahan)<br/>|
|
327
|
+
|[<img src="https://avatars.githubusercontent.com/u/17075261?v=4" width="100px;"/><br/><sub><b>nick-ng</b></sub>](https://github.com/nick-ng)<br/>|[<img src="https://avatars.githubusercontent.com/u/1706595?v=4" width="100px;"/><br/><sub><b>rishavsharan</b></sub>](https://github.com/rishavsharan)<br/>|[<img src="https://avatars.githubusercontent.com/u/1886161?v=4" width="100px;"/><br/><sub><b>willizm</b></sub>](https://github.com/willizm)<br/>|[<img src="https://avatars.githubusercontent.com/u/7227589?v=4" width="100px;"/><br/><sub><b>davidkhala</b></sub>](https://github.com/davidkhala)<br/>|[<img src="https://avatars.githubusercontent.com/u/535479?v=4" width="100px;"/><br/><sub><b>aleafs</b></sub>](https://github.com/aleafs)<br/>|[<img src="https://avatars.githubusercontent.com/u/3689968?v=4" width="100px;"/><br/><sub><b>Amunu</b></sub>](https://github.com/Amunu)<br/>|
|
328
|
+
|[<img src="https://avatars.githubusercontent.com/in/9426?v=4" width="100px;"/><br/><sub><b>azure-pipelines[bot]</b></sub>](https://github.com/apps/azure-pipelines)<br/>|[<img src="https://avatars.githubusercontent.com/u/1281323?v=4" width="100px;"/><br/><sub><b>changzhiwin</b></sub>](https://github.com/changzhiwin)<br/>|[<img src="https://avatars.githubusercontent.com/u/929503?v=4" width="100px;"/><br/><sub><b>yuzhigang33</b></sub>](https://github.com/yuzhigang33)<br/>|[<img src="https://avatars.githubusercontent.com/u/981128?v=4" width="100px;"/><br/><sub><b>fishbar</b></sub>](https://github.com/fishbar)<br/>|[<img src="https://avatars.githubusercontent.com/u/1207064?v=4" width="100px;"/><br/><sub><b>gxcsoccer</b></sub>](https://github.com/gxcsoccer)<br/>|[<img src="https://avatars.githubusercontent.com/u/17476119?v=4" width="100px;"/><br/><sub><b>mars-coder</b></sub>](https://github.com/mars-coder)<br/>|
|
329
|
+
[<img src="https://avatars.githubusercontent.com/u/929179?v=4" width="100px;"/><br/><sub><b>rockdai</b></sub>](https://github.com/rockdai)<br/>|[<img src="https://avatars.githubusercontent.com/u/2196373?v=4" width="100px;"/><br/><sub><b>dickeylth</b></sub>](https://github.com/dickeylth)<br/>|[<img src="https://avatars.githubusercontent.com/u/13050025?v=4" width="100px;"/><br/><sub><b>aladdin-add</b></sub>](https://github.com/aladdin-add)<br/>
|
330
330
|
|
331
|
-
This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `
|
331
|
+
This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Fri Sep 09 2022 21:45:49 GMT+0800`.
|
332
332
|
|
333
333
|
<!-- GITCONTRIBUTOR_END -->
|
334
334
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "urllib",
|
3
|
-
"version": "3.1
|
3
|
+
"version": "3.2.1",
|
4
4
|
"publishConfig": {
|
5
5
|
"tag": "latest"
|
6
6
|
},
|
@@ -49,8 +49,9 @@
|
|
49
49
|
"build:cjs:test": "cd test/cjs && rm -rf node_modules && npm link ../.. && node index.js",
|
50
50
|
"build:esm:test": "cd test/esm && rm -rf node_modules && npm link ../.. && node index.js",
|
51
51
|
"build:test": "npm run build && npm run build:cjs:test && npm run build:esm:test",
|
52
|
-
"test": "
|
53
|
-
"
|
52
|
+
"test": "vitest run",
|
53
|
+
"cov": "vitest run --coverage --no-threads",
|
54
|
+
"ci": "npm run lint && npm run cov && npm run build:test",
|
54
55
|
"contributor": "git-contributor",
|
55
56
|
"prepack": "npm run build && rm -rf src/*.tsbuildinfo"
|
56
57
|
},
|
@@ -67,10 +68,10 @@
|
|
67
68
|
"devDependencies": {
|
68
69
|
"@types/busboy": "^1.5.0",
|
69
70
|
"@types/default-user-agent": "^1.0.0",
|
70
|
-
"@types/jest": "28",
|
71
71
|
"@types/mime-types": "^2.1.1",
|
72
72
|
"@types/pump": "^1.1.1",
|
73
73
|
"@types/selfsigned": "^2.0.1",
|
74
|
+
"@vitest/coverage-c8": "^0.23.4",
|
74
75
|
"busboy": "^1.6.0",
|
75
76
|
"coffee": "5",
|
76
77
|
"egg-ci": "2",
|
@@ -78,14 +79,12 @@
|
|
78
79
|
"eslint-config-egg": "^12.0.0",
|
79
80
|
"git-contributor": "1",
|
80
81
|
"iconv-lite": "^0.6.3",
|
81
|
-
"jest": "28",
|
82
|
-
"jest-summary-reporter": "^0.0.2",
|
83
82
|
"selfsigned": "^2.0.1",
|
84
|
-
"
|
85
|
-
"
|
83
|
+
"typescript": "^4.8.3",
|
84
|
+
"vitest": "^0.23.4"
|
86
85
|
},
|
87
86
|
"engines": {
|
88
|
-
"node": ">= 14.
|
87
|
+
"node": ">= 14.17.0"
|
89
88
|
},
|
90
89
|
"ci": {
|
91
90
|
"version": "14, 16, 18"
|
package/src/HttpClient.ts
CHANGED
@@ -26,9 +26,12 @@ import mime from 'mime-types';
|
|
26
26
|
import pump from 'pump';
|
27
27
|
import { HttpAgent, CheckAddressFunction } from './HttpAgent';
|
28
28
|
import { RequestURL, RequestOptions, HttpMethod } from './Request';
|
29
|
-
import { HttpClientResponseMeta, HttpClientResponse, ReadableWithMeta } from './Response';
|
30
|
-
import { parseJSON, sleep, digestAuthHeader } from './utils';
|
29
|
+
import { HttpClientResponseMeta, HttpClientResponse, ReadableWithMeta, BaseResponseMeta, SocketInfo } from './Response';
|
30
|
+
import { parseJSON, sleep, digestAuthHeader, globalId, performanceTime } from './utils';
|
31
|
+
import symbols from './symbols';
|
32
|
+
import { initDiagnosticsChannel } from './diagnosticsChannel';
|
31
33
|
|
34
|
+
const PROTO_RE = /^https?:\/\//i;
|
32
35
|
const FormData = FormDataNative ?? FormDataNode;
|
33
36
|
// impl isReadable on Node.js 14
|
34
37
|
const isReadable = stream.isReadable ?? function isReadable(stream: any) {
|
@@ -48,10 +51,7 @@ function noop() {
|
|
48
51
|
// noop
|
49
52
|
}
|
50
53
|
|
51
|
-
const
|
52
|
-
let globalRequestId = 0;
|
53
|
-
|
54
|
-
const debug = debuglog('urllib');
|
54
|
+
const debug = debuglog('urllib:HttpClient');
|
55
55
|
|
56
56
|
export type ClientOptions = {
|
57
57
|
defaultArgs?: RequestOptions;
|
@@ -127,10 +127,6 @@ function defaultIsRetry(response: HttpClientResponse) {
|
|
127
127
|
return response.status >= 500;
|
128
128
|
}
|
129
129
|
|
130
|
-
function performanceTime(startTime: number) {
|
131
|
-
return Math.floor((performance.now() - startTime) * 1000) / 1000;
|
132
|
-
}
|
133
|
-
|
134
130
|
type RequestContext = {
|
135
131
|
retries: number;
|
136
132
|
};
|
@@ -149,6 +145,7 @@ export class HttpClient extends EventEmitter {
|
|
149
145
|
connect: clientOptions.connect,
|
150
146
|
});
|
151
147
|
}
|
148
|
+
initDiagnosticsChannel();
|
152
149
|
}
|
153
150
|
|
154
151
|
async request(url: RequestURL, options?: RequestOptions) {
|
@@ -156,12 +153,17 @@ export class HttpClient extends EventEmitter {
|
|
156
153
|
}
|
157
154
|
|
158
155
|
async #requestInternal(url: RequestURL, options?: RequestOptions, requestContext?: RequestContext): Promise<HttpClientResponse> {
|
159
|
-
|
160
|
-
|
156
|
+
const requestId = globalId('HttpClientRequest');
|
157
|
+
let requestUrl: URL;
|
158
|
+
if (typeof url === 'string') {
|
159
|
+
if (!PROTO_RE.test(url)) {
|
160
|
+
// Support `request('www.server.com')`
|
161
|
+
url = 'http://' + url;
|
162
|
+
}
|
163
|
+
requestUrl = new URL(url);
|
164
|
+
} else {
|
165
|
+
requestUrl = url;
|
161
166
|
}
|
162
|
-
const requestId = ++globalRequestId;
|
163
|
-
|
164
|
-
const requestUrl = typeof url === 'string' ? new URL(url) : url;
|
165
167
|
const args = {
|
166
168
|
retry: 0,
|
167
169
|
...this.#defaultArgs,
|
@@ -173,6 +175,32 @@ export class HttpClient extends EventEmitter {
|
|
173
175
|
};
|
174
176
|
const requestStartTime = performance.now();
|
175
177
|
|
178
|
+
// https://developer.chrome.com/docs/devtools/network/reference/?utm_source=devtools#timing-explanation
|
179
|
+
const timing = {
|
180
|
+
// socket assigned
|
181
|
+
queuing: 0,
|
182
|
+
// dns lookup time
|
183
|
+
// dnslookup: 0,
|
184
|
+
// socket connected
|
185
|
+
connected: 0,
|
186
|
+
// request headers sent
|
187
|
+
requestHeadersSent: 0,
|
188
|
+
// request sent, including headers and body
|
189
|
+
requestSent: 0,
|
190
|
+
// Time to first byte (TTFB), the response headers have been received
|
191
|
+
waiting: 0,
|
192
|
+
// the response body and trailers have been received
|
193
|
+
contentDownload: 0,
|
194
|
+
};
|
195
|
+
const orginalOpaque = args.opaque;
|
196
|
+
// using opaque to diagnostics channel, binding request and socket
|
197
|
+
const internalOpaque = {
|
198
|
+
[symbols.kRequestId]: requestId,
|
199
|
+
[symbols.kRequestStartTime]: requestStartTime,
|
200
|
+
[symbols.kEnableRequestTiming]: !!args.timing,
|
201
|
+
[symbols.kRequestTiming]: timing,
|
202
|
+
[symbols.kRequestOrginalOpaque]: orginalOpaque,
|
203
|
+
};
|
176
204
|
const reqMeta = {
|
177
205
|
requestId,
|
178
206
|
url: requestUrl.href,
|
@@ -180,6 +208,18 @@ export class HttpClient extends EventEmitter {
|
|
180
208
|
ctx: args.ctx,
|
181
209
|
retries: requestContext.retries,
|
182
210
|
};
|
211
|
+
const socketInfo = {
|
212
|
+
id: 0,
|
213
|
+
localAddress: '',
|
214
|
+
localPort: 0,
|
215
|
+
remoteAddress: '',
|
216
|
+
remotePort: 0,
|
217
|
+
remoteFamily: '',
|
218
|
+
bytesWritten: 0,
|
219
|
+
bytesRead: 0,
|
220
|
+
handledRequests: 0,
|
221
|
+
handledResponses: 0,
|
222
|
+
};
|
183
223
|
// keep urllib createCallbackResponse style
|
184
224
|
const resHeaders: IncomingHttpHeaders = {};
|
185
225
|
const res: HttpClientResponseMeta = {
|
@@ -191,10 +231,8 @@ export class HttpClient extends EventEmitter {
|
|
191
231
|
rt: 0,
|
192
232
|
keepAliveSocket: true,
|
193
233
|
requestUrls: [],
|
194
|
-
timing
|
195
|
-
|
196
|
-
contentDownload: 0,
|
197
|
-
},
|
234
|
+
timing,
|
235
|
+
socket: socketInfo,
|
198
236
|
};
|
199
237
|
|
200
238
|
let headersTimeout = 5000;
|
@@ -245,7 +283,6 @@ export class HttpClient extends EventEmitter {
|
|
245
283
|
headers.authorization = `Basic ${Buffer.from(args.auth).toString('base64')}`;
|
246
284
|
}
|
247
285
|
|
248
|
-
let opaque = args.opaque;
|
249
286
|
try {
|
250
287
|
const requestOptions: UndiciRquestOptions = {
|
251
288
|
method,
|
@@ -253,7 +290,7 @@ export class HttpClient extends EventEmitter {
|
|
253
290
|
maxRedirections: args.maxRedirects ?? 10,
|
254
291
|
headersTimeout,
|
255
292
|
bodyTimeout,
|
256
|
-
opaque,
|
293
|
+
opaque: internalOpaque,
|
257
294
|
dispatcher: this.#dispatcher,
|
258
295
|
};
|
259
296
|
if (args.followRedirect === false) {
|
@@ -383,11 +420,6 @@ export class HttpClient extends EventEmitter {
|
|
383
420
|
}
|
384
421
|
}
|
385
422
|
|
386
|
-
opaque = response.opaque;
|
387
|
-
if (args.timing) {
|
388
|
-
res.timing.waiting = performanceTime(requestStartTime);
|
389
|
-
}
|
390
|
-
|
391
423
|
const context = response.context as { history: URL[] };
|
392
424
|
let lastUrl = '';
|
393
425
|
if (context?.history) {
|
@@ -413,10 +445,12 @@ export class HttpClient extends EventEmitter {
|
|
413
445
|
if (args.dataType === 'stream') {
|
414
446
|
// streaming mode will disable retry
|
415
447
|
args.retry = 0;
|
416
|
-
const meta = {
|
448
|
+
const meta: BaseResponseMeta = {
|
417
449
|
status: res.status,
|
418
450
|
statusCode: res.statusCode,
|
419
451
|
headers: res.headers,
|
452
|
+
timing,
|
453
|
+
socket: socketInfo,
|
420
454
|
};
|
421
455
|
if (isCompressedContent) {
|
422
456
|
// gzip or br
|
@@ -458,12 +492,11 @@ export class HttpClient extends EventEmitter {
|
|
458
492
|
}
|
459
493
|
}
|
460
494
|
res.rt = performanceTime(requestStartTime);
|
461
|
-
|
462
|
-
|
463
|
-
}
|
495
|
+
// get real socket info from internalOpaque
|
496
|
+
this.#updateSocketInfo(socketInfo, internalOpaque);
|
464
497
|
|
465
498
|
const clientResponse: HttpClientResponse = {
|
466
|
-
opaque,
|
499
|
+
opaque: orginalOpaque,
|
467
500
|
data,
|
468
501
|
status: res.status,
|
469
502
|
statusCode: res.status,
|
@@ -507,7 +540,7 @@ export class HttpClient extends EventEmitter {
|
|
507
540
|
} else if (err.name === 'BodyTimeoutError') {
|
508
541
|
err = new HttpClientRequestTimeoutError(bodyTimeout, { cause: e });
|
509
542
|
}
|
510
|
-
err.opaque =
|
543
|
+
err.opaque = orginalOpaque;
|
511
544
|
err.status = res.status;
|
512
545
|
err.headers = res.headers;
|
513
546
|
err.res = res;
|
@@ -516,9 +549,7 @@ export class HttpClient extends EventEmitter {
|
|
516
549
|
res.requestUrls.push(requestUrl.href);
|
517
550
|
}
|
518
551
|
res.rt = performanceTime(requestStartTime);
|
519
|
-
|
520
|
-
res.timing.contentDownload = res.rt;
|
521
|
-
}
|
552
|
+
this.#updateSocketInfo(socketInfo, internalOpaque);
|
522
553
|
|
523
554
|
if (this.listenerCount('response') > 0) {
|
524
555
|
this.emit('response', {
|
@@ -532,4 +563,20 @@ export class HttpClient extends EventEmitter {
|
|
532
563
|
throw err;
|
533
564
|
}
|
534
565
|
}
|
566
|
+
|
567
|
+
#updateSocketInfo(socketInfo: SocketInfo, internalOpaque: any) {
|
568
|
+
const socket = internalOpaque[symbols.kRequestSocket];
|
569
|
+
if (socket) {
|
570
|
+
socketInfo.id = socket[symbols.kSocketId];
|
571
|
+
socketInfo.handledRequests = socket[symbols.kHandledRequests];
|
572
|
+
socketInfo.handledResponses = socket[symbols.kHandledResponses];
|
573
|
+
socketInfo.localAddress = socket.localAddress;
|
574
|
+
socketInfo.localPort = socket.localPort;
|
575
|
+
socketInfo.remoteAddress = socket.remoteAddress;
|
576
|
+
socketInfo.remotePort = socket.remotePort;
|
577
|
+
socketInfo.remoteFamily = socket.remoteFamily;
|
578
|
+
socketInfo.bytesRead = socket.bytesRead;
|
579
|
+
socketInfo.bytesWritten = socket.bytesWritten;
|
580
|
+
}
|
581
|
+
}
|
535
582
|
}
|
package/src/Request.ts
CHANGED
package/src/Response.ts
CHANGED
@@ -1,37 +1,61 @@
|
|
1
1
|
import { Readable } from 'stream';
|
2
2
|
import { IncomingHttpHeaders } from 'http';
|
3
3
|
|
4
|
-
export type
|
4
|
+
export type SocketInfo = {
|
5
|
+
id: number;
|
6
|
+
localAddress: string;
|
7
|
+
localPort: number;
|
8
|
+
remoteAddress: string;
|
9
|
+
remotePort: number;
|
10
|
+
remoteFamily: string;
|
11
|
+
bytesWritten: number;
|
12
|
+
bytesRead: number;
|
13
|
+
handledRequests: number;
|
14
|
+
handledResponses: number;
|
15
|
+
};
|
16
|
+
|
17
|
+
/**
|
18
|
+
* https://eggjs.org/en/core/httpclient.html#timing-boolean
|
19
|
+
*/
|
20
|
+
export type Timing = {
|
21
|
+
// socket assigned
|
22
|
+
queuing: number;
|
23
|
+
// dns lookup time
|
24
|
+
// dnslookup: number;
|
25
|
+
// socket connected
|
26
|
+
connected: number;
|
27
|
+
// request headers sent
|
28
|
+
requestHeadersSent: number;
|
29
|
+
// request sent, including headers and body
|
30
|
+
requestSent: number;
|
31
|
+
// Time to first byte (TTFB), the response headers have been received
|
32
|
+
waiting: number;
|
33
|
+
// the response body and trailers have been received
|
34
|
+
contentDownload: number;
|
35
|
+
};
|
36
|
+
|
37
|
+
export type BaseResponseMeta = {
|
5
38
|
status: number;
|
6
39
|
statusCode: number;
|
7
40
|
headers: IncomingHttpHeaders;
|
41
|
+
timing: Timing;
|
42
|
+
// SocketInfo
|
43
|
+
socket: SocketInfo;
|
44
|
+
};
|
45
|
+
|
46
|
+
export type HttpClientResponseMeta = BaseResponseMeta & {
|
8
47
|
size: number;
|
9
48
|
aborted: boolean;
|
10
49
|
rt: number;
|
11
50
|
keepAliveSocket: boolean;
|
12
51
|
requestUrls: string[];
|
13
|
-
/**
|
14
|
-
* https://eggjs.org/en/core/httpclient.html#timing-boolean
|
15
|
-
*/
|
16
|
-
timing: {
|
17
|
-
contentDownload: number;
|
18
|
-
waiting: number;
|
19
|
-
};
|
20
|
-
// remoteAddress: remoteAddress,
|
21
|
-
// remotePort: remotePort,
|
22
|
-
// socketHandledRequests: socketHandledRequests,
|
23
|
-
// socketHandledResponses: socketHandledResponses,
|
24
52
|
};
|
25
53
|
|
26
|
-
export type ReadableWithMeta = Readable &
|
27
|
-
status: number;
|
28
|
-
statusCode: number;
|
29
|
-
headers: IncomingHttpHeaders;
|
30
|
-
};
|
54
|
+
export type ReadableWithMeta = Readable & BaseResponseMeta;
|
31
55
|
|
32
56
|
export type HttpClientResponse = {
|
33
57
|
opaque: unknown;
|
34
|
-
data: any
|
58
|
+
data: any;
|
35
59
|
status: number;
|
36
60
|
// alias to status, keep compatibility
|
37
61
|
statusCode: number;
|
package/src/cjs/HttpClient.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
var _a, _b, _c;
|
3
|
-
var _BlobFromStream_stream, _BlobFromStream_type, _HttpClient_instances, _HttpClient_defaultArgs, _HttpClient_dispatcher, _HttpClient_requestInternal;
|
3
|
+
var _BlobFromStream_stream, _BlobFromStream_type, _HttpClient_instances, _HttpClient_defaultArgs, _HttpClient_dispatcher, _HttpClient_requestInternal, _HttpClient_updateSocketInfo;
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
5
5
|
exports.HttpClient = exports.HEADER_USER_AGENT = void 0;
|
6
6
|
const tslib_1 = require("tslib");
|
@@ -21,6 +21,9 @@ const mime_types_1 = tslib_1.__importDefault(require("mime-types"));
|
|
21
21
|
const pump_1 = tslib_1.__importDefault(require("pump"));
|
22
22
|
const HttpAgent_1 = require("./HttpAgent");
|
23
23
|
const utils_1 = require("./utils");
|
24
|
+
const symbols_1 = tslib_1.__importDefault(require("./symbols"));
|
25
|
+
const diagnosticsChannel_1 = require("./diagnosticsChannel");
|
26
|
+
const PROTO_RE = /^https?:\/\//i;
|
24
27
|
const FormData = undici_1.FormData !== null && undici_1.FormData !== void 0 ? undici_1.FormData : formdata_node_1.FormData;
|
25
28
|
// impl isReadable on Node.js 14
|
26
29
|
const isReadable = (_a = stream_2.default.isReadable) !== null && _a !== void 0 ? _a : function isReadable(stream) {
|
@@ -39,9 +42,7 @@ const pipelinePromise = (_c = (_b = stream_2.default.promises) === null || _b ==
|
|
39
42
|
function noop() {
|
40
43
|
// noop
|
41
44
|
}
|
42
|
-
const
|
43
|
-
let globalRequestId = 0;
|
44
|
-
const debug = (0, util_1.debuglog)('urllib');
|
45
|
+
const debug = (0, util_1.debuglog)('urllib:HttpClient');
|
45
46
|
// https://github.com/octet-stream/form-data
|
46
47
|
class BlobFromStream {
|
47
48
|
constructor(stream, type) {
|
@@ -79,9 +80,6 @@ function getFileName(stream) {
|
|
79
80
|
function defaultIsRetry(response) {
|
80
81
|
return response.status >= 500;
|
81
82
|
}
|
82
|
-
function performanceTime(startTime) {
|
83
|
-
return Math.floor((perf_hooks_1.performance.now() - startTime) * 1000) / 1000;
|
84
|
-
}
|
85
83
|
class HttpClient extends events_1.EventEmitter {
|
86
84
|
constructor(clientOptions) {
|
87
85
|
super();
|
@@ -96,6 +94,7 @@ class HttpClient extends events_1.EventEmitter {
|
|
96
94
|
connect: clientOptions.connect,
|
97
95
|
}), "f");
|
98
96
|
}
|
97
|
+
(0, diagnosticsChannel_1.initDiagnosticsChannel)();
|
99
98
|
}
|
100
99
|
async request(url, options) {
|
101
100
|
return await tslib_1.__classPrivateFieldGet(this, _HttpClient_instances, "m", _HttpClient_requestInternal).call(this, url, options);
|
@@ -104,11 +103,18 @@ class HttpClient extends events_1.EventEmitter {
|
|
104
103
|
exports.HttpClient = HttpClient;
|
105
104
|
_HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(), _HttpClient_instances = new WeakSet(), _HttpClient_requestInternal = async function _HttpClient_requestInternal(url, options, requestContext) {
|
106
105
|
var _a, _b, _c, _d, _e, _f;
|
107
|
-
|
108
|
-
|
106
|
+
const requestId = (0, utils_1.globalId)('HttpClientRequest');
|
107
|
+
let requestUrl;
|
108
|
+
if (typeof url === 'string') {
|
109
|
+
if (!PROTO_RE.test(url)) {
|
110
|
+
// Support `request('www.server.com')`
|
111
|
+
url = 'http://' + url;
|
112
|
+
}
|
113
|
+
requestUrl = new URL(url);
|
114
|
+
}
|
115
|
+
else {
|
116
|
+
requestUrl = url;
|
109
117
|
}
|
110
|
-
const requestId = ++globalRequestId;
|
111
|
-
const requestUrl = typeof url === 'string' ? new URL(url) : url;
|
112
118
|
const args = {
|
113
119
|
retry: 0,
|
114
120
|
...tslib_1.__classPrivateFieldGet(this, _HttpClient_defaultArgs, "f"),
|
@@ -119,6 +125,32 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
119
125
|
...requestContext,
|
120
126
|
};
|
121
127
|
const requestStartTime = perf_hooks_1.performance.now();
|
128
|
+
// https://developer.chrome.com/docs/devtools/network/reference/?utm_source=devtools#timing-explanation
|
129
|
+
const timing = {
|
130
|
+
// socket assigned
|
131
|
+
queuing: 0,
|
132
|
+
// dns lookup time
|
133
|
+
// dnslookup: 0,
|
134
|
+
// socket connected
|
135
|
+
connected: 0,
|
136
|
+
// request headers sent
|
137
|
+
requestHeadersSent: 0,
|
138
|
+
// request sent, including headers and body
|
139
|
+
requestSent: 0,
|
140
|
+
// Time to first byte (TTFB), the response headers have been received
|
141
|
+
waiting: 0,
|
142
|
+
// the response body and trailers have been received
|
143
|
+
contentDownload: 0,
|
144
|
+
};
|
145
|
+
const orginalOpaque = args.opaque;
|
146
|
+
// using opaque to diagnostics channel, binding request and socket
|
147
|
+
const internalOpaque = {
|
148
|
+
[symbols_1.default.kRequestId]: requestId,
|
149
|
+
[symbols_1.default.kRequestStartTime]: requestStartTime,
|
150
|
+
[symbols_1.default.kEnableRequestTiming]: !!args.timing,
|
151
|
+
[symbols_1.default.kRequestTiming]: timing,
|
152
|
+
[symbols_1.default.kRequestOrginalOpaque]: orginalOpaque,
|
153
|
+
};
|
122
154
|
const reqMeta = {
|
123
155
|
requestId,
|
124
156
|
url: requestUrl.href,
|
@@ -126,6 +158,18 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
126
158
|
ctx: args.ctx,
|
127
159
|
retries: requestContext.retries,
|
128
160
|
};
|
161
|
+
const socketInfo = {
|
162
|
+
id: 0,
|
163
|
+
localAddress: '',
|
164
|
+
localPort: 0,
|
165
|
+
remoteAddress: '',
|
166
|
+
remotePort: 0,
|
167
|
+
remoteFamily: '',
|
168
|
+
bytesWritten: 0,
|
169
|
+
bytesRead: 0,
|
170
|
+
handledRequests: 0,
|
171
|
+
handledResponses: 0,
|
172
|
+
};
|
129
173
|
// keep urllib createCallbackResponse style
|
130
174
|
const resHeaders = {};
|
131
175
|
const res = {
|
@@ -137,10 +181,8 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
137
181
|
rt: 0,
|
138
182
|
keepAliveSocket: true,
|
139
183
|
requestUrls: [],
|
140
|
-
timing
|
141
|
-
|
142
|
-
contentDownload: 0,
|
143
|
-
},
|
184
|
+
timing,
|
185
|
+
socket: socketInfo,
|
144
186
|
};
|
145
187
|
let headersTimeout = 5000;
|
146
188
|
let bodyTimeout = 5000;
|
@@ -190,7 +232,6 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
190
232
|
if (args.auth && !headers.authorization) {
|
191
233
|
headers.authorization = `Basic ${Buffer.from(args.auth).toString('base64')}`;
|
192
234
|
}
|
193
|
-
let opaque = args.opaque;
|
194
235
|
try {
|
195
236
|
const requestOptions = {
|
196
237
|
method,
|
@@ -198,7 +239,7 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
198
239
|
maxRedirections: (_d = args.maxRedirects) !== null && _d !== void 0 ? _d : 10,
|
199
240
|
headersTimeout,
|
200
241
|
bodyTimeout,
|
201
|
-
opaque,
|
242
|
+
opaque: internalOpaque,
|
202
243
|
dispatcher: tslib_1.__classPrivateFieldGet(this, _HttpClient_dispatcher, "f"),
|
203
244
|
};
|
204
245
|
if (args.followRedirect === false) {
|
@@ -332,10 +373,6 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
332
373
|
response = await (0, undici_1.request)(requestUrl, requestOptions);
|
333
374
|
}
|
334
375
|
}
|
335
|
-
opaque = response.opaque;
|
336
|
-
if (args.timing) {
|
337
|
-
res.timing.waiting = performanceTime(requestStartTime);
|
338
|
-
}
|
339
376
|
const context = response.context;
|
340
377
|
let lastUrl = '';
|
341
378
|
if (context === null || context === void 0 ? void 0 : context.history) {
|
@@ -364,6 +401,8 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
364
401
|
status: res.status,
|
365
402
|
statusCode: res.statusCode,
|
366
403
|
headers: res.headers,
|
404
|
+
timing,
|
405
|
+
socket: socketInfo,
|
367
406
|
};
|
368
407
|
if (isCompressedContent) {
|
369
408
|
// gzip or br
|
@@ -411,12 +450,11 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
411
450
|
}
|
412
451
|
}
|
413
452
|
}
|
414
|
-
res.rt = performanceTime(requestStartTime);
|
415
|
-
|
416
|
-
|
417
|
-
}
|
453
|
+
res.rt = (0, utils_1.performanceTime)(requestStartTime);
|
454
|
+
// get real socket info from internalOpaque
|
455
|
+
tslib_1.__classPrivateFieldGet(this, _HttpClient_instances, "m", _HttpClient_updateSocketInfo).call(this, socketInfo, internalOpaque);
|
418
456
|
const clientResponse = {
|
419
|
-
opaque,
|
457
|
+
opaque: orginalOpaque,
|
420
458
|
data,
|
421
459
|
status: res.status,
|
422
460
|
statusCode: res.status,
|
@@ -459,7 +497,7 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
459
497
|
else if (err.name === 'BodyTimeoutError') {
|
460
498
|
err = new HttpClientRequestTimeoutError(bodyTimeout, { cause: e });
|
461
499
|
}
|
462
|
-
err.opaque =
|
500
|
+
err.opaque = orginalOpaque;
|
463
501
|
err.status = res.status;
|
464
502
|
err.headers = res.headers;
|
465
503
|
err.res = res;
|
@@ -467,10 +505,8 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
467
505
|
if (res.requestUrls.length === 0) {
|
468
506
|
res.requestUrls.push(requestUrl.href);
|
469
507
|
}
|
470
|
-
res.rt = performanceTime(requestStartTime);
|
471
|
-
|
472
|
-
res.timing.contentDownload = res.rt;
|
473
|
-
}
|
508
|
+
res.rt = (0, utils_1.performanceTime)(requestStartTime);
|
509
|
+
tslib_1.__classPrivateFieldGet(this, _HttpClient_instances, "m", _HttpClient_updateSocketInfo).call(this, socketInfo, internalOpaque);
|
474
510
|
if (this.listenerCount('response') > 0) {
|
475
511
|
this.emit('response', {
|
476
512
|
requestId,
|
@@ -482,5 +518,19 @@ _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(),
|
|
482
518
|
}
|
483
519
|
throw err;
|
484
520
|
}
|
521
|
+
}, _HttpClient_updateSocketInfo = function _HttpClient_updateSocketInfo(socketInfo, internalOpaque) {
|
522
|
+
const socket = internalOpaque[symbols_1.default.kRequestSocket];
|
523
|
+
if (socket) {
|
524
|
+
socketInfo.id = socket[symbols_1.default.kSocketId];
|
525
|
+
socketInfo.handledRequests = socket[symbols_1.default.kHandledRequests];
|
526
|
+
socketInfo.handledResponses = socket[symbols_1.default.kHandledResponses];
|
527
|
+
socketInfo.localAddress = socket.localAddress;
|
528
|
+
socketInfo.localPort = socket.localPort;
|
529
|
+
socketInfo.remoteAddress = socket.remoteAddress;
|
530
|
+
socketInfo.remotePort = socket.remotePort;
|
531
|
+
socketInfo.remoteFamily = socket.remoteFamily;
|
532
|
+
socketInfo.bytesRead = socket.bytesRead;
|
533
|
+
socketInfo.bytesWritten = socket.bytesWritten;
|
534
|
+
}
|
485
535
|
};
|
486
536
|
//# sourceMappingURL=HttpClient.js.map
|