Bug 1460920 - Part 2 : Support referrerpolicy attribute in script HTMLScriptElement r=hsivonen
authorThomas Nguyen <tnguyen@mozilla.com>
Tue, 13 Nov 2018 14:33:02 +0000
changeset 503393 3309aa6d27ee8c2079b12e6904dc07af8d4951db
parent 503392 045f98957a596060173fc102aaf33ce4c20d9c39
child 503394 209069890e62b4c402c64be007f9cc992b9ec363
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen
bugs1460920
milestone65.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 1460920 - Part 2 : Support referrerpolicy attribute in script HTMLScriptElement r=hsivonen The patch adds the support of referrerpolicy attribute in script element and take the attribute into account when loading script. Differential Revision: https://phabricator.services.mozilla.com/D11637
dom/html/HTMLScriptElement.cpp
dom/html/HTMLScriptElement.h
dom/html/test/test_bug1260664.html
dom/script/ScriptLoader.cpp
dom/script/ScriptLoader.h
dom/script/nsIScriptElement.h
dom/webidl/HTMLScriptElement.webidl
--- a/dom/html/HTMLScriptElement.cpp
+++ b/dom/html/HTMLScriptElement.cpp
@@ -254,16 +254,22 @@ HTMLScriptElement::FreezeExecutionAttrs(
 }
 
 CORSMode
 HTMLScriptElement::GetCORSMode() const
 {
   return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
 }
 
+mozilla::net::ReferrerPolicy
+HTMLScriptElement::GetReferrerPolicy()
+{
+  return GetReferrerPolicyAsEnum();
+}
+
 bool
 HTMLScriptElement::HasScriptContent()
 {
   return (mFrozen ? mExternal : HasAttr(kNameSpaceID_None, nsGkAtoms::src)) ||
          nsContentUtils::HasNonEmptyTextContent(this);
 }
 
 } // namespace dom
--- a/dom/html/HTMLScriptElement.h
+++ b/dom/html/HTMLScriptElement.h
@@ -32,16 +32,17 @@ public:
                             mozilla::ErrorResult& aError) override;
 
   // nsIScriptElement
   virtual bool GetScriptType(nsAString& type) override;
   virtual void GetScriptText(nsAString& text) override;
   virtual void GetScriptCharset(nsAString& charset) override;
   virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) override;
   virtual CORSMode GetCORSMode() const override;
+  virtual mozilla::net::ReferrerPolicy GetReferrerPolicy() override;
 
   // nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent) override;
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsAtom* aAttribute,
                               const nsAString& aValue,
                               nsIPrincipal* aMaybeScriptedPrincipal,
@@ -150,16 +151,24 @@ public:
   void GetIntegrity(nsAString& aIntegrity)
   {
     GetHTMLAttr(nsGkAtoms::integrity, aIntegrity);
   }
   void SetIntegrity(const nsAString& aIntegrity, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::integrity, aIntegrity, aRv);
   }
+  void SetReferrerPolicy(const nsAString& aReferrerPolicy, ErrorResult& aError)
+  {
+    SetHTMLAttr(nsGkAtoms::referrerpolicy, aReferrerPolicy, aError);
+  }
+  void GetReferrerPolicy(nsAString& aReferrerPolicy)
+  {
+    GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrerPolicy);
+  }
 
 protected:
   virtual ~HTMLScriptElement();
 
   virtual bool GetAsyncState() override
   {
     return Async();
   }
