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