Bug 1157451. Make nsCORSListenerProxy::Init take an enum, not a boolean, to indicate what to do with data: URIs. And make it required, not defaulted to disallowing. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 22 Apr 2015 20:30:10 -0400
changeset 240611 fbcc88ae790e523a91ca4421d39c5bc90df9124e
parent 240610 fe1f03452fa1aa7f1dde2d4fc0cf02579ba65edf
child 240612 c0a33c32841d3b7d41704c5512f66772810d4724
push id58871
push userbzbarsky@mozilla.com
push dateThu, 23 Apr 2015 00:38:25 +0000
treeherdermozilla-inbound@c0a33c32841d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1157451
milestone40.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 1157451. Make nsCORSListenerProxy::Init take an enum, not a boolean, to indicate what to do with data: URIs. And make it required, not defaulted to disallowing. r=smaug
dom/base/EventSource.cpp
dom/base/ImportManager.cpp
dom/base/Navigator.cpp
dom/base/nsScriptLoader.cpp
dom/base/nsSyncLoadService.cpp
dom/base/nsXMLHttpRequest.cpp
dom/fetch/FetchDriver.cpp
dom/html/HTMLMediaElement.cpp
dom/media/MediaResource.cpp
dom/security/nsCORSListenerProxy.cpp
dom/security/nsCORSListenerProxy.h
dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
image/src/imgLoader.cpp
layout/style/FontFaceSet.cpp
layout/style/Loader.cpp
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -791,17 +791,17 @@ EventSource::InitChannelAndRequestEventS
   mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
   if (notificationCallbacks != this) {
     mNotificationCallbacks = notificationCallbacks;
     mHttpChannel->SetNotificationCallbacks(this);
   }
 
   nsRefPtr<nsCORSListenerProxy> listener =
     new nsCORSListenerProxy(this, mPrincipal, mWithCredentials);
-  rv = listener->Init(mHttpChannel);
+  rv = listener->Init(mHttpChannel, DataURIHandling::Allow);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Start reading from the channel
   rv = mHttpChannel->AsyncOpen(listener, nullptr);
   if (NS_SUCCEEDED(rv)) {
     mWaitingForOnStopRequest = true;
   }
   return rv;
--- a/dom/base/ImportManager.cpp
+++ b/dom/base/ImportManager.cpp
@@ -499,17 +499,17 @@ ImportLoader::Open()
                      nsIRequest::LOAD_BACKGROUND);
 
   NS_ENSURE_SUCCESS_VOID(rv);
 
   // Init CORSListenerProxy and omit credentials.
   nsRefPtr<nsCORSListenerProxy> corsListener =
     new nsCORSListenerProxy(this, principal,
                             /* aWithCredentials */ false);
