You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

517 lines
13 KiB

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