Bug 1169044 - Patch 3 - Store and set principal with script URI on ServiceWorkers. r=ehsan
authorNikhil Marathe <nsm.nikhil@gmail.com>
Thu, 04 Jun 2015 21:39:34 -0700
changeset 281023 66ea7374c23d9e22d4eb9cc11f9631530f485d59
parent 281022 67b6e55eb4acb234e5d847be5b0d80110dee6862
child 281024 7000726b44f88af4e75357079d849df0f98efd95
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1169044
milestone41.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 1169044 - Patch 3 - Store and set principal with script URI on ServiceWorkers. r=ehsan The ServiceWorkerRegistrationInfo's principal is the principal of the document that called register(). If we create WorkerPrivate instances based off of this, they have a valid principal in terms of security and same-origin-ness, but the URI path is wrong. When fetching the script from the network, the channel's principal is used to update the worker principal. We need to do the same when the script is loaded from Cache. This patch adds support to store the channel principal in the cache.
caps/BasePrincipal.cpp
caps/BasePrincipal.h
dom/cache/CacheTypes.ipdlh
dom/cache/DBSchema.cpp
dom/cache/TypeUtils.cpp
dom/fetch/FetchDriver.cpp
dom/fetch/InternalResponse.cpp
dom/fetch/InternalResponse.h
dom/fetch/Response.h
dom/workers/ScriptLoader.cpp
dom/workers/ServiceWorkerScriptCache.cpp
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -110,16 +110,33 @@ OriginAttributes::PopulateFromSuffix(con
 
   UniquePtr<URLParams> params(new URLParams());
   params->ParseInput(Substring(aStr, 1, aStr.Length() - 1));
 
   PopulateFromSuffixIterator iterator(this);
   return params->ForEach(iterator);
 }
 
+bool
+OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin,
+                                     nsACString& aOriginNoSuffix)
+{
+  // RFindChar is only available on nsCString.
+  nsCString origin(aOrigin);
+  int32_t pos = origin.RFindChar('!');
+
+  if (pos == kNotFound) {
+    aOriginNoSuffix = origin;
+    return true;
+  }
+
+  aOriginNoSuffix = Substring(origin, 0, pos);
+  return PopulateFromSuffix(Substring(origin, pos));
+}
+
 void
 OriginAttributes::CookieJar(nsACString& aStr)
 {
   mozilla::GetJarPrefix(mAppId, mInBrowser, aStr);
 }
 
 BasePrincipal::BasePrincipal()
 {}
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -43,16 +43,21 @@ public:
 
   // Serializes/Deserializes non-default values into the suffix format, i.e.
   // |!key1=value1&key2=value2|. If there are no non-default attributes, this
   // returns an empty string.
   void CreateSuffix(nsACString& aStr) const;
   bool PopulateFromSuffix(const nsACString& aStr);
 
   void CookieJar(nsACString& aStr);
+
+  // Populates the attributes from a string like
+  // |uri!key1=value1&key2=value2| and returns the uri without the suffix.
+  bool PopulateFromOrigin(const nsACString& aOrigin,
+                          nsACString& aOriginNoSuffix);
 };
 
 /*
  * Base class from which all nsIPrincipal implementations inherit. Use this for
  * default implementations and other commonalities between principal
  * implementations.
  *
  * We should merge nsJSPrincipals into this class at some point.
--- a/dom/cache/CacheTypes.ipdlh
+++ b/dom/cache/CacheTypes.ipdlh
@@ -2,16 +2,17 @@
  * 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/. */
 
 include protocol PCache;
 include protocol PCachePushStream;
 include protocol PCacheStreamControl;
 include InputStreamParams;
 include ChannelInfo;
