browser/modules/ContentLinkHandler.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/modules/ContentLinkHandler.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,141 @@
     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 +let Cc = Components.classes;
    1.11 +let Ci = Components.interfaces;
    1.12 +let Cu = Components.utils;
    1.13 +
    1.14 +this.EXPORTED_SYMBOLS = [ "ContentLinkHandler" ];
    1.15 +
    1.16 +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    1.17 +Cu.import("resource://gre/modules/Services.jsm");
    1.18 +
    1.19 +XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
    1.20 +  "resource:///modules/Feeds.jsm");
    1.21 +XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
    1.22 +  "resource://gre/modules/BrowserUtils.jsm");
    1.23 +
    1.24 +this.ContentLinkHandler = {
    1.25 +  init: function(chromeGlobal) {
    1.26 +    chromeGlobal.addEventListener("DOMLinkAdded", (event) => {
    1.27 +      this.onLinkAdded(event, chromeGlobal);
    1.28 +    }, false);
    1.29 +  },
    1.30 +
    1.31 +  onLinkAdded: function(event, chromeGlobal) {
    1.32 +    var link = event.originalTarget;
    1.33 +    var rel = link.rel && link.rel.toLowerCase();
    1.34 +    if (!link || !link.ownerDocument || !rel || !link.href)
    1.35 +      return;
    1.36 +
    1.37 +    // Ignore sub-frames (bugs 305472, 479408).
    1.38 +    let window = link.ownerDocument.defaultView;
    1.39 +    if (window != window.top)
    1.40 +      return;
    1.41 +
    1.42 +    var feedAdded = false;
    1.43 +    var iconAdded = false;
    1.44 +    var searchAdded = false;
    1.45 +    var rels = {};
    1.46 +    for (let relString of rel.split(/\s+/))
    1.47 +      rels[relString] = true;
    1.48 +
    1.49 +    for (let relVal in rels) {
    1.50 +      switch (relVal) {
    1.51 +        case "feed":
    1.52 +        case "alternate":
    1.53 +          if (!feedAdded) {
    1.54 +            if (!rels.feed && rels.alternate && rels.stylesheet)
    1.55 +              break;
    1.56 +
    1.57 +            if (Feeds.isValidFeed(link, link.ownerDocument.nodePrincipal, "feed" in rels)) {
    1.58 +              chromeGlobal.sendAsyncMessage("Link:AddFeed",
    1.59 +                                            {type: link.type,
    1.60 +                                             href: link.href,
    1.61 +                                             title: link.title});
    1.62 +              feedAdded = true;
    1.63 +            }
    1.64 +          }
    1.65 +          break;
    1.66 +        case "icon":
    1.67 +          if (!iconAdded) {
    1.68 +            if (!Services.prefs.getBoolPref("browser.chrome.site_icons"))
    1.69 +              break;
    1.70 +
    1.71 +            var uri = this.getLinkIconURI(link);
    1.72 +            if (!uri)
    1.73 +              break;
    1.74 +
    1.75 +            [iconAdded] = chromeGlobal.sendSyncMessage("Link:AddIcon", {url: uri.spec});
    1.76 +          }
    1.77 +          break;
    1.78 +        case "search":
    1.79 +          if (!searchAdded) {
    1.80 +            var type = link.type && link.type.toLowerCase();
    1.81 +            type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
    1.82 +
    1.83 +            let re = /^(?:https?|ftp):/i;
    1.84 +            if (type == "application/opensearchdescription+xml" && link.title &&
    1.85 +                re.test(link.href))
    1.86 +            {
    1.87 +              let engine = { title: link.title, href: link.href };
    1.88 +              chromeGlobal.sendAsyncMessage("Link:AddSearch",
    1.89 +                                            {engine: engine,
    1.90 +                                             url: link.ownerDocument.documentURI});
    1.91 +              searchAdded = true;
    1.92 +            }
    1.93 +          }
    1.94 +          break;
    1.95 +      }
    1.96 +    }
    1.97 +  },
    1.98 +
    1.99 +  getLinkIconURI: function(aLink) {
   1.100 +    let targetDoc = aLink.ownerDocument;
   1.101 +    var uri = BrowserUtils.makeURI(aLink.href, targetDoc.characterSet);
   1.102 +
   1.103 +    // Verify that the load of this icon is legal.
   1.104 +    // Some error or special pages can load their favicon.
   1.105 +    // To be on the safe side, only allow chrome:// favicons.
   1.106 +    var isAllowedPage = [
   1.107 +      /^about:neterror\?/,
   1.108 +      /^about:blocked\?/,
   1.109 +      /^about:certerror\?/,
   1.110 +      /^about:home$/,
   1.111 +    ].some(function (re) re.test(targetDoc.documentURI));
   1.112 +
   1.113 +    if (!isAllowedPage || !uri.schemeIs("chrome")) {
   1.114 +      var ssm = Services.scriptSecurityManager;
   1.115 +      try {
   1.116 +        ssm.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
   1.117 +                                      Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
   1.118 +      } catch(e) {
   1.119 +        return null;
   1.120 +      }
   1.121 +    }
   1.122 +
   1.123 +    try {
   1.124 +      var contentPolicy = Cc["@mozilla.org/layout/content-policy;1"].
   1.125 +                          getService(Ci.nsIContentPolicy);
   1.126 +    } catch(e) {
   1.127 +      return null; // Refuse to load if we can't do a security check.
   1.128 +    }
   1.129 +
   1.130 +    // Security says okay, now ask content policy
   1.131 +    if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
   1.132 +                                 uri, targetDoc.documentURIObject,
   1.133 +                                 aLink, aLink.type, null)
   1.134 +                                 != Ci.nsIContentPolicy.ACCEPT)
   1.135 +      return null;
   1.136 +
   1.137 +    try {
   1.138 +      uri.userPass = "";
   1.139 +    } catch(e) {
   1.140 +      // some URIs are immutable
   1.141 +    }
   1.142 +    return uri;
   1.143 +  },
   1.144 +};

mercurial