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