+include PBackgroundSharedTypes;
 
 using HeadersGuardEnum from "mozilla/dom/cache/IPCUtils.h";
 using RequestCredentials from "mozilla/dom/cache/IPCUtils.h";
 using RequestMode from "mozilla/dom/cache/IPCUtils.h";
 using RequestCache from "mozilla/dom/cache/IPCUtils.h";
 using ResponseType from "mozilla/dom/cache/IPCUtils.h";
 using mozilla::void_t from "ipc/IPCMessageUtils.h";
 using struct nsID from "nsID.h";
@@ -76,16 +77,17 @@ struct CacheResponse
   ResponseType type;
   nsCString url;
   uint32_t status;
   nsCString statusText;
   HeadersEntry[] headers;
   HeadersGuardEnum headersGuard;
   CacheReadStreamOrVoid body;
   IPCChannelInfo channelInfo;
+  OptionalPrincipalInfo principalInfo;
 };
 
 union CacheResponseOrVoid
 {
   void_t;
   CacheResponse;
 };
 
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/dom/cache/TypeUtils.h"
 #include "mozIStorageConnection.h"
 #include "mozIStorageStatement.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsCRT.h"
 #include "nsHttp.h"
 #include "nsICryptoHash.h"
+#include "mozilla/BasePrincipal.h"
 #include "mozilla/dom/HeadersBinding.h"
 #include "mozilla/dom/RequestBinding.h"
 #include "mozilla/dom/ResponseBinding.h"
 #include "nsIContentPolicy.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
@@ -277,16 +278,17 @@ CreateSchema(mozIStorageConnection* aCon
         "request_body_id TEXT NULL, "
         "response_type INTEGER NOT NULL, "
         "response_url TEXT NOT NULL, "
         "response_status INTEGER NOT NULL, "
         "response_status_text TEXT NOT NULL, "
         "response_headers_guard INTEGER NOT NULL, "
         "response_body_id TEXT NULL, "
         "response_security_info_id INTEGER NULL REFERENCES security_info(id), "
+        "response_principal_info TEXT NOT NULL, "
         "response_redirected INTEGER NOT NULL, "
         // Note that response_redirected_url is either going to be empty, or
         // it's going to be a URL different than response_url.
         "response_redirected_url TEXT NOT NULL, "
         "cache_id INTEGER NOT NULL REFERENCES caches(id) ON DELETE CASCADE"
       ");"
     ));
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -1472,16 +1474,17 @@ InsertEntry(mozIStorageConnection* aConn
       "request_body_id, "
       "response_type, "
       "response_url, "
       "response_status, "
       "response_status_text, "
       "response_headers_guard, "
       "response_body_id, "
       "response_security_info_id, "
+      "response_principal_info, "
       "response_redirected, "
       "response_redirected_url, "
       "cache_id "
     ") VALUES ("
       ":request_method, "
       ":request_url_no_query, "
       ":request_url_no_query_hash, "
       ":request_url_query, "
@@ -1495,16 +1498,17 @@ InsertEntry(mozIStorageConnection* aConn
       ":request_body_id, "
       ":response_type, "
       ":response_url, "
       ":response_status, "
       ":response_status_text, "
       ":response_headers_guard, "
       ":response_body_id, "
       ":response_security_info_id, "
+      ":response_principal_info, "
       ":response_redirected, "
       ":response_redirected_url, "
       ":cache_id "
     ");"
   ), getter_AddRefs(state));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("request_method"),
