toolkit/components/finalizationwitness/FinalizationWitnessService.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "FinalizationWitnessService.h"
     7 #include "nsString.h"
     8 #include "jsapi.h"
     9 #include "js/CallNonGenericMethod.h"
    10 #include "mozJSComponentLoader.h"
    11 #include "nsZipArchive.h"
    13 #include "mozilla/Scoped.h"
    14 #include "mozilla/Services.h"
    15 #include "mozilla/NullPtr.h"
    16 #include "nsIObserverService.h"
    17 #include "nsThreadUtils.h"
    20 // Implementation of nsIFinalizationWitnessService
    22 namespace mozilla {
    24 namespace {
    26 /**
    27  * An event meant to be dispatched to the main thread upon finalization
    28  * of a FinalizationWitness, unless method |forget()| has been called.
    29  *
    30  * Held as private data by each instance of FinalizationWitness.
    31  * Important note: we maintain the invariant that these private data
    32  * slots are already addrefed.
    33  */
    34 class FinalizationEvent MOZ_FINAL: public nsRunnable
    35 {
    36 public:
    37   FinalizationEvent(const char* aTopic,
    38                   const jschar* aValue)
    39     : mTopic(aTopic)
    40     , mValue(aValue)
    41   { }
    43   NS_METHOD Run() {
    44     nsCOMPtr<nsIObserverService> observerService =
    45       mozilla::services::GetObserverService();
    46     if (!observerService) {
    47       // This is either too early or, more likely, too late for notifications.
    48       // Bail out.
    49       return NS_ERROR_NOT_AVAILABLE;
    50     }
    51     (void)observerService->
    52       NotifyObservers(nullptr, mTopic.get(), mValue.get());
    53     return NS_OK;
    54   }
    55 private:
    56   /**
    57    * The topic on which to broadcast the notification of finalization.
    58    *
    59    * Deallocated on the main thread.
    60    */
    61   const nsCString mTopic;
    63   /**
    64    * The result of converting the exception to a string.
    65    *
    66    * Deallocated on the main thread.
    67    */
    68   const nsString mValue;
    69 };
    71 enum {
    72   WITNESS_SLOT_EVENT,
    73   WITNESS_INSTANCES_SLOTS
    74 };
    76 /**
    77  * Extract the FinalizationEvent from an instance of FinalizationWitness
    78  * and clear the slot containing the FinalizationEvent.
    79  */
    80 already_AddRefed<FinalizationEvent>
    81 ExtractFinalizationEvent(JSObject *objSelf)
    82 {
    83   JS::Value slotEvent = JS_GetReservedSlot(objSelf, WITNESS_SLOT_EVENT);
    84   if (slotEvent.isUndefined()) {
    85     // Forget() has been called
    86     return nullptr;
    87   }
    89   JS_SetReservedSlot(objSelf, WITNESS_SLOT_EVENT, JS::UndefinedValue());
    91   return dont_AddRef(static_cast<FinalizationEvent*>(slotEvent.toPrivate()));
    92 }
    94 /**
    95  * Finalizer for instances of FinalizationWitness.
    96  *
    97  * Unless method Forget() has been called, the finalizer displays an error
    98  * message.
    99  */
   100 void Finalize(JSFreeOp *fop, JSObject *objSelf)
   101 {
   102   nsRefPtr<FinalizationEvent> event = ExtractFinalizationEvent(objSelf);
   103   if (event == nullptr) {
   104     // Forget() has been called
   105     return;
   106   }
   108   // Notify observers. Since we are executed during garbage-collection,
   109   // we need to dispatch the notification to the main thread.
   110   (void)NS_DispatchToMainThread(event);
   111   // We may fail at dispatching to the main thread if we arrive too late
   112   // during shutdown. In that case, there is not much we can do.
   113 }
   115 static const JSClass sWitnessClass = {
   116   "FinalizationWitness",
   117   JSCLASS_HAS_RESERVED_SLOTS(WITNESS_INSTANCES_SLOTS),
   118   JS_PropertyStub /* addProperty */,
   119   JS_DeletePropertyStub /* delProperty */,
   120   JS_PropertyStub /* getProperty */,
   121   JS_StrictPropertyStub /* setProperty */,
   122   JS_EnumerateStub /* enumerate */,
   123   JS_ResolveStub /* resolve */,
   124   JS_ConvertStub /* convert */,
   125   Finalize /* finalize */
   126 };
   128 bool IsWitness(JS::Handle<JS::Value> v)
   129 {
   130   return v.isObject() && JS_GetClass(&v.toObject()) == &sWitnessClass;
   131 }
   134 /**
   135  * JS method |forget()|
   136  *
   137  * === JS documentation
   138  *
   139  *  Neutralize the witness. Once this method is called, the witness will
   140  *  never report any error.
   141  */
   142 bool ForgetImpl(JSContext* cx, JS::CallArgs args)
   143 {
   144   if (args.length() != 0) {
   145     JS_ReportError(cx, "forget() takes no arguments");
   146     return false;
   147   }
   148   JS::Rooted<JS::Value> valSelf(cx, args.thisv());
   149   JS::Rooted<JSObject*> objSelf(cx, &valSelf.toObject());
   151   nsRefPtr<FinalizationEvent> event = ExtractFinalizationEvent(objSelf);
   152   if (event == nullptr) {
   153     JS_ReportError(cx, "forget() called twice");
   154     return false;
   155   }
   157   args.rval().setUndefined();
   158   return true;
   159 }
   161 bool Forget(JSContext *cx, unsigned argc, JS::Value *vp)
   162 {
   163   JS::CallArgs args = CallArgsFromVp(argc, vp);
   164   return JS::CallNonGenericMethod<IsWitness, ForgetImpl>(cx, args);
   165 }
   167 static const JSFunctionSpec sWitnessClassFunctions[] = {
   168   JS_FN("forget", Forget, 0, JSPROP_READONLY | JSPROP_PERMANENT),
   169   JS_FS_END
   170 };
   172 }
   174 NS_IMPL_ISUPPORTS(FinalizationWitnessService, nsIFinalizationWitnessService)
   176 /**
   177  * Create a new Finalization Witness.
   178  *
   179  * A finalization witness is an object whose sole role is to notify
   180  * observers when it is gc-ed. Once the witness is created, call its
   181  * method |forget()| to prevent the observers from being notified.
   182  *
   183  * @param aTopic The notification topic.
   184  * @param aValue The notification value. Converted to a string.
   185  *
   186  * @constructor
   187  */
   188 NS_IMETHODIMP
   189 FinalizationWitnessService::Make(const char* aTopic,
   190                                  const char16_t* aValue,
   191                                  JSContext* aCx,
   192                                  JS::MutableHandle<JS::Value> aRetval)
   193 {
   194   JS::Rooted<JSObject*> objResult(aCx, JS_NewObject(aCx, &sWitnessClass, JS::NullPtr(),
   195                                                     JS::NullPtr()));
   196   if (!objResult) {
   197     return NS_ERROR_OUT_OF_MEMORY;
   198   }
   199   if (!JS_DefineFunctions(aCx, objResult, sWitnessClassFunctions)) {
   200     return NS_ERROR_FAILURE;
   201   }
   203   nsRefPtr<FinalizationEvent> event = new FinalizationEvent(aTopic, aValue);
   205   // Transfer ownership of the addrefed |event| to |objResult|.
   206   JS_SetReservedSlot(objResult, WITNESS_SLOT_EVENT,
   207                      JS::PrivateValue(event.forget().take()));
   209   aRetval.setObject(*objResult);
   210   return NS_OK;
   211 }
   213 } // namespace mozilla

mercurial