got 10.5.4 → 10.6.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.
@@ -21,7 +21,7 @@ function asStream(options) {
21
21
  throw new Error('Got\'s stream is not writable when the `body`, `json` or `form` option is used');
22
22
  };
23
23
  }
24
- else if (options.method === 'POST' || options.method === 'PUT' || options.method === 'PATCH') {
24
+ else if (options.method === 'POST' || options.method === 'PUT' || options.method === 'PATCH' || (options.allowGetBody && options.method === 'GET')) {
25
25
  options.body = input;
26
26
  }
27
27
  else {
@@ -67,6 +67,7 @@ const defaults = {
67
67
  maxRedirects: 10,
68
68
  prefixUrl: '',
69
69
  methodRewriting: true,
70
+ allowGetBody: false,
70
71
  ignoreInvalidCookies: false,
71
72
  context: {},
72
73
  _pagination: {
@@ -6,7 +6,7 @@ Called with plain request options, right before their normalization. This is esp
6
6
 
7
7
  @see [Request migration guide](https://github.com/sindresorhus/got/blob/master/migration-guides.md#breaking-changes) for an example.
8
8
  */
9
- export declare type InitHook = (options: NormalizedOptions) => void;
9
+ export declare type InitHook = (options: Options) => void;
10
10
  /**
11
11
  Called with normalized [request options](https://github.com/sindresorhus/got#options). Got will make no further changes to the request before it is sent (except the body serialization). This is especially useful in conjunction with [`got.extend()`](https://github.com/sindresorhus/got#instances) when you want to create an API client that, for example, uses HMAC-signing.
12
12
 
@@ -167,24 +167,18 @@ exports.preNormalizeArguments = (options, defaults) => {
167
167
  }
168
168
  // `options._pagination`
169
169
  if (is_1.default.object(options._pagination)) {
170
- if (defaults && !(Reflect.has(options, '_pagination') && is_1.default.undefined(options._pagination))) {
171
- options._pagination = {
172
- ...defaults.pagination,
173
- ...options._pagination
174
- };
175
- }
176
- const pagination = options._pagination;
170
+ const { _pagination: pagination } = options;
177
171
  if (!is_1.default.function_(pagination.transform)) {
178
- throw new Error('`options._pagination.transform` must be implemented');
172
+ throw new TypeError('`options._pagination.transform` must be implemented');
179
173
  }
180
174
  if (!is_1.default.function_(pagination.shouldContinue)) {
181
- throw new Error('`options._pagination.shouldContinue` must be implemented');
175
+ throw new TypeError('`options._pagination.shouldContinue` must be implemented');
182
176
  }
183
177
  if (!is_1.default.function_(pagination.filter)) {
184
- throw new Error('`options._pagination.filter` must be implemented');
178
+ throw new TypeError('`options._pagination.filter` must be implemented');
185
179
  }
186
180
  if (!is_1.default.function_(pagination.paginate)) {
187
- throw new Error('`options._pagination.paginate` must be implemented');
181
+ throw new TypeError('`options._pagination.paginate` must be implemented');
188
182
  }
189
183
  }
190
184
  // Other values
@@ -199,6 +193,7 @@ exports.preNormalizeArguments = (options, defaults) => {
199
193
  options.dnsCache = (_e = options.dnsCache, (_e !== null && _e !== void 0 ? _e : false));
200
194
  options.useElectronNet = Boolean(options.useElectronNet);
201
195
  options.methodRewriting = Boolean(options.methodRewriting);
196
+ options.allowGetBody = Boolean(options.allowGetBody);
202
197
  options.context = (_f = options.context, (_f !== null && _f !== void 0 ? _f : {}));
203
198
  return options;
204
199
  };
@@ -224,27 +219,52 @@ exports.mergeOptions = (...sources) => {
224
219
  return mergedOptions;
225
220
  };
226
221
  exports.normalizeArguments = (url, options, defaults) => {
227
- var _a, _b, _c, _d;
222
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
228
223
  // Merge options
229
224
  if (typeof url === 'undefined') {
230
225
  throw new TypeError('Missing `url` argument');
231
226
  }
232
- if (typeof options === 'undefined') {
233
- options = {};
234
- }
235
- if (is_1.default.urlInstance(url) || is_1.default.string(url)) {
236
- if (Reflect.has(options, 'url')) {
237
- throw new TypeError('The `url` option cannot be used if the input is a valid URL.');
227
+ const runInitHooks = (hooks, options) => {
228
+ if (hooks && options) {
229
+ for (const hook of hooks) {
230
+ const result = hook(options);
231
+ if (is_1.default.promise(result)) {
232
+ throw new TypeError('The `init` hook must be a synchronous function');
233
+ }
234
+ }
235
+ }
236
+ };
237
+ const hasUrl = is_1.default.urlInstance(url) || is_1.default.string(url);
238
+ if (hasUrl) {
239
+ if (options) {
240
+ if (Reflect.has(options, 'url')) {
241
+ throw new TypeError('The `url` option cannot be used if the input is a valid URL.');
242
+ }
243
+ }
244
+ else {
245
+ options = {};
238
246
  }
239
247
  // @ts-ignore URL is not URL
240
248
  options.url = url;
241
- options = exports.mergeOptions((_b = (_a = defaults) === null || _a === void 0 ? void 0 : _a.options, (_b !== null && _b !== void 0 ? _b : {})), options);
249
+ runInitHooks((_a = defaults) === null || _a === void 0 ? void 0 : _a.options.hooks.init, options);
250
+ runInitHooks((_b = options.hooks) === null || _b === void 0 ? void 0 : _b.init, options);
251
+ }
252
+ else if (Reflect.has(url, 'resolve')) {
253
+ throw new Error('The legacy `url.Url` is deprecated. Use `URL` instead.');
242
254
  }
243
255
  else {
244
- if (Reflect.has(url, 'resolve')) {
245
- throw new Error('The legacy `url.Url` is deprecated. Use `URL` instead.');
256
+ runInitHooks((_c = defaults) === null || _c === void 0 ? void 0 : _c.options.hooks.init, url);
257
+ runInitHooks((_d = url.hooks) === null || _d === void 0 ? void 0 : _d.init, url);
258
+ if (options) {
259
+ runInitHooks((_e = defaults) === null || _e === void 0 ? void 0 : _e.options.hooks.init, options);
260
+ runInitHooks((_f = options.hooks) === null || _f === void 0 ? void 0 : _f.init, options);
246
261
  }
247
- options = exports.mergeOptions((_d = (_c = defaults) === null || _c === void 0 ? void 0 : _c.options, (_d !== null && _d !== void 0 ? _d : {})), url, options);
262
+ }
263
+ if (hasUrl) {
264
+ options = exports.mergeOptions((_h = (_g = defaults) === null || _g === void 0 ? void 0 : _g.options, (_h !== null && _h !== void 0 ? _h : {})), (options !== null && options !== void 0 ? options : {}));
265
+ }
266
+ else {
267
+ options = exports.mergeOptions((_k = (_j = defaults) === null || _j === void 0 ? void 0 : _j.options, (_k !== null && _k !== void 0 ? _k : {})), url, (options !== null && options !== void 0 ? options : {}));
248
268
  }
249
269
  // Normalize URL
250
270
  // TODO: drop `optionsToUrl` in Got 12
@@ -284,15 +304,10 @@ exports.normalizeArguments = (url, options, defaults) => {
284
304
  delete normalizedOptions.headers[key];
285
305
  }
286
306
  }
287
- for (const hook of normalizedOptions.hooks.init) {
288
- const result = hook(normalizedOptions);
289
- if (is_1.default.promise(result)) {
290
- throw new TypeError('The `init` hook must be a synchronous function');
291
- }
292
- }
293
307
  return normalizedOptions;
294
308
  };
295
- const withoutBody = new Set(['GET', 'HEAD']);
309
+ const withoutBody = new Set(['HEAD']);
310
+ const withoutBodyUnlessSpecified = 'GET';
296
311
  exports.normalizeRequestArguments = async (options) => {
297
312
  var _a, _b, _c;
298
313
  options = exports.mergeOptions(options);
@@ -307,6 +322,9 @@ exports.normalizeRequestArguments = async (options) => {
307
322
  if ((isBody || isForm || isJson) && withoutBody.has(options.method)) {
308
323
  throw new TypeError(`The \`${options.method}\` method cannot be used with a body`);
309
324
  }
325
+ if (!options.allowGetBody && (isBody || isForm || isJson) && withoutBodyUnlessSpecified === options.method) {
326
+ throw new TypeError(`The \`${options.method}\` method cannot be used with a body`);
327
+ }
310
328
  if ([isBody, isForm, isJson].filter(isTrue => isTrue).length > 1) {
311
329
  throw new TypeError('The `body`, `json` and `form` options are mutually exclusive');
312
330
  }
@@ -353,7 +371,7 @@ exports.normalizeRequestArguments = async (options) => {
353
371
  // a payload body and the method semantics do not anticipate such a
354
372
  // body.
355
373
  if (is_1.default.undefined(headers['content-length']) && is_1.default.undefined(headers['transfer-encoding'])) {
356
- if ((options.method === 'POST' || options.method === 'PUT' || options.method === 'PATCH' || options.method === 'DELETE') &&
374
+ if ((options.method === 'POST' || options.method === 'PUT' || options.method === 'PATCH' || options.method === 'DELETE' || (options.allowGetBody && options.method === 'GET')) &&
357
375
  !is_1.default.undefined(uploadBodySize)) {
358
376
  // @ts-ignore We assign if it is undefined, so this IS correct
359
377
  headers['content-length'] = String(uploadBodySize);
@@ -81,6 +81,7 @@ exports.default = (options) => {
81
81
  }
82
82
  if (options.followRedirect && Reflect.has(typedResponse.headers, 'location') && redirectCodes.has(statusCode)) {
83
83
  typedResponse.resume(); // We're being redirected, we don't care about the response.
84
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare
84
85
  if (statusCode === 303 || options.methodRewriting === false) {
85
86
  if (options.method !== 'GET' && options.method !== 'HEAD') {
86
87
  // Server responded with "see other", indicating that the resource exists at another location,
@@ -145,6 +145,7 @@ export interface GotOptions extends PaginationOptions<unknown> {
145
145
  };
146
146
  maxRedirects?: number;
147
147
  lookup?: CacheableLookup['lookup'];
148
+ allowGetBody?: boolean;
148
149
  methodRewriting?: boolean;
149
150
  }
150
151
  export declare type Options = Merge<https.RequestOptions, Merge<GotOptions, URLOptions>>;
@@ -173,6 +174,7 @@ export interface NormalizedOptions extends Options {
173
174
  followRedirect: boolean;
174
175
  useElectronNet: boolean;
175
176
  methodRewriting: boolean;
177
+ allowGetBody: boolean;
176
178
  context: {
177
179
  [key: string]: any;
178
180
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "got",
3
- "version": "10.5.4",
3
+ "version": "10.6.0",
4
4
  "description": "Human-friendly and powerful HTTP request library for Node.js",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/got",
@@ -41,7 +41,7 @@
41
41
  "superagent"
42
42
  ],
43
43
  "dependencies": {
44
- "@sindresorhus/is": "^1.0.0",
44
+ "@sindresorhus/is": "^2.0.0",
45
45
  "@szmarczak/http-timer": "^4.0.0",
46
46
  "@types/cacheable-request": "^6.0.1",
47
47
  "cacheable-lookup": "^2.0.0",
@@ -50,15 +50,15 @@
50
50
  "duplexer3": "^0.1.4",
51
51
  "get-stream": "^5.0.0",
52
52
  "lowercase-keys": "^2.0.0",
53
- "mimic-response": "^2.0.0",
53
+ "mimic-response": "^2.1.0",
54
54
  "p-cancelable": "^2.0.0",
55
55
  "p-event": "^4.0.0",
56
56
  "responselike": "^2.0.0",
57
57
  "to-readable-stream": "^2.0.0",
58
- "type-fest": "^0.9.0"
58
+ "type-fest": "^0.10.0"
59
59
  },
60
60
  "devDependencies": {
61
- "@ava/typescript": "^1.1.0",
61
+ "@ava/typescript": "^1.1.1",
62
62
  "@sindresorhus/tsconfig": "^0.7.0",
63
63
  "@types/duplexer3": "^0.1.0",
64
64
  "@types/express": "^4.17.2",
@@ -67,29 +67,29 @@
67
67
  "@types/proxyquire": "^1.3.28",
68
68
  "@types/sinon": "^7.0.13",
69
69
  "@types/tough-cookie": "^2.3.5",
70
- "@typescript-eslint/eslint-plugin": "^2.17.0",
71
- "@typescript-eslint/parser": "^2.17.0",
72
- "ava": "^3.2.0",
70
+ "@typescript-eslint/eslint-plugin": "^2.19.2",
71
+ "@typescript-eslint/parser": "^2.19.2",
72
+ "ava": "^3.3.0",
73
73
  "coveralls": "^3.0.4",
74
74
  "create-test-server": "^3.0.1",
75
75
  "del-cli": "^3.0.0",
76
76
  "delay": "^4.3.0",
77
- "eslint-config-xo-typescript": "^0.24.1",
77
+ "eslint-config-xo-typescript": "^0.26.0",
78
78
  "express": "^4.17.1",
79
79
  "form-data": "^3.0.0",
80
80
  "get-port": "^5.0.0",
81
81
  "keyv": "^4.0.0",
82
- "lolex": "^5.1.1",
83
- "nock": "^11.3.4",
84
- "np": "^5.1.3",
82
+ "lolex": "^6.0.0",
83
+ "nock": "^12.0.0",
84
+ "np": "^6.0.0",
85
85
  "nyc": "^15.0.0",
86
86
  "proxyquire": "^2.0.1",
87
87
  "sinon": "^8.1.1",
88
88
  "slow-stream": "0.0.4",
89
- "tempy": "^0.3.0",
89
+ "tempy": "^0.4.0",
90
90
  "tough-cookie": "^3.0.0",
91
91
  "typescript": "3.7.5",
92
- "xo": "^0.25.3"
92
+ "xo": "^0.26.0"
93
93
  },
94
94
  "types": "dist/source",
95
95
  "sideEffects": false,
package/readme.md CHANGED
@@ -188,7 +188,7 @@ Type: `string | Buffer | stream.Readable` or [`form-data` instance](https://gith
188
188
 
189
189
  **Note #2:** If you provide this option, `got.stream()` will be read-only.
190
190
 
191
- **Note #3:** If you provide a payload with the `GET` or `HEAD` method, it will throw a `TypeError`.
191
+ **Note #3:** If you provide a payload with the `GET` or `HEAD` method, it will throw a `TypeError` unless the method is `GET` and the `allowGetBody` option is set to `true`.
192
192
 
193
193
  The `content-length` header will be automatically set if `body` is a `string` / `Buffer` / `fs.createReadStream` instance / [`form-data` instance](https://github.com/form-data/form-data), and `content-length` and `transfer-encoding` are not manually set in `options.headers`.
194
194
 
@@ -410,6 +410,15 @@ Default: `true`
410
410
 
411
411
  By default, redirects will use [method rewriting](https://tools.ietf.org/html/rfc7231#section-6.4). For example, when sending a POST request and receiving a `302`, it will resend the body to the new location using the same HTTP method (`POST` in this case).
412
412
 
413
+ ###### allowGetBody
414
+
415
+ Type: `boolean`\
416
+ Default: `false`
417
+
418
+ **Note:** The [RFC 7321](https://tools.ietf.org/html/rfc7231#section-4.3.1) doesn't specify any particular behavior for the GET method having a payload, therefore **it's considered an [anti-pattern](https://en.wikipedia.org/wiki/Anti-pattern)**.
419
+
420
+ Set this to `true` to allow sending body for the `GET` method. However, the [HTTP/2 specification](https://tools.ietf.org/html/rfc7540#section-8.1.3) says that `An HTTP GET request includes request header fields and no payload body`, therefore when using the HTTP/2 protocol this option will have no effect. This option is only meant to interact with non-compliant servers when you have no other choice.
421
+
413
422
  ###### maxRedirects
414
423
 
415
424
  Type: `number`\
@@ -810,7 +819,7 @@ Progress events for uploading (sending a request) and downloading (receiving a r
810
819
  }
811
820
  ```
812
821
 
813
- If it's not possible to retrieve the body size (can happen when streaming), `total` will be `undefined`.
822
+ If the `content-length` header is missing, `total` will be `undefined`.
814
823
 
815
824
  ```js
816
825
  (async () => {