bug 700693 - OCSP stapling PSM changes r=bsmith
[gecko.git] / dom / indexedDB / Client.cpp
blob2ed73d55e222bf755a174122a915531b8672d89e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "Client.h"
9 #include "mozilla/dom/quota/QuotaManager.h"
10 #include "mozilla/dom/quota/UsageRunnable.h"
11 #include "mozilla/dom/quota/Utilities.h"
13 #include "IDBDatabase.h"
14 #include "IndexedDatabaseManager.h"
15 #include "TransactionThreadPool.h"
17 USING_INDEXEDDB_NAMESPACE
18 using mozilla::dom::quota::AssertIsOnIOThread;
19 using mozilla::dom::quota::QuotaManager;
21 namespace {
23 bool
24 GetDatabaseBaseFilename(const nsAString& aFilename,
25 nsAString& aDatabaseBaseFilename)
27 NS_ASSERTION(!aFilename.IsEmpty(), "Bad argument!");
29 NS_NAMED_LITERAL_STRING(sqlite, ".sqlite");
31 if (!StringEndsWith(aFilename, sqlite)) {
32 return false;
35 aDatabaseBaseFilename =
36 Substring(aFilename, 0, aFilename.Length() - sqlite.Length());
38 return true;
41 } // anonymous namespace
43 // This needs to be fully qualified to not confuse trace refcnt assertions.
44 NS_IMPL_ADDREF(mozilla::dom::indexedDB::Client)
45 NS_IMPL_RELEASE(mozilla::dom::indexedDB::Client)
47 nsresult
48 Client::InitOrigin(const nsACString& aOrigin, UsageRunnable* aUsageRunnable)
50 AssertIsOnIOThread();
52 nsCOMPtr<nsIFile> directory;
53 nsresult rv = GetDirectory(aOrigin, getter_AddRefs(directory));
54 NS_ENSURE_SUCCESS(rv, rv);
56 // We need to see if there are any files in the directory already. If they
57 // are database files then we need to cleanup stored files (if it's needed)
58 // and also get the usage.
60 nsAutoTArray<nsString, 20> subdirsToProcess;
61 nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles;
62 nsTHashtable<nsStringHashKey> validSubdirs;
63 validSubdirs.Init(20);
65 nsCOMPtr<nsISimpleEnumerator> entries;
66 rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
67 NS_ENSURE_SUCCESS(rv, rv);
69 bool hasMore;
70 while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
71 hasMore && (!aUsageRunnable || !aUsageRunnable->Canceled())) {
72 nsCOMPtr<nsISupports> entry;
73 rv = entries->GetNext(getter_AddRefs(entry));
74 NS_ENSURE_SUCCESS(rv, rv);
76 nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
77 NS_ENSURE_TRUE(file, NS_NOINTERFACE);
79 nsString leafName;
80 rv = file->GetLeafName(leafName);
81 NS_ENSURE_SUCCESS(rv, rv);
83 if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
84 continue;
87 bool isDirectory;
88 rv = file->IsDirectory(&isDirectory);
89 NS_ENSURE_SUCCESS(rv, rv);
91 if (isDirectory) {
92 if (!validSubdirs.GetEntry(leafName)) {
93 subdirsToProcess.AppendElement(leafName);
95 continue;
98 nsString dbBaseFilename;
99 if (!GetDatabaseBaseFilename(leafName, dbBaseFilename)) {
100 unknownFiles.AppendElement(file);
101 continue;
104 nsCOMPtr<nsIFile> fmDirectory;
105 rv = directory->Clone(getter_AddRefs(fmDirectory));
106 NS_ENSURE_SUCCESS(rv, rv);
108 rv = fmDirectory->Append(dbBaseFilename);
109 NS_ENSURE_SUCCESS(rv, rv);
111 rv = FileManager::InitDirectory(fmDirectory, file, aOrigin);
112 NS_ENSURE_SUCCESS(rv, rv);
114 if (aUsageRunnable) {
115 int64_t fileSize;
116 rv = file->GetFileSize(&fileSize);
117 NS_ENSURE_SUCCESS(rv, rv);
119 aUsageRunnable->AppendToDatabaseUsage(uint64_t(fileSize));
121 uint64_t usage;
122 rv = FileManager::GetUsage(fmDirectory, &usage);
123 NS_ENSURE_SUCCESS(rv, rv);
125 aUsageRunnable->AppendToFileUsage(usage);
128 validSubdirs.PutEntry(dbBaseFilename);
130 NS_ENSURE_SUCCESS(rv, rv);
132 for (uint32_t i = 0; i < subdirsToProcess.Length(); i++) {
133 const nsString& subdir = subdirsToProcess[i];
134 if (!validSubdirs.GetEntry(subdir)) {
135 NS_WARNING("Unknown subdirectory found!");
136 return NS_ERROR_UNEXPECTED;
140 for (uint32_t i = 0; i < unknownFiles.Length(); i++) {
141 nsCOMPtr<nsIFile>& unknownFile = unknownFiles[i];
143 // Some temporary SQLite files could disappear, so we have to check if the
144 // unknown file still exists.
145 bool exists;
146 rv = unknownFile->Exists(&exists);
147 NS_ENSURE_SUCCESS(rv, rv);
149 if (exists) {
150 nsString leafName;
151 unknownFile->GetLeafName(leafName);
153 // The journal file may exists even after db has been correctly opened.
154 if (!StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
155 NS_WARNING("Unknown file found!");
156 return NS_ERROR_UNEXPECTED;
161 return NS_OK;
164 nsresult
165 Client::GetUsageForOrigin(const nsACString& aOrigin,
166 UsageRunnable* aUsageRunnable)
168 AssertIsOnIOThread();
169 NS_ASSERTION(aUsageRunnable, "Null pointer!");
171 nsCOMPtr<nsIFile> directory;
172 nsresult rv = GetDirectory(aOrigin, getter_AddRefs(directory));
173 NS_ENSURE_SUCCESS(rv, rv);
175 rv = GetUsageForDirectoryInternal(directory, aUsageRunnable, true);
176 NS_ENSURE_SUCCESS(rv, rv);
178 return NS_OK;
181 void
182 Client::OnOriginClearCompleted(const nsACString& aPattern)
184 AssertIsOnIOThread();
186 IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
187 if (mgr) {
188 mgr->InvalidateFileManagersForPattern(aPattern);
192 void
193 Client::ReleaseIOThreadObjects()
195 AssertIsOnIOThread();
197 IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
198 if (mgr) {
199 mgr->InvalidateAllFileManagers();
203 bool
204 Client::IsTransactionServiceActivated()
206 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
208 return !!TransactionThreadPool::Get();
211 void
212 Client::WaitForStoragesToComplete(nsTArray<nsIOfflineStorage*>& aStorages,
213 nsIRunnable* aCallback)
215 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
216 NS_ASSERTION(!aStorages.IsEmpty(), "No storages to wait on!");
217 NS_ASSERTION(aCallback, "Passed null callback!");
219 TransactionThreadPool* pool = TransactionThreadPool::Get();
220 NS_ASSERTION(pool, "Should have checked if transaction service is active!");
222 nsTArray<nsRefPtr<IDBDatabase> > databases(aStorages.Length());
223 for (uint32_t index = 0; index < aStorages.Length(); index++) {
224 IDBDatabase* database = IDBDatabase::FromStorage(aStorages[index]);
225 if (!database) {
226 MOZ_CRASH();
229 databases.AppendElement(database);
232 pool->WaitForDatabasesToComplete(databases, aCallback);
235 void
236 Client::AbortTransactionsForStorage(nsIOfflineStorage* aStorage)
238 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
239 NS_ASSERTION(aStorage, "Passed null storage!");
241 TransactionThreadPool* pool = TransactionThreadPool::Get();
242 NS_ASSERTION(pool, "Should have checked if transaction service is active!");
244 IDBDatabase* database = IDBDatabase::FromStorage(aStorage);
245 NS_ASSERTION(database, "This shouldn't be null!");
247 pool->AbortTransactionsForDatabase(database);
250 bool
251 Client::HasTransactionsForStorage(nsIOfflineStorage* aStorage)
253 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
255 TransactionThreadPool* pool = TransactionThreadPool::Get();
256 NS_ASSERTION(pool, "Should have checked if transaction service is active!");
258 IDBDatabase* database = IDBDatabase::FromStorage(aStorage);
259 NS_ASSERTION(database, "This shouldn't be null!");
261 return pool->HasTransactionsForDatabase(database);
264 void
265 Client::ShutdownTransactionService()
267 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
269 TransactionThreadPool::Shutdown();
272 nsresult
273 Client::GetDirectory(const nsACString& aOrigin, nsIFile** aDirectory)
275 QuotaManager* quotaManager = QuotaManager::Get();
276 NS_ASSERTION(quotaManager, "This should never fail!");
278 nsCOMPtr<nsIFile> directory;
279 nsresult rv =
280 quotaManager->GetDirectoryForOrigin(aOrigin, getter_AddRefs(directory));
281 NS_ENSURE_SUCCESS(rv, rv);
283 NS_ASSERTION(directory, "What?");
285 rv = directory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
286 NS_ENSURE_SUCCESS(rv, rv);
288 directory.forget(aDirectory);
289 return NS_OK;
292 nsresult
293 Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
294 UsageRunnable* aUsageRunnable,
295 bool aDatabaseFiles)
297 NS_ASSERTION(aDirectory, "Null pointer!");
298 NS_ASSERTION(aUsageRunnable, "Null pointer!");
300 nsCOMPtr<nsISimpleEnumerator> entries;
301 nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
302 NS_ENSURE_SUCCESS(rv, rv);
304 if (!entries) {
305 return NS_OK;
308 bool hasMore;
309 while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
310 hasMore && !aUsageRunnable->Canceled()) {
311 nsCOMPtr<nsISupports> entry;
312 rv = entries->GetNext(getter_AddRefs(entry));
313 NS_ENSURE_SUCCESS(rv, rv);
315 nsCOMPtr<nsIFile> file(do_QueryInterface(entry));
316 NS_ASSERTION(file, "Don't know what this is!");
318 bool isDirectory;
319 rv = file->IsDirectory(&isDirectory);
320 NS_ENSURE_SUCCESS(rv, rv);
322 if (isDirectory) {
323 if (aDatabaseFiles) {
324 rv = GetUsageForDirectoryInternal(file, aUsageRunnable, false);
325 NS_ENSURE_SUCCESS(rv, rv);
327 else {
328 nsString leafName;
329 rv = file->GetLeafName(leafName);
330 NS_ENSURE_SUCCESS(rv, rv);
332 if (!leafName.EqualsLiteral(JOURNAL_DIRECTORY_NAME)) {
333 NS_WARNING("Unknown directory found!");
337 continue;
340 int64_t fileSize;
341 rv = file->GetFileSize(&fileSize);
342 NS_ENSURE_SUCCESS(rv, rv);
344 NS_ASSERTION(fileSize >= 0, "Negative size?!");
346 if (aDatabaseFiles) {
347 aUsageRunnable->AppendToDatabaseUsage(uint64_t(fileSize));
349 else {
350 aUsageRunnable->AppendToFileUsage(uint64_t(fileSize));
353 NS_ENSURE_SUCCESS(rv, rv);
355 return NS_OK;