Bug 1195173 - Use channel->ascynOpen2 layout/style/Loader.cpp (r=bz)
authorChristoph Kerschbaumer <mozilla@christophkerschbaumer.com>
Tue, 02 Feb 2016 20:35:02 -0800
changeset 282817 86d0744f63c6e6b9e72c61b5d08574f74c450bc1
parent 282816 5665bf204fe39da168bf3c6d4a2795107b089f09
child 282818 a1a1dca9e27aa582bd68a170b066312fe2ffca77
push id29970
push usercbook@mozilla.com
push dateWed, 03 Feb 2016 10:59:33 +0000
treeherdermozilla-central@f2f8fc172f4c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1195173
milestone47.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 1195173 - Use channel->ascynOpen2 layout/style/Loader.cpp (r=bz)
dom/security/nsContentSecurityManager.cpp
layout/style/Loader.cpp
layout/style/Loader.h
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -138,18 +138,27 @@ DoContentSecurityChecks(nsIURI* aURI, ns
     }
 
     case nsIContentPolicy::TYPE_SCRIPT: {
       mimeTypeGuess = NS_LITERAL_CSTRING("application/javascript");
       requestingContext = aLoadInfo->LoadingNode();
       break;
     }
 
-    case nsIContentPolicy::TYPE_IMAGE:
-    case nsIContentPolicy::TYPE_STYLESHEET:
+    case nsIContentPolicy::TYPE_IMAGE: {
+      MOZ_ASSERT(false, "contentPolicyType not supported yet");
+      break;
+    }
+
+    case nsIContentPolicy::TYPE_STYLESHEET: {
+      mimeTypeGuess = NS_LITERAL_CSTRING("text/css");
+      requestingContext = aLoadInfo->LoadingNode();
+      break;
+    }
+
     case nsIContentPolicy::TYPE_OBJECT:
     case nsIContentPolicy::TYPE_DOCUMENT: {
       MOZ_ASSERT(false, "contentPolicyType not supported yet");
       break;
     }
 
     case nsIContentPolicy::TYPE_SUBDOCUMENT: {
       mimeTypeGuess = NS_LITERAL_CSTRING("text/html");
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -43,17 +43,16 @@
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsICSSLoaderObserver.h"
 #include "nsCSSParser.h"
 #include "mozilla/CSSStyleSheet.h"
 #include "mozilla/css/ImportRule.h"
 #include "nsThreadUtils.h"
 #include "nsGkAtoms.h"
 #include "nsIThreadInternal.h"
-#include "nsCORSListenerProxy.h"
 #include "nsINetworkPredictor.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/URL.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPrototypeCache.h"
 #endif
 
@@ -70,26 +69,24 @@ using mozilla::dom::EncodingUtils;
 using namespace mozilla::dom;
 
 /**
  * OVERALL ARCHITECTURE
  *
  * The CSS Loader gets requests to load various sorts of style sheets:
  * inline style from <style> elements, linked style, @import-ed child
  * sheets, non-document sheets.  The loader handles the following tasks:
- *
- * 1) Checking whether the load is allowed: CheckLoadAllowed()
- * 2) Creation of the actual style sheet objects: CreateSheet()
- * 3) setting of the right media, title, enabled state, etc on the
+ * 1) Creation of the actual style sheet objects: CreateSheet()
+ * 2) setting of the right media, title, enabled state, etc on the
  *    sheet: PrepareSheet()
- * 4) Insertion of the sheet in the proper cascade order:
+ * 3) Insertion of the sheet in the proper cascade order:
  *    InsertSheetInDoc() and InsertChildSheet()
- * 5) Load of the sheet: LoadSheet()
- * 6) Parsing of the sheet: ParseSheet()
- * 7) Cleanup: SheetComplete()
+ * 4) Load of the sheet: LoadSheet() including security checks
+ * 5) Parsing of the sheet: ParseSheet()
+ * 6) Cleanup: SheetComplete()
  *
  * The detailed documentation for these functions is found with the
  * function implementations.
  *
  * The following helper object is used:
  *    SheetLoadData -- a small class that is used to store all the
  *                     information needed for the loading of a sheet;
  *                     this class handles listening for the stream
@@ -1014,73 +1011,16 @@ Loader::ObsoleteSheet(nsIURI* aURI)
     if (NS_SUCCEEDED(rv) && areEqual) {
       iter.Remove();
     }
   }
   return NS_OK;
 }
 
 /**
- * CheckLoadAllowed will return success if the load is allowed,
- * failure otherwise.
- *
- * @param aSourcePrincipal the principal of the node or document or parent
- *                         sheet loading the sheet
- * @param aTargetURI the uri of the sheet to be loaded
- * @param aContext the node owning the sheet.  This is the element or document
- *                 owning the stylesheet (possibly indirectly, for child sheets)
- */
-nsresult
-Loader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
-                         nsIURI* aTargetURI,
-                         nsISupports* aContext,
-                         bool aIsPreload)
-{
-  LOG(("css::Loader::CheckLoadAllowed"));
-
-  nsresult rv;
-
-  if (aSourcePrincipal) {
-    // Check with the security manager
-    nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
-    rv =
-      secMan->CheckLoadURIWithPrincipal(aSourcePrincipal, aTargetURI,
-                                        nsIScriptSecurityManager::ALLOW_CHROME);
-    if (NS_FAILED(rv)) { // failure is normal here; don't warn
-      return rv;
-    }
-
-    LOG(("  Passed security check"));
-
-    // Check with content policy
-    nsContentPolicyType contentPolicyType =
-      aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
-                 : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
-
-    int16_t shouldLoad = nsIContentPolicy::ACCEPT;
-    rv = NS_CheckContentLoadPolicy(contentPolicyType,
-                                   aTargetURI,
-                                   aSourcePrincipal,
-                                   aContext,
-                                   NS_LITERAL_CSTRING("text/css"),
-                                   nullptr,                     //extra param
-                                   &shouldLoad,
-                                   nsContentUtils::GetContentPolicy(),
-                                   nsContentUtils::GetSecurityManager());
-
-    if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
-      LOG(("  Load blocked by content policy"));
-      return NS_ERROR_CONTENT_BLOCKED;
-    }
-  }
-
-  return NS_OK;
-}
-
-/**
  * CreateSheet() creates a CSSStyleSheet object for the given URI,
  * if any.  If there is no URI given, we just create a new style sheet
  * object.  Otherwise, we check for an existing style sheet object for
  * that uri in various caches and clone it if we find it.  Cloned
  * sheets will have the title/media/enabled state of the sheet they
  * are clones off; make sure to call PrepareSheet() on the result of
  * CreateSheet().
  */
