|                                                                                                                                                                                                                         |  | var capability = require('./capability');var inherits = require('inherits');var stream = require('readable-stream');
var rStates = (exports.readyStates = {  UNSENT: 0,  OPENED: 1,  HEADERS_RECEIVED: 2,  LOADING: 3,  DONE: 4});
var IncomingMessage = (exports.IncomingMessage = function (xhr, response, mode, fetchTimer) {  var self = this;  stream.Readable.call(self);
  self._mode = mode;  self.headers = {};  self.rawHeaders = [];  self.trailers = {};  self.rawTrailers = [];
  // Fake the 'close' event, but only once 'end' fires
  self.on('end', function () {    // The nextTick is necessary to prevent the 'request' module from causing an infinite loop
    process.nextTick(function () {      self.emit('close');    });  });
  if (mode === 'fetch') {    self._fetchResponse = response;
    self.url = response.url;    self.statusCode = response.status;    self.statusMessage = response.statusText;
    response.headers.forEach(function (header, key) {      self.headers[key.toLowerCase()] = header;      self.rawHeaders.push(key, header);    });
    if (capability.writableStream) {      var writable = new WritableStream({        write: function (chunk) {          return new Promise(function (resolve, reject) {            if (self._destroyed) {              reject();            } else if (self.push(new Buffer(chunk))) {              resolve();            } else {              self._resumeFetch = resolve;            }          });        },        close: function () {          global.clearTimeout(fetchTimer);          if (!self._destroyed) self.push(null);        },        abort: function (err) {          if (!self._destroyed) self.emit('error', err);        }      });
      try {        response.body.pipeTo(writable).catch(function (err) {          global.clearTimeout(fetchTimer);          if (!self._destroyed) self.emit('error', err);        });        return;      } catch (e) {} // pipeTo method isn't defined. Can't find a better way to feature test this
    }    // fallback for when writableStream or pipeTo aren't available
    var reader = response.body.getReader();    function read() {      reader        .read()        .then(function (result) {          if (self._destroyed) return;          if (result.done) {            global.clearTimeout(fetchTimer);            self.push(null);            return;          }          self.push(new Buffer(result.value));          read();        })        .catch(function (err) {          global.clearTimeout(fetchTimer);          if (!self._destroyed) self.emit('error', err);        });    }    read();  } else {    self._xhr = xhr;    self._pos = 0;
    self.url = xhr.responseURL;    self.statusCode = xhr.status;    self.statusMessage = xhr.statusText;    var headers = xhr.getAllResponseHeaders().split(/\r?\n/);    headers.forEach(function (header) {      var matches = header.match(/^([^:]+):\s*(.*)/);      if (matches) {        var key = matches[1].toLowerCase();        if (key === 'set-cookie') {          if (self.headers[key] === undefined) {            self.headers[key] = [];          }          self.headers[key].push(matches[2]);        } else if (self.headers[key] !== undefined) {          self.headers[key] += ', ' + matches[2];        } else {          self.headers[key] = matches[2];        }        self.rawHeaders.push(matches[1], matches[2]);      }    });
    self._charset = 'x-user-defined';    if (!capability.overrideMimeType) {      var mimeType = self.rawHeaders['mime-type'];      if (mimeType) {        var charsetMatch = mimeType.match(/;\s*charset=([^;])(;|$)/);        if (charsetMatch) {          self._charset = charsetMatch[1].toLowerCase();        }      }      if (!self._charset) self._charset = 'utf-8'; // best guess
    }  }});
inherits(IncomingMessage, stream.Readable);
IncomingMessage.prototype._read = function () {  var self = this;
  var resolve = self._resumeFetch;  if (resolve) {    self._resumeFetch = null;    resolve();  }};
IncomingMessage.prototype._onXHRProgress = function () {  var self = this;
  var xhr = self._xhr;
  var response = null;  switch (self._mode) {    case 'text:vbarray': // For IE9
      if (xhr.readyState !== rStates.DONE) break;      try {        // This fails in IE8
        response = new global.VBArray(xhr.responseBody).toArray();      } catch (e) {}      if (response !== null) {        self.push(new Buffer(response));        break;      }    // Falls through in IE8
    case 'text':      try {        // This will fail when readyState = 3 in IE9. Switch mode and wait for readyState = 4
        response = xhr.responseText;      } catch (e) {        self._mode = 'text:vbarray';        break;      }      if (response.length > self._pos) {        var newData = response.substr(self._pos);        if (self._charset === 'x-user-defined') {          var buffer = new Buffer(newData.length);          for (var i = 0; i < newData.length; i++) buffer[i] = newData.charCodeAt(i) & 0xff;
          self.push(buffer);        } else {          self.push(newData, self._charset);        }        self._pos = response.length;      }      break;    case 'arraybuffer':      if (xhr.readyState !== rStates.DONE || !xhr.response) break;      response = xhr.response;      self.push(new Buffer(new Uint8Array(response)));      break;    case 'moz-chunked-arraybuffer': // take whole
      response = xhr.response;      if (xhr.readyState !== rStates.LOADING || !response) break;      self.push(new Buffer(new Uint8Array(response)));      break;    case 'ms-stream':      response = xhr.response;      if (xhr.readyState !== rStates.LOADING) break;      var reader = new global.MSStreamReader();      reader.onprogress = function () {        if (reader.result.byteLength > self._pos) {          self.push(new Buffer(new Uint8Array(reader.result.slice(self._pos))));          self._pos = reader.result.byteLength;        }      };      reader.onload = function () {        self.push(null);      };      // reader.onerror = ??? // TODO: this
      reader.readAsArrayBuffer(response);      break;  }
  // The ms-stream case handles end separately in reader.onload()
  if (self._xhr.readyState === rStates.DONE && self._mode !== 'ms-stream') {    self.push(null);  }};
 |