urllib 3.22.1 → 3.22.3

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/README.md CHANGED
@@ -68,7 +68,7 @@ console.log('status: %s, body size: %d, headers: %j', res.status, data.length, r
68
68
  - **keepAliveTimeout** `number | null` - Default is `4000`, 4 seconds - The timeout after which a socket without active requests will time out. Monitors time between activity on a connected socket. This value may be overridden by *keep-alive* hints from the server. See [MDN: HTTP - Headers - Keep-Alive directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive#directives) for more details.
69
69
  - ***auth*** String - `username:password` used in HTTP Basic Authorization.
70
70
  - ***digestAuth*** String - `username:password` used in HTTP [Digest Authorization](https://en.wikipedia.org/wiki/Digest_access_authentication).
71
- - ***followRedirect*** Boolean - follow HTTP 3xx responses as redirects. defaults to false.
71
+ - ***followRedirect*** Boolean - follow HTTP 3xx responses as redirects. defaults to true.
72
72
  - ***maxRedirects*** Number - The maximum number of redirects to follow, defaults to 10.
73
73
  - ***formatRedirectUrl*** Function - Format the redirect url by your self. Default is `url.resolve(from, to)`.
74
74
  - ***beforeRequest*** Function - Before request hook, you can change every thing here.
@@ -16,6 +16,7 @@ const node_path_1 = require("node:path");
16
16
  const node_fs_1 = require("node:fs");
17
17
  const node_url_1 = require("node:url");
18
18
  const node_perf_hooks_1 = require("node:perf_hooks");
19
+ const node_querystring_1 = __importDefault(require("node:querystring"));
19
20
  const undici_1 = require("undici");
20
21
  const symbols_js_1 = __importDefault(require("undici/lib/core/symbols.js"));
21
22
  const formdata_node_1 = require("formdata-node");
@@ -67,7 +68,7 @@ class BlobFromStream {
67
68
  return 'Blob';
68
69
  }
69
70
  }
70
- exports.HEADER_USER_AGENT = (0, default_user_agent_1.default)('node-urllib', '3.22.1');
71
+ exports.HEADER_USER_AGENT = (0, default_user_agent_1.default)('node-urllib', '3.22.3');
71
72
  function getFileName(stream) {
72
73
  const filePath = stream.path;
73
74
  if (filePath) {
@@ -412,20 +413,16 @@ class HttpClient extends node_events_1.EventEmitter {
412
413
  || (0, utils_js_1.isReadable)(args.data);
413
414
  if (isGETOrHEAD) {
414
415
  if (!isStringOrBufferOrReadable) {
416
+ let query;
415
417
  if (args.nestedQuerystring) {
416
- const querystring = qs_1.default.stringify(args.data);
417
- // reset the requestUrl
418
- const href = requestUrl.href;
419
- requestUrl = new URL(href + (href.includes('?') ? '&' : '?') + querystring);
418
+ query = qs_1.default.stringify(args.data);
420
419
  }
421
420
  else {
422
- for (const field in args.data) {
423
- const fieldValue = args.data[field];
424
- if (fieldValue === undefined)
425
- continue;
426
- requestUrl.searchParams.append(field, fieldValue);
427
- }
421
+ query = node_querystring_1.default.stringify(args.data);
428
422
  }
423
+ // reset the requestUrl
424
+ const href = requestUrl.href;
425
+ requestUrl = new URL(href + (href.includes('?') ? '&' : '?') + query);
429
426
  }
430
427
  }
431
428
  else {
@@ -56,6 +56,21 @@ node_net_1.Socket.prototype.destroy = function (err) {
56
56
  }
57
57
  return this[kDestroy](err);
58
58
  };
59
+ function getRequestOpaque(request, kHandler) {
60
+ if (!kHandler)
61
+ return;
62
+ const handler = request[kHandler];
63
+ // maxRedirects = 0 will get [Symbol(handler)]: RequestHandler {
64
+ // responseHeaders: null,
65
+ // opaque: {
66
+ // [Symbol(request id)]: 1,
67
+ // [Symbol(request start time)]: 465.0712921619415,
68
+ // [Symbol(enable request timing or not)]: true,
69
+ // [Symbol(request timing)]: [Object],
70
+ // [Symbol(request original opaque)]: undefined
71
+ // }
72
+ return handler?.opts?.opaque ?? handler?.opaque;
73
+ }
59
74
  function initDiagnosticsChannel() {
60
75
  // makre sure init global DiagnosticsChannel once
61
76
  if (initedDiagnosticsChannel)
@@ -75,7 +90,7 @@ function initDiagnosticsChannel() {
75
90
  }
76
91
  }
77
92
  }
78
- const opaque = request[kHandler]?.opts?.opaque;
93
+ const opaque = getRequestOpaque(request, kHandler);
79
94
  // ignore non HttpClient Request
80
95
  if (!opaque || !opaque[symbols_js_1.default.kRequestId])
81
96
  return;
@@ -129,9 +144,7 @@ function initDiagnosticsChannel() {
129
144
  // This message is published right before the first byte of the request is written to the socket.
130
145
  subscribe('undici:client:sendHeaders', (message, name) => {
131
146
  const { request, socket } = message;
132
- if (!kHandler)
133
- return;
134
- const opaque = request[kHandler]?.opts?.opaque;
147
+ const opaque = getRequestOpaque(request, kHandler);
135
148
  if (!opaque || !opaque[symbols_js_1.default.kRequestId])
136
149
  return;
137
150
  socket[symbols_js_1.default.kHandledRequests]++;
@@ -150,9 +163,7 @@ function initDiagnosticsChannel() {
150
163
  });
151
164
  subscribe('undici:request:bodySent', (message, name) => {
152
165
  const { request } = message;
153
- if (!kHandler)
154
- return;
155
- const opaque = request[kHandler]?.opts?.opaque;
166
+ const opaque = getRequestOpaque(request, kHandler);
156
167
  if (!opaque || !opaque[symbols_js_1.default.kRequestId])
157
168
  return;
158
169
  debug('[%s] Request#%d send body', name, opaque[symbols_js_1.default.kRequestId]);
@@ -163,9 +174,7 @@ function initDiagnosticsChannel() {
163
174
  // This message is published after the response headers have been received, i.e. the response has been completed.
164
175
  subscribe('undici:request:headers', (message, name) => {
165
176
  const { request, response } = message;
166
- if (!kHandler)
167
- return;
168
- const opaque = request[kHandler]?.opts?.opaque;
177
+ const opaque = getRequestOpaque(request, kHandler);
169
178
  if (!opaque || !opaque[symbols_js_1.default.kRequestId])
170
179
  return;
171
180
  // get socket from opaque
@@ -179,9 +188,7 @@ function initDiagnosticsChannel() {
179
188
  // This message is published after the response body and trailers have been received, i.e. the response has been completed.
180
189
  subscribe('undici:request:trailers', (message, name) => {
181
190
  const { request } = message;
182
- if (!kHandler)
183
- return;
184
- const opaque = request[kHandler]?.opts?.opaque;
191
+ const opaque = getRequestOpaque(request, kHandler);
185
192
  if (!opaque || !opaque[symbols_js_1.default.kRequestId])
186
193
  return;
187
194
  debug('[%s] Request#%d get response body and trailers', name, opaque[symbols_js_1.default.kRequestId]);
@@ -10,6 +10,7 @@ import { basename } from 'node:path';
10
10
  import { createReadStream } from 'node:fs';
11
11
  import { format as urlFormat } from 'node:url';
12
12
  import { performance } from 'node:perf_hooks';
13
+ import querystring from 'node:querystring';
13
14
  import { FormData as FormDataNative, request as undiciRequest, Agent, getGlobalDispatcher, } from 'undici';
14
15
  import undiciSymbols from 'undici/lib/core/symbols.js';
15
16
  import { FormData as FormDataNode } from 'formdata-node';
@@ -61,7 +62,7 @@ class BlobFromStream {
61
62
  return 'Blob';
62
63
  }
63
64
  }
64
- export const HEADER_USER_AGENT = createUserAgent('node-urllib', '3.22.1');
65
+ export const HEADER_USER_AGENT = createUserAgent('node-urllib', '3.22.3');
65
66
  function getFileName(stream) {
66
67
  const filePath = stream.path;
67
68
  if (filePath) {
@@ -406,20 +407,16 @@ export class HttpClient extends EventEmitter {
406
407
  || isReadable(args.data);
407
408
  if (isGETOrHEAD) {
408
409
  if (!isStringOrBufferOrReadable) {
410
+ let query;
409
411
  if (args.nestedQuerystring) {
410
- const querystring = qs.stringify(args.data);
411
- // reset the requestUrl
412
- const href = requestUrl.href;
413
- requestUrl = new URL(href + (href.includes('?') ? '&' : '?') + querystring);
412
+ query = qs.stringify(args.data);
414
413
  }
415
414
  else {
416
- for (const field in args.data) {
417
- const fieldValue = args.data[field];
418
- if (fieldValue === undefined)
419
- continue;
420
- requestUrl.searchParams.append(field, fieldValue);
421
- }
415
+ query = querystring.stringify(args.data);
422
416
  }
417
+ // reset the requestUrl
418
+ const href = requestUrl.href;
419
+ requestUrl = new URL(href + (href.includes('?') ? '&' : '?') + query);
423
420
  }
424
421
  }
425
422
  else {
@@ -50,6 +50,21 @@ Socket.prototype.destroy = function (err) {
50
50
  }
51
51
  return this[kDestroy](err);
52
52
  };
53
+ function getRequestOpaque(request, kHandler) {
54
+ if (!kHandler)
55
+ return;
56
+ const handler = request[kHandler];
57
+ // maxRedirects = 0 will get [Symbol(handler)]: RequestHandler {
58
+ // responseHeaders: null,
59
+ // opaque: {
60
+ // [Symbol(request id)]: 1,
61
+ // [Symbol(request start time)]: 465.0712921619415,
62
+ // [Symbol(enable request timing or not)]: true,
63
+ // [Symbol(request timing)]: [Object],
64
+ // [Symbol(request original opaque)]: undefined
65
+ // }
66
+ return handler?.opts?.opaque ?? handler?.opaque;
67
+ }
53
68
  export function initDiagnosticsChannel() {
54
69
  // makre sure init global DiagnosticsChannel once
55
70
  if (initedDiagnosticsChannel)
@@ -69,7 +84,7 @@ export function initDiagnosticsChannel() {
69
84
  }
70
85
  }
71
86
  }
72
- const opaque = request[kHandler]?.opts?.opaque;
87
+ const opaque = getRequestOpaque(request, kHandler);
73
88
  // ignore non HttpClient Request
74
89
  if (!opaque || !opaque[symbols.kRequestId])
75
90
  return;
@@ -123,9 +138,7 @@ export function initDiagnosticsChannel() {
123
138
  // This message is published right before the first byte of the request is written to the socket.
124
139
  subscribe('undici:client:sendHeaders', (message, name) => {
125
140
  const { request, socket } = message;
126
- if (!kHandler)
127
- return;
128
- const opaque = request[kHandler]?.opts?.opaque;
141
+ const opaque = getRequestOpaque(request, kHandler);
129
142
  if (!opaque || !opaque[symbols.kRequestId])
130
143
  return;
131
144
  socket[symbols.kHandledRequests]++;
@@ -144,9 +157,7 @@ export function initDiagnosticsChannel() {
144
157
  });
145
158
  subscribe('undici:request:bodySent', (message, name) => {
146
159
  const { request } = message;
147
- if (!kHandler)
148
- return;
149
- const opaque = request[kHandler]?.opts?.opaque;
160
+ const opaque = getRequestOpaque(request, kHandler);
150
161
  if (!opaque || !opaque[symbols.kRequestId])
151
162
  return;
152
163
  debug('[%s] Request#%d send body', name, opaque[symbols.kRequestId]);
@@ -157,9 +168,7 @@ export function initDiagnosticsChannel() {
157
168
  // This message is published after the response headers have been received, i.e. the response has been completed.
158
169
  subscribe('undici:request:headers', (message, name) => {
159
170
  const { request, response } = message;
160
- if (!kHandler)
161
- return;
162
- const opaque = request[kHandler]?.opts?.opaque;
171
+ const opaque = getRequestOpaque(request, kHandler);
163
172
  if (!opaque || !opaque[symbols.kRequestId])
164
173
  return;
165
174
  // get socket from opaque
@@ -173,9 +182,7 @@ export function initDiagnosticsChannel() {
173
182
  // This message is published after the response body and trailers have been received, i.e. the response has been completed.
174
183
  subscribe('undici:request:trailers', (message, name) => {
175
184
  const { request } = message;
176
- if (!kHandler)
177
- return;
178
- const opaque = request[kHandler]?.opts?.opaque;
185
+ const opaque = getRequestOpaque(request, kHandler);
179
186
  if (!opaque || !opaque[symbols.kRequestId])
180
187
  return;
181
188
  debug('[%s] Request#%d get response body and trailers', name, opaque[symbols.kRequestId]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "urllib",
3
- "version": "3.22.1",
3
+ "version": "3.22.3",
4
4
  "publishConfig": {
5
5
  "tag": "latest"
6
6
  },
@@ -55,7 +55,7 @@
55
55
  "pump": "^3.0.0",
56
56
  "qs": "^6.11.2",
57
57
  "type-fest": "^4.3.1",
58
- "undici": "^5.22.1",
58
+ "undici": "^5.28.2",
59
59
  "ylru": "^1.3.2"
60
60
  },
61
61
  "devDependencies": {
package/src/HttpClient.ts CHANGED
@@ -16,6 +16,7 @@ import { basename } from 'node:path';
16
16
  import { createReadStream } from 'node:fs';
17
17
  import { format as urlFormat } from 'node:url';
18
18
  import { performance } from 'node:perf_hooks';
19
+ import querystring from 'node:querystring';
19
20
  import {
20
21
  FormData as FormDataNative,
21
22
  request as undiciRequest,
@@ -503,18 +504,15 @@ export class HttpClient extends EventEmitter {
503
504
  || isReadable(args.data);
504
505
  if (isGETOrHEAD) {
505
506
  if (!isStringOrBufferOrReadable) {
507
+ let query;
506
508
  if (args.nestedQuerystring) {
507
- const querystring = qs.stringify(args.data);
508
- // reset the requestUrl
509
- const href = requestUrl.href;
510
- requestUrl = new URL(href + (href.includes('?') ? '&' : '?') + querystring);
509
+ query = qs.stringify(args.data);
511
510
  } else {
512
- for (const field in args.data) {
513
- const fieldValue = args.data[field];
514
- if (fieldValue === undefined) continue;
515
- requestUrl.searchParams.append(field, fieldValue);
516
- }
511
+ query = querystring.stringify(args.data);
517
512
  }
513
+ // reset the requestUrl
514
+ const href = requestUrl.href;
515
+ requestUrl = new URL(href + (href.includes('?') ? '&' : '?') + query);
518
516
  }
519
517
  } else {
520
518
  if (isStringOrBufferOrReadable) {
@@ -54,6 +54,21 @@ Socket.prototype.destroy = function(err?: any) {
54
54
  return this[kDestroy](err);
55
55
  };
56
56
 
57
+ function getRequestOpaque(request: DiagnosticsChannel.Request, kHandler?: symbol) {
58
+ if (!kHandler) return;
59
+ const handler = request[kHandler];
60
+ // maxRedirects = 0 will get [Symbol(handler)]: RequestHandler {
61
+ // responseHeaders: null,
62
+ // opaque: {
63
+ // [Symbol(request id)]: 1,
64
+ // [Symbol(request start time)]: 465.0712921619415,
65
+ // [Symbol(enable request timing or not)]: true,
66
+ // [Symbol(request timing)]: [Object],
67
+ // [Symbol(request original opaque)]: undefined
68
+ // }
69
+ return handler?.opts?.opaque ?? handler?.opaque;
70
+ }
71
+
57
72
  export function initDiagnosticsChannel() {
58
73
  // makre sure init global DiagnosticsChannel once
59
74
  if (initedDiagnosticsChannel) return;
@@ -73,7 +88,7 @@ export function initDiagnosticsChannel() {
73
88
  }
74
89
  }
75
90
  }
76
- const opaque = request[kHandler]?.opts?.opaque;
91
+ const opaque = getRequestOpaque(request, kHandler);
77
92
  // ignore non HttpClient Request
78
93
  if (!opaque || !opaque[symbols.kRequestId]) return;
79
94
  debug('[%s] Request#%d %s %s, path: %s, headers: %o',
@@ -131,8 +146,7 @@ export function initDiagnosticsChannel() {
131
146
  // This message is published right before the first byte of the request is written to the socket.
132
147
  subscribe('undici:client:sendHeaders', (message, name) => {
133
148
  const { request, socket } = message as DiagnosticsChannel.ClientSendHeadersMessage;
134
- if (!kHandler) return;
135
- const opaque = request[kHandler]?.opts?.opaque;
149
+ const opaque = getRequestOpaque(request, kHandler);
136
150
  if (!opaque || !opaque[symbols.kRequestId]) return;
137
151
 
138
152
  socket[symbols.kHandledRequests]++;
@@ -154,8 +168,7 @@ export function initDiagnosticsChannel() {
154
168
 
155
169
  subscribe('undici:request:bodySent', (message, name) => {
156
170
  const { request } = message as DiagnosticsChannel.RequestBodySentMessage;
157
- if (!kHandler) return;
158
- const opaque = request[kHandler]?.opts?.opaque;
171
+ const opaque = getRequestOpaque(request, kHandler);
159
172
  if (!opaque || !opaque[symbols.kRequestId]) return;
160
173
 
161
174
  debug('[%s] Request#%d send body', name, opaque[symbols.kRequestId]);
@@ -166,8 +179,7 @@ export function initDiagnosticsChannel() {
166
179
  // This message is published after the response headers have been received, i.e. the response has been completed.
167
180
  subscribe('undici:request:headers', (message, name) => {
168
181
  const { request, response } = message as DiagnosticsChannel.RequestHeadersMessage;
169
- if (!kHandler) return;
170
- const opaque = request[kHandler]?.opts?.opaque;
182
+ const opaque = getRequestOpaque(request, kHandler);
171
183
  if (!opaque || !opaque[symbols.kRequestId]) return;
172
184
 
173
185
  // get socket from opaque
@@ -184,8 +196,7 @@ export function initDiagnosticsChannel() {
184
196
  // This message is published after the response body and trailers have been received, i.e. the response has been completed.
185
197
  subscribe('undici:request:trailers', (message, name) => {
186
198
  const { request } = message as DiagnosticsChannel.RequestTrailersMessage;
187
- if (!kHandler) return;
188
- const opaque = request[kHandler]?.opts?.opaque;
199
+ const opaque = getRequestOpaque(request, kHandler);
189
200
  if (!opaque || !opaque[symbols.kRequestId]) return;
190
201
 
191
202
  debug('[%s] Request#%d get response body and trailers', name, opaque[symbols.kRequestId]);