@@ -1588,16 +1592,38 @@ InsertEntry(mozIStorageConnection* aConn
   if (aResponse.channelInfo().securityInfo().IsEmpty()) {
     rv = state->BindNullByName(NS_LITERAL_CSTRING("response_security_info_id"));
   } else {
     rv = state->BindInt32ByName(NS_LITERAL_CSTRING("response_security_info_id"),
                                 securityId);
   }
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
+  nsAutoCString serializedInfo;
+  // We only allow content serviceworkers right now.
+  if (aResponse.principalInfo().type() == mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) {
+    const mozilla::ipc::PrincipalInfo& principalInfo =
+      aResponse.principalInfo().get_PrincipalInfo();
+    MOZ_ASSERT(principalInfo.type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
+    const mozilla::ipc::ContentPrincipalInfo& cInfo =
+      principalInfo.get_ContentPrincipalInfo();
+
+    serializedInfo.Append(cInfo.spec());
+
+    MOZ_ASSERT(cInfo.appId() != nsIScriptSecurityManager::UNKNOWN_APP_ID);
+    OriginAttributes attrs(cInfo.appId(), cInfo.isInBrowserElement());
+    nsAutoCString suffix;
+    attrs.CreateSuffix(suffix);
+    serializedInfo.Append(suffix);
+  }
+
+  rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("response_principal_info"),
+                                   serializedInfo);
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
   rv = state->BindInt32ByName(NS_LITERAL_CSTRING("response_redirected"),
                               aResponse.channelInfo().redirected() ? 1 : 0);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("response_redirected_url"),
                                    aResponse.channelInfo().redirectedURI());
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
@@ -1687,16 +1713,17 @@ ReadResponse(mozIStorageConnection* aCon
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT "
       "entries.response_type, "
       "entries.response_url, "
       "entries.response_status, "
       "entries.response_status_text, "
       "entries.response_headers_guard, "
       "entries.response_body_id, "
+      "entries.response_principal_info, "
       "entries.response_redirected, "
       "entries.response_redirected_url, "
       "security_info.data "
     "FROM entries "
     "LEFT OUTER JOIN security_info "
     "ON entries.response_security_info_id=security_info.id "
     "WHERE entries.id=:id;"
   ), getter_AddRefs(state));
