Skip to content
Snippets Groups Projects
request-analyzer.js 4.08 KiB
Newer Older
Thomas Rientjes's avatar
Thomas Rientjes committed
/**
 * Request Analyzer
 * Belongs to Decentraleyes.
 *
 * @author      Thomas Rientjes
 * @since       2014-05-30
 * @license     MPL 2.0
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 */

'use strict';

/**
 * Imports
 */

/**
 * Resource version mappings.
 * @var {object} mappings
 */
Thomas Rientjes's avatar
Thomas Rientjes committed
var mappings = require('./mappings');

Thomas Rientjes's avatar
Thomas Rientjes committed
/**
 * Gets and sets add-on specific preferences.
 * @var {object} simplePreferences
 */
var simplePreferences = require('sdk/simple-prefs');

/**
 * Constants
 */

const MAPPING_FILE_EXPRESSION = new RegExp('.map$', 'i');
const VERSION_EXPRESSION = /(?:\d{1,2}\.){1,3}\d{1,2}/;
const VERSION_PLACEHOLDER = '{version}';
const WEB_PREFIX_VALUE = 'www.';
const WEB_PREFIX_LENGTH = WEB_PREFIX_VALUE.length;
const VALUE_SEPARATOR = ';';

/**
 * Variables
 */

Thomas Rientjes's avatar
Thomas Rientjes committed
var preferences = simplePreferences.prefs;
var whitelistedDomains = {};

/**
 * Initializations
 */

Thomas Rientjes's avatar
Thomas Rientjes committed
_applyWhitelistPreference();

/**
 * Event Handlers
 */

Thomas Rientjes's avatar
Thomas Rientjes committed
simplePreferences.on('domainWhitelist', _applyWhitelistPreference);
Thomas Rientjes's avatar
Thomas Rientjes committed
/**
 * Public Methods
 */

Thomas Rientjes's avatar
Thomas Rientjes committed
exports.isValidCandidate = function (httpChannel) {
Thomas Rientjes's avatar
Thomas Rientjes committed
    // See if the request is targeted at a Content Delivery Network.
    if (mappings[httpChannel.URI.host] === undefined) {
        return false;
    }
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed
    // Attempt to determine the domain of the request initiator.
    var initiatorDomain =
        httpChannel.loadInfo && httpChannel.loadInfo.loadingDocument && httpChannel.loadInfo.loadingDocument.domain ||
        httpChannel.referrer && httpChannel.referrer.host;
Thomas Rientjes's avatar
Thomas Rientjes committed
    // If the request initiator could be determined and is whitelisted.
    if (initiatorDomain && whitelistedDomains[_normalizeDomain(initiatorDomain)]) {
Thomas Rientjes's avatar
Thomas Rientjes committed
        // Remove referer header from request.
        httpChannel.setRequestHeader('Referer', null, false);
        return false;
Thomas Rientjes's avatar
Thomas Rientjes committed
    // Only requests of type GET can be valid candidates.
    return httpChannel.requestMethod === 'GET';
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed
exports.getLocalTarget = function (channelHost, channelPath) {
Thomas Rientjes's avatar
Thomas Rientjes committed
    var hostMappings, basePath, resourceMappings;
Thomas Rientjes's avatar
Thomas Rientjes committed
    // Use the proper mappings for the targeted host.
    hostMappings = mappings[channelHost];

Thomas Rientjes's avatar
Thomas Rientjes committed
    // Resource mapping files are never locally available.
    if (MAPPING_FILE_EXPRESSION.test(channelPath)) {
        return false;
    }
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed
    basePath = _matchBasePath(hostMappings, channelPath);
    resourceMappings = hostMappings[basePath];
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed
    if (!resourceMappings) {
Thomas Rientjes's avatar
Thomas Rientjes committed
    // Return either the local target's path or false.
    return _findLocalTarget(resourceMappings, basePath, channelPath);
};
Thomas Rientjes's avatar
Thomas Rientjes committed

/**
 * Private Methods
 */

Thomas Rientjes's avatar
Thomas Rientjes committed
function _matchBasePath(hostMappings, channelPath) {
Thomas Rientjes's avatar
Thomas Rientjes committed
    for (let basePath of Object.keys(hostMappings)) {
Thomas Rientjes's avatar
Thomas Rientjes committed
        if (channelPath.startsWith(basePath)) {
            return basePath;
Thomas Rientjes's avatar
Thomas Rientjes committed

    return false;
Thomas Rientjes's avatar
Thomas Rientjes committed
function _findLocalTarget(resourceMappings, basePath, channelPath) {
Thomas Rientjes's avatar
Thomas Rientjes committed

    var resourcePath, versionNumber, resourcePattern;

    resourcePath = channelPath.replace(basePath, '');

Thomas Rientjes's avatar
Thomas Rientjes committed
    versionNumber = resourcePath.match(VERSION_EXPRESSION);
    resourcePattern = resourcePath.replace(versionNumber, VERSION_PLACEHOLDER);
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed
    for (let resourceMold of Object.keys(resourceMappings)) {
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed
        if (resourcePattern.startsWith(resourceMold)) {
Thomas Rientjes's avatar
Thomas Rientjes committed

Thomas Rientjes's avatar
Thomas Rientjes committed
            // Prepare and return a local target.
            return {
                path: resourceMappings[resourceMold].path.replace(VERSION_PLACEHOLDER, versionNumber),
                type: resourceMappings[resourceMold].type
            };
Thomas Rientjes's avatar
Thomas Rientjes committed

    return false;
Thomas Rientjes's avatar
Thomas Rientjes committed
}
Thomas Rientjes's avatar
Thomas Rientjes committed
function _normalizeDomain(domain) {

    domain = domain.toLowerCase().trim();

Thomas Rientjes's avatar
Thomas Rientjes committed
    if (domain.startsWith(WEB_PREFIX_VALUE)) {
        domain = domain.slice(WEB_PREFIX_LENGTH);
Thomas Rientjes's avatar
Thomas Rientjes committed
function _applyWhitelistPreference() {
Thomas Rientjes's avatar
Thomas Rientjes committed
    whitelistedDomains = {};

    //noinspection JSUnresolvedVariable
Thomas Rientjes's avatar
Thomas Rientjes committed
    preferences.domainWhitelist.split(VALUE_SEPARATOR).forEach(function (domain) {
        whitelistedDomains[_normalizeDomain(domain)] = true;