browser/modules/ContentLinkHandler.jsm

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     5 "use strict";
     7 let Cc = Components.classes;
     8 let Ci = Components.interfaces;
     9 let Cu = Components.utils;
    11 this.EXPORTED_SYMBOLS = [ "ContentLinkHandler" ];
    13 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    14 Cu.import("resource://gre/modules/Services.jsm");
    16 XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
    17   "resource:///modules/Feeds.jsm");
    18 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
    19   "resource://gre/modules/BrowserUtils.jsm");
    21 this.ContentLinkHandler = {
    22   init: function(chromeGlobal) {
    23     chromeGlobal.addEventListener("DOMLinkAdded", (event) => {
    24       this.onLinkAdded(event, chromeGlobal);
    25     }, false);
    26   },
    28   onLinkAdded: function(event, chromeGlobal) {
    29     var link = event.originalTarget;
    30     var rel = link.rel && link.rel.toLowerCase();
    31     if (!link || !link.ownerDocument || !rel || !link.href)
    32       return;
    34     // Ignore sub-frames (bugs 305472, 479408).
    35     let window = link.ownerDocument.defaultView;
    36     if (window != window.top)
    37       return;
    39     var feedAdded = false;
    40     var iconAdded = false;
    41     var searchAdded = false;
    42     var rels = {};
    43     for (let relString of rel.split(/\s+/))
    44       rels[relString] = true;
    46     for (let relVal in rels) {
    47       switch (relVal) {
    48         case "feed":
    49         case "alternate":
    50           if (!feedAdded) {
    51             if (!rels.feed && rels.alternate && rels.stylesheet)
    52               break;
    54             if (Feeds.isValidFeed(link, link.ownerDocument.nodePrincipal, "feed" in rels)) {
    55               chromeGlobal.sendAsyncMessage("Link:AddFeed",
    56                                             {type: link.type,
    57                                              href: link.href,
    58                                              title: link.title});
    59               feedAdded = true;
    60             }
    61           }
    62           break;
    63         case "icon":
    64           if (!iconAdded) {
    65             if (!Services.prefs.getBoolPref("browser.chrome.site_icons"))
    66               break;
    68             var uri = this.getLinkIconURI(link);
    69             if (!uri)
    70               break;
    72             [iconAdded] = chromeGlobal.sendSyncMessage("Link:AddIcon", {url: uri.spec});
    73           }
    74           break;
    75         case "search":
    76           if (!searchAdded) {
    77             var type = link.type && link.type.toLowerCase();
    78             type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
    80             let re = /^(?:https?|ftp):/i;
    81             if (type == "application/opensearchdescription+xml" && link.title &&
    82                 re.test(link.href))
    83             {
    84               let engine = { title: link.title, href: link.href };
    85               chromeGlobal.sendAsyncMessage("Link:AddSearch",
    86                                             {engine: engine,
    87                                              url: link.ownerDocument.documentURI});
    88               searchAdded = true;
    89             }
    90           }
    91           break;
    92       }
    93     }
    94   },
    96   getLinkIconURI: function(aLink) {
    97     let targetDoc = aLink.ownerDocument;
    98     var uri = BrowserUtils.makeURI(aLink.href, targetDoc.characterSet);
   100     // Verify that the load of this icon is legal.
   101     // Some error or special pages can load their favicon.
   102     // To be on the safe side, only allow chrome:// favicons.
   103     var isAllowedPage = [
   104       /^about:neterror\?/,
   105       /^about:blocked\?/,
   106       /^about:certerror\?/,
   107       /^about:home$/,
   108     ].some(function (re) re.test(targetDoc.documentURI));
   110     if (!isAllowedPage || !uri.schemeIs("chrome")) {
   111       var ssm = Services.scriptSecurityManager;
   112       try {
   113         ssm.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
   114                                       Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
   115       } catch(e) {
   116         return null;
   117       }
   118     }
   120     try {
   121       var contentPolicy = Cc["@mozilla.org/layout/content-policy;1"].
   122                           getService(Ci.nsIContentPolicy);
   123     } catch(e) {
   124       return null; // Refuse to load if we can't do a security check.
   125     }
   127     // Security says okay, now ask content policy
   128     if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
   129                                  uri, targetDoc.documentURIObject,
   130                                  aLink, aLink.type, null)
   131                                  != Ci.nsIContentPolicy.ACCEPT)
   132       return null;
   134     try {
   135       uri.userPass = "";
   136     } catch(e) {
   137       // some URIs are immutable
   138     }
   139     return uri;
   140   },
   141 };

mercurial