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