got 6.7.0 → 8.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.
Files changed (4) hide show
  1. package/index.js +427 -104
  2. package/license +4 -16
  3. package/package.json +92 -76
  4. package/readme.md +291 -42
package/index.js CHANGED
@@ -3,47 +3,136 @@ const EventEmitter = require('events');
3
3
  const http = require('http');
4
4
  const https = require('https');
5
5
  const PassThrough = require('stream').PassThrough;
6
+ const Transform = require('stream').Transform;
6
7
  const urlLib = require('url');
8
+ const fs = require('fs');
7
9
  const querystring = require('querystring');
10
+ const CacheableRequest = require('cacheable-request');
8
11
  const duplexer3 = require('duplexer3');
12
+ const intoStream = require('into-stream');
9
13
  const isStream = require('is-stream');
10
14
  const getStream = require('get-stream');
11
15
  const timedOut = require('timed-out');
12
16
  const urlParseLax = require('url-parse-lax');
17
+ const urlToOptions = require('url-to-options');
13
18
  const lowercaseKeys = require('lowercase-keys');
14
- const isRedirect = require('is-redirect');
15
- const unzipResponse = require('unzip-response');
16
- const createErrorClass = require('create-error-class');
19
+ const decompressResponse = require('decompress-response');
20
+ const mimicResponse = require('mimic-response');
17
21
  const isRetryAllowed = require('is-retry-allowed');
22
+ const isURL = require('isurl');
23
+ const isPlainObj = require('is-plain-obj');
24
+ const PCancelable = require('p-cancelable');
25
+ const pTimeout = require('p-timeout');
26
+ const pify = require('pify');
18
27
  const Buffer = require('safe-buffer').Buffer;
19
- const pkg = require('./package');
28
+ const pkg = require('./package.json');
29
+
30
+ const getMethodRedirectCodes = new Set([300, 301, 302, 303, 304, 305, 307, 308]);
31
+ const allMethodRedirectCodes = new Set([300, 303, 307, 308]);
32
+
33
+ const isFormData = body => isStream(body) && typeof body.getBoundary === 'function';
34
+
35
+ const getBodySize = opts => {
36
+ const body = opts.body;
37
+
38
+ if (opts.headers['content-length']) {
39
+ return Number(opts.headers['content-length']);
40
+ }
41
+
42
+ if (!body && !opts.stream) {
43
+ return 0;
44
+ }
45
+
46
+ if (typeof body === 'string') {
47
+ return Buffer.byteLength(body);
48
+ }
49
+
50
+ if (isFormData(body)) {
51
+ return pify(body.getLength.bind(body))();
52
+ }
53
+
54
+ if (body instanceof fs.ReadStream) {
55
+ return pify(fs.stat)(body.path).then(stat => stat.size);
56
+ }
57
+
58
+ if (isStream(body) && Buffer.isBuffer(body._buffer)) {
59
+ return body._buffer.length;
60
+ }
61
+
62
+ return null;
63
+ };
20
64
 
