Bug 1198078 - Add support for TYPE_INTERNAL_SERVICE_WORKER. r=ckerschb r=tanvi, a=al
authorEhsan Akhgari <ehsan@mozilla.com>
Fri, 11 Sep 2015 18:48:43 -0400
changeset 289303 567a6defb14bd2e80fd0fd7564c388dddb75a635
parent 289302 9896afee855e6850fb8d90ff97f1dea0c0be5080
child 289304 f5099905567566b2c530a7e7fef760a659dd96d9
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb, tanvi, al
bugs1198078
milestone42.0a2
Bug 1198078 - Add support for TYPE_INTERNAL_SERVICE_WORKER. r=ckerschb r=tanvi, a=al
dom/base/nsContentPolicy.cpp
dom/base/nsContentPolicyUtils.h
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsIContentPolicy.idl
dom/base/nsIContentPolicyBase.idl
dom/base/nsISimpleContentPolicy.idl
dom/cache/DBSchema.cpp
dom/fetch/InternalRequest.cpp
dom/security/nsMixedContentBlocker.cpp
dom/workers/ScriptLoader.cpp
dom/workers/WorkerPrivate.h
extensions/permissions/nsContentBlocker.cpp
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -18,16 +18,17 @@
 #include "nsIDocShell.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMWindow.h"
 #include "nsIContent.h"
 #include "nsILoadContext.h"
 #include "nsCOMArray.h"
 #include "nsContentUtils.h"
+#include "mozilla/dom/nsMixedContentBlocker.h"
 
 using mozilla::LogLevel;
 
 NS_IMPL_ISUPPORTS(nsContentPolicy, nsIContentPolicy)
 
 static PRLogModuleInfo* gConPolLog;
 
 nsresult
@@ -114,27 +115,41 @@ nsContentPolicy::CheckPolicy(CPMethod   
         if (doc) {
             requestingLocation = doc->GetDocumentURI();
         }
     }
 
     nsContentPolicyType externalType =
         nsContentUtils::InternalContentPolicyTypeToExternal(contentType);
 
+    nsContentPolicyType externalTypeOrScript =
+        nsContentUtils::InternalContentPolicyTypeToExternalOrScript(contentType);
+
+    nsCOMPtr<nsIContentPolicy> mixedContentBlocker =
+        do_GetService(NS_MIXEDCONTENTBLOCKER_CONTRACTID);
+
     /* 
      * Enumerate mPolicies and ask each of them, taking the logical AND of
      * their permissions.
      */
     nsresult rv;
     nsCOMArray<nsIContentPolicy> entries;
     mPolicies.GetEntries(entries);
     int32_t count = entries.Count();
     for (int32_t i = 0; i < count; i++) {
         /* check the appropriate policy */
-        rv = (entries[i]->*policyMethod)(externalType, contentLocation,
+        // Send the internal content policy type to the mixed content blocker
+        // which needs to know about TYPE_INTERNAL_WORKER,
+        // TYPE_INTERNAL_SHARED_WORKER and TYPE_INTERNAL_SERVICE_WORKER.
+        bool isMixedContentBlocker = mixedContentBlocker == entries[i];
+        nsContentPolicyType type = externalType;
+        if (isMixedContentBlocker) {
+            type = externalTypeOrScript;
+        }
+        rv = (entries[i]->*policyMethod)(type, contentLocation,
                                          requestingLocation, requestingContext,
                                          mimeType, extra, requestPrincipal,
                                          decision);
 
         if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
             /* policy says no, no point continuing to check */
             return NS_OK;
         }
--- a/dom/base/nsContentPolicyUtils.h
+++ b/dom/base/nsContentPolicyUtils.h
@@ -121,16 +121,17 @@ NS_CP_ContentTypeName(uint32_t contentTy
     CASE_RETURN( TYPE_INTERNAL_OBJECT         );
     CASE_RETURN( TYPE_INTERNAL_FRAME          );
     CASE_RETURN( TYPE_INTERNAL_IFRAME         );
     CASE_RETURN( TYPE_INTERNAL_AUDIO          );
     CASE_RETURN( TYPE_INTERNAL_VIDEO          );
     CASE_RETURN( TYPE_INTERNAL_TRACK          );
     CASE_RETURN( TYPE_INTERNAL_XMLHTTPREQUEST );
     CASE_RETURN( TYPE_INTERNAL_EVENTSOURCE    );
+    CASE_RETURN( TYPE_INTERNAL_SERVICE_WORKER );
    default:
     return "<Unknown Type>";
   }
 }
 
 #undef CASE_RETURN
 
 /* Passes on parameters from its "caller"'s context. */
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7903,16 +7903,17 @@ nsContentUtils::GetWindowRoot(nsIDocumen
 /* static */
 nsContentPolicyType
 nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType)
 {
   switch (aType) {
   case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
   case nsIContentPolicy::TYPE_INTERNAL_WORKER:
   case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
+  case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
     return nsIContentPolicy::TYPE_SCRIPT;
 
   case nsIContentPolicy::TYPE_INTERNAL_EMBED:
   case nsIContentPolicy::TYPE_INTERNAL_OBJECT:
     return nsIContentPolicy::TYPE_OBJECT;
 
   case nsIContentPolicy::TYPE_INTERNAL_FRAME:
   case nsIContentPolicy::TYPE_INTERNAL_IFRAME:
@@ -7927,16 +7928,32 @@ nsContentUtils::InternalContentPolicyTyp
   case nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE:
     return nsIContentPolicy::TYPE_XMLHTTPREQUEST;
 
   default:
     return aType;
   }
 }
 
