Bug 1330487 - Apply referrer policy to request resources referenced from stylesheet draft
authorThomas Nguyen <tnguyen@mozilla.com>
Fri, 20 Oct 2017 13:01:38 +0800
changeset 689142 9ba290dd5c205870d7b65ec8705894de38a23e33
parent 680024 196dadb2fe500e75c6fbddcac78106648676cf10
child 689143 3a4bb44e65ad984c2d4332cf58c716f67f3802e3
push id86930
push userbmo:tnguyen@mozilla.com
push dateTue, 31 Oct 2017 04:27:08 +0000
bugs1330487
milestone58.0a1
Bug 1330487 - Apply referrer policy to request resources referenced from stylesheet MozReview-Commit-ID: 84AoFANESJe
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsDocument.cpp
layout/style/FontFaceSet.cpp
layout/style/ImageLoader.cpp
layout/style/ImageLoader.h
layout/style/Loader.cpp
layout/style/Loader.h
layout/style/ServoStyleSheet.cpp
layout/style/SheetLoadData.h
layout/style/StyleSheet.h
layout/style/StyleSheetInlines.h
layout/style/URLExtraData.h
layout/style/nsCSSParser.cpp
layout/style/nsCSSValue.cpp
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8980,16 +8980,49 @@ nsContentUtils::GetReferrerPolicyFromHea
     if (policy != net::RP_Unset) {
       referrerPolicy = policy;
     }
   }
   return referrerPolicy;
 }
 
 // static
+nsresult
+nsContentUtils::GetReferrerPolicyFromResponse(nsIChannel* aChannel,
+                                              mozilla::net::ReferrerPolicy& aPolicy)
+{
+  aPolicy = net::RP_Unset;
+
+  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
+  if (!httpChannel) {
+    return NS_OK;
+  }
+
+  nsresult rv;
+  nsAutoCString tRPHeaderCValue;
+  bool requestSucceeded;
+  rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
+  if (NS_FAILED(rv) || !requestSucceeded) {
+    return NS_ERROR_FAILURE;
+  }
+
+  rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("referrer-policy"),
+                                      tRPHeaderCValue);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (tRPHeaderCValue.IsEmpty()) {
+    return NS_OK;
+  }
+
+  NS_ConvertUTF8toUTF16 headerValue(tRPHeaderCValue);
+  aPolicy = GetReferrerPolicyFromHeader(headerValue);
+
+  return NS_OK;
+}
+
+// static
 bool
 nsContentUtils::PromiseRejectionEventsEnabled(JSContext* aCx, JSObject* aObj)
 {
   if (NS_IsMainThread()) {
     return Preferences::GetBool("dom.promise_rejection_events.enabled", false);
   }
 
   using namespace workers;
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2927,16 +2927,19 @@ public:
    * Parse a referrer policy from a Referrer-Policy header
    * https://www.w3.org/TR/referrer-policy/#parse-referrer-policy-from-header
    *
    * @param aHeader the response's Referrer-Policy header to parse
    * @return referrer policy from the response header.
    */
   static mozilla::net::ReferrerPolicy GetReferrerPolicyFromHeader(const nsAString& aHeader);
 
+  static nsresult GetReferrerPolicyFromResponse(nsIChannel* aChannel,
+                                                mozilla::net::ReferrerPolicy& aPolicy);
+
   static bool PromiseRejectionEventsEnabled(JSContext* aCx, JSObject* aObj);
 
   static bool PushEnabled(JSContext* aCx, JSObject* aObj);
 
   static bool StreamsEnabled(JSContext* aCx, JSObject* aObj);
 
   static bool IsNonSubresourceRequest(nsIChannel* aChannel);
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1258,31 +1258,39 @@ nsExternalResourceMap::PendingLoad::OnSt
 
 nsresult
 nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
                                               nsINode* aRequestingNode)
 {
   NS_PRECONDITION(aURI, "Must have a URI");
   NS_PRECONDITION(aRequestingNode, "Must have a node");
 
-  nsCOMPtr<nsILoadGroup> loadGroup =
-    aRequestingNode->OwnerDoc()->GetDocumentLoadGroup();
-
+  nsIDocument* ownerDoc = aRequestingNode->OwnerDoc();
+  nsCOMPtr<nsILoadGroup> loadGroup = ownerDoc->GetDocumentLoadGroup();
   nsresult rv = NS_OK;
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      aURI,
                      aRequestingNode,
                      nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
                      nsIContentPolicy::TYPE_OTHER,
                      loadGroup);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mURI = aURI;
 
