1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/appcache/appcache.h"
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "content/browser/appcache/appcache_executable_handler.h"
12 #include "content/browser/appcache/appcache_group.h"
13 #include "content/browser/appcache/appcache_host.h"
14 #include "content/browser/appcache/appcache_storage.h"
15 #include "content/common/appcache_interfaces.h"
19 AppCache::AppCache(AppCacheStorage
* storage
, int64 cache_id
)
20 : cache_id_(cache_id
),
22 online_whitelist_all_(false),
26 storage_
->working_set()->AddCache(this);
29 AppCache::~AppCache() {
30 DCHECK(associated_hosts_
.empty());
31 if (owning_group_
.get()) {
33 owning_group_
->RemoveCache(this);
35 DCHECK(!owning_group_
.get());
36 storage_
->working_set()->RemoveCache(this);
37 STLDeleteContainerPairSecondPointers(
38 executable_handlers_
.begin(), executable_handlers_
.end());
41 void AppCache::UnassociateHost(AppCacheHost
* host
) {
42 associated_hosts_
.erase(host
);
45 void AppCache::AddEntry(const GURL
& url
, const AppCacheEntry
& entry
) {
46 DCHECK(entries_
.find(url
) == entries_
.end());
47 entries_
.insert(EntryMap::value_type(url
, entry
));
48 cache_size_
+= entry
.response_size();
51 bool AppCache::AddOrModifyEntry(const GURL
& url
, const AppCacheEntry
& entry
) {
52 std::pair
<EntryMap::iterator
, bool> ret
=
53 entries_
.insert(EntryMap::value_type(url
, entry
));
55 // Entry already exists. Merge the types of the new and existing entries.
57 ret
.first
->second
.add_types(entry
.types());
59 cache_size_
+= entry
.response_size(); // New entry. Add to cache size.
63 void AppCache::RemoveEntry(const GURL
& url
) {
64 EntryMap::iterator found
= entries_
.find(url
);
65 DCHECK(found
!= entries_
.end());
66 cache_size_
-= found
->second
.response_size();
67 entries_
.erase(found
);
70 AppCacheEntry
* AppCache::GetEntry(const GURL
& url
) {
71 EntryMap::iterator it
= entries_
.find(url
);
72 return (it
!= entries_
.end()) ? &(it
->second
) : NULL
;
75 const AppCacheEntry
* AppCache::GetEntryAndUrlWithResponseId(
76 int64 response_id
, GURL
* optional_url_out
) {
77 for (EntryMap::const_iterator iter
= entries_
.begin();
78 iter
!= entries_
.end(); ++iter
) {
79 if (iter
->second
.response_id() == response_id
) {
81 *optional_url_out
= iter
->first
;
88 AppCacheExecutableHandler
* AppCache::GetExecutableHandler(int64 response_id
) {
89 HandlerMap::const_iterator found
= executable_handlers_
.find(response_id
);
90 if (found
!= executable_handlers_
.end())
95 AppCacheExecutableHandler
* AppCache::GetOrCreateExecutableHandler(
96 int64 response_id
, net::IOBuffer
* handler_source
) {
97 AppCacheExecutableHandler
* handler
= GetExecutableHandler(response_id
);
102 const AppCacheEntry
* entry
= GetEntryAndUrlWithResponseId(
103 response_id
, &handler_url
);
104 if (!entry
|| !entry
->IsExecutable())
107 DCHECK(storage_
->service()->handler_factory());
108 scoped_ptr
<AppCacheExecutableHandler
> own_ptr
=
109 storage_
->service()->handler_factory()->
110 CreateHandler(handler_url
, handler_source
);
111 handler
= own_ptr
.release();
114 executable_handlers_
[response_id
] = handler
;
118 GURL
AppCache::GetNamespaceEntryUrl(const AppCacheNamespaceVector
& namespaces
,
119 const GURL
& namespace_url
) const {
120 size_t count
= namespaces
.size();
121 for (size_t i
= 0; i
< count
; ++i
) {
122 if (namespaces
[i
].namespace_url
== namespace_url
)
123 return namespaces
[i
].target_url
;
130 bool SortNamespacesByLength(
131 const AppCacheNamespace
& lhs
, const AppCacheNamespace
& rhs
) {
132 return lhs
.namespace_url
.spec().length() > rhs
.namespace_url
.spec().length();
136 void AppCache::InitializeWithManifest(AppCacheManifest
* manifest
) {
138 intercept_namespaces_
.swap(manifest
->intercept_namespaces
);
139 fallback_namespaces_
.swap(manifest
->fallback_namespaces
);
140 online_whitelist_namespaces_
.swap(manifest
->online_whitelist_namespaces
);
141 online_whitelist_all_
= manifest
->online_whitelist_all
;
143 // Sort the namespaces by url string length, longest to shortest,
144 // since longer matches trump when matching a url to a namespace.
145 std::sort(intercept_namespaces_
.begin(), intercept_namespaces_
.end(),
146 SortNamespacesByLength
);
147 std::sort(fallback_namespaces_
.begin(), fallback_namespaces_
.end(),
148 SortNamespacesByLength
);
151 void AppCache::InitializeWithDatabaseRecords(
152 const AppCacheDatabase::CacheRecord
& cache_record
,
153 const std::vector
<AppCacheDatabase::EntryRecord
>& entries
,
154 const std::vector
<AppCacheDatabase::NamespaceRecord
>& intercepts
,
155 const std::vector
<AppCacheDatabase::NamespaceRecord
>& fallbacks
,
156 const std::vector
<AppCacheDatabase::OnlineWhiteListRecord
>& whitelists
) {
157 DCHECK(cache_id_
== cache_record
.cache_id
);
158 online_whitelist_all_
= cache_record
.online_wildcard
;
159 update_time_
= cache_record
.update_time
;
161 for (size_t i
= 0; i
< entries
.size(); ++i
) {
162 const AppCacheDatabase::EntryRecord
& entry
= entries
.at(i
);
163 AddEntry(entry
.url
, AppCacheEntry(entry
.flags
, entry
.response_id
,
164 entry
.response_size
));
166 DCHECK(cache_size_
== cache_record
.cache_size
);
168 for (size_t i
= 0; i
< intercepts
.size(); ++i
)
169 intercept_namespaces_
.push_back(intercepts
.at(i
).namespace_
);
171 for (size_t i
= 0; i
< fallbacks
.size(); ++i
)
172 fallback_namespaces_
.push_back(fallbacks
.at(i
).namespace_
);
174 // Sort the fallback namespaces by url string length, longest to shortest,
175 // since longer matches trump when matching a url to a namespace.
176 std::sort(intercept_namespaces_
.begin(), intercept_namespaces_
.end(),
177 SortNamespacesByLength
);
178 std::sort(fallback_namespaces_
.begin(), fallback_namespaces_
.end(),
179 SortNamespacesByLength
);
181 for (size_t i
= 0; i
< whitelists
.size(); ++i
) {
182 const AppCacheDatabase::OnlineWhiteListRecord
& record
= whitelists
.at(i
);
183 online_whitelist_namespaces_
.push_back(
184 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE
,
185 record
.namespace_url
,
191 void AppCache::ToDatabaseRecords(
192 const AppCacheGroup
* group
,
193 AppCacheDatabase::CacheRecord
* cache_record
,
194 std::vector
<AppCacheDatabase::EntryRecord
>* entries
,
195 std::vector
<AppCacheDatabase::NamespaceRecord
>* intercepts
,
196 std::vector
<AppCacheDatabase::NamespaceRecord
>* fallbacks
,
197 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
>* whitelists
) {
198 DCHECK(group
&& cache_record
&& entries
&& fallbacks
&& whitelists
);
199 DCHECK(entries
->empty() && fallbacks
->empty() && whitelists
->empty());
201 cache_record
->cache_id
= cache_id_
;
202 cache_record
->group_id
= group
->group_id();
203 cache_record
->online_wildcard
= online_whitelist_all_
;
204 cache_record
->update_time
= update_time_
;
205 cache_record
->cache_size
= 0;
207 for (EntryMap::const_iterator iter
= entries_
.begin();
208 iter
!= entries_
.end(); ++iter
) {
209 entries
->push_back(AppCacheDatabase::EntryRecord());
210 AppCacheDatabase::EntryRecord
& record
= entries
->back();
211 record
.url
= iter
->first
;
212 record
.cache_id
= cache_id_
;
213 record
.flags
= iter
->second
.types();
214 record
.response_id
= iter
->second
.response_id();
215 record
.response_size
= iter
->second
.response_size();
216 cache_record
->cache_size
+= record
.response_size
;
219 GURL origin
= group
->manifest_url().GetOrigin();
221 for (size_t i
= 0; i
< intercept_namespaces_
.size(); ++i
) {
222 intercepts
->push_back(AppCacheDatabase::NamespaceRecord());
223 AppCacheDatabase::NamespaceRecord
& record
= intercepts
->back();
224 record
.cache_id
= cache_id_
;
225 record
.origin
= origin
;
226 record
.namespace_
= intercept_namespaces_
[i
];
229 for (size_t i
= 0; i
< fallback_namespaces_
.size(); ++i
) {
230 fallbacks
->push_back(AppCacheDatabase::NamespaceRecord());
231 AppCacheDatabase::NamespaceRecord
& record
= fallbacks
->back();
232 record
.cache_id
= cache_id_
;
233 record
.origin
= origin
;
234 record
.namespace_
= fallback_namespaces_
[i
];
237 for (size_t i
= 0; i
< online_whitelist_namespaces_
.size(); ++i
) {
238 whitelists
->push_back(AppCacheDatabase::OnlineWhiteListRecord());
239 AppCacheDatabase::OnlineWhiteListRecord
& record
= whitelists
->back();
240 record
.cache_id
= cache_id_
;
241 record
.namespace_url
= online_whitelist_namespaces_
[i
].namespace_url
;
242 record
.is_pattern
= online_whitelist_namespaces_
[i
].is_pattern
;
246 bool AppCache::FindResponseForRequest(const GURL
& url
,
247 AppCacheEntry
* found_entry
, GURL
* found_intercept_namespace
,
248 AppCacheEntry
* found_fallback_entry
, GURL
* found_fallback_namespace
,
249 bool* found_network_namespace
) {
250 // Ignore fragments when looking up URL in the cache.
253 GURL::Replacements replacements
;
254 replacements
.ClearRef();
255 url_no_ref
= url
.ReplaceComponents(replacements
);
260 // 6.6.6 Changes to the networking model
262 AppCacheEntry
* entry
= GetEntry(url_no_ref
);
264 *found_entry
= *entry
;
268 *found_network_namespace
= IsInNetworkNamespace(url_no_ref
);
269 if (*found_network_namespace
)
272 const AppCacheNamespace
* intercept_namespace
=
273 FindInterceptNamespace(url_no_ref
);
274 if (intercept_namespace
) {
275 entry
= GetEntry(intercept_namespace
->target_url
);
277 *found_entry
= *entry
;
278 *found_intercept_namespace
= intercept_namespace
->namespace_url
;
282 const AppCacheNamespace
* fallback_namespace
=
283 FindFallbackNamespace(url_no_ref
);
284 if (fallback_namespace
) {
285 entry
= GetEntry(fallback_namespace
->target_url
);
287 *found_fallback_entry
= *entry
;
288 *found_fallback_namespace
= fallback_namespace
->namespace_url
;
292 *found_network_namespace
= online_whitelist_all_
;
293 return *found_network_namespace
;
297 void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector
* infos
) const {
298 DCHECK(infos
&& infos
->empty());
299 for (EntryMap::const_iterator iter
= entries_
.begin();
300 iter
!= entries_
.end(); ++iter
) {
301 infos
->push_back(AppCacheResourceInfo());
302 AppCacheResourceInfo
& info
= infos
->back();
303 info
.url
= iter
->first
;
304 info
.is_master
= iter
->second
.IsMaster();
305 info
.is_manifest
= iter
->second
.IsManifest();
306 info
.is_intercept
= iter
->second
.IsIntercept();
307 info
.is_fallback
= iter
->second
.IsFallback();
308 info
.is_foreign
= iter
->second
.IsForeign();
309 info
.is_explicit
= iter
->second
.IsExplicit();
310 info
.size
= iter
->second
.response_size();
311 info
.response_id
= iter
->second
.response_id();
316 const AppCacheNamespace
* AppCache::FindNamespace(
317 const AppCacheNamespaceVector
& namespaces
,
319 size_t count
= namespaces
.size();
320 for (size_t i
= 0; i
< count
; ++i
) {
321 if (namespaces
[i
].IsMatch(url
))
322 return &namespaces
[i
];
327 } // namespace content