租房小程序前端代码
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.

217 lines
6.2 KiB

3 months ago
  1. var capability = require('./capability');
  2. var inherits = require('inherits');
  3. var stream = require('readable-stream');
  4. var rStates = (exports.readyStates = {
  5. UNSENT: 0,
  6. OPENED: 1,
  7. HEADERS_RECEIVED: 2,
  8. LOADING: 3,
  9. DONE: 4
  10. });
  11. var IncomingMessage = (exports.IncomingMessage = function (xhr, response, mode, fetchTimer) {
  12. var self = this;
  13. stream.Readable.call(self);
  14. self._mode = mode;
  15. self.headers = {};
  16. self.rawHeaders = [];
  17. self.trailers = {};
  18. self.rawTrailers = [];
  19. // Fake the 'close' event, but only once 'end' fires
  20. self.on('end', function () {
  21. // The nextTick is necessary to prevent the 'request' module from causing an infinite loop
  22. process.nextTick(function () {
  23. self.emit('close');
  24. });
  25. });
  26. if (mode === 'fetch') {
  27. self._fetchResponse = response;
  28. self.url = response.url;
  29. self.statusCode = response.status;
  30. self.statusMessage = response.statusText;
  31. response.headers.forEach(function (header, key) {
  32. self.headers[key.toLowerCase()] = header;
  33. self.rawHeaders.push(key, header);
  34. });
  35. if (capability.writableStream) {
  36. var writable = new WritableStream({
  37. write: function (chunk) {
  38. return new Promise(function (resolve, reject) {
  39. if (self._destroyed) {
  40. reject();
  41. } else if (self.push(new Buffer(chunk))) {
  42. resolve();
  43. } else {
  44. self._resumeFetch = resolve;
  45. }
  46. });
  47. },
  48. close: function () {
  49. global.clearTimeout(fetchTimer);
  50. if (!self._destroyed) self.push(null);
  51. },
  52. abort: function (err) {
  53. if (!self._destroyed) self.emit('error', err);
  54. }
  55. });
  56. try {
  57. response.body.pipeTo(writable).catch(function (err) {
  58. global.clearTimeout(fetchTimer);
  59. if (!self._destroyed) self.emit('error', err);
  60. });
  61. return;
  62. } catch (e) {} // pipeTo method isn't defined. Can't find a better way to feature test this
  63. }
  64. // fallback for when writableStream or pipeTo aren't available
  65. var reader = response.body.getReader();
  66. function read() {
  67. reader
  68. .read()
  69. .then(function (result) {
  70. if (self._destroyed) return;
  71. if (result.done) {
  72. global.clearTimeout(fetchTimer);
  73. self.push(null);
  74. return;
  75. }
  76. self.push(new Buffer(result.value));
  77. read();
  78. })
  79. .catch(function (err) {
  80. global.clearTimeout(fetchTimer);
  81. if (!self._destroyed) self.emit('error', err);
  82. });
  83. }
  84. read();
  85. } else {
  86. self._xhr = xhr;
  87. self._pos = 0;
  88. self.url = xhr.responseURL;
  89. self.statusCode = xhr.status;
  90. self.statusMessage = xhr.statusText;
  91. var headers = xhr.getAllResponseHeaders().split(/\r?\n/);
  92. headers.forEach(function (header) {
  93. var matches = header.match(/^([^:]+):\s*(.*)/);
  94. if (matches) {
  95. var key = matches[1].toLowerCase();
  96. if (key === 'set-cookie') {
  97. if (self.headers[key] === undefined) {
  98. self.headers[key] = [];
  99. }
  100. self.headers[key].push(matches[2]);
  101. } else if (self.headers[key] !== undefined) {
  102. self.headers[key] += ', ' + matches[2];
  103. } else {
  104. self.headers[key] = matches[2];
  105. }
  106. self.rawHeaders.push(matches[1], matches[2]);
  107. }
  108. });
  109. self._charset = 'x-user-defined';
  110. if (!capability.overrideMimeType) {
  111. var mimeType = self.rawHeaders['mime-type'];
  112. if (mimeType) {
  113. var charsetMatch = mimeType.match(/;\s*charset=([^;])(;|$)/);
  114. if (charsetMatch) {
  115. self._charset = charsetMatch[1].toLowerCase();
  116. }
  117. }
  118. if (!self._charset) self._charset = 'utf-8'; // best guess
  119. }
  120. }
  121. });
  122. inherits(IncomingMessage, stream.Readable);
  123. IncomingMessage.prototype._read = function () {
  124. var self = this;
  125. var resolve = self._resumeFetch;
  126. if (resolve) {
  127. self._resumeFetch = null;
  128. resolve();
  129. }
  130. };
  131. IncomingMessage.prototype._onXHRProgress = function () {
  132. var self = this;
  133. var xhr = self._xhr;
  134. var response = null;
  135. switch (self._mode) {
  136. case 'text:vbarray': // For IE9
  137. if (xhr.readyState !== rStates.DONE) break;
  138. try {
  139. // This fails in IE8
  140. response = new global.VBArray(xhr.responseBody).toArray();
  141. } catch (e) {}
  142. if (response !== null) {
  143. self.push(new Buffer(response));
  144. break;
  145. }
  146. // Falls through in IE8
  147. case 'text':
  148. try {
  149. // This will fail when readyState = 3 in IE9. Switch mode and wait for readyState = 4
  150. response = xhr.responseText;
  151. } catch (e) {
  152. self._mode = 'text:vbarray';
  153. break;
  154. }
  155. if (response.length > self._pos) {
  156. var newData = response.substr(self._pos);
  157. if (self._charset === 'x-user-defined') {
  158. var buffer = new Buffer(newData.length);
  159. for (var i = 0; i < newData.length; i++) buffer[i] = newData.charCodeAt(i) & 0xff;
  160. self.push(buffer);
  161. } else {
  162. self.push(newData, self._charset);
  163. }
  164. self._pos = response.length;
  165. }
  166. break;
  167. case 'arraybuffer':
  168. if (xhr.readyState !== rStates.DONE || !xhr.response) break;
  169. response = xhr.response;
  170. self.push(new Buffer(new Uint8Array(response)));
  171. break;
  172. case 'moz-chunked-arraybuffer': // take whole
  173. response = xhr.response;
  174. if (xhr.readyState !== rStates.LOADING || !response) break;
  175. self.push(new Buffer(new Uint8Array(response)));
  176. break;
  177. case 'ms-stream':
  178. response = xhr.response;
  179. if (xhr.readyState !== rStates.LOADING) break;
  180. var reader = new global.MSStreamReader();
  181. reader.onprogress = function () {
  182. if (reader.result.byteLength > self._pos) {
  183. self.push(new Buffer(new Uint8Array(reader.result.slice(self._pos))));
  184. self._pos = reader.result.byteLength;
  185. }
  186. };
  187. reader.onload = function () {
  188. self.push(null);
  189. };
  190. // reader.onerror = ??? // TODO: this
  191. reader.readAsArrayBuffer(response);
  192. break;
  193. }
  194. // The ms-stream case handles end separately in reader.onload()
  195. if (self._xhr.readyState === rStates.DONE && self._mode !== 'ms-stream') {
  196. self.push(null);
  197. }
  198. };