1/* 2 * Copyright (C) 2008 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 "ApplicationCache.h" 28 29#include "ApplicationCacheGroup.h" 30#include "ApplicationCacheResource.h" 31#include "ApplicationCacheStorage.h" 32#include "ResourceRequest.h" 33#include "SecurityOrigin.h" 34#include <algorithm> 35#include <stdio.h> 36#include <wtf/text/CString.h> 37 38namespace WebCore { 39 40static inline bool fallbackURLLongerThan(const std::pair<URL, URL>& lhs, const std::pair<URL, URL>& rhs) 41{ 42 return lhs.first.string().length() > rhs.first.string().length(); 43} 44 45ApplicationCache::ApplicationCache() 46 : m_group(0) 47 , m_manifest(0) 48 , m_estimatedSizeInStorage(0) 49 , m_storageID(0) 50{ 51} 52 53ApplicationCache::~ApplicationCache() 54{ 55 if (m_group && !m_group->isCopy()) 56 m_group->cacheDestroyed(this); 57} 58 59void ApplicationCache::setGroup(ApplicationCacheGroup* group) 60{ 61 ASSERT(!m_group || group == m_group); 62 m_group = group; 63} 64 65bool ApplicationCache::isComplete() const 66{ 67 return !m_group->cacheIsBeingUpdated(this); 68} 69 70void ApplicationCache::setManifestResource(PassRefPtr<ApplicationCacheResource> manifest) 71{ 72 ASSERT(manifest); 73 ASSERT(!m_manifest); 74 ASSERT(manifest->type() & ApplicationCacheResource::Manifest); 75 76 m_manifest = manifest.get(); 77 78 addResource(manifest); 79} 80 81void ApplicationCache::addResource(PassRefPtr<ApplicationCacheResource> resource) 82{ 83 ASSERT(resource); 84 85 const String& url = resource->url(); 86 87 ASSERT(!m_resources.contains(url)); 88 89 if (m_storageID) { 90 ASSERT(!resource->storageID()); 91 ASSERT(resource->type() & ApplicationCacheResource::Master); 92 93 // Add the resource to the storage. 94 cacheStorage().store(resource.get(), this); 95 } 96 97 m_estimatedSizeInStorage += resource->estimatedSizeInStorage(); 98 99 m_resources.set(url, resource); 100} 101 102unsigned ApplicationCache::removeResource(const String& url) 103{ 104 HashMap<String, RefPtr<ApplicationCacheResource>>::iterator it = m_resources.find(url); 105 if (it == m_resources.end()) 106 return 0; 107 108 // The resource exists, get its type so we can return it. 109 unsigned type = it->value->type(); 110 111 m_estimatedSizeInStorage -= it->value->estimatedSizeInStorage(); 112 113 m_resources.remove(it); 114 115 return type; 116} 117 118ApplicationCacheResource* ApplicationCache::resourceForURL(const String& url) 119{ 120 ASSERT(!URL(ParsedURLString, url).hasFragmentIdentifier()); 121 return m_resources.get(url); 122} 123 124bool ApplicationCache::requestIsHTTPOrHTTPSGet(const ResourceRequest& request) 125{ 126 if (!request.url().protocolIsInHTTPFamily()) 127 return false; 128 129 if (!equalIgnoringCase(request.httpMethod(), "GET")) 130 return false; 131 132 return true; 133} 134 135ApplicationCacheResource* ApplicationCache::resourceForRequest(const ResourceRequest& request) 136{ 137 // We only care about HTTP/HTTPS GET requests. 138 if (!requestIsHTTPOrHTTPSGet(request)) 139 return 0; 140 141 URL url(request.url()); 142 if (url.hasFragmentIdentifier()) 143 url.removeFragmentIdentifier(); 144 145 return resourceForURL(url); 146} 147 148void ApplicationCache::setOnlineWhitelist(const Vector<URL>& onlineWhitelist) 149{ 150 ASSERT(m_onlineWhitelist.isEmpty()); 151 m_onlineWhitelist = onlineWhitelist; 152} 153 154bool ApplicationCache::isURLInOnlineWhitelist(const URL& url) 155{ 156 size_t whitelistSize = m_onlineWhitelist.size(); 157 for (size_t i = 0; i < whitelistSize; ++i) { 158 if (protocolHostAndPortAreEqual(url, m_onlineWhitelist[i]) && url.string().startsWith(m_onlineWhitelist[i].string())) 159 return true; 160 } 161 return false; 162} 163 164void ApplicationCache::setFallbackURLs(const FallbackURLVector& fallbackURLs) 165{ 166 ASSERT(m_fallbackURLs.isEmpty()); 167 m_fallbackURLs = fallbackURLs; 168 // FIXME: What's the right behavior if we have 2 or more identical namespace URLs? 169 std::stable_sort(m_fallbackURLs.begin(), m_fallbackURLs.end(), fallbackURLLongerThan); 170} 171 172bool ApplicationCache::urlMatchesFallbackNamespace(const URL& url, URL* fallbackURL) 173{ 174 size_t fallbackCount = m_fallbackURLs.size(); 175 for (size_t i = 0; i < fallbackCount; ++i) { 176 if (protocolHostAndPortAreEqual(url, m_fallbackURLs[i].first) && url.string().startsWith(m_fallbackURLs[i].first.string())) { 177 if (fallbackURL) 178 *fallbackURL = m_fallbackURLs[i].second; 179 return true; 180 } 181 } 182 return false; 183} 184 185void ApplicationCache::clearStorageID() 186{ 187 m_storageID = 0; 188 189 for (const auto& resource : m_resources.values()) 190 resource->clearStorageID(); 191} 192 193void ApplicationCache::deleteCacheForOrigin(SecurityOrigin* origin) 194{ 195 Vector<URL> urls; 196 if (!cacheStorage().manifestURLs(&urls)) { 197 LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs"); 198 return; 199 } 200 201 URL originURL(URL(), origin->toString()); 202 203 size_t count = urls.size(); 204 for (size_t i = 0; i < count; ++i) { 205 if (protocolHostAndPortAreEqual(urls[i], originURL)) { 206 ApplicationCacheGroup* group = cacheStorage().findInMemoryCacheGroup(urls[i]); 207 if (group) 208 group->makeObsolete(); 209 else 210 cacheStorage().deleteCacheGroup(urls[i]); 211 } 212 } 213} 214 215int64_t ApplicationCache::diskUsageForOrigin(SecurityOrigin* origin) 216{ 217 int64_t usage = 0; 218 cacheStorage().calculateUsageForOrigin(origin, usage); 219 return usage; 220} 221 222#ifndef NDEBUG 223void ApplicationCache::dump() 224{ 225 for (const auto& urlAndResource : m_resources) { 226 printf("%s ", urlAndResource.key.utf8().data()); 227 ApplicationCacheResource::dumpType(urlAndResource.value->type()); 228 } 229} 230#endif 231 232} 233