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
ApplicationCache()41 ApplicationCache::ApplicationCache()
42 : m_group(0)
43 , m_manifest(0)
44 , m_estimatedSizeInStorage(0)
45 , m_storageID(0)
46 {
47 }
48
~ApplicationCache()49 ApplicationCache::~ApplicationCache()
50 {
51 if (m_group && !m_group->isCopy())
52 m_group->cacheDestroyed(this);
53 }
54
setGroup(ApplicationCacheGroup * group)55 void ApplicationCache::setGroup(ApplicationCacheGroup* group)
56 {
57 ASSERT(!m_group || group == m_group);
58 m_group = group;
59 }
60
isComplete() const61 bool ApplicationCache::isComplete() const
62 {
63 return !m_group->cacheIsBeingUpdated(this);
64 }
65
setManifestResource(PassRefPtr<ApplicationCacheResource> manifest)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
addResource(PassRefPtr<ApplicationCacheResource> resource)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
removeResource(const String & url)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
resourceForURL(const String & url)114 ApplicationCacheResource* ApplicationCache::resourceForURL(const String& url)
115 {
116 ASSERT(!KURL(ParsedURLString, url).hasFragmentIdentifier());
117 return m_resources.get(url).get();
118 }
119
requestIsHTTPOrHTTPSGet(const ResourceRequest & request)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
resourceForRequest(const ResourceRequest & request)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
setOnlineWhitelist(const Vector<KURL> & onlineWhitelist)144 void ApplicationCache::setOnlineWhitelist(const Vector<KURL>& onlineWhitelist)
145 {
146 ASSERT(m_onlineWhitelist.isEmpty());
147 m_onlineWhitelist = onlineWhitelist;
148 }
149
isURLInOnlineWhitelist(const KURL & url)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
setFallbackURLs(const FallbackURLVector & fallbackURLs)160 void ApplicationCache::setFallbackURLs(const FallbackURLVector& fallbackURLs)
161 {
162 ASSERT(m_fallbackURLs.isEmpty());
163 m_fallbackURLs = fallbackURLs;
164 }
165
urlMatchesFallbackNamespace(const KURL & url,KURL * fallbackURL)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
clearStorageID()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
deleteCacheForOrigin(SecurityOrigin * origin)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
dump()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