dom/xbl/nsXBLDocumentInfo.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "mozilla/DebugOnly.h"
     9 #include "nsXBLDocumentInfo.h"
    10 #include "nsIDocument.h"
    11 #include "nsXBLPrototypeBinding.h"
    12 #include "nsIScriptObjectPrincipal.h"
    13 #include "nsIScriptContext.h"
    14 #include "nsIDOMDocument.h"
    15 #include "nsIDOMScriptObjectFactory.h"
    16 #include "jsapi.h"
    17 #include "jsfriendapi.h"
    18 #include "nsIURI.h"
    19 #include "nsIConsoleService.h"
    20 #include "nsIScriptError.h"
    21 #include "nsIChromeRegistry.h"
    22 #include "nsIPrincipal.h"
    23 #include "nsJSPrincipals.h"
    24 #include "nsIScriptSecurityManager.h"
    25 #include "nsContentUtils.h"
    26 #include "nsCxPusher.h"
    27 #include "nsDOMJSUtils.h"
    28 #include "mozilla/Services.h"
    29 #include "xpcpublic.h"
    30 #include "mozilla/scache/StartupCache.h"
    31 #include "mozilla/scache/StartupCacheUtils.h"
    32 #include "nsCCUncollectableMarker.h"
    33 #include "mozilla/dom/BindingUtils.h"
    34 #include "mozilla/dom/URL.h"
    36 using namespace mozilla;
    37 using namespace mozilla::scache;
    38 using namespace mozilla::dom;
    40 static const char kXBLCachePrefix[] = "xblcache";
    42 /* Implementation file */
    44 static PLDHashOperator
    45 TraverseProtos(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
    46 {
    47   nsCycleCollectionTraversalCallback *cb =
    48     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
    49   aProto->Traverse(*cb);
    50   return PL_DHASH_NEXT;
    51 }
    53 static PLDHashOperator
    54 UnlinkProtoJSObjects(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
    55 {
    56   aProto->UnlinkJSObjects();
    57   return PL_DHASH_NEXT;
    58 }
    60 struct ProtoTracer
    61 {
    62   const TraceCallbacks &mCallbacks;
    63   void *mClosure;
    64 };
    66 static PLDHashOperator
    67 TraceProtos(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
    68 {
    69   ProtoTracer* closure = static_cast<ProtoTracer*>(aClosure);
    70   aProto->Trace(closure->mCallbacks, closure->mClosure);
    71   return PL_DHASH_NEXT;
    72 }
    74 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo)
    76 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLDocumentInfo)
    77   if (tmp->mBindingTable) {
    78     tmp->mBindingTable->EnumerateRead(UnlinkProtoJSObjects, nullptr);
    79   }
    80   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
    81 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    82 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLDocumentInfo)
    83   if (tmp->mDocument &&
    84       nsCCUncollectableMarker::InGeneration(cb, tmp->mDocument->GetMarkedCCGeneration())) {
    85     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
    86     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
    87   }
    88   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
    89   if (tmp->mBindingTable) {
    90     tmp->mBindingTable->EnumerateRead(TraverseProtos, &cb);
    91   }
    92   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
    93 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    94 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXBLDocumentInfo)
    95   if (tmp->mBindingTable) {
    96     ProtoTracer closure = { aCallbacks, aClosure };
    97     tmp->mBindingTable->EnumerateRead(TraceProtos, &closure);
    98   }
    99 NS_IMPL_CYCLE_COLLECTION_TRACE_END
   101 static void
   102 UnmarkXBLJSObject(void* aP, const char* aName, void* aClosure)
   103 {
   104   JS::ExposeObjectToActiveJS(static_cast<JSObject*>(aP));
   105 }
   107 static PLDHashOperator
   108 UnmarkProtos(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
   109 {
   110   aProto->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
   111   return PL_DHASH_NEXT;
   112 }
   114 void
   115 nsXBLDocumentInfo::MarkInCCGeneration(uint32_t aGeneration)
   116 {
   117   if (mDocument) {
   118     mDocument->MarkUncollectableForCCGeneration(aGeneration);
   119   }
   120   // Unmark any JS we hold
   121   if (mBindingTable) {
   122     mBindingTable->EnumerateRead(UnmarkProtos, nullptr);
   123   }
   124 }
   126 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLDocumentInfo)
   127   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   128   NS_INTERFACE_MAP_ENTRY(nsISupports)
   129 NS_INTERFACE_MAP_END
   131 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXBLDocumentInfo)
   132 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXBLDocumentInfo)
   134 nsXBLDocumentInfo::nsXBLDocumentInfo(nsIDocument* aDocument)
   135   : mDocument(aDocument),
   136     mScriptAccess(true),
   137     mIsChrome(false),
   138     mFirstBinding(nullptr)
   139 {
   140   nsIURI* uri = aDocument->GetDocumentURI();
   141   if (IsChromeURI(uri)) {
   142     // Cache whether or not this chrome XBL can execute scripts.
   143     nsCOMPtr<nsIXULChromeRegistry> reg =
   144       mozilla::services::GetXULChromeRegistryService();
   145     if (reg) {
   146       bool allow = true;
   147       reg->AllowScriptsForPackage(uri, &allow);
   148       mScriptAccess = allow;
   149     }
   150     mIsChrome = true;
   151   } else {
   152     // If this binding isn't running with system principal, then it's running
   153     // from a remote-XUL whitelisted domain. This is already a not-really-
   154     // supported configuration (among other things, we don't use XBL scopes in
   155     // that configuration for compatibility reasons). But we should still at
   156     // least make an effort to prevent binding code from running if content
   157     // script is disabled or if the source domain is blacklisted (since the
   158     // source domain for remote XBL must always be the same as the source domain
   159     // of the bound content).
   160     //
   161     // If we just ask the binding document if script is enabled, it will
   162     // discover that it has no inner window, and return false. So instead, we
   163     // short-circuit the normal compartment-managed script-disabling machinery,
   164     // and query the policy for the URI directly.
   165     bool allow;
   166     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   167     nsresult rv = ssm->PolicyAllowsScript(uri, &allow);
   168     mScriptAccess = NS_SUCCEEDED(rv) && allow;
   169   }
   170 }
   172 nsXBLDocumentInfo::~nsXBLDocumentInfo()
   173 {
   174   mozilla::DropJSObjects(this);
   175 }
   177 nsXBLPrototypeBinding*
   178 nsXBLDocumentInfo::GetPrototypeBinding(const nsACString& aRef)
   179 {
   180   if (!mBindingTable)
   181     return nullptr;
   183   if (aRef.IsEmpty()) {
   184     // Return our first binding
   185     return mFirstBinding;
   186   }
   188   return mBindingTable->Get(aRef);
   189 }
   191 nsresult
   192 nsXBLDocumentInfo::SetPrototypeBinding(const nsACString& aRef, nsXBLPrototypeBinding* aBinding)
   193 {
   194   if (!mBindingTable) {
   195     mBindingTable = new nsClassHashtable<nsCStringHashKey, nsXBLPrototypeBinding>();
   196     mozilla::HoldJSObjects(this);
   197   }
   199   NS_ENSURE_STATE(!mBindingTable->Get(aRef));
   200   mBindingTable->Put(aRef, aBinding);
   202   return NS_OK;
   203 }
   205 void
   206 nsXBLDocumentInfo::RemovePrototypeBinding(const nsACString& aRef)
   207 {
   208   if (mBindingTable) {
   209     nsAutoPtr<nsXBLPrototypeBinding> bindingToRemove;
   210     mBindingTable->RemoveAndForget(aRef, bindingToRemove);
   212     // We do not want to destroy the binding, so just forget it.
   213     bindingToRemove.forget();
   214   }
   215 }
   217 // Callback to enumerate over the bindings from this document and write them
   218 // out to the cache.
   219 static PLDHashOperator
   220 WriteBinding(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
   221 {
   222   aProto->Write((nsIObjectOutputStream*)aClosure);
   224   return PL_DHASH_NEXT;
   225 }
   227 // static
   228 nsresult
   229 nsXBLDocumentInfo::ReadPrototypeBindings(nsIURI* aURI, nsXBLDocumentInfo** aDocInfo)
   230 {
   231   *aDocInfo = nullptr;
   233   nsAutoCString spec(kXBLCachePrefix);
   234   nsresult rv = PathifyURI(aURI, spec);
   235   NS_ENSURE_SUCCESS(rv, rv);
   237   StartupCache* startupCache = StartupCache::GetSingleton();
   238   NS_ENSURE_TRUE(startupCache, NS_ERROR_FAILURE);
   240   nsAutoArrayPtr<char> buf;
   241   uint32_t len;
   242   rv = startupCache->GetBuffer(spec.get(), getter_Transfers(buf), &len);
   243   // GetBuffer will fail if the binding is not in the cache.
   244   if (NS_FAILED(rv))
   245     return rv;
   247   nsCOMPtr<nsIObjectInputStream> stream;
   248   rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(stream));
   249   NS_ENSURE_SUCCESS(rv, rv);
   250   buf.forget();
   252   // The file compatibility.ini stores the build id. This is checked in
   253   // nsAppRunner.cpp and will delete the cache if a different build is
   254   // present. However, we check that the version matches here to be safe. 
   255   uint32_t version;
   256   rv = stream->Read32(&version);
   257   NS_ENSURE_SUCCESS(rv, rv);
   258   if (version != XBLBinding_Serialize_Version) {
   259     // The version that exists is different than expected, likely created with a
   260     // different build, so invalidate the cache.
   261     startupCache->InvalidateCache();
   262     return NS_ERROR_NOT_AVAILABLE;
   263   }
   265   nsCOMPtr<nsIPrincipal> principal;
   266   nsContentUtils::GetSecurityManager()->
   267     GetSystemPrincipal(getter_AddRefs(principal));
   269   nsCOMPtr<nsIDOMDocument> domdoc;
   270   rv = NS_NewXBLDocument(getter_AddRefs(domdoc), aURI, nullptr, principal);
   271   NS_ENSURE_SUCCESS(rv, rv);
   273   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
   274   NS_ASSERTION(doc, "Must have a document!");
   275   nsRefPtr<nsXBLDocumentInfo> docInfo = new nsXBLDocumentInfo(doc);
   277   while (1) {
   278     uint8_t flags;
   279     nsresult rv = stream->Read8(&flags);
   280     NS_ENSURE_SUCCESS(rv, rv);
   281     if (flags == XBLBinding_Serialize_NoMoreBindings)
   282       break;
   284     rv = nsXBLPrototypeBinding::ReadNewBinding(stream, docInfo, doc, flags);
   285     if (NS_FAILED(rv)) {
   286       return rv;
   287     }
   288   }
   290   docInfo.swap(*aDocInfo);
   291   return NS_OK;
   292 }
   294 nsresult
   295 nsXBLDocumentInfo::WritePrototypeBindings()
   296 {
   297   // Only write out bindings with the system principal
   298   if (!nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal()))
   299     return NS_OK;
   301   nsAutoCString spec(kXBLCachePrefix);
   302   nsresult rv = PathifyURI(DocumentURI(), spec);
   303   NS_ENSURE_SUCCESS(rv, rv);
   305   StartupCache* startupCache = StartupCache::GetSingleton();
   306   NS_ENSURE_TRUE(startupCache, rv);
   308   nsCOMPtr<nsIObjectOutputStream> stream;
   309   nsCOMPtr<nsIStorageStream> storageStream;
   310   rv = NewObjectOutputWrappedStorageStream(getter_AddRefs(stream),
   311                                            getter_AddRefs(storageStream),
   312                                            true);
   313   NS_ENSURE_SUCCESS(rv, rv);
   315   rv = stream->Write32(XBLBinding_Serialize_Version);
   316   NS_ENSURE_SUCCESS(rv, rv);
   318   if (mBindingTable) {
   319     mBindingTable->EnumerateRead(WriteBinding, stream);
   320   }
   322   // write a end marker at the end
   323   rv = stream->Write8(XBLBinding_Serialize_NoMoreBindings);
   324   NS_ENSURE_SUCCESS(rv, rv);
   326   stream->Close();
   327   NS_ENSURE_SUCCESS(rv, rv);
   329   uint32_t len;
   330   nsAutoArrayPtr<char> buf;
   331   rv = NewBufferFromStorageStream(storageStream, getter_Transfers(buf), &len);
   332   NS_ENSURE_SUCCESS(rv, rv);
   334   return startupCache->PutBuffer(spec.get(), buf, len);
   335 }
   337 void
   338 nsXBLDocumentInfo::SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding)
   339 {
   340   mFirstBinding = aBinding;
   341 }
   343 static PLDHashOperator
   344 FlushScopedSkinSheets(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
   345 {
   346   aProto->FlushSkinSheets();
   347   return PL_DHASH_NEXT;
   348 }
   350 void
   351 nsXBLDocumentInfo::FlushSkinStylesheets()
   352 {
   353   if (mBindingTable) {
   354     mBindingTable->EnumerateRead(FlushScopedSkinSheets, nullptr);
   355   }
   356 }
   358 #ifdef DEBUG
   359 void
   360 AssertInCompilationScope()
   361 {
   362   AutoJSContext cx;
   363   // Note - Inverting the order of these operands is a rooting hazard.
   364   MOZ_ASSERT(xpc::GetCompilationScope() == JS::CurrentGlobalOrNull(cx));
   365 }
   366 #endif

mercurial