21
65
  function requestAsEventEmitter(opts) {
22
66
  opts = opts || {};
23
67
 
24
68
  const ee = new EventEmitter();
25
69
  const requestUrl = opts.href || urlLib.resolve(urlLib.format(opts), opts.path);
26
- let redirectCount = 0;
70
+ const redirects = [];
71
+ const agents = typeof opts.agent === 'object' ? opts.agent : null;
27
72
  let retryCount = 0;
28
73
  let redirectUrl;
74
+ let uploadBodySize;
75
+ let uploaded = 0;
29
76
 
30
77
  const get = opts => {
31
- const fn = opts.protocol === 'https:' ? https : http;
78
+ if (opts.protocol !== 'http:' && opts.protocol !== 'https:') {
79
+ ee.emit('error', new got.UnsupportedProtocolError(opts));
80
+ return;
81
+ }
82
+
83
+ let fn = opts.protocol === 'https:' ? https : http;
84
+
85
+ if (agents) {
86
+ const protocolName = opts.protocol === 'https:' ? 'https' : 'http';
87
+ opts.agent = agents[protocolName] || opts.agent;
88
+ }
89
+
90
+ if (opts.useElectronNet && process.versions.electron) {
91
+ const electron = require('electron');
92
+ fn = electron.net || electron.remote.net;
93
+ }
94
+
95
+ let progressInterval;
96
+
97
+ const cacheableRequest = new CacheableRequest(fn.request, opts.cache);
98
+ const cacheReq = cacheableRequest(opts, res => {
99
+ clearInterval(progressInterval);
100
+
101
+ ee.emit('uploadProgress', {
102
+ percent: 1,
103
+ transferred: uploaded,
104
+ total: uploadBodySize
105
+ });
32
106
 
33
- const req = fn.request(opts, res => {
34
107
  const statusCode = res.statusCode;
35
108
 
36
- if (isRedirect(statusCode) && opts.followRedirect && 'location' in res.headers && (opts.method === 'GET' || opts.method === 'HEAD')) {
109
+ res.url = redirectUrl || requestUrl;
110
+ res.requestUrl = requestUrl;
111
+
112
+ const followRedirect = opts.followRedirect && 'location' in res.headers;
113
+ const redirectGet = followRedirect && getMethodRedirectCodes.has(statusCode);
114
+ const redirectAll = followRedirect && allMethodRedirectCodes.has(statusCode);
115
+
116
+ if (redirectAll || (redirectGet && (opts.method === 'GET' || opts.method === 'HEAD'))) {
37
117
  res.resume();
38
118
 
39
- if (++redirectCount > 10) {
40
- ee.emit('error', new got.MaxRedirectsError(statusCode, opts), null, res);
119
+ if (statusCode === 303) {
120
+ // Server responded with "see other", indicating that the resource exists at another location,
121
+ // and the client should request it from that location via GET or HEAD.
122
+ opts.method = 'GET';
123
+ }
124
+
125
+ if (redirects.length >= 10) {
126
+ ee.emit('error', new got.MaxRedirectsError(statusCode, redirects, opts), null, res);
41
127
  return;
42
128
  }
43
129
 
44
130
  const bufferString = Buffer.from(res.headers.location, 'binary').toString();
45
131
 
46
132
  redirectUrl = urlLib.resolve(urlLib.format(opts), bufferString);
133
+
134
+ redirects.push(redirectUrl);
135
+
47
136
  const redirectOpts = Object.assign({}, opts, urlLib.parse(redirectUrl));
48
137
 
49
138
  ee.emit('redirect', res, redirectOpts);
@@ -53,44 +142,169 @@ function requestAsEventEmitter(opts) {
53
142
  return;
54
143
  }
55
144
 
145
+ const downloadBodySize = Number(res.headers['content-length']) || null;
146
+ let downloaded = 0;
147
+
56
148
  setImmediate(() => {
57
- const response = typeof unzipResponse === 'function' && req.method !== 'HEAD' ? unzipResponse(res) : res;
58
- response.url = redirectUrl || requestUrl;
59
- response.requestUrl = requestUrl;
149
+ const progressStream = new Transform({
150
+ transform(chunk, encoding, callback) {
151
+ downloaded += chunk.length;
152
+
153
+ const percent = downloadBodySize ? downloaded / downloadBodySize : 0;
154
+
155
+ // Let flush() be responsible for emitting the last event
156
+ if (percent < 1) {
157
+ ee.emit('downloadProgress', {
158
+ percent,
159
+ transferred: downloaded,
160
+ total: downloadBodySize
161
+ });
162
+ }
163
+
164
+ callback(null, chunk);
165
+ },
166
+
167
+ flush(callback) {
168
+ ee.emit('downloadProgress', {
169
+ percent: 1,
170
+ transferred: downloaded,
171
+ total: downloadBodySize
172
+ });
173
+
174
+ callback();
175
+ }
176
+ });
177
+
178
+ mimicResponse(res, progressStream);
179
+ progressStream.redirectUrls = redirects;
180
+
181
+ const response = opts.decompress === true &&
182
+ typeof decompressResponse === 'function' &&
183
+ opts.method !== 'HEAD' ? decompressResponse(progressStream) : progressStream;
184
+
185
+ if (!opts.decompress && ['gzip', 'deflate'].indexOf(res.headers['content-encoding']) !== -1) {
186
+ opts.encoding = null;
187
+ }
60
188
 
61
189
  ee.emit('response', response);
190
+
191
+ ee.emit('downloadProgress', {
192
+ percent: 0,
193
+ transferred: 0,
194
+ total: downloadBodySize
195
+ });
196
+
197
+ res.pipe(progressStream);
62
198
  });
63
199
  });
64
200
 
65
- req.once('error', err => {
66
- const backoff = opts.retries(++retryCount, err);
67
-
68
- if (backoff) {
69
- setTimeout(get, backoff, opts);
70
- return;
201
+ cacheReq.on('error', err => {
202
+ if (err instanceof CacheableRequest.RequestError) {
203
+ ee.emit('error', new got.RequestError(err, opts));
204
+ } else {
205
+ ee.emit('error', new got.CacheError(err, opts));
71
206
  }
72
-
73
- ee.emit('error', new got.RequestError(err, opts));
74
207
  });
75
208
 
76
- if (opts.timeout) {
77
- timedOut(req, opts.timeout);
78
- }
209
+ cacheReq.once('request', req => {
210
+ req.once('error', err => {
211
+ clearInterval(progressInterval);
212
+
213
+ const backoff = opts.retries(++retryCount, err);
214
+
215
+ if (backoff) {
216
+ setTimeout(get, backoff, opts);
217
+ return;
218
+ }
219
+
220
+ ee.emit('error', new got.RequestError(err, opts));
221
+ });
222
+
223
+ ee.once('request', req => {
224
+ ee.emit('uploadProgress', {
225
+ percent: 0,
226
+ transferred: 0,
227
+ total: uploadBodySize
228
+ });
229
+
230
+ req.connection.once('connect', () => {
231
+ const uploadEventFrequency = 150;
232
+
233
+ progressInterval = setInterval(() => {
234
+ const lastUploaded = uploaded;
235
+ const headersSize = Buffer.byteLength(req._header);
236
+ uploaded = req.connection.bytesWritten - headersSize;
237
+
238
+ // Prevent the known issue of `bytesWritten` being larger than body size
239
+ if (uploadBodySize && uploaded > uploadBodySize) {
240
+ uploaded = uploadBodySize;
241
+ }
242
+
243
+ // Don't emit events with unchanged progress and
244
+ // prevent last event from being emitted, because
245
+ // it's emitted when `response` is emitted
246
+ if (uploaded === lastUploaded || uploaded === uploadBodySize) {
247
+ return;
248
+ }
79
249
 
80
- setImmediate(() => {
81
- ee.emit('request', req);
250
+ ee.emit('uploadProgress', {
251
+ percent: uploadBodySize ? uploaded / uploadBodySize : 0,
252
+ transferred: uploaded,
253
+ total: uploadBodySize
254
+ });
255
+ }, uploadEventFrequency);
256
+ });
257
+ });
258
+
259
+ if (opts.gotTimeout) {
260
+ clearInterval(progressInterval);
261
+ timedOut(req, opts.gotTimeout);
262
+ }
263
+
264
+ setImmediate(() => {
265
+ ee.emit('request', req);
266
+ });
82
267
  });
83
268
  };
84
269
 
85
- get(opts);
270
+ setImmediate(() => {
271
+ Promise.resolve(getBodySize(opts))
272
+ .then(size => {
273
+ uploadBodySize = size;
274
+ get(opts);
275
+ })
276
+ .catch(err => {
277
+ ee.emit('error', err);
278
+ });
279
+ });
280
+
86
281
  return ee;
87
282
  }
88
283
 
89
284
  function asPromise(opts) {
90
- return new Promise((resolve, reject) => {
285
+ const timeoutFn = requestPromise => opts.gotTimeout && opts.gotTimeout.request ?
286
+ pTimeout(requestPromise, opts.gotTimeout.request, new got.RequestError({message: 'Request timed out', code: 'ETIMEDOUT'}, opts)) :
287
+ requestPromise;
288
+
289
+ const proxy = new EventEmitter();
290
+
291
+ const cancelable = new PCancelable((onCancel, resolve, reject) => {
91
292
  const ee = requestAsEventEmitter(opts);
293
+ let cancelOnRequest = false;
294
+
295
+ onCancel(() => {
296
+ cancelOnRequest = true;
297
+ });
92
298
 
93
299
  ee.on('request', req => {
300
+ if (cancelOnRequest) {
301
+ req.abort();
302
+ }
303
+
304
+ onCancel(() => {
305
+ req.abort();
306
+ });
307
+
94
308
  if (isStream(opts.body)) {
95
309
  opts.body.pipe(req);
96
310
  opts.body = undefined;
@@ -114,13 +328,15 @@ function asPromise(opts) {
114
328
  if (opts.json && res.body) {
115
329
  try {
116
330
  res.body = JSON.parse(res.body);
117
- } catch (e) {
118
- throw new got.ParseError(e, statusCode, opts, data);
331
+ } catch (err) {
332
+ if (statusCode >= 200 && statusCode < 300) {
333
+ throw new got.ParseError(err, statusCode, opts, data);
334
+ }
119
335
  }
120
336
  }
121
337
 
122
- if (statusCode < 200 || statusCode > limitStatusCode) {
123
- throw new got.HTTPError(statusCode, opts);
338
+ if (statusCode !== 304 && (statusCode < 200 || statusCode > limitStatusCode)) {
339
+ throw new got.HTTPError(statusCode, res.statusMessage, res.headers, opts);
124
340
  }
125
341
 
126
342
  resolve(res);
@@ -131,22 +347,45 @@ function asPromise(opts) {
131
347
  });
132
348
  });
133
349
 
134
- ee.on('error', reject);
350
+ ee.once('error', reject);
351
+ ee.on('redirect', proxy.emit.bind(proxy, 'redirect'));
352
+ ee.on('uploadProgress', proxy.emit.bind(proxy, 'uploadProgress'));
353
+ ee.on('downloadProgress', proxy.emit.bind(proxy, 'downloadProgress'));
135
354
  });
355
+
356
+ const promise = timeoutFn(cancelable);
357
+
358
+ promise.cancel = cancelable.cancel.bind(cancelable);
359
+
360
+ promise.on = (name, fn) => {
361
+ proxy.on(name, fn);
362
+ return promise;
363
+ };
364
+
365
+ return promise;
136
366
  }
137
367
 
138
368
  function asStream(opts) {
369
+ opts.stream = true;
370
+
139
371
  const input = new PassThrough();
140
372
  const output = new PassThrough();
141
373
  const proxy = duplexer3(input, output);
374
+ let timeout;
375
+
376
+ if (opts.gotTimeout && opts.gotTimeout.request) {
377
+ timeout = setTimeout(() => {
378
+ proxy.emit('error', new got.RequestError({message: 'Request timed out', code: 'ETIMEDOUT'}, opts));
379
+ }, opts.gotTimeout.request);
380
+ }
142
381
 
143
382
  if (opts.json) {
144
- throw new Error('got can not be used as stream when options.json is used');
383
+ throw new Error('Got can not be used as a stream when the `json` option is used');
145
384
  }
146
385
 
147
386
  if (opts.body) {
148
387
  proxy.write = () => {
149
- throw new Error('got\'s stream is not writable when options.body is used');
388
+ throw new Error('Got\'s stream is not writable when the `body` option is used');
150
389
  };
151
390
  }
152
391
 
@@ -174,52 +413,67 @@ function asStream(opts) {
174
413
  });
175
414
 
176
415
  ee.on('response', res => {
416
+ clearTimeout(timeout);
417
+
177
418
  const statusCode = res.statusCode;
178
419
 
179
420
  res.pipe(output);
180
421
 
181
- if (statusCode < 200 || statusCode > 299) {
182
- proxy.emit('error', new got.HTTPError(statusCode, opts), null, res);
422
+ if (statusCode !== 304 && (statusCode < 200 || statusCode > 299)) {
423
+ proxy.emit('error', new got.HTTPError(statusCode, res.statusMessage, res.headers, opts), null, res);
183
424
  return;
184
425
  }
185
426
 
186
427
  proxy.emit('response', res);
187
428
  });
188
429
 
189
- ee.on('redirect', proxy.emit.bind(proxy, 'redirect'));
190
430
  ee.on('error', proxy.emit.bind(proxy, 'error'));
431
+ ee.on('redirect', proxy.emit.bind(proxy, 'redirect'));
432
+ ee.on('uploadProgress', proxy.emit.bind(proxy, 'uploadProgress'));
433
+ ee.on('downloadProgress', proxy.emit.bind(proxy, 'downloadProgress'));
191
434
 
192
435
  return proxy;
193
436
  }
194
437
 
195
438
  function normalizeArguments(url, opts) {
196
439
  if (typeof url !== 'string' && typeof url !== 'object') {
197
- throw new Error(`Parameter \`url\` must be a string or object, not ${typeof url}`);
198
- }
199
-
200
- if (typeof url === 'string') {
440
+ throw new TypeError(`Parameter \`url\` must be a string or object, not ${typeof url}`);
441
+ } else if (typeof url === 'string') {
201
442
  url = url.replace(/^unix:/, 'http://$&');
202
443
  url = urlParseLax(url);
203
-
204
444
  if (url.auth) {
205
- throw new Error('Basic authentication must be done with auth option');
445
+ throw new Error('Basic authentication must be done with the `auth` option');
206
446
  }
447
+ } else if (isURL.lenient(url)) {
448
+ url = urlToOptions(url);
207
449
  }
208
450
 
209
451
  opts = Object.assign(
210
452
  {
211
- protocol: 'http:',
212
453
  path: '',
213
- retries: 5
454
+ retries: 2,
455
+ cache: false,
456
+ decompress: true,
457
+ useElectronNet: false
214
458
  },
215
459
  url,
460
+ {
461
+ protocol: url.protocol || 'http:' // Override both null/undefined with default protocol
462
+ },
216
463
  opts
217
464
  );
218
465
 
466
+ const headers = lowercaseKeys(opts.headers);
467
+ for (const key of Object.keys(headers)) {
468
+ if (headers[key] === null || headers[key] === undefined) {
469
+ delete headers[key];
470
+ }
471
+ }
472
+
219
473
  opts.headers = Object.assign({
220
474
  'user-agent': `${pkg.name}/${pkg.version} (https://github.com/sindresorhus/got)`,
221
475
  'accept-encoding': 'gzip,deflate'
222
- }, lowercaseKeys(opts.headers));
476
+ }, headers);
223
477
 
224
478
  const query = opts.query;
225
479
 
@@ -236,33 +490,48 @@ function normalizeArguments(url, opts) {
236
490
  opts.headers.accept = 'application/json';
237
491
  }
238
492
 
239
- let body = opts.body;
240
-
241
- if (body) {
242
- if (typeof body !== 'string' && !(body !== null && typeof body === 'object')) {
243
- throw new Error('options.body must be a ReadableStream, string, Buffer or plain Object');
493
+ const body = opts.body;
494
+ if (body !== null && body !== undefined) {
495
+ const headers = opts.headers;
496
+ if (!isStream(body) && typeof body !== 'string' && !Buffer.isBuffer(body) && !(opts.form || opts.json)) {
497
+ throw new TypeError('The `body` option must be a stream.Readable, string, Buffer or plain Object');
244
498
  }
245
499
 
246
- opts.method = opts.method || 'POST';
500
+ const canBodyBeStringified = isPlainObj(body) || Array.isArray(body);
501
+ if ((opts.form || opts.json) && !canBodyBeStringified) {
502
+ throw new TypeError('The `body` option must be a plain Object or Array when the `form` or `json` option is used');
503
+ }
247
504
 
248
- if (isStream(body) && typeof body.getBoundary === 'function') {
505
+ if (isFormData(body)) {
249
506
  // Special case for https://github.com/form-data/form-data
250
- opts.headers['content-type'] = opts.headers['content-type'] || `multipart/form-data; boundary=${body.getBoundary()}`;
251
- } else if (body !== null && typeof body === 'object' && !Buffer.isBuffer(body) && !isStream(body)) {
252
- opts.headers['content-type'] = opts.headers['content-type'] || 'application/x-www-form-urlencoded';
253
- body = opts.body = querystring.stringify(body);
507
+ headers['content-type'] = headers['content-type'] || `multipart/form-data; boundary=${body.getBoundary()}`;
508
+ } else if (opts.form && canBodyBeStringified) {
509
+ headers['content-type'] = headers['content-type'] || 'application/x-www-form-urlencoded';
510
+ opts.body = querystring.stringify(body);
511
+ } else if (opts.json && canBodyBeStringified) {
512
+ headers['content-type'] = headers['content-type'] || 'application/json';
513
+ opts.body = JSON.stringify(body);
254
514
  }
255
515
 
256
- if (opts.headers['content-length'] === undefined && opts.headers['transfer-encoding'] === undefined && !isStream(body)) {
257
- const length = typeof body === 'string' ? Buffer.byteLength(body) : body.length;
258
- opts.headers['content-length'] = length;
516
+ if (headers['content-length'] === undefined && headers['transfer-encoding'] === undefined && !isStream(body)) {
517
+ const length = typeof opts.body === 'string' ? Buffer.byteLength(opts.body) : opts.body.length;
518
+ headers['content-length'] = length;
519
+ }
520
+
521
+ // Convert buffer to stream to receive upload progress events
522
+ // see https://github.com/sindresorhus/got/pull/322
523
+ if (Buffer.isBuffer(body)) {
524
+ opts.body = intoStream(body);
525
+ opts.body._buffer = body;
259
526
  }
260
- }
261
527
 
262
- opts.method = (opts.method || 'GET').toUpperCase();
528
+ opts.method = (opts.method || 'POST').toUpperCase();
529
+ } else {
530
+ opts.method = (opts.method || 'GET').toUpperCase();
531
+ }
263
532
 
264
533
  if (opts.hostname === 'unix') {
265
- const matches = /(.+):(.+)/.exec(opts.path);
534
+ const matches = /(.+?):(.+)/.exec(opts.path);
266
535
 
267
536
  if (matches) {
268
537
  opts.socketPath = matches[1];
@@ -289,6 +558,15 @@ function normalizeArguments(url, opts) {
289
558
  opts.followRedirect = true;
290
559
  }
291
560
 
561
+ if (opts.timeout) {
562
+ if (typeof opts.timeout === 'number') {
563
+ opts.gotTimeout = {request: opts.timeout};
564
+ } else {
565
+ opts.gotTimeout = opts.timeout;
566
+ }
567
+ delete opts.timeout;
568
+ }
569
+
292
570
  return opts;
293
571
  }
294
572
 
@@ -300,7 +578,9 @@ function got(url, opts) {
300
578
  }
301
579
  }
302
580
 
303
- const helpers = [
581
+ got.stream = (url, opts) => asStream(normalizeArguments(url, opts));
582
+
583
+ const methods = [
304
584
  'get',
305
585
  'post',
306
586
  'put',
@@ -309,51 +589,94 @@ const helpers = [
309
589
  'delete'
310
590
  ];
311
591
 
312
- helpers.forEach(el => {
313
- got[el] = (url, opts) => got(url, Object.assign({}, opts, {method: el}));
314
- });
592
+ for (const method of methods) {
593
+ got[method] = (url, opts) => got(url, Object.assign({}, opts, {method}));
594
+ got.stream[method] = (url, opts) => got.stream(url, Object.assign({}, opts, {method}));
595
+ }
596
+
597
+ class StdError extends Error {
598
+ constructor(message, error, opts) {
599
+ super(message);
600
+ Error.captureStackTrace(this, this.constructor);
601
+ this.name = 'StdError';
315
602
 
316
- got.stream = (url, opts) => asStream(normalizeArguments(url, opts));
603
+ if (error.code !== undefined) {
604
+ this.code = error.code;
605
+ }
317
606
 
318
- for (const el of helpers) {
319
- got.stream[el] = (url, opts) => got.stream(url, Object.assign({}, opts, {method: el}));
607
+ Object.assign(this, {
608
+ host: opts.host,
609
+ hostname: opts.hostname,
610
+ method: opts.method,
611
+ path: opts.path,
612
+ protocol: opts.protocol,
613
+ url: opts.href
614
+ });
615
+ }
320
616
  }
321
617
 
322
- function stdError(error, opts) {
323
- if (error.code !== undefined) {
324
- this.code = error.code;
618
+ got.CacheError = class extends StdError {
619
+ constructor(error, opts) {
620
+ super(error.message, error, opts);
621
+ this.name = 'CacheError';
325
622
  }
623
+ };
326
624
 
327
- Object.assign(this, {
328
- message: error.message,
329
- host: opts.host,
330
- hostname: opts.hostname,
331
- method: opts.method,
332
- path: opts.path
333
- });
334
- }
625
+ got.RequestError = class extends StdError {
626
+ constructor(error, opts) {
627
+ super(error.message, error, opts);
628
+ this.name = 'RequestError';
629
+ }
630
+ };
631
+
632
+ got.ReadError = class extends StdError {
633
+ constructor(error, opts) {
634
+ super(error.message, error, opts);
635
+ this.name = 'ReadError';
636
+ }
637
+ };
638
+
639
+ got.ParseError = class extends StdError {
640
+ constructor(error, statusCode, opts, data) {
641
+ super(`${error.message} in "${urlLib.format(opts)}": \n${data.slice(0, 77)}...`, error, opts);
642
+ this.name = 'ParseError';
643
+ this.statusCode = statusCode;
644
+ this.statusMessage = http.STATUS_CODES[this.statusCode];
645
+ }
646
+ };
647
+
648
+ got.HTTPError = class extends StdError {
649
+ constructor(statusCode, statusMessage, headers, opts) {
650
+ if (statusMessage) {
651
+ statusMessage = statusMessage.replace(/\r?\n/g, ' ').trim();
652
+ } else {
653
+ statusMessage = http.STATUS_CODES[statusCode];
654
+ }
655
+ super(`Response code ${statusCode} (${statusMessage})`, {}, opts);
656
+ this.name = 'HTTPError';
657
+ this.statusCode = statusCode;
658
+ this.statusMessage = statusMessage;
659
+ this.headers = headers;
660
+ }
661
+ };
662
+
663
+ got.MaxRedirectsError = class extends StdError {
664
+ constructor(statusCode, redirectUrls, opts) {
665
+ super('Redirected 10 times. Aborting.', {}, opts);
666
+ this.name = 'MaxRedirectsError';
667
+ this.statusCode = statusCode;
668
+ this.statusMessage = http.STATUS_CODES[this.statusCode];
669
+ this.redirectUrls = redirectUrls;
670
+ }
671
+ };
672
+
673
+ got.UnsupportedProtocolError = class extends StdError {
674
+ constructor(opts) {
675
+ super(`Unsupported protocol "${opts.protocol}"`, {}, opts);
676
+ this.name = 'UnsupportedProtocolError';
677
+ }
678
+ };
335
679
 
336
- got.RequestError = createErrorClass('RequestError', stdError);
337
- got.ReadError = createErrorClass('ReadError', stdError);
338
- got.ParseError = createErrorClass('ParseError', function (e, statusCode, opts, data) {
339
- stdError.call(this, e, opts);
340
- this.statusCode = statusCode;
341
- this.statusMessage = http.STATUS_CODES[this.statusCode];
342
- this.message = `${e.message} in "${urlLib.format(opts)}": \n${data.slice(0, 77)}...`;
343
- });
344
-
345
- got.HTTPError = createErrorClass('HTTPError', function (statusCode, opts) {
346
- stdError.call(this, {}, opts);
347
- this.statusCode = statusCode;
348
- this.statusMessage = http.STATUS_CODES[this.statusCode];
349
- this.message = `Response code ${this.statusCode} (${this.statusMessage})`;
350
- });
351
-
352
- got.MaxRedirectsError = createErrorClass('MaxRedirectsError', function (statusCode, opts) {
353
- stdError.call(this, {}, opts);
354
- this.statusCode = statusCode;
355
- this.statusMessage = http.STATUS_CODES[this.statusCode];
356
- this.message = 'Redirected 10 times. Aborting.';
357
- });
680
+ got.CancelError = PCancelable.CancelError;
358
681
 
359
682
  module.exports = got;