-  rv = corsListener->Init(channel, true);
+  rv = corsListener->Init(channel, DataURIHandling::Allow);
   NS_ENSURE_SUCCESS_VOID(rv);
 
   rv = channel->AsyncOpen(corsListener, nullptr);
   NS_ENSURE_SUCCESS_VOID(rv);
 
   BlockScripts();
   ae.Pass();
 }
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1216,17 +1216,17 @@ Navigator::SendBeacon(const nsAString& a
   if (cos) {
     cos->AddClassFlags(nsIClassOfService::Background);
   }
 
   nsRefPtr<nsCORSListenerProxy> cors = new nsCORSListenerProxy(new BeaconStreamListener(),
                                                                principal,
                                                                true);
 
-  rv = cors->Init(channel, true);
+  rv = cors->Init(channel, DataURIHandling::Allow);
   NS_ENSURE_SUCCESS(rv, false);
 
   nsCOMPtr<nsINetworkInterceptController> interceptController = do_QueryInterface(docShell);
   cors->SetInterceptController(interceptController);
 
   // Start a preflight if cross-origin and content type is not whitelisted
   rv = secMan->CheckSameOriginURI(documentURI, uri, false);
   bool crossOrigin = NS_FAILED(rv);
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -342,17 +342,17 @@ nsScriptLoader::StartLoad(nsScriptLoadRe
 
   nsCOMPtr<nsIStreamListener> listener = loader.get();
 
   if (aRequest->mCORSMode != CORS_NONE) {
     bool withCredentials = (aRequest->mCORSMode == CORS_USE_CREDENTIALS);
     nsRefPtr<nsCORSListenerProxy> corsListener =
       new nsCORSListenerProxy(listener, mDocument->NodePrincipal(),
                               withCredentials);
-    rv = corsListener->Init(channel, true);
+    rv = corsListener->Init(channel, DataURIHandling::Allow);
     NS_ENSURE_SUCCESS(rv, rv);
     listener = corsListener;
   }
 
   rv = channel->AsyncOpen(listener, aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
--- a/dom/base/nsSyncLoadService.cpp
+++ b/dom/base/nsSyncLoadService.cpp
@@ -184,17 +184,17 @@ nsSyncLoader::LoadDocument(nsIChannel* a
         nsCOMPtr<nsIStreamListener> forceListener =
             new nsForceXMLListener(listener);
         listener.swap(forceListener);
     }
 
     if (aLoaderPrincipal) {
         nsRefPtr<nsCORSListenerProxy> corsListener =
           new nsCORSListenerProxy(listener, aLoaderPrincipal, false);
-        rv = corsListener->Init(mChannel);
+        rv = corsListener->Init(mChannel, DataURIHandling::Disallow);
         NS_ENSURE_SUCCESS(rv, rv);
         listener = corsListener;
     }
 
     if (aChannelIsSync) {
         rv = PushSyncStream(listener);
     }
     else {
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -2884,17 +2884,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
   }
 
   nsCOMPtr<nsIStreamListener> listener = this;
   if (!IsSystemXHR()) {
     // Always create a nsCORSListenerProxy here even if it's
     // a same-origin request right now, since it could be redirected.
     nsRefPtr<nsCORSListenerProxy> corsListener =
       new nsCORSListenerProxy(listener, mPrincipal, withCredentials);
-    rv = corsListener->Init(mChannel, true);
+    rv = corsListener->Init(mChannel, DataURIHandling::Allow);
     NS_ENSURE_SUCCESS(rv, rv);
     listener = corsListener;
   }
   else {
     // Because of bug 682305, we can't let listener be the XHR object itself
     // because JS wouldn't be able to use it. So if we haven't otherwise
     // created a listener around 'this', do so now.
 
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -496,17 +496,17 @@ FetchDriver::HttpFetch(bool aCORSFlag, b
   if (mRequest->Mode() != RequestMode::No_cors) {
     // Set up a CORS proxy that will handle the various requirements of the CORS
     // protocol. It handles the preflight cache and CORS response headers.
     // If the request is allowed, it will start our original request
     // and our observer will be notified. On failure, our observer is notified
     // directly.
     nsRefPtr<nsCORSListenerProxy> corsListener =
       new nsCORSListenerProxy(this, mPrincipal, useCredentials);
-    rv = corsListener->Init(chan, true /* allow data uri */);
+    rv = corsListener->Init(chan, DataURIHandling::Allow);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return FailWithNetworkError();
     }
     listener = corsListener.forget();
   }
 
   // If preflight is required, start a "CORS preflight fetch"
   // https://fetch.spec.whatwg.org/#cors-preflight-fetch-0. All the
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1270,17 +1270,17 @@ nsresult HTMLMediaElement::LoadResource(
   channel->SetNotificationCallbacks(loadListener);
 
   nsCOMPtr<nsIStreamListener> listener;
   if (ShouldCheckAllowOrigin()) {
     nsRefPtr<nsCORSListenerProxy> corsListener =
       new nsCORSListenerProxy(loadListener,
                               NodePrincipal(),
                               GetCORSMode() == CORS_USE_CREDENTIALS);
-    rv = corsListener->Init(channel, true);
+    rv = corsListener->Init(channel, DataURIHandling::Allow);
     NS_ENSURE_SUCCESS(rv, rv);
     listener = corsListener;
   } else {
     rv = nsContentUtils::GetSecurityManager()->
            CheckLoadURIWithPrincipal(NodePrincipal(),
                                      mLoadingSrc,
                                      nsIScriptSecurityManager::STANDARD);
     listener = loadListener;
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -614,17 +614,17 @@ nsresult ChannelMediaResource::OpenChann
     dom::HTMLMediaElement* element = owner->GetMediaElement();
     NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
     if (element->ShouldCheckAllowOrigin()) {
       nsRefPtr<nsCORSListenerProxy> crossSiteListener =
         new nsCORSListenerProxy(mListener,
                                 element->NodePrincipal(),
                                 false);
       NS_ENSURE_TRUE(crossSiteListener, NS_ERROR_OUT_OF_MEMORY);
-      rv = crossSiteListener->Init(mChannel, true);
+      rv = crossSiteListener->Init(mChannel, DataURIHandling::Allow);
       NS_ENSURE_SUCCESS(rv, rv);
       listener = crossSiteListener;
     } else {
       rv = nsContentUtils::GetSecurityManager()->
         CheckLoadURIWithPrincipal(element->NodePrincipal(),
                                   mURI,
                                   nsIScriptSecurityManager::STANDARD);
       NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/security/nsCORSListenerProxy.cpp
+++ b/dom/security/nsCORSListenerProxy.cpp
@@ -466,17 +466,17 @@ nsCORSListenerProxy::nsCORSListenerProxy
   mPreflightHeaders.Sort();
 }
 
 nsCORSListenerProxy::~nsCORSListenerProxy()
 {
 }
 
 nsresult
-nsCORSListenerProxy::Init(nsIChannel* aChannel, bool aAllowDataURI)
+nsCORSListenerProxy::Init(nsIChannel* aChannel, DataURIHandling aAllowDataURI)
 {
   aChannel->GetNotificationCallbacks(getter_AddRefs(mOuterNotificationCallbacks));
   aChannel->SetNotificationCallbacks(this);
 
   nsresult rv = UpdateChannel(aChannel, aAllowDataURI);
   if (NS_FAILED(rv)) {
     mOuterListener = nullptr;
     mRequestingPrincipal = nullptr;
@@ -793,17 +793,17 @@ nsCORSListenerProxy::AsyncOnChannelRedir
 NS_IMETHODIMP
 nsCORSListenerProxy::OnRedirectVerifyCallback(nsresult result)
 {
   NS_ASSERTION(mRedirectCallback, "mRedirectCallback not set in callback");
   NS_ASSERTION(mOldRedirectChannel, "mOldRedirectChannel not set in callback");
   NS_ASSERTION(mNewRedirectChannel, "mNewRedirectChannel not set in callback");
 
   if (NS_SUCCEEDED(result)) {
-      nsresult rv = UpdateChannel(mNewRedirectChannel);
+    nsresult rv = UpdateChannel(mNewRedirectChannel, DataURIHandling::Disallow);
       if (NS_FAILED(rv)) {
           NS_WARNING("nsCORSListenerProxy::OnRedirectVerifyCallback: "
                      "UpdateChannel() returned failure");
       }
       result = rv;
   }
 
   if (NS_FAILED(result)) {
@@ -813,26 +813,27 @@ nsCORSListenerProxy::OnRedirectVerifyCal
   mOldRedirectChannel = nullptr;
   mNewRedirectChannel = nullptr;
   mRedirectCallback->OnRedirectVerifyCallback(result);
   mRedirectCallback   = nullptr;
   return NS_OK;
 }
 
 nsresult
-nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, bool aAllowDataURI)
+nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
+                                   DataURIHandling aAllowDataURI)
 {
   nsCOMPtr<nsIURI> uri, originalURI;
   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // exempt data URIs from the same origin check.
-  if (aAllowDataURI && originalURI == uri) {
+  if (aAllowDataURI == DataURIHandling::Allow && originalURI == uri) {
     bool dataScheme = false;
     rv = uri->SchemeIs("data", &dataScheme);
     NS_ENSURE_SUCCESS(rv, rv);
     if (dataScheme) {
       return NS_OK;
     }
   }
 
@@ -1235,17 +1236,17 @@ NS_StartCORSPreflight(nsIChannel* aReque
     new nsCORSPreflightListener(aRequestChannel, aListener, nullptr, aPrincipal,
                                 method, aWithCredentials);
   NS_ENSURE_TRUE(preflightListener, NS_ERROR_OUT_OF_MEMORY);
 
   nsRefPtr<nsCORSListenerProxy> corsListener =
     new nsCORSListenerProxy(preflightListener, aPrincipal,
                             aWithCredentials, method,
                             aUnsafeHeaders);
-  rv = corsListener->Init(preflightChannel);
+  rv = corsListener->Init(preflightChannel, DataURIHandling::Disallow);
   NS_ENSURE_SUCCESS(rv, rv);
   preflightListener = corsListener;
 
   // Start preflight
   rv = preflightChannel->AsyncOpen(preflightListener, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
   
   // Return newly created preflight channel
--- a/dom/security/nsCORSListenerProxy.h
+++ b/dom/security/nsCORSListenerProxy.h
@@ -24,16 +24,22 @@ class nsINetworkInterceptController;
 nsresult
 NS_StartCORSPreflight(nsIChannel* aRequestChannel,
                       nsIStreamListener* aListener,
                       nsIPrincipal* aPrincipal,
                       bool aWithCredentials,
                       nsTArray<nsCString>& aACUnsafeHeaders,
                       nsIChannel** aPreflightChannel);
 
+enum class DataURIHandling
+{
+  Allow,
+  Disallow
+};
+
 class nsCORSListenerProxy final : public nsIStreamListener,
                                   public nsIInterfaceRequestor,
                                   public nsIChannelEventSink,
                                   public nsIAsyncVerifyRedirectCallback
 {
 public:
   nsCORSListenerProxy(nsIStreamListener* aOuter,
                       nsIPrincipal* aRequestingPrincipal,
@@ -51,24 +57,24 @@ public:
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
 
   // Must be called at startup.
   static void Startup();
 
   static void Shutdown();
 
-  nsresult Init(nsIChannel* aChannel, bool aAllowDataURI = false);
+  nsresult Init(nsIChannel* aChannel, DataURIHandling aAllowDataURI);
 
   void SetInterceptController(nsINetworkInterceptController* aInterceptController);
 
 private:
   ~nsCORSListenerProxy();
 
-  nsresult UpdateChannel(nsIChannel* aChannel, bool aAllowDataURI = false);
+  nsresult UpdateChannel(nsIChannel* aChannel, DataURIHandling aAllowDataURI);
   nsresult CheckRequestApproved(nsIRequest* aRequest);
 
   nsCOMPtr<nsIStreamListener> mOuterListener;
   // The principal that originally kicked off the request
   nsCOMPtr<nsIPrincipal> mRequestingPrincipal;
   // The principal to use for our Origin header ("source origin" in spec terms).
   // This can get changed during redirects, unlike mRequestingPrincipal.
   nsCOMPtr<nsIPrincipal> mOriginHeaderPrincipal;
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -500,17 +500,17 @@ txCompileObserver::startLoad(nsIURI* aUr
 
     parser->SetCommand(kLoadAsData);
     parser->SetContentSink(sink);
     parser->Parse(aUri);
 
     // Always install in case of redirects
     nsRefPtr<nsCORSListenerProxy> listener =
         new nsCORSListenerProxy(sink, aReferrerPrincipal, false);
-    rv = listener->Init(channel);
+    rv = listener->Init(channel, DataURIHandling::Disallow);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return channel->AsyncOpen(listener, parser);
 }
 
 nsresult
 TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor,
              nsIDocument* aLoaderDocument, ReferrerPolicy aReferrerPolicy)
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -1669,17 +1669,17 @@ imgLoader::ValidateRequestWithNewChannel
     // CORS listener, because that's also interested inthe
     // notification callbacks.
     newChannel->SetNotificationCallbacks(hvc);
 
     if (aCORSMode != imgIRequest::CORS_NONE) {
       bool withCredentials = aCORSMode == imgIRequest::CORS_USE_CREDENTIALS;
       nsRefPtr<nsCORSListenerProxy> corsproxy =
         new nsCORSListenerProxy(listener, aLoadingPrincipal, withCredentials);
-      rv = corsproxy->Init(newChannel, true);
+      rv = corsproxy->Init(newChannel, DataURIHandling::Allow);
       if (NS_FAILED(rv)) {
         return false;
       }
 
       listener = corsproxy;
     }
 
     request->SetValidator(hvc);
@@ -2246,17 +2246,17 @@ imgLoader::LoadImage(nsIURI* aURI,
     if (corsmode != imgIRequest::CORS_NONE) {
       PR_LOG(GetImgLog(), PR_LOG_DEBUG,
              ("[this=%p] imgLoader::LoadImage -- Setting up a CORS load",
               this));
       bool withCredentials = corsmode == imgIRequest::CORS_USE_CREDENTIALS;
 
       nsRefPtr<nsCORSListenerProxy> corsproxy =
         new nsCORSListenerProxy(pl, aLoadingPrincipal, withCredentials);
-      rv = corsproxy->Init(newChannel, true);
+      rv = corsproxy->Init(newChannel, DataURIHandling::Allow);
       if (NS_FAILED(rv)) {
         PR_LOG(GetImgLog(), PR_LOG_DEBUG,
                ("[this=%p] imgLoader::LoadImage -- nsCORSListenerProxy "
                 "creation failed: 0x%x\n", this, rv));
         request->CancelAndAbort(rv);
         return NS_ERROR_FAILURE;
       }
 
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -506,17 +506,19 @@ FontFaceSet::StartLoad(gfxUserFontEntry*
                            nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
                            &inherits);
   if (NS_SUCCEEDED(rv) && inherits) {
     // allow data, javascript, etc URI's
     rv = channel->AsyncOpen(streamLoader, nullptr);
   } else {
     nsRefPtr<nsCORSListenerProxy> listener =
       new nsCORSListenerProxy(streamLoader, aUserFontEntry->GetPrincipal(), false);
-    rv = listener->Init(channel);
+    // Doesn't matter what data: URI handling we use here, since we
+    // don't even use a CORS listener proxy for the data: case.
+    rv = listener->Init(channel, DataURIHandling::Disallow);
     if (NS_SUCCEEDED(rv)) {
       rv = channel->AsyncOpen(listener, nullptr);
     }
     if (NS_FAILED(rv)) {
       fontLoader->DropChannel();  // explicitly need to break ref cycle
     }
   }
 
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1665,17 +1665,17 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
   nsCOMPtr<nsIStreamListener> channelListener;
   CORSMode ourCORSMode = aLoadData->mSheet->GetCORSMode();
   if (ourCORSMode != CORS_NONE) {
     bool withCredentials = (ourCORSMode == CORS_USE_CREDENTIALS);
     LOG(("  Doing CORS-enabled load; credentials %d", withCredentials));
     nsRefPtr<nsCORSListenerProxy> corsListener =
       new nsCORSListenerProxy(streamLoader, aLoadData->mLoaderPrincipal,
 			      withCredentials);
-    rv = corsListener->Init(channel, true);
+    rv = corsListener->Init(channel, DataURIHandling::Allow);
     if (NS_FAILED(rv)) {
 #ifdef DEBUG
       mSyncCallback = false;
 #endif
       LOG_ERROR(("  Initial CORS check failed"));
       SheetComplete(aLoadData, rv);
       return rv;
     }