@@ -1441,29 +1381,18 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
 
   if (!mDocument && !aLoadData->mIsNonDocumentSheet) {
     // No point starting the load; just release all the data and such.
     LOG_WARN(("  No document and not non-document sheet; pre-dropping load"));
     SheetComplete(aLoadData, NS_BINDING_ABORTED);
     return NS_BINDING_ABORTED;
   }
 
-  bool inherit = false;
   nsIPrincipal* triggeringPrincipal = aLoadData->mLoaderPrincipal;
-  if (triggeringPrincipal) {
-    rv = NS_URIChainHasFlags(aLoadData->mURI,
-                             nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
-                             &inherit);
-    inherit =
-      ((NS_SUCCEEDED(rv) && inherit) ||
-       (nsContentUtils::URIIsLocalFile(aLoadData->mURI) &&
-        NS_SUCCEEDED(aLoadData->mLoaderPrincipal->
-                     CheckMayLoad(aLoadData->mURI, false, false))));
-  }
-  else {
+  if (!triggeringPrincipal) {
     triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
   }
 
   SRIMetadata sriMetadata = aLoadData->mSheet->GetIntegrity();
 
   if (aLoadData->mSyncLoad) {
     LOG(("  Synchronous load"));
     NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync load?");
@@ -1482,47 +1411,59 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
     }
 
     if (mDocument) {
       mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
                                    nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
                                    mDocument);
     }
 
+    nsSecurityFlags securityFlags =
+      nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
+      nsILoadInfo::SEC_ALLOW_CHROME;
+
+    nsContentPolicyType contentPolicyType =
+      aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
+                 : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
+
     // Just load it
     nsCOMPtr<nsIChannel> channel;
     // Note that we are calling NS_NewChannelWithTriggeringPrincipal() with both
     // a node and a principal.
     // This is because of a case where the node is the document being styled and
     // the principal is the stylesheet (perhaps from a different origin) that is
     // applying the styles.
     if (aLoadData->mRequestingNode) {
       rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
                                                 aLoadData->mURI,
                                                 aLoadData->mRequestingNode,
                                                 triggeringPrincipal,
-                                                nsILoadInfo::SEC_NORMAL,
-                                                nsIContentPolicy::TYPE_OTHER);
+                                                securityFlags,
+                                                contentPolicyType);
     }
     else {
       // either we are loading something inside a document, in which case
       // we should always have a requestingNode, or we are loading something
       // outside a document, in which case the triggeringPrincipal
       // should always be the systemPrincipal.
       MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(triggeringPrincipal));
       rv = NS_NewChannel(getter_AddRefs(channel),
                          aLoadData->mURI,
                          triggeringPrincipal,
-                         nsILoadInfo::SEC_NORMAL,
-                         nsIContentPolicy::TYPE_OTHER);
+                         securityFlags,
+                         contentPolicyType);
     }
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_FAILED(rv)) {
+      LOG_ERROR(("  Failed to create channel"));
+      SheetComplete(aLoadData, rv);
+      return rv;
+    }
 
     nsCOMPtr<nsIInputStream> stream;