@@ -1736,25 +1763,42 @@ ReadResponse(mozIStorageConnection* aCon
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   aSavedResponseOut->mHasBodyId = !nullBody;
 
   if (aSavedResponseOut->mHasBodyId) {
     rv = ExtractId(state, 5, &aSavedResponseOut->mBodyId);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   }
 
+  nsAutoCString serializedInfo;
+  rv = state->GetUTF8String(6, serializedInfo);
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+  aSavedResponseOut->mValue.principalInfo() = void_t();
+  if (!serializedInfo.IsEmpty()) {
+    nsAutoCString originNoSuffix;
+    OriginAttributes attrs;
+    fprintf(stderr, "\n%s\n", serializedInfo.get());
+    if (!attrs.PopulateFromOrigin(serializedInfo, originNoSuffix)) {
+      NS_WARNING("Something went wrong parsing a serialized principal!");
+      return NS_ERROR_FAILURE;
+    }
+
+    aSavedResponseOut->mValue.principalInfo() =
+      mozilla::ipc::ContentPrincipalInfo(attrs.mAppId, attrs.mInBrowser, originNoSuffix);
+  }
+
   int32_t redirected;
-  rv = state->GetInt32(6, &redirected);
-  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+  rv = state->GetInt32(7, &redirected);
   aSavedResponseOut->mValue.channelInfo().redirected() = !!redirected;
 
-  rv = state->GetUTF8String(7, aSavedResponseOut->mValue.channelInfo().redirectedURI());
+  rv = state->GetUTF8String(8, aSavedResponseOut->mValue.channelInfo().redirectedURI());
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
-  rv = state->GetBlobAsUTF8String(8, aSavedResponseOut->mValue.channelInfo().securityInfo());
+  rv = state->GetBlobAsUTF8String(9, aSavedResponseOut->mValue.channelInfo().securityInfo());
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT "
       "name, "
       "value "
     "FROM response_headers "
     "WHERE entry_id=:entry_id;"
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -218,16 +218,21 @@ TypeUtils::ToCacheResponseWithoutBody(Ca
   MOZ_ASSERT(headers);
   if (HasVaryStar(headers)) {
     aRv.ThrowTypeError(MSG_RESPONSE_HAS_VARY_STAR);
     return;
   }
   ToHeadersEntryList(aOut.headers(), headers);
   aOut.headersGuard() = headers->Guard();
   aOut.channelInfo() = aIn.GetChannelInfo().AsIPCChannelInfo();
+  if (aIn.GetPrincipalInfo()) {
+    aOut.principalInfo() = *aIn.GetPrincipalInfo();
+  } else {
+    aOut.principalInfo() = void_t();
+  }
 }
 
 void
 TypeUtils::ToCacheResponse(CacheResponse& aOut, Response& aIn, ErrorResult& aRv)
 {
   if (aIn.BodyUsed()) {
     aRv.ThrowTypeError(MSG_FETCH_BODY_CONSUMED_ERROR);
     return;
@@ -284,16 +289,20 @@ TypeUtils::ToResponse(const CacheRespons
     ToInternalHeaders(aIn.headers(), aIn.headersGuard());
   ErrorResult result;
   ir->Headers()->SetGuard(aIn.headersGuard(), result);
   MOZ_ASSERT(!result.Failed());
   ir->Headers()->Fill(*internalHeaders, result);
   MOZ_ASSERT(!result.Failed());
 
   ir->InitChannelInfo(aIn.channelInfo());
+  if (aIn.principalInfo().type() == mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) {
+    UniquePtr<mozilla::ipc::PrincipalInfo> info(new mozilla::ipc::PrincipalInfo(aIn.principalInfo().get_PrincipalInfo()));
+    ir->SetPrincipalInfo(Move(info));
+  }
 
   nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
   ir->SetBody(stream);
 
   switch (aIn.type())
   {
     case ResponseType::Default:
       break;
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -428,28 +428,28 @@ FetchDriver::HttpFetch(bool aCORSFlag, b
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return FailWithNetworkError();
       }
     } else {
       // From "Determine request's Referrer" step 3
       // "If request's referrer is a URL, let referrerSource be request's
       // referrer."
       //
-      // This allows ServiceWorkers to function transparently when the referrer
-      // of the intercepted request is already set.
+      // XXXnsm - We never actually hit this from a fetch() call since both
+      // fetch and Request() create a new internal request whose referrer is
+      // always set to about:client. Should we just crash here instead until
+      // someone tries to use FetchDriver for non-fetch() APIs?
       nsCOMPtr<nsIURI> referrerURI;
       rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return FailWithNetworkError();
       }
 
-      // FIXME(nsm): Can we assert that this case can only happen in
-      // ServiceWorkers and assume null mDocument?
       rv =
-        httpChan->SetReferrerWithPolicy(nullptr,
+        httpChan->SetReferrerWithPolicy(referrerURI,
                                         mDocument ? mDocument->GetReferrerPolicy() :
                                                     net::RP_Default);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return FailWithNetworkError();
       }
     }
 
     // Step 3 "If HTTPRequest's force Origin header flag is set..."
--- a/dom/fetch/InternalResponse.cpp
+++ b/dom/fetch/InternalResponse.cpp
@@ -2,29 +2,35 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "InternalResponse.h"
 
 #include "mozilla/dom/InternalHeaders.h"
+#include "mozilla/dom/cache/CacheTypes.h"
+#include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "nsStreamUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText)
   : mType(ResponseType::Default)
   , mStatus(aStatus)
   , mStatusText(aStatusText)
   , mHeaders(new InternalHeaders(HeadersGuardEnum::Response))
 {
 }
 
+InternalResponse::~InternalResponse()
+{
+}
+
 already_AddRefed<InternalResponse>
 InternalResponse::Clone()
 {
   nsRefPtr<InternalResponse> clone = CreateIncompleteCopy();
 
   clone->mHeaders = new InternalHeaders(*mHeaders);
   if (mWrappedResponse) {
     clone->mWrappedResponse = mWrappedResponse->Clone();
@@ -68,10 +74,46 @@ InternalResponse::CORSResponse()
   MOZ_ASSERT(!mWrappedResponse, "Can't CORSResponse a already wrapped response");
   nsRefPtr<InternalResponse> cors = CreateIncompleteCopy();
   cors->mType = ResponseType::Cors;
   cors->mHeaders = InternalHeaders::CORSHeaders(Headers());
   cors->mWrappedResponse = this;
   return cors.forget();
 }
 
+void
+InternalResponse::SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo)
+{
+  mPrincipalInfo = Move(aPrincipalInfo);
+}
+
+already_AddRefed<InternalResponse>
+InternalResponse::OpaqueResponse()
+{
+  MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueResponse a already wrapped response");
+  nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
+  response->mType = ResponseType::Opaque;
+  response->mTerminationReason = mTerminationReason;
+  response->mURL = mURL;
+  response->mChannelInfo = mChannelInfo;
+  if (mPrincipalInfo) {
+    response->mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo);
+  }
+  response->mWrappedResponse = this;
+  return response.forget();
+}
+
+already_AddRefed<InternalResponse>
+InternalResponse::CreateIncompleteCopy()
+{
+  nsRefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText);
+  copy->mType = mType;
+  copy->mTerminationReason = mTerminationReason;
+  copy->mURL = mURL;
+  copy->mChannelInfo = mChannelInfo;
+  if (mPrincipalInfo) {
+    copy->mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo);
+  }
+  return copy.forget();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/InternalResponse.h
+++ b/dom/fetch/InternalResponse.h
@@ -7,18 +7,23 @@
 #ifndef mozilla_dom_InternalResponse_h
 #define mozilla_dom_InternalResponse_h
 
 #include "nsIInputStream.h"
 #include "nsISupportsImpl.h"
 
 #include "mozilla/dom/ResponseBinding.h"
 #include "mozilla/dom/ChannelInfo.h"
+#include "mozilla/UniquePtr.h"
 
 namespace mozilla {
+namespace ipc {
+class PrincipalInfo;
+}
+
 namespace dom {
 
 class InternalHeaders;
 
 class InternalResponse final
 {
   friend class FetchDriver;
 
@@ -36,27 +41,17 @@ public:
     ErrorResult result;
     response->Headers()->SetGuard(HeadersGuardEnum::Immutable, result);
     MOZ_ASSERT(!result.Failed());
     response->mType = ResponseType::Error;
     return response.forget();
   }
 
   already_AddRefed<InternalResponse>
-  OpaqueResponse()
-  {
-    MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueResponse a already wrapped response");
-    nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
-    response->mType = ResponseType::Opaque;
-    response->mTerminationReason = mTerminationReason;
-    response->mURL = mURL;
-    response->mChannelInfo = mChannelInfo;
-    response->mWrappedResponse = this;
-    return response.forget();
-  }
+  OpaqueResponse();
 
   already_AddRefed<InternalResponse>
   BasicResponse();
 
   already_AddRefed<InternalResponse>
   CORSResponse();
 
   ResponseType
@@ -169,44 +164,46 @@ public:
   }
 
   const ChannelInfo&
   GetChannelInfo() const
   {
     return mChannelInfo;
   }
 
+  const UniquePtr<mozilla::ipc::PrincipalInfo>&
+  GetPrincipalInfo() const
+  {
+    return mPrincipalInfo;
+  }
+
+  // Takes ownership of the principal info.
+  void
+  SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo);
+
 private:
-  ~InternalResponse()
-  { }
+  ~InternalResponse();
 
   explicit InternalResponse(const InternalResponse& aOther) = delete;
   InternalResponse& operator=(const InternalResponse&) = delete;
 
   // Returns an instance of InternalResponse which is a copy of this
   // InternalResponse, except headers, body and wrapped response (if any) which
   // are left uninitialized. Used for cloning and filtering.
-  already_AddRefed<InternalResponse> CreateIncompleteCopy()
-  {
-    nsRefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText);
-    copy->mType = mType;
-    copy->mTerminationReason = mTerminationReason;
-    copy->mURL = mURL;
-    copy->mChannelInfo = mChannelInfo;
-    return copy.forget();
-  }
+  already_AddRefed<InternalResponse> CreateIncompleteCopy();
 
   ResponseType mType;
   nsCString mTerminationReason;
   nsCString mURL;
   const uint16_t mStatus;
   const nsCString mStatusText;
   nsRefPtr<InternalHeaders> mHeaders;
   nsCOMPtr<nsIInputStream> mBody;
   ChannelInfo mChannelInfo;
