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