+  nsIURI* documentURI = ownerDoc->GetDocumentURI();
+  if (documentURI) {
+    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
+    if (httpChannel) {
+      Unused << httpChannel->SetReferrerWithPolicy(documentURI,
+                                                   ownerDoc->GetReferrerPolicy());
+    }
+  }
+
   return channel->AsyncOpen2(this);
 }
 
 NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks,
                   nsIInterfaceRequestor)
 
 #define IMPL_SHIM(_i) \
   NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i)
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -653,17 +653,17 @@ FontFaceSet::StartLoad(gfxUserFontEntry*
          aFontFaceSrc->mReferrer
          ? aFontFaceSrc->mReferrer->GetSpecOrDefault().get()
          : ""));
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
     rv = httpChannel->SetReferrerWithPolicy(aFontFaceSrc->mReferrer,
-                                            mDocument->GetReferrerPolicy());
+                                            aFontFaceSrc->mReferrerPolicy);
     Unused << NS_WARN_IF(NS_FAILED(rv));
 
     nsAutoCString accept("application/font-woff;q=0.9,*/*;q=0.8");
     if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED)) {
       accept.InsertLiteral("application/font-woff2;q=1.0,", 0);
     }
     rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                        accept, false);
@@ -1125,17 +1125,23 @@ FontFaceSet::FindOrCreateUserFontEntryFr
           face->mReferrerPolicy = mozilla::net::RP_Unset;
           break;
         case eCSSUnit_URL: {
           face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
           nsIURI* uri = val.GetURLValue();
           face->mURI = uri ? new gfxFontSrcURI(uri) : nullptr;
           URLValue* url = val.GetURLStructValue();
           face->mReferrer = url->mExtraData->GetReferrer();
-          face->mReferrerPolicy = mDocument->GetReferrerPolicy();
+          mozilla::net::ReferrerPolicy referrerPolicy =
+            url->mExtraData->GetReferrerPolicy();
+          if (referrerPolicy == mozilla::net::RP_Unset) {
+            referrerPolicy = mDocument->GetReferrerPolicy();
+          }
+
+          face->mReferrerPolicy = referrerPolicy;
           face->mOriginPrincipal =
             new gfxFontSrcPrincipal(url->mExtraData->GetPrincipal());
           NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
 
           // agent and user stylesheets are treated slightly differently,
           // the same-site origin check and access control headers are
           // enforced against the sheet principal rather than the document
           // principal to allow user stylesheets to include @font-face rules
--- a/layout/style/ImageLoader.cpp
+++ b/layout/style/ImageLoader.cpp
@@ -251,30 +251,36 @@ ImageLoader::ClearFrames(nsPresContext* 
   }
 
   mRequestToFrameMap.Clear();
   mFrameToRequestMap.Clear();
 }
 
 void
 ImageLoader::LoadImage(nsIURI* aURI, nsIPrincipal* aOriginPrincipal,
-                       nsIURI* aReferrer, ImageLoader::Image* aImage)
+                       nsIURI* aReferrer, mozilla::net::ReferrerPolicy aPolicy,
+                       ImageLoader::Image* aImage)
 {
   NS_ASSERTION(aImage->mRequests.Count() == 0, "Huh?");
 
   aImage->mRequests.Put(nullptr, nullptr);
 
   if (!aURI) {
     return;
   }
 
+  mozilla::net::ReferrerPolicy referrerPolicy(aPolicy);
+  if (referrerPolicy == mozilla::net::RP_Unset) {
+    referrerPolicy = mDocument->GetReferrerPolicy();
+  }
+
   RefPtr<imgRequestProxy> request;
   nsresult rv = nsContentUtils::LoadImage(aURI, mDocument, mDocument,
                                           aOriginPrincipal, 0, aReferrer,
-                                          mDocument->GetReferrerPolicy(),
+                                          referrerPolicy,
                                           nullptr, nsIRequest::LOAD_NORMAL,
                                           NS_LITERAL_STRING("css"),
                                           getter_AddRefs(request));
 
   if (NS_FAILED(rv) || !request) {
     return;
   }
 
--- a/layout/style/ImageLoader.h
+++ b/layout/style/ImageLoader.h
@@ -10,16 +10,17 @@
 
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsTArray.h"
 #include "imgIRequest.h"
 #include "imgIOnloadBlocker.h"
 #include "imgINotificationObserver.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/net/ReferrerPolicy.h"
 
 class imgIContainer;
 class nsIFrame;
 class nsIDocument;
 class nsPresContext;
 class nsIURI;
 class nsIPrincipal;
 
@@ -61,17 +62,17 @@ public:
   void SetAnimationMode(uint16_t aMode);
 
   // The prescontext for this ImageLoader's document. We need it to be passed
   // in because this can be called during presentation destruction after the
   // presshell pointer on the document has been cleared.
   void ClearFrames(nsPresContext* aPresContext);
 
   void LoadImage(nsIURI* aURI, nsIPrincipal* aPrincipal, nsIURI* aReferrer,
-                 Image* aCSSValue);
+                 mozilla::net::ReferrerPolicy aPolicy, Image* aCSSValue);
 
   void DestroyRequest(imgIRequest* aRequest);
 
   void FlushUseCounters();
 
 private:
   ~ImageLoader() {}
 
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -594,16 +594,49 @@ SheetLoadData::GetReferrerURI()
   nsCOMPtr<nsIURI> uri;
   if (mParentData)
     uri = mParentData->mSheet->GetSheetURI();
   if (!uri && mLoader->mDocument)
     uri = mLoader->mDocument->GetDocumentURI();
   return uri.forget();
 }
 