+  UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
 
   // For filtered responses.
   // Cache, and SW interception should always serialize/access the underlying
   // unfiltered headers and when deserializing, create an InternalResponse
   // with the unfiltered headers followed by wrapping it.
   nsRefPtr<InternalResponse> mWrappedResponse;
 };
 
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -12,16 +12,20 @@
 
 #include "mozilla/dom/Fetch.h"
 #include "mozilla/dom/ResponseBinding.h"
 
 #include "InternalHeaders.h"
 #include "InternalResponse.h"
 
 namespace mozilla {
+namespace ipc {
+class PrincipalInfo;
+}
+
 namespace dom {
 
 class Headers;
 
 class Response final : public nsISupports
                      , public FetchBody<Response>
                      , public nsWrapperCache
 {
@@ -85,16 +89,22 @@ public:
   }
 
   const ChannelInfo&
   GetChannelInfo() const
   {
     return mInternalResponse->GetChannelInfo();
   }
 
+  const UniquePtr<mozilla::ipc::PrincipalInfo>&
+  GetPrincipalInfo() const
+  {
+    return mInternalResponse->GetPrincipalInfo();
+  }
+
   Headers* Headers_();
 
   void
   GetBody(nsIInputStream** aStream) { return mInternalResponse->GetBody(aStream); }
 
   static already_AddRefed<Response>
   Error(const GlobalObject& aGlobal);
 
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -33,16 +33,17 @@
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "xpcpublic.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/dom/CacheBinding.h"
+#include "mozilla/dom/cache/CacheTypes.h"
 #include "mozilla/dom/cache/Cache.h"
 #include "mozilla/dom/cache/CacheStorage.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/InternalResponse.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/Response.h"
 #include "Principal.h"
 #include "WorkerFeature.h"
@@ -417,16 +418,17 @@ private:
   ScriptLoadInfo& mLoadInfo;
   uint32_t mIndex;
   nsRefPtr<ScriptLoaderRunnable> mRunnable;
   bool mIsWorkerScript;
   bool mFailed;
   nsCOMPtr<nsIInputStreamPump> mPump;
   nsCOMPtr<nsIURI> mBaseURI;
   ChannelInfo mChannelInfo;
+  UniquePtr<PrincipalInfo> mPrincipalInfo;
 };
 
 NS_IMPL_ISUPPORTS(CacheScriptLoader, nsIStreamLoaderObserver)
 
 class CachePromiseHandler final : public PromiseNativeHandler
 {
 public:
   CachePromiseHandler(ScriptLoaderRunnable* aRunnable,
@@ -587,16 +589,37 @@ private:
     nsRefPtr<InternalResponse> ir =
       new InternalResponse(200, NS_LITERAL_CSTRING("OK"));
     ir->SetBody(mReader);
 
     // Set the channel info of the channel on the response so that it's
     // saved in the cache.
     ir->InitChannelInfo(channel);
 
+    // Save the principal of the channel since its URI encodes the script URI
+    // rather than the ServiceWorkerRegistrationInfo URI.
+    nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
+    NS_ASSERTION(ssm, "Should never be null!");
+
+    nsCOMPtr<nsIPrincipal> channelPrincipal;
+    nsresult rv = ssm->GetChannelResultPrincipal(channel, getter_AddRefs(channelPrincipal));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      channel->Cancel(rv);
+      return rv;
+    }
+
+    UniquePtr<PrincipalInfo> principalInfo(new PrincipalInfo());
+    rv = PrincipalToPrincipalInfo(channelPrincipal, principalInfo.get());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      channel->Cancel(rv);
+      return rv;
+    }
+
+    ir->SetPrincipalInfo(Move(principalInfo));
+
     nsRefPtr<Response> response = new Response(mCacheCreator->Global(), ir);
 
     RequestOrUSVString request;
 
     MOZ_ASSERT(!loadInfo.mFullURL.IsEmpty());
     request.SetAsUSVString().Rebind(loadInfo.mFullURL.Data(),
                                     loadInfo.mFullURL.Length());
 
@@ -1025,17 +1048,18 @@ private:
 
     DataReceived();
     return NS_OK;
   }
 
   void
   DataReceivedFromCache(uint32_t aIndex, const uint8_t* aString,
                         uint32_t aStringLen,
-                        const ChannelInfo& aChannelInfo)
+                        const ChannelInfo& aChannelInfo,
+                        UniquePtr<PrincipalInfo> aPrincipalInfo)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aIndex < mLoadInfos.Length());
     ScriptLoadInfo& loadInfo = mLoadInfos[aIndex];
     MOZ_ASSERT(loadInfo.mCacheStatus == ScriptLoadInfo::Cached);
 
     // May be null.
     nsIDocument* parentDoc = mWorkerPrivate->GetDocument();
