Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* vim:set st=2 sts=2 ts=2 et cin: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsIObserverService.h"
7 #include "mozilla/Services.h"
8 #include "nsISupportsPrimitives.h"
9 #include "nsIStringEnumerator.h"
11 #include "nsXPCOMCID.h"
13 #include "nsCategoryCache.h"
15 nsCategoryObserver::nsCategoryObserver(const char* aCategory)
16 : mCategory(aCategory)
17 , mObserversRemoved(false)
18 {
19 // First, enumerate the currently existing entries
20 nsCOMPtr<nsICategoryManager> catMan =
21 do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
22 if (!catMan)
23 return;
25 nsCOMPtr<nsISimpleEnumerator> enumerator;
26 nsresult rv = catMan->EnumerateCategory(aCategory,
27 getter_AddRefs(enumerator));
28 if (NS_FAILED(rv))
29 return;
31 nsCOMPtr<nsIUTF8StringEnumerator> strings = do_QueryInterface(enumerator);
32 MOZ_ASSERT(strings);
34 bool more;
35 while (NS_SUCCEEDED(strings->HasMore(&more)) && more) {
36 nsAutoCString entryName;
37 strings->GetNext(entryName);
39 nsCString entryValue;
40 rv = catMan->GetCategoryEntry(aCategory,
41 entryName.get(),
42 getter_Copies(entryValue));
43 if (NS_SUCCEEDED(rv)) {
44 nsCOMPtr<nsISupports> service = do_GetService(entryValue.get());
45 if (service) {
46 mHash.Put(entryName, service);
47 }
48 }
49 }
51 // Now, listen for changes
52 nsCOMPtr<nsIObserverService> serv =
53 mozilla::services::GetObserverService();
54 if (serv) {
55 serv->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
56 serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, false);
57 serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID, false);
58 serv->AddObserver(this, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID, false);
59 }
60 }
62 nsCategoryObserver::~nsCategoryObserver() {
63 }
65 NS_IMPL_ISUPPORTS(nsCategoryObserver, nsIObserver)
67 void
68 nsCategoryObserver::ListenerDied() {
69 RemoveObservers();
70 }
72 void
73 nsCategoryObserver::RemoveObservers() {
74 if (mObserversRemoved)
75 return;
77 mObserversRemoved = true;
78 nsCOMPtr<nsIObserverService> obsSvc =
79 mozilla::services::GetObserverService();
80 if (obsSvc) {
81 obsSvc->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
82 obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID);
83 obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID);
84 obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID);
85 }
86 }
88 NS_IMETHODIMP
89 nsCategoryObserver::Observe(nsISupports* aSubject, const char* aTopic,
90 const char16_t* aData) {
91 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
92 mHash.Clear();
93 RemoveObservers();
95 return NS_OK;
96 }
98 if (!aData ||
99 !nsDependentString(aData).Equals(NS_ConvertASCIItoUTF16(mCategory)))
100 return NS_OK;
102 nsAutoCString str;
103 nsCOMPtr<nsISupportsCString> strWrapper(do_QueryInterface(aSubject));
104 if (strWrapper)
105 strWrapper->GetData(str);
107 if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID) == 0) {
108 // We may get an add notification even when we already have an entry. This
109 // is due to the notification happening asynchronously, so if the entry gets
110 // added and an nsCategoryObserver gets instantiated before events get
111 // processed, we'd get the notification for an existing entry.
112 // Do nothing in that case.
113 if (mHash.GetWeak(str))
114 return NS_OK;
116 nsCOMPtr<nsICategoryManager> catMan =
117 do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
118 if (!catMan)
119 return NS_OK;
121 nsCString entryValue;
122 catMan->GetCategoryEntry(mCategory.get(),
123 str.get(),
124 getter_Copies(entryValue));
126 nsCOMPtr<nsISupports> service = do_GetService(entryValue.get());
128 if (service) {
129 mHash.Put(str, service);
130 }
131 } else if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID) == 0) {
132 mHash.Remove(str);
133 } else if (strcmp(aTopic, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID) == 0) {
134 mHash.Clear();
135 }
136 return NS_OK;
137 }