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