1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Mozilla Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Neil Deakin <enndeakin@sympatico.ca>
24 : * Honza Bambas <honzab@firemni.cz>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsCOMPtr.h"
41 : #include "nsDOMError.h"
42 : #include "nsDOMStorage.h"
43 : #include "nsDOMStorageMemoryDB.h"
44 : #include "nsNetUtil.h"
45 :
46 : nsresult
47 78 : nsDOMStorageMemoryDB::Init(nsDOMStoragePersistentDB* aPreloadDB)
48 : {
49 78 : if (!mData.Init(20))
50 0 : return NS_ERROR_OUT_OF_MEMORY;
51 :
52 78 : mPreloadDB = aPreloadDB;
53 78 : return NS_OK;
54 : }
55 :
56 : static PLDHashOperator
57 0 : AllKeyEnum(nsSessionStorageEntry* aEntry, void* userArg)
58 : {
59 : nsDOMStorageMemoryDB::nsStorageItemsTable *target =
60 0 : (nsDOMStorageMemoryDB::nsStorageItemsTable *)userArg;
61 :
62 : nsDOMStorageMemoryDB::nsInMemoryItem* item =
63 0 : new nsDOMStorageMemoryDB::nsInMemoryItem();
64 0 : if (!item)
65 0 : return PL_DHASH_STOP;
66 :
67 0 : aEntry->mItem->GetValue(item->mValue);
68 0 : nsresult rv = aEntry->mItem->GetSecure(&item->mSecure);
69 0 : if (NS_FAILED(rv))
70 0 : item->mSecure = false;
71 :
72 0 : target->Put(aEntry->GetKey(), item);
73 0 : return PL_DHASH_NEXT;
74 : }
75 :
76 : nsresult
77 0 : nsDOMStorageMemoryDB::GetItemsTable(DOMStorageImpl* aStorage,
78 : nsInMemoryStorage** aMemoryStorage)
79 : {
80 0 : if (mData.Get(aStorage->GetScopeDBKey(), aMemoryStorage))
81 0 : return NS_OK;
82 :
83 0 : *aMemoryStorage = nsnull;
84 :
85 0 : nsInMemoryStorage* storageData = new nsInMemoryStorage();
86 0 : if (!storageData)
87 0 : return NS_ERROR_OUT_OF_MEMORY;
88 :
89 0 : if (!storageData->mTable.Init()) {
90 0 : delete storageData;
91 0 : return NS_ERROR_OUT_OF_MEMORY;
92 : }
93 :
94 0 : if (mPreloadDB) {
95 : nsresult rv;
96 :
97 0 : nsTHashtable<nsSessionStorageEntry> keys;
98 0 : keys.Init();
99 :
100 0 : rv = mPreloadDB->GetAllKeys(aStorage, &keys);
101 0 : NS_ENSURE_SUCCESS(rv, rv);
102 :
103 0 : mPreloading = true;
104 0 : keys.EnumerateEntries(AllKeyEnum, &storageData->mTable);
105 0 : mPreloading = false;
106 : }
107 :
108 0 : mData.Put(aStorage->GetScopeDBKey(), storageData);
109 0 : *aMemoryStorage = storageData;
110 :
111 0 : return NS_OK;
112 : }
113 :
114 : struct GetAllKeysEnumStruc
115 : {
116 : nsTHashtable<nsSessionStorageEntry>* mTarget;
117 : DOMStorageImpl* mStorage;
118 : };
119 :
120 : static PLDHashOperator
121 0 : GetAllKeysEnum(const nsAString& keyname,
122 : nsDOMStorageMemoryDB::nsInMemoryItem* item,
123 : void *closure)
124 : {
125 0 : GetAllKeysEnumStruc* struc = (GetAllKeysEnumStruc*)closure;
126 :
127 0 : nsSessionStorageEntry* entry = struc->mTarget->PutEntry(keyname);
128 0 : if (!entry)
129 0 : return PL_DHASH_STOP;
130 :
131 : entry->mItem = new nsDOMStorageItem(struc->mStorage,
132 : keyname,
133 0 : EmptyString(),
134 0 : item->mSecure);
135 0 : if (!entry->mItem)
136 0 : return PL_DHASH_STOP;
137 :
138 0 : return PL_DHASH_NEXT;
139 : }
140 :
141 : nsresult
142 0 : nsDOMStorageMemoryDB::GetAllKeys(DOMStorageImpl* aStorage,
143 : nsTHashtable<nsSessionStorageEntry>* aKeys)
144 : {
145 : nsresult rv;
146 :
147 : nsInMemoryStorage* storage;
148 0 : rv = GetItemsTable(aStorage, &storage);
149 0 : NS_ENSURE_SUCCESS(rv, rv);
150 :
151 : GetAllKeysEnumStruc struc;
152 0 : struc.mTarget = aKeys;
153 0 : struc.mStorage = aStorage;
154 0 : storage->mTable.EnumerateRead(GetAllKeysEnum, &struc);
155 :
156 0 : return NS_OK;
157 : }
158 :
159 : nsresult
160 0 : nsDOMStorageMemoryDB::GetKeyValue(DOMStorageImpl* aStorage,
161 : const nsAString& aKey,
162 : nsAString& aValue,
163 : bool* aSecure)
164 : {
165 0 : if (mPreloading) {
166 0 : NS_PRECONDITION(mPreloadDB, "Must have a preload DB set when preloading");
167 0 : return mPreloadDB->GetKeyValue(aStorage, aKey, aValue, aSecure);
168 : }
169 :
170 : nsresult rv;
171 :
172 : nsInMemoryStorage* storage;
173 0 : rv = GetItemsTable(aStorage, &storage);
174 0 : NS_ENSURE_SUCCESS(rv, rv);
175 :
176 : nsInMemoryItem* item;
177 0 : if (!storage->mTable.Get(aKey, &item))
178 0 : return NS_ERROR_DOM_NOT_FOUND_ERR;
179 :
180 0 : aValue = item->mValue;
181 0 : *aSecure = item->mSecure;
182 0 : return NS_OK;
183 : }
184 :
185 : nsresult
186 0 : nsDOMStorageMemoryDB::SetKey(DOMStorageImpl* aStorage,
187 : const nsAString& aKey,
188 : const nsAString& aValue,
189 : bool aSecure,
190 : PRInt32 aQuota,
191 : bool aExcludeOfflineFromUsage,
192 : PRInt32 *aNewUsage)
193 : {
194 : nsresult rv;
195 :
196 : nsInMemoryStorage* storage;
197 0 : rv = GetItemsTable(aStorage, &storage);
198 0 : NS_ENSURE_SUCCESS(rv, rv);
199 :
200 0 : PRInt32 usage = 0;
201 0 : if (!aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage).IsEmpty()) {
202 0 : rv = GetUsage(aStorage, aExcludeOfflineFromUsage, &usage);
203 0 : NS_ENSURE_SUCCESS(rv, rv);
204 : }
205 :
206 0 : usage += aKey.Length() + aValue.Length();
207 :
208 : nsInMemoryItem* item;
209 0 : if (!storage->mTable.Get(aKey, &item)) {
210 0 : if (usage > aQuota) {
211 0 : return NS_ERROR_DOM_QUOTA_REACHED;
212 : }
213 :
214 0 : item = new nsInMemoryItem();
215 0 : if (!item)
216 0 : return NS_ERROR_OUT_OF_MEMORY;
217 :
218 0 : storage->mTable.Put(aKey, item);
219 0 : storage->mUsageDelta += aKey.Length();
220 : }
221 : else
222 : {
223 0 : if (!aSecure && item->mSecure)
224 0 : return NS_ERROR_DOM_SECURITY_ERR;
225 0 : usage -= aKey.Length() + item->mValue.Length();
226 0 : if (usage > aQuota) {
227 0 : return NS_ERROR_DOM_QUOTA_REACHED;
228 : }
229 : }
230 :
231 0 : storage->mUsageDelta += aValue.Length() - item->mValue.Length();
232 :
233 0 : item->mValue = aValue;
234 0 : item->mSecure = aSecure;
235 :
236 0 : *aNewUsage = usage;
237 :
238 0 : MarkScopeDirty(aStorage);
239 :
240 0 : return NS_OK;
241 : }
242 :
243 : nsresult
244 0 : nsDOMStorageMemoryDB::SetSecure(DOMStorageImpl* aStorage,
245 : const nsAString& aKey,
246 : const bool aSecure)
247 : {
248 : nsresult rv;
249 :
250 : nsInMemoryStorage* storage;
251 0 : rv = GetItemsTable(aStorage, &storage);
252 0 : NS_ENSURE_SUCCESS(rv, rv);
253 :
254 : nsInMemoryItem* item;
255 0 : if (!storage->mTable.Get(aKey, &item))
256 0 : return NS_ERROR_DOM_NOT_FOUND_ERR;
257 :
258 0 : item->mSecure = aSecure;
259 :
260 0 : MarkScopeDirty(aStorage);
261 :
262 0 : return NS_OK;
263 : }
264 :
265 : nsresult
266 0 : nsDOMStorageMemoryDB::RemoveKey(DOMStorageImpl* aStorage,
267 : const nsAString& aKey,
268 : bool aExcludeOfflineFromUsage,
269 : PRInt32 aKeyUsage)
270 : {
271 : nsresult rv;
272 :
273 : nsInMemoryStorage* storage;
274 0 : rv = GetItemsTable(aStorage, &storage);
275 0 : NS_ENSURE_SUCCESS(rv, rv);
276 :
277 : nsInMemoryItem* item;
278 0 : if (!storage->mTable.Get(aKey, &item))
279 0 : return NS_ERROR_DOM_NOT_FOUND_ERR;
280 :
281 0 : storage->mUsageDelta -= aKey.Length() + item->mValue.Length();
282 0 : storage->mTable.Remove(aKey);
283 :
284 0 : MarkScopeDirty(aStorage);
285 :
286 0 : return NS_OK;
287 : }
288 :
289 : static PLDHashOperator
290 0 : RemoveAllKeysEnum(const nsAString& keyname,
291 : nsAutoPtr<nsDOMStorageMemoryDB::nsInMemoryItem>& item,
292 : void *closure)
293 : {
294 : nsDOMStorageMemoryDB::nsInMemoryStorage* storage =
295 0 : (nsDOMStorageMemoryDB::nsInMemoryStorage*)closure;
296 :
297 0 : storage->mUsageDelta -= keyname.Length() + item->mValue.Length();
298 0 : return PL_DHASH_REMOVE;
299 : }
300 :
301 : nsresult
302 0 : nsDOMStorageMemoryDB::ClearStorage(DOMStorageImpl* aStorage)
303 : {
304 : nsresult rv;
305 :
306 : nsInMemoryStorage* storage;
307 0 : rv = GetItemsTable(aStorage, &storage);
308 0 : NS_ENSURE_SUCCESS(rv, rv);
309 :
310 0 : storage->mTable.Enumerate(RemoveAllKeysEnum, storage);
311 :
312 0 : MarkScopeDirty(aStorage);
313 :
314 0 : return NS_OK;
315 : }
316 :
317 : nsresult
318 0 : nsDOMStorageMemoryDB::DropStorage(DOMStorageImpl* aStorage)
319 : {
320 0 : mData.Remove(aStorage->GetScopeDBKey());
321 0 : MarkScopeDirty(aStorage);
322 0 : return NS_OK;
323 : }
324 :
325 : struct RemoveOwnersStruc
326 : {
327 : nsCString* mSubDomain;
328 : bool mMatch;
329 : };
330 :
331 : static PLDHashOperator
332 0 : RemoveOwnersEnum(const nsACString& key,
333 : nsAutoPtr<nsDOMStorageMemoryDB::nsInMemoryStorage>& storage,
334 : void *closure)
335 : {
336 0 : RemoveOwnersStruc* struc = (RemoveOwnersStruc*)closure;
337 :
338 0 : if (StringBeginsWith(key, *(struc->mSubDomain)) == struc->mMatch)
339 0 : return PL_DHASH_REMOVE;
340 :
341 0 : return PL_DHASH_NEXT;
342 : }
343 :
344 : nsresult
345 96 : nsDOMStorageMemoryDB::RemoveOwner(const nsACString& aOwner,
346 : bool aIncludeSubDomains)
347 : {
348 192 : nsCAutoString subdomainsDBKey;
349 96 : nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aOwner, subdomainsDBKey);
350 :
351 96 : if (!aIncludeSubDomains)
352 0 : subdomainsDBKey.AppendLiteral(":");
353 :
354 : RemoveOwnersStruc struc;
355 96 : struc.mSubDomain = &subdomainsDBKey;
356 96 : struc.mMatch = true;
357 96 : mData.Enumerate(RemoveOwnersEnum, &struc);
358 :
359 96 : MarkAllScopesDirty();
360 :
361 96 : return NS_OK;
362 : }
363 :
364 :
365 : nsresult
366 25 : nsDOMStorageMemoryDB::RemoveOwners(const nsTArray<nsString> &aOwners,
367 : bool aIncludeSubDomains,
368 : bool aMatch)
369 : {
370 25 : if (aOwners.Length() == 0) {
371 25 : if (aMatch) {
372 2 : return NS_OK;
373 : }
374 :
375 23 : return RemoveAll();
376 : }
377 :
378 0 : for (PRUint32 i = 0; i < aOwners.Length(); i++) {
379 0 : nsCAutoString quotaKey;
380 : nsresult rv;
381 : rv = nsDOMStorageDBWrapper::CreateDomainScopeDBKey(
382 0 : NS_ConvertUTF16toUTF8(aOwners[i]), quotaKey);
383 :
384 0 : if (!aIncludeSubDomains)
385 0 : quotaKey.AppendLiteral(":");
386 :
387 : RemoveOwnersStruc struc;
388 0 : struc.mSubDomain = "aKey;
389 0 : struc.mMatch = aMatch;
390 0 : mData.Enumerate(RemoveOwnersEnum, &struc);
391 : }
392 :
393 0 : MarkAllScopesDirty();
394 :
395 0 : return NS_OK;
396 : }
397 :
398 : nsresult
399 160 : nsDOMStorageMemoryDB::RemoveAll()
400 : {
401 160 : mData.Clear(); // XXX Check this releases all instances
402 :
403 160 : MarkAllScopesDirty();
404 :
405 160 : return NS_OK;
406 : }
407 :
408 : nsresult
409 0 : nsDOMStorageMemoryDB::GetUsage(DOMStorageImpl* aStorage,
410 : bool aExcludeOfflineFromUsage, PRInt32 *aUsage)
411 : {
412 0 : return GetUsageInternal(aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage),
413 0 : aExcludeOfflineFromUsage, aUsage);
414 : }
415 :
416 : nsresult
417 0 : nsDOMStorageMemoryDB::GetUsage(const nsACString& aDomain,
418 : bool aIncludeSubDomains,
419 : PRInt32 *aUsage)
420 : {
421 : nsresult rv;
422 :
423 0 : nsCAutoString quotadomainDBKey;
424 : rv = nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomain,
425 : aIncludeSubDomains,
426 : false,
427 0 : quotadomainDBKey);
428 0 : NS_ENSURE_SUCCESS(rv, rv);
429 :
430 0 : return GetUsageInternal(quotadomainDBKey, false, aUsage);
431 : }
432 :
433 : struct GetUsageEnumStruc
434 0 : {
435 : PRInt32 mUsage;
436 : PRInt32 mExcludeOfflineFromUsage;
437 : nsCString mSubdomain;
438 : };
439 :
440 : static PLDHashOperator
441 0 : GetUsageEnum(const nsACString& key,
442 : nsDOMStorageMemoryDB::nsInMemoryStorage* storageData,
443 : void *closure)
444 : {
445 0 : GetUsageEnumStruc* struc = (GetUsageEnumStruc*)closure;
446 :
447 0 : if (StringBeginsWith(key, struc->mSubdomain)) {
448 0 : if (struc->mExcludeOfflineFromUsage) {
449 0 : nsCAutoString domain;
450 0 : nsresult rv = nsDOMStorageDBWrapper::GetDomainFromScopeKey(key, domain);
451 0 : if (NS_SUCCEEDED(rv) && IsOfflineAllowed(domain))
452 0 : return PL_DHASH_NEXT;
453 : }
454 :
455 0 : struc->mUsage += storageData->mUsageDelta;
456 : }
457 :
458 0 : return PL_DHASH_NEXT;
459 : }
460 :
461 : nsresult
462 0 : nsDOMStorageMemoryDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
463 : bool aExcludeOfflineFromUsage,
464 : PRInt32 *aUsage)
465 : {
466 0 : GetUsageEnumStruc struc;
467 0 : struc.mUsage = 0;
468 0 : struc.mExcludeOfflineFromUsage = aExcludeOfflineFromUsage;
469 0 : struc.mSubdomain = aQuotaDomainDBKey;
470 :
471 0 : if (mPreloadDB) {
472 : nsresult rv;
473 :
474 : rv = mPreloadDB->GetUsageInternal(aQuotaDomainDBKey,
475 0 : aExcludeOfflineFromUsage, &struc.mUsage);
476 0 : NS_ENSURE_SUCCESS(rv, rv);
477 : }
478 :
479 0 : mData.EnumerateRead(GetUsageEnum, &struc);
480 :
481 0 : *aUsage = struc.mUsage;
482 0 : return NS_OK;
483 : }
|