| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "webkit/browser/appcache/appcache.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/stl_util.h" | |
| 11 #include "webkit/browser/appcache/appcache_executable_handler.h" | |
| 12 #include "webkit/browser/appcache/appcache_group.h" | |
| 13 #include "webkit/browser/appcache/appcache_host.h" | |
| 14 #include "webkit/browser/appcache/appcache_storage.h" | |
| 15 #include "webkit/common/appcache/appcache_interfaces.h" | |
| 16 | |
| 17 namespace appcache { | |
| 18 | |
| 19 AppCache::AppCache(AppCacheStorage* storage, int64 cache_id) | |
| 20 : cache_id_(cache_id), | |
| 21 owning_group_(NULL), | |
| 22 online_whitelist_all_(false), | |
| 23 is_complete_(false), | |
| 24 cache_size_(0), | |
| 25 storage_(storage) { | |
| 26 storage_->working_set()->AddCache(this); | |
| 27 } | |
| 28 | |
| 29 AppCache::~AppCache() { | |
| 30 DCHECK(associated_hosts_.empty()); | |
| 31 if (owning_group_.get()) { | |
| 32 DCHECK(is_complete_); | |
| 33 owning_group_->RemoveCache(this); | |
| 34 } | |
| 35 DCHECK(!owning_group_.get()); | |
| 36 storage_->working_set()->RemoveCache(this); | |
| 37 STLDeleteContainerPairSecondPointers( | |
| 38 executable_handlers_.begin(), executable_handlers_.end()); | |
| 39 } | |
| 40 | |
| 41 void AppCache::UnassociateHost(AppCacheHost* host) { | |
| 42 associated_hosts_.erase(host); | |
| 43 } | |
| 44 | |
| 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(); | |
| 49 } | |
| 50 | |
| 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)); | |
| 54 | |
| 55 // Entry already exists. Merge the types of the new and existing entries. | |
| 56 if (!ret.second) | |
| 57 ret.first->second.add_types(entry.types()); | |
| 58 else | |
| 59 cache_size_ += entry.response_size(); // New entry. Add to cache size. | |
| 60 return ret.second; | |
| 61 } | |
| 62 | |
| 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); | |
| 68 } | |
| 69 | |
| 70 AppCacheEntry* AppCache::GetEntry(const GURL& url) { | |
| 71 EntryMap::iterator it = entries_.find(url); | |
| 72 return (it != entries_.end()) ? &(it->second) : NULL; | |
| 73 } | |
| 74 | |
| 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) { | |
| 80 if (optional_url_out) | |
| 81 *optional_url_out = iter->first; | |
| 82 return &iter->second; | |
| 83 } | |
| 84 } | |
| 85 return NULL; | |
| 86 } | |
| 87 | |
| 88 AppCacheExecutableHandler* AppCache::GetExecutableHandler(int64 response_id) { | |
| 89 HandlerMap::const_iterator found = executable_handlers_.find(response_id); | |
| 90 if (found != executable_handlers_.end()) | |
| 91 return found->second; | |
| 92 return NULL; | |
| 93 } | |
| 94 | |
| 95 AppCacheExecutableHandler* AppCache::GetOrCreateExecutableHandler( | |
| 96 int64 response_id, net::IOBuffer* handler_source) { | |
| 97 AppCacheExecutableHandler* handler = GetExecutableHandler(response_id); | |
| 98 if (handler) | |
| 99 return handler; | |
| 100 | |
| 101 GURL handler_url; | |
| 102 const AppCacheEntry* entry = GetEntryAndUrlWithResponseId( | |
| 103 response_id, &handler_url); | |
| 104 if (!entry || !entry->IsExecutable()) | |
| 105 return NULL; | |
| 106 | |
| 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(); | |
| 112 if (!handler) | |
| 113 return NULL; | |
| 114 executable_handlers_[response_id] = handler; | |
| 115 return handler; | |
| 116 } | |
| 117 | |
| 118 GURL AppCache::GetNamespaceEntryUrl(const NamespaceVector& 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; | |
| 124 } | |
| 125 NOTREACHED(); | |
| 126 return GURL(); | |
| 127 } | |
| 128 | |
| 129 namespace { | |
| 130 bool SortNamespacesByLength( | |
| 131 const Namespace& lhs, const Namespace& rhs) { | |
| 132 return lhs.namespace_url.spec().length() > rhs.namespace_url.spec().length(); | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 void AppCache::InitializeWithManifest(Manifest* manifest) { | |
| 137 DCHECK(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; | |
| 142 | |
| 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); | |
| 149 } | |
| 150 | |
| 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; | |
| 160 | |
| 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)); | |
| 165 } | |
| 166 DCHECK(cache_size_ == cache_record.cache_size); | |
| 167 | |
| 168 for (size_t i = 0; i < intercepts.size(); ++i) | |
| 169 intercept_namespaces_.push_back(intercepts.at(i).namespace_); | |
| 170 | |
| 171 for (size_t i = 0; i < fallbacks.size(); ++i) | |
| 172 fallback_namespaces_.push_back(fallbacks.at(i).namespace_); | |
| 173 | |
| 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); | |
| 180 | |
| 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 Namespace(APPCACHE_NETWORK_NAMESPACE, | |
| 185 record.namespace_url, | |
| 186 GURL(), | |
| 187 record.is_pattern)); | |
| 188 } | |
| 189 } | |
| 190 | |
| 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()); | |
| 200 | |
| 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; | |
| 206 | |
| 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; | |
| 217 } | |
| 218 | |
| 219 GURL origin = group->manifest_url().GetOrigin(); | |
| 220 | |
| 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]; | |
| 227 } | |
| 228 | |
| 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]; | |
| 235 } | |
| 236 | |
| 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; | |
| 243 } | |
| 244 } | |
| 245 | |
| 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. | |
| 251 GURL url_no_ref; | |
| 252 if (url.has_ref()) { | |
| 253 GURL::Replacements replacements; | |
| 254 replacements.ClearRef(); | |
| 255 url_no_ref = url.ReplaceComponents(replacements); | |
| 256 } else { | |
| 257 url_no_ref = url; | |
| 258 } | |
| 259 | |
| 260 // 6.6.6 Changes to the networking model | |
| 261 | |
| 262 AppCacheEntry* entry = GetEntry(url_no_ref); | |
| 263 if (entry) { | |
| 264 *found_entry = *entry; | |
| 265 return true; | |
| 266 } | |
| 267 | |
| 268 if ((*found_network_namespace = IsInNetworkNamespace(url_no_ref))) | |
| 269 return true; | |
| 270 | |
| 271 const Namespace* intercept_namespace = FindInterceptNamespace(url_no_ref); | |
| 272 if (intercept_namespace) { | |
| 273 entry = GetEntry(intercept_namespace->target_url); | |
| 274 DCHECK(entry); | |
| 275 *found_entry = *entry; | |
| 276 *found_intercept_namespace = intercept_namespace->namespace_url; | |
| 277 return true; | |
| 278 } | |
| 279 | |
| 280 const Namespace* fallback_namespace = FindFallbackNamespace(url_no_ref); | |
| 281 if (fallback_namespace) { | |
| 282 entry = GetEntry(fallback_namespace->target_url); | |
| 283 DCHECK(entry); | |
| 284 *found_fallback_entry = *entry; | |
| 285 *found_fallback_namespace = fallback_namespace->namespace_url; | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 289 *found_network_namespace = online_whitelist_all_; | |
| 290 return *found_network_namespace; | |
| 291 } | |
| 292 | |
| 293 | |
| 294 void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector* infos) const { | |
| 295 DCHECK(infos && infos->empty()); | |
| 296 for (EntryMap::const_iterator iter = entries_.begin(); | |
| 297 iter != entries_.end(); ++iter) { | |
| 298 infos->push_back(AppCacheResourceInfo()); | |
| 299 AppCacheResourceInfo& info = infos->back(); | |
| 300 info.url = iter->first; | |
| 301 info.is_master = iter->second.IsMaster(); | |
| 302 info.is_manifest = iter->second.IsManifest(); | |
| 303 info.is_intercept = iter->second.IsIntercept(); | |
| 304 info.is_fallback = iter->second.IsFallback(); | |
| 305 info.is_foreign = iter->second.IsForeign(); | |
| 306 info.is_explicit = iter->second.IsExplicit(); | |
| 307 info.size = iter->second.response_size(); | |
| 308 info.response_id = iter->second.response_id(); | |
| 309 } | |
| 310 } | |
| 311 | |
| 312 // static | |
| 313 const Namespace* AppCache::FindNamespace( | |
| 314 const NamespaceVector& namespaces, | |
| 315 const GURL& url) { | |
| 316 size_t count = namespaces.size(); | |
| 317 for (size_t i = 0; i < count; ++i) { | |
| 318 if (namespaces[i].IsMatch(url)) | |
| 319 return &namespaces[i]; | |
| 320 } | |
| 321 return NULL; | |
| 322 } | |
| 323 | |
| 324 } // namespace appcache | |
| OLD | NEW |