-    rv = channel->Open(getter_AddRefs(stream));
+    rv = channel->Open2(getter_AddRefs(stream));
 
     if (NS_FAILED(rv)) {
       LOG_ERROR(("  Failed to open URI synchronously"));
       SheetComplete(aLoadData, rv);
       return rv;
     }
 
     // Force UA sheets to be UTF-8.
@@ -1576,30 +1517,42 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
       LOG(("  Forcing load of pending data"));
       return LoadSheet(existingData, eSheetNeedsParser, aIsPreload);
     }
     // All done here; once the load completes we'll be marked complete
     // automatically
     return NS_OK;
   }
 
-#ifdef DEBUG
-  mSyncCallback = true;
-#endif
   nsCOMPtr<nsILoadGroup> loadGroup;
   if (mDocument) {
     loadGroup = mDocument->GetDocumentLoadGroup();
-    NS_ASSERTION(loadGroup,
-                 "No loadgroup for stylesheet; onload will fire early");
+    // load for a document with no loadgrup indicates that something is
+    // completely bogus, let's bail out early.
+    if (!loadGroup) {
+      LOG_ERROR(("  Failed to query loadGroup from document"));
+      SheetComplete(aLoadData, NS_ERROR_UNEXPECTED);
+      return NS_ERROR_UNEXPECTED;
+    }
   }
+#ifdef DEBUG
+  mSyncCallback = true;
+#endif
 
-  nsLoadFlags securityFlags = nsILoadInfo::SEC_NORMAL;
-  if (inherit) {
-    securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
+  CORSMode ourCORSMode = aLoadData->mSheet->GetCORSMode();
+  nsSecurityFlags securityFlags =
+    ourCORSMode == CORS_NONE
+      ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS
+      : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
+  if (ourCORSMode == CORS_ANONYMOUS) {
+    securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
+  } else if (ourCORSMode == CORS_USE_CREDENTIALS) {
+    securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
   }
+  securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
 
   nsContentPolicyType contentPolicyType =
     aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
                : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
 
   nsCOMPtr<nsIChannel> channel;
   // Note we are calling NS_NewChannelWithTriggeringPrincipal here with a node
   // and a principal. This is because of a case where the node is the document
@@ -1685,45 +1638,23 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
 #ifdef DEBUG
     mSyncCallback = false;
 #endif
     LOG_ERROR(("  Failed to create stream loader"));
     SheetComplete(aLoadData, rv);
     return rv;
   }
 
-  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));
-    RefPtr<nsCORSListenerProxy> corsListener =
-      new nsCORSListenerProxy(streamLoader, aLoadData->mLoaderPrincipal,
-			      withCredentials);
-    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;
-    }
-    channelListener = corsListener;
-  } else {
-    channelListener = streamLoader;
-  }
-
   if (mDocument) {
     mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
                                  nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
                                  mDocument);
   }
 
