urllib 3.12.0 → 3.13.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.
@@ -1,26 +1,14 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _BlobFromStream_stream, _BlobFromStream_type, _HttpClient_instances, _HttpClient_defaultArgs, _HttpClient_dispatcher, _HttpClient_requestInternal, _HttpClient_updateSocketInfo;
13
- import { EventEmitter } from 'events';
14
- import { STATUS_CODES } from 'http';
15
- import { debuglog } from 'util';
16
- import { createGunzip, createBrotliDecompress, gunzipSync, brotliDecompressSync, } from 'zlib';
17
- import { Blob } from 'buffer';
18
- import { Readable, pipeline } from 'stream';
19
- import stream from 'stream';
20
- import { basename } from 'path';
21
- import { createReadStream } from 'fs';
22
- import { format as urlFormat } from 'url';
23
- import { performance } from 'perf_hooks';
1
+ import { EventEmitter } from 'node:events';
2
+ import { STATUS_CODES } from 'node:http';
3
+ import { debuglog } from 'node:util';
4
+ import { createGunzip, createBrotliDecompress, gunzipSync, brotliDecompressSync, } from 'node:zlib';
5
+ import { Blob } from 'node:buffer';
6
+ import { Readable, pipeline } from 'node:stream';
7
+ import stream from 'node:stream';
8
+ import { basename } from 'node:path';
9
+ import { createReadStream } from 'node:fs';
10
+ import { format as urlFormat } from 'node:url';
11
+ import { performance } from 'node:perf_hooks';
24
12
  import { FormData as FormDataNative, request as undiciRequest, } from 'undici';
25
13
  import { FormData as FormDataNode } from 'formdata-node';
26
14
  import { FormDataEncoder } from 'form-data-encoder';
