Sat, 03 Jan 2015 20:18:00 +0100
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 |