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)
							 | 
						|
									}
							 | 
						|
								}
							 |