UNPKG

16.9 kBJavaScriptView Raw
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) {
6
7 var global = (function(self) {
8 return self
9 // eslint-disable-next-line no-invalid-this
10 })(typeof self !== 'undefined' ? self : this);
11 var support = {
12 searchParams: 'URLSearchParams' in global,
13 iterable: 'Symbol' in global && 'iterator' in Symbol,
14 blob:
15 'FileReader' in global &&
16 'Blob' in global &&
17 (function() {
18 try {
19 new Blob();
20 return true
21 } catch (e) {
22 return false
23 }
24 })(),
25 formData: 'FormData' in global,
26 arrayBuffer: 'ArrayBuffer' in global
27 };
28
29 function isDataView(obj) {
30 return obj && DataView.prototype.isPrototypeOf(obj)
31 }
32
33 if (support.arrayBuffer) {
34 var viewClasses = [
35 '[object Int8Array]',
36 '[object Uint8Array]',
37 '[object Uint8ClampedArray]',
38 '[object Int16Array]',
39 '[object Uint16Array]',
40 '[object Int32Array]',
41 '[object Uint32Array]',
42 '[object Float32Array]',
43 '[object Float64Array]'
44 ];
45
46 var isArrayBufferView =
47 ArrayBuffer.isView ||
48 function(obj) {
49 return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
50 };
51 }
52
53 function normalizeName(name) {
54 if (typeof name !== 'string') {
55 name = String(name);
56 }
57 if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {
58 throw new TypeError('Invalid character in header field name')
59 }
60 return name.toLowerCase()
61 }
62
63 function normalizeValue(value) {
64 if (typeof value !== 'string') {
65 value = String(value);
66 }
67 return value
68 }
69
70 // Build a destructive iterator for the value list
71 function iteratorFor(items) {
72 var iterator = {
73 next: function() {
74 var value = items.shift();
75 return {done: value === undefined, value: value}
76 }
77 };
78
79 if (support.iterable) {
80 iterator[Symbol.iterator] = function() {
81 return iterator
82 };
83 }
84
85 return iterator
86 }
87
88 function Headers(headers) {
89 this.map = {};
90
91 if (headers instanceof Headers) {
92 headers.forEach(function(value, name) {
93 this.append(name, value);
94 }, this);
95 } else if (Array.isArray(headers)) {
96 headers.forEach(function(header) {
97 this.append(header[0], header[1]);
98 }, this);
99 } else if (headers) {
100 Object.getOwnPropertyNames(headers).forEach(function(name) {
101 this.append(name, headers[name]);
102 }, this);
103 }
104 }
105
106 Headers.prototype.append = function(name, value) {
107 name = normalizeName(name);
108 value = normalizeValue(value);
109 var oldValue = this.map[name];
110 this.map[name] = oldValue ? oldValue + ', ' + value : value;
111 };
112
113 Headers.prototype['delete'] = function(name) {
114 delete this.map[normalizeName(name)];
115 };
116
117 Headers.prototype.get = function(name) {
118 name = normalizeName(name);
119 return this.has(name) ? this.map[name] : null
120 };
121
122 Headers.prototype.has = function(name) {
123 return this.map.hasOwnProperty(normalizeName(name))
124 };
125
126 Headers.prototype.set = function(name, value) {
127 this.map[normalizeName(name)] = normalizeValue(value);
128 };
129
130 Headers.prototype.forEach = function(callback, thisArg) {
131 for (var name in this.map) {
132 if (this.map.hasOwnProperty(name)) {
133 callback.call(thisArg, this.map[name], name, this);
134 }
135 }
136 };
137
138 Headers.prototype.keys = function() {
139 var items = [];
140 this.forEach(function(value, name) {
141 items.push(name);
142 });
143 return iteratorFor(items)
144 };
145
146 Headers.prototype.values = function() {
147 var items = [];
148 this.forEach(function(value) {
149 items.push(value);
150 });
151 return iteratorFor(items)
152 };
153
154 Headers.prototype.entries = function() {
155 var items = [];
156 this.forEach(function(value, name) {
157 items.push([name, value]);
158 });
159 return iteratorFor(items)
160 };
161
162 if (support.iterable) {
163 Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
164 }
165
166 function consumed(body) {
167 if (body.bodyUsed) {
168 return Promise.reject(new TypeError('Already read'))
169 }
170 body.bodyUsed = true;
171 }
172
173 function fileReaderReady(reader) {
174 return new Promise(function(resolve, reject) {
175 reader.onload = function() {
176 resolve(reader.result);
177 };
178 reader.onerror = function() {
179 reject(reader.error);
180 };
181 })
182 }
183
184 function readBlobAsArrayBuffer(blob) {
185 var reader = new FileReader();
186 var promise = fileReaderReady(reader);
187 reader.readAsArrayBuffer(blob);
188 return promise
189 }
190
191 function readBlobAsText(blob) {
192 var reader = new FileReader();
193 var promise = fileReaderReady(reader);
194 reader.readAsText(blob);
195 return promise
196 }
197
198 function readArrayBufferAsText(buf) {
199 var view = new Uint8Array(buf);
200 var chars = new Array(view.length);
201
202 for (var i = 0; i < view.length; i++) {
203 chars[i] = String.fromCharCode(view[i]);
204 }
205 return chars.join('')
206 }
207
208 function bufferClone(buf) {
209 if (buf.slice) {
210 return buf.slice(0)
211 } else {
212 var view = new Uint8Array(buf.byteLength);
213 view.set(new Uint8Array(buf));
214 return view.buffer
215 }
216 }
217
218 function Body() {
219 this.bodyUsed = false;
220
221 this._initBody = function(body) {
222 /*
223 fetch-mock wraps the Response object in an ES6 Proxy to
224 provide useful test harness features such as flush. However, on
225 ES5 browsers without fetch or Proxy support pollyfills must be used;
226 the proxy-pollyfill is unable to proxy an attribute unless it exists
227 on the object before the Proxy is created. This change ensures
228 Response.bodyUsed exists on the instance, while maintaining the
229 semantic of setting Request.bodyUsed in the constructor before
230 _initBody is called.
231 */
232 this.bodyUsed = this.bodyUsed;
233 this._bodyInit = body;
234 if (!body) {
235 this._bodyText = '';
236 } else if (typeof body === 'string') {
237 this._bodyText = body;
238 } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
239 this._bodyBlob = body;
240 } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
241 this._bodyFormData = body;
242 } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
243 this._bodyText = body.toString();
244 } else if (support.arrayBuffer && support.blob && isDataView(body)) {
245 this._bodyArrayBuffer = bufferClone(body.buffer);
246 // IE 10-11 can't handle a DataView body.
247 this._bodyInit = new Blob([this._bodyArrayBuffer]);
248 } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
249 this._bodyArrayBuffer = bufferClone(body);
250 } else {
251 this._bodyText = body = Object.prototype.toString.call(body);
252 }
253
254 if (!this.headers.get('content-type')) {
255 if (typeof body === 'string') {
256 this.headers.set('content-type', 'text/plain;charset=UTF-8');
257 } else if (this._bodyBlob && this._bodyBlob.type) {
258 this.headers.set('content-type', this._bodyBlob.type);
259 } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
260 this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
261 }
262 }
263 };
264
265 if (support.blob) {
266 this.blob = function() {
267 var rejected = consumed(this);
268 if (rejected) {
269 return rejected
270 }
271
272 if (this._bodyBlob) {
273 return Promise.resolve(this._bodyBlob)
274 } else if (this._bodyArrayBuffer) {
275 return Promise.resolve(new Blob([this._bodyArrayBuffer]))
276 } else if (this._bodyFormData) {
277 throw new Error('could not read FormData body as blob')
278 } else {
279 return Promise.resolve(new Blob([this._bodyText]))
280 }
281 };
282
283 this.arrayBuffer = function() {
284 if (this._bodyArrayBuffer) {
285 return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
286 } else {
287 return this.blob().then(readBlobAsArrayBuffer)
288 }
289 };
290 }
291
292 this.text = function() {
293 var rejected = consumed(this);
294 if (rejected) {
295 return rejected
296 }
297
298 if (this._bodyBlob) {
299 return readBlobAsText(this._bodyBlob)
300 } else if (this._bodyArrayBuffer) {
301 return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
302 } else if (this._bodyFormData) {
303 throw new Error('could not read FormData body as text')
304 } else {
305 return Promise.resolve(this._bodyText)
306 }
307 };
308
309 if (support.formData) {
310 this.formData = function() {
311 return this.text().then(decode)
312 };
313 }
314
315 this.json = function() {
316 return this.text().then(JSON.parse)
317 };
318
319 return this
320 }
321
322 // HTTP methods whose capitalization should be normalized
323 var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
324
325 function normalizeMethod(method) {
326 var upcased = method.toUpperCase();
327 return methods.indexOf(upcased) > -1 ? upcased : method
328 }
329
330 function Request(input, options) {
331 options = options || {};
332 var body = options.body;
333
334 if (input instanceof Request) {
335 if (input.bodyUsed) {
336 throw new TypeError('Already read')
337 }
338 this.url = input.url;
339 this.credentials = input.credentials;
340 if (!options.headers) {
341 this.headers = new Headers(input.headers);
342 }
343 this.method = input.method;
344 this.mode = input.mode;
345 this.signal = input.signal;
346 if (!body && input._bodyInit != null) {
347 body = input._bodyInit;
348 input.bodyUsed = true;
349 }
350 } else {
351 this.url = String(input);
352 }
353
354 this.credentials = options.credentials || this.credentials || 'same-origin';
355 if (options.headers || !this.headers) {
356 this.headers = new Headers(options.headers);
357 }
358 this.method = normalizeMethod(options.method || this.method || 'GET');
359 this.mode = options.mode || this.mode || null;
360 this.signal = options.signal || this.signal;
361 this.referrer = null;
362
363 if ((this.method === 'GET' || this.method === 'HEAD') && body) {
364 throw new TypeError('Body not allowed for GET or HEAD requests')
365 }
366 this._initBody(body);
367
368 if (this.method === 'GET' || this.method === 'HEAD') {
369 if (options.cache === 'no-store' || options.cache === 'no-cache') {
370 // Search for a '_' parameter in the query string
371 var reParamSearch = /([?&])_=[^&]*/;
372 if (reParamSearch.test(this.url)) {
373 // If it already exists then set the value with the current time
374 this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime());
375 } else {
376 // Otherwise add a new '_' parameter to the end with the current time
377 var reQueryString = /\?/;
378 this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime();
379 }
380 }
381 }
382 }
383
384 Request.prototype.clone = function() {
385 return new Request(this, {body: this._bodyInit})
386 };
387
388 function decode(body) {
389 var form = new FormData();
390 body
391 .trim()
392 .split('&')
393 .forEach(function(bytes) {
394 if (bytes) {
395 var split = bytes.split('=');
396 var name = split.shift().replace(/\+/g, ' ');
397 var value = split.join('=').replace(/\+/g, ' ');
398 form.append(decodeURIComponent(name), decodeURIComponent(value));
399 }
400 });
401 return form
402 }
403
404 function parseHeaders(rawHeaders) {
405 var headers = new Headers();
406 // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
407 // https://tools.ietf.org/html/rfc7230#section-3.2
408 var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
409 preProcessedHeaders.split(/\r?\n/).forEach(function(line) {
410 var parts = line.split(':');
411 var key = parts.shift().trim();
412 if (key) {
413 var value = parts.join(':').trim();
414 headers.append(key, value);
415 }
416 });
417 return headers
418 }
419
420 Body.call(Request.prototype);
421
422 function Response(bodyInit, options) {
423 if (!options) {
424 options = {};
425 }
426
427 this.type = 'default';
428 this.status = options.status === undefined ? 200 : options.status;
429 this.ok = this.status >= 200 && this.status < 300;
430 this.statusText = 'statusText' in options ? options.statusText : '';
431 this.headers = new Headers(options.headers);
432 this.url = options.url || '';
433 this._initBody(bodyInit);
434 }
435
436 Body.call(Response.prototype);
437
438 Response.prototype.clone = function() {
439 return new Response(this._bodyInit, {
440 status: this.status,
441 statusText: this.statusText,
442 headers: new Headers(this.headers),
443 url: this.url
444 })
445 };
446
447 Response.error = function() {
448 var response = new Response(null, {status: 0, statusText: ''});
449 response.type = 'error';
450 return response
451 };
452
453 var redirectStatuses = [301, 302, 303, 307, 308];
454
455 Response.redirect = function(url, status) {
456 if (redirectStatuses.indexOf(status) === -1) {
457 throw new RangeError('Invalid status code')
458 }
459
460 return new Response(null, {status: status, headers: {location: url}})
461 };
462
463 exports.DOMException = global.DOMException;
464
465 if (typeof exports.DOMException !== 'function') {
466 exports.DOMException = function(message, name) {
467 this.message = message;
468 this.name = name;
469 var error = Error(message);
470 this.stack = error.stack;
471 };
472 exports.DOMException.prototype = Object.create(Error.prototype);
473 exports.DOMException.prototype.constructor = exports.DOMException;
474 }
475
476 function fetch(input, init) {
477 return new Promise(function(resolve, reject) {
478 var request = new Request(input, init);
479
480 if (request.signal && request.signal.aborted) {
481 return reject(new exports.DOMException('Aborted', 'AbortError'))
482 }
483
484 var xhr = new XMLHttpRequest();
485
486 function abortXhr() {
487 xhr.abort();
488 }
489
490 xhr.onload = function() {
491 var options = {
492 status: xhr.status,
493 statusText: xhr.statusText,
494 headers: parseHeaders(xhr.getAllResponseHeaders() || '')
495 };
496 options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
497 var body = 'response' in xhr ? xhr.response : xhr.responseText;
498 setTimeout(function() {
499 resolve(new Response(body, options));
500 }, 0);
501 };
502
503 xhr.onerror = function() {
504 setTimeout(function() {
505 reject(new TypeError('Network request failed'));
506 }, 0);
507 };
508
509 xhr.ontimeout = function() {
510 setTimeout(function() {
511 reject(new TypeError('Network request failed'));
512 }, 0);
513 };
514
515 xhr.onabort = function() {
516 setTimeout(function() {
517 reject(new exports.DOMException('Aborted', 'AbortError'));
518 }, 0);
519 };
520
521 function fixUrl(url) {
522 try {
523 return url === '' && global.location.href ? global.location.href : url
524 } catch (e) {
525 return url
526 }
527 }
528
529 xhr.open(request.method, fixUrl(request.url), true);
530
531 if (request.credentials === 'include') {
532 xhr.withCredentials = true;
533 } else if (request.credentials === 'omit') {
534 xhr.withCredentials = false;
535 }
536
537 if ('responseType' in xhr) {
538 if (support.blob) {
539 xhr.responseType = 'blob';
540 } else if (
541 support.arrayBuffer &&
542 request.headers.get('Content-Type') &&
543 request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1
544 ) {
545 xhr.responseType = 'arraybuffer';
546 }
547 }
548
549 request.headers.forEach(function(value, name) {
550 xhr.setRequestHeader(name, value);
551 });
552
553 if (request.signal) {
554 request.signal.addEventListener('abort', abortXhr);
555
556 xhr.onreadystatechange = function() {
557 // DONE (success or failure)
558 if (xhr.readyState === 4) {
559 request.signal.removeEventListener('abort', abortXhr);
560 }
561 };
562 }
563
564 xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
565 })
566 }
567
568 fetch.polyfill = true;
569
570 if (!global.fetch) {
571 global.fetch = fetch;
572 global.Headers = Headers;
573 global.Request = Request;
574 global.Response = Response;
575 }
576
577 exports.Headers = Headers;
578 exports.Request = Request;
579 exports.Response = Response;
580 exports.fetch = fetch;
581
582 Object.defineProperty(exports, '__esModule', { value: true });
583
584})));