michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: const Cu = Components.utils; michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: michael@0: const MAX_CACHE_SIZE = 250; michael@0: const PREF_UPDATE = "general.useragent.updates."; michael@0: const PREF_OVERRIDE = "general.useragent.override."; michael@0: const XPCOM_SHUTDOWN = "xpcom-shutdown"; michael@0: const HTTP_PROTO_HANDLER = Cc["@mozilla.org/network/protocol;1?name=http"] michael@0: .getService(Ci.nsIHttpProtocolHandler); michael@0: michael@0: XPCOMUtils.defineLazyServiceGetter(this, "cpmm", michael@0: "@mozilla.org/childprocessmessagemanager;1", michael@0: "nsISyncMessageSender"); michael@0: michael@0: function SiteSpecificUserAgent() { michael@0: this.inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime) michael@0: .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; michael@0: michael@0: if (this.inParent) { michael@0: Cu.import("resource://gre/modules/UserAgentOverrides.jsm"); michael@0: } else { michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Services.prefs.addObserver(PREF_OVERRIDE, this, false); michael@0: Services.prefs.addObserver(PREF_UPDATE, this, false); michael@0: Services.obs.addObserver(this, XPCOM_SHUTDOWN, false); michael@0: this.userAgentCache = new Map; michael@0: } michael@0: } michael@0: michael@0: SiteSpecificUserAgent.prototype = { michael@0: getUserAgentForURIAndWindow: function ssua_getUserAgentForURIAndWindow(aURI, aWindow) { michael@0: if (this.inParent) { michael@0: return UserAgentOverrides.getOverrideForURI(aURI) || HTTP_PROTO_HANDLER.userAgent; michael@0: } michael@0: michael@0: let host = aURI.asciiHost; michael@0: let cachedResult = this.userAgentCache.get(host); michael@0: if (cachedResult) { michael@0: return cachedResult; michael@0: } michael@0: michael@0: let data = { uri: aURI }; michael@0: let result = cpmm.sendSyncMessage("Useragent:GetOverride", data)[0] || HTTP_PROTO_HANDLER.userAgent; michael@0: michael@0: if (this.userAgentCache.size >= MAX_CACHE_SIZE) { michael@0: this.userAgentCache.clear(); michael@0: } michael@0: michael@0: this.userAgentCache.set(host, result); michael@0: return result; michael@0: }, michael@0: michael@0: invalidateCache: function() { michael@0: this.userAgentCache.clear(); michael@0: }, michael@0: michael@0: clean: function() { michael@0: this.userAgentCache.clear(); michael@0: if (!this.inParent) { michael@0: Services.obs.removeObserver(this, XPCOM_SHUTDOWN); michael@0: Services.prefs.removeObserver(PREF_OVERRIDE, this); michael@0: Services.prefs.removeObserver(PREF_UPDATE, this); michael@0: } michael@0: }, michael@0: michael@0: observe: function(subject, topic, data) { michael@0: switch (topic) { michael@0: case "nsPref:changed": michael@0: this.invalidateCache(); michael@0: break; michael@0: case XPCOM_SHUTDOWN: michael@0: this.clean(); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: classID: Components.ID("{506c680f-3d1c-4954-b351-2c80afbc37d3}"), michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsISiteSpecificUserAgent]) michael@0: }; michael@0: michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SiteSpecificUserAgent]);