Bug 1165162 - Make OriginAttributes a dictionary, and make it accessible as both a jsval and a canonical string. r=gabor,r=bholley,sr=sicking
--- 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',