@@ -1053,20 +1077,25 @@ private:
       if (NS_SUCCEEDED(rv)) {
         mWorkerPrivate->SetBaseURI(finalURI);
       }
 
       nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
       MOZ_ASSERT(principal);
       nsILoadGroup* loadGroup = mWorkerPrivate->GetLoadGroup();
       MOZ_ASSERT(loadGroup);
+
+      nsCOMPtr<nsIPrincipal> responsePrincipal =
+        PrincipalInfoToPrincipal(*aPrincipalInfo);
+      DebugOnly<bool> equal = false;
+      MOZ_ASSERT(responsePrincipal && NS_SUCCEEDED(responsePrincipal->Equals(principal, &equal)));
+      MOZ_ASSERT(equal);
+
       mWorkerPrivate->InitChannelInfo(aChannelInfo);
-      // Needed to initialize the principal info. This is fine because
-      // the cache principal cannot change, unlike the channel principal.
-      mWorkerPrivate->SetPrincipal(principal, loadGroup);
+      mWorkerPrivate->SetPrincipal(responsePrincipal, loadGroup);
     }
 
     if (NS_SUCCEEDED(rv)) {
       DataReceived();
     }
 
     LoadingFinished(aIndex, rv);
   }
@@ -1408,20 +1437,26 @@ CacheScriptLoader::ResolvedCallback(JSCo
   if (NS_WARN_IF(NS_FAILED(rv))) {
     Fail(rv);
     return;
   }
 
   nsCOMPtr<nsIInputStream> inputStream;
   response->GetBody(getter_AddRefs(inputStream));
   mChannelInfo = response->GetChannelInfo();
+  const UniquePtr<mozilla::ipc::PrincipalInfo>& pInfo =
+    response->GetPrincipalInfo();
+  if (pInfo) {
+    mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*pInfo);
+  }
 
   if (!inputStream) {
     mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached;
-    mRunnable->DataReceivedFromCache(mIndex, (uint8_t*)"", 0, mChannelInfo);
+    mRunnable->DataReceivedFromCache(mIndex, (uint8_t*)"", 0, mChannelInfo,
+                                     Move(mPrincipalInfo));
     return;
   }
 
   MOZ_ASSERT(!mPump);
   rv = NS_NewInputStreamPump(getter_AddRefs(mPump), inputStream);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     Fail(rv);
     return;
