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