+/* static */
+nsContentPolicyType
+nsContentUtils::InternalContentPolicyTypeToExternalOrScript(nsContentPolicyType aType)
+{
+  switch (aType) {
+  case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
+  case nsIContentPolicy::TYPE_INTERNAL_WORKER:
+  case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
+  case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
+    return aType;
+
+  default:
+    return InternalContentPolicyTypeToExternal(aType);
+  }
+}
+
 
 nsresult
 nsContentUtils::SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal,
                                               nsIDocument* aDoc,
                                               nsIHttpChannel* aChannel)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
   NS_ENSURE_ARG_POINTER(aChannel);
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -932,16 +932,28 @@ public:
   static nsIContentPolicy *GetContentPolicy();
 
   /**
    * Map internal content policy types to external ones.
    */
   static nsContentPolicyType InternalContentPolicyTypeToExternal(nsContentPolicyType aType);
 
   /**
+   * Map internal content policy types to external ones or script types:
+   *   * TYPE_INTERNAL_SCRIPT
+   *   * TYPE_INTERNAL_WORKER
+   *   * TYPE_INTERNAL_SHARED_WORKER
+   *   * TYPE_INTERNAL_SERVICE_WORKER
+   *
+   *
+   * Note: DO NOT call this function unless you know what you're doing!
+   */
+  static nsContentPolicyType InternalContentPolicyTypeToExternalOrScript(nsContentPolicyType aType);
+
+  /**
    * Quick helper to determine whether there are any mutation listeners
    * of a given type that apply to this content or any of its ancestors.
    * The method has the side effect to call document's MayDispatchMutationEvent
    * using aTargetForSubtreeModified as the parameter.
    *
    * @param aNode  The node to search for listeners
    * @param aType  The type of listener (NS_EVENT_BITS_MUTATION_*)
    * @param aTargetForSubtreeModified The node which is the target of the
--- a/dom/base/nsIContentPolicy.idl
+++ b/dom/base/nsIContentPolicy.idl
@@ -15,17 +15,17 @@ interface nsIPrincipal;
  * Interface for content policy mechanism.  Implementations of this
  * interface can be used to control loading of various types of out-of-line
  * content, or processing of certain types of in-line content.
  *
  * WARNING: do not block the caller from shouldLoad or shouldProcess (e.g.,
  * by launching a dialog to prompt the user for something).
  */
 