--- a/dom/html/test/test_bug1260664.html
+++ b/dom/html/test/test_bug1260664.html
@@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 1260664 **/
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(runTests);
 
 function runTests() {
-  var elements = [ "iframe", "img", "a", "area", "link" ];
+  var elements = [ "iframe", "img", "a", "area", "link", "script"];
 
   for (var i = 0; i < elements.length; ++i) {
     reflectLimitedEnumerated({
       element: document.createElement(elements[i]),
       attribute: { content: "referrerpolicy", idl: "referrerPolicy" },
       validValues: [ "no-referrer",
                      "origin",
                      /** These 2 below values are still invalid, please see
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -1412,19 +1412,20 @@ ScriptLoader::ProcessExternalScript(nsIS
     }
 
     nsCOMPtr<nsIPrincipal> principal = aElement->GetScriptURITriggeringPrincipal();
     if (!principal) {
       principal = aScriptContent->NodePrincipal();
     }
 
     CORSMode ourCORSMode = aElement->GetCORSMode();
-    mozilla::net::ReferrerPolicy ourRefPolicy = mDocument->GetReferrerPolicy();
+    mozilla::net::ReferrerPolicy referrerPolicy = GetReferrerPolicy(aElement);
+
     request = CreateLoadRequest(aScriptKind, scriptURI, aElement, principal,
-                                ourCORSMode, sriMetadata, ourRefPolicy);
+                                ourCORSMode, sriMetadata, referrerPolicy);
     request->mIsInline = false;
     request->SetScriptMode(aElement->GetScriptDeferred(),
                            aElement->GetScriptAsync());
     // keep request->mScriptFromHead to false so we don't treat non preloaded
     // scripts as blockers for full page load. See bug 792438.
 
     LOG(("ScriptLoadRequest (%p): Created request for external script",
          request.get()));
@@ -1551,22 +1552,23 @@ ScriptLoader::ProcessInlineScript(nsIScr
   }
 
   // Inline classic scripts ignore their CORS mode and are always CORS_NONE.
   CORSMode corsMode = CORS_NONE;
   if (aScriptKind == ScriptKind::eModule) {
     corsMode = aElement->GetCORSMode();
   }
 
+  mozilla::net::ReferrerPolicy referrerPolicy = GetReferrerPolicy(aElement);
   RefPtr<ScriptLoadRequest> request =
     CreateLoadRequest(aScriptKind, mDocument->GetDocumentURI(), aElement,
                       mDocument->NodePrincipal(),
                       corsMode,
                       SRIMetadata(), // SRI doesn't apply
-                      mDocument->GetReferrerPolicy());
+                      referrerPolicy);
   request->mIsInline = true;
   request->mLineNo = aElement->GetScriptLineNumber();
   request->mProgress = ScriptLoadRequest::Progress::eLoading_Source;
   request->SetTextSource();
   TRACE_FOR_TEST_BOOL(request->Element(), "scriptloader_load_source");
   CollectScriptTelemetry(request);
 
   // Only the 'async' attribute is heeded on an inline module script and
@@ -1654,19 +1656,21 @@ ScriptLoader::LookupPreloadRequest(nsISc
   request->SetElement(aElement);
   nsString preloadCharset(mPreloads[i].mCharset);
   mPreloads.RemoveElementAt(i);
 
   // Double-check that the charset the preload used is the same as the charset
   // we have now.
   nsAutoString elementCharset;
   aElement->GetScriptCharset(elementCharset);
+  mozilla::net::ReferrerPolicy referrerPolicy = GetReferrerPolicy(aElement);
+
   if (!elementCharset.Equals(preloadCharset) ||
       aElement->GetCORSMode() != request->CORSMode() ||
-      mDocument->GetReferrerPolicy() != request->ReferrerPolicy() ||
+      referrerPolicy != request->ReferrerPolicy() ||
       aScriptKind != request->mKind) {
     // Drop the preload.
     request->Cancel();
     AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::RequestMismatch);
     return nullptr;
   }
 
   return request;
@@ -1689,16 +1693,28 @@ ScriptLoader::GetSRIMetadata(const nsASt
   nsAutoCString sourceUri;
   if (mDocument->GetDocumentURI()) {
     mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
   }
   SRICheck::IntegrityMetadata(aIntegrityAttr, sourceUri, mReporter,
                               aMetadataOut);
 }
 
+
+mozilla::net::ReferrerPolicy
+ScriptLoader::GetReferrerPolicy(nsIScriptElement* aElement)
+{
+  mozilla::net::ReferrerPolicy scriptReferrerPolicy =
+    aElement->GetReferrerPolicy();
+  if (scriptReferrerPolicy != mozilla::net::RP_Unset) {
+    return scriptReferrerPolicy;
+  }
+  return mDocument->GetReferrerPolicy();
+}
+
 namespace {
 
 class NotifyOffThreadScriptLoadCompletedRunnable : public Runnable
 {
   RefPtr<ScriptLoadRequest> mRequest;
   RefPtr<ScriptLoader> mLoader;
   RefPtr<DocGroup> mDocGroup;
   JS::OffThreadToken* mToken;
--- a/dom/script/ScriptLoader.h
+++ b/dom/script/ScriptLoader.h
@@ -378,16 +378,22 @@ private:
 
   ScriptLoadRequest* LookupPreloadRequest(nsIScriptElement* aElement,
                                           ScriptKind aScriptKind);
 
   void GetSRIMetadata(const nsAString& aIntegrityAttr,
                       SRIMetadata *aMetadataOut);
 
   /**
+   * Given a script element, get the referrer policy should be applied to load
+   * requests.
+   */
+  mozilla::net::ReferrerPolicy GetReferrerPolicy(nsIScriptElement* aElement);
+
+  /**
    * Helper function to check the content policy for a given request.
    */
   static nsresult CheckContentPolicy(nsIDocument* aDocument,
                                      nsISupports* aContext,
                                      nsIURI* aURI,
                                      const nsAString& aType,
                                      bool aIsPreLoad);
 
--- a/dom/script/nsIScriptElement.h
+++ b/dom/script/nsIScriptElement.h
@@ -11,16 +11,17 @@
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsIScriptLoaderObserver.h"
 #include "nsIWeakReferenceUtils.h"
 #include "nsIParser.h"
 #include "nsIContent.h"
 #include "nsContentCreatorFunctions.h"
 #include "mozilla/CORSMode.h"
+#include "mozilla/net/ReferrerPolicy.h"
 
 // Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs
 #define NS_ISCRIPTELEMENT_IID \
 { 0xe60fca9b, 0x1b96, 0x4e4e, \
  { 0xa9, 0xb4, 0xdc, 0x98, 0x4f, 0x88, 0x3f, 0x9c } }
 
 /**
  * Internal interface implemented by script elements
@@ -269,16 +270,24 @@ public:
    */
   virtual mozilla::CORSMode GetCORSMode() const
   {
     /* Default to no CORS */
     return mozilla::CORS_NONE;
   }
 
   /**
+   * Get referrer policy of the script element
+   */
+  virtual mozilla::net::ReferrerPolicy GetReferrerPolicy()
+  {
+    return mozilla::net::RP_Unset;
+  }
+
+  /**
    * Fire an error event
    */
   virtual nsresult FireErrorEvent() = 0;
 
 protected:
   /**
    * Processes the script if it's in the document-tree and links to or
    * contains a script. Once it has been evaluated there is no way to make it
--- a/dom/webidl/HTMLScriptElement.webidl
+++ b/dom/webidl/HTMLScriptElement.webidl
@@ -19,16 +19,18 @@ interface HTMLScriptElement : HTMLElemen
   [CEReactions, SetterThrows]
   attribute DOMString charset;
   [CEReactions, SetterThrows]
   attribute boolean async;
   [CEReactions, SetterThrows]
   attribute boolean defer;
   [CEReactions, SetterThrows]
   attribute DOMString? crossOrigin;
+  [CEReactions, SetterThrows]
+  attribute DOMString referrerPolicy;
   [CEReactions, Throws]
   attribute DOMString text;
 };
 
 // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
 partial interface HTMLScriptElement {
   [CEReactions, SetterThrows]
   attribute DOMString event;