+mozilla::net::ReferrerPolicy
+SheetLoadData::GetReferrerPolicy()
+{
+  if (mParentData) {
+    return mParentData->mSheet->GetReferrerPolicy();
+  }
+
+  if (mLoader->mDocument) {
+    return mLoader->mDocument->GetReferrerPolicy();
+  }
+
+  return mozilla::net::RP_Unset;
+}
+
+nsresult
+SheetLoadData::SetReferrerPolicyFromHeader(nsIChannel* aChannel)
+{
+  net::ReferrerPolicy policy = net::RP_Unset;
+  nsresult rv = nsContentUtils::GetReferrerPolicyFromResponse(aChannel, policy);
+  if (NS_FAILED(rv) || policy == net::RP_Unset ||
+      policy == mSheet->GetReferrerPolicy()) {
+    return NS_OK;
+  }
+
+  URIPrincipalReferrerPolicyAndCORSModeHashKey key(mURI,
+                                                   mLoaderPrincipal,
+                                                   mSheet->GetCORSMode(),
+                                                   mSheet->GetReferrerPolicy());
+
+  mSheet->SetReferrerPolicy(policy);
+  mLoader->UpdateLoadingData(&key, this);
+  return NS_OK;
+}
 /*
  * Load completion for the old style system.
  */
 NS_IMETHODIMP
 SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
                                 nsISupports* aContext,
                                 nsresult aStatus,
                                 const nsAString& aBuffer)
@@ -832,16 +865,18 @@ SheetLoadData::VerifySheetReadyToParse(n
       LOG(("  Load was blocked by SRI"));
       MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
               ("css::Loader::OnStreamComplete, bad metadata"));
       mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
       return NS_OK;
     }
   }
 
