Bug 1165162 - Make OriginAttributes a dictionary, and make it accessible as both a jsval and a canonical string. r=gabor,r=bholley,sr=sicking
authorBobby Holley <bobbyholley@gmail.com>
Thu, 14 May 2015 16:24:25 -0700
changeset 277260 72f81e3ed9aa3c442938803630b82b668c4725cc
parent 277259 121b818c01a55a4c1c672a4168bec164a6a5775f
child 277261 5bc2395aa7105f2e8b59242c01671f1584f1f4b3
push id897
push userjlund@mozilla.com
push dateMon, 14 Sep 2015 18:56:12 +0000
treeherdermozilla-release@9411e2d2b214 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgabor, bholley, sicking
bugs1165162
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 1165162 - Make OriginAttributes a dictionary, and make it accessible as both a jsval and a canonical string. r=gabor,r=bholley,sr=sicking
caps/BasePrincipal.cpp
caps/BasePrincipal.h
caps/nsIPrincipal.idl
dom/webidl/SystemDictionaries.webidl
dom/webidl/moz.build
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -5,32 +5,51 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/BasePrincipal.h"
 
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsScriptSecurityManager.h"
 
+#include "mozilla/dom/ToJSValue.h"
+
 namespace mozilla {
 
 void
+BasePrincipal::OriginAttributes::CreateSuffix(nsACString& aStr)
+{
+  aStr.Truncate();
+  MOZ_RELEASE_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
+  int attrCount = 0;
+
+  if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
+    aStr.Append(attrCount++ ? "&appId=" : "!appId=");
+    aStr.AppendInt(mAppId);
+  }
+
+  if (mInBrowser) {
+    aStr.Append(attrCount++ ? "&inBrowser=1" : "!inBrowser=1");
+  }
+}
+
+void
 BasePrincipal::OriginAttributes::Serialize(nsIObjectOutputStream* aStream) const
 {
   aStream->Write32(mAppId);
-  aStream->WriteBoolean(mIsInBrowserElement);
+  aStream->WriteBoolean(mInBrowser);
 }
 
 nsresult
 BasePrincipal::OriginAttributes::Deserialize(nsIObjectInputStream* aStream)
 {
   nsresult rv = aStream->Read32(&mAppId);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = aStream->ReadBoolean(&mIsInBrowserElement);
+  rv = aStream->ReadBoolean(&mInBrowser);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 bool
 BasePrincipal::Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration)
 {
@@ -100,16 +119,32 @@ BasePrincipal::GetJarPrefix(nsACString& 
 {
   MOZ_ASSERT(AppId() != nsIScriptSecurityManager::UNKNOWN_APP_ID);
 
   mozilla::GetJarPrefix(AppId(), IsInBrowserElement(), aJarPrefix);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+BasePrincipal::GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
+{
+  if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aVal))) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BasePrincipal::GetOriginSuffix(nsACString& aOriginAttributes)
+{
+  mOriginAttributes.CreateSuffix(aOriginAttributes);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 BasePrincipal::GetAppStatus(uint16_t* aAppStatus)
 {
   if (AppId() == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
     NS_WARNING("Asking for app status on a principal with an unknown app id");
     *aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
     return NS_OK;
   }
 
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -6,16 +6,18 @@
 
 #ifndef mozilla_BasePrincipal_h
 #define mozilla_BasePrincipal_h
 
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsJSPrincipals.h"
 
+#include "mozilla/dom/SystemDictionariesBinding.h"
+
 class nsIObjectOutputStream;
 class nsIObjectInputStream;
 
 namespace mozilla {
 
 /*
  * Base class from which all nsIPrincipal implementations inherit. Use this for
  * default implementations and other commonalities between principal
@@ -34,52 +36,57 @@ public:
   NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
   NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal) override;
   NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix) final;
+  NS_IMETHOD GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) final;
+  NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
   NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) final;
   NS_IMETHOD GetAppId(uint32_t* aAppStatus) final;
   NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement) final;
   NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) final;
 
   virtual bool IsOnCSSUnprefixingWhitelist() override { return false; }
 
   static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
 
-  struct OriginAttributes {
-    // NB: If you add any members here, you need to update Serialize/Deserialize
-    // and bump the CIDs of all the principal implementations that invoke those
-    // methods.
-    uint32_t mAppId;
-    bool mIsInBrowserElement;
+  struct OriginAttributes : public dom::OriginAttributesDictionary {
+    OriginAttributes() {}
+    OriginAttributes(uint32_t aAppId, bool aInBrowser)
+    {
+      mAppId = aAppId;
+      mInBrowser = aInBrowser;
+    }
 
-    OriginAttributes() : mAppId(nsIScriptSecurityManager::NO_APP_ID), mIsInBrowserElement(false) {}
-    OriginAttributes(uint32_t aAppId, bool aIsInBrowserElement)
-      : mAppId(aAppId), mIsInBrowserElement(aIsInBrowserElement) {}
     bool operator==(const OriginAttributes& aOther) const
     {
       return mAppId == aOther.mAppId &&
-             mIsInBrowserElement == aOther.mIsInBrowserElement;
+             mInBrowser == aOther.mInBrowser;
     }
     bool operator!=(const OriginAttributes& aOther) const
     {
       return !(*this == aOther);
     }
 
+    // Serializes 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);
+
     void Serialize(nsIObjectOutputStream* aStream) const;
     nsresult Deserialize(nsIObjectInputStream* aStream);
   };
 
   const OriginAttributes& OriginAttributesRef() { return mOriginAttributes; }
   uint32_t AppId() const { return mOriginAttributes.mAppId; }
-  bool IsInBrowserElement() const { return mOriginAttributes.mIsInBrowserElement; }
+  bool IsInBrowserElement() const { return mOriginAttributes.mInBrowser; }
 
 protected:
   virtual ~BasePrincipal() {}
 
   virtual bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsider) = 0;
 
   nsCOMPtr<nsIContentSecurityPolicy> mCSP;
   OriginAttributes mOriginAttributes;
--- a/caps/nsIPrincipal.idl
+++ b/caps/nsIPrincipal.idl
@@ -15,17 +15,17 @@ struct JSPrincipals;
 
 interface nsIURI;
 interface nsIContentSecurityPolicy;
 
 [ptr] native JSContext(JSContext);
 [ptr] native JSPrincipals(JSPrincipals);
 [ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
 
-[scriptable, builtinclass, uuid(7e024afa-afd4-48e7-ba11-1c7b9620b1b2)]
+[scriptable, builtinclass, uuid(74fb6760-4ae7-4ec7-8ac7-06817c60a93a)]
 interface nsIPrincipal : nsISerializable
 {
     /**
      * Returns whether the other principal is equivalent to this principal.
      * Principals are considered equal if they are the same principal, or
      * they have the same origin.
      */
     boolean equals(in nsIPrincipal other);
@@ -153,16 +153,47 @@ interface nsIPrincipal : nsISerializable
      *
      * The jarPrefix is intended to be an opaque identifier. It is currently
      * "human-readable" but no callers should assume it will stay as is and
      * it might be crypto-hashed at some point.
      */
     readonly attribute AUTF8String jarPrefix;
 
     /**
+     * A dictionary of the non-default origin attributes associated with this
+     * nsIPrincipal.
+     *
+     * Attributes are tokens that are taken into account when determining whether
+     * two principals are same-origin - if any attributes differ, the principals
+     * are cross-origin, even if the scheme, host, and port are the same.
+     * Attributes should also be considered for all security and bucketing decisions,
+     * even those which make non-standard comparisons (like cookies, which ignore
+     * scheme, or quotas, which ignore subdomains).
+     *
+     * If you're looking for an easy-to-use canonical stringification of the origin
+     * attributes, see |originSuffix| below.
+     */
+    [implicit_jscontext]
+    readonly attribute jsval originAttributes;
+
+    /**
+     * A string of the form !key1=value1&key2=value2, where each pair represents
+     * an attribute with a non-default value. If all attributes have default
+     * values, this is the empty string.
+     *
+     * The value of .originSuffix is automatically serialized into .origin, so any
+     * consumers using that are automatically origin-attribute-aware. Consumers with
+     * special requirements must inspect and compare .originSuffix manually.
+     *
+     * originsuffix are intended to be a replacement for jarPrefix, which will
+     * eventually be removed.
+     */
+    readonly attribute AUTF8String originSuffix;
+
+    /**
      * The base domain of the codebase URI to which this principal pertains
      * (generally the document URI), handling null principals and
      * non-hierarchical schemes correctly.
      */
     readonly attribute ACString baseDomain;
 
     const short APP_STATUS_NOT_INSTALLED = 0;
     const short APP_STATUS_INSTALLED     = 1;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/SystemDictionaries.webidl
@@ -0,0 +1,22 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+/*
+ * Used by principals and the script security manager to represent origin
+ * attributes.
+ *
+ * IMPORTANT: If you add any members here, you need to update the
+ * CreateSuffix, Serialize, and Deserialize implementations in BasePrincipal,
+ * and bump the CIDs of all the principal implementations that invoke those
+ * methods.
+ */
+dictionary OriginAttributesDictionary {
+  unsigned long appId = 0;
+  boolean inBrowser = false;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -504,16 +504,17 @@ WEBIDL_FILES = [
     'SVGTransformList.webidl',
     'SVGTSpanElement.webidl',
     'SVGUnitTypes.webidl',
     'SVGURIReference.webidl',
     'SVGUseElement.webidl',
     'SVGViewElement.webidl',
     'SVGZoomAndPan.webidl',
     'SVGZoomEvent.webidl',
+    'SystemDictionaries.webidl',
     'Telephony.webidl',
     'TelephonyCall.webidl',
     'TelephonyCallGroup.webidl',
     'TelephonyCallId.webidl',
     'Text.webidl',
     'TextDecoder.webidl',
     'TextEncoder.webidl',
     'TextTrack.webidl',