@@ -1467,17 +1502,19 @@ CacheScriptLoader::OnStreamComplete(nsIS
 
   if (NS_FAILED(aStatus)) {
     Fail(aStatus);
     return NS_OK;
   }
 
   mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached;
 
-  mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen, mChannelInfo);
+  MOZ_ASSERT(mPrincipalInfo);
+  mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen, mChannelInfo,
+                                   Move(mPrincipalInfo));
   return NS_OK;
 }
 
  class ChannelGetterRunnable final : public nsRunnable
 {
   WorkerPrivate* mParentWorker;
   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
   const nsAString& mScriptURL;
--- a/dom/workers/ServiceWorkerScriptCache.cpp
+++ b/dom/workers/ServiceWorkerScriptCache.cpp
@@ -4,16 +4,18 @@
  * 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/. */
 
 #include "ServiceWorkerScriptCache.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/CacheBinding.h"
 #include "mozilla/dom/cache/CacheStorage.h"
 #include "mozilla/dom/cache/Cache.h"
+#include "mozilla/ipc/BackgroundUtils.h"
+#include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "nsIThreadRetargetableRequest.h"
 
 #include "nsIPrincipal.h"
 #include "Workers.h"
 
 using mozilla::dom::cache::Cache;
 using mozilla::dom::cache::CacheStorage;
 
@@ -83,21 +85,27 @@ public:
     AssertIsOnMainThread();
 
     nsCOMPtr<nsIURI> uri;
     nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, nullptr);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
