Improve use of NeverDestroyed
[WebKit-https.git] / Source / WebCore / loader / appcache / ApplicationCacheStorage.cpp
1 /*
2  * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "ApplicationCacheStorage.h"
28
29 #include "ApplicationCache.h"
30 #include "ApplicationCacheGroup.h"
31 #include "ApplicationCacheHost.h"
32 #include "ApplicationCacheResource.h"
33 #include "FileSystem.h"
34 #include "SQLiteDatabaseTracker.h"
35 #include "SQLiteStatement.h"
36 #include "SQLiteTransaction.h"
37 #include "SecurityOrigin.h"
38 #include "SecurityOriginData.h"
39 #include "URL.h"
40 #include <wtf/StdLibExtras.h>
41 #include <wtf/StringExtras.h>
42 #include <wtf/UUID.h>
43 #include <wtf/text/CString.h>
44 #include <wtf/text/StringBuilder.h>
45
46 namespace WebCore {
47
48 template <class T>
49 class StorageIDJournal {
50 public:  
51     ~StorageIDJournal()
52     {
53         for (auto& record : m_records)
54             record.restore();
55     }
56
57     void add(T* resource, unsigned storageID)
58     {
59         m_records.append(Record(resource, storageID));
60     }
61
62     void commit()
63     {
64         m_records.clear();
65     }
66
67 private:
68     class Record {
69     public:
70         Record() : m_resource(nullptr), m_storageID(0) { }
71         Record(T* resource, unsigned storageID) : m_resource(resource), m_storageID(storageID) { }
72
73         void restore()
74         {
75             m_resource->setStorageID(m_storageID);
76         }
77
78     private:
79         T* m_resource;
80         unsigned m_storageID;
81     };
82
83     Vector<Record> m_records;
84 };
85
86 static unsigned urlHostHash(const URL& url)
87 {
88     unsigned hostStart = url.hostStart();
89     unsigned hostEnd = url.hostEnd();
90
91     const String& urlString = url.string();
92
93     if (urlString.is8Bit())
94         return AlreadyHashed::avoidDeletedValue(StringHasher::computeHashAndMaskTop8Bits(urlString.characters8() + hostStart, hostEnd - hostStart));
95     
96     return AlreadyHashed::avoidDeletedValue(StringHasher::computeHashAndMaskTop8Bits(urlString.characters16() + hostStart, hostEnd - hostStart));
97 }
98
99 ApplicationCacheGroup* ApplicationCacheStorage::loadCacheGroup(const URL& manifestURL)
100 {
101     SQLiteTransactionInProgressAutoCounter transactionCounter;
102
103     openDatabase(false);
104     if (!m_database.isOpen())
105         return nullptr;
106
107     SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL AND manifestURL=?");
108     if (statement.prepare() != SQLITE_OK)
109         return nullptr;
110     
111     statement.bindText(1, manifestURL);
112    
113     int result = statement.step();
114     if (result == SQLITE_DONE)
115         return nullptr;
116     
117     if (result != SQLITE_ROW) {
118         LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg());
119         return nullptr;
120     }
121     
122     unsigned newestCacheStorageID = static_cast<unsigned>(statement.getColumnInt64(2));
123
124     auto cache = loadCache(newestCacheStorageID);
125     if (!cache)
126         return nullptr;
127         
128     auto& group = *new ApplicationCacheGroup(*this, manifestURL);
129     group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
130     group.setNewestCache(cache.releaseNonNull());
131     return &group;
132 }    
133
134 ApplicationCacheGroup* ApplicationCacheStorage::findOrCreateCacheGroup(const URL& manifestURL)
135 {
136     ASSERT(!manifestURL.hasFragmentIdentifier());
137
138     auto result = m_cachesInMemory.add(manifestURL, nullptr);
139     if (!result.isNewEntry) {
140         ASSERT(result.iterator->value);
141         return result.iterator->value;
142     }
143
144     // Look up the group in the database
145     auto* group = loadCacheGroup(manifestURL);
146     
147     // If the group was not found we need to create it
148     if (!group) {
149         group = new ApplicationCacheGroup(*this, manifestURL);
150         m_cacheHostSet.add(urlHostHash(manifestURL));
151     }
152
153     result.iterator->value = group;
154     return group;
155 }
156
157 ApplicationCacheGroup* ApplicationCacheStorage::findInMemoryCacheGroup(const URL& manifestURL) const
158 {
159     return m_cachesInMemory.get(manifestURL);
160 }
161
162 void ApplicationCacheStorage::loadManifestHostHashes()
163 {
164     static bool hasLoadedHashes = false;
165     
166     if (hasLoadedHashes)
167         return;
168     
169     // We set this flag to true before the database has been opened
170     // to avoid trying to open the database over and over if it doesn't exist.
171     hasLoadedHashes = true;
172     
173     SQLiteTransactionInProgressAutoCounter transactionCounter;
174
175     openDatabase(false);
176     if (!m_database.isOpen())
177         return;
178
179     // Fetch the host hashes.
180     SQLiteStatement statement(m_database, "SELECT manifestHostHash FROM CacheGroups");    
181     if (statement.prepare() != SQLITE_OK)
182         return;
183     
184     while (statement.step() == SQLITE_ROW)
185         m_cacheHostSet.add(static_cast<unsigned>(statement.getColumnInt64(0)));
186 }    
187
188 ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const URL& url)
189 {
190     ASSERT(!url.hasFragmentIdentifier());
191     
192     loadManifestHostHashes();
193     
194     // Hash the host name and see if there's a manifest with the same host.
195     if (!m_cacheHostSet.contains(urlHostHash(url)))
196         return nullptr;
197
198     // Check if a cache already exists in memory.
199     for (const auto& group : m_cachesInMemory.values()) {
200         ASSERT(!group->isObsolete());
201
202         if (!protocolHostAndPortAreEqual(url, group->manifestURL()))
203             continue;
204         
205         if (ApplicationCache* cache = group->newestCache()) {
206             ApplicationCacheResource* resource = cache->resourceForURL(url);
207             if (!resource)
208                 continue;
209             if (resource->type() & ApplicationCacheResource::Foreign)
210                 continue;
211             return group;
212         }
213     }
214     
215     if (!m_database.isOpen())
216         return nullptr;
217         
218     SQLiteTransactionInProgressAutoCounter transactionCounter;
219
220     // Check the database. Look for all cache groups with a newest cache.
221     SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL");
222     if (statement.prepare() != SQLITE_OK)
223         return nullptr;
224     
225     int result;
226     while ((result = statement.step()) == SQLITE_ROW) {
227         URL manifestURL = URL(ParsedURLString, statement.getColumnText(1));
228
229         if (m_cachesInMemory.contains(manifestURL))
230             continue;
231
232         if (!protocolHostAndPortAreEqual(url, manifestURL))
233             continue;
234
235         // We found a cache group that matches. Now check if the newest cache has a resource with
236         // a matching URL.
237         unsigned newestCacheID = static_cast<unsigned>(statement.getColumnInt64(2));
238         auto cache = loadCache(newestCacheID);
239         if (!cache)
240             continue;
241
242         auto* resource = cache->resourceForURL(url);
243         if (!resource)
244             continue;
245         if (resource->type() & ApplicationCacheResource::Foreign)
246             continue;
247
248         auto& group = *new ApplicationCacheGroup(*this, manifestURL);
249         group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
250         group.setNewestCache(cache.releaseNonNull());
251         m_cachesInMemory.set(group.manifestURL(), &group);
252
253         return &group;
254     }
255
256     if (result != SQLITE_DONE)
257         LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg());
258     
259     return nullptr;
260 }
261
262 ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const URL& url)
263 {
264     SQLiteTransactionInProgressAutoCounter transactionCounter;
265
266     ASSERT(!url.hasFragmentIdentifier());
267
268     // Check if an appropriate cache already exists in memory.
269     for (auto* group : m_cachesInMemory.values()) {
270         ASSERT(!group->isObsolete());
271
272         if (ApplicationCache* cache = group->newestCache()) {
273             URL fallbackURL;
274             if (cache->isURLInOnlineWhitelist(url))
275                 continue;
276             if (!cache->urlMatchesFallbackNamespace(url, &fallbackURL))
277                 continue;
278             if (cache->resourceForURL(fallbackURL)->type() & ApplicationCacheResource::Foreign)
279                 continue;
280             return group;
281         }
282     }
283     
284     if (!m_database.isOpen())
285         return nullptr;
286         
287     // Check the database. Look for all cache groups with a newest cache.
288     SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL");
289     if (statement.prepare() != SQLITE_OK)
290         return nullptr;
291     
292     int result;
293     while ((result = statement.step()) == SQLITE_ROW) {
294         URL manifestURL = URL(ParsedURLString, statement.getColumnText(1));
295
296         if (m_cachesInMemory.contains(manifestURL))
297             continue;
298
299         // Fallback namespaces always have the same origin as manifest URL, so we can avoid loading caches that cannot match.
300         if (!protocolHostAndPortAreEqual(url, manifestURL))
301             continue;
302
303         // We found a cache group that matches. Now check if the newest cache has a resource with
304         // a matching fallback namespace.
305         unsigned newestCacheID = static_cast<unsigned>(statement.getColumnInt64(2));
306         auto cache = loadCache(newestCacheID);
307
308         URL fallbackURL;
309         if (cache->isURLInOnlineWhitelist(url))
310             continue;
311         if (!cache->urlMatchesFallbackNamespace(url, &fallbackURL))
312             continue;
313         if (cache->resourceForURL(fallbackURL)->type() & ApplicationCacheResource::Foreign)
314             continue;
315
316         auto& group = *new ApplicationCacheGroup(*this, manifestURL);
317         group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
318         group.setNewestCache(cache.releaseNonNull());
319
320         m_cachesInMemory.set(group.manifestURL(), &group);
321
322         return &group;
323     }
324
325     if (result != SQLITE_DONE)
326         LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg());
327     
328     return nullptr;
329 }
330
331 void ApplicationCacheStorage::cacheGroupDestroyed(ApplicationCacheGroup& group)
332 {
333     if (group.isObsolete()) {
334         ASSERT(!group.storageID());
335         ASSERT(m_cachesInMemory.get(group.manifestURL()) != &group);
336         return;
337     }
338
339     ASSERT(m_cachesInMemory.get(group.manifestURL()) == &group);
340
341     m_cachesInMemory.remove(group.manifestURL());
342     
343     // If the cache group is half-created, we don't want it in the saved set (as it is not stored in database).
344     if (!group.storageID())
345         m_cacheHostSet.remove(urlHostHash(group.manifestURL()));
346 }
347
348 void ApplicationCacheStorage::cacheGroupMadeObsolete(ApplicationCacheGroup& group)
349 {
350     ASSERT(m_cachesInMemory.get(group.manifestURL()) == &group);
351     ASSERT(m_cacheHostSet.contains(urlHostHash(group.manifestURL())));
352
353     if (auto* newestCache = group.newestCache())
354         remove(newestCache);
355
356     m_cachesInMemory.remove(group.manifestURL());
357     m_cacheHostSet.remove(urlHostHash(group.manifestURL()));
358 }
359
360 const String& ApplicationCacheStorage::cacheDirectory() const
361 {
362     return m_cacheDirectory;
363 }
364
365 void ApplicationCacheStorage::setMaximumSize(int64_t size)
366 {
367     m_maximumSize = size;
368 }
369
370 int64_t ApplicationCacheStorage::maximumSize() const
371 {
372     return m_maximumSize;
373 }
374
375 bool ApplicationCacheStorage::isMaximumSizeReached() const
376 {
377     return m_isMaximumSizeReached;
378 }
379
380 int64_t ApplicationCacheStorage::spaceNeeded(int64_t cacheToSave)
381 {
382     int64_t spaceNeeded = 0;
383     long long fileSize = 0;
384     if (!getFileSize(m_cacheFile, fileSize))
385         return 0;
386
387     int64_t currentSize = fileSize + flatFileAreaSize();
388
389     // Determine the amount of free space we have available.
390     int64_t totalAvailableSize = 0;
391     if (m_maximumSize < currentSize) {
392         // The max size is smaller than the actual size of the app cache file.
393         // This can happen if the client previously imposed a larger max size
394         // value and the app cache file has already grown beyond the current
395         // max size value.
396         // The amount of free space is just the amount of free space inside
397         // the database file. Note that this is always 0 if SQLite is compiled
398         // with AUTO_VACUUM = 1.
399         totalAvailableSize = m_database.freeSpaceSize();
400     } else {
401         // The max size is the same or larger than the current size.
402         // The amount of free space available is the amount of free space
403         // inside the database file plus the amount we can grow until we hit
404         // the max size.
405         totalAvailableSize = (m_maximumSize - currentSize) + m_database.freeSpaceSize();
406     }
407
408     // The space needed to be freed in order to accommodate the failed cache is
409     // the size of the failed cache minus any already available free space.
410     spaceNeeded = cacheToSave - totalAvailableSize;
411     // The space needed value must be positive (or else the total already
412     // available free space would be larger than the size of the failed cache and
413     // saving of the cache should have never failed).
414     ASSERT(spaceNeeded);
415     return spaceNeeded;
416 }
417
418 void ApplicationCacheStorage::setDefaultOriginQuota(int64_t quota)
419 {
420     m_defaultOriginQuota = quota;
421 }
422
423 bool ApplicationCacheStorage::calculateQuotaForOrigin(const SecurityOrigin& origin, int64_t& quota)
424 {
425     SQLiteTransactionInProgressAutoCounter transactionCounter;
426
427     // If an Origin record doesn't exist, then the COUNT will be 0 and quota will be 0.
428     // Using the count to determine if a record existed or not is a safe way to determine
429     // if a quota of 0 is real, from the record, or from null.
430     SQLiteStatement statement(m_database, "SELECT COUNT(quota), quota FROM Origins WHERE origin=?");
431     if (statement.prepare() != SQLITE_OK)
432         return false;
433
434     statement.bindText(1, SecurityOriginData::fromSecurityOrigin(origin).databaseIdentifier());
435     int result = statement.step();
436
437     // Return the quota, or if it was null the default.
438     if (result == SQLITE_ROW) {
439         bool wasNoRecord = statement.getColumnInt64(0) == 0;
440         quota = wasNoRecord ? m_defaultOriginQuota : statement.getColumnInt64(1);
441         return true;
442     }
443
444     LOG_ERROR("Could not get the quota of an origin, error \"%s\"", m_database.lastErrorMsg());
445     return false;
446 }
447
448 bool ApplicationCacheStorage::calculateUsageForOrigin(const SecurityOrigin* origin, int64_t& usage)
449 {
450     SQLiteTransactionInProgressAutoCounter transactionCounter;
451
452     // If an Origins record doesn't exist, then the SUM will be null,
453     // which will become 0, as expected, when converting to a number.
454     SQLiteStatement statement(m_database, "SELECT SUM(Caches.size)"
455                                           "  FROM CacheGroups"
456                                           " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
457                                           " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
458                                           " WHERE Origins.origin=?");
459     if (statement.prepare() != SQLITE_OK)
460         return false;
461
462     statement.bindText(1, SecurityOriginData::fromSecurityOrigin(*origin).databaseIdentifier());
463     int result = statement.step();
464
465     if (result == SQLITE_ROW) {
466         usage = statement.getColumnInt64(0);
467         return true;
468     }
469
470     LOG_ERROR("Could not get the quota of an origin, error \"%s\"", m_database.lastErrorMsg());
471     return false;
472 }
473
474 bool ApplicationCacheStorage::calculateRemainingSizeForOriginExcludingCache(const SecurityOrigin& origin, ApplicationCache* cache, int64_t& remainingSize)
475 {
476     SQLiteTransactionInProgressAutoCounter transactionCounter;
477
478     openDatabase(false);
479     if (!m_database.isOpen())
480         return false;
481
482     // Remaining size = total origin quota - size of all caches with origin excluding the provided cache.
483     // Keep track of the number of caches so we can tell if the result was a calculation or not.
484     const char* query;
485     int64_t excludingCacheIdentifier = cache ? cache->storageID() : 0;
486     if (excludingCacheIdentifier != 0) {
487         query = "SELECT COUNT(Caches.size), Origins.quota - SUM(Caches.size)"
488                 "  FROM CacheGroups"
489                 " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
490                 " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
491                 " WHERE Origins.origin=?"
492                 "   AND Caches.id!=?";
493     } else {
494         query = "SELECT COUNT(Caches.size), Origins.quota - SUM(Caches.size)"
495                 "  FROM CacheGroups"
496                 " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
497                 " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
498                 " WHERE Origins.origin=?";
499     }
500
501     SQLiteStatement statement(m_database, query);
502     if (statement.prepare() != SQLITE_OK)
503         return false;
504
505     statement.bindText(1, SecurityOriginData::fromSecurityOrigin(origin).databaseIdentifier());
506     if (excludingCacheIdentifier != 0)
507         statement.bindInt64(2, excludingCacheIdentifier);
508     int result = statement.step();
509
510     // If the count was 0 that then we have to query the origin table directly
511     // for its quota. Otherwise we can use the calculated value.
512     if (result == SQLITE_ROW) {
513         int64_t numberOfCaches = statement.getColumnInt64(0);
514         if (numberOfCaches == 0)
515             calculateQuotaForOrigin(origin, remainingSize);
516         else
517             remainingSize = statement.getColumnInt64(1);
518         return true;
519     }
520
521     LOG_ERROR("Could not get the remaining size of an origin's quota, error \"%s\"", m_database.lastErrorMsg());
522     return false;
523 }
524
525 bool ApplicationCacheStorage::storeUpdatedQuotaForOrigin(const SecurityOrigin* origin, int64_t quota)
526 {
527     SQLiteTransactionInProgressAutoCounter transactionCounter;
528
529     openDatabase(true);
530     if (!m_database.isOpen())
531         return false;
532
533     if (!ensureOriginRecord(origin))
534         return false;
535
536     SQLiteStatement updateStatement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
537     if (updateStatement.prepare() != SQLITE_OK)
538         return false;
539
540     updateStatement.bindInt64(1, quota);
541     updateStatement.bindText(2, SecurityOriginData::fromSecurityOrigin(*origin).databaseIdentifier());
542
543     return executeStatement(updateStatement);
544 }
545
546 bool ApplicationCacheStorage::executeSQLCommand(const String& sql)
547 {
548     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
549     ASSERT(m_database.isOpen());
550     
551     bool result = m_database.executeCommand(sql);
552     if (!result)
553         LOG_ERROR("Application Cache Storage: failed to execute statement \"%s\" error \"%s\"", 
554                   sql.utf8().data(), m_database.lastErrorMsg());
555
556     return result;
557 }
558
559 // Update the schemaVersion when the schema of any the Application Cache
560 // SQLite tables changes. This allows the database to be rebuilt when
561 // a new, incompatible change has been introduced to the database schema.
562 static const int schemaVersion = 7;
563     
564 void ApplicationCacheStorage::verifySchemaVersion()
565 {
566     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
567
568     int version = SQLiteStatement(m_database, "PRAGMA user_version").getColumnInt(0);
569     if (version == schemaVersion)
570         return;
571
572     // Version will be 0 if we just created an empty file. Trying to delete tables would cause errors, because they don't exist yet.
573     if (version)
574         deleteTables();
575
576     // Update user version.
577     SQLiteTransaction setDatabaseVersion(m_database);
578     setDatabaseVersion.begin();
579
580     char userVersionSQL[32];
581     int unusedNumBytes = snprintf(userVersionSQL, sizeof(userVersionSQL), "PRAGMA user_version=%d", schemaVersion);
582     ASSERT_UNUSED(unusedNumBytes, static_cast<int>(sizeof(userVersionSQL)) >= unusedNumBytes);
583
584     SQLiteStatement statement(m_database, userVersionSQL);
585     if (statement.prepare() != SQLITE_OK)
586         return;
587     
588     executeStatement(statement);
589     setDatabaseVersion.commit();
590 }
591     
592 void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist)
593 {
594     SQLiteTransactionInProgressAutoCounter transactionCounter;
595
596     if (m_database.isOpen())
597         return;
598
599     // The cache directory should never be null, but if it for some weird reason is we bail out.
600     if (m_cacheDirectory.isNull())
601         return;
602
603     m_cacheFile = pathByAppendingComponent(m_cacheDirectory, "ApplicationCache.db");
604     if (!createIfDoesNotExist && !fileExists(m_cacheFile))
605         return;
606
607     makeAllDirectories(m_cacheDirectory);
608     m_database.open(m_cacheFile);
609     
610     if (!m_database.isOpen())
611         return;
612     
613     verifySchemaVersion();
614     
615     // Create tables
616     executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheGroups (id INTEGER PRIMARY KEY AUTOINCREMENT, "
617                       "manifestHostHash INTEGER NOT NULL ON CONFLICT FAIL, manifestURL TEXT UNIQUE ON CONFLICT FAIL, newestCache INTEGER, origin TEXT)");
618     executeSQLCommand("CREATE TABLE IF NOT EXISTS Caches (id INTEGER PRIMARY KEY AUTOINCREMENT, cacheGroup INTEGER, size INTEGER)");
619     executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheWhitelistURLs (url TEXT NOT NULL ON CONFLICT FAIL, cache INTEGER NOT NULL ON CONFLICT FAIL)");
620     executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheAllowsAllNetworkRequests (wildcard INTEGER NOT NULL ON CONFLICT FAIL, cache INTEGER NOT NULL ON CONFLICT FAIL)");
621     executeSQLCommand("CREATE TABLE IF NOT EXISTS FallbackURLs (namespace TEXT NOT NULL ON CONFLICT FAIL, fallbackURL TEXT NOT NULL ON CONFLICT FAIL, "
622                       "cache INTEGER NOT NULL ON CONFLICT FAIL)");
623     executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheEntries (cache INTEGER NOT NULL ON CONFLICT FAIL, type INTEGER, resource INTEGER NOT NULL)");
624     executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheResources (id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL ON CONFLICT FAIL, "
625                       "statusCode INTEGER NOT NULL, responseURL TEXT NOT NULL, mimeType TEXT, textEncodingName TEXT, headers TEXT, data INTEGER NOT NULL ON CONFLICT FAIL)");
626     executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheResourceData (id INTEGER PRIMARY KEY AUTOINCREMENT, data BLOB, path TEXT)");
627     executeSQLCommand("CREATE TABLE IF NOT EXISTS DeletedCacheResources (id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT)");
628     executeSQLCommand("CREATE TABLE IF NOT EXISTS Origins (origin TEXT UNIQUE ON CONFLICT IGNORE, quota INTEGER NOT NULL ON CONFLICT FAIL)");
629
630     // When a cache is deleted, all its entries and its whitelist should be deleted.
631     executeSQLCommand("CREATE TRIGGER IF NOT EXISTS CacheDeleted AFTER DELETE ON Caches"
632                       " FOR EACH ROW BEGIN"
633                       "  DELETE FROM CacheEntries WHERE cache = OLD.id;"
634                       "  DELETE FROM CacheWhitelistURLs WHERE cache = OLD.id;"
635                       "  DELETE FROM CacheAllowsAllNetworkRequests WHERE cache = OLD.id;"
636                       "  DELETE FROM FallbackURLs WHERE cache = OLD.id;"
637                       " END");
638
639     // When a cache entry is deleted, its resource should also be deleted.
640     executeSQLCommand("CREATE TRIGGER IF NOT EXISTS CacheEntryDeleted AFTER DELETE ON CacheEntries"
641                       " FOR EACH ROW BEGIN"
642                       "  DELETE FROM CacheResources WHERE id = OLD.resource;"
643                       " END");
644
645     // When a cache resource is deleted, its data blob should also be deleted.
646     executeSQLCommand("CREATE TRIGGER IF NOT EXISTS CacheResourceDeleted AFTER DELETE ON CacheResources"
647                       " FOR EACH ROW BEGIN"
648                       "  DELETE FROM CacheResourceData WHERE id = OLD.data;"
649                       " END");
650     
651     // When a cache resource is deleted, if it contains a non-empty path, that path should
652     // be added to the DeletedCacheResources table so the flat file at that path can
653     // be deleted at a later time.
654     executeSQLCommand("CREATE TRIGGER IF NOT EXISTS CacheResourceDataDeleted AFTER DELETE ON CacheResourceData"
655                       " FOR EACH ROW"
656                       " WHEN OLD.path NOT NULL BEGIN"
657                       "  INSERT INTO DeletedCacheResources (path) values (OLD.path);"
658                       " END");
659 }
660
661 bool ApplicationCacheStorage::executeStatement(SQLiteStatement& statement)
662 {
663     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
664     bool result = statement.executeCommand();
665     if (!result)
666         LOG_ERROR("Application Cache Storage: failed to execute statement \"%s\" error \"%s\"", 
667                   statement.query().utf8().data(), m_database.lastErrorMsg());
668     
669     return result;
670 }    
671
672 bool ApplicationCacheStorage::store(ApplicationCacheGroup* group, GroupStorageIDJournal* journal)
673 {
674     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
675     ASSERT(group->storageID() == 0);
676     ASSERT(journal);
677
678     // For some reason, an app cache may be partially written to disk. In particular, there may be
679     // a cache group with an identical manifest URL and associated cache entries. We want to remove
680     // this cache group and its associated cache entries so that we can create it again (below) as
681     // a way to repair it.
682     deleteCacheGroupRecord(group->manifestURL());
683
684     SQLiteStatement statement(m_database, "INSERT INTO CacheGroups (manifestHostHash, manifestURL, origin) VALUES (?, ?, ?)");
685     if (statement.prepare() != SQLITE_OK)
686         return false;
687
688     statement.bindInt64(1, urlHostHash(group->manifestURL()));
689     statement.bindText(2, group->manifestURL());
690     statement.bindText(3, SecurityOriginData::fromSecurityOrigin(group->origin()).databaseIdentifier());
691
692     if (!executeStatement(statement))
693         return false;
694
695     unsigned groupStorageID = static_cast<unsigned>(m_database.lastInsertRowID());
696
697     if (!ensureOriginRecord(&group->origin()))
698         return false;
699
700     group->setStorageID(groupStorageID);
701     journal->add(group, 0);
702     return true;
703 }    
704
705 bool ApplicationCacheStorage::store(ApplicationCache* cache, ResourceStorageIDJournal* storageIDJournal)
706 {
707     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
708     ASSERT(cache->storageID() == 0);
709     ASSERT(cache->group()->storageID() != 0);
710     ASSERT(storageIDJournal);
711     
712     SQLiteStatement statement(m_database, "INSERT INTO Caches (cacheGroup, size) VALUES (?, ?)");
713     if (statement.prepare() != SQLITE_OK)
714         return false;
715
716     statement.bindInt64(1, cache->group()->storageID());
717     statement.bindInt64(2, cache->estimatedSizeInStorage());
718
719     if (!executeStatement(statement))
720         return false;
721     
722     unsigned cacheStorageID = static_cast<unsigned>(m_database.lastInsertRowID());
723
724     // Store all resources
725     for (auto& resource : cache->resources().values()) {
726         unsigned oldStorageID = resource->storageID();
727         if (!store(resource.get(), cacheStorageID))
728             return false;
729
730         // Storing the resource succeeded. Log its old storageID in case
731         // it needs to be restored later.
732         storageIDJournal->add(resource.get(), oldStorageID);
733     }
734     
735     // Store the online whitelist
736     const Vector<URL>& onlineWhitelist = cache->onlineWhitelist();
737     {
738         for (auto& whitelistURL : onlineWhitelist) {
739             SQLiteStatement statement(m_database, "INSERT INTO CacheWhitelistURLs (url, cache) VALUES (?, ?)");
740             statement.prepare();
741
742             statement.bindText(1, whitelistURL);
743             statement.bindInt64(2, cacheStorageID);
744
745             if (!executeStatement(statement))
746                 return false;
747         }
748     }
749
750     // Store online whitelist wildcard flag.
751     {
752         SQLiteStatement statement(m_database, "INSERT INTO CacheAllowsAllNetworkRequests (wildcard, cache) VALUES (?, ?)");
753         statement.prepare();
754
755         statement.bindInt64(1, cache->allowsAllNetworkRequests());
756         statement.bindInt64(2, cacheStorageID);
757
758         if (!executeStatement(statement))
759             return false;
760     }
761     
762     // Store fallback URLs.
763     const FallbackURLVector& fallbackURLs = cache->fallbackURLs();
764     {
765         for (auto& fallbackURL : fallbackURLs) {
766             SQLiteStatement statement(m_database, "INSERT INTO FallbackURLs (namespace, fallbackURL, cache) VALUES (?, ?, ?)");
767             statement.prepare();
768
769             statement.bindText(1, fallbackURL.first);
770             statement.bindText(2, fallbackURL.second);
771             statement.bindInt64(3, cacheStorageID);
772
773             if (!executeStatement(statement))
774                 return false;
775         }
776     }
777
778     cache->setStorageID(cacheStorageID);
779     return true;
780 }
781
782 bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned cacheStorageID)
783 {
784     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
785     ASSERT(cacheStorageID);
786     ASSERT(!resource->storageID());
787     
788     openDatabase(true);
789
790     // openDatabase(true) could still fail, for example when cacheStorage is full or no longer available.
791     if (!m_database.isOpen())
792         return false;
793
794     // First, insert the data
795     SQLiteStatement dataStatement(m_database, "INSERT INTO CacheResourceData (data, path) VALUES (?, ?)");
796     if (dataStatement.prepare() != SQLITE_OK)
797         return false;
798     
799
800     String fullPath;
801     if (!resource->path().isEmpty())
802         dataStatement.bindText(2, pathGetFileName(resource->path()));
803     else if (shouldStoreResourceAsFlatFile(resource)) {
804         // First, check to see if creating the flat file would violate the maximum total quota. We don't need
805         // to check the per-origin quota here, as it was already checked in storeNewestCache().
806         if (m_database.totalSize() + flatFileAreaSize() + static_cast<int64_t>(resource->data().size()) > m_maximumSize) {
807             m_isMaximumSizeReached = true;
808             return false;
809         }
810         
811         String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
812         makeAllDirectories(flatFileDirectory);
813
814         String extension;
815         
816         String fileName = resource->response().suggestedFilename();
817         size_t dotIndex = fileName.reverseFind('.');
818         if (dotIndex != notFound && dotIndex < (fileName.length() - 1))
819             extension = fileName.substring(dotIndex);
820
821         String path;
822         if (!writeDataToUniqueFileInDirectory(resource->data(), flatFileDirectory, path, extension))
823             return false;
824         
825         fullPath = pathByAppendingComponent(flatFileDirectory, path);
826         resource->setPath(fullPath);
827         dataStatement.bindText(2, path);
828     } else {
829         if (resource->data().size())
830             dataStatement.bindBlob(1, resource->data().data(), resource->data().size());
831     }
832     
833     if (!dataStatement.executeCommand()) {
834         // Clean up the file which we may have written to:
835         if (!fullPath.isEmpty())
836             deleteFile(fullPath);
837
838         return false;
839     }
840
841     unsigned dataId = static_cast<unsigned>(m_database.lastInsertRowID());
842
843     // Then, insert the resource
844     
845     // Serialize the headers
846     StringBuilder stringBuilder;
847     
848     for (const auto& header : resource->response().httpHeaderFields()) {
849         stringBuilder.append(header.key);
850         stringBuilder.append(':');
851         stringBuilder.append(header.value);
852         stringBuilder.append('\n');
853     }
854     
855     String headers = stringBuilder.toString();
856     
857     SQLiteStatement resourceStatement(m_database, "INSERT INTO CacheResources (url, statusCode, responseURL, headers, data, mimeType, textEncodingName) VALUES (?, ?, ?, ?, ?, ?, ?)");
858     if (resourceStatement.prepare() != SQLITE_OK)
859         return false;
860     
861     // The same ApplicationCacheResource are used in ApplicationCacheResource::size()
862     // to calculate the approximate size of an ApplicationCacheResource object. If
863     // you change the code below, please also change ApplicationCacheResource::size().
864     resourceStatement.bindText(1, resource->url());
865     resourceStatement.bindInt64(2, resource->response().httpStatusCode());
866     resourceStatement.bindText(3, resource->response().url());
867     resourceStatement.bindText(4, headers);
868     resourceStatement.bindInt64(5, dataId);
869     resourceStatement.bindText(6, resource->response().mimeType());
870     resourceStatement.bindText(7, resource->response().textEncodingName());
871
872     if (!executeStatement(resourceStatement))
873         return false;
874
875     unsigned resourceId = static_cast<unsigned>(m_database.lastInsertRowID());
876     
877     // Finally, insert the cache entry
878     SQLiteStatement entryStatement(m_database, "INSERT INTO CacheEntries (cache, type, resource) VALUES (?, ?, ?)");
879     if (entryStatement.prepare() != SQLITE_OK)
880         return false;
881     
882     entryStatement.bindInt64(1, cacheStorageID);
883     entryStatement.bindInt64(2, resource->type());
884     entryStatement.bindInt64(3, resourceId);
885     
886     if (!executeStatement(entryStatement))
887         return false;
888     
889     // Did we successfully write the resource data to a file? If so,
890     // release the resource's data and free up a potentially large amount
891     // of memory:
892     if (!fullPath.isEmpty())
893         resource->data().clear();
894
895     resource->setStorageID(resourceId);
896     return true;
897 }
898
899 bool ApplicationCacheStorage::storeUpdatedType(ApplicationCacheResource* resource, ApplicationCache* cache)
900 {
901     SQLiteTransactionInProgressAutoCounter transactionCounter;
902
903     ASSERT_UNUSED(cache, cache->storageID());
904     ASSERT(resource->storageID());
905
906     // First, insert the data
907     SQLiteStatement entryStatement(m_database, "UPDATE CacheEntries SET type=? WHERE resource=?");
908     if (entryStatement.prepare() != SQLITE_OK)
909         return false;
910
911     entryStatement.bindInt64(1, resource->type());
912     entryStatement.bindInt64(2, resource->storageID());
913
914     return executeStatement(entryStatement);
915 }
916
917 bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, ApplicationCache* cache)
918 {
919     SQLiteTransactionInProgressAutoCounter transactionCounter;
920
921     ASSERT(cache->storageID());
922     
923     openDatabase(true);
924
925     if (!m_database.isOpen())
926         return false;
927  
928     m_isMaximumSizeReached = false;
929     m_database.setMaximumSize(m_maximumSize - flatFileAreaSize());
930
931     SQLiteTransaction storeResourceTransaction(m_database);
932     storeResourceTransaction.begin();
933     
934     if (!store(resource, cache->storageID())) {
935         checkForMaxSizeReached();
936         return false;
937     }
938
939     // A resource was added to the cache. Update the total data size for the cache.
940     SQLiteStatement sizeUpdateStatement(m_database, "UPDATE Caches SET size=size+? WHERE id=?");
941     if (sizeUpdateStatement.prepare() != SQLITE_OK)
942         return false;
943
944     sizeUpdateStatement.bindInt64(1, resource->estimatedSizeInStorage());
945     sizeUpdateStatement.bindInt64(2, cache->storageID());
946
947     if (!executeStatement(sizeUpdateStatement))
948         return false;
949     
950     storeResourceTransaction.commit();
951     return true;
952 }
953
954 bool ApplicationCacheStorage::ensureOriginRecord(const SecurityOrigin* origin)
955 {
956     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
957     SQLiteStatement insertOriginStatement(m_database, "INSERT INTO Origins (origin, quota) VALUES (?, ?)");
958     if (insertOriginStatement.prepare() != SQLITE_OK)
959         return false;
960
961     insertOriginStatement.bindText(1, SecurityOriginData::fromSecurityOrigin(*origin).databaseIdentifier());
962     insertOriginStatement.bindInt64(2, m_defaultOriginQuota);
963     if (!executeStatement(insertOriginStatement))
964         return false;
965
966     return true;
967 }
968
969 bool ApplicationCacheStorage::checkOriginQuota(ApplicationCacheGroup* group, ApplicationCache* oldCache, ApplicationCache* newCache, int64_t& totalSpaceNeeded)
970 {
971     // Check if the oldCache with the newCache would reach the per-origin quota.
972     int64_t remainingSpaceInOrigin;
973     auto& origin = group->origin();
974     if (calculateRemainingSizeForOriginExcludingCache(origin, oldCache, remainingSpaceInOrigin)) {
975         if (remainingSpaceInOrigin < newCache->estimatedSizeInStorage()) {
976             int64_t quota;
977             if (calculateQuotaForOrigin(origin, quota)) {
978                 totalSpaceNeeded = quota - remainingSpaceInOrigin + newCache->estimatedSizeInStorage();
979                 return false;
980             }
981
982             ASSERT_NOT_REACHED();
983             totalSpaceNeeded = 0;
984             return false;
985         }
986     }
987
988     return true;
989 }
990
991 bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup& group, ApplicationCache* oldCache, FailureReason& failureReason)
992 {
993     openDatabase(true);
994
995     if (!m_database.isOpen())
996         return false;
997
998     m_isMaximumSizeReached = false;
999     m_database.setMaximumSize(m_maximumSize - flatFileAreaSize());
1000
1001     SQLiteTransaction storeCacheTransaction(m_database);
1002     
1003     storeCacheTransaction.begin();
1004
1005     // Check if this would reach the per-origin quota.
1006     int64_t totalSpaceNeededIgnored;
1007     if (!checkOriginQuota(&group, oldCache, group.newestCache(), totalSpaceNeededIgnored)) {
1008         failureReason = OriginQuotaReached;
1009         return false;
1010     }
1011
1012     GroupStorageIDJournal groupStorageIDJournal;
1013     if (!group.storageID()) {
1014         // Store the group
1015         if (!store(&group, &groupStorageIDJournal)) {
1016             checkForMaxSizeReached();
1017             failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure;
1018             return false;
1019         }
1020     }
1021     
1022     ASSERT(group.newestCache());
1023     ASSERT(!group.isObsolete());
1024     ASSERT(!group.newestCache()->storageID());
1025     
1026     // Log the storageID changes to the in-memory resource objects. The journal
1027     // object will roll them back automatically in case a database operation
1028     // fails and this method returns early.
1029     ResourceStorageIDJournal resourceStorageIDJournal;
1030
1031     // Store the newest cache
1032     if (!store(group.newestCache(), &resourceStorageIDJournal)) {
1033         checkForMaxSizeReached();
1034         failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure;
1035         return false;
1036     }
1037     
1038     // Update the newest cache in the group.
1039     
1040     SQLiteStatement statement(m_database, "UPDATE CacheGroups SET newestCache=? WHERE id=?");
1041     if (statement.prepare() != SQLITE_OK) {
1042         failureReason = DiskOrOperationFailure;
1043         return false;
1044     }
1045     
1046     statement.bindInt64(1, group.newestCache()->storageID());
1047     statement.bindInt64(2, group.storageID());
1048     
1049     if (!executeStatement(statement)) {
1050         failureReason = DiskOrOperationFailure;
1051         return false;
1052     }
1053     
1054     groupStorageIDJournal.commit();
1055     resourceStorageIDJournal.commit();
1056     storeCacheTransaction.commit();
1057     return true;
1058 }
1059
1060 bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup& group)
1061 {
1062     // Ignore the reason for failing, just attempt the store.
1063     FailureReason ignoredFailureReason;
1064     return storeNewestCache(group, nullptr, ignoredFailureReason);
1065 }
1066
1067 template<typename CharacterType>
1068 static inline void parseHeader(const CharacterType* header, unsigned headerLength, ResourceResponse& response)
1069 {
1070     ASSERT(find(header, headerLength, ':') != notFound);
1071     unsigned colonPosition = find(header, headerLength, ':');
1072
1073     // Save memory by putting the header names into atomic strings so each is stored only once,
1074     // even though the setHTTPHeaderField function does not require an atomic string.
1075     AtomicString headerName { header, colonPosition };
1076     String headerValue { header + colonPosition + 1, headerLength - colonPosition - 1 };
1077
1078     response.setHTTPHeaderField(headerName, headerValue);
1079 }
1080
1081 static inline void parseHeaders(const String& headers, ResourceResponse& response)
1082 {
1083     unsigned startPos = 0;
1084     size_t endPos;
1085     while ((endPos = headers.find('\n', startPos)) != notFound) {
1086         ASSERT(startPos != endPos);
1087
1088         if (headers.is8Bit())
1089             parseHeader(headers.characters8() + startPos, endPos - startPos, response);
1090         else
1091             parseHeader(headers.characters16() + startPos, endPos - startPos, response);
1092         
1093         startPos = endPos + 1;
1094     }
1095     
1096     if (startPos != headers.length()) {
1097         if (headers.is8Bit())
1098             parseHeader(headers.characters8(), headers.length(), response);
1099         else
1100             parseHeader(headers.characters16(), headers.length(), response);
1101     }
1102 }
1103     
1104 RefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storageID)
1105 {
1106     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
1107     SQLiteStatement cacheStatement(m_database,
1108                                    "SELECT url, statusCode, type, mimeType, textEncodingName, headers, CacheResourceData.data, CacheResourceData.path FROM CacheEntries INNER JOIN CacheResources ON CacheEntries.resource=CacheResources.id "
1109                                    "INNER JOIN CacheResourceData ON CacheResourceData.id=CacheResources.data WHERE CacheEntries.cache=?");
1110     if (cacheStatement.prepare() != SQLITE_OK) {
1111         LOG_ERROR("Could not prepare cache statement, error \"%s\"", m_database.lastErrorMsg());
1112         return nullptr;
1113     }
1114     
1115     cacheStatement.bindInt64(1, storageID);
1116
1117     auto cache = ApplicationCache::create();
1118
1119     String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
1120
1121     int result;
1122     while ((result = cacheStatement.step()) == SQLITE_ROW) {
1123         URL url(ParsedURLString, cacheStatement.getColumnText(0));
1124         
1125         int httpStatusCode = cacheStatement.getColumnInt(1);
1126
1127         unsigned type = static_cast<unsigned>(cacheStatement.getColumnInt64(2));
1128
1129         Vector<char> blob;
1130         cacheStatement.getColumnBlobAsVector(6, blob);
1131         
1132         auto data = SharedBuffer::create(WTFMove(blob));
1133         
1134         String path = cacheStatement.getColumnText(7);
1135         long long size = 0;
1136         if (path.isEmpty())
1137             size = data->size();
1138         else {
1139             path = pathByAppendingComponent(flatFileDirectory, path);
1140             getFileSize(path, size);
1141         }
1142         
1143         String mimeType = cacheStatement.getColumnText(3);
1144         String textEncodingName = cacheStatement.getColumnText(4);
1145         
1146         ResourceResponse response(url, mimeType, size, textEncodingName);
1147         response.setHTTPStatusCode(httpStatusCode);
1148
1149         String headers = cacheStatement.getColumnText(5);
1150         parseHeaders(headers, response);
1151         
1152         auto resource = ApplicationCacheResource::create(url, response, type, WTFMove(data), path);
1153
1154         if (type & ApplicationCacheResource::Manifest)
1155             cache->setManifestResource(WTFMove(resource));
1156         else
1157             cache->addResource(WTFMove(resource));
1158     }
1159
1160     if (result != SQLITE_DONE)
1161         LOG_ERROR("Could not load cache resources, error \"%s\"", m_database.lastErrorMsg());
1162
1163     if (!cache->manifestResource()) {
1164         LOG_ERROR("Could not load application cache because there was no manifest resource");
1165         return nullptr;
1166     }
1167
1168     // Load the online whitelist
1169     SQLiteStatement whitelistStatement(m_database, "SELECT url FROM CacheWhitelistURLs WHERE cache=?");
1170     if (whitelistStatement.prepare() != SQLITE_OK)
1171         return nullptr;
1172     whitelistStatement.bindInt64(1, storageID);
1173     
1174     Vector<URL> whitelist;
1175     while ((result = whitelistStatement.step()) == SQLITE_ROW) 
1176         whitelist.append(URL(ParsedURLString, whitelistStatement.getColumnText(0)));
1177
1178     if (result != SQLITE_DONE)
1179         LOG_ERROR("Could not load cache online whitelist, error \"%s\"", m_database.lastErrorMsg());
1180
1181     cache->setOnlineWhitelist(whitelist);
1182
1183     // Load online whitelist wildcard flag.
1184     SQLiteStatement whitelistWildcardStatement(m_database, "SELECT wildcard FROM CacheAllowsAllNetworkRequests WHERE cache=?");
1185     if (whitelistWildcardStatement.prepare() != SQLITE_OK)
1186         return nullptr;
1187     whitelistWildcardStatement.bindInt64(1, storageID);
1188     
1189     result = whitelistWildcardStatement.step();
1190     if (result != SQLITE_ROW)
1191         LOG_ERROR("Could not load cache online whitelist wildcard flag, error \"%s\"", m_database.lastErrorMsg());
1192
1193     cache->setAllowsAllNetworkRequests(whitelistWildcardStatement.getColumnInt64(0));
1194
1195     if (whitelistWildcardStatement.step() != SQLITE_DONE)
1196         LOG_ERROR("Too many rows for online whitelist wildcard flag");
1197
1198     // Load fallback URLs.
1199     SQLiteStatement fallbackStatement(m_database, "SELECT namespace, fallbackURL FROM FallbackURLs WHERE cache=?");
1200     if (fallbackStatement.prepare() != SQLITE_OK)
1201         return nullptr;
1202     fallbackStatement.bindInt64(1, storageID);
1203     
1204     FallbackURLVector fallbackURLs;
1205     while ((result = fallbackStatement.step()) == SQLITE_ROW) 
1206         fallbackURLs.append(std::make_pair(URL(ParsedURLString, fallbackStatement.getColumnText(0)), URL(ParsedURLString, fallbackStatement.getColumnText(1))));
1207
1208     if (result != SQLITE_DONE)
1209         LOG_ERROR("Could not load fallback URLs, error \"%s\"", m_database.lastErrorMsg());
1210
1211     cache->setFallbackURLs(fallbackURLs);
1212     
1213     cache->setStorageID(storageID);
1214
1215     return WTFMove(cache);
1216 }    
1217     
1218 void ApplicationCacheStorage::remove(ApplicationCache* cache)
1219 {
1220     SQLiteTransactionInProgressAutoCounter transactionCounter;
1221
1222     if (!cache->storageID())
1223         return;
1224     
1225     openDatabase(false);
1226     if (!m_database.isOpen())
1227         return;
1228
1229     ASSERT(cache->group());
1230     ASSERT(cache->group()->storageID());
1231
1232     // All associated data will be deleted by database triggers.
1233     SQLiteStatement statement(m_database, "DELETE FROM Caches WHERE id=?");
1234     if (statement.prepare() != SQLITE_OK)
1235         return;
1236     
1237     statement.bindInt64(1, cache->storageID());
1238     executeStatement(statement);
1239
1240     cache->clearStorageID();
1241
1242     if (cache->group()->newestCache() == cache) {
1243         // Currently, there are no triggers on the cache group, which is why the cache had to be removed separately above.
1244         SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
1245         if (groupStatement.prepare() != SQLITE_OK)
1246             return;
1247         
1248         groupStatement.bindInt64(1, cache->group()->storageID());
1249         executeStatement(groupStatement);
1250
1251         cache->group()->clearStorageID();
1252     }
1253     
1254     checkForDeletedResources();
1255 }    
1256
1257 void ApplicationCacheStorage::empty()
1258 {
1259     SQLiteTransactionInProgressAutoCounter transactionCounter;
1260
1261     openDatabase(false);
1262     
1263     if (!m_database.isOpen())
1264         return;
1265     
1266     // Clear cache groups, caches, cache resources, and origins.
1267     executeSQLCommand("DELETE FROM CacheGroups");
1268     executeSQLCommand("DELETE FROM Caches");
1269     executeSQLCommand("DELETE FROM Origins");
1270     
1271     // Clear the storage IDs for the caches in memory.
1272     // The caches will still work, but cached resources will not be saved to disk 
1273     // until a cache update process has been initiated.
1274     for (auto* group : m_cachesInMemory.values())
1275         group->clearStorageID();
1276
1277     checkForDeletedResources();
1278 }
1279     
1280 void ApplicationCacheStorage::deleteTables()
1281 {
1282     empty();
1283     m_database.clearAllTables();
1284 }
1285     
1286 bool ApplicationCacheStorage::shouldStoreResourceAsFlatFile(ApplicationCacheResource* resource)
1287 {
1288     return resource->response().mimeType().startsWith("audio/", false) 
1289         || resource->response().mimeType().startsWith("video/", false);
1290 }
1291     
1292 bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer& data, const String& directory, String& path, const String& fileExtension)
1293 {
1294     String fullPath;
1295     
1296     do {
1297         path = encodeForFileName(createCanonicalUUIDString()) + fileExtension;
1298         // Guard against the above function being called on a platform which does not implement
1299         // createCanonicalUUIDString().
1300         ASSERT(!path.isEmpty());
1301         if (path.isEmpty())
1302             return false;
1303         
1304         fullPath = pathByAppendingComponent(directory, path);
1305     } while (directoryName(fullPath) != directory || fileExists(fullPath));
1306     
1307     PlatformFileHandle handle = openFile(fullPath, OpenForWrite);
1308     if (!handle)
1309         return false;
1310     
1311     int64_t writtenBytes = writeToFile(handle, data.data(), data.size());
1312     closeFile(handle);
1313     
1314     if (writtenBytes != static_cast<int64_t>(data.size())) {
1315         deleteFile(fullPath);
1316         return false;
1317     }
1318     
1319     return true;
1320 }
1321
1322 bool ApplicationCacheStorage::getManifestURLs(Vector<URL>* urls)
1323 {
1324     SQLiteTransactionInProgressAutoCounter transactionCounter;
1325
1326     ASSERT(urls);
1327     openDatabase(false);
1328     if (!m_database.isOpen())
1329         return false;
1330
1331     SQLiteStatement selectURLs(m_database, "SELECT manifestURL FROM CacheGroups");
1332
1333     if (selectURLs.prepare() != SQLITE_OK)
1334         return false;
1335
1336     while (selectURLs.step() == SQLITE_ROW)
1337         urls->append(URL(ParsedURLString, selectURLs.getColumnText(0)));
1338
1339     return true;
1340 }
1341
1342 bool ApplicationCacheStorage::cacheGroupSize(const String& manifestURL, int64_t* size)
1343 {
1344     SQLiteTransactionInProgressAutoCounter transactionCounter;
1345
1346     ASSERT(size);
1347     openDatabase(false);
1348     if (!m_database.isOpen())
1349         return false;
1350
1351     SQLiteStatement statement(m_database, "SELECT sum(Caches.size) FROM Caches INNER JOIN CacheGroups ON Caches.cacheGroup=CacheGroups.id WHERE CacheGroups.manifestURL=?");
1352     if (statement.prepare() != SQLITE_OK)
1353         return false;
1354
1355     statement.bindText(1, manifestURL);
1356
1357     int result = statement.step();
1358     if (result == SQLITE_DONE)
1359         return false;
1360
1361     if (result != SQLITE_ROW) {
1362         LOG_ERROR("Could not get the size of the cache group, error \"%s\"", m_database.lastErrorMsg());
1363         return false;
1364     }
1365
1366     *size = statement.getColumnInt64(0);
1367     return true;
1368 }
1369
1370 bool ApplicationCacheStorage::deleteCacheGroupRecord(const String& manifestURL)
1371 {
1372     ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
1373     SQLiteStatement idStatement(m_database, "SELECT id FROM CacheGroups WHERE manifestURL=?");
1374     if (idStatement.prepare() != SQLITE_OK)
1375         return false;
1376
1377     idStatement.bindText(1, manifestURL);
1378
1379     int result = idStatement.step();
1380     if (result != SQLITE_ROW)
1381         return false;
1382
1383     int64_t groupId = idStatement.getColumnInt64(0);
1384
1385     SQLiteStatement cacheStatement(m_database, "DELETE FROM Caches WHERE cacheGroup=?");
1386     if (cacheStatement.prepare() != SQLITE_OK)
1387         return false;
1388
1389     SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
1390     if (groupStatement.prepare() != SQLITE_OK)
1391         return false;
1392
1393     cacheStatement.bindInt64(1, groupId);
1394     executeStatement(cacheStatement);
1395     groupStatement.bindInt64(1, groupId);
1396     executeStatement(groupStatement);
1397     return true;
1398 }
1399
1400 bool ApplicationCacheStorage::deleteCacheGroup(const String& manifestURL)
1401 {
1402     SQLiteTransactionInProgressAutoCounter transactionCounter;
1403
1404     SQLiteTransaction deleteTransaction(m_database);
1405
1406     // Check to see if the group is in memory.
1407     auto* group = m_cachesInMemory.get(manifestURL);
1408     if (group)
1409         cacheGroupMadeObsolete(*group);
1410     else {
1411         // The cache group is not in memory, so remove it from the disk.
1412         openDatabase(false);
1413         if (!m_database.isOpen())
1414             return false;
1415         if (!deleteCacheGroupRecord(manifestURL)) {
1416             LOG_ERROR("Could not delete cache group record, error \"%s\"", m_database.lastErrorMsg());
1417             return false;
1418         }
1419     }
1420
1421     deleteTransaction.commit();
1422
1423     checkForDeletedResources();
1424
1425     return true;
1426 }
1427
1428 void ApplicationCacheStorage::vacuumDatabaseFile()
1429 {
1430     SQLiteTransactionInProgressAutoCounter transactionCounter;
1431
1432     openDatabase(false);
1433     if (!m_database.isOpen())
1434         return;
1435
1436     m_database.runVacuumCommand();
1437 }
1438
1439 void ApplicationCacheStorage::checkForMaxSizeReached()
1440 {
1441     if (m_database.lastError() == SQLITE_FULL)
1442         m_isMaximumSizeReached = true;
1443 }
1444     
1445 void ApplicationCacheStorage::checkForDeletedResources()
1446 {
1447     openDatabase(false);
1448     if (!m_database.isOpen())
1449         return;
1450
1451     // Select only the paths in DeletedCacheResources that do not also appear in CacheResourceData:
1452     SQLiteStatement selectPaths(m_database, "SELECT DeletedCacheResources.path "
1453         "FROM DeletedCacheResources "
1454         "LEFT JOIN CacheResourceData "
1455         "ON DeletedCacheResources.path = CacheResourceData.path "
1456         "WHERE (SELECT DeletedCacheResources.path == CacheResourceData.path) IS NULL");
1457     
1458     if (selectPaths.prepare() != SQLITE_OK)
1459         return;
1460     
1461     if (selectPaths.step() != SQLITE_ROW)
1462         return;
1463     
1464     do {
1465         String path = selectPaths.getColumnText(0);
1466         if (path.isEmpty())
1467             continue;
1468         
1469         String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
1470         String fullPath = pathByAppendingComponent(flatFileDirectory, path);
1471         
1472         // Don't exit the flatFileDirectory! This should only happen if the "path" entry contains a directory 
1473         // component, but protect against it regardless.
1474         if (directoryName(fullPath) != flatFileDirectory)
1475             continue;
1476         
1477         deleteFile(fullPath);
1478     } while (selectPaths.step() == SQLITE_ROW);
1479     
1480     executeSQLCommand("DELETE FROM DeletedCacheResources");
1481 }
1482     
1483 long long ApplicationCacheStorage::flatFileAreaSize()
1484 {
1485     openDatabase(false);
1486     if (!m_database.isOpen())
1487         return 0;
1488     
1489     SQLiteStatement selectPaths(m_database, "SELECT path FROM CacheResourceData WHERE path NOT NULL");
1490
1491     if (selectPaths.prepare() != SQLITE_OK) {
1492         LOG_ERROR("Could not load flat file cache resource data, error \"%s\"", m_database.lastErrorMsg());
1493         return 0;
1494     }
1495
1496     long long totalSize = 0;
1497     String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName);
1498     while (selectPaths.step() == SQLITE_ROW) {
1499         String path = selectPaths.getColumnText(0);
1500         String fullPath = pathByAppendingComponent(flatFileDirectory, path);
1501         long long pathSize = 0;
1502         if (!getFileSize(fullPath, pathSize))
1503             continue;
1504         totalSize += pathSize;
1505     }
1506     
1507     return totalSize;
1508 }
1509
1510 void ApplicationCacheStorage::getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>>& origins)
1511 {
1512     Vector<URL> urls;
1513     getManifestURLs(&urls);
1514
1515     // Multiple manifest URLs might share the same SecurityOrigin, so we might be creating extra, wasted origins here.
1516     // The current schema doesn't allow for a more efficient way of building this list.
1517     for (auto& url : urls)
1518         origins.add(SecurityOrigin::create(url));
1519 }
1520
1521 void ApplicationCacheStorage::deleteAllEntries()
1522 {
1523     empty();
1524     vacuumDatabaseFile();
1525 }
1526
1527 void ApplicationCacheStorage::deleteAllCaches()
1528 {
1529     HashSet<RefPtr<SecurityOrigin>> origins;
1530
1531     getOriginsWithCache(origins);
1532     for (auto& origin : origins)
1533         deleteCacheForOrigin(*origin);
1534
1535     vacuumDatabaseFile();
1536 }
1537
1538 void ApplicationCacheStorage::deleteCacheForOrigin(const SecurityOrigin& securityOrigin)
1539 {
1540     Vector<URL> urls;
1541     if (!getManifestURLs(&urls)) {
1542         LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs");
1543         return;
1544     }
1545
1546     URL originURL(URL(), securityOrigin.toString());
1547
1548     for (const auto& url : urls) {
1549         if (!protocolHostAndPortAreEqual(url, originURL))
1550             continue;
1551
1552         if (auto* group = findInMemoryCacheGroup(url))
1553             group->makeObsolete();
1554         else
1555             deleteCacheGroup(url);
1556     }
1557 }
1558
1559 int64_t ApplicationCacheStorage::diskUsageForOrigin(const SecurityOrigin& securityOrigin)
1560 {
1561     int64_t usage = 0;
1562     calculateUsageForOrigin(&securityOrigin, usage);
1563     return usage;
1564 }
1565
1566 ApplicationCacheStorage::ApplicationCacheStorage(const String& cacheDirectory, const String& flatFileSubdirectoryName)
1567     : m_cacheDirectory(cacheDirectory)
1568     , m_flatFileSubdirectoryName(flatFileSubdirectoryName)
1569     , m_maximumSize(ApplicationCacheStorage::noQuota())
1570     , m_isMaximumSizeReached(false)
1571     , m_defaultOriginQuota(ApplicationCacheStorage::noQuota())
1572 {
1573 }
1574
1575 Ref<ApplicationCacheStorage> ApplicationCacheStorage::create(const String& cacheDirectory, const String& flatFileSubdirectoryName)
1576 {
1577     return adoptRef(*new ApplicationCacheStorage(cacheDirectory, flatFileSubdirectoryName));
1578 }
1579
1580 }