diff --git a/lib/helpers.js b/lib/helpers.js index 2cd01791..5729282c 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -7,7 +7,9 @@ var path = require('path'); var url = require('url'); var sriToolbox = require('sri-toolbox'); -var XMLHttpRequest = XMLHttpRequest || require('xhr2'); +var http = require('http'); +var https = require('https'); +var zlib = require('zlib'); var resourceTypes = require('./resourceTypes.json'); var secureHosts = require('./secureHosts.json'); @@ -47,6 +49,25 @@ var upgradeToHttps = function (urlString) { return url.format(urlObject); }; +/** + * Choose corresponding module (http or https) for downloading a resource. + * + * @param {string} urlString + * @return {Object} http or https module + */ +var moduleForProtocol = function (urlString) { + var urlObject = url.parse(urlString); + + if (urlObject.protocol === 'https:') { + return https; + } + + if (urlObject.protocol === 'http:') { + return http; + } + + return false; +}; /** * Check XHR response headers for issues that could affect SRI eligibility @@ -54,10 +75,10 @@ var upgradeToHttps = function (urlString) { * @param {Object.XMLHttpRequest} fetchResource request * @return {Array} list of potential issues */ -var eligibility = function (request) { +var eligibility = function (response) { var issues = []; - var acao = request.getResponseHeader('access-control-allow-origin'); + var acao = response.headers['access-control-allow-origin']; if (!acao) { issues.push('non-cors'); } @@ -69,31 +90,27 @@ var eligibility = function (request) { /** * Handle server response. * + * @param {string} data + * @param {Object} response * @param {string} resourceUrl * @param {Function} cb - callback * @return {Function.cb} */ -var processResource = function (resourceUrl, cb) { - var request = this; - - if (request.readyState !== 4) { - return false; - } - - if (request.status !== 200) { +var processResource = function (data, response, resourceUrl, cb) { + if (response.statusCode !== 200) { return cb({ 'success': false, - 'status': request.status + 'status': response.statusCode }); } return cb({ 'success': true, - 'status': request.status, + 'status': response.statusCode, 'url': resourceUrl, - 'eligibility': eligibility(request), - 'data': request.responseText, - 'ct': request.getResponseHeader('content-type') + 'eligibility': eligibility(response), + 'data': data, + 'ct': response.headers['content-type'] }); }; @@ -111,11 +128,25 @@ var fetchResource = function (resourceUrl, cb) { return cb(false); } - var request = new XMLHttpRequest(); - request.onreadystatechange = processResource.bind(request, resourceUrl, cb); + moduleForProtocol(resourceUrl).get(resourceUrl, function (response) { + var output; + if (response.headers['content-encoding'] === 'gzip') { + var gzip = zlib.createGunzip(); + response.pipe(gzip); + output = gzip; + } else { + output = response; + } - request.open('GET', resourceUrl); - request.send(); + var data = []; + output.on('data', function (chunk) { + data.push(chunk); + }); + output.on('end', function () { + data = Buffer.concat(data); + processResource(data, response, resourceUrl, cb); + }); + }); }; diff --git a/test/helpers.js b/test/helpers.js index 49db9661..6bd60de5 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -8,23 +8,6 @@ var assert = require('assert'); var helpers = require('../lib/helpers.js'); -/** - * Simulate a XMLHttpRequest object - */ -var FauxXHR = function (attributes) { - var that = this, - headers = {}; - - // Store header keys as lowercase - Object.keys(attributes.headers).map(function (header) { - headers[header.toLowerCase()] = attributes.headers[header]; - }); - - that.getResponseHeader = function (header) { - return headers[header.toLowerCase()]; - }; -}; - describe('upgradeToHttps()', function () { describe('CDNs', function () { it('Known', function () { @@ -74,7 +57,7 @@ describe('upgradeToHttps()', function () { describe('eligibility()', function () { describe('Eligible', function () { it('CORS', function () { - var allGood = new FauxXHR({ headers: { 'access-control-allow-origin': '*' } }); + var allGood = { headers: { 'access-control-allow-origin': '*' } }; var result = helpers.eligibility(allGood); assert.deepEqual(result, []); }); @@ -82,7 +65,7 @@ describe('eligibility()', function () { describe('Non-eligible', function () { it('non-CORS', function () { - var nonCORS = new FauxXHR({ headers: { 'dnt': '1' } }); + var nonCORS = { headers: { 'dnt': '1' } }; var result = helpers.eligibility(nonCORS); assert.deepEqual(result, ['non-cors']); });