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