+  Unused << SetReferrerPolicyFromHeader(aChannel);
+
   // Enough to set the URIs on mSheet, since any sibling datas we have share
   // the same mInner as mSheet and will thus get the same URI.
   mSheet->SetURIs(channelURI, originalURI, channelURI);
   return NS_OK_PARSE_SHEET;
 }
 
 bool
 Loader::IsAlternate(const nsAString& aTitle, bool aHasAlternateRel)
@@ -881,16 +916,37 @@ Loader::ObsoleteSheet(nsIURI* aURI)
     nsresult rv = sheetURI->Equals(aURI, &areEqual);
     if (NS_SUCCEEDED(rv) && areEqual) {
       iter.Remove();
     }
   }
   return NS_OK;
 }
 
+void
+Loader::UpdateLoadingData(URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey,
+                          SheetLoadData* aData)
+{
+  if (NS_WARN_IF(!mSheets)) {
+    return;
+  }
+
+  if (NS_WARN_IF(!aData->mIsLoading)) {
+    return;
+  }
+
+  mSheets->mLoadingDatas.Remove(aKey);
+  URIPrincipalReferrerPolicyAndCORSModeHashKey key(aData->mURI,
+                                                   aData->mLoaderPrincipal,
+                                                   aData->mSheet->GetCORSMode(),
+                                                   aData->mSheet->GetReferrerPolicy());
+
+  mSheets->mLoadingDatas.Put(&key, aData);
+}
+
 nsresult
 Loader::CheckContentPolicy(nsIPrincipal* aLoadingPrincipal,
                            nsIPrincipal* aTriggeringPrincipal,
                            nsIURI* aTargetURI,
                            nsISupports* aContext,
                            bool aIsPreload)
 {
   // When performing a system load (e.g. aUseSystemPrincipal = true)
@@ -1537,17 +1593,17 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
     rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                        NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
                                        false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
     if (referrerURI) {
       rv = httpChannel->SetReferrerWithPolicy(referrerURI,
-                                              aLoadData->mSheet->GetReferrerPolicy());
+                                              aLoadData->GetReferrerPolicy());
       Unused << NS_WARN_IF(NS_FAILED(rv));
     }
 
     nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChannel);
     if (internalChannel) {
       rv = internalChannel->SetIntegrityMetadata(sriMetadata.GetIntegrityString());
       NS_ENSURE_SUCCESS(rv, rv);
     }
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -575,16 +575,19 @@ private:
   // The guts of SheetComplete.  This may be called recursively on parent datas
   // or datas that had glommed on to a single load.  The array is there so load
   // datas whose observers need to be notified can be added to it.
   void DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
                        LoadDataArray& aDatasToNotify);
 
   StyleBackendType GetStyleBackendType() const;
 
