Bug 418354 - Redirects should go through Mixed Content Blocker. r=smaug, ckerschb
authorTanvi Vyas <tvyas@mozilla.com>
Sat, 18 Oct 2014 13:21:06 -0700
changeset 211040 cf931893650a652c24f8bc447335df9e79c39107
parent 211039 8c605fc7e0e1b6bc91c7b11f95bf475a9f169ef6
child 211041 b3ab0a703e5637573848d2904f7c14cfc4b925f7
push id50627
push usertvyas@mozilla.com
push dateSat, 18 Oct 2014 20:22:32 +0000
treeherdermozilla-inbound@e8ff3c1b73d3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, ckerschb
bugs418354
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 418354 - Redirects should go through Mixed Content Blocker. r=smaug, ckerschb
content/base/src/nsMixedContentBlocker.cpp
content/base/src/nsMixedContentBlocker.h
layout/build/nsLayoutModule.cpp
--- a/content/base/src/nsMixedContentBlocker.cpp
+++ b/content/base/src/nsMixedContentBlocker.cpp
@@ -21,16 +21,20 @@
 #include "nsIHttpChannel.h"
 #include "mozilla/Preferences.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIDocumentLoader.h"
 #include "nsIWebNavigation.h"
 #include "nsLoadGroup.h"
 #include "nsIScriptError.h"
+#include "nsIURI.h"
+#include "nsIChannelEventSink.h"
+#include "nsAsyncRedirectVerifyHelper.h"
+#include "mozilla/LoadInfo.h"
 
 #include "prlog.h"
 
 using namespace mozilla;
 
 enum nsMixedContentBlockerMessageType {
   eBlocked = 0x00,
   eUserOverride = 0x01
@@ -145,17 +149,17 @@ nsMixedContentBlocker::nsMixedContentBlo
   Preferences::AddBoolVarCache(&sBlockMixedDisplay,
                                "security.mixed_content.block_display_content");
 }
 
 nsMixedContentBlocker::~nsMixedContentBlocker()
 {
 }
 
