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.

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

mercurial