Bug 1420622 - Remove feed and pcast protocols. r?Gijs draft
authorJonathan Kingston <jkt@mozilla.com>
Tue, 19 Dec 2017 16:12:29 +0000
changeset 713116 3a2519e3e932e8c461cefc4ca090b39fe5d4dc3f
parent 713115 c0bcaa13c37fae43dbd6ddc995c64e14ab8cb5a8
child 744242 202f20b14430b81d6145a23d73b5a62df6ce21bf
push id93543
push userbmo:jkt@mozilla.com
push dateTue, 19 Dec 2017 16:19:00 +0000
reviewersGijs
bugs1420622
milestone59.0a1
Bug 1420622 - Remove feed and pcast protocols. r?Gijs MozReview-Commit-ID: KAC9MmLiuBG
browser/base/content/browser-feeds.js
browser/base/content/test/general/feed_discovery.html
browser/components/feeds/BrowserFeeds.manifest
browser/components/feeds/FeedConverter.js
browser/components/feeds/moz.build
browser/components/feeds/nsFeedSniffer.cpp
browser/modules/test/unit/test_E10SUtils_nested_URIs.js
caps/tests/mochitest/browser_checkloaduri.js
docshell/test/chrome/test_viewsource_forbidden_in_iframe.xul
toolkit/components/telemetry/Histograms.json
--- a/browser/base/content/browser-feeds.js
+++ b/browser/base/content/browser-feeds.js
@@ -203,21 +203,16 @@ var FeedHandler = {
    */
   subscribeToFeed(href, event) {
     // Just load the feed in the content area to either subscribe or show the
     // preview UI
     if (!href)
       href = event.target.getAttribute("feed");
     urlSecurityCheck(href, gBrowser.contentPrincipal,
                      Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
-    let feedURI = makeURI(href, document.characterSet);
-    // Use the feed scheme so X-Moz-Is-Feed will be set
-    // The value doesn't matter
-    if (/^https?$/.test(feedURI.scheme))
-      href = "feed:" + href;
     this.loadFeed(href, event);
   },
 
   loadFeed(href, event) {
     let feeds = gBrowser.selectedBrowser.feeds;
     try {
       openUILink(href, event, { ignoreAlt: true });
     } finally {
@@ -274,16 +269,23 @@ var FeedHandler = {
       this._feedMenupopup.setAttribute("hidden", "true");
     }
   },
 
   addFeed(link, browserForLink) {
     if (!browserForLink.feeds)
       browserForLink.feeds = [];
 
+    urlSecurityCheck(link.href, gBrowser.contentPrincipal,
+                     Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
+
+    let feedURI = makeURI(link.href, document.characterSet);
+    if (!/^https?$/.test(feedURI.scheme))
+      return;
+
     browserForLink.feeds.push({ href: link.href, title: link.title });
 
     // If this addition was for the current browser, update the UI. For
     // background browsers, we'll update on tab switch.
     if (browserForLink == gBrowser.selectedBrowser) {
       // Batch updates to avoid updating the UI for multiple onLinkAdded events
       // fired within 100ms of each other.
       if (this._updateFeedTimeout)
--- a/browser/base/content/test/general/feed_discovery.html
+++ b/browser/base/content/test/general/feed_discovery.html
@@ -7,16 +7,21 @@ https://bugzilla.mozilla.org/show_bug.cg
     <title>Test for feed discovery</title>
     <meta charset="utf-8">
 
     <!-- Straight up standard -->
     <link rel="alternate" type="application/atom+xml" title="1" href="/1.atom" />
     <link rel="alternate" type="application/rss+xml" title="2" href="/2.rss" />
     <link rel="feed" title="3" href="/3.xml" />
 
+    <!-- invalid protocol -->
+    <link rel="alternate" type="application/atom+xml" title="Bogus non file protocol" href="file://path/1.rss" />
+    <link rel="alternate" type="application/atom+xml" title="Bogus non feed:http protocol" href="feed:http://path/1.rss" />
+    <link rel="alternate" type="application/atom+xml" title="Bogus non pcast protocol" href="pcast://path/1.rss" />
+
     <!-- rel is a space-separated list -->
     <link rel=" alternate " type="application/atom+xml" title="4" href="/4.atom" />
     <link rel="foo alternate" type="application/atom+xml" title="5" href="/5.atom" />
     <link rel="alternate foo" type="application/atom+xml" title="6" href="/6.atom" />
     <link rel="foo alternate foo" type="application/atom+xml" title="7" href="/7.atom" />
     <link rel="meat feed cake" title="8" href="/8.atom" />
 
     <!-- rel is case-insensitive -->
--- a/browser/components/feeds/BrowserFeeds.manifest
+++ b/browser/components/feeds/BrowserFeeds.manifest
@@ -9,17 +9,13 @@
 #   graphene:       {d1bfe7d9-c01e-4237-998b-7b5f960a4314}
 
 component {229fa115-9412-4d32-baf3-2fc407f76fb1} FeedConverter.js
 contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
 contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.video.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
 contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.audio.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
 component {2376201c-bbc6-472f-9b62-7548040a61c6} FeedConverter.js
 contract @mozilla.org/browser/feeds/result-service;1 {2376201c-bbc6-472f-9b62-7548040a61c6}
-component {4f91ef2e-57ba-472e-ab7a-b4999e42d6c0} FeedConverter.js
-contract @mozilla.org/network/protocol;1?name=feed {4f91ef2e-57ba-472e-ab7a-b4999e42d6c0}
-component {1c31ed79-accd-4b94-b517-06e0c81999d5} FeedConverter.js
-contract @mozilla.org/network/protocol;1?name=pcast {1c31ed79-accd-4b94-b517-06e0c81999d5}
 component {49bb6593-3aff-4eb3-a068-2712c28bd58e} FeedWriter.js
 contract @mozilla.org/browser/feeds/result-writer;1 {49bb6593-3aff-4eb3-a068-2712c28bd58e}
 component {792a7e82-06a0-437c-af63-b2d12e808acc} WebContentConverter.js
 contract @mozilla.org/embeddor.implemented/web-content-handler-registrar;1 {792a7e82-06a0-437c-af63-b2d12e808acc}
 category app-startup WebContentConverter service,@mozilla.org/embeddor.implemented/web-content-handler-registrar;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66} application={d1bfe7d9-c01e-4237-998b-7b5f960a4314}
--- a/browser/components/feeds/FeedConverter.js
+++ b/browser/components/feeds/FeedConverter.js
@@ -450,128 +450,14 @@ FeedResultService.prototype = {
     if (iid.equals(Ci.nsIFeedResultService) ||
         iid.equals(Ci.nsIFactory) ||
         iid.equals(Ci.nsISupports))
       return this;
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
 };
 
-/**
- * A protocol handler that attempts to deal with the variant forms of feed:
- * URIs that are actually either http or https.
- */
-function GenericProtocolHandler() {
-}
-GenericProtocolHandler.prototype = {
-  _init(scheme) {
-    this._http = Services.io.getProtocolHandler("http");
-    this._scheme = scheme;
-  },
-
-  get scheme() {
-    return this._scheme;
-  },
-
-  get protocolFlags() {
-    let {URI_DANGEROUS_TO_LOAD, ALLOWS_PROXY_HTTP, ALLOWS_PROXY} =
-      Ci.nsIProtocolHandler;
-    return URI_DANGEROUS_TO_LOAD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP;
-  },
-
-  get defaultPort() {
-    return this._http.defaultPort;
-  },
-
-  allowPort(port, scheme) {
-    return this._http.allowPort(port, scheme);
-  },
-
-  _getTelemetrySchemeId() {
-    // Gets a scheme id from 1-8
-    let schemeId;
-    if (!this._telemetrySubScheme) {
-      schemeId = 1;
-    } else {
-      switch (this._telemetryInnerScheme) {
-        case "http":
-          schemeId = 2;
-          break;
-        case "https":
-          schemeId = 3;
-          break;
-        default:
-          // Invalid scheme
-          schemeId = 4;
-      }
-    }
-    if (this._scheme === "pcast") {
-      schemeId += 4;
-    }
-    return schemeId;
-  },
-
-  newURI(spec, originalCharset, baseURI) {
-    // Feed URIs can be either nested URIs of the form feed:realURI (in which
-    // case we create a nested URI for the realURI) or feed://example.com, in
-    // which case we create a nested URI for the real protocol which is http.
-
-    let scheme = this._scheme + ":";
-    if (spec.substr(0, scheme.length) != scheme)
-      throw Cr.NS_ERROR_MALFORMED_URI;
-
-    this._telemetrySubScheme = spec.substr(scheme.length, 2) != "//";
-
-    let prefix = spec.substr(scheme.length, 2) == "//" ? "http:" : "";
-    let inner = Services.io.newURI(spec.replace(scheme, prefix),
-                                   originalCharset, baseURI);
-    this._telemetryInnerScheme = inner.scheme;
-
-
-    if (!["http", "https"].includes(inner.scheme))
-      throw Cr.NS_ERROR_MALFORMED_URI;
-
-    let uri = Services.io.QueryInterface(Ci.nsINetUtil).newSimpleNestedURI(inner);
-    uri.spec = inner.spec.replace(prefix, scheme);
-    return uri;
-  },
-
-  newChannel2(aUri, aLoadInfo) {
-    let inner = aUri.QueryInterface(Ci.nsINestedURI).innerURI;
-    let channel = Services.io.newChannelFromURIWithLoadInfo(inner, aLoadInfo);
-
-    const schemeId = this._getTelemetrySchemeId();
-    Services.telemetry.getHistogramById("FEED_PROTOCOL_USAGE").add(schemeId);
-
-    if (channel instanceof Components.interfaces.nsIHttpChannel)
-      // Set this so we know this is supposed to be a feed
-      channel.setRequestHeader("X-Moz-Is-Feed", "1", false);
-    channel.originalURI = aUri;
-    return channel;
-  },
-
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIProtocolHandler) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
-};
-
-function FeedProtocolHandler() {
-  this._init("feed");
-}
-FeedProtocolHandler.prototype = new GenericProtocolHandler();
-FeedProtocolHandler.prototype.classID = Components.ID("{4f91ef2e-57ba-472e-ab7a-b4999e42d6c0}");
-
-function PodCastProtocolHandler() {
-  this._init("pcast");
-}
-PodCastProtocolHandler.prototype = new GenericProtocolHandler();
-PodCastProtocolHandler.prototype.classID = Components.ID("{1c31ed79-accd-4b94-b517-06e0c81999d5}");
 
 var components = [FeedConverter,
-                  FeedResultService,
-                  FeedProtocolHandler,
-                  PodCastProtocolHandler];
+                  FeedResultService];
 
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/browser/components/feeds/moz.build
+++ b/browser/components/feeds/moz.build
@@ -1,15 +1,14 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome/chrome.ini']
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 
 JAR_MANIFESTS += ['jar.mn']
 
 XPIDL_SOURCES += [
     'nsIFeedResultService.idl',
     'nsIWebContentConverterRegistrar.idl',
--- a/browser/components/feeds/nsFeedSniffer.cpp
+++ b/browser/components/feeds/nsFeedSniffer.cpp
@@ -241,27 +241,16 @@ nsFeedSniffer::GetMIMETypeFromContent(ns
   // something specific that we think is a reliable indication of a feed, don't
   // bother sniffing since we assume the site maintainer knows what they're
   // doing.
   nsAutoCString contentType;
   channel->GetContentType(contentType);
   bool noSniff = contentType.EqualsLiteral(TYPE_RSS) ||
                    contentType.EqualsLiteral(TYPE_ATOM);
 
-  // Check to see if this was a feed request from the location bar or from
-  // the feed: protocol. This is also a reliable indication.
-  // The value of the header doesn't matter.
-  if (!noSniff) {
-    nsAutoCString sniffHeader;
-    nsresult foundHeader =
-      channel->GetRequestHeader(NS_LITERAL_CSTRING("X-Moz-Is-Feed"),
-                                sniffHeader);
-    noSniff = NS_SUCCEEDED(foundHeader);
-  }
-
   if (noSniff) {
     // check for an attachment after we have a likely feed.
     if(HasAttachmentDisposition(channel)) {
       sniffedType.Truncate();
       return NS_OK;
     }
 
     // set the feed header as a response header, since we have good metadata
--- a/browser/modules/test/unit/test_E10SUtils_nested_URIs.js
+++ b/browser/modules/test/unit/test_E10SUtils_nested_URIs.js
@@ -24,44 +24,32 @@ var TEST_CASES = [
     nestedURL: "jar:jar:file:///some.file!/!/",
     plainURL: "file:///some.file",
   },
   {
     nestedURL: "jar:http://some.site/file!/",
     plainURL: "http://some.site/file",
   },
   {
-    nestedURL: "feed:http://some.site",
-    plainURL: "http://some.site",
-  },
-  {
-    nestedURL: "pcast:http://some.site",
-    plainURL: "http://some.site",
-  },
-  {
     nestedURL: "view-source:http://some.site",
     plainURL: "http://some.site",
   },
   {
     nestedURL: "view-source:file:///some.file",
     plainURL: "file:///some.file",
   },
   {
     nestedURL: "view-source:about:home",
     plainURL: "about:home",
   },
   {
     nestedURL: "view-source:about:robots",
     plainURL: "about:robots",
   },
   {
-    nestedURL: "view-source:feed:http://some.site",
-    plainURL: "http://some.site",
-  },
-  {
     nestedURL: "view-source:pcast:http://some.site",
     plainURL: "http://some.site",
   },
 ];
 
 function run_test() {
   for (let testCase of TEST_CASES) {
     for (let preferredRemoteType of TEST_PREFERRED_REMOTE_TYPES) {
--- a/caps/tests/mochitest/browser_checkloaduri.js
+++ b/caps/tests/mochitest/browser_checkloaduri.js
@@ -42,74 +42,41 @@ const kAboutPagesRegistered = Promise.al
 const URLs = new Map([
   ["http://www.example.com", [
   // For each of these entries, the booleans represent whether the parent URI can:
   // - load them
   // - load them without principal inheritance
   // - whether the URI can be created at all (some protocol handlers will
   //   refuse to create certain variants)
     ["http://www.example2.com", true, true, true],
-    ["feed:http://www.example2.com", false, false, true],
     ["https://www.example2.com", true, true, true],
     ["moz-icon:file:///foo/bar/baz.exe", false, false, true],
     ["moz-icon://.exe", false, false, true],
     ["chrome://foo/content/bar.xul", false, false, true],
-    ["feed:chrome://foo/content/bar.xul", false, false, false],
     ["view-source:http://www.example2.com", false, false, true],
     ["view-source:https://www.example2.com", false, false, true],
-    ["view-source:feed:http://www.example2.com", false, false, true],
-    ["feed:view-source:http://www.example2.com", false, false, false],
-    ["data:text/html,Hi", true, false, true],
-    ["view-source:data:text/html,Hi", false, false, true],
-    ["javascript:alert('hi')", true, false, true],
-    ["moz://a", false, false, true],
-    ["about:test-chrome-privs", false, false, true],
-    ["about:test-unknown-unlinkable", false, false, true],
-    ["about:test-content-unlinkable", false, false, true],
-    ["about:test-content-linkable", true, true, true],
-    // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it:
-    ["about:test-unknown-linkable", false, false, true],
-  ]],
-  ["feed:http://www.example.com", [
-    ["http://www.example2.com", true, true, true],
-    ["feed:http://www.example2.com", true, true, true],
-    ["https://www.example2.com", true, true, true],
-    ["moz-icon:file:///foo/bar/baz.exe", false, false, true],
-    ["moz-icon://.exe", false, false, true],
-    ["feed:https://www.example2.com", true, true, true],
-    ["chrome://foo/content/bar.xul", false, false, true],
-    ["feed:chrome://foo/content/bar.xul", false, false, false],
-    ["view-source:http://www.example2.com", false, false, true],
-    ["view-source:https://www.example2.com", false, false, true],
-    ["view-source:feed:http://www.example2.com", false, false, true],
-    ["feed:view-source:http://www.example2.com", false, false, false],
     ["data:text/html,Hi", true, false, true],
     ["view-source:data:text/html,Hi", false, false, true],
     ["javascript:alert('hi')", true, false, true],
     ["moz://a", false, false, true],
     ["about:test-chrome-privs", false, false, true],
     ["about:test-unknown-unlinkable", false, false, true],
     ["about:test-content-unlinkable", false, false, true],
     ["about:test-content-linkable", true, true, true],
     // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it:
     ["about:test-unknown-linkable", false, false, true],
   ]],
   ["view-source:http://www.example.com", [
     ["http://www.example2.com", true, true, true],
-    ["feed:http://www.example2.com", false, false, true],
     ["https://www.example2.com", true, true, true],
     ["moz-icon:file:///foo/bar/baz.exe", false, false, true],
     ["moz-icon://.exe", false, false, true],
-    ["feed:https://www.example2.com", false, false, true],
     ["chrome://foo/content/bar.xul", false, false, true],
-    ["feed:chrome://foo/content/bar.xul", false, false, false],
     ["view-source:http://www.example2.com", true, true, true],
     ["view-source:https://www.example2.com", true, true, true],
-    ["view-source:feed:http://www.example2.com", false, false, true],
-    ["feed:view-source:http://www.example2.com", false, false, false],
     ["data:text/html,Hi", true, false, true],
     ["view-source:data:text/html,Hi", true, false, true],
     ["javascript:alert('hi')", true, false, true],
     ["moz://a", false, false, true],
     ["about:test-chrome-privs", false, false, true],
     ["about:test-unknown-unlinkable", false, false, true],
     ["about:test-content-unlinkable", false, false, true],
     ["about:test-content-linkable", true, true, true],
@@ -284,21 +251,13 @@ add_task(async function() {
         testURL(contentPrincipal, contentBlobURI, true, true, true, baseFlags);
         testURL(contentPrincipal, contentBlobURI, true, true, true,
                 baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL);
 
         testURL(contentPrincipal, "view-source:" + contentBlobURI, false, false, true,
                 baseFlags);
         testURL(contentPrincipal, "view-source:" + contentBlobURI, false, false, true,
                 baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL);
-
-        // Feed URIs for blobs can't be created, so need to pass false as the fourth param.
-        for (let prefix of ["feed:", "view-source:feed:", "feed:view-source:"]) {
-          testURL(contentPrincipal, prefix + contentBlobURI, false, false, false,
-                  baseFlags);
-          testURL(contentPrincipal, prefix + contentBlobURI, false, false, false,
-                  baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL);
-        }
       }
     );
 
   });
 });
--- a/docshell/test/chrome/test_viewsource_forbidden_in_iframe.xul
+++ b/docshell/test/chrome/test_viewsource_forbidden_in_iframe.xul
@@ -127,44 +127,29 @@ https://bugzilla.mozilla.org/show_bug.cg
   var testCaseIndex = -1;
   testCases = [
     {
       desc: "Test 1: view-source should not be allowed in an iframe",
       protocols: "view-source:http",
       expectedProtocolList: "view-source, http"
     },
     {
-      desc: "Test 2: feed:view-source should not be allowed in an iframe",
-      protocols: "feed:view-source:http",
-      expectedProtocolList: "feed, view-source, http"
-    },
-    {
-      desc: "Test 3: jar:view-source should not be allowed in an iframe",
+      desc: "Test 2: jar:view-source should not be allowed in an iframe",
       protocols: "jar:view-source:http",
       expectedProtocolList: "jar, view-source, http"
     },
     {
-      desc: "Test 4: pcast:view-source should not be allowed in an iframe",
-      protocols: "pcast:view-source:http",
-      expectedProtocolList: "pcast, view-source, http"
-    },
-    {
-      desc: "Test 5: pcast:feed:view-source should not be allowed in an iframe",
-      protocols: "pcast:feed:view-source:http",
-      expectedProtocolList: "pcast, feed, view-source, http"
-    },
-    {
-      desc: "Test 6: if invalid protocol first should report before view-source",
+      desc: "Test 3: if invalid protocol first should report before view-source",
       protocols: "wibble:view-source:http",
       // Nothing after the invalid protocol gets set as a proper nested URI,
       // so the list stops there.
       expectedProtocolList: "wibble"
     },
     {
-      desc: "Test 7: if view-source first should report before invalid protocol",
+      desc: "Test 4: if view-source first should report before invalid protocol",
       protocols: "view-source:wibble:http",
       expectedProtocolList: "view-source, wibble"
     }
   ];
 
   function runNextTestCase() {
     ++testCaseIndex;
     if (testCaseIndex == testCases.length) {
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -864,25 +864,16 @@
     "record_in_processes": ["main", "content"],
     "alert_emails": ["seceng-telemetry@mozilla.com"],
     "expires_in_version": "60",
     "kind": "enumerated",
     "n_values": 16,
     "bug_numbers": [1239166],
     "description": "Status of Family Safety detection and remediation. See nsNSSComponent.cpp."
   },
-  "FEED_PROTOCOL_USAGE": {
-    "record_in_processes": ["main", "content"],
-    "alert_emails": ["jkt@mozilla.com"],
-    "bug_numbers": [1345546],
-    "expires_in_version": "60",
-    "kind": "enumerated",
-    "n_values": 8,
-    "description": "Usage counts of feed protocols used to load a page. (1=feed, 2=feed:http, 3=feed:https, 4=feed:brokenScheme, 5=pcast, 6=pcast:http, 7=pcast:https, 8=pcast:brokenScheme)"
-  },
   "FETCH_IS_MAINTHREAD": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "50",
     "kind": "boolean",
     "description": "Was Fetch request initiated from the main thread?"
   },
   "FORCED_DEVICE_RESET_REASON": {
     "record_in_processes": ["main", "content", "gpu"],