@@ -51,19 +39,19 @@ function noop() {
51
39
  const debug = debuglog('urllib:HttpClient');
52
40
  // https://github.com/octet-stream/form-data
53
41
  class BlobFromStream {
42
+ #stream;
43
+ #type;
54
44
  constructor(stream, type) {
55
- _BlobFromStream_stream.set(this, void 0);
56
- _BlobFromStream_type.set(this, void 0);
57
- __classPrivateFieldSet(this, _BlobFromStream_stream, stream, "f");
58
- __classPrivateFieldSet(this, _BlobFromStream_type, type, "f");
45
+ this.#stream = stream;
46
+ this.#type = type;
59
47
  }
60
48
  stream() {
61
- return __classPrivateFieldGet(this, _BlobFromStream_stream, "f");
49
+ return this.#stream;
62
50
  }
63
51
  get type() {
64
- return __classPrivateFieldGet(this, _BlobFromStream_type, "f");
52
+ return this.#type;
65
53
  }
66
- get [(_BlobFromStream_stream = new WeakMap(), _BlobFromStream_type = new WeakMap(), Symbol.toStringTag)]() {
54
+ get [Symbol.toStringTag]() {
67
55
  return 'Blob';
68
56
  }
69
57
  }
@@ -87,483 +75,483 @@ function defaultIsRetry(response) {
87
75
  return response.status >= 500;
88
76
  }
89
77
  export class HttpClient extends EventEmitter {
78
+ #defaultArgs;
79
+ #dispatcher;
90
80
  constructor(clientOptions) {
91
81
  super();
92
- _HttpClient_instances.add(this);
93
- _HttpClient_defaultArgs.set(this, void 0);
94
- _HttpClient_dispatcher.set(this, void 0);
95
- __classPrivateFieldSet(this, _HttpClient_defaultArgs, clientOptions?.defaultArgs, "f");
82
+ this.#defaultArgs = clientOptions?.defaultArgs;
96
83
  if (clientOptions?.lookup || clientOptions?.checkAddress || clientOptions?.connect) {
97
- __classPrivateFieldSet(this, _HttpClient_dispatcher, new HttpAgent({
84
+ this.#dispatcher = new HttpAgent({
98
85
  lookup: clientOptions.lookup,
99
86
  checkAddress: clientOptions.checkAddress,
100
87
  connect: clientOptions.connect,
101
- }), "f");
88
+ });
102
89
  }
103
90
  initDiagnosticsChannel();
104
91
  }
105
92
  async request(url, options) {
106
- return await __classPrivateFieldGet(this, _HttpClient_instances, "m", _HttpClient_requestInternal).call(this, url, options);
93
+ return await this.#requestInternal(url, options);
107
94
  }
108
95
  // alias to request, keep compatible with urlib@2 HttpClient.curl
109
96
  async curl(url, options) {
110
97
  return await this.request(url, options);
111
98
  }
112
- }
113
- _HttpClient_defaultArgs = new WeakMap(), _HttpClient_dispatcher = new WeakMap(), _HttpClient_instances = new WeakSet(), _HttpClient_requestInternal = async function _HttpClient_requestInternal(url, options, requestContext) {
114
- const requestId = globalId('HttpClientRequest');
115
- let requestUrl;
116
- if (typeof url === 'string') {
117
- if (!PROTO_RE.test(url)) {
118
- // Support `request('www.server.com')`
119
- url = 'http://' + url;
120
- }
121
- requestUrl = new URL(url);
122
- }
123
- else {
124
- if (!url.searchParams) {
125
- // url maybe url.parse(url) object in urllib2
126
- requestUrl = new URL(urlFormat(url));
127
- }
128
- else {
129
- requestUrl = url;
130
- }
131
- }
132
- const method = (options?.method ?? 'GET').toUpperCase();
133
- const originalHeaders = options?.headers;
134
- const headers = {};
135
- const args = {
136
- retry: 0,
137
- ...__classPrivateFieldGet(this, _HttpClient_defaultArgs, "f"),
138
- ...options,
139
- // keep method and headers exists on args for request event handler to easy use
140
- method,
141
- headers,
142
- };
143
- requestContext = {
144
- retries: 0,
145
- ...requestContext,
146
- };
147
- const requestStartTime = performance.now();
148
- // https://developer.chrome.com/docs/devtools/network/reference/?utm_source=devtools#timing-explanation
149
- const timing = {
150
- // socket assigned
151
- queuing: 0,
152
- // dns lookup time
153
- // dnslookup: 0,
154
- // socket connected
155
- connected: 0,
156
- // request headers sent
157
- requestHeadersSent: 0,
158
- // request sent, including headers and body
159
- requestSent: 0,
160
- // Time to first byte (TTFB), the response headers have been received
161
- waiting: 0,
162
- // the response body and trailers have been received
163
- contentDownload: 0,
164
- };
165
- const orginalOpaque = args.opaque;
166
- // using opaque to diagnostics channel, binding request and socket
167
- const internalOpaque = {
168
- [symbols.kRequestId]: requestId,
169
- [symbols.kRequestStartTime]: requestStartTime,
170
- [symbols.kEnableRequestTiming]: !!args.timing,
171
- [symbols.kRequestTiming]: timing,
172
- [symbols.kRequestOrginalOpaque]: orginalOpaque,
173
- };
174
- const reqMeta = {
175
- requestId,
176
- url: requestUrl.href,
177
- args,
178
- ctx: args.ctx,
179
- retries: requestContext.retries,
180
- };
181
- const socketInfo = {
182
- id: 0,
183
- localAddress: '',
184
- localPort: 0,
185
- remoteAddress: '',
186
- remotePort: 0,
187
- remoteFamily: '',
188
- bytesWritten: 0,
189
- bytesRead: 0,
190
- handledRequests: 0,
191
- handledResponses: 0,
192
- };
193
- // keep urllib createCallbackResponse style
194
- const resHeaders = {};
195
- let res = {
196
- status: -1,
197
- statusCode: -1,
198
- statusText: '',
199
- headers: resHeaders,
200
- size: 0,
201
- aborted: false,
202
- rt: 0,
203
- keepAliveSocket: true,
204
- requestUrls: [],
205
- timing,
206
- socket: socketInfo,
207
- };
208
- let headersTimeout = 5000;
209
- let bodyTimeout = 5000;
210
- if (args.timeout) {
211
- if (Array.isArray(args.timeout)) {
212
- headersTimeout = args.timeout[0] ?? headersTimeout;
213
- bodyTimeout = args.timeout[1] ?? bodyTimeout;
99
+ async #requestInternal(url, options, requestContext) {
100
+ const requestId = globalId('HttpClientRequest');
101
+ let requestUrl;
102
+ if (typeof url === 'string') {
103
+ if (!PROTO_RE.test(url)) {
104
+ // Support `request('www.server.com')`
105
+ url = 'http://' + url;
106
+ }
107
+ requestUrl = new URL(url);
214
108
  }
215
109
  else {
216
- headersTimeout = bodyTimeout = args.timeout;
217
- }
218
- }
219
- if (originalHeaders) {
220
- // convert headers to lower-case
221
- for (const name in originalHeaders) {
222
- headers[name.toLowerCase()] = originalHeaders[name];
110
+ if (!url.searchParams) {
111
+ // url maybe url.parse(url) object in urllib2
112
+ requestUrl = new URL(urlFormat(url));
113
+ }
114
+ else {
115
+ requestUrl = url;
116
+ }
223
117
  }
224
- }
225
- // hidden user-agent
226
- const hiddenUserAgent = 'user-agent' in headers && !headers['user-agent'];
227
- if (hiddenUserAgent) {
228
- delete headers['user-agent'];
229
- }
230
- else if (!headers['user-agent']) {
231
- // need to set user-agent
232
- headers['user-agent'] = HEADER_USER_AGENT;
233
- }
234
- // Alias to dataType = 'stream'
235
- if (args.streaming || args.customResponse) {
236
- args.dataType = 'stream';
237
- }
238
- if (args.dataType === 'json' && !headers.accept) {
239
- headers.accept = 'application/json';
240
- }
241
- // gzip alias to compressed
242
- if (args.gzip && args.compressed !== false) {
243
- args.compressed = true;
244
- }
245
- if (args.compressed && !headers['accept-encoding']) {
246
- headers['accept-encoding'] = 'gzip, br';
247
- }
248
- if (requestContext.retries > 0) {
249
- headers['x-urllib-retry'] = `${requestContext.retries}/${args.retry}`;
250
- }
251
- if (args.auth && !headers.authorization) {
252
- headers.authorization = `Basic ${Buffer.from(args.auth).toString('base64')}`;
253
- }
254
- try {
255
- const requestOptions = {
118
+ const method = (options?.method ?? 'GET').toUpperCase();
119
+ const originalHeaders = options?.headers;
120
+ const headers = {};
121
+ const args = {
122
+ retry: 0,
123
+ ...this.#defaultArgs,
124
+ ...options,
125
+ // keep method and headers exists on args for request event handler to easy use
256
126
  method,
257
- maxRedirections: args.maxRedirects ?? 10,
258
- headersTimeout,
259
127
  headers,
260
- bodyTimeout,
261
- opaque: internalOpaque,
262
- dispatcher: args.dispatcher ?? __classPrivateFieldGet(this, _HttpClient_dispatcher, "f"),
263
128
  };
264
- if (typeof args.reset === 'boolean') {
265
- requestOptions.reset = args.reset;
266
- }
267
- if (args.followRedirect === false) {
268
- requestOptions.maxRedirections = 0;
269
- }
270
- const isGETOrHEAD = requestOptions.method === 'GET' || requestOptions.method === 'HEAD';
271
- // alias to args.content
272
- if (args.stream && !args.content) {
273
- // convert old style stream to new stream
274
- // https://nodejs.org/dist/latest-v18.x/docs/api/stream.html#readablewrapstream
275
- if (isReadable(args.stream) && !(args.stream instanceof Readable)) {
276
- debug('Request#%d convert old style stream to Readable', requestId);
277
- args.stream = new Readable().wrap(args.stream);
129
+ requestContext = {
130
+ retries: 0,
131
+ ...requestContext,
132
+ };
133
+ const requestStartTime = performance.now();
134
+ // https://developer.chrome.com/docs/devtools/network/reference/?utm_source=devtools#timing-explanation
135
+ const timing = {
136
+ // socket assigned
137
+ queuing: 0,
138
+ // dns lookup time
139
+ // dnslookup: 0,
140
+ // socket connected
141
+ connected: 0,
142
+ // request headers sent
143
+ requestHeadersSent: 0,
144
+ // request sent, including headers and body
145
+ requestSent: 0,
146
+ // Time to first byte (TTFB), the response headers have been received
147
+ waiting: 0,
148
+ // the response body and trailers have been received
149
+ contentDownload: 0,
150
+ };
151
+ const orginalOpaque = args.opaque;
152
+ // using opaque to diagnostics channel, binding request and socket
153
+ const internalOpaque = {
154
+ [symbols.kRequestId]: requestId,
155
+ [symbols.kRequestStartTime]: requestStartTime,
156
+ [symbols.kEnableRequestTiming]: !!args.timing,
157
+ [symbols.kRequestTiming]: timing,
158
+ [symbols.kRequestOrginalOpaque]: orginalOpaque,
159
+ };
160
+ const reqMeta = {
161
+ requestId,
162
+ url: requestUrl.href,
163
+ args,
164
+ ctx: args.ctx,
165
+ retries: requestContext.retries,
166
+ };
167
+ const socketInfo = {
168
+ id: 0,
169
+ localAddress: '',
170
+ localPort: 0,
171
+ remoteAddress: '',
172
+ remotePort: 0,
173
+ remoteFamily: '',
174
+ bytesWritten: 0,
175
+ bytesRead: 0,
176
+ handledRequests: 0,
177
+ handledResponses: 0,
178
+ };
179
+ // keep urllib createCallbackResponse style
180
+ const resHeaders = {};
181
+ let res = {
182
+ status: -1,
183
+ statusCode: -1,
184
+ statusText: '',
185
+ headers: resHeaders,
186
+ size: 0,
187
+ aborted: false,
188
+ rt: 0,
189
+ keepAliveSocket: true,
190
+ requestUrls: [],
191
+ timing,
192
+ socket: socketInfo,
193
+ };
194
+ let headersTimeout = 5000;
195
+ let bodyTimeout = 5000;
196
+ if (args.timeout) {
197
+ if (Array.isArray(args.timeout)) {
198
+ headersTimeout = args.timeout[0] ?? headersTimeout;
199
+ bodyTimeout = args.timeout[1] ?? bodyTimeout;
278
200
  }
279
- else if (args.stream instanceof FormStream) {
280
- debug('Request#%d convert formstream to Readable', requestId);
281
- args.stream = new Readable().wrap(args.stream);
201
+ else {
202
+ headersTimeout = bodyTimeout = args.timeout;
282
203
  }
283
- args.content = args.stream;
284
204
  }
285
- if (args.files) {
286
- if (isGETOrHEAD) {
287
- requestOptions.method = 'POST';
288
- }
289
- const formData = new FormData();
290
- const uploadFiles = [];
291
- if (Array.isArray(args.files)) {
292
- for (const [index, file] of args.files.entries()) {
293
- const field = index === 0 ? 'file' : `file${index}`;
294
- uploadFiles.push([field, file]);
295
- }
205
+ if (originalHeaders) {
206
+ // convert headers to lower-case
207
+ for (const name in originalHeaders) {
208
+ headers[name.toLowerCase()] = originalHeaders[name];
296
209
  }
297
- else if (args.files instanceof Readable || isReadable(args.files)) {
298
- uploadFiles.push(['file', args.files]);
210
+ }
211
+ // hidden user-agent
212
+ const hiddenUserAgent = 'user-agent' in headers && !headers['user-agent'];
213
+ if (hiddenUserAgent) {
214
+ delete headers['user-agent'];
215
+ }
216
+ else if (!headers['user-agent']) {
217
+ // need to set user-agent
218
+ headers['user-agent'] = HEADER_USER_AGENT;
219
+ }
220
+ // Alias to dataType = 'stream'
221
+ if (args.streaming || args.customResponse) {
222
+ args.dataType = 'stream';
223
+ }
224
+ if (args.dataType === 'json' && !headers.accept) {
225
+ headers.accept = 'application/json';
226
+ }
227
+ // gzip alias to compressed
228
+ if (args.gzip && args.compressed !== false) {
229
+ args.compressed = true;
230
+ }
231
+ if (args.compressed && !headers['accept-encoding']) {
232
+ headers['accept-encoding'] = 'gzip, br';
233
+ }
234
+ if (requestContext.retries > 0) {
235
+ headers['x-urllib-retry'] = `${requestContext.retries}/${args.retry}`;
236
+ }
237
+ if (args.auth && !headers.authorization) {
238
+ headers.authorization = `Basic ${Buffer.from(args.auth).toString('base64')}`;
239
+ }
240
+ try {
241
+ const requestOptions = {
242
+ method,
243
+ maxRedirections: args.maxRedirects ?? 10,
244
+ headersTimeout,
245
+ headers,
246
+ bodyTimeout,
247
+ opaque: internalOpaque,
248
+ dispatcher: args.dispatcher ?? this.#dispatcher,
249
+ };
250
+ if (typeof args.reset === 'boolean') {
251
+ requestOptions.reset = args.reset;
299
252
  }
300
- else if (typeof args.files === 'string' || Buffer.isBuffer(args.files)) {
301
- uploadFiles.push(['file', args.files]);
253
+ if (args.followRedirect === false) {
254
+ requestOptions.maxRedirections = 0;
302
255
  }
303
- else if (typeof args.files === 'object') {
304
- for (const field in args.files) {
305
- uploadFiles.push([field, args.files[field]]);
256
+ const isGETOrHEAD = requestOptions.method === 'GET' || requestOptions.method === 'HEAD';
257
+ // alias to args.content
258
+ if (args.stream && !args.content) {
259
+ // convert old style stream to new stream
260
+ // https://nodejs.org/dist/latest-v18.x/docs/api/stream.html#readablewrapstream
261
+ if (isReadable(args.stream) && !(args.stream instanceof Readable)) {
262
+ debug('Request#%d convert old style stream to Readable', requestId);
263
+ args.stream = new Readable().wrap(args.stream);
306
264
  }
307
- }
308
- // set normal fields first
309
- if (args.data) {
310
- for (const field in args.data) {
311
- formData.append(field, args.data[field]);
265
+ else if (args.stream instanceof FormStream) {
266
+ debug('Request#%d convert formstream to Readable', requestId);
267
+ args.stream = new Readable().wrap(args.stream);
312
268
  }
269
+ args.content = args.stream;
313
270
  }
314
- for (const [index, [field, file]] of uploadFiles.entries()) {
315
- if (typeof file === 'string') {
316
- // FIXME: support non-ascii filename
317
- // const fileName = encodeURIComponent(basename(file));
318
- // formData.append(field, await fileFromPath(file, `utf-8''${fileName}`, { type: mime.lookup(fileName) || '' }));
319
- const fileName = basename(file);
320
- const fileReadable = createReadStream(file);
321
- formData.append(field, new BlobFromStream(fileReadable, mime.lookup(fileName) || ''), fileName);
271
+ if (args.files) {
272
+ if (isGETOrHEAD) {
273
+ requestOptions.method = 'POST';
322
274
  }
323
- else if (Buffer.isBuffer(file)) {
324
- formData.append(field, new Blob([file]), `bufferfile${index}`);
275
+ const formData = new FormData();
276
+ const uploadFiles = [];
277
+ if (Array.isArray(args.files)) {
278
+ for (const [index, file] of args.files.entries()) {
279
+ const field = index === 0 ? 'file' : `file${index}`;
280
+ uploadFiles.push([field, file]);
281
+ }
325
282
  }
326
- else if (file instanceof Readable || isReadable(file)) {
327
- const fileName = getFileName(file) || `streamfile${index}`;
328
- formData.append(field, new BlobFromStream(file, mime.lookup(fileName) || ''), fileName);
283
+ else if (args.files instanceof Readable || isReadable(args.files)) {
284
+ uploadFiles.push(['file', args.files]);
329
285
  }
330
- }
331
- if (FormDataNative) {
332
- requestOptions.body = formData;
333
- }
334
- else {
335
- // Node.js 14 does not support spec-compliant FormData
336
- // https://github.com/octet-stream/form-data#usage
337
- const encoder = new FormDataEncoder(formData);
338
- Object.assign(headers, encoder.headers);
339
- // fix "Content-Length":"NaN"
340
- delete headers['Content-Length'];
341
- requestOptions.body = Readable.from(encoder);
342
- }
343
- }
344
- else if (args.content) {
345
- if (!isGETOrHEAD) {
346
- // handle content
347
- requestOptions.body = args.content;
348
- if (args.contentType) {
349
- headers['content-type'] = args.contentType;
286
+ else if (typeof args.files === 'string' || Buffer.isBuffer(args.files)) {
287
+ uploadFiles.push(['file', args.files]);
350
288
  }
351
- else if (typeof args.content === 'string' && !headers['content-type']) {
352
- headers['content-type'] = 'text/plain;charset=UTF-8';
289
+ else if (typeof args.files === 'object') {
290
+ for (const field in args.files) {
291
+ uploadFiles.push([field, args.files[field]]);
292
+ }
353
293
  }
354
- }
355
- }
356
- else if (args.data) {
357
- const isStringOrBufferOrReadable = typeof args.data === 'string'
358
- || Buffer.isBuffer(args.data)
359
- || isReadable(args.data);
360
- if (isGETOrHEAD) {
361
- if (!isStringOrBufferOrReadable) {
294
+ // set normal fields first
295
+ if (args.data) {
362
296
  for (const field in args.data) {
363
- requestUrl.searchParams.append(field, args.data[field]);
297
+ formData.append(field, args.data[field]);
364
298
  }
365
299
  }
366
- }
367
- else {
368
- if (isStringOrBufferOrReadable) {
369
- requestOptions.body = args.data;
300
+ for (const [index, [field, file]] of uploadFiles.entries()) {
301
+ if (typeof file === 'string') {
302
+ // FIXME: support non-ascii filename
303
+ // const fileName = encodeURIComponent(basename(file));
304
+ // formData.append(field, await fileFromPath(file, `utf-8''${fileName}`, { type: mime.lookup(fileName) || '' }));
305
+ const fileName = basename(file);
306
+ const fileReadable = createReadStream(file);
307
+ formData.append(field, new BlobFromStream(fileReadable, mime.lookup(fileName) || ''), fileName);
308
+ }
309
+ else if (Buffer.isBuffer(file)) {
310
+ formData.append(field, new Blob([file]), `bufferfile${index}`);
311
+ }
312
+ else if (file instanceof Readable || isReadable(file)) {
313
+ const fileName = getFileName(file) || `streamfile${index}`;
314
+ formData.append(field, new BlobFromStream(file, mime.lookup(fileName) || ''), fileName);
315
+ }
316
+ }
317
+ if (FormDataNative) {
318
+ requestOptions.body = formData;
370
319
  }
371
320
  else {
372
- if (args.contentType === 'json'
373
- || args.contentType === 'application/json'
374
- || headers['content-type']?.startsWith('application/json')) {
375
- requestOptions.body = JSON.stringify(args.data);
376
- if (!headers['content-type']) {
377
- headers['content-type'] = 'application/json';
321
+ // Node.js 14 does not support spec-compliant FormData
322
+ // https://github.com/octet-stream/form-data#usage
323
+ const encoder = new FormDataEncoder(formData);
324
+ Object.assign(headers, encoder.headers);
325
+ // fix "Content-Length":"NaN"
326
+ delete headers['Content-Length'];
327
+ requestOptions.body = Readable.from(encoder);
328
+ }
329
+ }
330
+ else if (args.content) {
331
+ if (!isGETOrHEAD) {
332
+ // handle content
333
+ requestOptions.body = args.content;
334
+ if (args.contentType) {
335
+ headers['content-type'] = args.contentType;
336
+ }
337
+ else if (typeof args.content === 'string' && !headers['content-type']) {
338
+ headers['content-type'] = 'text/plain;charset=UTF-8';
339
+ }
340
+ }
341
+ }
342
+ else if (args.data) {
343
+ const isStringOrBufferOrReadable = typeof args.data === 'string'
344
+ || Buffer.isBuffer(args.data)
345
+ || isReadable(args.data);
346
+ if (isGETOrHEAD) {
347
+ if (!isStringOrBufferOrReadable) {
348
+ for (const field in args.data) {
349
+ requestUrl.searchParams.append(field, args.data[field]);
378
350
  }
379
351
  }
352
+ }
353
+ else {
354
+ if (isStringOrBufferOrReadable) {
355
+ requestOptions.body = args.data;
356
+ }
380
357
  else {
381
- headers['content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
382
- requestOptions.body = new URLSearchParams(args.data).toString();
358
+ if (args.contentType === 'json'
359
+ || args.contentType === 'application/json'
360
+ || headers['content-type']?.startsWith('application/json')) {
361
+ requestOptions.body = JSON.stringify(args.data);
362
+ if (!headers['content-type']) {
363
+ headers['content-type'] = 'application/json';
364
+ }
365
+ }
366
+ else {
367
+ headers['content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
368
+ requestOptions.body = new URLSearchParams(args.data).toString();
369
+ }
383
370
  }
384
371
  }
385
372
  }
386
- }
387
- debug('Request#%d %s %s, headers: %j, headersTimeout: %s, bodyTimeout: %s', requestId, requestOptions.method, requestUrl.href, headers, headersTimeout, bodyTimeout);
388
- requestOptions.headers = headers;
389
- if (this.listenerCount('request') > 0) {
390
- this.emit('request', reqMeta);
391
- }
392
- let response = await undiciRequest(requestUrl, requestOptions);
393
- if (response.statusCode === 401 && response.headers['www-authenticate'] &&
394
- !requestOptions.headers.authorization && args.digestAuth) {
395
- // handle digest auth
396
- const authenticateHeaders = response.headers['www-authenticate'];
397
- const authenticate = Array.isArray(authenticateHeaders)
398
- ? authenticateHeaders.find(authHeader => authHeader.startsWith('Digest '))
399
- : authenticateHeaders;
400
- if (authenticate && authenticate.startsWith('Digest ')) {
401
- debug('Request#%d %s: got digest auth header WWW-Authenticate: %s', requestId, requestUrl.href, authenticate);
402
- requestOptions.headers.authorization = digestAuthHeader(requestOptions.method, `${requestUrl.pathname}${requestUrl.search}`, authenticate, args.digestAuth);
403
- debug('Request#%d %s: auth with digest header: %s', requestId, url, requestOptions.headers.authorization);
404
- if (Array.isArray(response.headers['set-cookie'])) {
405
- // FIXME: merge exists cookie header
406
- requestOptions.headers.cookie = response.headers['set-cookie'].join(';');
407
- }
408
- response = await undiciRequest(requestUrl, requestOptions);
373
+ debug('Request#%d %s %s, headers: %j, headersTimeout: %s, bodyTimeout: %s', requestId, requestOptions.method, requestUrl.href, headers, headersTimeout, bodyTimeout);
374
+ requestOptions.headers = headers;
375
+ if (this.listenerCount('request') > 0) {
376
+ this.emit('request', reqMeta);
409
377
  }
410
- }
411
- const context = response.context;
412
- let lastUrl = '';
413
- if (context?.history) {
414
- for (const urlObject of context?.history) {
415
- res.requestUrls.push(urlObject.href);
416
- lastUrl = urlObject.href;
378
+ let response = await undiciRequest(requestUrl, requestOptions);
379
+ if (response.statusCode === 401 && response.headers['www-authenticate'] &&
380
+ !requestOptions.headers.authorization && args.digestAuth) {
381
+ // handle digest auth
382
+ const authenticateHeaders = response.headers['www-authenticate'];
383
+ const authenticate = Array.isArray(authenticateHeaders)
384
+ ? authenticateHeaders.find(authHeader => authHeader.startsWith('Digest '))
385
+ : authenticateHeaders;
386
+ if (authenticate && authenticate.startsWith('Digest ')) {
387
+ debug('Request#%d %s: got digest auth header WWW-Authenticate: %s', requestId, requestUrl.href, authenticate);
388
+ requestOptions.headers.authorization = digestAuthHeader(requestOptions.method, `${requestUrl.pathname}${requestUrl.search}`, authenticate, args.digestAuth);
389
+ debug('Request#%d %s: auth with digest header: %s', requestId, url, requestOptions.headers.authorization);
390
+ if (Array.isArray(response.headers['set-cookie'])) {
391
+ // FIXME: merge exists cookie header
392
+ requestOptions.headers.cookie = response.headers['set-cookie'].join(';');
393
+ }
394
+ response = await undiciRequest(requestUrl, requestOptions);
395
+ }
417
396
  }
418
- }
419
- else {
420
- res.requestUrls.push(requestUrl.href);
421
- lastUrl = requestUrl.href;
422
- }
423
- const contentEncoding = response.headers['content-encoding'];
424
- const isCompressedContent = contentEncoding === 'gzip' || contentEncoding === 'br';
425
- res.headers = response.headers;
426
- res.status = res.statusCode = response.statusCode;
427
- res.statusText = STATUS_CODES[res.status] || '';
428
- if (res.headers['content-length']) {
429
- res.size = parseInt(res.headers['content-length']);
430
- }
431
- let data = null;
432
- if (args.dataType === 'stream') {
433
- // streaming mode will disable retry
434
- args.retry = 0;
435
- // only auto decompress on request args.compressed = true
436
- if (args.compressed === true && isCompressedContent) {
437
- // gzip or br
438
- const decoder = contentEncoding === 'gzip' ? createGunzip() : createBrotliDecompress();
439
- res = Object.assign(pipeline(response.body, decoder, noop), res);
397
+ const context = response.context;
398
+ let lastUrl = '';
399
+ if (context?.history) {
400
+ for (const urlObject of context?.history) {
401
+ res.requestUrls.push(urlObject.href);
402
+ lastUrl = urlObject.href;
403
+ }
440
404
  }
441
405
  else {
442
- res = Object.assign(response.body, res);
406
+ res.requestUrls.push(requestUrl.href);
407
+ lastUrl = requestUrl.href;
443
408
  }
444
- }
445
- else if (args.writeStream) {
446
- // streaming mode will disable retry
447
- args.retry = 0;
448
- if (args.compressed === true && isCompressedContent) {
449
- const decoder = contentEncoding === 'gzip' ? createGunzip() : createBrotliDecompress();
450
- await pipelinePromise(response.body, decoder, args.writeStream);
409
+ const contentEncoding = response.headers['content-encoding'];
410
+ const isCompressedContent = contentEncoding === 'gzip' || contentEncoding === 'br';
411
+ res.headers = response.headers;
412
+ res.status = res.statusCode = response.statusCode;
413
+ res.statusText = STATUS_CODES[res.status] || '';
414
+ if (res.headers['content-length']) {
415
+ res.size = parseInt(res.headers['content-length']);
451
416
  }
452
- else {
453
- await pipelinePromise(response.body, args.writeStream);
454
- }
455
- }
456
- else {
457
- // buffer
458
- data = Buffer.from(await response.body.arrayBuffer());
459
- if (isCompressedContent && data.length > 0) {
460
- try {
461
- data = contentEncoding === 'gzip' ? gunzipSync(data) : brotliDecompressSync(data);
417
+ let data = null;
418
+ if (args.dataType === 'stream') {
419
+ // streaming mode will disable retry
420
+ args.retry = 0;
421
+ // only auto decompress on request args.compressed = true
422
+ if (args.compressed === true && isCompressedContent) {
423
+ // gzip or br
424
+ const decoder = contentEncoding === 'gzip' ? createGunzip() : createBrotliDecompress();
425
+ res = Object.assign(pipeline(response.body, decoder, noop), res);
462
426
  }
463
- catch (err) {
464
- if (err.name === 'Error') {
465
- err.name = 'UnzipError';
466
- }
467
- throw err;
427
+ else {
428
+ res = Object.assign(response.body, res);
468
429
  }
469
430
  }
470
- if (args.dataType === 'text' || args.dataType === 'html') {
471
- data = data.toString();
472
- }
473
- else if (args.dataType === 'json') {
474
- if (data.length === 0) {
475
- data = null;
431
+ else if (args.writeStream) {
432
+ // streaming mode will disable retry
433
+ args.retry = 0;
434
+ if (args.compressed === true && isCompressedContent) {
435
+ const decoder = contentEncoding === 'gzip' ? createGunzip() : createBrotliDecompress();
436
+ await pipelinePromise(response.body, decoder, args.writeStream);
476
437
  }
477
438
  else {
478
- data = parseJSON(data.toString(), args.fixJSONCtlChars);
439
+ await pipelinePromise(response.body, args.writeStream);
479
440
  }
480
441
  }
481
- }
482
- res.rt = performanceTime(requestStartTime);
483
- // get real socket info from internalOpaque
484
- __classPrivateFieldGet(this, _HttpClient_instances, "m", _HttpClient_updateSocketInfo).call(this, socketInfo, internalOpaque);
485
- const clientResponse = {
486
- opaque: orginalOpaque,
487
- data,
488
- status: res.status,
489
- statusCode: res.status,
490
- statusText: res.statusText,
491
- headers: res.headers,
492
- url: lastUrl,
493
- redirected: res.requestUrls.length > 1,
494
- requestUrls: res.requestUrls,
495
- res,
496
- };
497
- if (args.retry > 0 && requestContext.retries < args.retry) {
498
- const isRetry = args.isRetry ?? defaultIsRetry;
499
- if (isRetry(clientResponse)) {
500
- if (args.retryDelay) {
501
- await sleep(args.retryDelay);
442
+ else {
443
+ // buffer
444
+ data = Buffer.from(await response.body.arrayBuffer());
445
+ if (isCompressedContent && data.length > 0) {
446
+ try {
447
+ data = contentEncoding === 'gzip' ? gunzipSync(data) : brotliDecompressSync(data);
448
+ }
449
+ catch (err) {
450
+ if (err.name === 'Error') {
451
+ err.name = 'UnzipError';
452
+ }
453
+ throw err;
454
+ }
455
+ }
456
+ if (args.dataType === 'text' || args.dataType === 'html') {
457
+ data = data.toString();
458
+ }
459
+ else if (args.dataType === 'json') {
460
+ if (data.length === 0) {
461
+ data = null;
462
+ }
463
+ else {
464
+ data = parseJSON(data.toString(), args.fixJSONCtlChars);
465
+ }
502
466
  }
503
- requestContext.retries++;
504
- return await __classPrivateFieldGet(this, _HttpClient_instances, "m", _HttpClient_requestInternal).call(this, url, options, requestContext);
505
467
  }
506
- }
507
- if (this.listenerCount('response') > 0) {
508
- this.emit('response', {
509
- requestId,
510
- error: null,
511
- ctx: args.ctx,
512
- req: {
513
- ...reqMeta,
514
- options: args,
515
- },
468
+ res.rt = performanceTime(requestStartTime);
469
+ // get real socket info from internalOpaque
470
+ this.#updateSocketInfo(socketInfo, internalOpaque);
471
+ const clientResponse = {
472
+ opaque: orginalOpaque,
473
+ data,
474
+ status: res.status,
475
+ statusCode: res.status,
476
+ statusText: res.statusText,
477
+ headers: res.headers,
478
+ url: lastUrl,
479
+ redirected: res.requestUrls.length > 1,
480
+ requestUrls: res.requestUrls,
516
481
  res,
517
- });
518
- }
519
- return clientResponse;
520
- }
521
- catch (e) {
522
- debug('Request#%d throw error: %s', requestId, e);
523
- let err = e;
524
- if (err.name === 'HeadersTimeoutError') {
525
- err = new HttpClientRequestTimeoutError(headersTimeout, { cause: e });
526
- }
527
- else if (err.name === 'BodyTimeoutError') {
528
- err = new HttpClientRequestTimeoutError(bodyTimeout, { cause: e });
529
- }
530
- err.opaque = orginalOpaque;
531
- err.status = res.status;
532
- err.headers = res.headers;
533
- err.res = res;
534
- // make sure requestUrls not empty
535
- if (res.requestUrls.length === 0) {
536
- res.requestUrls.push(requestUrl.href);
482
+ };
483
+ if (args.retry > 0 && requestContext.retries < args.retry) {
484
+ const isRetry = args.isRetry ?? defaultIsRetry;
485
+ if (isRetry(clientResponse)) {
486
+ if (args.retryDelay) {
487
+ await sleep(args.retryDelay);
488
+ }
489
+ requestContext.retries++;
490
+ return await this.#requestInternal(url, options, requestContext);
491
+ }
492
+ }
493
+ if (this.listenerCount('response') > 0) {
494
+ this.emit('response', {
495
+ requestId,
496
+ error: null,
497
+ ctx: args.ctx,
498
+ req: {
499
+ ...reqMeta,
500
+ options: args,
501
+ },
502
+ res,
503
+ });
504
+ }
505
+ return clientResponse;
537
506
  }
538
- res.rt = performanceTime(requestStartTime);
539
- __classPrivateFieldGet(this, _HttpClient_instances, "m", _HttpClient_updateSocketInfo).call(this, socketInfo, internalOpaque);
540
- if (this.listenerCount('response') > 0) {
541
- this.emit('response', {
542
- requestId,
543
- error: err,
544
- ctx: args.ctx,
545
- req: {
546
- ...reqMeta,
547
- options: args,
548
- },
549
- res,
550
- });
507
+ catch (e) {
508
+ debug('Request#%d throw error: %s', requestId, e);
509
+ let err = e;
510
+ if (err.name === 'HeadersTimeoutError') {
511
+ err = new HttpClientRequestTimeoutError(headersTimeout, { cause: e });
512
+ }
513
+ else if (err.name === 'BodyTimeoutError') {
514
+ err = new HttpClientRequestTimeoutError(bodyTimeout, { cause: e });
515
+ }
516
+ err.opaque = orginalOpaque;
517
+ err.status = res.status;
518
+ err.headers = res.headers;
519
+ err.res = res;
520
+ // make sure requestUrls not empty
521
+ if (res.requestUrls.length === 0) {
522
+ res.requestUrls.push(requestUrl.href);
523
+ }
524
+ res.rt = performanceTime(requestStartTime);
525
+ this.#updateSocketInfo(socketInfo, internalOpaque);
526
+ if (this.listenerCount('response') > 0) {
527
+ this.emit('response', {
528
+ requestId,
529
+ error: err,
530
+ ctx: args.ctx,
531
+ req: {
532
+ ...reqMeta,
533
+ options: args,
534
+ },
535
+ res,
536
+ });
537
+ }
538
+ throw err;
551
539
  }
552
- throw err;
553
540
  }
554
- }, _HttpClient_updateSocketInfo = function _HttpClient_updateSocketInfo(socketInfo, internalOpaque) {
555
- const socket = internalOpaque[symbols.kRequestSocket];
556
- if (socket) {
557
- socketInfo.id = socket[symbols.kSocketId];
558
- socketInfo.handledRequests = socket[symbols.kHandledRequests];
559
- socketInfo.handledResponses = socket[symbols.kHandledResponses];
560
- socketInfo.localAddress = socket.localAddress;
561
- socketInfo.localPort = socket.localPort;
562
- socketInfo.remoteAddress = socket.remoteAddress;
563
- socketInfo.remotePort = socket.remotePort;
564
- socketInfo.remoteFamily = socket.remoteFamily;
565
- socketInfo.bytesRead = socket.bytesRead;
566
- socketInfo.bytesWritten = socket.bytesWritten;
541
+ #updateSocketInfo(socketInfo, internalOpaque) {
542
+ const socket = internalOpaque[symbols.kRequestSocket];
543
+ if (socket) {
544
+ socketInfo.id = socket[symbols.kSocketId];
545
+ socketInfo.handledRequests = socket[symbols.kHandledRequests];
546
+ socketInfo.handledResponses = socket[symbols.kHandledResponses];
547
+ socketInfo.localAddress = socket.localAddress;
548
+ socketInfo.localPort = socket.localPort;
549
+ socketInfo.remoteAddress = socket.remoteAddress;
550
+ socketInfo.remotePort = socket.remotePort;
551
+ socketInfo.remoteFamily = socket.remoteFamily;
552
+ socketInfo.bytesRead = socket.bytesRead;
553
+ socketInfo.bytesWritten = socket.bytesWritten;
554
+ }
567
555
  }
568
- };
556
+ }
569
557
  //# sourceMappingURL=HttpClient.js.map