xhr.js 3.8 KB

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