Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-go / node_modules / node-fetch / lib / index.mjs
1 import Stream from 'stream';
2 import http from 'http';
3 import Url from 'url';
4 import https from 'https';
5 import zlib from 'zlib';
6
7 // Based on https://github.com/tmpvar/jsdom/blob/aa85b2abf07766ff7bf5c1f6daafb3726f2f2db5/lib/jsdom/living/blob.js
8
9 // fix for "Readable" isn't a named export issue
10 const Readable = Stream.Readable;
11
12 const BUFFER = Symbol('buffer');
13 const TYPE = Symbol('type');
14
15 class Blob {
16         constructor() {
17                 this[TYPE] = '';
18
19                 const blobParts = arguments[0];
20                 const options = arguments[1];
21
22                 const buffers = [];
23                 let size = 0;
24
25                 if (blobParts) {
26                         const a = blobParts;
27                         const length = Number(a.length);
28                         for (let i = 0; i < length; i++) {
29                                 const element = a[i];
30                                 let buffer;
31                                 if (element instanceof Buffer) {
32                                         buffer = element;
33                                 } else if (ArrayBuffer.isView(element)) {
34                                         buffer = Buffer.from(element.buffer, element.byteOffset, element.byteLength);
35                                 } else if (element instanceof ArrayBuffer) {
36                                         buffer = Buffer.from(element);
37                                 } else if (element instanceof Blob) {
38                                         buffer = element[BUFFER];
39                                 } else {
40                                         buffer = Buffer.from(typeof element === 'string' ? element : String(element));
41                                 }
42                                 size += buffer.length;
43                                 buffers.push(buffer);
44                         }
45                 }
46
47                 this[BUFFER] = Buffer.concat(buffers);
48
49                 let type = options && options.type !== undefined && String(options.type).toLowerCase();
50                 if (type && !/[^\u0020-\u007E]/.test(type)) {
51                         this[TYPE] = type;
52                 }
53         }
54         get size() {
55                 return this[BUFFER].length;
56         }
57         get type() {
58                 return this[TYPE];
59         }
60         text() {
61                 return Promise.resolve(this[BUFFER].toString());
62         }
63         arrayBuffer() {
64                 const buf = this[BUFFER];
65                 const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
66                 return Promise.resolve(ab);
67         }
68         stream() {
69                 const readable = new Readable();
70                 readable._read = function () {};
71                 readable.push(this[BUFFER]);
72                 readable.push(null);
73                 return readable;
74         }
75         toString() {
76                 return '[object Blob]';
77         }
78         slice() {
79                 const size = this.size;
80
81                 const start = arguments[0];
82                 const end = arguments[1];
83                 let relativeStart, relativeEnd;
84                 if (start === undefined) {
85                         relativeStart = 0;
86                 } else if (start < 0) {
87                         relativeStart = Math.max(size + start, 0);
88                 } else {
89                         relativeStart = Math.min(start, size);
90                 }
91                 if (end === undefined) {
92                         relativeEnd = size;
93                 } else if (end < 0) {
94                         relativeEnd = Math.max(size + end, 0);
95                 } else {
96                         relativeEnd = Math.min(end, size);
97                 }
98                 const span = Math.max(relativeEnd - relativeStart, 0);
99
100                 const buffer = this[BUFFER];
101                 const slicedBuffer = buffer.slice(relativeStart, relativeStart + span);
102                 const blob = new Blob([], { type: arguments[2] });
103                 blob[BUFFER] = slicedBuffer;
104                 return blob;
105         }
106 }
107
108 Object.defineProperties(Blob.prototype, {
109         size: { enumerable: true },
110         type: { enumerable: true },
111         slice: { enumerable: true }
112 });
113
114 Object.defineProperty(Blob.prototype, Symbol.toStringTag, {
115         value: 'Blob',
116         writable: false,
117         enumerable: false,
118         configurable: true
119 });
120
121 /**
122  * fetch-error.js
123  *
124  * FetchError interface for operational errors
125  */
126
127 /**
128  * Create FetchError instance
129  *
130  * @param   String      message      Error message for human
131  * @param   String      type         Error type for machine
132  * @param   String      systemError  For Node.js system error
133  * @return  FetchError
134  */
135 function FetchError(message, type, systemError) {
136   Error.call(this, message);
137
138   this.message = message;
139   this.type = type;
140
141   // when err.type is `system`, err.code contains system error code
142   if (systemError) {
143     this.code = this.errno = systemError.code;
144   }
145
146   // hide custom error implementation details from end-users
147   Error.captureStackTrace(this, this.constructor);
148 }
149
150 FetchError.prototype = Object.create(Error.prototype);
151 FetchError.prototype.constructor = FetchError;
152 FetchError.prototype.name = 'FetchError';
153
154 let convert;
155 try {
156         convert = require('encoding').convert;
157 } catch (e) {}
158
159 const INTERNALS = Symbol('Body internals');
160
161 // fix an issue where "PassThrough" isn't a named export for node <10
162 const PassThrough = Stream.PassThrough;
163
164 /**
165  * Body mixin
166  *
167  * Ref: https://fetch.spec.whatwg.org/#body
168  *
169  * @param   Stream  body  Readable stream
170  * @param   Object  opts  Response options
171  * @return  Void
172  */
173 function Body(body) {
174         var _this = this;
175
176         var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
177             _ref$size = _ref.size;
178
179         let size = _ref$size === undefined ? 0 : _ref$size;
180         var _ref$timeout = _ref.timeout;
181         let timeout = _ref$timeout === undefined ? 0 : _ref$timeout;
182
183         if (body == null) {
184                 // body is undefined or null
185                 body = null;
186         } else if (isURLSearchParams(body)) {
187                 // body is a URLSearchParams
188                 body = Buffer.from(body.toString());
189         } else if (isBlob(body)) ; else if (Buffer.isBuffer(body)) ; else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
190                 // body is ArrayBuffer
191                 body = Buffer.from(body);
192         } else if (ArrayBuffer.isView(body)) {
193                 // body is ArrayBufferView
194                 body = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
195         } else if (body instanceof Stream) ; else {
196                 // none of the above
197                 // coerce to string then buffer
198                 body = Buffer.from(String(body));
199         }
200         this[INTERNALS] = {
201                 body,
202                 disturbed: false,
203                 error: null
204         };
205         this.size = size;
206         this.timeout = timeout;
207
208         if (body instanceof Stream) {
209                 body.on('error', function (err) {
210                         const error = err.name === 'AbortError' ? err : new FetchError(`Invalid response body while trying to fetch ${_this.url}: ${err.message}`, 'system', err);
211                         _this[INTERNALS].error = error;
212                 });
213         }
214 }
215
216 Body.prototype = {
217         get body() {
218                 return this[INTERNALS].body;
219         },
220
221         get bodyUsed() {
222                 return this[INTERNALS].disturbed;
223         },
224
225         /**
226   * Decode response as ArrayBuffer
227   *
228   * @return  Promise
229   */
230         arrayBuffer() {
231                 return consumeBody.call(this).then(function (buf) {
232                         return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
233                 });
234         },
235
236         /**
237   * Return raw response as Blob
238   *
239   * @return Promise
240   */
241         blob() {
242                 let ct = this.headers && this.headers.get('content-type') || '';
243                 return consumeBody.call(this).then(function (buf) {
244                         return Object.assign(
245                         // Prevent copying
246                         new Blob([], {
247                                 type: ct.toLowerCase()
248                         }), {
249                                 [BUFFER]: buf
250                         });
251                 });
252         },
253
254         /**
255   * Decode response as json
256   *
257   * @return  Promise
258   */
259         json() {
260                 var _this2 = this;
261
262                 return consumeBody.call(this).then(function (buffer) {
263                         try {
264                                 return JSON.parse(buffer.toString());
265                         } catch (err) {
266                                 return Body.Promise.reject(new FetchError(`invalid json response body at ${_this2.url} reason: ${err.message}`, 'invalid-json'));
267                         }
268                 });
269         },
270
271         /**
272   * Decode response as text
273   *
274   * @return  Promise
275   */
276         text() {
277                 return consumeBody.call(this).then(function (buffer) {
278                         return buffer.toString();
279                 });
280         },
281
282         /**
283   * Decode response as buffer (non-spec api)
284   *
285   * @return  Promise
286   */
287         buffer() {
288                 return consumeBody.call(this);
289         },
290
291         /**
292   * Decode response as text, while automatically detecting the encoding and
293   * trying to decode to UTF-8 (non-spec api)
294   *
295   * @return  Promise
296   */
297         textConverted() {
298                 var _this3 = this;
299
300                 return consumeBody.call(this).then(function (buffer) {
301                         return convertBody(buffer, _this3.headers);
302                 });
303         }
304 };
305
306 // In browsers, all properties are enumerable.
307 Object.defineProperties(Body.prototype, {
308         body: { enumerable: true },
309         bodyUsed: { enumerable: true },
310         arrayBuffer: { enumerable: true },
311         blob: { enumerable: true },
312         json: { enumerable: true },
313         text: { enumerable: true }
314 });
315
316 Body.mixIn = function (proto) {
317         for (const name of Object.getOwnPropertyNames(Body.prototype)) {
318                 // istanbul ignore else: future proof
319                 if (!(name in proto)) {
320                         const desc = Object.getOwnPropertyDescriptor(Body.prototype, name);
321                         Object.defineProperty(proto, name, desc);
322                 }
323         }
324 };
325
326 /**
327  * Consume and convert an entire Body to a Buffer.
328  *
329  * Ref: https://fetch.spec.whatwg.org/#concept-body-consume-body
330  *
331  * @return  Promise
332  */
333 function consumeBody() {
334         var _this4 = this;
335
336         if (this[INTERNALS].disturbed) {
337                 return Body.Promise.reject(new TypeError(`body used already for: ${this.url}`));
338         }
339
340         this[INTERNALS].disturbed = true;
341
342         if (this[INTERNALS].error) {
343                 return Body.Promise.reject(this[INTERNALS].error);
344         }
345
346         let body = this.body;
347
348         // body is null
349         if (body === null) {
350                 return Body.Promise.resolve(Buffer.alloc(0));
351         }
352
353         // body is blob
354         if (isBlob(body)) {
355                 body = body.stream();
356         }
357
358         // body is buffer
359         if (Buffer.isBuffer(body)) {
360                 return Body.Promise.resolve(body);
361         }
362
363         // istanbul ignore if: should never happen
364         if (!(body instanceof Stream)) {
365                 return Body.Promise.resolve(Buffer.alloc(0));
366         }
367
368         // body is stream
369         // get ready to actually consume the body
370         let accum = [];
371         let accumBytes = 0;
372         let abort = false;
373
374         return new Body.Promise(function (resolve, reject) {
375                 let resTimeout;
376
377                 // allow timeout on slow response body
378                 if (_this4.timeout) {
379                         resTimeout = setTimeout(function () {
380                                 abort = true;
381                                 reject(new FetchError(`Response timeout while trying to fetch ${_this4.url} (over ${_this4.timeout}ms)`, 'body-timeout'));
382                         }, _this4.timeout);
383                 }
384
385                 // handle stream errors
386                 body.on('error', function (err) {
387                         if (err.name === 'AbortError') {
388                                 // if the request was aborted, reject with this Error
389                                 abort = true;
390                                 reject(err);
391                         } else {
392                                 // other errors, such as incorrect content-encoding
393                                 reject(new FetchError(`Invalid response body while trying to fetch ${_this4.url}: ${err.message}`, 'system', err));
394                         }
395                 });
396
397                 body.on('data', function (chunk) {
398                         if (abort || chunk === null) {
399                                 return;
400                         }
401
402                         if (_this4.size && accumBytes + chunk.length > _this4.size) {
403                                 abort = true;
404                                 reject(new FetchError(`content size at ${_this4.url} over limit: ${_this4.size}`, 'max-size'));
405                                 return;
406                         }
407
408                         accumBytes += chunk.length;
409                         accum.push(chunk);
410                 });
411
412                 body.on('end', function () {
413                         if (abort) {
414                                 return;
415                         }
416
417                         clearTimeout(resTimeout);
418
419                         try {
420                                 resolve(Buffer.concat(accum, accumBytes));
421                         } catch (err) {
422                                 // handle streams that have accumulated too much data (issue #414)
423                                 reject(new FetchError(`Could not create Buffer from response body for ${_this4.url}: ${err.message}`, 'system', err));
424                         }
425                 });
426         });
427 }
428
429 /**
430  * Detect buffer encoding and convert to target encoding
431  * ref: http://www.w3.org/TR/2011/WD-html5-20110113/parsing.html#determining-the-character-encoding
432  *
433  * @param   Buffer  buffer    Incoming buffer
434  * @param   String  encoding  Target encoding
435  * @return  String
436  */
437 function convertBody(buffer, headers) {
438         if (typeof convert !== 'function') {
439                 throw new Error('The package `encoding` must be installed to use the textConverted() function');
440         }
441
442         const ct = headers.get('content-type');
443         let charset = 'utf-8';
444         let res, str;
445
446         // header
447         if (ct) {
448                 res = /charset=([^;]*)/i.exec(ct);
449         }
450
451         // no charset in content type, peek at response body for at most 1024 bytes
452         str = buffer.slice(0, 1024).toString();
453
454         // html5
455         if (!res && str) {
456                 res = /<meta.+?charset=(['"])(.+?)\1/i.exec(str);
457         }
458
459         // html4
460         if (!res && str) {
461                 res = /<meta[\s]+?http-equiv=(['"])content-type\1[\s]+?content=(['"])(.+?)\2/i.exec(str);
462                 if (!res) {
463                         res = /<meta[\s]+?content=(['"])(.+?)\1[\s]+?http-equiv=(['"])content-type\3/i.exec(str);
464                         if (res) {
465                                 res.pop(); // drop last quote
466                         }
467                 }
468
469                 if (res) {
470                         res = /charset=(.*)/i.exec(res.pop());
471                 }
472         }
473
474         // xml
475         if (!res && str) {
476                 res = /<\?xml.+?encoding=(['"])(.+?)\1/i.exec(str);
477         }
478
479         // found charset
480         if (res) {
481                 charset = res.pop();
482
483                 // prevent decode issues when sites use incorrect encoding
484                 // ref: https://hsivonen.fi/encoding-menu/
485                 if (charset === 'gb2312' || charset === 'gbk') {
486                         charset = 'gb18030';
487                 }
488         }
489
490         // turn raw buffers into a single utf-8 buffer
491         return convert(buffer, 'UTF-8', charset).toString();
492 }
493
494 /**
495  * Detect a URLSearchParams object
496  * ref: https://github.com/bitinn/node-fetch/issues/296#issuecomment-307598143
497  *
498  * @param   Object  obj     Object to detect by type or brand
499  * @return  String
500  */
501 function isURLSearchParams(obj) {
502         // Duck-typing as a necessary condition.
503         if (typeof obj !== 'object' || typeof obj.append !== 'function' || typeof obj.delete !== 'function' || typeof obj.get !== 'function' || typeof obj.getAll !== 'function' || typeof obj.has !== 'function' || typeof obj.set !== 'function') {
504                 return false;
505         }
506
507         // Brand-checking and more duck-typing as optional condition.
508         return obj.constructor.name === 'URLSearchParams' || Object.prototype.toString.call(obj) === '[object URLSearchParams]' || typeof obj.sort === 'function';
509 }
510
511 /**
512  * Check if `obj` is a W3C `Blob` object (which `File` inherits from)
513  * @param  {*} obj
514  * @return {boolean}
515  */
516 function isBlob(obj) {
517         return typeof obj === 'object' && typeof obj.arrayBuffer === 'function' && typeof obj.type === 'string' && typeof obj.stream === 'function' && typeof obj.constructor === 'function' && typeof obj.constructor.name === 'string' && /^(Blob|File)$/.test(obj.constructor.name) && /^(Blob|File)$/.test(obj[Symbol.toStringTag]);
518 }
519
520 /**
521  * Clone body given Res/Req instance
522  *
523  * @param   Mixed  instance  Response or Request instance
524  * @return  Mixed
525  */
526 function clone(instance) {
527         let p1, p2;
528         let body = instance.body;
529
530         // don't allow cloning a used body
531         if (instance.bodyUsed) {
532                 throw new Error('cannot clone body after it is used');
533         }
534
535         // check that body is a stream and not form-data object
536         // note: we can't clone the form-data object without having it as a dependency
537         if (body instanceof Stream && typeof body.getBoundary !== 'function') {
538                 // tee instance body
539                 p1 = new PassThrough();
540                 p2 = new PassThrough();
541                 body.pipe(p1);
542                 body.pipe(p2);
543                 // set instance body to teed body and return the other teed body
544                 instance[INTERNALS].body = p1;
545                 body = p2;
546         }
547
548         return body;
549 }
550
551 /**
552  * Performs the operation "extract a `Content-Type` value from |object|" as
553  * specified in the specification:
554  * https://fetch.spec.whatwg.org/#concept-bodyinit-extract
555  *
556  * This function assumes that instance.body is present.
557  *
558  * @param   Mixed  instance  Any options.body input
559  */
560 function extractContentType(body) {
561         if (body === null) {
562                 // body is null
563                 return null;
564         } else if (typeof body === 'string') {
565                 // body is string
566                 return 'text/plain;charset=UTF-8';
567         } else if (isURLSearchParams(body)) {
568                 // body is a URLSearchParams
569                 return 'application/x-www-form-urlencoded;charset=UTF-8';
570         } else if (isBlob(body)) {
571                 // body is blob
572                 return body.type || null;
573         } else if (Buffer.isBuffer(body)) {
574                 // body is buffer
575                 return null;
576         } else if (Object.prototype.toString.call(body) === '[object ArrayBuffer]') {
577                 // body is ArrayBuffer
578                 return null;
579         } else if (ArrayBuffer.isView(body)) {
580                 // body is ArrayBufferView
581                 return null;
582         } else if (typeof body.getBoundary === 'function') {
583                 // detect form data input from form-data module
584                 return `multipart/form-data;boundary=${body.getBoundary()}`;
585         } else if (body instanceof Stream) {
586                 // body is stream
587                 // can't really do much about this
588                 return null;
589         } else {
590                 // Body constructor defaults other things to string
591                 return 'text/plain;charset=UTF-8';
592         }
593 }
594
595 /**
596  * The Fetch Standard treats this as if "total bytes" is a property on the body.
597  * For us, we have to explicitly get it with a function.
598  *
599  * ref: https://fetch.spec.whatwg.org/#concept-body-total-bytes
600  *
601  * @param   Body    instance   Instance of Body
602  * @return  Number?            Number of bytes, or null if not possible
603  */
604 function getTotalBytes(instance) {
605         const body = instance.body;
606
607
608         if (body === null) {
609                 // body is null
610                 return 0;
611         } else if (isBlob(body)) {
612                 return body.size;
613         } else if (Buffer.isBuffer(body)) {
614                 // body is buffer
615                 return body.length;
616         } else if (body && typeof body.getLengthSync === 'function') {
617                 // detect form data input from form-data module
618                 if (body._lengthRetrievers && body._lengthRetrievers.length == 0 || // 1.x
619                 body.hasKnownLength && body.hasKnownLength()) {
620                         // 2.x
621                         return body.getLengthSync();
622                 }
623                 return null;
624         } else {
625                 // body is stream
626                 return null;
627         }
628 }
629
630 /**
631  * Write a Body to a Node.js WritableStream (e.g. http.Request) object.
632  *
633  * @param   Body    instance   Instance of Body
634  * @return  Void
635  */
636 function writeToStream(dest, instance) {
637         const body = instance.body;
638
639
640         if (body === null) {
641                 // body is null
642                 dest.end();
643         } else if (isBlob(body)) {
644                 body.stream().pipe(dest);
645         } else if (Buffer.isBuffer(body)) {
646                 // body is buffer
647                 dest.write(body);
648                 dest.end();
649         } else {
650                 // body is stream
651                 body.pipe(dest);
652         }
653 }
654
655 // expose Promise
656 Body.Promise = global.Promise;
657
658 /**
659  * headers.js
660  *
661  * Headers class offers convenient helpers
662  */
663
664 const invalidTokenRegex = /[^\^_`a-zA-Z\-0-9!#$%&'*+.|~]/;
665 const invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
666
667 function validateName(name) {
668         name = `${name}`;
669         if (invalidTokenRegex.test(name) || name === '') {
670                 throw new TypeError(`${name} is not a legal HTTP header name`);
671         }
672 }
673
674 function validateValue(value) {
675         value = `${value}`;
676         if (invalidHeaderCharRegex.test(value)) {
677                 throw new TypeError(`${value} is not a legal HTTP header value`);
678         }
679 }
680
681 /**
682  * Find the key in the map object given a header name.
683  *
684  * Returns undefined if not found.
685  *
686  * @param   String  name  Header name
687  * @return  String|Undefined
688  */
689 function find(map, name) {
690         name = name.toLowerCase();
691         for (const key in map) {
692                 if (key.toLowerCase() === name) {
693                         return key;
694                 }
695         }
696         return undefined;
697 }
698
699 const MAP = Symbol('map');
700 class Headers {
701         /**
702   * Headers class
703   *
704   * @param   Object  headers  Response headers
705   * @return  Void
706   */
707         constructor() {
708                 let init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
709
710                 this[MAP] = Object.create(null);
711
712                 if (init instanceof Headers) {
713                         const rawHeaders = init.raw();
714                         const headerNames = Object.keys(rawHeaders);
715
716                         for (const headerName of headerNames) {
717                                 for (const value of rawHeaders[headerName]) {
718                                         this.append(headerName, value);
719                                 }
720                         }
721
722                         return;
723                 }
724
725                 // We don't worry about converting prop to ByteString here as append()
726                 // will handle it.
727                 if (init == null) ; else if (typeof init === 'object') {
728                         const method = init[Symbol.iterator];
729                         if (method != null) {
730                                 if (typeof method !== 'function') {
731                                         throw new TypeError('Header pairs must be iterable');
732                                 }
733
734                                 // sequence<sequence<ByteString>>
735                                 // Note: per spec we have to first exhaust the lists then process them
736                                 const pairs = [];
737                                 for (const pair of init) {
738                                         if (typeof pair !== 'object' || typeof pair[Symbol.iterator] !== 'function') {
739                                                 throw new TypeError('Each header pair must be iterable');
740                                         }
741                                         pairs.push(Array.from(pair));
742                                 }
743
744                                 for (const pair of pairs) {
745                                         if (pair.length !== 2) {
746                                                 throw new TypeError('Each header pair must be a name/value tuple');
747                                         }
748                                         this.append(pair[0], pair[1]);
749                                 }
750                         } else {
751                                 // record<ByteString, ByteString>
752                                 for (const key of Object.keys(init)) {
753                                         const value = init[key];
754                                         this.append(key, value);
755                                 }
756                         }
757                 } else {
758                         throw new TypeError('Provided initializer must be an object');
759                 }
760         }
761
762         /**
763   * Return combined header value given name
764   *
765   * @param   String  name  Header name
766   * @return  Mixed
767   */
768         get(name) {
769                 name = `${name}`;
770                 validateName(name);
771                 const key = find(this[MAP], name);
772                 if (key === undefined) {
773                         return null;
774                 }
775
776                 return this[MAP][key].join(', ');
777         }
778
779         /**
780   * Iterate over all headers
781   *
782   * @param   Function  callback  Executed for each item with parameters (value, name, thisArg)
783   * @param   Boolean   thisArg   `this` context for callback function
784   * @return  Void
785   */
786         forEach(callback) {
787                 let thisArg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
788
789                 let pairs = getHeaders(this);
790                 let i = 0;
791                 while (i < pairs.length) {
792                         var _pairs$i = pairs[i];
793                         const name = _pairs$i[0],
794                               value = _pairs$i[1];
795
796                         callback.call(thisArg, value, name, this);
797                         pairs = getHeaders(this);
798                         i++;
799                 }
800         }
801
802         /**
803   * Overwrite header values given name
804   *
805   * @param   String  name   Header name
806   * @param   String  value  Header value
807   * @return  Void
808   */
809         set(name, value) {
810                 name = `${name}`;
811                 value = `${value}`;
812                 validateName(name);
813                 validateValue(value);
814                 const key = find(this[MAP], name);
815                 this[MAP][key !== undefined ? key : name] = [value];
816         }
817
818         /**
819   * Append a value onto existing header
820   *
821   * @param   String  name   Header name
822   * @param   String  value  Header value
823   * @return  Void
824   */
825         append(name, value) {
826                 name = `${name}`;
827                 value = `${value}`;
828                 validateName(name);
829                 validateValue(value);
830                 const key = find(this[MAP], name);
831                 if (key !== undefined) {
832                         this[MAP][key].push(value);
833                 } else {
834                         this[MAP][name] = [value];
835                 }
836         }
837
838         /**
839   * Check for header name existence
840   *
841   * @param   String   name  Header name
842   * @return  Boolean
843   */
844         has(name) {
845                 name = `${name}`;
846                 validateName(name);
847                 return find(this[MAP], name) !== undefined;
848         }
849
850         /**
851   * Delete all header values given name
852   *
853   * @param   String  name  Header name
854   * @return  Void
855   */
856         delete(name) {
857                 name = `${name}`;
858                 validateName(name);
859                 const key = find(this[MAP], name);
860                 if (key !== undefined) {
861                         delete this[MAP][key];
862                 }
863         }
864
865         /**
866   * Return raw headers (non-spec api)
867   *
868   * @return  Object
869   */
870         raw() {
871                 return this[MAP];
872         }
873
874         /**
875   * Get an iterator on keys.
876   *
877   * @return  Iterator
878   */
879         keys() {
880                 return createHeadersIterator(this, 'key');
881         }
882
883         /**
884   * Get an iterator on values.
885   *
886   * @return  Iterator
887   */
888         values() {
889                 return createHeadersIterator(this, 'value');
890         }
891
892         /**
893   * Get an iterator on entries.
894   *
895   * This is the default iterator of the Headers object.
896   *
897   * @return  Iterator
898   */
899         [Symbol.iterator]() {
900                 return createHeadersIterator(this, 'key+value');
901         }
902 }
903 Headers.prototype.entries = Headers.prototype[Symbol.iterator];
904
905 Object.defineProperty(Headers.prototype, Symbol.toStringTag, {
906         value: 'Headers',
907         writable: false,
908         enumerable: false,
909         configurable: true
910 });
911
912 Object.defineProperties(Headers.prototype, {
913         get: { enumerable: true },
914         forEach: { enumerable: true },
915         set: { enumerable: true },
916         append: { enumerable: true },
917         has: { enumerable: true },
918         delete: { enumerable: true },
919         keys: { enumerable: true },
920         values: { enumerable: true },
921         entries: { enumerable: true }
922 });
923
924 function getHeaders(headers) {
925         let kind = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'key+value';
926
927         const keys = Object.keys(headers[MAP]).sort();
928         return keys.map(kind === 'key' ? function (k) {
929                 return k.toLowerCase();
930         } : kind === 'value' ? function (k) {
931                 return headers[MAP][k].join(', ');
932         } : function (k) {
933                 return [k.toLowerCase(), headers[MAP][k].join(', ')];
934         });
935 }
936
937 const INTERNAL = Symbol('internal');
938
939 function createHeadersIterator(target, kind) {
940         const iterator = Object.create(HeadersIteratorPrototype);
941         iterator[INTERNAL] = {
942                 target,
943                 kind,
944                 index: 0
945         };
946         return iterator;
947 }
948
949 const HeadersIteratorPrototype = Object.setPrototypeOf({
950         next() {
951                 // istanbul ignore if
952                 if (!this || Object.getPrototypeOf(this) !== HeadersIteratorPrototype) {
953                         throw new TypeError('Value of `this` is not a HeadersIterator');
954                 }
955
956                 var _INTERNAL = this[INTERNAL];
957                 const target = _INTERNAL.target,
958                       kind = _INTERNAL.kind,
959                       index = _INTERNAL.index;
960
961                 const values = getHeaders(target, kind);
962                 const len = values.length;
963                 if (index >= len) {
964                         return {
965                                 value: undefined,
966                                 done: true
967                         };
968                 }
969
970                 this[INTERNAL].index = index + 1;
971
972                 return {
973                         value: values[index],
974                         done: false
975                 };
976         }
977 }, Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())));
978
979 Object.defineProperty(HeadersIteratorPrototype, Symbol.toStringTag, {
980         value: 'HeadersIterator',
981         writable: false,
982         enumerable: false,
983         configurable: true
984 });
985
986 /**
987  * Export the Headers object in a form that Node.js can consume.
988  *
989  * @param   Headers  headers
990  * @return  Object
991  */
992 function exportNodeCompatibleHeaders(headers) {
993         const obj = Object.assign({ __proto__: null }, headers[MAP]);
994
995         // http.request() only supports string as Host header. This hack makes
996         // specifying custom Host header possible.
997         const hostHeaderKey = find(headers[MAP], 'Host');
998         if (hostHeaderKey !== undefined) {
999                 obj[hostHeaderKey] = obj[hostHeaderKey][0];
1000         }
1001
1002         return obj;
1003 }
1004
1005 /**
1006  * Create a Headers object from an object of headers, ignoring those that do
1007  * not conform to HTTP grammar productions.
1008  *
1009  * @param   Object  obj  Object of headers
1010  * @return  Headers
1011  */
1012 function createHeadersLenient(obj) {
1013         const headers = new Headers();
1014         for (const name of Object.keys(obj)) {
1015                 if (invalidTokenRegex.test(name)) {
1016                         continue;
1017                 }
1018                 if (Array.isArray(obj[name])) {
1019                         for (const val of obj[name]) {
1020                                 if (invalidHeaderCharRegex.test(val)) {
1021                                         continue;
1022                                 }
1023                                 if (headers[MAP][name] === undefined) {
1024                                         headers[MAP][name] = [val];
1025                                 } else {
1026                                         headers[MAP][name].push(val);
1027                                 }
1028                         }
1029                 } else if (!invalidHeaderCharRegex.test(obj[name])) {
1030                         headers[MAP][name] = [obj[name]];
1031                 }
1032         }
1033         return headers;
1034 }
1035
1036 const INTERNALS$1 = Symbol('Response internals');
1037
1038 // fix an issue where "STATUS_CODES" aren't a named export for node <10
1039 const STATUS_CODES = http.STATUS_CODES;
1040
1041 /**
1042  * Response class
1043  *
1044  * @param   Stream  body  Readable stream
1045  * @param   Object  opts  Response options
1046  * @return  Void
1047  */
1048 class Response {
1049         constructor() {
1050                 let body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
1051                 let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1052
1053                 Body.call(this, body, opts);
1054
1055                 const status = opts.status || 200;
1056                 const headers = new Headers(opts.headers);
1057
1058                 if (body != null && !headers.has('Content-Type')) {
1059                         const contentType = extractContentType(body);
1060                         if (contentType) {
1061                                 headers.append('Content-Type', contentType);
1062                         }
1063                 }
1064
1065                 this[INTERNALS$1] = {
1066                         url: opts.url,
1067                         status,
1068                         statusText: opts.statusText || STATUS_CODES[status],
1069                         headers,
1070                         counter: opts.counter
1071                 };
1072         }
1073
1074         get url() {
1075                 return this[INTERNALS$1].url || '';
1076         }
1077
1078         get status() {
1079                 return this[INTERNALS$1].status;
1080         }
1081
1082         /**
1083   * Convenience property representing if the request ended normally
1084   */
1085         get ok() {
1086                 return this[INTERNALS$1].status >= 200 && this[INTERNALS$1].status < 300;
1087         }
1088
1089         get redirected() {
1090                 return this[INTERNALS$1].counter > 0;
1091         }
1092
1093         get statusText() {
1094                 return this[INTERNALS$1].statusText;
1095         }
1096
1097         get headers() {
1098                 return this[INTERNALS$1].headers;
1099         }
1100
1101         /**
1102   * Clone this response
1103   *
1104   * @return  Response
1105   */
1106         clone() {
1107                 return new Response(clone(this), {
1108                         url: this.url,
1109                         status: this.status,
1110                         statusText: this.statusText,
1111                         headers: this.headers,
1112                         ok: this.ok,
1113                         redirected: this.redirected
1114                 });
1115         }
1116 }
1117
1118 Body.mixIn(Response.prototype);
1119
1120 Object.defineProperties(Response.prototype, {
1121         url: { enumerable: true },
1122         status: { enumerable: true },
1123         ok: { enumerable: true },
1124         redirected: { enumerable: true },
1125         statusText: { enumerable: true },
1126         headers: { enumerable: true },
1127         clone: { enumerable: true }
1128 });
1129
1130 Object.defineProperty(Response.prototype, Symbol.toStringTag, {
1131         value: 'Response',
1132         writable: false,
1133         enumerable: false,
1134         configurable: true
1135 });
1136
1137 const INTERNALS$2 = Symbol('Request internals');
1138
1139 // fix an issue where "format", "parse" aren't a named export for node <10
1140 const parse_url = Url.parse;
1141 const format_url = Url.format;
1142
1143 const streamDestructionSupported = 'destroy' in Stream.Readable.prototype;
1144
1145 /**
1146  * Check if a value is an instance of Request.
1147  *
1148  * @param   Mixed   input
1149  * @return  Boolean
1150  */
1151 function isRequest(input) {
1152         return typeof input === 'object' && typeof input[INTERNALS$2] === 'object';
1153 }
1154
1155 function isAbortSignal(signal) {
1156         const proto = signal && typeof signal === 'object' && Object.getPrototypeOf(signal);
1157         return !!(proto && proto.constructor.name === 'AbortSignal');
1158 }
1159
1160 /**
1161  * Request class
1162  *
1163  * @param   Mixed   input  Url or Request instance
1164  * @param   Object  init   Custom options
1165  * @return  Void
1166  */
1167 class Request {
1168         constructor(input) {
1169                 let init = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1170
1171                 let parsedURL;
1172
1173                 // normalize input
1174                 if (!isRequest(input)) {
1175                         if (input && input.href) {
1176                                 // in order to support Node.js' Url objects; though WHATWG's URL objects
1177                                 // will fall into this branch also (since their `toString()` will return
1178                                 // `href` property anyway)
1179                                 parsedURL = parse_url(input.href);
1180                         } else {
1181                                 // coerce input to a string before attempting to parse
1182                                 parsedURL = parse_url(`${input}`);
1183                         }
1184                         input = {};
1185                 } else {
1186                         parsedURL = parse_url(input.url);
1187                 }
1188
1189                 let method = init.method || input.method || 'GET';
1190                 method = method.toUpperCase();
1191
1192                 if ((init.body != null || isRequest(input) && input.body !== null) && (method === 'GET' || method === 'HEAD')) {
1193                         throw new TypeError('Request with GET/HEAD method cannot have body');
1194                 }
1195
1196                 let inputBody = init.body != null ? init.body : isRequest(input) && input.body !== null ? clone(input) : null;
1197
1198                 Body.call(this, inputBody, {
1199                         timeout: init.timeout || input.timeout || 0,
1200                         size: init.size || input.size || 0
1201                 });
1202
1203                 const headers = new Headers(init.headers || input.headers || {});
1204
1205                 if (inputBody != null && !headers.has('Content-Type')) {
1206                         const contentType = extractContentType(inputBody);
1207                         if (contentType) {
1208                                 headers.append('Content-Type', contentType);
1209                         }
1210                 }
1211
1212                 let signal = isRequest(input) ? input.signal : null;
1213                 if ('signal' in init) signal = init.signal;
1214
1215                 if (signal != null && !isAbortSignal(signal)) {
1216                         throw new TypeError('Expected signal to be an instanceof AbortSignal');
1217                 }
1218
1219                 this[INTERNALS$2] = {
1220                         method,
1221                         redirect: init.redirect || input.redirect || 'follow',
1222                         headers,
1223                         parsedURL,
1224                         signal
1225                 };
1226
1227                 // node-fetch-only options
1228                 this.follow = init.follow !== undefined ? init.follow : input.follow !== undefined ? input.follow : 20;
1229                 this.compress = init.compress !== undefined ? init.compress : input.compress !== undefined ? input.compress : true;
1230                 this.counter = init.counter || input.counter || 0;
1231                 this.agent = init.agent || input.agent;
1232         }
1233
1234         get method() {
1235                 return this[INTERNALS$2].method;
1236         }
1237
1238         get url() {
1239                 return format_url(this[INTERNALS$2].parsedURL);
1240         }
1241
1242         get headers() {
1243                 return this[INTERNALS$2].headers;
1244         }
1245
1246         get redirect() {
1247                 return this[INTERNALS$2].redirect;
1248         }
1249
1250         get signal() {
1251                 return this[INTERNALS$2].signal;
1252         }
1253
1254         /**
1255   * Clone this request
1256   *
1257   * @return  Request
1258   */
1259         clone() {
1260                 return new Request(this);
1261         }
1262 }
1263
1264 Body.mixIn(Request.prototype);
1265
1266 Object.defineProperty(Request.prototype, Symbol.toStringTag, {
1267         value: 'Request',
1268         writable: false,
1269         enumerable: false,
1270         configurable: true
1271 });
1272
1273 Object.defineProperties(Request.prototype, {
1274         method: { enumerable: true },
1275         url: { enumerable: true },
1276         headers: { enumerable: true },
1277         redirect: { enumerable: true },
1278         clone: { enumerable: true },
1279         signal: { enumerable: true }
1280 });
1281
1282 /**
1283  * Convert a Request to Node.js http request options.
1284  *
1285  * @param   Request  A Request instance
1286  * @return  Object   The options object to be passed to http.request
1287  */
1288 function getNodeRequestOptions(request) {
1289         const parsedURL = request[INTERNALS$2].parsedURL;
1290         const headers = new Headers(request[INTERNALS$2].headers);
1291
1292         // fetch step 1.3
1293         if (!headers.has('Accept')) {
1294                 headers.set('Accept', '*/*');
1295         }
1296
1297         // Basic fetch
1298         if (!parsedURL.protocol || !parsedURL.hostname) {
1299                 throw new TypeError('Only absolute URLs are supported');
1300         }
1301
1302         if (!/^https?:$/.test(parsedURL.protocol)) {
1303                 throw new TypeError('Only HTTP(S) protocols are supported');
1304         }
1305
1306         if (request.signal && request.body instanceof Stream.Readable && !streamDestructionSupported) {
1307                 throw new Error('Cancellation of streamed requests with AbortSignal is not supported in node < 8');
1308         }
1309
1310         // HTTP-network-or-cache fetch steps 2.4-2.7
1311         let contentLengthValue = null;
1312         if (request.body == null && /^(POST|PUT)$/i.test(request.method)) {
1313                 contentLengthValue = '0';
1314         }
1315         if (request.body != null) {
1316                 const totalBytes = getTotalBytes(request);
1317                 if (typeof totalBytes === 'number') {
1318                         contentLengthValue = String(totalBytes);
1319                 }
1320         }
1321         if (contentLengthValue) {
1322                 headers.set('Content-Length', contentLengthValue);
1323         }
1324
1325         // HTTP-network-or-cache fetch step 2.11
1326         if (!headers.has('User-Agent')) {
1327                 headers.set('User-Agent', 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)');
1328         }
1329
1330         // HTTP-network-or-cache fetch step 2.15
1331         if (request.compress && !headers.has('Accept-Encoding')) {
1332                 headers.set('Accept-Encoding', 'gzip,deflate');
1333         }
1334
1335         let agent = request.agent;
1336         if (typeof agent === 'function') {
1337                 agent = agent(parsedURL);
1338         }
1339
1340         if (!headers.has('Connection') && !agent) {
1341                 headers.set('Connection', 'close');
1342         }
1343
1344         // HTTP-network fetch step 4.2
1345         // chunked encoding is handled by Node.js
1346
1347         return Object.assign({}, parsedURL, {
1348                 method: request.method,
1349                 headers: exportNodeCompatibleHeaders(headers),
1350                 agent
1351         });
1352 }
1353
1354 /**
1355  * abort-error.js
1356  *
1357  * AbortError interface for cancelled requests
1358  */
1359
1360 /**
1361  * Create AbortError instance
1362  *
1363  * @param   String      message      Error message for human
1364  * @return  AbortError
1365  */
1366 function AbortError(message) {
1367   Error.call(this, message);
1368
1369   this.type = 'aborted';
1370   this.message = message;
1371
1372   // hide custom error implementation details from end-users
1373   Error.captureStackTrace(this, this.constructor);
1374 }
1375
1376 AbortError.prototype = Object.create(Error.prototype);
1377 AbortError.prototype.constructor = AbortError;
1378 AbortError.prototype.name = 'AbortError';
1379
1380 // fix an issue where "PassThrough", "resolve" aren't a named export for node <10
1381 const PassThrough$1 = Stream.PassThrough;
1382 const resolve_url = Url.resolve;
1383
1384 /**
1385  * Fetch function
1386  *
1387  * @param   Mixed    url   Absolute url or Request instance
1388  * @param   Object   opts  Fetch options
1389  * @return  Promise
1390  */
1391 function fetch(url, opts) {
1392
1393         // allow custom promise
1394         if (!fetch.Promise) {
1395                 throw new Error('native promise missing, set fetch.Promise to your favorite alternative');
1396         }
1397
1398         Body.Promise = fetch.Promise;
1399
1400         // wrap http.request into fetch
1401         return new fetch.Promise(function (resolve, reject) {
1402                 // build request object
1403                 const request = new Request(url, opts);
1404                 const options = getNodeRequestOptions(request);
1405
1406                 const send = (options.protocol === 'https:' ? https : http).request;
1407                 const signal = request.signal;
1408
1409                 let response = null;
1410
1411                 const abort = function abort() {
1412                         let error = new AbortError('The user aborted a request.');
1413                         reject(error);
1414                         if (request.body && request.body instanceof Stream.Readable) {
1415                                 request.body.destroy(error);
1416                         }
1417                         if (!response || !response.body) return;
1418                         response.body.emit('error', error);
1419                 };
1420
1421                 if (signal && signal.aborted) {
1422                         abort();
1423                         return;
1424                 }
1425
1426                 const abortAndFinalize = function abortAndFinalize() {
1427                         abort();
1428                         finalize();
1429                 };
1430
1431                 // send request
1432                 const req = send(options);
1433                 let reqTimeout;
1434
1435                 if (signal) {
1436                         signal.addEventListener('abort', abortAndFinalize);
1437                 }
1438
1439                 function finalize() {
1440                         req.abort();
1441                         if (signal) signal.removeEventListener('abort', abortAndFinalize);
1442                         clearTimeout(reqTimeout);
1443                 }
1444
1445                 if (request.timeout) {
1446                         req.once('socket', function (socket) {
1447                                 reqTimeout = setTimeout(function () {
1448                                         reject(new FetchError(`network timeout at: ${request.url}`, 'request-timeout'));
1449                                         finalize();
1450                                 }, request.timeout);
1451                         });
1452                 }
1453
1454                 req.on('error', function (err) {
1455                         reject(new FetchError(`request to ${request.url} failed, reason: ${err.message}`, 'system', err));
1456                         finalize();
1457                 });
1458
1459                 req.on('response', function (res) {
1460                         clearTimeout(reqTimeout);
1461
1462                         const headers = createHeadersLenient(res.headers);
1463
1464                         // HTTP fetch step 5
1465                         if (fetch.isRedirect(res.statusCode)) {
1466                                 // HTTP fetch step 5.2
1467                                 const location = headers.get('Location');
1468
1469                                 // HTTP fetch step 5.3
1470                                 const locationURL = location === null ? null : resolve_url(request.url, location);
1471
1472                                 // HTTP fetch step 5.5
1473                                 switch (request.redirect) {
1474                                         case 'error':
1475                                                 reject(new FetchError(`uri requested responds with a redirect, redirect mode is set to error: ${request.url}`, 'no-redirect'));
1476                                                 finalize();
1477                                                 return;
1478                                         case 'manual':
1479                                                 // node-fetch-specific step: make manual redirect a bit easier to use by setting the Location header value to the resolved URL.
1480                                                 if (locationURL !== null) {
1481                                                         // handle corrupted header
1482                                                         try {
1483                                                                 headers.set('Location', locationURL);
1484                                                         } catch (err) {
1485                                                                 // istanbul ignore next: nodejs server prevent invalid response headers, we can't test this through normal request
1486                                                                 reject(err);
1487                                                         }
1488                                                 }
1489                                                 break;
1490                                         case 'follow':
1491                                                 // HTTP-redirect fetch step 2
1492                                                 if (locationURL === null) {
1493                                                         break;
1494                                                 }
1495
1496                                                 // HTTP-redirect fetch step 5
1497                                                 if (request.counter >= request.follow) {
1498                                                         reject(new FetchError(`maximum redirect reached at: ${request.url}`, 'max-redirect'));
1499                                                         finalize();
1500                                                         return;
1501                                                 }
1502
1503                                                 // HTTP-redirect fetch step 6 (counter increment)
1504                                                 // Create a new Request object.
1505                                                 const requestOpts = {
1506                                                         headers: new Headers(request.headers),
1507                                                         follow: request.follow,
1508                                                         counter: request.counter + 1,
1509                                                         agent: request.agent,
1510                                                         compress: request.compress,
1511                                                         method: request.method,
1512                                                         body: request.body,
1513                                                         signal: request.signal,
1514                                                         timeout: request.timeout,
1515                                                         size: request.size
1516                                                 };
1517
1518                                                 // HTTP-redirect fetch step 9
1519                                                 if (res.statusCode !== 303 && request.body && getTotalBytes(request) === null) {
1520                                                         reject(new FetchError('Cannot follow redirect with body being a readable stream', 'unsupported-redirect'));
1521                                                         finalize();
1522                                                         return;
1523                                                 }
1524
1525                                                 // HTTP-redirect fetch step 11
1526                                                 if (res.statusCode === 303 || (res.statusCode === 301 || res.statusCode === 302) && request.method === 'POST') {
1527                                                         requestOpts.method = 'GET';
1528                                                         requestOpts.body = undefined;
1529                                                         requestOpts.headers.delete('content-length');
1530                                                 }
1531
1532                                                 // HTTP-redirect fetch step 15
1533                                                 resolve(fetch(new Request(locationURL, requestOpts)));
1534                                                 finalize();
1535                                                 return;
1536                                 }
1537                         }
1538
1539                         // prepare response
1540                         res.once('end', function () {
1541                                 if (signal) signal.removeEventListener('abort', abortAndFinalize);
1542                         });
1543                         let body = res.pipe(new PassThrough$1());
1544
1545                         const response_options = {
1546                                 url: request.url,
1547                                 status: res.statusCode,
1548                                 statusText: res.statusMessage,
1549                                 headers: headers,
1550                                 size: request.size,
1551                                 timeout: request.timeout,
1552                                 counter: request.counter
1553                         };
1554
1555                         // HTTP-network fetch step 12.1.1.3
1556                         const codings = headers.get('Content-Encoding');
1557
1558                         // HTTP-network fetch step 12.1.1.4: handle content codings
1559
1560                         // in following scenarios we ignore compression support
1561                         // 1. compression support is disabled
1562                         // 2. HEAD request
1563                         // 3. no Content-Encoding header
1564                         // 4. no content response (204)
1565                         // 5. content not modified response (304)
1566                         if (!request.compress || request.method === 'HEAD' || codings === null || res.statusCode === 204 || res.statusCode === 304) {
1567                                 response = new Response(body, response_options);
1568                                 resolve(response);
1569                                 return;
1570                         }
1571
1572                         // For Node v6+
1573                         // Be less strict when decoding compressed responses, since sometimes
1574                         // servers send slightly invalid responses that are still accepted
1575                         // by common browsers.
1576                         // Always using Z_SYNC_FLUSH is what cURL does.
1577                         const zlibOptions = {
1578                                 flush: zlib.Z_SYNC_FLUSH,
1579                                 finishFlush: zlib.Z_SYNC_FLUSH
1580                         };
1581
1582                         // for gzip
1583                         if (codings == 'gzip' || codings == 'x-gzip') {
1584                                 body = body.pipe(zlib.createGunzip(zlibOptions));
1585                                 response = new Response(body, response_options);
1586                                 resolve(response);
1587                                 return;
1588                         }
1589
1590                         // for deflate
1591                         if (codings == 'deflate' || codings == 'x-deflate') {
1592                                 // handle the infamous raw deflate response from old servers
1593                                 // a hack for old IIS and Apache servers
1594                                 const raw = res.pipe(new PassThrough$1());
1595                                 raw.once('data', function (chunk) {
1596                                         // see http://stackoverflow.com/questions/37519828
1597                                         if ((chunk[0] & 0x0F) === 0x08) {
1598                                                 body = body.pipe(zlib.createInflate());
1599                                         } else {
1600                                                 body = body.pipe(zlib.createInflateRaw());
1601                                         }
1602                                         response = new Response(body, response_options);
1603                                         resolve(response);
1604                                 });
1605                                 return;
1606                         }
1607
1608                         // for br
1609                         if (codings == 'br' && typeof zlib.createBrotliDecompress === 'function') {
1610                                 body = body.pipe(zlib.createBrotliDecompress());
1611                                 response = new Response(body, response_options);
1612                                 resolve(response);
1613                                 return;
1614                         }
1615
1616                         // otherwise, use response as-is
1617                         response = new Response(body, response_options);
1618                         resolve(response);
1619                 });
1620
1621                 writeToStream(req, request);
1622         });
1623 }
1624 /**
1625  * Redirect code matching
1626  *
1627  * @param   Number   code  Status code
1628  * @return  Boolean
1629  */
1630 fetch.isRedirect = function (code) {
1631         return code === 301 || code === 302 || code === 303 || code === 307 || code === 308;
1632 };
1633
1634 // expose Promise
1635 fetch.Promise = global.Promise;
1636
1637 export default fetch;
1638 export { Headers, Request, Response, FetchError };