From 5983f838e4a82e6a3e99695c8068c54339c7a6b0 Mon Sep 17 00:00:00 2001 From: "bzbarsky@mit.edu" Date: Mon, 17 Sep 2007 15:18:28 -0700 Subject: [PATCH] Make the nsISerializable implementation of nsPrincipal actually work. This makes it possible to save principal objects to a stream and read them back. Bug 369566, r=dveditz+brendan, sr=jst, a=jst --- caps/include/nsPrincipal.h | 4 +- caps/src/nsPrincipal.cpp | 203 ++++++++++++------ .../document/public/nsIXULPrototypeCache.h | 2 +- 3 files changed, 146 insertions(+), 63 deletions(-) diff --git a/caps/include/nsPrincipal.h b/caps/include/nsPrincipal.h index 26f64c065d02..2f0c599aa17c 100755 --- a/caps/include/nsPrincipal.h +++ b/caps/include/nsPrincipal.h @@ -45,6 +45,8 @@ #include "nsVoidArray.h" #include "nsHashtable.h" #include "nsJSPrincipals.h" +#include "nsTArray.h" +#include "nsAutoPtr.h" class nsIObjectInputStream; class nsIObjectOutputStream; @@ -100,7 +102,7 @@ public: protected: nsJSPrincipals mJSPrincipals; - nsVoidArray mAnnotations; + nsTArray< nsAutoPtr > mAnnotations; nsHashtable mCapabilities; nsCString mPrefName; static PRInt32 sCapabilitiesOrdinal; diff --git a/caps/src/nsPrincipal.cpp b/caps/src/nsPrincipal.cpp index b6d5b8ac8d6d..05b68c5cb373 100755 --- a/caps/src/nsPrincipal.cpp +++ b/caps/src/nsPrincipal.cpp @@ -150,18 +150,8 @@ nsPrincipal::Init(const nsACString& aCertFingerprint, return rv; } - -PR_STATIC_CALLBACK(PRBool) -deleteElement(void* aElement, void *aData) -{ - nsHashtable *ht = (nsHashtable *) aElement; - delete ht; - return PR_TRUE; -} - nsPrincipal::~nsPrincipal(void) { - mAnnotations.EnumerateForwards(deleteElement, nsnull); SetSecurityPolicy(nsnull); } @@ -486,14 +476,20 @@ nsPrincipal::SetCapability(const char *capability, void **annotation, AnnotationValue value) { if (*annotation == nsnull) { - *annotation = new nsHashtable(5); - if (!*annotation) { + nsHashtable* ht = new nsHashtable(5); + + if (!ht) { return NS_ERROR_OUT_OF_MEMORY; } // This object owns its annotations. Save them so we can release // them when we destroy this object. - mAnnotations.AppendElement(*annotation); + if (!mAnnotations.AppendElement(ht)) { + delete ht; + return NS_ERROR_OUT_OF_MEMORY; + } + + *annotation = ht; } const char *start = capability; @@ -502,7 +498,7 @@ nsPrincipal::SetCapability(const char *capability, void **annotation, int len = space ? space - start : strlen(start); nsCAutoString capString(start, len); nsCStringKey key(capString); - nsHashtable *ht = (nsHashtable *) *annotation; + nsHashtable *ht = static_cast(*annotation); ht->Put(&key, (void *) value); if (!space) { break; @@ -673,7 +669,7 @@ nsPrincipal::InitFromPersistent(const char* aPrefName, { NS_PRECONDITION(mCapabilities.Count() == 0, "mCapabilities was already initialized?"); - NS_PRECONDITION(mAnnotations.Count() == 0, + NS_PRECONDITION(mAnnotations.Length() == 0, "mAnnotations was already initialized?"); NS_PRECONDITION(!mInitialized, "We were already initialized?"); @@ -911,39 +907,15 @@ FreeAnnotationEntry(nsIObjectInputStream* aStream, nsHashKey* aKey, NS_IMETHODIMP nsPrincipal::Read(nsIObjectInputStream* aStream) { - PRUint32 annotationCount; - nsresult rv = aStream->Read32(&annotationCount); - if (NS_FAILED(rv)) { - return rv; - } - - for (PRInt32 i = 0, n = PRInt32(annotationCount); i < n; i++) { - nsHashtable *ht = new nsHashtable(aStream, - ReadAnnotationEntry, - FreeAnnotationEntry, - &rv); - if (!ht) { - return NS_ERROR_OUT_OF_MEMORY; - } - - if (NS_FAILED(rv)) { - delete ht; - return rv; - } - - if (!mAnnotations.InsertElementAt(reinterpret_cast(ht), i)) { - delete ht; - return NS_ERROR_OUT_OF_MEMORY; - } - } - PRBool hasCapabilities; - rv = aStream->ReadBoolean(&hasCapabilities); + nsresult rv = aStream->ReadBoolean(&hasCapabilities); if (NS_SUCCEEDED(rv) && hasCapabilities) { - mCapabilities = nsHashtable(aStream, - ReadAnnotationEntry, - FreeAnnotationEntry, - &rv); + // We want to use one of the nsHashtable constructors, but don't want to + // generally have mCapabilities be a pointer... and nsHashtable has no + // reasonable copy-constructor. Placement-new to the rescue! + mCapabilities.~nsHashtable(); + new (&mCapabilities) nsHashtable(aStream, ReadAnnotationEntry, + FreeAnnotationEntry, &rv); } if (NS_FAILED(rv)) { @@ -955,6 +927,68 @@ nsPrincipal::Read(nsIObjectInputStream* aStream) return rv; } + const char* ordinalBegin = PL_strpbrk(mPrefName.get(), "1234567890"); + if (ordinalBegin) { + PRIntn n = atoi(ordinalBegin); + if (sCapabilitiesOrdinal <= n) { + sCapabilitiesOrdinal = n + 1; + } + } + + PRBool haveCert; + rv = aStream->ReadBoolean(&haveCert); + if (NS_FAILED(rv)) { + return rv; + } + + nsCString fingerprint; + nsCString subjectName; + nsCString prettyName; + nsCOMPtr cert; + if (haveCert) { + rv = NS_ReadOptionalCString(aStream, fingerprint); + if (NS_FAILED(rv)) { + return rv; + } + + rv = NS_ReadOptionalCString(aStream, subjectName); + if (NS_FAILED(rv)) { + return rv; + } + + rv = NS_ReadOptionalCString(aStream, prettyName); + if (NS_FAILED(rv)) { + return rv; + } + + rv = aStream->ReadObject(PR_TRUE, getter_AddRefs(cert)); + if (NS_FAILED(rv)) { + return rv; + } + } + + nsCOMPtr codebase; + rv = NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(codebase)); + if (NS_FAILED(rv)) { + return rv; + } + + rv = Init(fingerprint, subjectName, prettyName, cert, codebase); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr domain; + rv = NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(domain)); + if (NS_FAILED(rv)) { + return rv; + } + + SetDomain(domain); + + rv = aStream->Read8(&mTrusted); + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; } @@ -969,22 +1003,13 @@ WriteScalarValue(nsIObjectOutputStream* aStream, void* aData) NS_IMETHODIMP nsPrincipal::Write(nsIObjectOutputStream* aStream) { - PRUint32 annotationCount = PRUint32(mAnnotations.Count()); - nsresult rv = aStream->Write32(annotationCount); - if (NS_FAILED(rv)) { - return rv; - } - - for (PRInt32 i = 0, n = PRInt32(annotationCount); i < n; i++) { - nsHashtable *ht = reinterpret_cast(mAnnotations[i]); - rv = ht->Write(aStream, WriteScalarValue); - if (NS_FAILED(rv)) { - return rv; - } - } - + NS_ENSURE_STATE(mCert || mCodebase); + + // mAnnotations is transient data associated to specific JS stack frames. We + // don't want to serialize that. + PRBool hasCapabilities = (mCapabilities.Count() > 0); - rv = aStream->WriteBoolean(hasCapabilities); + nsresult rv = aStream->WriteBoolean(hasCapabilities); if (NS_SUCCEEDED(rv) && hasCapabilities) { rv = mCapabilities.Write(aStream, WriteScalarValue); } @@ -998,5 +1023,61 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream) return rv; } + rv = aStream->WriteBoolean(mCert != nsnull); + if (NS_FAILED(rv)) { + return rv; + } + + if (mCert) { + NS_ENSURE_STATE(mCert->cert); + + rv = NS_WriteOptionalStringZ(aStream, mCert->fingerprint.get()); + if (NS_FAILED(rv)) { + return rv; + } + + rv = NS_WriteOptionalStringZ(aStream, mCert->subjectName.get()); + if (NS_FAILED(rv)) { + return rv; + } + + rv = NS_WriteOptionalStringZ(aStream, mCert->prettyName.get()); + if (NS_FAILED(rv)) { + return rv; + } + + rv = aStream->WriteCompoundObject(mCert->cert, NS_GET_IID(nsISupports), + PR_TRUE); + if (NS_FAILED(rv)) { + return rv; + } + } + + // mSecurityPolicy is an optimization; it'll get looked up again as needed. + // Don't bother saving and restoring it, esp. since it might change if + // preferences change. + + rv = NS_WriteOptionalCompoundObject(aStream, mCodebase, NS_GET_IID(nsIURI), + PR_TRUE); + if (NS_FAILED(rv)) { + return rv; + } + + rv = NS_WriteOptionalCompoundObject(aStream, mDomain, NS_GET_IID(nsIURI), + PR_TRUE); + if (NS_FAILED(rv)) { + return rv; + } + + // mOrigin is an optimization; don't bother serializing it. + + rv = aStream->Write8(mTrusted); + if (NS_FAILED(rv)) { + return rv; + } + + // mCodebaseImmutable and mDomainImmutable will be recomputed based + // on the deserialized URIs in Read(). + return NS_OK; } diff --git a/content/xul/document/public/nsIXULPrototypeCache.h b/content/xul/document/public/nsIXULPrototypeCache.h index 14cd85489ab0..fd9d41d73323 100644 --- a/content/xul/document/public/nsIXULPrototypeCache.h +++ b/content/xul/document/public/nsIXULPrototypeCache.h @@ -82,7 +82,7 @@ const char XUL_FASTLOAD_FILE_BASENAME[] = "XUL"; // (opaque to XPCOM FastLoad code) format of XUL-specific XDR serializations. // See also JSXDR_BYTECODE_VERSION in jsxdrapi.h, which tracks incompatible JS // bytecode version changes. -#define XUL_FASTLOAD_FILE_VERSION (0xfeedbeef - 22) +#define XUL_FASTLOAD_FILE_VERSION (0xfeedbeef - 23) #define XUL_SERIALIZATION_BUFFER_SIZE (64 * 1024) #define XUL_DESERIALIZATION_BUFFER_SIZE (8 * 1024)