Bug 732209 part 6. Allow web pages to access cross-origin stylesheets if the CORS headers say so. r=dbaron,sicking
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 28 Aug 2012 13:10:09 -0400
changeset 105710 62b86f439a09333d52db9d69e2023a1b0002fbc5
parent 105709 4af1510fc1c2f8e4ac154e5d5724c9a56e2e3135
child 105711 cfd19083d2989e51e367f6ff0d9341ad3e8b2c75
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersdbaron, sicking
bugs732209
milestone18.0a1
Bug 732209 part 6. Allow web pages to access cross-origin stylesheets if the CORS headers say so. r=dbaron,sicking When gaining such access, the web page resets the stylesheet to its principal, because it can now edit the sheet.
layout/style/nsCSSStyleSheet.cpp
layout/style/nsCSSStyleSheet.h
layout/style/test/test_bug732209.html
--- a/layout/style/nsCSSStyleSheet.cpp
+++ b/layout/style/nsCSSStyleSheet.cpp
@@ -1584,17 +1584,17 @@ void
 nsCSSStyleSheet::DidDirty()
 {
   NS_ABORT_IF_FALSE(!mInner->mComplete || mDirty,
                     "caller must have called WillDirty()");
   ClearRuleCascades();
 }
 
 nsresult
-nsCSSStyleSheet::SubjectSubsumesInnerPrincipal() const
+nsCSSStyleSheet::SubjectSubsumesInnerPrincipal()
 {
   // Get the security manager and do the subsumes check
   nsIScriptSecurityManager *securityManager =
     nsContentUtils::GetSecurityManager();
 
   nsCOMPtr<nsIPrincipal> subjectPrincipal;
   nsresult rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1607,17 +1607,36 @@ nsCSSStyleSheet::SubjectSubsumesInnerPri
   rv = subjectPrincipal->Subsumes(mInner->mPrincipal, &subsumes);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (subsumes) {
     return NS_OK;
   }
   
   if (!nsContentUtils::IsCallerTrustedForWrite()) {
-    return NS_ERROR_DOM_SECURITY_ERR;
+    // Allow access only if CORS mode is not NONE
+    if (GetCORSMode() == CORS_NONE) {
+      return NS_ERROR_DOM_SECURITY_ERR;
+    }
+
+    // Now make sure we set the principal of our inner to the
+    // subjectPrincipal.  That means we need a unique inner, of
+    // course.  But we don't want to do that if we're not complete
+    // yet.  Luckily, all the callers of this method throw anyway if
+    // not complete, so we can just do that here too.
+    if (!mInner->mComplete) {
+      return NS_ERROR_DOM_INVALID_ACCESS_ERR;
+    }
+
+    rv = WillDirty();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    mInner->mPrincipal = subjectPrincipal;
+
+    DidDirty();
   }
 
   return NS_OK;
 }
 
 nsresult
 nsCSSStyleSheet::RegisterNamespaceRule(css::Rule* aRule)
 {
--- a/layout/style/nsCSSStyleSheet.h
+++ b/layout/style/nsCSSStyleSheet.h
@@ -260,18 +260,19 @@ protected:
 
   void ClearRuleCascades();
 
   nsresult WillDirty();
   void     DidDirty();
 
   // Return success if the subject principal subsumes the principal of our
   // inner, error otherwise.  This will also succeed if the subject has
-  // UniversalXPConnect.
-  nsresult SubjectSubsumesInnerPrincipal() const;
+  // UniversalXPConnect or if access is allowed by CORS.  In the latter case,
+  // it will set the principal of the inner to the subject principal.
+  nsresult SubjectSubsumesInnerPrincipal();
 
   // Add the namespace mapping from this @namespace rule to our namespace map
   nsresult RegisterNamespaceRule(mozilla::css::Rule* aRule);
 
 protected:
   nsString              mTitle;
   nsRefPtr<nsMediaList> mMedia;
   nsRefPtr<nsCSSStyleSheet> mNext;
--- a/layout/style/test/test_bug732209.html
+++ b/layout/style/test/test_bug732209.html
@@ -22,17 +22,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <link rel="stylesheet"
         href="http://example.com/tests/layout/style/test/bug732209-css.sjs?five"
         crossorigin>
   <link rel="stylesheet"
         href="http://example.com/tests/layout/style/test/bug732209-css.sjs?six"
         crossorigin="use-credentials">
   <link rel="stylesheet"
         href="http://example.com/tests/layout/style/test/bug732209-css.sjs?seven&cors-anonymous">
-  <link rel="stylesheet"
+  <link rel="stylesheet" id="cross-origin-sheet"
         href="http://example.com/tests/layout/style/test/bug732209-css.sjs?eight&cors-anonymous"
         crossorigin>
   <link rel="stylesheet"
         href="http://example.com/tests/layout/style/test/bug732209-css.sjs?nine&cors-anonymous"
         crossorigin="use-credentials">
   <link rel="stylesheet"
         href="http://example.com/tests/layout/style/test/bug732209-css.sjs?ten&cors-credentials">
   <link rel="stylesheet"
@@ -66,16 +66,29 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(function() {
   var spans = $("content").querySelectorAll("span");
   for (var i = 0; i < spans.length; ++i) {
     is(getComputedStyle(spans[i], "").color, "rgb(0, 128, 0)",
        "Span " + spans[i].id + " should be green");
   }
+
+  try {
+    var sheet = $("cross-origin-sheet").sheet;
+    dump('aaa');
+    is(sheet.cssRules.length, 2,
+       "Should be able to get length of list of rules");
+    is(sheet.cssRules[0].style.color, "green",
+       "Should be able to read individual rules");
+  } catch (e) {
+    ok(false,
+       "Should be allowed to access cross-origin sheet that opted in with CORS: " + e);
+  }
+
   SimpleTest.finish();
 });
 
 
 
 </script>
 </pre>
 </body>