stream-http-2.7.2/000077500000000000000000000000001311757373400140055ustar00rootroot00000000000000stream-http-2.7.2/.gitignore000066400000000000000000000000671311757373400160000ustar00rootroot00000000000000.DS_Store bundle.js node_modules npm-debug.log .zuulrc stream-http-2.7.2/.travis.yml000066400000000000000000000000441311757373400161140ustar00rootroot00000000000000language: node_js node_js: - "6.4"stream-http-2.7.2/.zuul.yml000066400000000000000000000006721311757373400156120ustar00rootroot00000000000000ui: tape browsers: - name: chrome version: 39..latest - name: firefox version: 34..latest - name: safari version: 5..latest - name: microsoftedge version: 13..latest - name: ie version: 9..latest - name: opera version: 11..latest - name: iphone version: '8.1..latest' - name: android version: '4.4..latest' server: ./test/server/index.js scripts: - "/ie8-polyfill.js" - "/test-polyfill.js" stream-http-2.7.2/LICENSE000066400000000000000000000020761311757373400150170ustar00rootroot00000000000000The MIT License Copyright (c) 2015 John Hiesey Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.stream-http-2.7.2/README.md000066400000000000000000000145551311757373400152760ustar00rootroot00000000000000# stream-http [![Build Status](https://travis-ci.org/jhiesey/stream-http.svg?branch=master)](https://travis-ci.org/jhiesey/stream-http) [![Sauce Test Status](https://saucelabs.com/browser-matrix/stream-http.svg)](https://saucelabs.com/u/stream-http) This module is an implementation of Node's native `http` module for the browser. It tries to match Node's API and behavior as closely as possible, but some features aren't available, since browsers don't give nearly as much control over requests. This is heavily inspired by, and intended to replace, [http-browserify](https://github.com/substack/http-browserify). ## What does it do? In accordance with its name, `stream-http` tries to provide data to its caller before the request has completed whenever possible. The following browsers support true streaming, where only a small amount of the request has to be held in memory at once: * Chrome >= 43 (using the `fetch` API) * Firefox >= 9 (using `moz-chunked-arraybuffer` responseType with xhr) The following browsers support pseudo-streaming, where the data is available before the request finishes, but the entire response must be held in memory: * Chrome * Safari >= 5, and maybe older * IE >= 10 * Most other Webkit-based browsers, including the default Android browser All browsers newer than IE8 support binary responses. All of the above browsers that support true streaming or pseudo-streaming support that for binary data as well except for IE10. Old (presto-based) Opera also does not support binary streaming either. ### IE8 note: As of version 2.0.0, IE8 support requires the user to supply polyfills for `Object.keys`, `Array.prototype.forEach`, and `Array.prototype.indexOf`. Example implementations are provided in [ie8-polyfill.js](ie8-polyfill.js); alternately, you may want to consider using [es5-shim](https://github.com/es-shims/es5-shim). All browsers with full ES5 support shouldn't require any polyfills. ## How do you use it? The intent is to have the same API as the client part of the [Node HTTP module](https://nodejs.org/api/http.html). The interfaces are the same wherever practical, although limitations in browsers make an exact clone of the Node API impossible. This module implements `http.request`, `http.get`, and most of `http.ClientRequest` and `http.IncomingMessage` in addition to `http.METHODS` and `http.STATUS_CODES`. See the Node docs for how these work. ### Extra features compared to Node * The `message.url` property provides access to the final URL after all redirects. This is useful since the browser follows all redirects silently, unlike Node. It is available in Chrome 37 and newer, Firefox 32 and newer, and Safari 9 and newer. * The `options.withCredentials` boolean flag, used to indicate if the browser should send cookies or authentication information with a CORS request. Default false. This module has to make some tradeoffs to support binary data and/or streaming. Generally, the module can make a fairly good decision about which underlying browser features to use, but sometimes it helps to get a little input from the developer. * The `options.mode` field passed into `http.request` or `http.get` can take on one of the following values: * 'default' (or any falsy value, including `undefined`): Try to provide partial data before the request completes, but not at the cost of correctness for binary data or correctness of the 'content-type' response header. This mode will also avoid slower code paths whenever possible, which is particularly useful when making large requests in a browser like Safari that has a weaker JavaScript engine. * 'allow-wrong-content-type': Provides partial data in more cases than 'default', but at the expense of causing the 'content-type' response header to be incorrectly reported (as 'text/plain; charset=x-user-defined') in some browsers, notably Safari and Chrome 42 and older. Preserves binary data whenever possible. In some cases the implementation may also be a bit slow. This was the default in versions of this module before 1.5. * 'prefer-stream': Provide data before the request completes even if binary data (anything that isn't a single-byte ASCII or UTF8 character) will be corrupted. Of course, this option is only safe for text data. May also cause the 'content-type' response header to be incorrectly reported (as 'text/plain; charset=x-user-defined'). * 'disable-fetch': Force the use of plain XHR regardless of the browser declaring a fetch capability. Preserves the correctness of binary data and the 'content-type' response header. * 'prefer-fast': Deprecated; now a synonym for 'default', which has the same performance characteristics as this mode did in versions before 1.5. ### Features missing compared to Node * `http.Agent` is only a stub * The 'socket', 'connect', 'upgrade', and 'continue' events on `http.ClientRequest`. * Any operations, including `request.setTimeout`, that operate directly on the underlying socket. * Any options that are disallowed for security reasons. This includes setting or getting certain headers. * `message.httpVersion` * `message.rawHeaders` is modified by the browser, and may not quite match what is sent by the server. * `message.trailers` and `message.rawTrailers` will remain empty. * Redirects are followed silently by the browser, so it isn't possible to access the 301/302 redirect pages. * The `timeout` options in the `request` method is non-operational in Safari <= 5 and Opera <= 12. ## Example ``` js http.get('/bundle.js', function (res) { var div = document.getElementById('result'); div.innerHTML += 'GET /beep
'; res.on('data', function (buf) { div.innerHTML += buf; }); res.on('end', function () { div.innerHTML += '
__END__'; }); }) ``` ## Running tests There are two sets of tests: the tests that run in Node (found in `test/node`) and the tests that run in the browser (found in `test/browser`). Normally the browser tests run on [Sauce Labs](http://saucelabs.com/). Running `npm test` will run both sets of tests, but in order for the Sauce Labs tests to run you will need to sign up for an account (free for open source projects) and put the credentials in a [`.zuulrc` file](https://github.com/defunctzombie/zuul/wiki/zuulrc). To run just the Node tests, run `npm run test-node`. To run the browser tests locally, run `npm run test-browser-local` and point your browser to `http://localhost:8080/__zuul` ## License MIT. Copyright (C) John Hiesey and other contributors. stream-http-2.7.2/ie8-polyfill.js000066400000000000000000000114421311757373400166620ustar00rootroot00000000000000// These polyfills taken from MDN (developer.mozilla.org) // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys if (!Object.keys) { Object.keys = (function() { 'use strict'; var hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'), dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ], dontEnumsLength = dontEnums.length; return function(obj) { if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { throw new TypeError('Object.keys called on non-object'); } var result = [], prop, i; for (prop in obj) { if (hasOwnProperty.call(obj, prop)) { result.push(prop); } } if (hasDontEnumBug) { for (i = 0; i < dontEnumsLength; i++) { if (hasOwnProperty.call(obj, dontEnums[i])) { result.push(dontEnums[i]); } } } return result; }; }()); } // Production steps of ECMA-262, Edition 5, 15.4.4.18 // Reference: http://es5.github.io/#x15.4.4.18 if (!Array.prototype.forEach) { Array.prototype.forEach = function(callback, thisArg) { var T, k; if (this == null) { throw new TypeError(' this is null or not defined'); } // 1. Let O be the result of calling ToObject passing the |this| value as the argument. var O = Object(this); // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". // 3. Let len be ToUint32(lenValue). var len = O.length >>> 0; // 4. If IsCallable(callback) is false, throw a TypeError exception. // See: http://es5.github.com/#x9.11 if (typeof callback !== "function") { throw new TypeError(callback + ' is not a function'); } // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 1) { T = thisArg; } // 6. Let k be 0 k = 0; // 7. Repeat, while k < len while (k < len) { var kValue; // a. Let Pk be ToString(k). // This is implicit for LHS operands of the in operator // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. // This step can be combined with c // c. If kPresent is true, then if (k in O) { // i. Let kValue be the result of calling the Get internal method of O with argument Pk. kValue = O[k]; // ii. Call the Call internal method of callback with T as the this value and // argument list containing kValue, k, and O. callback.call(T, kValue, k, O); } // d. Increase k by 1. k++; } // 8. return undefined }; } // Production steps of ECMA-262, Edition 5, 15.4.4.14 // Reference: http://es5.github.io/#x15.4.4.14 if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(searchElement, fromIndex) { var k; // 1. Let O be the result of calling ToObject passing // the this value as the argument. if (this == null) { throw new TypeError('"this" is null or not defined'); } var O = Object(this); // 2. Let lenValue be the result of calling the Get // internal method of O with the argument "length". // 3. Let len be ToUint32(lenValue). var len = O.length >>> 0; // 4. If len is 0, return -1. if (len === 0) { return -1; } // 5. If argument fromIndex was passed let n be // ToInteger(fromIndex); else let n be 0. var n = +fromIndex || 0; if (Math.abs(n) === Infinity) { n = 0; } // 6. If n >= len, return -1. if (n >= len) { return -1; } // 7. If n >= 0, then Let k be n. // 8. Else, n<0, Let k be len - abs(n). // If k is less than 0, then let k be 0. k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); // 9. Repeat, while k < len while (k < len) { // a. Let Pk be ToString(k). // This is implicit for LHS operands of the in operator // b. Let kPresent be the result of calling the // HasProperty internal method of O with argument Pk. // This step can be combined with c // c. If kPresent is true, then // i. Let elementK be the result of calling the Get // internal method of O with the argument ToString(k). // ii. Let same be the result of applying the // Strict Equality Comparison Algorithm to // searchElement and elementK. // iii. If same is true, return k. if (k in O && O[k] === searchElement) { return k; } k++; } return -1; }; }stream-http-2.7.2/index.js000066400000000000000000000032661311757373400154610ustar00rootroot00000000000000var ClientRequest = require('./lib/request') var extend = require('xtend') var statusCodes = require('builtin-status-codes') var url = require('url') var http = exports http.request = function (opts, cb) { if (typeof opts === 'string') opts = url.parse(opts) else opts = extend(opts) // Normally, the page is loaded from http or https, so not specifying a protocol // will result in a (valid) protocol-relative url. However, this won't work if // the protocol is something else, like 'file:' var defaultProtocol = global.location.protocol.search(/^https?:$/) === -1 ? 'http:' : '' var protocol = opts.protocol || defaultProtocol var host = opts.hostname || opts.host var port = opts.port var path = opts.path || '/' // Necessary for IPv6 addresses if (host && host.indexOf(':') !== -1) host = '[' + host + ']' // This may be a relative url. The browser should always be able to interpret it correctly. opts.url = (host ? (protocol + '//' + host) : '') + (port ? ':' + port : '') + path opts.method = (opts.method || 'GET').toUpperCase() opts.headers = opts.headers || {} // Also valid opts.auth, opts.mode var req = new ClientRequest(opts) if (cb) req.on('response', cb) return req } http.get = function get (opts, cb) { var req = http.request(opts, cb) req.end() return req } http.Agent = function () {} http.Agent.defaultMaxSockets = 4 http.STATUS_CODES = statusCodes http.METHODS = [ 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'MKCOL', 'MOVE', 'NOTIFY', 'OPTIONS', 'PATCH', 'POST', 'PROPFIND', 'PROPPATCH', 'PURGE', 'PUT', 'REPORT', 'SEARCH', 'SUBSCRIBE', 'TRACE', 'UNLOCK', 'UNSUBSCRIBE' ]stream-http-2.7.2/lib/000077500000000000000000000000001311757373400145535ustar00rootroot00000000000000stream-http-2.7.2/lib/capability.js000066400000000000000000000044351311757373400172400ustar00rootroot00000000000000exports.fetch = isFunction(global.fetch) && isFunction(global.ReadableStream) exports.blobConstructor = false try { new Blob([new ArrayBuffer(1)]) exports.blobConstructor = true } catch (e) {} // The xhr request to example.com may violate some restrictive CSP configurations, // so if we're running in a browser that supports `fetch`, avoid calling getXHR() // and assume support for certain features below. var xhr function getXHR () { // Cache the xhr value if (xhr !== undefined) return xhr if (global.XMLHttpRequest) { xhr = new global.XMLHttpRequest() // If XDomainRequest is available (ie only, where xhr might not work // cross domain), use the page location. Otherwise use example.com // Note: this doesn't actually make an http request. try { xhr.open('GET', global.XDomainRequest ? '/' : 'https://example.com') } catch(e) { xhr = null } } else { // Service workers don't have XHR xhr = null } return xhr } function checkTypeSupport (type) { var xhr = getXHR() if (!xhr) return false try { xhr.responseType = type return xhr.responseType === type } catch (e) {} return false } // For some strange reason, Safari 7.0 reports typeof global.ArrayBuffer === 'object'. // Safari 7.1 appears to have fixed this bug. var haveArrayBuffer = typeof global.ArrayBuffer !== 'undefined' var haveSlice = haveArrayBuffer && isFunction(global.ArrayBuffer.prototype.slice) // If fetch is supported, then arraybuffer will be supported too. Skip calling // checkTypeSupport(), since that calls getXHR(). exports.arraybuffer = exports.fetch || (haveArrayBuffer && checkTypeSupport('arraybuffer')) // These next two tests unavoidably show warnings in Chrome. Since fetch will always // be used if it's available, just return false for these to avoid the warnings. exports.msstream = !exports.fetch && haveSlice && checkTypeSupport('ms-stream') exports.mozchunkedarraybuffer = !exports.fetch && haveArrayBuffer && checkTypeSupport('moz-chunked-arraybuffer') // If fetch is supported, then overrideMimeType will be supported too. Skip calling // getXHR(). exports.overrideMimeType = exports.fetch || (getXHR() ? isFunction(getXHR().overrideMimeType) : false) exports.vbArray = isFunction(global.VBArray) function isFunction (value) { return typeof value === 'function' } xhr = null // Help gc stream-http-2.7.2/lib/request.js000066400000000000000000000171321311757373400166050ustar00rootroot00000000000000var capability = require('./capability') var inherits = require('inherits') var response = require('./response') var stream = require('readable-stream') var toArrayBuffer = require('to-arraybuffer') var IncomingMessage = response.IncomingMessage var rStates = response.readyStates function decideMode (preferBinary, useFetch) { if (capability.fetch && useFetch) { return 'fetch' } else if (capability.mozchunkedarraybuffer) { return 'moz-chunked-arraybuffer' } else if (capability.msstream) { return 'ms-stream' } else if (capability.arraybuffer && preferBinary) { return 'arraybuffer' } else if (capability.vbArray && preferBinary) { return 'text:vbarray' } else { return 'text' } } var ClientRequest = module.exports = function (opts) { var self = this stream.Writable.call(self) self._opts = opts self._body = [] self._headers = {} if (opts.auth) self.setHeader('Authorization', 'Basic ' + new Buffer(opts.auth).toString('base64')) Object.keys(opts.headers).forEach(function (name) { self.setHeader(name, opts.headers[name]) }) var preferBinary var useFetch = true if (opts.mode === 'disable-fetch' || 'timeout' in opts) { // If the use of XHR should be preferred and includes preserving the 'content-type' header. // Force XHR to be used since the Fetch API does not yet support timeouts. useFetch = false preferBinary = true } else if (opts.mode === 'prefer-streaming') { // If streaming is a high priority but binary compatibility and // the accuracy of the 'content-type' header aren't preferBinary = false } else if (opts.mode === 'allow-wrong-content-type') { // If streaming is more important than preserving the 'content-type' header preferBinary = !capability.overrideMimeType } else if (!opts.mode || opts.mode === 'default' || opts.mode === 'prefer-fast') { // Use binary if text streaming may corrupt data or the content-type header, or for speed preferBinary = true } else { throw new Error('Invalid value for opts.mode') } self._mode = decideMode(preferBinary, useFetch) self.on('finish', function () { self._onFinish() }) } inherits(ClientRequest, stream.Writable) ClientRequest.prototype.setHeader = function (name, value) { var self = this var lowerName = name.toLowerCase() // This check is not necessary, but it prevents warnings from browsers about setting unsafe // headers. To be honest I'm not entirely sure hiding these warnings is a good thing, but // http-browserify did it, so I will too. if (unsafeHeaders.indexOf(lowerName) !== -1) return self._headers[lowerName] = { name: name, value: value } } ClientRequest.prototype.getHeader = function (name) { var header = this._headers[name.toLowerCase()] if (header) return header.value return null } ClientRequest.prototype.removeHeader = function (name) { var self = this delete self._headers[name.toLowerCase()] } ClientRequest.prototype._onFinish = function () { var self = this if (self._destroyed) return var opts = self._opts var headersObj = self._headers var body = null if (opts.method !== 'GET' && opts.method !== 'HEAD') { if (capability.blobConstructor) { body = new global.Blob(self._body.map(function (buffer) { return toArrayBuffer(buffer) }), { type: (headersObj['content-type'] || {}).value || '' }) } else { // get utf8 string body = Buffer.concat(self._body).toString() } } // create flattened list of headers var headersList = [] Object.keys(headersObj).forEach(function (keyName) { var name = headersObj[keyName].name var value = headersObj[keyName].value if (Array.isArray(value)) { value.forEach(function (v) { headersList.push([name, v]) }) } else { headersList.push([name, value]) } }) if (self._mode === 'fetch') { global.fetch(self._opts.url, { method: self._opts.method, headers: headersList, body: body || undefined, mode: 'cors', credentials: opts.withCredentials ? 'include' : 'same-origin' }).then(function (response) { self._fetchResponse = response self._connect() }, function (reason) { self.emit('error', reason) }) } else { var xhr = self._xhr = new global.XMLHttpRequest() try { xhr.open(self._opts.method, self._opts.url, true) } catch (err) { process.nextTick(function () { self.emit('error', err) }) return } // Can't set responseType on really old browsers if ('responseType' in xhr) xhr.responseType = self._mode.split(':')[0] if ('withCredentials' in xhr) xhr.withCredentials = !!opts.withCredentials if (self._mode === 'text' && 'overrideMimeType' in xhr) xhr.overrideMimeType('text/plain; charset=x-user-defined') if ('timeout' in opts) { xhr.timeout = opts.timeout xhr.ontimeout = function () { self.emit('timeout') } } headersList.forEach(function (header) { xhr.setRequestHeader(header[0], header[1]) }) self._response = null xhr.onreadystatechange = function () { switch (xhr.readyState) { case rStates.LOADING: case rStates.DONE: self._onXHRProgress() break } } // Necessary for streaming in Firefox, since xhr.response is ONLY defined // in onprogress, not in onreadystatechange with xhr.readyState = 3 if (self._mode === 'moz-chunked-arraybuffer') { xhr.onprogress = function () { self._onXHRProgress() } } xhr.onerror = function () { if (self._destroyed) return self.emit('error', new Error('XHR error')) } try { xhr.send(body) } catch (err) { process.nextTick(function () { self.emit('error', err) }) return } } } /** * Checks if xhr.status is readable and non-zero, indicating no error. * Even though the spec says it should be available in readyState 3, * accessing it throws an exception in IE8 */ function statusValid (xhr) { try { var status = xhr.status return (status !== null && status !== 0) } catch (e) { return false } } ClientRequest.prototype._onXHRProgress = function () { var self = this if (!statusValid(self._xhr) || self._destroyed) return if (!self._response) self._connect() self._response._onXHRProgress() } ClientRequest.prototype._connect = function () { var self = this if (self._destroyed) return self._response = new IncomingMessage(self._xhr, self._fetchResponse, self._mode) self._response.on('error', function(err) { self.emit('error', err) }) self.emit('response', self._response) } ClientRequest.prototype._write = function (chunk, encoding, cb) { var self = this self._body.push(chunk) cb() } ClientRequest.prototype.abort = ClientRequest.prototype.destroy = function () { var self = this self._destroyed = true if (self._response) self._response._destroyed = true if (self._xhr) self._xhr.abort() // Currently, there isn't a way to truly abort a fetch. // If you like bikeshedding, see https://github.com/whatwg/fetch/issues/27 } ClientRequest.prototype.end = function (data, encoding, cb) { var self = this if (typeof data === 'function') { cb = data data = undefined } stream.Writable.prototype.end.call(self, data, encoding, cb) } ClientRequest.prototype.flushHeaders = function () {} ClientRequest.prototype.setTimeout = function () {} ClientRequest.prototype.setNoDelay = function () {} ClientRequest.prototype.setSocketKeepAlive = function () {} // Taken from http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method var unsafeHeaders = [ 'accept-charset', 'accept-encoding', 'access-control-request-headers', 'access-control-request-method', 'connection', 'content-length', 'cookie', 'cookie2', 'date', 'dnt', 'expect', 'host', 'keep-alive', 'origin', 'referer', 'te', 'trailer', 'transfer-encoding', 'upgrade', 'user-agent', 'via' ] stream-http-2.7.2/lib/response.js000066400000000000000000000111261311757373400167500ustar00rootroot00000000000000var 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) { 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) }) // TODO: this doesn't respect backpressure. Once WritableStream is available, this can be fixed var reader = response.body.getReader() function read () { reader.read().then(function (result) { if (self._destroyed) return if (result.done) { self.push(null) return } self.push(new Buffer(result.value)) read() }).catch(function(err) { 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 () {} 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) } } stream-http-2.7.2/package.json000066400000000000000000000023471311757373400163010ustar00rootroot00000000000000{ "name": "stream-http", "version": "2.7.2", "description": "Streaming http in the browser", "main": "index.js", "repository": { "type": "git", "url": "git://github.com/jhiesey/stream-http.git" }, "scripts": { "test": "npm run test-node && ([ -n \"${TRAVIS_PULL_REQUEST}\" -a \"${TRAVIS_PULL_REQUEST}\" != 'false' ] || npm run test-browser)", "test-node": "tape test/node/*.js", "test-browser": "zuul --no-coverage -- test/browser/*.js", "test-browser-local": "zuul --local 8080 --no-coverage -- test/browser/*.js" }, "author": "John Hiesey", "license": "MIT", "bugs": { "url": "https://github.com/jhiesey/stream-http/issues" }, "homepage": "https://github.com/jhiesey/stream-http#readme", "keywords": [ "http", "stream", "streaming", "xhr", "http-browserify" ], "dependencies": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", "readable-stream": "^2.2.6", "to-arraybuffer": "^1.0.0", "xtend": "^4.0.0" }, "devDependencies": { "basic-auth": "^1.0.3", "brfs": "^1.4.0", "cookie-parser": "^1.4.3", "express": "^4.15.2", "tape": "^4.0.0", "ua-parser-js": "^0.7.7", "webworkify": "^1.0.2", "zuul": "^3.10.3" } } stream-http-2.7.2/test/000077500000000000000000000000001311757373400147645ustar00rootroot00000000000000stream-http-2.7.2/test/browser/000077500000000000000000000000001311757373400164475ustar00rootroot00000000000000stream-http-2.7.2/test/browser/abort.js000066400000000000000000000021301311757373400201100ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var http = require('../..') test('abort before response', function (t) { var req = http.get('/basic.txt', function (res) { t.fail('unexpected response') }) req.abort() t.end() }) test('abort on response', function (t) { var req = http.get('/basic.txt', function (res) { req.abort() t.end() res.on('end', function () { t.fail('unexpected end') }) res.on('data', function (data) { t.fail('unexpected data') }) }) }) test('abort on data', function (t) { var req = http.get('/browserify.png?copies=5', function (res) { var firstData = true var failOnData = false res.on('end', function () { t.fail('unexpected end') }) res.on('data', function (data) { if (failOnData) t.fail('unexpected data') else if (firstData) { firstData = false req.abort() t.end() process.nextTick(function () { // Wait for any data that may have been queued // in the stream before considering data events // as errors failOnData = true }) } }) }) })stream-http-2.7.2/test/browser/auth.js000066400000000000000000000006701311757373400177510ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var test = require('tape') var http = require('../..') test('authentication', function (t) { http.get({ path: '/auth', auth: 'TestUser:trustno1' }, function (res) { var buffers = [] res.on('end', function () { t.ok(new Buffer('You\'re in!').equals(Buffer.concat(buffers)), 'authentication succeeded') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) })stream-http-2.7.2/test/browser/binary-streaming.js000066400000000000000000000040201311757373400222540ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var UAParser = require('ua-parser-js') var http = require('../..') var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser() var browserName = browser.name var browserVersion = browser.major // Binary streaming doesn't work in IE10 or below or in Opera var skipStreamingCheck = (browserName === 'Opera' || (browserName === 'IE' && browserVersion <= 10)) // Binary data gets corrupted in IE8 or below var skipVerification = (browserName === 'IE' && browserVersion <= 8) // IE8 tends to throw up modal dialogs complaining about scripts running too long // Since streaming doesn't actually work there anyway, just use one copy var COPIES = skipVerification ? 1 : 20 var MIN_PIECES = 2 var referenceOnce = fs.readFileSync(__dirname + '/../server/static/browserify.png') var reference = new Buffer(referenceOnce.length * COPIES) for(var i = 0; i < COPIES; i++) { referenceOnce.copy(reference, referenceOnce.length * i) } test('binary streaming', function (t) { http.get({ path: '/browserify.png?copies=' + COPIES, mode: 'allow-wrong-content-type' }, function (res) { var buffers = [] res.on('end', function () { if (skipVerification) t.skip('binary data not preserved on IE <= 8') else t.ok(reference.equals(Buffer.concat(buffers)), 'contents match') if (skipStreamingCheck) t.skip('streaming not available on IE <= 8') else t.ok(buffers.length >= MIN_PIECES, 'received in multiple parts') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) }) test('large binary request without streaming', function (t) { http.get({ path: '/browserify.png?copies=' + COPIES, mode: 'default', }, function (res) { var buffers = [] res.on('end', function () { if (skipVerification) t.skip('binary data not preserved on IE <= 8') else t.ok(reference.equals(Buffer.concat(buffers)), 'contents match') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) })stream-http-2.7.2/test/browser/binary.js000066400000000000000000000015401311757373400202710ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var UAParser = require('ua-parser-js') var http = require('../..') var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser() var browserName = browser.name var browserVersion = browser.major // Binary data gets corrupted in IE8 or below var skipVerification = (browserName === 'IE' && browserVersion <= 8) var reference = fs.readFileSync(__dirname + '/../server/static/browserify.png') test('binary download', function (t) { http.get('/browserify.png', function (res) { var buffers = [] res.on('end', function () { if (skipVerification) t.skip('binary data not preserved on IE <= 8') else t.ok(reference.equals(Buffer.concat(buffers)), 'contents match') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) })stream-http-2.7.2/test/browser/body-empty.js000066400000000000000000000012201311757373400210710ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var http = require('../..') var reference = fs.readFileSync(__dirname + '/../server/static/basic.txt') test('get body empty', function (t) { var req = http.request({ path: '/verifyEmpty', method: 'GET' }, function (res) { var buffers = [] res.on('end', function () { console.log(Buffer.concat(buffers).toString('utf8')) t.ok(Buffer.from('empty').equals(Buffer.concat(buffers)), 'response body indicates request body was empty') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) req.write(reference) req.end() }) stream-http-2.7.2/test/browser/cookie.js000066400000000000000000000007761311757373400202700ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var test = require('tape') var http = require('../..') test('cookie', function (t) { var cookie = 'hello=world' window.document.cookie = cookie http.get({ path: '/cookie', withCredentials: false }, function (res) { var buffers = [] res.on('end', function () { t.ok(new Buffer(cookie).equals(Buffer.concat(buffers)), 'hello cookie echoed') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) }) stream-http-2.7.2/test/browser/disable-fetch.js000066400000000000000000000013261311757373400215010ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var test = require('tape') var http = require('../..') test('disable fetch', function (t) { var originalFetch if (typeof fetch === 'function') { originalFetch = fetch } var fetchCalled = false fetch = function (input, options) { fetchCalled = true if (originalFetch) { return originalFetch(input, options) } } http.get({ path: '/browserify.png', mode: 'disable-fetch' }, function (res) { t.ok(!fetchCalled, 'fetch was not called') if (originalFetch) { fetch = originalFetch } res.on('end', function () { t.ok(res.headers['content-type'] === 'image/png', 'content-type was set correctly') t.end() }) res.on('data', function () {}) }) }) stream-http-2.7.2/test/browser/error.js.disabled000066400000000000000000000004301311757373400217010ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var test = require('tape') var http = require('../..') test('error handling', function (t) { var req = http.get('https://0.0.0.0:0/fail.txt') req.on('error', function (err) { t.ok(err && ('message' in err), 'got error') t.end() }) })stream-http-2.7.2/test/browser/headers.js000066400000000000000000000104341311757373400204220ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var UAParser = require('ua-parser-js') var http = require('../..') test('headers', function (t) { http.get({ path: '/testHeaders?Response-Header=bar&Response-Header-2=BAR2', headers: { 'Test-Request-Header': 'foo', 'Test-Request-Header-2': 'FOO2' } }, function (res) { var rawHeaders = [] for (var i = 0; i < res.rawHeaders.length; i += 2) { var lowerKey = res.rawHeaders[i].toLowerCase() if (lowerKey.indexOf('test-') === 0) rawHeaders.push(lowerKey, res.rawHeaders[i + 1]) } var header1Pos = rawHeaders.indexOf('test-response-header') t.ok(header1Pos >= 0, 'raw response header 1 present') t.equal(rawHeaders[header1Pos + 1], 'bar', 'raw response header value 1') var header2Pos = rawHeaders.indexOf('test-response-header-2') t.ok(header2Pos >= 0, 'raw response header 2 present') t.equal(rawHeaders[header2Pos + 1], 'BAR2', 'raw response header value 2') t.equal(rawHeaders.length, 4, 'correct number of raw headers') t.equal(res.headers['test-response-header'], 'bar', 'response header 1') t.equal(res.headers['test-response-header-2'], 'BAR2', 'response header 2') var buffers = [] res.on('end', function () { var body = JSON.parse(Buffer.concat(buffers).toString()) t.equal(body['test-request-header'], 'foo', 'request header 1') t.equal(body['test-request-header-2'], 'FOO2', 'request header 2') t.equal(Object.keys(body).length, 2, 'correct number of request headers') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) }) test('arrays of headers', function (t) { http.get({ path: '/testHeaders?Response-Header=bar&Response-Header=BAR2', headers: { 'Test-Request-Header': ['foo', 'FOO2'] } }, function (res) { var rawHeaders = [] for (var i = 0; i < res.rawHeaders.length; i += 2) { var lowerKey = res.rawHeaders[i].toLowerCase() if (lowerKey.indexOf('test-') === 0) rawHeaders.push(lowerKey, res.rawHeaders[i + 1]) } t.equal(rawHeaders[0], 'test-response-header', 'raw response header present') t.equal(rawHeaders[1], 'bar, BAR2', 'raw response header value') t.equal(rawHeaders.length, 2, 'correct number of raw headers') t.equal(res.headers['test-response-header'], 'bar, BAR2', 'response header') var buffers = [] res.on('end', function () { var body = JSON.parse(Buffer.concat(buffers).toString()) t.equal(body['test-request-header'], 'foo,FOO2', 'request headers') t.equal(Object.keys(body).length, 1, 'correct number of request headers') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) }) test('content-type response header', function (t) { http.get('/testHeaders', function (res) { t.equal(res.headers['content-type'], 'application/json', 'content-type preserved') t.end() }) }) var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser() var browserName = browser.name var browserVersion = browser.major var browserMinorVersion = browser.minor || 0 // The content-type header is broken when 'prefer-streaming' or 'allow-wrong-content-type' // is passed in browsers that rely on xhr.overrideMimeType(), namely older chrome, safari 6-10.0, and the stock Android browser // Note that Safari 10.0 on iOS 10.3 doesn't need to override the mime type, so the content-type is preserved. var wrongMimeType = ((browserName === 'Chrome' && browserVersion <= 42) || ((browserName === 'Safari' || browserName === 'Mobile Safari') && browserVersion >= 6 && (browserVersion < 10 || (browserVersion == 10 && browserMinorVersion == 0))) || (browserName === 'Android Browser')) test('content-type response header with forced streaming', function (t) { http.get({ path: '/testHeaders', mode: 'prefer-streaming' }, function (res) { if (wrongMimeType) { // allow both the 'wrong' and correct mime type, since sometimes it's impossible to tell which to expect // from the browser version alone (e.g. Safari 10.0 on iOS 10.2 vs iOS 10.3) var contentType = res.headers['content-type'] var correct = (contentType === 'text/plain; charset=x-user-defined') || (contentType === 'application/json') t.ok(correct, 'content-type either preserved or overridden') } else t.equal(res.headers['content-type'], 'application/json', 'content-type preserved') t.end() }) })stream-http-2.7.2/test/browser/lib/000077500000000000000000000000001311757373400172155ustar00rootroot00000000000000stream-http-2.7.2/test/browser/lib/webworker-worker.js000066400000000000000000000006131311757373400230710ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var http = require('../../..') module.exports = function (self) { self.addEventListener('message', function (ev) { var url = ev.data http.get(url, function (res) { var buffers = [] res.on('end', function () { self.postMessage(Buffer.concat(buffers).buffer) }) res.on('data', function (data) { buffers.push(data) }) }) }) }stream-http-2.7.2/test/browser/package.json000066400000000000000000000000621311757373400207330ustar00rootroot00000000000000{ "browserify": { "transform": [ "brfs" ] } } stream-http-2.7.2/test/browser/post-binary.js000066400000000000000000000022651311757373400212610ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var UAParser = require('ua-parser-js') var http = require('../..') var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser() var browserName = browser.name var browserVersion = browser.major // Binary request bodies don't work in a bunch of browsers var skipVerification = ((browserName === 'Opera' && browserVersion <= 11) || (browserName === 'IE' && browserVersion <= 10) || (browserName === 'Safari' && browserVersion <= 5) || (browserName === 'WebKit' && browserVersion <= 534) || // Old mobile safari (browserName === 'Android Browser' && browserVersion <= 4)) var reference = fs.readFileSync(__dirname + '/../server/static/browserify.png') test('post binary', function (t) { var req = http.request({ path: '/echo', method: 'POST' }, function (res) { var buffers = [] res.on('end', function () { if (skipVerification) t.skip('binary data not preserved on this browser') else t.ok(reference.equals(Buffer.concat(buffers)), 'echoed contents match') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) req.write(reference) req.end() })stream-http-2.7.2/test/browser/post-text.js000066400000000000000000000016261311757373400207610ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var http = require('../..') var reference = fs.readFileSync(__dirname + '/../server/static/basic.txt') test('post text', function (t) { var req = http.request({ path: '/echo', method: 'POST' }, function (res) { var buffers = [] res.on('end', function () { t.ok(reference.equals(Buffer.concat(buffers)), 'echoed contents match') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) req.write(reference) req.end() }) test('post text with data in end()', function (t) { var req = http.request({ path: '/echo', method: 'POST' }, function (res) { var buffers = [] res.on('end', function () { t.ok(reference.equals(Buffer.concat(buffers)), 'echoed contents match') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) req.end(reference) })stream-http-2.7.2/test/browser/text-streaming.js000066400000000000000000000022731311757373400217640ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var UAParser = require('ua-parser-js') var http = require('../..') var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser() var browserName = browser.name var browserVersion = browser.major // Streaming doesn't work in IE9 or below or in Opera var skipStreamingCheck = (browserName === 'Opera' || (browserName === 'IE' && browserVersion <= 9)) var COPIES = 1000 var MIN_PIECES = 5 var referenceOnce = fs.readFileSync(__dirname + '/../server/static/basic.txt') var reference = new Buffer(referenceOnce.length * COPIES) for(var i = 0; i < COPIES; i++) { referenceOnce.copy(reference, referenceOnce.length * i) } test('text streaming', function (t) { http.get({ path: '/basic.txt?copies=' + COPIES, mode: 'prefer-streaming' }, function (res) { var buffers = [] res.on('end', function () { if (skipStreamingCheck) t.skip('streaming not available on IE <= 8') else t.ok(buffers.length >= MIN_PIECES, 'received in multiple parts') t.ok(reference.equals(Buffer.concat(buffers)), 'contents match') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) })stream-http-2.7.2/test/browser/text.js000066400000000000000000000026121311757373400177720ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var UAParser = require('ua-parser-js') var url = require('url') var http = require('../..') var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser() var browserName = browser.name var browserVersion = browser.major // Response urls don't work on many browsers var skipResponseUrl = ((browserName === 'Opera') || (browserName === 'IE') || (browserName === 'Edge') || (browserName === 'Chrome' && browserVersion <= 36) || (browserName === 'Firefox' && browserVersion <= 31) || ((browserName === 'Safari' || browserName === 'Mobile Safari') && browserVersion <= 8) || (browserName === 'WebKit') || // Old mobile safari (browserName === 'Android Browser' && browserVersion <= 4)) var reference = fs.readFileSync(__dirname + '/../server/static/basic.txt') test('basic functionality', function (t) { http.get('/basic.txt', function (res) { if (!skipResponseUrl) { var testUrl = url.resolve(global.location.href, '/basic.txt') // Redirects aren't tested, but presumably only browser bugs // would cause this to fail only after redirects. t.equals(res.url, testUrl, 'response url correct') } var buffers = [] res.on('end', function () { t.ok(reference.equals(Buffer.concat(buffers)), 'contents match') t.end() }) res.on('data', function (data) { buffers.push(data) }) }) })stream-http-2.7.2/test/browser/timeout.js.disabled000066400000000000000000000014131311757373400222400ustar00rootroot00000000000000var Buffer = require('buffer').Buffer var fs = require('fs') var test = require('tape') var UAParser = require('ua-parser-js') var url = require('url') var http = require('../..') var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser() var browserName = browser.name var browserVersion = browser.major var skipTimeout = ((browserName === 'Opera' && browserVersion <= 12) || (browserName === 'Safari' && browserVersion <= 5)) test('emits timeout events', function (t) { if (skipTimeout) { return t.skip('Browser does not support setting timeouts') } var req = http.request({ path: '/basic.txt', timeout: 1 }) req.on('timeout', function () { t.pass('timeout caught') t.end() // the test will timeout if this does not happen }) req.end() }) stream-http-2.7.2/test/browser/webworker.js000066400000000000000000000023321311757373400210140ustar00rootroot00000000000000var fs = require('fs') var test = require('tape') var UAParser = require('ua-parser-js') var url = require('url') var work = require('webworkify') var browser = (new UAParser()).setUA(navigator.userAgent).getBrowser() var browserName = browser.name var browserVersion = browser.major // Skip browsers with poor or nonexistant WebWorker support var skip = ((browserName === 'Opera' && browserVersion <= 12) || (browserName === 'IE' && browserVersion <= 10) || (browserName === 'Safari' && browserVersion <= 5) || (browserName === 'WebKit' && browserVersion <= 534) || // Old mobile safari (browserName === 'Android Browser' && browserVersion <= 4)) var reference = fs.readFileSync(__dirname + '/../server/static/browserify.png') test('binary download in WebWorker', { skip: skip }, function (t) { // We have to use a global url, since webworkify puts the worker in a Blob, // which doesn't have a proper location var testUrl = url.resolve(global.location.href, '/browserify.png') var worker = work(require('./lib/webworker-worker.js')) worker.addEventListener('message', function (ev) { var data = new Buffer(new Uint8Array(ev.data)) t.ok(reference.equals(data), 'contents match') t.end() }) worker.postMessage(testUrl) })stream-http-2.7.2/test/node/000077500000000000000000000000001311757373400157115ustar00rootroot00000000000000stream-http-2.7.2/test/node/http-browserify.js000066400000000000000000000067401311757373400214260ustar00rootroot00000000000000// These tests are teken from http-browserify to ensure compatibility with // that module var test = require('tape') var url = require('url') var location = 'http://localhost:8081/foo/123' var noop = function() {} global.location = url.parse(location) global.XMLHttpRequest = function() { this.open = noop this.send = noop this.withCredentials = false } var moduleName = require.resolve('../../') delete require.cache[moduleName] var http = require('../../') test('Test simple url string', function(t) { var testUrl = { path: '/api/foo' } var request = http.get(testUrl, noop) var resolved = url.resolve(location, request._opts.url) t.equal(resolved, 'http://localhost:8081/api/foo', 'Url should be correct') t.end() }) test('Test full url object', function(t) { var testUrl = { host: "localhost:8081", hostname: "localhost", href: "http://localhost:8081/api/foo?bar=baz", method: "GET", path: "/api/foo?bar=baz", pathname: "/api/foo", port: "8081", protocol: "http:", query: "bar=baz", search: "?bar=baz", slashes: true } var request = http.get(testUrl, noop) var resolved = url.resolve(location, request._opts.url) t.equal(resolved, 'http://localhost:8081/api/foo?bar=baz', 'Url should be correct') t.end() }) test('Test alt protocol', function(t) { var params = { protocol: "foo:", hostname: "localhost", port: "3000", path: "/bar" } var request = http.get(params, noop) var resolved = url.resolve(location, request._opts.url) t.equal(resolved, 'foo://localhost:3000/bar', 'Url should be correct') t.end() }) test('Test page with \'file:\' protocol', function (t) { var params = { hostname: 'localhost', port: 3000, path: '/bar' } var fileLocation = 'file:///home/me/stuff/index.html' var normalLocation = global.location global.location = url.parse(fileLocation) // Temporarily change the location var request = http.get(params, noop) global.location = normalLocation // Reset the location var resolved = url.resolve(fileLocation, request._opts.url) t.equal(resolved, 'http://localhost:3000/bar', 'Url should be correct') t.end() }) test('Test string as parameters', function(t) { var testUrl = '/api/foo' var request = http.get(testUrl, noop) var resolved = url.resolve(location, request._opts.url) t.equal(resolved, 'http://localhost:8081/api/foo', 'Url should be correct') t.end() }) test('Test withCredentials param', function(t) { var url = '/api/foo' var request = http.get({ url: url, withCredentials: false }, noop) t.equal(request._xhr.withCredentials, false, 'xhr.withCredentials should be false') var request = http.get({ url: url, withCredentials: true }, noop) t.equal(request._xhr.withCredentials, true, 'xhr.withCredentials should be true') var request = http.get({ url: url }, noop) t.equal(request._xhr.withCredentials, false, 'xhr.withCredentials should be false') t.end() }) test('Test ipv6 address', function(t) { var testUrl = 'http://[::1]:80/foo' var request = http.get(testUrl, noop) var resolved = url.resolve(location, request._opts.url) t.equal(resolved, 'http://[::1]:80/foo', 'Url should be correct') t.end() }) test('Test relative path in url', function(t) { var params = { path: './bar' } var request = http.get(params, noop) var resolved = url.resolve(location, request._opts.url) t.equal(resolved, 'http://localhost:8081/foo/bar', 'Url should be correct') t.end() }) test('Cleanup', function (t) { delete global.location delete global.XMLHttpRequest delete require.cache[moduleName] t.end() }) stream-http-2.7.2/test/server/000077500000000000000000000000001311757373400162725ustar00rootroot00000000000000stream-http-2.7.2/test/server/index.js000066400000000000000000000064561311757373400177520ustar00rootroot00000000000000var cookieParser = require('cookie-parser') var basicAuth = require('basic-auth') var express = require('express') var fs = require('fs') var http = require('http') var path = require('path') var url = require('url') var app = express() var server = http.createServer(app) // Otherwise, use 'application/octet-stream' var copiesMimeTypes = { '/basic.txt': 'text/plain' } var maxDelay = 5000 // ms // This should make sure bodies aren't cached // so the streaming tests always pass app.use(function (req, res, next) { res.setHeader('Cache-Control', 'no-store') next() }) app.get('/testHeaders', function (req, res) { var parsed = url.parse(req.url, true) // Values in query parameters are sent as response headers Object.keys(parsed.query).forEach(function (key) { res.setHeader('Test-' + key, parsed.query[key]) }) res.setHeader('Content-Type', 'application/json') res.setHeader('Cache-Control', 'no-cache') // Request headers are sent in the body as json var reqHeaders = {} Object.keys(req.headers).forEach(function (key) { key = key.toLowerCase() if (key.indexOf('test-') === 0) { // different browsers format request headers with multiple values // slightly differently, so normalize reqHeaders[key] = req.headers[key].replace(', ', ',') } }) var body = JSON.stringify(reqHeaders) res.setHeader('Content-Length', body.length) res.write(body) res.end() }) app.get('/cookie', cookieParser(), function (req, res) { res.setHeader('Content-Type', 'text/plain') res.write('hello=' + req.cookies.hello) res.end() }) app.get('/auth', function (req, res) { var user = basicAuth(req) if (!user || user.name !== 'TestUser' || user.pass !== 'trustno1') { res.setHeader('WWW-Authenticate', 'Basic realm="example"') res.end('Access denied') } else { res.setHeader('Content-Type', 'text/plain') res.write('You\'re in!') res.end() } }) app.post('/echo', function (req, res) { res.setHeader('Content-Type', 'application/octet-stream') req.pipe(res) }) app.use('/verifyEmpty', function (req, res) { var empty = true req.on('data', function (buf) { if (buf.length > 0) { empty = false } }) req.on('end', function () { res.setHeader('Content-Type', 'text/plain') if (empty) { res.end('empty') } else { res.end('not empty') } }) }) app.use(function (req, res, next) { var parsed = url.parse(req.url, true) if ('copies' in parsed.query) { var totalCopies = parseInt(parsed.query.copies, 10) function fail () { res.statusCode = 500 res.end() } fs.readFile(path.join(__dirname, 'static', parsed.pathname), function (err, data) { if (err) return fail() var mimeType = copiesMimeTypes[parsed.pathname] || 'application/octet-stream' res.setHeader('Content-Type', mimeType) res.setHeader('Content-Length', data.length * totalCopies) var pieceDelay = maxDelay / totalCopies if (pieceDelay > 100) pieceDelay = 100 function write (copies) { if (copies === 0) return res.end() res.write(data, function (err) { if (err) return fail() setTimeout(write.bind(null, copies - 1), pieceDelay) }) } write(totalCopies) }) return } next() }) app.use(express.static(path.join(__dirname, 'static'))) var port = parseInt(process.env.ZUUL_PORT) || 8199 console.log('Test server listening on port', port) server.listen(port) stream-http-2.7.2/test/server/static/000077500000000000000000000000001311757373400175615ustar00rootroot00000000000000stream-http-2.7.2/test/server/static/basic.txt000066400000000000000000000007241311757373400214060ustar00rootroot00000000000000Mary had a little lamb, His fleece was white as snow, And everywhere that Mary went, The lamb was sure to go. He followed her to school one day, Which was against the rule, It made the children laugh and play To see a lamb at school. And so the teacher turned it out, But still it lingered near, And waited patiently about, Till Mary did appear. "Why does the lamb love Mary so?" The eager children cry. "Why, Mary loves the lamb, you know." The teacher did reply. stream-http-2.7.2/test/server/static/ie8-polyfill.js000077700000000000000000000000001311757373400261432../../../ie8-polyfill.jsustar00rootroot00000000000000stream-http-2.7.2/test/server/static/test-polyfill.js000066400000000000000000000003521311757373400227260ustar00rootroot00000000000000if (!String.prototype.trim) { (function() { // Make sure we trim BOM and NBSP var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; String.prototype.trim = function() { return this.replace(rtrim, ''); }; })(); }