1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/http/UserAgentOverrides.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,182 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +this.EXPORTED_SYMBOLS = [ "UserAgentOverrides" ]; 1.11 + 1.12 +const Ci = Components.interfaces; 1.13 +const Cc = Components.classes; 1.14 + 1.15 +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); 1.16 +Components.utils.import("resource://gre/modules/Services.jsm"); 1.17 +Components.utils.import("resource://gre/modules/UserAgentUpdates.jsm"); 1.18 + 1.19 +const OVERRIDE_MESSAGE = "Useragent:GetOverride"; 1.20 +const PREF_OVERRIDES_ENABLED = "general.useragent.site_specific_overrides"; 1.21 +const DEFAULT_UA = Cc["@mozilla.org/network/protocol;1?name=http"] 1.22 + .getService(Ci.nsIHttpProtocolHandler) 1.23 + .userAgent; 1.24 +const MAX_OVERRIDE_FOR_HOST_CACHE_SIZE = 250; 1.25 + 1.26 +XPCOMUtils.defineLazyServiceGetter(this, "ppmm", 1.27 + "@mozilla.org/parentprocessmessagemanager;1", 1.28 + "nsIMessageListenerManager"); // Might have to make this broadcast? 1.29 + 1.30 +var gPrefBranch; 1.31 +var gOverrides = new Map; 1.32 +var gUpdatedOverrides; 1.33 +var gOverrideForHostCache = new Map; 1.34 +var gInitialized = false; 1.35 +var gOverrideFunctions = [ 1.36 + function (aHttpChannel) UserAgentOverrides.getOverrideForURI(aHttpChannel.URI) 1.37 +]; 1.38 +var gBuiltUAs = new Map; 1.39 + 1.40 +this.UserAgentOverrides = { 1.41 + init: function uao_init() { 1.42 + if (gInitialized) 1.43 + return; 1.44 + 1.45 + gPrefBranch = Services.prefs.getBranch("general.useragent.override."); 1.46 + gPrefBranch.addObserver("", buildOverrides, false); 1.47 + 1.48 + ppmm.addMessageListener(OVERRIDE_MESSAGE, this); 1.49 + Services.prefs.addObserver(PREF_OVERRIDES_ENABLED, buildOverrides, false); 1.50 + 1.51 + try { 1.52 + Services.obs.addObserver(HTTP_on_modify_request, "http-on-modify-request", false); 1.53 + } catch (x) { 1.54 + // The http-on-modify-request notification is disallowed in content processes. 1.55 + } 1.56 + 1.57 + UserAgentUpdates.init(function(overrides) { 1.58 + gOverrideForHostCache.clear(); 1.59 + if (overrides) { 1.60 + for (let domain in overrides) { 1.61 + overrides[domain] = getUserAgentFromOverride(overrides[domain]); 1.62 + } 1.63 + overrides.get = function(key) this[key]; 1.64 + } 1.65 + gUpdatedOverrides = overrides; 1.66 + }); 1.67 + 1.68 + buildOverrides(); 1.69 + gInitialized = true; 1.70 + }, 1.71 + 1.72 + addComplexOverride: function uao_addComplexOverride(callback) { 1.73 + // Add to front of array so complex overrides have precedence 1.74 + gOverrideFunctions.unshift(callback); 1.75 + }, 1.76 + 1.77 + getOverrideForURI: function uao_getOverrideForURI(aURI) { 1.78 + let host = aURI.asciiHost; 1.79 + if (!gInitialized || 1.80 + (!gOverrides.size && !gUpdatedOverrides) || 1.81 + !(host)) { 1.82 + return null; 1.83 + } 1.84 + 1.85 + let override = gOverrideForHostCache.get(host); 1.86 + if (override !== undefined) 1.87 + return override; 1.88 + 1.89 + function findOverride(overrides) { 1.90 + let searchHost = host; 1.91 + let userAgent = overrides.get(searchHost); 1.92 + 1.93 + while (!userAgent) { 1.94 + let dot = searchHost.indexOf('.'); 1.95 + if (dot === -1) { 1.96 + return null; 1.97 + } 1.98 + searchHost = searchHost.slice(dot + 1); 1.99 + userAgent = overrides.get(searchHost); 1.100 + } 1.101 + return userAgent; 1.102 + } 1.103 + 1.104 + override = (gOverrides.size && findOverride(gOverrides)) 1.105 + || (gUpdatedOverrides && findOverride(gUpdatedOverrides)); 1.106 + 1.107 + if (gOverrideForHostCache.size >= MAX_OVERRIDE_FOR_HOST_CACHE_SIZE) { 1.108 + gOverrideForHostCache.clear(); 1.109 + } 1.110 + gOverrideForHostCache.set(host, override); 1.111 + 1.112 + return override; 1.113 + }, 1.114 + 1.115 + uninit: function uao_uninit() { 1.116 + if (!gInitialized) 1.117 + return; 1.118 + gInitialized = false; 1.119 + 1.120 + gPrefBranch.removeObserver("", buildOverrides); 1.121 + 1.122 + Services.prefs.removeObserver(PREF_OVERRIDES_ENABLED, buildOverrides); 1.123 + 1.124 + Services.obs.removeObserver(HTTP_on_modify_request, "http-on-modify-request"); 1.125 + }, 1.126 + 1.127 + receiveMessage: function(aMessage) { 1.128 + let name = aMessage.name; 1.129 + switch (name) { 1.130 + case OVERRIDE_MESSAGE: 1.131 + let uri = aMessage.data.uri; 1.132 + return this.getOverrideForURI(uri); 1.133 + default: 1.134 + throw("Wrong Message in UserAgentOverride: " + name); 1.135 + } 1.136 + } 1.137 +}; 1.138 + 1.139 +function getUserAgentFromOverride(override) 1.140 +{ 1.141 + let userAgent = gBuiltUAs.get(override); 1.142 + if (userAgent !== undefined) { 1.143 + return userAgent; 1.144 + } 1.145 + let [search, replace] = override.split("#", 2); 1.146 + if (search && replace) { 1.147 + userAgent = DEFAULT_UA.replace(new RegExp(search, "g"), replace); 1.148 + } else { 1.149 + userAgent = override; 1.150 + } 1.151 + gBuiltUAs.set(override, userAgent); 1.152 + return userAgent; 1.153 +} 1.154 + 1.155 +function buildOverrides() { 1.156 + gOverrides.clear(); 1.157 + gOverrideForHostCache.clear(); 1.158 + 1.159 + if (!Services.prefs.getBoolPref(PREF_OVERRIDES_ENABLED)) 1.160 + return; 1.161 + 1.162 + let builtUAs = new Map; 1.163 + let domains = gPrefBranch.getChildList(""); 1.164 + 1.165 + for (let domain of domains) { 1.166 + let override = gPrefBranch.getCharPref(domain); 1.167 + let userAgent = getUserAgentFromOverride(override); 1.168 + 1.169 + if (userAgent != DEFAULT_UA) { 1.170 + gOverrides.set(domain, userAgent); 1.171 + } 1.172 + } 1.173 +} 1.174 + 1.175 +function HTTP_on_modify_request(aSubject, aTopic, aData) { 1.176 + let channel = aSubject.QueryInterface(Ci.nsIHttpChannel); 1.177 + 1.178 + for (let callback of gOverrideFunctions) { 1.179 + let modifiedUA = callback(channel, DEFAULT_UA); 1.180 + if (modifiedUA) { 1.181 + channel.setRequestHeader("User-Agent", modifiedUA, false); 1.182 + return; 1.183 + } 1.184 + } 1.185 +}