urllib 3.0.0-alpha.1 → 3.0.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/README.md CHANGED
@@ -79,58 +79,27 @@ console.log('status: %s, body size: %d, headers: %j', res.statusCode, data.lengt
79
79
  - ***options*** Object - Optional
80
80
  - ***method*** String - Request method, defaults to `GET`. Could be `GET`, `POST`, `DELETE` or `PUT`. Alias 'type'.
81
81
  - ***data*** Object - Data to be sent. Will be stringify automatically.
82
- - ***dataAsQueryString*** Boolean - Force convert `data` to query string.
83
82
  - ***content*** String | [Buffer](http://nodejs.org/api/buffer.html) - Manually set the content of payload. If set, `data` will be ignored.
84
83
  - ***stream*** [stream.Readable](http://nodejs.org/api/stream.html#stream_class_stream_readable) - Stream to be pipe to the remote. If set, `data` and `content` will be ignored.
85
84
  - ***writeStream*** [stream.Writable](http://nodejs.org/api/stream.html#stream_class_stream_writable) - A writable stream to be piped by the response stream. Responding data will be write to this stream and `callback` will be called with `data` set `null` after finished writing.
86
85
  - ***files*** {Array<ReadStream|Buffer|String> | Object | ReadStream | Buffer | String - The files will send with `multipart/form-data` format, base on `formstream`. If `method` not set, will use `POST` method by default.
87
- - ***consumeWriteStream*** [true] - consume the writeStream, invoke the callback after writeStream close.
88
86
  - ***contentType*** String - Type of request data. Could be `json` (**Notes**: not use `application/json` here). If it's `json`, will auto set `Content-Type: application/json` header.
89
- - ***nestedQuerystring*** Boolean - urllib default use querystring to stringify form data which don't support nested object, will use [qs](https://github.com/ljharb/qs) instead of querystring to support nested object by set this option to true.
90
87
  - ***dataType*** String - Type of response data. Could be `text` or `json`. If it's `text`, the `callback`ed `data` would be a String. If it's `json`, the `data` of callback would be a parsed JSON Object and will auto set `Accept: application/json` header. Default `callback`ed `data` would be a `Buffer`.
91
88
  - **fixJSONCtlChars** Boolean - Fix the control characters (U+0000 through U+001F) before JSON parse response. Default is `false`.
92
89
  - ***headers*** Object - Request headers.
93
- - ***keepHeaderCase*** Boolean - by default will convert header keys to lowercase
94
90
  - ***timeout*** Number | Array - Request timeout in milliseconds for connecting phase and response receiving phase. Defaults to `exports.TIMEOUT`, both are 5s. You can use `timeout: 5000` to tell urllib use same timeout on two phase or set them seperately such as `timeout: [3000, 5000]`, which will set connecting timeout to 3s and response 5s.
95
91
  - ***auth*** String - `username:password` used in HTTP Basic Authorization.
96
- - ***digestAuth*** String - `username:password` used in HTTP [Digest Authorization](http://en.wikipedia.org/wiki/Digest_access_authentication).
97
92
  - ***agent*** [http.Agent](http://nodejs.org/api/http.html#http_class_http_agent) - HTTP Agent object.
98
93
  Set `false` if you does not use agent.
99
94
  - ***httpsAgent*** [https.Agent](http://nodejs.org/api/https.html#https_class_https_agent) - HTTPS Agent object.
100
95
  Set `false` if you does not use agent.
101
- - ***ca*** String | Buffer | Array - An array of strings or Buffers of trusted certificates.
102
- If this is omitted several well known "root" CAs will be used, like VeriSign.
103
- These are used to authorize connections.
104
- **Notes**: This is necessary only if the server uses the self-signed certificate
105
- - ***rejectUnauthorized*** Boolean - If true, the server certificate is verified against the list of supplied CAs.
106
- An 'error' event is emitted if verification fails. Default: true.
107
- - ***pfx*** String | Buffer - A string or Buffer containing the private key,
108
- certificate and CA certs of the server in PFX or PKCS12 format.
109
- - ***key*** String | Buffer - A string or Buffer containing the private key of the client in PEM format.
110
- **Notes**: This is necessary only if using the client certificate authentication
111
- - ***cert*** String | Buffer - A string or Buffer containing the certificate key of the client in PEM format.
112
- **Notes**: This is necessary only if using the client certificate authentication
113
- - ***passphrase*** String - A string of passphrase for the private key or pfx.
114
- - ***ciphers*** String - A string describing the ciphers to use or exclude.
115
- - ***secureProtocol*** String - The SSL method to use, e.g. SSLv3_method to force SSL version 3.
116
96
  - ***followRedirect*** Boolean - follow HTTP 3xx responses as redirects. defaults to false.
117
97
  - ***maxRedirects*** Number - The maximum number of redirects to follow, defaults to 10.
118
98
  - ***formatRedirectUrl*** Function - Format the redirect url by your self. Default is `url.resolve(from, to)`.
119
99
  - ***beforeRequest*** Function - Before request hook, you can change every thing here.
120
100
  - ***streaming*** Boolean - let you get the `res` object when request connected, default `false`. alias `customResponse`
121
- - ***gzip*** Boolean - Accept gzip response content and auto decode it, default is `false`.
101
+ - ***gzip*** Boolean - Accept `gzip, br` response content and auto decode it, default is `false`.
122
102
  - ***timing*** Boolean - Enable timing or not, default is `false`.
123
- - ***enableProxy*** Boolean - Enable proxy request, default is `false`.
124
- - ***proxy*** String | Object - proxy agent uri or options, default is `null`.
125
- - ***lookup*** Function - Custom DNS lookup function, default is `dns.lookup`. Require node >= 4.0.0(for http protocol) and node >=8(for https protocol)
126
- - ***checkAddress*** Function: optional, check request address to protect from SSRF and similar attacks. It receive tow arguments(`ip` and `family`) and should return true or false to identified the address is legal or not. It rely on `lookup` and have the same version requirement.
127
- - ***trace*** Boolean - Enable capture stack include call site of library entrance, default is `false`.
128
- - ***socketPath*** String - optional Unix Domain Socket. (Refer to [Node.js Document](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_http_request_options_callback))
129
-
130
- #### Returns
131
-
132
- - **data** Buffer | Object - The data responsed. Would be a Buffer if `dataType` is set to `text` or an JSON parsed into Object if it's set to `json`.
133
- - **res** [http.IncomingMessage](http://nodejs.org/api/http.html#http_http_incomingmessage) - The response.
134
103
 
135
104
  #### Options: `options.data`
136
105
 
@@ -150,14 +119,14 @@ For `GET` request, `data` will be stringify to query string, e.g. `http://exampl
150
119
 
151
120
  For others like `POST`, `PATCH` or `PUT` request,
152
121
  in defaults, the `data` will be stringify into `application/x-www-form-urlencoded` format
153
- if `Content-Type` header is not set.
122
+ if `content-type` header is not set.
154
123
 
155
- If `Content-type` is `application/json`, the `data` will be `JSON.stringify` to JSON data format.
124
+ If `content-type` is `application/json`, the `data` will be `JSON.stringify` to JSON data format.
156
125
 
157
126
  #### Options: `options.content`
158
127
 
159
128
  `options.content` is useful when you wish to construct the request body by yourself,
160
- for example making a `Content-Type: application/json` request.
129
+ for example making a `content-type: application/json` request.
161
130
 
162
131
  Notes that if you want to send a JSON body, you should stringify it yourself:
163
132
 
@@ -178,8 +147,8 @@ It would make a HTTP request like:
178
147
 
179
148
  ```http
180
149
  POST / HTTP/1.1
181
- Host: example.com
182
- Content-Type: application/json
150
+ host: example.com
151
+ content-type: application/json
183
152
 
184
153
  {
185
154
  "a": "hello",
@@ -193,7 +162,7 @@ This exmaple can use `options.data` with `application/json` content type:
193
162
  await request('https://example.com', {
194
163
  method: 'POST',
195
164
  headers: {
196
- 'Content-Type': 'application/json'
165
+ 'content-type': 'application/json'
197
166
  },
198
167
  data: {
199
168
  a: 'hello',
@@ -268,7 +237,6 @@ Response is normal object, it contains:
268
237
  - `status` or `statusCode`: response status code.
269
238
  - `-1` meaning some network error like `ENOTFOUND`
270
239
  - `-2` meaning ConnectionTimeoutError
271
- - `statusMessage`: response status message.
272
240
  - `headers`: response http headers, default is `{}`
273
241
  - `size`: response size
274
242
  - `aborted`: response was aborted or not
@@ -279,76 +247,12 @@ Response is normal object, it contains:
279
247
  - `socketHandledRequests`: socket already handled request count
280
248
  - `socketHandledResponses`: socket already handled response count
281
249
 
282
- #### Response: `res.aborted`
283
-
284
- If the underlaying connection was terminated before `response.end()` was called,
285
- `res.aborted` should be `true`.
286
-
287
- ```js
288
- import { createServer } from 'http';
289
-
290
- createServer((req, res) => {
291
- req.resume();
292
- req.on('end', () => {
293
- res.write('foo haha\n');
294
- setTimeout(() => {
295
- res.write('foo haha 2');
296
- setTimeout(() => {
297
- res.socket.end();
298
- }, 300);
299
- }, 200);
300
- return;
301
- });
302
- }).listen(2022);
303
-
304
- const { data, res } = await request('http://127.0.0.1:2022/socket.end');
305
- assert.equal(data.toString(), 'foo haha\nfoo haha 2');
306
- assert(res.aborted);
307
- ```
308
-
309
- ### HttpClient2
310
-
311
- HttpClient2 base on HttpClient.
312
-
313
- #### Options
314
-
315
- options extends from urllib, besides below
250
+ ## Run test with debug log
316
251
 
317
- - ***retry*** Number - a retry count, when get an error, it will request again until reach the retry count.
318
- - ***retryDelay*** Number - wait a delay(ms) between retries.
319
- - ***isRetry*** Function - determine whether retry, a response object as the first argument. it will retry when status >= 500 by default. Request error is not included.
320
-
321
- #### Warning
322
-
323
- It's not supported by using retry and writeStream, because the retry request can't stop the stream which is consuming.
324
-
325
- ### Trace
326
-
327
- If set trace true, error stack will contains full call stack, like
328
-
329
- ```
330
- Error: connect ECONNREFUSED 127.0.0.1:11
331
- at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1113:14)
332
- --------------------
333
- at ~/workspace/urllib/lib/urllib.js:150:13
334
- at new Promise (<anonymous>)
335
- at Object.request (~/workspace/urllib/lib/urllib.js:149:10)
336
- at Context.<anonymous> (~/workspace/urllib/test/urllib_promise.test.js:49:19)
337
- ....
252
+ ```bash
253
+ NODE_DEBUG=urllib npm test
338
254
  ```
339
255
 
340
- When open the trace, urllib may have poor perfomance, please consider carefully.
341
-
342
- ## TODO
343
-
344
- - ❎ Support Proxy
345
- - ✅ Upload file like form upload
346
- - ✅ Auto redirect handle
347
- - ✅ https & self-signed certificate
348
- - ✅ Connection timeout & Response timeout
349
- - ✅ Support `Accept-Encoding=gzip` by default
350
- - ✅ Support [Digest access authentication](http://en.wikipedia.org/wiki/Digest_access_authentication)
351
-
352
256
  <!-- GITCONTRIBUTOR_START -->
353
257
 
354
258
  ## Contributors
@@ -356,18 +260,16 @@ When open the trace, urllib may have poor perfomance, please consider carefully.
356
260
  |[<img src="https://avatars.githubusercontent.com/u/156269?v=4" width="100px;"/><br/><sub><b>fengmk2</b></sub>](https://github.com/fengmk2)<br/>|[<img src="https://avatars.githubusercontent.com/u/985607?v=4" width="100px;"/><br/><sub><b>dead-horse</b></sub>](https://github.com/dead-horse)<br/>|[<img src="https://avatars.githubusercontent.com/u/288288?v=4" width="100px;"/><br/><sub><b>xingrz</b></sub>](https://github.com/xingrz)<br/>|[<img src="https://avatars.githubusercontent.com/u/360661?v=4" width="100px;"/><br/><sub><b>popomore</b></sub>](https://github.com/popomore)<br/>|[<img src="https://avatars.githubusercontent.com/u/327019?v=4" width="100px;"/><br/><sub><b>JacksonTian</b></sub>](https://github.com/JacksonTian)<br/>|[<img src="https://avatars.githubusercontent.com/u/543405?v=4" width="100px;"/><br/><sub><b>ibigbug</b></sub>](https://github.com/ibigbug)<br/>|
357
261
  | :---: | :---: | :---: | :---: | :---: | :---: |
358
262
  |[<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/>|
359
- |[<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/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/>|[<img src="https://avatars.githubusercontent.com/u/309219?v=4" width="100px;"/><br/><sub><b>chadxz</b></sub>](https://github.com/chadxz)<br/>|
360
- |[<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/>|[<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/>|
361
- |[<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/>|[<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/>|
362
- |[<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/6897780?v=4" width="100px;"/><br/><sub><b>killagu</b></sub>](https://github.com/killagu)<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/>|[<img src="https://avatars.githubusercontent.com/u/929179?v=4" width="100px;"/><br/><sub><b>rockdai</b></sub>](https://github.com/rockdai)<br/>|
263
+ |[<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/>|
264
+ |[<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/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/>|[<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/>|
265
+ |[<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/>|[<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/>|
266
+ |[<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/>|[<img src="https://avatars.githubusercontent.com/u/929179?v=4" width="100px;"/><br/><sub><b>rockdai</b></sub>](https://github.com/rockdai)<br/>|
363
267
  [<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/>
364
268
 
365
- This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Fri Mar 25 2022 00:05:23 GMT+0800`.
269
+ This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Tue Jul 05 2022 16:17:31 GMT+0800`.
366
270
 
367
271
  <!-- GITCONTRIBUTOR_END -->
368
272
 
369
273
  ## License
370
274
 
371
275
  [MIT](LICENSE)
372
-
373
- [bluebird]: https://github.com/petkaantonov/bluebird
package/package.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "urllib",
3
- "version": "3.0.0-alpha.1",
3
+ "version": "3.0.0",
4
+ "publishConfig": {
5
+ "tag": "latest"
6
+ },
4
7
  "description": "Help in opening URLs (mostly HTTP) in a complex world — basic and digest authentication, redirections, cookies and more. Base undici fetch API.",
5
8
  "keywords": [
6
9
  "urllib",
@@ -54,15 +57,19 @@
54
57
  "dependencies": {
55
58
  "default-user-agent": "^1.0.0",
56
59
  "digest-header": "^0.0.1",
57
- "ip": "^1.1.5",
60
+ "form-data-encoder": "^1.7.2",
61
+ "formdata-node": "^4.3.3",
58
62
  "mime-types": "^2.1.35",
59
- "undici": "^5.4.0"
63
+ "pump": "^3.0.0",
64
+ "undici": "^5.6.0"
60
65
  },
61
66
  "devDependencies": {
62
67
  "@types/busboy": "^1.5.0",
63
68
  "@types/default-user-agent": "^1.0.0",
64
69
  "@types/jest": "28",
65
70
  "@types/mime-types": "^2.1.1",
71
+ "@types/pump": "^1.1.1",
72
+ "@types/selfsigned": "^2.0.1",
66
73
  "busboy": "^1.6.0",
67
74
  "coffee": "5",
68
75
  "egg-ci": "2",
@@ -72,19 +79,16 @@
72
79
  "iconv-lite": "^0.6.3",
73
80
  "jest": "28",
74
81
  "jest-summary-reporter": "^0.0.2",
75
- "p-event": "^4.2.0",
82
+ "selfsigned": "^2.0.1",
76
83
  "ts-jest": "28",
77
84
  "tslib": "^2.4.0",
78
85
  "typescript": "4"
79
86
  },
80
87
  "engines": {
81
- "node": ">= 16.5.0"
88
+ "node": ">= 14.0.0"
82
89
  },
83
90
  "ci": {
84
- "version": "16, 18"
85
- },
86
- "publishConfig": {
87
- "tag": "next"
91
+ "version": "14, 16, 18"
88
92
  },
89
93
  "license": "MIT"
90
94
  }
@@ -0,0 +1,72 @@
1
+ import dns from 'dns';
2
+ import { LookupFunction, isIP } from 'net';
3
+ import {
4
+ Agent,
5
+ } from 'undici';
6
+ import { DispatchHandlers } from 'undici/types/dispatcher';
7
+ import { BuildOptions } from 'undici/types/connector';
8
+
9
+ export type CheckAddressFunction = (ip: string, family: number | string) => boolean;
10
+
11
+ export type HttpAgentOptions = {
12
+ lookup?: LookupFunction;
13
+ checkAddress?: CheckAddressFunction;
14
+ connect?: BuildOptions,
15
+ };
16
+
17
+ class IllegalAddressError extends Error {
18
+ hostname: string;
19
+ ip: string;
20
+ family: number;
21
+
22
+ constructor(hostname: string, ip: string, family: number) {
23
+ const message = 'illegal address';
24
+ super(message);
25
+ this.name = this.constructor.name;
26
+ this.hostname = hostname;
27
+ this.ip = ip;
28
+ this.family = family;
29
+ Error.captureStackTrace(this, this.constructor);
30
+ }
31
+ }
32
+
33
+ export class HttpAgent extends Agent {
34
+ #checkAddress?: CheckAddressFunction;
35
+
36
+ constructor(options: HttpAgentOptions) {
37
+ /* eslint node/prefer-promises/dns: off*/
38
+ const _lookup = options.lookup ?? dns.lookup;
39
+ const lookup: LookupFunction = (hostname, dnsOptions, callback) => {
40
+ _lookup(hostname, dnsOptions, (err, address, family) => {
41
+ if (err) return callback(err, address, family);
42
+ if (options.checkAddress && !options.checkAddress(address, family)) {
43
+ err = new IllegalAddressError(hostname, address, family);
44
+ }
45
+ callback(err, address, family);
46
+ });
47
+ };
48
+ super({
49
+ connect: { ...options.connect, lookup },
50
+ });
51
+ this.#checkAddress = options.checkAddress;
52
+ }
53
+
54
+ dispatch(options: Agent.DispatchOptions, handler: DispatchHandlers): boolean {
55
+ if (this.#checkAddress && options.origin) {
56
+ const originUrl = typeof options.origin === 'string' ? new URL(options.origin) : options.origin;
57
+ let hostname = originUrl.hostname;
58
+ // [2001:db8:2de::e13] => 2001:db8:2de::e13
59
+ if (hostname.startsWith('[') && hostname.endsWith(']')) {
60
+ hostname = hostname.substring(1, hostname.length - 1);
61
+ }
62
+ const family = isIP(hostname);
63
+ if (family === 4 || family === 6) {
64
+ // if request hostname is ip, custom lookup won't excute
65
+ if (!this.#checkAddress(hostname, family)) {
66
+ throw new IllegalAddressError(hostname, hostname, family);
67
+ }
68
+ }
69
+ }
70
+ return super.dispatch(options, handler);
71
+ }
72
+ }