-  rv = channel->AsyncOpen(channelListener, nullptr);
+  rv = channel->AsyncOpen2(streamLoader);
 
 #ifdef DEBUG
   mSyncCallback = false;
 #endif
 
   if (NS_FAILED(rv)) {
     LOG_ERROR(("  Failed to create stream loader"));
     SheetComplete(aLoadData, rv);
@@ -2056,27 +1987,23 @@ Loader::LoadStyleLink(nsIContent* aEleme
 
   nsIPrincipal* principal =
     aElement ? aElement->NodePrincipal() : mDocument->NodePrincipal();
 
   nsISupports* context = aElement;
   if (!context) {
     context = mDocument;
   }
-  nsresult rv = CheckLoadAllowed(principal, aURL, context, false);
-  if (NS_FAILED(rv)) return rv;
-
-  LOG(("  Passed load check"));
 
   StyleSheetState state;
   RefPtr<CSSStyleSheet> sheet;
-  rv = CreateSheet(aURL, aElement, principal, aCORSMode,
-                   aReferrerPolicy, aIntegrity, false,
-                   aHasAlternateRel, aTitle, state, aIsAlternate,
-                   getter_AddRefs(sheet));
+  nsresult rv = CreateSheet(aURL, aElement, principal, aCORSMode,
+                            aReferrerPolicy, aIntegrity, false,
+                            aHasAlternateRel, aTitle, state, aIsAlternate,
+                            getter_AddRefs(sheet));
   NS_ENSURE_SUCCESS(rv, rv);
 
   LOG(("  Sheet is alternate: %d", *aIsAlternate));
 
   PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate);
 
   rv = InsertSheetInDoc(sheet, aElement, mDocument);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2190,22 +2117,16 @@ Loader::LoadChildSheet(CSSStyleSheet* aP
     topSheet->GetOwnerNode(getter_AddRefs(owningNode));
   }
 
   nsISupports* context = owningNode;
   if (!context) {
     context = mDocument;
   }
 
-  nsIPrincipal* principal = aParentSheet->Principal();
-  nsresult rv = CheckLoadAllowed(principal, aURL, context, false);
-  if (NS_FAILED(rv)) return rv;
-
-  LOG(("  Passed load check"));
-
   SheetLoadData* parentData = nullptr;
   nsCOMPtr<nsICSSLoaderObserver> observer;
 
   int32_t count = mParsingDatas.Length();
   if (count > 0) {
     LOG(("  Have a parent load"));
     parentData = mParsingDatas.ElementAt(count - 1);
     // Check for cycles
@@ -2222,17 +2143,19 @@ Loader::LoadChildSheet(CSSStyleSheet* aP
     LOG(("  No parent load; must be CSSOM"));
     // No parent load data, so the sheet will need to be notified when
     // we finish, if it can be, if we do the load asynchronously.
     observer = aParentSheet;
   }
 
   // Now that we know it's safe to load this (passes security check and not a
   // loop) do so.
+  nsIPrincipal* principal = aParentSheet->Principal();
   RefPtr<CSSStyleSheet> sheet;
+  nsresult rv;
   StyleSheetState state;
   if (aReusableSheets && aReusableSheets->FindReusableStyleSheet(aURL, sheet)) {
     aParentRule->SetSheet(sheet);
     state = eSheetComplete;
   } else {
     bool isAlternate;
     const nsSubstring& empty = EmptyString();
     // For now, use CORS_NONE for child sheets
@@ -2346,26 +2269,22 @@ Loader::InternalLoadNonDocumentSheet(nsI
     *aSheet = nullptr;
   }
 
   if (!mEnabled) {
     LOG_WARN(("  Not enabled"));
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  nsresult rv = CheckLoadAllowed(aOriginPrincipal, aURL, mDocument, aIsPreload);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
   StyleSheetState state;
   bool isAlternate;
   RefPtr<CSSStyleSheet> sheet;
   bool syncLoad = (aObserver == nullptr);
   const nsSubstring& empty = EmptyString();
+  nsresult rv;
 
   rv = CreateSheet(aURL, nullptr, aOriginPrincipal, aCORSMode,
                    aReferrerPolicy, aIntegrity, syncLoad, false,
                    empty, state, &isAlternate, getter_AddRefs(sheet));
   NS_ENSURE_SUCCESS(rv, rv);
 
   PrepareSheet(sheet, empty, empty, nullptr, nullptr, isAlternate);
 
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -436,26 +436,16 @@ public:
 
   // Marks all the sheets at the given URI obsolete, and removes them from the
   // cache.
   nsresult ObsoleteSheet(nsIURI* aURI);
 
 private:
   friend class SheetLoadData;
 
-  // Note: null aSourcePrincipal indicates that the content policy and
-  // CheckLoadURI checks should be skipped.
-  // aIsPreload indicates whether the html parser preloads that
-  // stylesheet or if it is a regular load.
-  nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
-                            nsIURI* aTargetURI,
-                            nsISupports* aContext,
-                            bool aIsPreload);
-
-
   // For inline style, the aURI param is null, but the aLinkingContent
   // must be non-null then.  The loader principal must never be null
   // if aURI is not null.
   // *aIsAlternate is set based on aTitle and aHasAlternateRel.
   nsresult CreateSheet(nsIURI* aURI,
                        nsIContent* aLinkingContent,
                        nsIPrincipal* aLoaderPrincipal,
                        CORSMode aCORSMode,