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
authorbzbarsky@mit.edu
Mon, 17 Sep 2007 15:18:28 -0700
changeset 6004 5c4a24b11b871c519a72c4378f4225c886444cd8
parent 6003 21a52cfb4a7942d9d4b020f9b8c84a220160c5ec
child 6005 3259f85aa0ab0e97a992acfe437d9e73c0137d91
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdveditz, jst, jst
bugs369566
milestone1.9a8pre
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
caps/src/nsPrincipal.cpp
content/xul/document/public/nsIXULPrototypeCache.h
--- a/caps/include/nsPrincipal.h
+++ b/caps/include/nsPrincipal.h
@@ -40,16 +40,18 @@
 #ifndef nsPrincipal_h__
 #define nsPrincipal_h__
 
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsVoidArray.h"
 #include "nsHashtable.h"
 #include "nsJSPrincipals.h"
+#include "nsTArray.h"
+#include "nsAutoPtr.h"
 
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 
 class nsPrincipal : public nsIPrincipal
 {
 public:
   nsPrincipal();
@@ -95,17 +97,17 @@ public:
   void SetURI(nsIURI *aURI);
   nsresult SetCapability(const char *capability, void **annotation, 
                          AnnotationValue value);
 
   static const char sInvalid[];
 
 protected:
   nsJSPrincipals mJSPrincipals;
-  nsVoidArray mAnnotations;
+  nsTArray< nsAutoPtr<nsHashtable> > mAnnotations;
   nsHashtable mCapabilities;
   nsCString mPrefName;
   static PRInt32 sCapabilitiesOrdinal;
 
   // XXXcaa This is a semi-hack.  The best solution here is to keep
   // a reference to an interface here, except there is no interface
   // that we can use yet.
   struct Certificate
--- a/caps/src/nsPrincipal.cpp
+++ b/caps/src/nsPrincipal.cpp
@@ -145,28 +145,18 @@ nsPrincipal::Init(const nsACString& aCer
     }
   }
 
   NS_ASSERTION(NS_SUCCEEDED(rv), "nsPrincipal::Init() failed");
 
   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); 
 }
 
 NS_IMETHODIMP
 nsPrincipal::GetJSPrincipals(JSContext *cx, JSPrincipals **jsprin)
 {
   NS_PRECONDITION(mJSPrincipals.nsIPrincipalPtr, "mJSPrincipals is uninitialized!");
 
@@ -481,33 +471,39 @@ nsPrincipal::RevertCapability(const char
   return NS_OK;
 }
 
 nsresult
 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;
   for(;;) {
     const char *space = PL_strchr(start, ' ');
     int len = space ? space - start : strlen(start);
     nsCAutoString capString(start, len);
     nsCStringKey key(capString);
-    nsHashtable *ht = (nsHashtable *) *annotation;
+    nsHashtable *ht = static_cast<nsHashtable *>(*annotation);
     ht->Put(&key, (void *) value);
     if (!space) {
       break;
     }
 
     start = space + 1;
   }
 
@@ -668,17 +664,17 @@ nsPrincipal::InitFromPersistent(const ch
                                 const char* aGrantedList,
                                 const char* aDeniedList,
                                 nsISupports* aCert,
                                 PRBool aIsCert,
                                 PRBool aTrusted)
 {
   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?");
 
   mInitialized = PR_TRUE;
 
   nsresult rv;
   if (aIsCert) {
     rv = SetCertificate(aToken, aSubjectName, aPrettyName, aCert);
@@ -906,97 +902,182 @@ FreeAnnotationEntry(nsIObjectInputStream
                     void* aData)
 {
   delete 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<void*>(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)) {
     return rv;
   }
 
   rv = NS_ReadOptionalCString(aStream, mPrefName);
   if (NS_FAILED(rv)) {
     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<nsISupports> 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<nsIURI> 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<nsIURI> 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;
 }
 
 PR_STATIC_CALLBACK(nsresult)
 WriteScalarValue(nsIObjectOutputStream* aStream, void* aData)
 {
   PRUint32 value = NS_PTR_TO_INT32(aData);
 
   return aStream->Write32(value);
 }
 
 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<nsHashtable *>(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);
   }
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   rv = NS_WriteOptionalStringZ(aStream, mPrefName.get());
   if (NS_FAILED(rv)) {
     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;
 }
--- a/content/xul/document/public/nsIXULPrototypeCache.h
+++ b/content/xul/document/public/nsIXULPrototypeCache.h
@@ -77,15 +77,15 @@ NS_NewXULPrototypeCache(nsISupports* aOu
 
 
 const char XUL_FASTLOAD_FILE_BASENAME[] = "XUL";
 
 // Increase the subtractor when changing version, say when changing the
 // (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)
 
 
 #endif // nsIXULPrototypeCache_h__