+  void UpdateLoadingData(URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey,
+                         SheetLoadData* aData);
+
   struct Sheets {
     nsBaseHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey,
                     RefPtr<StyleSheet>,
                     StyleSheet*> mCompleteSheets;
     nsDataHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey, SheetLoadData*>
                       mLoadingDatas; // weak refs
     nsDataHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey, SheetLoadData*>
                       mPendingDatas; // weak refs
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -203,17 +203,17 @@ ServoStyleSheet::ParseSheet(css::Loader*
                             nsIURI* aBaseURI,
                             nsIPrincipal* aSheetPrincipal,
                             uint32_t aLineNumber,
                             nsCompatibility aCompatMode,
                             css::LoaderReusableStyleSheets* aReusableSheets)
 {
   MOZ_ASSERT(!mMedia || mMedia->IsServo());
   RefPtr<URLExtraData> extraData =
-    new URLExtraData(aBaseURI, aSheetURI, aSheetPrincipal);
+    new URLExtraData(aBaseURI, aSheetURI, aSheetPrincipal, mInner->mReferrerPolicy);
 
   Inner()->mContents = Servo_StyleSheet_FromUTF8Bytes(aLoader,
                                                       this,
                                                       aInput.Elements(),
                                                       aInput.Length(),
                                                       mParsingMode,
                                                       extraData,
                                                       aLineNumber,
--- a/layout/style/SheetLoadData.h
+++ b/layout/style/SheetLoadData.h
@@ -5,16 +5,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/. */
 
 #ifndef mozilla_css_SheetLoadData_h
 #define mozilla_css_SheetLoadData_h
 
 #include "nsIUnicharStreamLoader.h"
 #include "nsIThreadInternal.h"
+#include "mozilla/net/ReferrerPolicy.h"
 
 namespace mozilla {
 namespace css {
 
 /*********************************************
  * Data needed to properly load a stylesheet *
  *********************************************/
 
@@ -60,25 +61,29 @@ public:
                 bool aUseSystemPrincipal,
                 const Encoding* aPreloadEncoding,
                 nsICSSLoaderObserver* aObserver,
                 nsIPrincipal* aLoaderPrincipal,
                 nsINode* aRequestingNode);
 
   already_AddRefed<nsIURI> GetReferrerURI();
 
+  mozilla::net::ReferrerPolicy GetReferrerPolicy();
+
   void ScheduleLoadEventIfNeeded(nsresult aStatus);
 
   NotNull<const Encoding*> DetermineNonBOMEncoding(nsACString const& aSegment,
                                                    nsIChannel* aChannel);
 
   nsresult VerifySheetReadyToParse(nsresult aStatus,
                                    const nsACString& aBytes,
                                    nsIChannel* aChannel);
 
+  nsresult SetReferrerPolicyFromHeader(nsIChannel* aChannel);
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_NSITHREADOBSERVER
   NS_DECL_NSIUNICHARSTREAMLOADEROBSERVER
 
   // Hold a ref to the CSSLoader so we can call back to it to let it
   // know the load finished
   RefPtr<Loader> mLoader;
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -191,16 +191,18 @@ public:
 
   void SetTitle(const nsAString& aTitle) { mTitle = aTitle; }
   void SetMedia(dom::MediaList* aMedia);
 
   // Get this style sheet's CORS mode
   inline CORSMode GetCORSMode() const;
   // Get this style sheet's Referrer Policy
   inline net::ReferrerPolicy GetReferrerPolicy() const;
+  // Set style sheet's Referrer Policy
+  inline void SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy);
   // Get this style sheet's integrity metadata
   inline void GetIntegrity(dom::SRIMetadata& aResult) const;
 
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 #ifdef DEBUG
   virtual void List(FILE* aOut = stdout, int32_t aIndex = 0) const;
 #endif
 
--- a/layout/style/StyleSheetInlines.h
+++ b/layout/style/StyleSheetInlines.h
@@ -119,16 +119,22 @@ StyleSheet::GetCORSMode() const
 
 net::ReferrerPolicy
 StyleSheet::GetReferrerPolicy() const
 {
   return SheetInfo().mReferrerPolicy;
 }
 
 void
+StyleSheet::SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
+{
+  SheetInfo().mReferrerPolicy = aReferrerPolicy;
+}
+
+void
 StyleSheet::GetIntegrity(dom::SRIMetadata& aResult) const
 {
   aResult = SheetInfo().mIntegrity;
 }
 
 }
 
 #endif // mozilla_StyleSheetInlines_h
--- a/layout/style/URLExtraData.h
+++ b/layout/style/URLExtraData.h
@@ -7,61 +7,84 @@
 /* thread-safe container of information for resolving url values */
 
 #ifndef mozilla_URLExtraData_h
 #define mozilla_URLExtraData_h
 
 #include "mozilla/dom/URL.h"
 #include "mozilla/Move.h"
 #include "mozilla/StaticPtr.h"
+#include "mozilla/net/ReferrerPolicy.h"
 
 #include "nsCOMPtr.h"
 #include "nsIPrincipal.h"
 #include "nsIURI.h"
 
 namespace mozilla {
 
 struct URLExtraData
 {
   URLExtraData(already_AddRefed<nsIURI> aBaseURI,
                already_AddRefed<nsIURI> aReferrer,
-               already_AddRefed<nsIPrincipal> aPrincipal)
+               already_AddRefed<nsIPrincipal> aPrincipal,
+               net::ReferrerPolicy aReferrerPolicy)
     : mBaseURI(Move(aBaseURI))
     , mReferrer(Move(aReferrer))
+    , mReferrerPolicy(aReferrerPolicy)
     , mPrincipal(Move(aPrincipal))
       // When we hold the URI data of a style sheet, mReferrer is always
       // equal to the sheet URI.
     , mIsChrome(mReferrer ? dom::IsChromeURI(mReferrer) : false)
   {
     MOZ_ASSERT(mBaseURI);
   }
 
+  URLExtraData(already_AddRefed<nsIURI> aBaseURI,
+               already_AddRefed<nsIURI> aReferrer,
+               already_AddRefed<nsIPrincipal> aPrincipal)
+    : URLExtraData(Move(aBaseURI),
+                   Move(aReferrer),
+                   Move(aPrincipal),
+                   net::RP_Unset) {}
+
   URLExtraData(nsIURI* aBaseURI, nsIURI* aReferrer, nsIPrincipal* aPrincipal)
     : URLExtraData(do_AddRef(aBaseURI),
                    do_AddRef(aReferrer),
-                   do_AddRef(aPrincipal)) {}
+                   do_AddRef(aPrincipal),
+                   net::RP_Unset) {}
+
+  URLExtraData(nsIURI* aBaseURI, nsIURI* aReferrer,
+               nsIPrincipal* aPrincipal,
+               net::ReferrerPolicy aReferrerPolicy)
+    : URLExtraData(do_AddRef(aBaseURI),
+                   do_AddRef(aReferrer),
+                   do_AddRef(aPrincipal),
+                   aReferrerPolicy) {}
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLExtraData)
 
   nsIURI* BaseURI() const { return mBaseURI; }
   nsIURI* GetReferrer() const { return mReferrer; }
+  net::ReferrerPolicy GetReferrerPolicy() const { return mReferrerPolicy;}
+  void SetReferrerPolicy(net::ReferrerPolicy aPolicy) { mReferrerPolicy = aPolicy;}
   nsIPrincipal* GetPrincipal() const { return mPrincipal; }
 
   static URLExtraData* Dummy() {
     MOZ_ASSERT(sDummy);
     return sDummy;
   }
   static void InitDummy();
   static void ReleaseDummy();
 
 private:
   ~URLExtraData();
 
   nsCOMPtr<nsIURI> mBaseURI;
   nsCOMPtr<nsIURI> mReferrer;
+  net::ReferrerPolicy mReferrerPolicy;
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
   // True if mReferrer is a chrome:// URI.
   const bool mIsChrome;
 
   static StaticRefPtr<URLExtraData> sDummy;
 };
 
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -8137,16 +8137,21 @@ CSSParserImpl::SetValueToURL(nsCSSValue&
 
     NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an "
                   "origin principal");
     return false;
   }
 
   mozilla::css::URLValue *urlVal =
     new mozilla::css::URLValue(aURL, mBaseURI, mSheetURI, mSheetPrincipal);
+
+  if (mSheet) {
+    urlVal->mExtraData->SetReferrerPolicy(mSheet->GetReferrerPolicy());
+  }
+
   aValue.SetURLValue(urlVal);
   return true;
 }
 
 /**
  * Parse the image-orientation property, which has the grammar:
  * <angle> flip? | flip | from-image
  */
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -3173,17 +3173,19 @@ css::ImageValue::Initialize(nsIDocument*
   nsIDocument* loadingDoc = aDocument->GetOriginalDocument();
   if (!loadingDoc) {
     loadingDoc = aDocument;
   }
 
   if (!mLoadedImage) {
     loadingDoc->StyleImageLoader()->LoadImage(GetURI(),
                                               mExtraData->GetPrincipal(),
-                                              mExtraData->GetReferrer(), this);
+                                              mExtraData->GetReferrer(),
+                                              mExtraData->GetReferrerPolicy(),
+                                              this);
 
      mLoadedImage = true;
   }
 
   aDocument->StyleImageLoader()->MaybeRegisterCSSImage(this);
 }
 
 css::ImageValue::~ImageValue()