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