1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); 6 7ChromeUtils.defineModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); 8ChromeUtils.defineModuleGetter(this, "UserAgentOverrides", "resource://gre/modules/UserAgentOverrides.jsm"); 9XPCOMUtils.defineLazyServiceGetter(this, "eTLDService", "@mozilla.org/network/effective-tld-service;1", "nsIEffectiveTLDService"); 10 11class UAOverrider { 12 constructor(overrides) { 13 this._overrides = {}; 14 15 this.initOverrides(overrides); 16 } 17 18 initOverrides(overrides) { 19 for (let override of overrides) { 20 if (!this._overrides[override.baseDomain]) { 21 this._overrides[override.baseDomain] = []; 22 } 23 24 if (!override.uriMatcher) { 25 override.uriMatcher = () => true; 26 } 27 28 this._overrides[override.baseDomain].push(override); 29 } 30 } 31 32 init() { 33 UserAgentOverrides.addComplexOverride(this.overrideCallback.bind(this)); 34 } 35 36 overrideCallback(channel, defaultUA) { 37 let uaOverride = this.lookupUAOverride(channel.URI, defaultUA); 38 if (uaOverride) { 39 console.log("The user agent has been overridden for compatibility reasons."); 40 return uaOverride; 41 } 42 43 return false; 44 } 45 46 /** 47 * Try to use the eTLDService to get the base domain (will return example.com 48 * for http://foo.bar.example.com/foo/bar). 49 * 50 * However, the eTLDService is a bit picky and throws whenever we pass a 51 * blank host name or an IP into it, see bug 1337785. Since we do not plan on 52 * override UAs for such cases, we simply catch everything and return false. 53 */ 54 getBaseDomainFromURI(uri) { 55 try { 56 return eTLDService.getBaseDomain(uri); 57 } catch (_) { 58 return false; 59 } 60 } 61 62 /** 63 * This function returns a User Agent based on the URI passed into. All 64 * override rules are defined in data/ua_overrides.jsm and the required format 65 * is explained there. 66 * 67 * Since it is expected and designed to have more than one override per base 68 * domain, we have to loop over this._overrides[baseDomain], which contains 69 * all available overrides. 70 * 71 * If the uriMatcher function returns true, the uaTransformer function gets 72 * called and its result will be used as the Use Agent for the current 73 * request. 74 * 75 * If there are more than one possible overrides, that is if two or more 76 * uriMatchers would return true, the first one gets applied. 77 */ 78 lookupUAOverride(uri, defaultUA) { 79 let baseDomain = this.getBaseDomainFromURI(uri); 80 if (baseDomain && this._overrides[baseDomain]) { 81 for (let uaOverride of this._overrides[baseDomain]) { 82 if (uaOverride.uriMatcher(uri.specIgnoringRef)) { 83 return uaOverride.uaTransformer(defaultUA); 84 } 85 } 86 } 87 88 return false; 89 } 90} 91 92var EXPORTED_SYMBOLS = ["UAOverrider"]; /* exported UAOverrider */ 93