xhr.js (3627B)
1 var AWS = require('../core'); 2 var EventEmitter = require('events').EventEmitter; 3 require('../http'); 4 5 /** 6 * @api private 7 */ 8 AWS.XHRClient = AWS.util.inherit({ 9 handleRequest: function handleRequest(httpRequest, httpOptions, callback, errCallback) { 10 var self = this; 11 var endpoint = httpRequest.endpoint; 12 var emitter = new EventEmitter(); 13 var href = endpoint.protocol + '//' + endpoint.hostname; 14 if (endpoint.port !== 80 && endpoint.port !== 443) { 15 href += ':' + endpoint.port; 16 } 17 href += httpRequest.path; 18 19 var xhr = new XMLHttpRequest(), headersEmitted = false; 20 httpRequest.stream = xhr; 21 22 xhr.addEventListener('readystatechange', function() { 23 try { 24 if (xhr.status === 0) return; // 0 code is invalid 25 } catch (e) { return; } 26 27 if (this.readyState >= this.HEADERS_RECEIVED && !headersEmitted) { 28 try { xhr.responseType = 'arraybuffer'; } catch (e) {} 29 emitter.statusCode = xhr.status; 30 emitter.headers = self.parseHeaders(xhr.getAllResponseHeaders()); 31 emitter.emit('headers', emitter.statusCode, emitter.headers); 32 headersEmitted = true; 33 } 34 if (this.readyState === this.DONE) { 35 self.finishRequest(xhr, emitter); 36 } 37 }, false); 38 xhr.upload.addEventListener('progress', function (evt) { 39 emitter.emit('sendProgress', evt); 40 }); 41 xhr.addEventListener('progress', function (evt) { 42 emitter.emit('receiveProgress', evt); 43 }, false); 44 xhr.addEventListener('timeout', function () { 45 errCallback(AWS.util.error(new Error('Timeout'), {code: 'TimeoutError'})); 46 }, false); 47 xhr.addEventListener('error', function () { 48 errCallback(AWS.util.error(new Error('Network Failure'), { 49 code: 'NetworkingError' 50 })); 51 }, false); 52 53 callback(emitter); 54 xhr.open(httpRequest.method, href, httpOptions.xhrAsync !== false); 55 AWS.util.each(httpRequest.headers, function (key, value) { 56 if (key !== 'Content-Length' && key !== 'User-Agent' && key !== 'Host') { 57 xhr.setRequestHeader(key, value); 58 } 59 }); 60 61 if (httpOptions.timeout && httpOptions.xhrAsync !== false) { 62 xhr.timeout = httpOptions.timeout; 63 } 64 65 if (httpOptions.xhrWithCredentials) { 66 xhr.withCredentials = true; 67 } 68 69 try { 70 xhr.send(httpRequest.body); 71 } catch (err) { 72 if (httpRequest.body && typeof httpRequest.body.buffer === 'object') { 73 xhr.send(httpRequest.body.buffer); // send ArrayBuffer directly 74 } else { 75 throw err; 76 } 77 } 78 79 return emitter; 80 }, 81 82 parseHeaders: function parseHeaders(rawHeaders) { 83 var headers = {}; 84 AWS.util.arrayEach(rawHeaders.split(/\r?\n/), function (line) { 85 var key = line.split(':', 1)[0]; 86 var value = line.substring(key.length + 2); 87 if (key.length > 0) headers[key.toLowerCase()] = value; 88 }); 89 return headers; 90 }, 91 92 finishRequest: function finishRequest(xhr, emitter) { 93 var buffer; 94 if (xhr.responseType === 'arraybuffer' && xhr.response) { 95 var ab = xhr.response; 96 buffer = new AWS.util.Buffer(ab.byteLength); 97 var view = new Uint8Array(ab); 98 for (var i = 0; i < buffer.length; ++i) { 99 buffer[i] = view[i]; 100 } 101 } 102 103 try { 104 if (!buffer && typeof xhr.responseText === 'string') { 105 buffer = new AWS.util.Buffer(xhr.responseText); 106 } 107 } catch (e) {} 108 109 if (buffer) emitter.emit('data', buffer); 110 emitter.emit('end'); 111 } 112 }); 113 114 /** 115 * @api private 116 */ 117 AWS.HttpClient.prototype = AWS.XHRClient.prototype; 118 119 /** 120 * @api private 121 */ 122 AWS.HttpClient.streamsApiVersion = 1;