1 (function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (factory((global.WHATWGFetch = {})));
5 }(this, (function (exports) { 'use strict';
8 (typeof globalThis !== 'undefined' && globalThis) ||
9 (typeof self !== 'undefined' && self) ||
10 (typeof global !== 'undefined' && global);
13 searchParams: 'URLSearchParams' in global,
14 iterable: 'Symbol' in global && 'iterator' in Symbol,
16 'FileReader' in global &&
26 formData: 'FormData' in global,
27 arrayBuffer: 'ArrayBuffer' in global
30 function isDataView(obj) {
31 return obj && DataView.prototype.isPrototypeOf(obj)
34 if (support.arrayBuffer) {
37 '[object Uint8Array]',
38 '[object Uint8ClampedArray]',
39 '[object Int16Array]',
40 '[object Uint16Array]',
41 '[object Int32Array]',
42 '[object Uint32Array]',
43 '[object Float32Array]',
44 '[object Float64Array]'
47 var isArrayBufferView =
50 return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
54 function normalizeName(name) {
55 if (typeof name !== 'string') {
58 if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {
59 throw new TypeError('Invalid character in header field name: "' + name + '"')
61 return name.toLowerCase()
64 function normalizeValue(value) {
65 if (typeof value !== 'string') {
66 value = String(value);
71 // Build a destructive iterator for the value list
72 function iteratorFor(items) {
75 var value = items.shift();
76 return {done: value === undefined, value: value}
80 if (support.iterable) {
81 iterator[Symbol.iterator] = function() {
89 function Headers(headers) {
92 if (headers instanceof Headers) {
93 headers.forEach(function(value, name) {
94 this.append(name, value);
96 } else if (Array.isArray(headers)) {
97 headers.forEach(function(header) {
98 this.append(header[0], header[1]);
100 } else if (headers) {
101 Object.getOwnPropertyNames(headers).forEach(function(name) {
102 this.append(name, headers[name]);
107 Headers.prototype.append = function(name, value) {
108 name = normalizeName(name);
109 value = normalizeValue(value);
110 var oldValue = this.map[name];
111 this.map[name] = oldValue ? oldValue + ', ' + value : value;
114 Headers.prototype['delete'] = function(name) {
115 delete this.map[normalizeName(name)];
118 Headers.prototype.get = function(name) {
119 name = normalizeName(name);
120 return this.has(name) ? this.map[name] : null
123 Headers.prototype.has = function(name) {
124 return this.map.hasOwnProperty(normalizeName(name))
127 Headers.prototype.set = function(name, value) {
128 this.map[normalizeName(name)] = normalizeValue(value);
131 Headers.prototype.forEach = function(callback, thisArg) {
132 for (var name in this.map) {
133 if (this.map.hasOwnProperty(name)) {
134 callback.call(thisArg, this.map[name], name, this);
139 Headers.prototype.keys = function() {
141 this.forEach(function(value, name) {
144 return iteratorFor(items)
147 Headers.prototype.values = function() {
149 this.forEach(function(value) {
152 return iteratorFor(items)
155 Headers.prototype.entries = function() {
157 this.forEach(function(value, name) {
158 items.push([name, value]);
160 return iteratorFor(items)
163 if (support.iterable) {
164 Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
167 function consumed(body) {
169 return Promise.reject(new TypeError('Already read'))
171 body.bodyUsed = true;
174 function fileReaderReady(reader) {
175 return new Promise(function(resolve, reject) {
176 reader.onload = function() {
177 resolve(reader.result);
179 reader.onerror = function() {
180 reject(reader.error);
185 function readBlobAsArrayBuffer(blob) {
186 var reader = new FileReader();
187 var promise = fileReaderReady(reader);
188 reader.readAsArrayBuffer(blob);
192 function readBlobAsText(blob) {
193 var reader = new FileReader();
194 var promise = fileReaderReady(reader);
195 reader.readAsText(blob);
199 function readArrayBufferAsText(buf) {
200 var view = new Uint8Array(buf);
201 var chars = new Array(view.length);
203 for (var i = 0; i < view.length; i++) {
204 chars[i] = String.fromCharCode(view[i]);
206 return chars.join('')
209 function bufferClone(buf) {
213 var view = new Uint8Array(buf.byteLength);
214 view.set(new Uint8Array(buf));
220 this.bodyUsed = false;
222 this._initBody = function(body) {
224 fetch-mock wraps the Response object in an ES6 Proxy to
225 provide useful test harness features such as flush. However, on
226 ES5 browsers without fetch or Proxy support pollyfills must be used;
227 the proxy-pollyfill is unable to proxy an attribute unless it exists
228 on the object before the Proxy is created. This change ensures
229 Response.bodyUsed exists on the instance, while maintaining the
230 semantic of setting Request.bodyUsed in the constructor before
233 this.bodyUsed = this.bodyUsed;
234 this._bodyInit = body;
237 } else if (typeof body === 'string') {
238 this._bodyText = body;
239 } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
240 this._bodyBlob = body;
241 } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
242 this._bodyFormData = body;
243 } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
244 this._bodyText = body.toString();
245 } else if (support.arrayBuffer && support.blob && isDataView(body)) {
246 this._bodyArrayBuffer = bufferClone(body.buffer);
247 // IE 10-11 can't handle a DataView body.
248 this._bodyInit = new Blob([this._bodyArrayBuffer]);
249 } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
250 this._bodyArrayBuffer = bufferClone(body);
252 this._bodyText = body = Object.prototype.toString.call(body);
255 if (!this.headers.get('content-type')) {
256 if (typeof body === 'string') {
257 this.headers.set('content-type', 'text/plain;charset=UTF-8');
258 } else if (this._bodyBlob && this._bodyBlob.type) {
259 this.headers.set('content-type', this._bodyBlob.type);
260 } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
261 this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
267 this.blob = function() {
268 var rejected = consumed(this);
273 if (this._bodyBlob) {
274 return Promise.resolve(this._bodyBlob)
275 } else if (this._bodyArrayBuffer) {
276 return Promise.resolve(new Blob([this._bodyArrayBuffer]))
277 } else if (this._bodyFormData) {
278 throw new Error('could not read FormData body as blob')
280 return Promise.resolve(new Blob([this._bodyText]))
284 this.arrayBuffer = function() {
285 if (this._bodyArrayBuffer) {
286 var isConsumed = consumed(this);
290 if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
291 return Promise.resolve(
292 this._bodyArrayBuffer.buffer.slice(
293 this._bodyArrayBuffer.byteOffset,
294 this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength
298 return Promise.resolve(this._bodyArrayBuffer)
301 return this.blob().then(readBlobAsArrayBuffer)
306 this.text = function() {
307 var rejected = consumed(this);
312 if (this._bodyBlob) {
313 return readBlobAsText(this._bodyBlob)
314 } else if (this._bodyArrayBuffer) {
315 return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
316 } else if (this._bodyFormData) {
317 throw new Error('could not read FormData body as text')
319 return Promise.resolve(this._bodyText)
323 if (support.formData) {
324 this.formData = function() {
325 return this.text().then(decode)
329 this.json = function() {
330 return this.text().then(JSON.parse)
336 // HTTP methods whose capitalization should be normalized
337 var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
339 function normalizeMethod(method) {
340 var upcased = method.toUpperCase();
341 return methods.indexOf(upcased) > -1 ? upcased : method
344 function Request(input, options) {
345 if (!(this instanceof Request)) {
346 throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.')
349 options = options || {};
350 var body = options.body;
352 if (input instanceof Request) {
353 if (input.bodyUsed) {
354 throw new TypeError('Already read')
356 this.url = input.url;
357 this.credentials = input.credentials;
358 if (!options.headers) {
359 this.headers = new Headers(input.headers);
361 this.method = input.method;
362 this.mode = input.mode;
363 this.signal = input.signal;
364 if (!body && input._bodyInit != null) {
365 body = input._bodyInit;
366 input.bodyUsed = true;
369 this.url = String(input);
372 this.credentials = options.credentials || this.credentials || 'same-origin';
373 if (options.headers || !this.headers) {
374 this.headers = new Headers(options.headers);
376 this.method = normalizeMethod(options.method || this.method || 'GET');
377 this.mode = options.mode || this.mode || null;
378 this.signal = options.signal || this.signal;
379 this.referrer = null;
381 if ((this.method === 'GET' || this.method === 'HEAD') && body) {
382 throw new TypeError('Body not allowed for GET or HEAD requests')
384 this._initBody(body);
386 if (this.method === 'GET' || this.method === 'HEAD') {
387 if (options.cache === 'no-store' || options.cache === 'no-cache') {
388 // Search for a '_' parameter in the query string
389 var reParamSearch = /([?&])_=[^&]*/;
390 if (reParamSearch.test(this.url)) {
391 // If it already exists then set the value with the current time
392 this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime());
394 // Otherwise add a new '_' parameter to the end with the current time
395 var reQueryString = /\?/;
396 this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime();
402 Request.prototype.clone = function() {
403 return new Request(this, {body: this._bodyInit})
406 function decode(body) {
407 var form = new FormData();
411 .forEach(function(bytes) {
413 var split = bytes.split('=');
414 var name = split.shift().replace(/\+/g, ' ');
415 var value = split.join('=').replace(/\+/g, ' ');
416 form.append(decodeURIComponent(name), decodeURIComponent(value));
422 function parseHeaders(rawHeaders) {
423 var headers = new Headers();
424 // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
425 // https://tools.ietf.org/html/rfc7230#section-3.2
426 var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
427 // Avoiding split via regex to work around a common IE11 bug with the core-js 3.6.0 regex polyfill
428 // https://github.com/github/fetch/issues/748
429 // https://github.com/zloirock/core-js/issues/751
432 .map(function(header) {
433 return header.indexOf('\n') === 0 ? header.substr(1, header.length) : header
435 .forEach(function(line) {
436 var parts = line.split(':');
437 var key = parts.shift().trim();
439 var value = parts.join(':').trim();
440 headers.append(key, value);
446 Body.call(Request.prototype);
448 function Response(bodyInit, options) {
449 if (!(this instanceof Response)) {
450 throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.')
456 this.type = 'default';
457 this.status = options.status === undefined ? 200 : options.status;
458 this.ok = this.status >= 200 && this.status < 300;
459 this.statusText = options.statusText === undefined ? '' : '' + options.statusText;
460 this.headers = new Headers(options.headers);
461 this.url = options.url || '';
462 this._initBody(bodyInit);
465 Body.call(Response.prototype);
467 Response.prototype.clone = function() {
468 return new Response(this._bodyInit, {
470 statusText: this.statusText,
471 headers: new Headers(this.headers),
476 Response.error = function() {
477 var response = new Response(null, {status: 0, statusText: ''});
478 response.type = 'error';
482 var redirectStatuses = [301, 302, 303, 307, 308];
484 Response.redirect = function(url, status) {
485 if (redirectStatuses.indexOf(status) === -1) {
486 throw new RangeError('Invalid status code')
489 return new Response(null, {status: status, headers: {location: url}})
492 exports.DOMException = global.DOMException;
494 new exports.DOMException();
496 exports.DOMException = function(message, name) {
497 this.message = message;
499 var error = Error(message);
500 this.stack = error.stack;
502 exports.DOMException.prototype = Object.create(Error.prototype);
503 exports.DOMException.prototype.constructor = exports.DOMException;
506 function fetch(input, init) {
507 return new Promise(function(resolve, reject) {
508 var request = new Request(input, init);
510 if (request.signal && request.signal.aborted) {
511 return reject(new exports.DOMException('Aborted', 'AbortError'))
514 var xhr = new XMLHttpRequest();
516 function abortXhr() {
520 xhr.onload = function() {
523 statusText: xhr.statusText,
524 headers: parseHeaders(xhr.getAllResponseHeaders() || '')
526 options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
527 var body = 'response' in xhr ? xhr.response : xhr.responseText;
528 setTimeout(function() {
529 resolve(new Response(body, options));
533 xhr.onerror = function() {
534 setTimeout(function() {
535 reject(new TypeError('Network request failed'));
539 xhr.ontimeout = function() {
540 setTimeout(function() {
541 reject(new TypeError('Network request failed'));
545 xhr.onabort = function() {
546 setTimeout(function() {
547 reject(new exports.DOMException('Aborted', 'AbortError'));
551 function fixUrl(url) {
553 return url === '' && global.location.href ? global.location.href : url
559 xhr.open(request.method, fixUrl(request.url), true);
561 if (request.credentials === 'include') {
562 xhr.withCredentials = true;
563 } else if (request.credentials === 'omit') {
564 xhr.withCredentials = false;
567 if ('responseType' in xhr) {
569 xhr.responseType = 'blob';
571 support.arrayBuffer &&
572 request.headers.get('Content-Type') &&
573 request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1
575 xhr.responseType = 'arraybuffer';
579 if (init && typeof init.headers === 'object' && !(init.headers instanceof Headers)) {
580 Object.getOwnPropertyNames(init.headers).forEach(function(name) {
581 xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
584 request.headers.forEach(function(value, name) {
585 xhr.setRequestHeader(name, value);
589 if (request.signal) {
590 request.signal.addEventListener('abort', abortXhr);
592 xhr.onreadystatechange = function() {
593 // DONE (success or failure)
594 if (xhr.readyState === 4) {
595 request.signal.removeEventListener('abort', abortXhr);
600 xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
604 fetch.polyfill = true;
607 global.fetch = fetch;
608 global.Headers = Headers;
609 global.Request = Request;
610 global.Response = Response;
613 exports.Headers = Headers;
614 exports.Request = Request;
615 exports.Response = Response;
616 exports.fetch = fetch;
618 Object.defineProperty(exports, '__esModule', { value: true });