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 "nsDOMStorageDBWrapper.h"
44 : #include "nsIFile.h"
45 : #include "nsIURL.h"
46 : #include "nsIVariant.h"
47 : #include "nsIEffectiveTLDService.h"
48 : #include "nsAppDirectoryServiceDefs.h"
49 : #include "mozStorageCID.h"
50 : #include "mozStorageHelper.h"
51 : #include "mozIStorageService.h"
52 : #include "mozIStorageValueArray.h"
53 : #include "mozIStorageFunction.h"
54 : #include "nsPrintfCString.h"
55 : #include "nsNetUtil.h"
56 :
57 224 : void ReverseString(const nsCSubstring& source, nsCSubstring& result)
58 : {
59 224 : nsACString::const_iterator sourceBegin, sourceEnd;
60 224 : source.BeginReading(sourceBegin);
61 224 : source.EndReading(sourceEnd);
62 :
63 224 : result.SetLength(source.Length());
64 224 : nsACString::iterator destEnd;
65 224 : result.EndWriting(destEnd);
66 :
67 2891 : while (sourceBegin != sourceEnd) {
68 2443 : *(--destEnd) = *sourceBegin;
69 2443 : ++sourceBegin;
70 : }
71 224 : }
72 :
73 77 : nsDOMStorageDBWrapper::nsDOMStorageDBWrapper()
74 : {
75 77 : }
76 :
77 77 : nsDOMStorageDBWrapper::~nsDOMStorageDBWrapper()
78 : {
79 77 : }
80 :
81 : void
82 37 : nsDOMStorageDBWrapper::Close()
83 : {
84 37 : mPersistentDB.Close();
85 37 : mChromePersistentDB.Close();
86 37 : }
87 :
88 : nsresult
89 77 : nsDOMStorageDBWrapper::Init()
90 : {
91 : nsresult rv;
92 :
93 77 : rv = mPersistentDB.Init(NS_LITERAL_STRING("webappsstore.sqlite"));
94 77 : NS_ENSURE_SUCCESS(rv, rv);
95 :
96 39 : rv = mChromePersistentDB.Init(NS_LITERAL_STRING("chromeappsstore.sqlite"));
97 39 : NS_ENSURE_SUCCESS(rv, rv);
98 :
99 39 : rv = mSessionOnlyDB.Init(&mPersistentDB);
100 39 : NS_ENSURE_SUCCESS(rv, rv);
101 :
102 39 : rv = mPrivateBrowsingDB.Init();
103 39 : NS_ENSURE_SUCCESS(rv, rv);
104 :
105 39 : return NS_OK;
106 : }
107 :
108 : nsresult
109 37 : nsDOMStorageDBWrapper::FlushAndDeleteTemporaryTables(bool force)
110 : {
111 : nsresult rv1, rv2;
112 37 : rv1 = mChromePersistentDB.FlushTemporaryTables(force);
113 37 : rv2 = mPersistentDB.FlushTemporaryTables(force);
114 :
115 : // Everything flushed? Then no need for a timer.
116 74 : if (!mChromePersistentDB.mTempTableLoads.Count() &&
117 37 : !mPersistentDB.mTempTableLoads.Count())
118 37 : StopTempTableFlushTimer();
119 :
120 37 : return NS_FAILED(rv1) ? rv1 : rv2;
121 : }
122 :
123 : #define IMPL_FORWARDER_GUTS(_return, _code) \
124 : PR_BEGIN_MACRO \
125 : if (aStorage->CanUseChromePersist()) \
126 : _return mChromePersistentDB._code; \
127 : if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) \
128 : _return mPrivateBrowsingDB._code; \
129 : if (aStorage->SessionOnly()) \
130 : _return mSessionOnlyDB._code; \
131 : _return mPersistentDB._code; \
132 : PR_END_MACRO
133 :
134 : #define IMPL_FORWARDER(_code) \
135 : IMPL_FORWARDER_GUTS(return, _code)
136 :
137 : #define IMPL_VOID_FORWARDER(_code) \
138 : IMPL_FORWARDER_GUTS((void), _code)
139 :
140 : nsresult
141 38 : nsDOMStorageDBWrapper::GetAllKeys(DOMStorageImpl* aStorage,
142 : nsTHashtable<nsSessionStorageEntry>* aKeys)
143 : {
144 38 : IMPL_FORWARDER(GetAllKeys(aStorage, aKeys));
145 : }
146 :
147 : nsresult
148 50 : nsDOMStorageDBWrapper::GetKeyValue(DOMStorageImpl* aStorage,
149 : const nsAString& aKey,
150 : nsAString& aValue,
151 : bool* aSecure)
152 : {
153 50 : IMPL_FORWARDER(GetKeyValue(aStorage, aKey, aValue, aSecure));
154 : }
155 :
156 : nsresult
157 18 : nsDOMStorageDBWrapper::SetKey(DOMStorageImpl* aStorage,
158 : const nsAString& aKey,
159 : const nsAString& aValue,
160 : bool aSecure,
161 : PRInt32 aQuota,
162 : bool aExcludeOfflineFromUsage,
163 : PRInt32 *aNewUsage)
164 : {
165 18 : IMPL_FORWARDER(SetKey(aStorage, aKey, aValue, aSecure,
166 : aQuota, aExcludeOfflineFromUsage, aNewUsage));
167 : }
168 :
169 : nsresult
170 0 : nsDOMStorageDBWrapper::SetSecure(DOMStorageImpl* aStorage,
171 : const nsAString& aKey,
172 : const bool aSecure)
173 : {
174 0 : IMPL_FORWARDER(SetSecure(aStorage, aKey, aSecure));
175 : }
176 :
177 : nsresult
178 6 : nsDOMStorageDBWrapper::RemoveKey(DOMStorageImpl* aStorage,
179 : const nsAString& aKey,
180 : bool aExcludeOfflineFromUsage,
181 : PRInt32 aKeyUsage)
182 : {
183 6 : IMPL_FORWARDER(RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage));
184 : }
185 :
186 : nsresult
187 6 : nsDOMStorageDBWrapper::ClearStorage(DOMStorageImpl* aStorage)
188 : {
189 6 : IMPL_FORWARDER(ClearStorage(aStorage));
190 : }
191 :
192 : void
193 38 : nsDOMStorageDBWrapper::MarkScopeCached(DOMStorageImpl* aStorage)
194 : {
195 38 : IMPL_VOID_FORWARDER(MarkScopeCached(aStorage));
196 38 : }
197 :
198 : bool
199 92 : nsDOMStorageDBWrapper::IsScopeDirty(DOMStorageImpl* aStorage)
200 : {
201 92 : IMPL_FORWARDER(IsScopeDirty(aStorage));
202 : }
203 :
204 : nsresult
205 0 : nsDOMStorageDBWrapper::DropSessionOnlyStoragesForHost(const nsACString& aHostName)
206 : {
207 0 : return mSessionOnlyDB.RemoveOwner(aHostName, true);
208 : }
209 :
210 : nsresult
211 137 : nsDOMStorageDBWrapper::DropPrivateBrowsingStorages()
212 : {
213 137 : return mPrivateBrowsingDB.RemoveAll();
214 : }
215 :
216 : nsresult
217 48 : nsDOMStorageDBWrapper::RemoveOwner(const nsACString& aOwner,
218 : bool aIncludeSubDomains)
219 : {
220 : nsresult rv;
221 :
222 48 : rv = mPrivateBrowsingDB.RemoveOwner(aOwner, aIncludeSubDomains);
223 48 : NS_ENSURE_SUCCESS(rv, rv);
224 :
225 48 : if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
226 0 : return NS_OK;
227 :
228 48 : rv = mSessionOnlyDB.RemoveOwner(aOwner, aIncludeSubDomains);
229 48 : NS_ENSURE_SUCCESS(rv, rv);
230 :
231 48 : rv = mPersistentDB.RemoveOwner(aOwner, aIncludeSubDomains);
232 48 : NS_ENSURE_SUCCESS(rv, rv);
233 :
234 48 : return rv;
235 : }
236 :
237 :
238 : nsresult
239 13 : nsDOMStorageDBWrapper::RemoveOwners(const nsTArray<nsString> &aOwners,
240 : bool aIncludeSubDomains, bool aMatch)
241 : {
242 : nsresult rv;
243 :
244 13 : rv = mPrivateBrowsingDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
245 13 : NS_ENSURE_SUCCESS(rv, rv);
246 :
247 13 : if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
248 1 : return NS_OK;
249 :
250 12 : rv = mSessionOnlyDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
251 12 : NS_ENSURE_SUCCESS(rv, rv);
252 :
253 12 : rv = mPersistentDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
254 12 : NS_ENSURE_SUCCESS(rv, rv);
255 :
256 12 : return rv;
257 : }
258 :
259 : nsresult
260 0 : nsDOMStorageDBWrapper::RemoveAll()
261 : {
262 : nsresult rv;
263 :
264 0 : rv = mPrivateBrowsingDB.RemoveAll();
265 0 : NS_ENSURE_SUCCESS(rv, rv);
266 :
267 0 : if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
268 0 : return NS_OK;
269 :
270 0 : rv = mSessionOnlyDB.RemoveAll();
271 0 : NS_ENSURE_SUCCESS(rv, rv);
272 :
273 0 : rv = mPersistentDB.RemoveAll();
274 0 : NS_ENSURE_SUCCESS(rv, rv);
275 :
276 0 : return rv;
277 : }
278 :
279 : nsresult
280 0 : nsDOMStorageDBWrapper::GetUsage(DOMStorageImpl* aStorage,
281 : bool aExcludeOfflineFromUsage, PRInt32 *aUsage)
282 : {
283 0 : IMPL_FORWARDER(GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage));
284 : }
285 :
286 : nsresult
287 0 : nsDOMStorageDBWrapper::GetUsage(const nsACString& aDomain,
288 : bool aIncludeSubDomains, PRInt32 *aUsage)
289 : {
290 0 : if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
291 0 : return mPrivateBrowsingDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
292 :
293 : #if 0
294 : // XXX Check where from all this method gets called, not sure this should
295 : // include any potential session-only data
296 : nsresult rv;
297 : rv = mSessionOnlyDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
298 : if (NS_SUECEEDED(rv))
299 : return rv;
300 : #endif
301 :
302 0 : return mPersistentDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
303 : }
304 :
305 : nsresult
306 20 : nsDOMStorageDBWrapper::CreateOriginScopeDBKey(nsIURI* aUri, nsACString& aKey)
307 : {
308 : nsresult rv;
309 :
310 20 : rv = CreateDomainScopeDBKey(aUri, aKey);
311 20 : if (NS_FAILED(rv))
312 0 : return rv;
313 :
314 40 : nsCAutoString scheme;
315 20 : rv = aUri->GetScheme(scheme);
316 20 : NS_ENSURE_SUCCESS(rv, rv);
317 :
318 20 : aKey.AppendLiteral(":");
319 20 : aKey.Append(scheme);
320 :
321 20 : PRInt32 port = NS_GetRealPort(aUri);
322 20 : if (port != -1) {
323 6 : aKey.AppendLiteral(":");
324 6 : aKey.Append(nsPrintfCString(32, "%d", port));
325 : }
326 :
327 20 : return NS_OK;
328 : }
329 :
330 : nsresult
331 20 : nsDOMStorageDBWrapper::CreateDomainScopeDBKey(nsIURI* aUri, nsACString& aKey)
332 : {
333 : nsresult rv;
334 :
335 40 : nsCAutoString domainScope;
336 20 : rv = aUri->GetAsciiHost(domainScope);
337 20 : NS_ENSURE_SUCCESS(rv, rv);
338 :
339 20 : if (domainScope.IsEmpty()) {
340 : // About pages have an empty host but a valid path. Since they are handled
341 : // internally by our own redirector, we can trust them and use path as key.
342 : // if file:/// protocol, let's make the exact directory the domain
343 14 : bool isScheme = false;
344 28 : if ((NS_SUCCEEDED(aUri->SchemeIs("about", &isScheme)) && isScheme) ||
345 14 : (NS_SUCCEEDED(aUri->SchemeIs("moz-safe-about", &isScheme)) && isScheme)) {
346 14 : rv = aUri->GetPath(domainScope);
347 14 : NS_ENSURE_SUCCESS(rv, rv);
348 : // While the host is always canonicalized to lowercase, the path is not,
349 : // thus need to force the casing.
350 14 : ToLowerCase(domainScope);
351 : }
352 0 : else if (NS_SUCCEEDED(aUri->SchemeIs("file", &isScheme)) && isScheme) {
353 0 : nsCOMPtr<nsIURL> url = do_QueryInterface(aUri, &rv);
354 0 : NS_ENSURE_SUCCESS(rv, rv);
355 0 : rv = url->GetDirectory(domainScope);
356 0 : NS_ENSURE_SUCCESS(rv, rv);
357 : }
358 : }
359 :
360 20 : rv = CreateDomainScopeDBKey(domainScope, aKey);
361 20 : NS_ENSURE_SUCCESS(rv, rv);
362 :
363 20 : return NS_OK;
364 : }
365 :
366 : nsresult
367 252 : nsDOMStorageDBWrapper::CreateDomainScopeDBKey(const nsACString& aAsciiDomain,
368 : nsACString& aKey)
369 : {
370 252 : if (aAsciiDomain.IsEmpty())
371 28 : return NS_ERROR_NOT_AVAILABLE;
372 :
373 224 : ReverseString(aAsciiDomain, aKey);
374 :
375 224 : aKey.AppendLiteral(".");
376 224 : return NS_OK;
377 : }
378 :
379 : nsresult
380 40 : nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(const nsACString& aAsciiDomain,
381 : bool aIncludeSubDomains,
382 : bool aEffectiveTLDplus1Only,
383 : nsACString& aKey)
384 : {
385 : nsresult rv;
386 :
387 80 : nsCAutoString subdomainsDBKey;
388 40 : if (aEffectiveTLDplus1Only) {
389 : nsCOMPtr<nsIEffectiveTLDService> eTLDService(do_GetService(
390 40 : NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv));
391 20 : NS_ENSURE_SUCCESS(rv, rv);
392 :
393 40 : nsCOMPtr<nsIURI> uri;
394 20 : rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aAsciiDomain);
395 20 : NS_ENSURE_SUCCESS(rv, rv);
396 :
397 40 : nsCAutoString eTLDplusOne;
398 20 : rv = eTLDService->GetBaseDomain(uri, 0, eTLDplusOne);
399 20 : if (NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS == rv) {
400 : // XXX bug 357323 - what to do for localhost/file exactly?
401 14 : eTLDplusOne = aAsciiDomain;
402 14 : rv = NS_OK;
403 : }
404 20 : NS_ENSURE_SUCCESS(rv, rv);
405 :
406 40 : CreateDomainScopeDBKey(eTLDplusOne, subdomainsDBKey);
407 : }
408 : else
409 20 : CreateDomainScopeDBKey(aAsciiDomain, subdomainsDBKey);
410 :
411 40 : if (!aIncludeSubDomains)
412 0 : subdomainsDBKey.AppendLiteral(":");
413 :
414 40 : aKey.Assign(subdomainsDBKey);
415 40 : return NS_OK;
416 : }
417 :
418 : nsresult
419 0 : nsDOMStorageDBWrapper::GetDomainFromScopeKey(const nsACString& aScope,
420 : nsACString& aDomain)
421 : {
422 0 : nsCAutoString reverseDomain, scope;
423 0 : scope = aScope;
424 0 : scope.Left(reverseDomain, scope.FindChar(':')-1);
425 :
426 0 : ReverseString(reverseDomain, aDomain);
427 0 : return NS_OK;
428 : }
429 :
430 : void
431 8 : nsDOMStorageDBWrapper::EnsureTempTableFlushTimer()
432 : {
433 8 : if (!mTempTableFlushTimer) {
434 : nsresult rv;
435 3 : mTempTableFlushTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
436 :
437 3 : if (!NS_SUCCEEDED(rv)) {
438 0 : mTempTableFlushTimer = nsnull;
439 0 : return;
440 : }
441 :
442 3 : mTempTableFlushTimer->Init(nsDOMStorageManager::gStorageManager, 5000,
443 3 : nsITimer::TYPE_REPEATING_SLACK);
444 : }
445 : }
446 :
447 : void
448 37 : nsDOMStorageDBWrapper::StopTempTableFlushTimer()
449 : {
450 37 : if (mTempTableFlushTimer) {
451 3 : mTempTableFlushTimer->Cancel();
452 3 : mTempTableFlushTimer = nsnull;
453 : }
454 37 : }
455 :
|