+    nsCOMPtr<nsILoadGroup> loadGroup;
+    rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), aPrincipal);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
     rv = NS_NewChannel(getter_AddRefs(mChannel),
                        uri, aPrincipal,
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_SCRIPT, // FIXME(nsm): TYPE_SERVICEWORKER
-                       aLoadGroup);
+                       loadGroup);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsLoadFlags flags;
     rv = mChannel->GetLoadFlags(&flags);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -446,16 +454,38 @@ public:
   }
 
   void
   InitChannelInfo(nsIChannel* aChannel)
   {
     mChannelInfo.InitFromChannel(aChannel);
   }
 
+  nsresult
+  SetPrincipalInfo(nsIChannel* aChannel)
+  {
+    nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
+    NS_ASSERTION(ssm, "Should never be null!");
+
+    nsCOMPtr<nsIPrincipal> channelPrincipal;
+    nsresult rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(channelPrincipal));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo(new mozilla::ipc::PrincipalInfo());
+    rv = PrincipalToPrincipalInfo(channelPrincipal, principalInfo.get());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    mPrincipalInfo = Move(principalInfo);
+    return NS_OK;
+  }
+
 private:
   ~CompareManager()
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(!mCC);
     MOZ_ASSERT(!mCN);
   }
 
@@ -541,16 +571,19 @@ private:
       return;
     }
 
     nsRefPtr<InternalResponse> ir =
       new InternalResponse(200, NS_LITERAL_CSTRING("OK"));
     ir->SetBody(body);
 
     ir->InitChannelInfo(mChannelInfo);
+    if (mPrincipalInfo) {
+      ir->SetPrincipalInfo(Move(mPrincipalInfo));
+    }
 
     nsRefPtr<Response> response = new Response(aCache->GetGlobalObject(), ir);
 
     RequestOrUSVString request;
     request.SetAsUSVString().Rebind(URL().Data(), URL().Length());
 
     // For now we have to wait until the Put Promise is fulfilled before we can
     // continue since Cache does not yet support starting a read that is being
@@ -574,16 +607,18 @@ private:
   nsRefPtr<CompareCache> mCC;
 
   nsString mURL;
   // Only used if the network script has changed and needs to be cached.
   nsString mNewCacheName;
 
   ChannelInfo mChannelInfo;
 
+  UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
+
   nsCString mMaxScope;
 
   enum {
     WaitingForOpen,
     WaitingForPut
   } mState;
 
   bool mNetworkFinished;
@@ -602,16 +637,20 @@ CompareNetwork::OnStartRequest(nsIReques
   }
 
 #ifdef DEBUG
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
   MOZ_ASSERT(channel == mChannel);
 #endif
 
   mManager->InitChannelInfo(mChannel);
+  nsresult rv = mManager->SetPrincipalInfo(mChannel);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CompareNetwork::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
                               nsresult aStatusCode)
 {