); export let WebsiteFilter = { _observerAdded: false, init(blocklist, exceptionlist) { let blockArray = [], exceptionArray = []; for (let i = 0; i < blocklist.length && i < LIST_LENGTH_LIMIT; i++) { try { let pattern = new MatchPattern(blocklist[i].toLowerCase()); blockArray.push(pattern); lazy.log.debug( `Pattern added to WebsiteFilter. Block: ${blocklist[i]}` ); } catch (e) { lazy.log.error( `Invalid pattern on WebsiteFilter. Block: ${blocklist[i]}` ); } } this._blockPatterns = new MatchPatternSet(blockArray); for (let i = 0; i < exceptionlist.length && i < LIST_LENGTH_LIMIT; i++) { try { let pattern = new MatchPattern(exceptionlist[i].toLowerCase()); exceptionArray.push(pattern); lazy.log.debug( `Pattern added to WebsiteFilter. Exception: ${exceptionlist[i]}` ); } catch (e) { lazy.log.error( `Invalid pattern on WebsiteFilter. Exception: ${exceptionlist[i]}` ); } } if (exceptionArray.length) { this._exceptionsPatterns = new MatchPatternSet(exceptionArray); } let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); if (!registrar.isContractIDRegistered(this.contractID)) { registrar.registerFactory( this.classID, this.classDescription, this.contractID, this ); Services.catMan.addCategoryEntry( "content-policy", this.contractID, this.contractID, false, true ); } // We have to do this to catch 30X redirects. // See bug 456957. if (!this._observerAdded) { this._observerAdded = true; // We rely on weak references, so we never remove this observer. Services.obs.addObserver(this, "http-on-examine-response", true); } }, shouldLoad(contentLocation, loadInfo) { let contentType = loadInfo.externalContentPolicyType; let url = contentLocation.spec.toLowerCase(); if (contentLocation.scheme == "view-source") { url = contentLocation.pathQueryRef; } else if (url.startsWith("about:reader?url=")) { url = decodeURIComponent(url.substr(17)); } if ( contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT || contentType == Ci.nsIContentPolicy.TYPE_SUBDOCUMENT ) { if (!this.isAllowed(url)) { return Ci.nsIContentPolicy.REJECT_POLICY; } } return Ci.nsIContentPolicy.ACCEPT; }, shouldProcess() { return Ci.nsIContentPolicy.ACCEPT; }, observe(subject) { try { let channel = subject.QueryInterface(Ci.nsIHttpChannel); if ( !channel.isDocument || channel.responseStatus < 300 || channel.responseStatus >= 400 ) { return; } let location = channel.getResponseHeader("location"); // location might not be a fully qualified URL let url = URL.parse(location); if (!url) { url = URL.parse(location, channel.URI.spec); } if (url && !this.isAllowed(url.href)) { channel.cancel(Cr.NS_ERROR_BLOCKED_BY_POLICY); } } catch (e) {} }, classDescription: "Policy Engine File Content Policy", contractID: "@mozilla-org/policy-engine-file-content-policy-service;1", classID: Components.ID("{c0bbb557-813e-4e25-809d-b46a531a258f}"), QueryInterface: ChromeUtils.generateQI([ "nsIContentPolicy", "nsIObserver", "nsISupportsWeakReference", ]), createInstance(iid) { return this.QueryInterface(iid); }, isAllowed(url) { if (this._blockPatterns?.matches(url.toLowerCase())) { if ( !this._exceptionsPatterns || !this._exceptionsPatterns.matches(url.toLowerCase()) ) { return false; } } return true; }, }; PK