-[scriptable,uuid(3663021e-5670-496f-887b-b408d6526b5b)]
+[scriptable,uuid(ce321216-c404-40a7-a711-d80454ec6b76)]
 interface nsIContentPolicy : nsIContentPolicyBase
 {
   /**
    * Should the resource at this location be loaded?
    * ShouldLoad will be called before loading the resource at aContentLocation
    * to determine whether to start the load at all.
    *
    * @param aContentType      the type of content being tested. This will be one
--- a/dom/base/nsIContentPolicyBase.idl
+++ b/dom/base/nsIContentPolicyBase.idl
@@ -19,17 +19,17 @@ typedef unsigned long nsContentPolicyTyp
  * Interface for content policy mechanism.  Implementations of this
  * interface can be used to control loading of various types of out-of-line
  * content, or processing of certain types of in-line content.
  *
  * WARNING: do not block the caller from shouldLoad or shouldProcess (e.g.,
  * by launching a dialog to prompt the user for something).
  */
 
-[scriptable,uuid(20f7b9bf-d7d5-4987-ade8-b7dc0398d44a)]
+[scriptable,uuid(8527ae0d-0c43-4413-bc46-85c0bcb66876)]
 interface nsIContentPolicyBase : nsISupports
 {
   /**
    * Indicates a unset or bogus policy type.
    */
   const nsContentPolicyType TYPE_INVALID = 0;
 
   /**
@@ -266,16 +266,25 @@ interface nsIContentPolicyBase : nsISupp
 
   /**
    * Indicates an internal constant for EventSource.
    *
    * This will be mapped to TYPE_DATAREQUEST.
    */
   const nsContentPolicyType TYPE_INTERNAL_EVENTSOURCE = 34;
 
+  /**
+   * Indicates an internal constant for scripts loaded through a service
+   * worker.
+   *
+   * This will be mapped to TYPE_SCRIPT before being passed to content policy
+   * implementations.
+   */
+  const nsContentPolicyType TYPE_INTERNAL_SERVICE_WORKER = 35;
+
   /* When adding new content types, please update nsContentBlocker,
    * NS_CP_ContentTypeName, nsCSPContext, all nsIContentPolicy
    * implementations, the static_assert in dom/cache/DBSchema.cpp,
    * and other things that are not listed here that are related to
    * nsIContentPolicy. */
 
   //////////////////////////////////////////////////////////////////////
 
--- a/dom/base/nsISimpleContentPolicy.idl
+++ b/dom/base/nsISimpleContentPolicy.idl
@@ -23,17 +23,17 @@ interface nsIDOMElement;
  * to block loads without using cross-process wrappers (CPOWs). Add-ons should
  * prefer this interface to nsIContentPolicy because it should be faster in
  * e10s. In the future, it may also be run asynchronously.
  *
  * WARNING: do not block the caller from shouldLoad or shouldProcess (e.g.,
  * by launching a dialog to prompt the user for something).
  */
 
-[scriptable,uuid(b181c97c-9d67-4da1-95a0-e0a202e1807c)]
+[scriptable,uuid(b9df71e3-a9b3-4706-b2d5-e6c0d3d68ec7)]
 interface nsISimpleContentPolicy : nsIContentPolicyBase
 {
   /**
    * Should the resource at this location be loaded?
    * ShouldLoad will be called before loading the resource at aContentLocation
    * to determine whether to start the load at all.
    *
    * @param aContentType      the type of content being tested. This will be one
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -138,18 +138,19 @@ static_assert(nsIContentPolicy::TYPE_INV
               nsIContentPolicy::TYPE_INTERNAL_EMBED == 26 &&
               nsIContentPolicy::TYPE_INTERNAL_OBJECT == 27 &&
               nsIContentPolicy::TYPE_INTERNAL_FRAME == 28 &&
               nsIContentPolicy::TYPE_INTERNAL_IFRAME == 29 &&
               nsIContentPolicy::TYPE_INTERNAL_AUDIO == 30 &&
               nsIContentPolicy::TYPE_INTERNAL_VIDEO == 31 &&
               nsIContentPolicy::TYPE_INTERNAL_TRACK == 32 &&
               nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST == 33 &&
-              nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE == 34,
-              "nsContentPolicytType values are as expected");
+              nsIContentPolicy::TYPE_INTERNAL_EVENTSOURCE == 34 &&
+              nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER == 35,
+              "nsContentPolicyType values are as expected");
 
 namespace {
 
 typedef int32_t EntryId;
 
 struct IdCount
 {
   IdCount() : mId(-1), mCount(0) { }
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -109,16 +109,17 @@ RequestContext
 InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aContentPolicyType)
 {
   RequestContext context = RequestContext::Internal;
   switch (aContentPolicyType) {
   case nsIContentPolicy::TYPE_OTHER:
     context = RequestContext::Internal;
     break;
   case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
+  case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
     context = RequestContext::Script;
     break;
   case nsIContentPolicy::TYPE_INTERNAL_WORKER:
     context = RequestContext::Worker;
     break;
   case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
     context = RequestContext::Sharedworker;
     break;
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -286,17 +286,17 @@ nsMixedContentBlocker::AsyncOnChannelRed
     // 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();
+  nsContentPolicyType contentPolicyType = loadInfo->InternalContentPolicyType();
   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
@@ -305,17 +305,17 @@ nsMixedContentBlocker::AsyncOnChannelRed
       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(nsContentUtils::InternalContentPolicyTypeToExternal(contentPolicyType),
+  rv = ShouldLoad(nsContentUtils::InternalContentPolicyTypeToExternalOrScript(contentPolicyType),
                   newUri,
                   requestingLocation,
                   loadInfo->LoadingNode(),
                   EmptyCString(),       // aMimeGuess
                   nullptr,              // aExtra
                   requestingPrincipal,
                   &decision);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -373,19 +373,27 @@ nsMixedContentBlocker::ShouldLoad(bool a
                                   nsIPrincipal* aRequestPrincipal,
                                   int16_t* aDecision)
 {
   // Asserting that we are on the main thread here and hence do not have to lock
   // and unlock sBlockMixedScript and sBlockMixedDisplay before reading/writing
   // to them.
   MOZ_ASSERT(NS_IsMainThread());
 
-  MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
+  MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternalOrScript(aContentType),
              "We should only see external content policy types here.");
 
+  // The content policy type that we receive may be an internal type for
+  // scripts.  Let's remember if we have seen a worker type, and reset it to the
+  // external type in all cases right now.
+  bool isWorkerType = aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
+                      aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
+                      aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER;
+  aContentType = nsContentUtils::InternalContentPolicyTypeToExternal(aContentType);
+
   // Assume active (high risk) content and blocked by default
   MixedContentTypes classification = eMixedScript;
   // Make decision to block/reject by default
   *aDecision = REJECT_REQUEST;
 
   // Notes on non-obvious decisions:
   //
   // TYPE_DTD: A DTD can contain entity definitions that expand to scripts.
@@ -620,16 +628,33 @@ nsMixedContentBlocker::ShouldLoad(bool a
     *aDecision = REJECT_REQUEST;
     return NS_OK;
   }
   if (!parentIsHttps) {
     *aDecision = ACCEPT;
     return NS_OK;
   }
 
+  // Disallow mixed content loads for workers, shared workers and service
+  // workers.
+  if (isWorkerType) {
+    // For workers, we can assume that we're mixed content at this point, since
+    // the parent is https, and the protocol associated with aContentLocation
+    // doesn't map to the secure URI flags checked above.  Assert this for
+    // sanity's sake
+#ifdef DEBUG
+    bool isHttpsScheme = false;
+    rv = aContentLocation->SchemeIs("https", &isHttpsScheme);
+    NS_ENSURE_SUCCESS(rv, rv);
+    MOZ_ASSERT(!isHttpsScheme);
+#endif
+    *aDecision = REJECT_REQUEST;
+    return NS_OK;
+  }
+
   // Determine if the rootDoc is https and if the user decided to allow Mixed Content
   nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(aRequestingContext);
   NS_ENSURE_TRUE(docShell, NS_OK);
 
   // The page might have set the CSP directive 'upgrade-insecure-requests'. In such
   // a case allow the http: load to succeed with the promise that the channel will
   // get upgraded to https before fetching any data from the netwerk.
   // Please see: nsHttpChannel::Connect()
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -115,31 +115,28 @@ ChannelFromScriptURL(nsIPrincipal* princ
   nsCOMPtr<nsIURI> uri;
   rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
                                                  aScriptURL, parentDoc,
                                                  baseURI);
   if (NS_FAILED(rv)) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
-  // If we're part of a document then check the content load policy.
-  if (parentDoc) {
-    int16_t shouldLoad = nsIContentPolicy::ACCEPT;
-    rv = NS_CheckContentLoadPolicy(aContentPolicyType, uri,
-                                   principal, parentDoc,
-                                   NS_LITERAL_CSTRING("text/javascript"),
-                                   nullptr, &shouldLoad,
-                                   nsContentUtils::GetContentPolicy(),
-                                   secMan);
-    if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
-      if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
-        return rv = NS_ERROR_CONTENT_BLOCKED;
-      }
-      return rv = NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
+  int16_t shouldLoad = nsIContentPolicy::ACCEPT;
+  rv = NS_CheckContentLoadPolicy(aContentPolicyType, uri,
+                                 principal, parentDoc,
+                                 NS_LITERAL_CSTRING("text/javascript"),
+                                 nullptr, &shouldLoad,
+                                 nsContentUtils::GetContentPolicy(),
+                                 secMan);
+  if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
+    if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
+      return rv = NS_ERROR_CONTENT_BLOCKED;
     }
+    return rv = NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
   }
 
   if (aWorkerScriptType == DebuggerScript) {
     bool isChrome = false;
     NS_ENSURE_SUCCESS(uri->SchemeIs("chrome", &isChrome),
                       NS_ERROR_DOM_SECURITY_ERR);
 
     bool isResource = false;
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -745,17 +745,17 @@ public:
   ContentPolicyType(WorkerType aWorkerType)
   {
     switch (aWorkerType) {
     case WorkerTypeDedicated:
       return nsIContentPolicy::TYPE_INTERNAL_WORKER;
     case WorkerTypeShared:
       return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;
     case WorkerTypeService:
-      return nsIContentPolicy::TYPE_SCRIPT;
+      return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER;
     default:
       MOZ_ASSERT_UNREACHABLE("Invalid worker type");
       return nsIContentPolicy::TYPE_INVALID;
     }
   }
 
   const nsCString&
   SharedWorkerName() const
--- a/extensions/permissions/nsContentBlocker.cpp
+++ b/extensions/permissions/nsContentBlocker.cpp
@@ -52,17 +52,18 @@ static const char *kTypeString[] = {
                                     "", // TYPE_INTERNAL_EMBED
                                     "", // TYPE_INTERNAL_OBJECT
                                     "", // TYPE_INTERNAL_FRAME
                                     "", // TYPE_INTERNAL_IFRAME
                                     "", // TYPE_INTERNAL_AUDIO
                                     "", // TYPE_INTERNAL_VIDEO
                                     "", // TYPE_INTERNAL_TRACK
                                     "", // TYPE_INTERNAL_XMLHTTPREQUEST
-                                    ""  // TYPE_INTERNAL_EVENTSOURCE
+                                    "", // TYPE_INTERNAL_EVENTSOURCE
+                                    "", // TYPE_INTERNAL_SERVICE_WORKER
 };
 
 #define NUMBER_OF_TYPES MOZ_ARRAY_LENGTH(kTypeString)
 uint8_t nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES];
 
 NS_IMPL_ISUPPORTS(nsContentBlocker, 
                   nsIContentPolicy,
                   nsIObserver,