-NS_IMPL_ISUPPORTS(nsMixedContentBlocker, nsIContentPolicy)
+NS_IMPL_ISUPPORTS(nsMixedContentBlocker, nsIContentPolicy, nsIChannelEventSink)
 
 static void
 LogMixedContentMessage(MixedContentTypes aClassification,
                        nsIURI* aContentLocation,
                        nsIDocument* aRootDoc,
                        nsMixedContentBlockerMessageType aMessageType)
 {
   nsAutoCString messageCategory;
@@ -185,16 +189,97 @@ LogMixedContentMessage(MixedContentTypes
   NS_ConvertUTF8toUTF16 locationSpecUTF16(locationSpec);
 
   const char16_t* strings[] = { locationSpecUTF16.get() };
   nsContentUtils::ReportToConsole(severityFlag, messageCategory, aRootDoc,
                                   nsContentUtils::eSECURITY_PROPERTIES,
                                   messageLookupKey.get(), strings, ArrayLength(strings));
 }
 
+
+
+/* nsIChannelEventSink implementation
+ * This code is called when a request is redirected.
+ * We check the channel associated with the new uri is allowed to load
+ * in the current context
+ */
+NS_IMETHODIMP
+nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
+                                              nsIChannel* aNewChannel,
+                                              uint32_t aFlags,
+                                              nsIAsyncVerifyRedirectCallback* aCallback)
+{
+  nsAsyncRedirectAutoCallback autoCallback(aCallback);
+
+  if (!aOldChannel) {
+    NS_ERROR("No channel when evaluating mixed content!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsIURI> oldUri;
+  rv = aOldChannel->GetURI(getter_AddRefs(oldUri));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIURI> newUri;
+  rv = aNewChannel->GetURI(getter_AddRefs(newUri));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Get the loading Info from the old channel
+  nsCOMPtr<nsILoadInfo> loadInfo;
+  rv = aOldChannel->GetLoadInfo(getter_AddRefs(loadInfo));
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!loadInfo) {
+    // XXX: We want to have a loadInfo on all channels, but we don't yet.
+    // If an addon creates a channel, they may not set loadinfo. If that
+    // channel redirects from one page to another page, we would get caught
+    // in this code path. Hence, we have to return NS_OK. Once we have more
+    // confidence that all channels have loadinfo, we can change this to
+    // a failure. See bug 1077201.
+    return NS_OK;
+  }
+
+  uint32_t contentPolicyType = loadInfo->GetContentPolicyType();
+  nsCOMPtr<nsIPrincipal> requestingPrincipal = loadInfo->LoadingPrincipal();
+
+  // Since we are calling shouldLoad() directly on redirects, we don't go through the code
+  // in nsContentPolicyUtils::NS_CheckContentLoadPolicy(). Hence, we have to
+  // duplicate parts of it here.
+  nsCOMPtr<nsIURI> requestingLocation;
+  if (requestingPrincipal) {
+    // We check to see if the loadingPrincipal is systemPrincipal and return
+    // early if it is
+    if (nsContentUtils::IsSystemPrincipal(requestingPrincipal)) {
+      return NS_OK;
+    }
+    // We set the requestingLocation from the RequestingPrincipal.
+    rv = requestingPrincipal->GetURI(getter_AddRefs(requestingLocation));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  int16_t decision = REJECT_REQUEST;
+  rv = ShouldLoad(contentPolicyType,
+                  newUri,
+                  requestingLocation,
+                  loadInfo->LoadingNode(),
+                  EmptyCString(),       // aMimeGuess
+                  nullptr,              // aExtra
+                  requestingPrincipal,
+                  &decision);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // If the channel is about to load mixed content, abort the channel
+  if (!NS_CP_ACCEPTED(decision)) {
+    autoCallback.DontCallback();
+    return NS_BINDING_FAILED;
+  }
+
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
                                   nsIURI* aContentLocation,
                                   nsIURI* aRequestingLocation,
                                   nsISupports* aRequestingContext,
                                   const nsACString& aMimeGuess,
                                   nsISupports* aExtra,
                                   nsIPrincipal* aRequestPrincipal,
--- a/content/base/src/nsMixedContentBlocker.h
+++ b/content/base/src/nsMixedContentBlocker.h
@@ -18,23 +18,27 @@ enum MixedContentTypes {
   // "Active" content, such as fonts, plugin content, JavaScript, stylesheets,
   // iframes, WebSockets, and XHR
   eMixedScript,
   // "Display" content, such as images, audio, video, and <a ping>
   eMixedDisplay
 };
 
 #include "nsIContentPolicy.h"
+#include "nsIChannel.h"
+#include "nsIChannelEventSink.h"
 
-class nsMixedContentBlocker : public nsIContentPolicy
+class nsMixedContentBlocker : public nsIContentPolicy,
+                              public nsIChannelEventSink
 {
   virtual ~nsMixedContentBlocker();
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTENTPOLICY
+  NS_DECL_NSICHANNELEVENTSINK
 
   nsMixedContentBlocker();
   static bool sBlockMixedScript;
   static bool sBlockMixedDisplay;
 };
 
 #endif /* nsMixedContentBlocker_h___ */
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -1240,16 +1240,17 @@ static const mozilla::Module::ContractID
 
 static const mozilla::Module::CategoryEntry kLayoutCategories[] = {
   XPCONNECT_CATEGORIES
   { "content-policy", NS_DATADOCUMENTCONTENTPOLICY_CONTRACTID, NS_DATADOCUMENTCONTENTPOLICY_CONTRACTID },
   { "content-policy", NS_NODATAPROTOCOLCONTENTPOLICY_CONTRACTID, NS_NODATAPROTOCOLCONTENTPOLICY_CONTRACTID },
   { "content-policy", "CSPService", CSPSERVICE_CONTRACTID },
   { "content-policy", NS_MIXEDCONTENTBLOCKER_CONTRACTID, NS_MIXEDCONTENTBLOCKER_CONTRACTID },
   { "net-channel-event-sinks", "CSPService", CSPSERVICE_CONTRACTID },
+  { "net-channel-event-sinks", NS_MIXEDCONTENTBLOCKER_CONTRACTID, NS_MIXEDCONTENTBLOCKER_CONTRACTID },
   { "app-startup", "Script Security Manager", "service," NS_SCRIPTSECURITYMANAGER_CONTRACTID },
   { TOPIC_WEB_APP_CLEAR_DATA, "QuotaManager", "service," QUOTA_MANAGER_CONTRACTID },
 #ifdef MOZ_WIDGET_GONK
   { "app-startup", "Volume Service", "service," NS_VOLUMESERVICE_CONTRACTID },
 #endif
   CONTENTDLF_CATEGORIES
 #ifdef MOZ_WIDGET_GONK
   { "profile-after-change", "Gonk System Worker Manager", SYSTEMWORKERMANAGER_CONTRACTID },