OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/browser/appcache/appcache_host.h" | 5 #include "webkit/browser/appcache/appcache_host.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/strings/utf_string_conversions.h" |
10 #include "net/url_request/url_request.h" | 11 #include "net/url_request/url_request.h" |
11 #include "webkit/browser/appcache/appcache.h" | 12 #include "webkit/browser/appcache/appcache.h" |
12 #include "webkit/browser/appcache/appcache_backend_impl.h" | 13 #include "webkit/browser/appcache/appcache_backend_impl.h" |
13 #include "webkit/browser/appcache/appcache_policy.h" | 14 #include "webkit/browser/appcache/appcache_policy.h" |
14 #include "webkit/browser/appcache/appcache_request_handler.h" | 15 #include "webkit/browser/appcache/appcache_request_handler.h" |
15 #include "webkit/browser/quota/quota_manager.h" | 16 #include "webkit/browser/quota/quota_manager.h" |
| 17 #include "webkit/browser/appcache/manifest_parser.h" |
16 | 18 |
17 namespace appcache { | 19 namespace appcache { |
18 | 20 |
19 namespace { | 21 namespace { |
20 | 22 |
21 void FillCacheInfo(const AppCache* cache, | 23 void FillCacheInfo(const AppCache* cache, |
22 const GURL& manifest_url, | 24 const GURL& manifest_url, |
23 Status status, AppCacheInfo* info) { | 25 Status status, AppCacheInfo* info) { |
24 info->manifest_url = manifest_url; | 26 info->manifest_url = manifest_url; |
25 info->status = status; | 27 info->status = status; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 | 60 |
59 AppCacheHost::~AppCacheHost() { | 61 AppCacheHost::~AppCacheHost() { |
60 FOR_EACH_OBSERVER(Observer, observers_, OnDestructionImminent(this)); | 62 FOR_EACH_OBSERVER(Observer, observers_, OnDestructionImminent(this)); |
61 if (associated_cache_.get()) | 63 if (associated_cache_.get()) |
62 associated_cache_->UnassociateHost(this); | 64 associated_cache_->UnassociateHost(this); |
63 if (group_being_updated_.get()) | 65 if (group_being_updated_.get()) |
64 group_being_updated_->RemoveUpdateObserver(this); | 66 group_being_updated_->RemoveUpdateObserver(this); |
65 service_->storage()->CancelDelegateCallbacks(this); | 67 service_->storage()->CancelDelegateCallbacks(this); |
66 if (service()->quota_manager_proxy() && !origin_in_use_.is_empty()) | 68 if (service()->quota_manager_proxy() && !origin_in_use_.is_empty()) |
67 service()->quota_manager_proxy()->NotifyOriginNoLongerInUse(origin_in_use_); | 69 service()->quota_manager_proxy()->NotifyOriginNoLongerInUse(origin_in_use_); |
| 70 if (controller_group_) |
| 71 controller_group_->RemoveUpdateObserver(this); |
68 } | 72 } |
69 | 73 |
70 void AppCacheHost::AddObserver(Observer* observer) { | 74 void AppCacheHost::AddObserver(Observer* observer) { |
71 observers_.AddObserver(observer); | 75 observers_.AddObserver(observer); |
72 } | 76 } |
73 | 77 |
74 void AppCacheHost::RemoveObserver(Observer* observer) { | 78 void AppCacheHost::RemoveObserver(Observer* observer) { |
75 observers_.RemoveObserver(observer); | 79 observers_.RemoveObserver(observer); |
76 } | 80 } |
77 | 81 |
78 void AppCacheHost::SelectCache(const GURL& document_url, | 82 void AppCacheHost::SelectCache(const GURL& document_url, |
79 const int64 cache_document_was_loaded_from, | 83 const int64 cache_document_was_loaded_from, |
80 const GURL& manifest_url) { | 84 const GURL& manifest_url) { |
81 DCHECK(pending_start_update_callback_.is_null() && | 85 DCHECK(pending_start_update_callback_.is_null() && |
82 pending_swap_cache_callback_.is_null() && | 86 pending_swap_cache_callback_.is_null() && |
83 pending_get_status_callback_.is_null() && | 87 pending_get_status_callback_.is_null() && |
84 !is_selection_pending()); | 88 !is_selection_pending()); |
85 | 89 |
| 90 // Note: extra logic to release this cache in case an exe handler |
| 91 // generated a redirect to a resource outside of the scope of this cache. |
| 92 scoped_refptr<AppCache> main_cache_releaser = main_resource_cache_; |
| 93 main_resource_cache_ = NULL; |
| 94 |
86 origin_in_use_ = document_url.GetOrigin(); | 95 origin_in_use_ = document_url.GetOrigin(); |
87 if (service()->quota_manager_proxy() && !origin_in_use_.is_empty()) | 96 if (service()->quota_manager_proxy() && !origin_in_use_.is_empty()) |
88 service()->quota_manager_proxy()->NotifyOriginInUse(origin_in_use_); | 97 service()->quota_manager_proxy()->NotifyOriginInUse(origin_in_use_); |
89 | 98 |
90 if (main_resource_blocked_) | 99 if (main_resource_blocked_) |
91 frontend_->OnContentBlocked(host_id_, | 100 frontend_->OnContentBlocked(host_id_, |
92 blocked_manifest_url_); | 101 blocked_manifest_url_); |
93 | 102 |
94 // 6.9.6 The application cache selection algorithm. | 103 // 6.9.6 The application cache selection algorithm. |
95 // The algorithm is started here and continues in FinishCacheSelection, | 104 // The algorithm is started here and continues in FinishCacheSelection, |
96 // after cache or group loading is complete. | 105 // after cache or group loading is complete. |
97 // Note: Foreign entries are detected on the client side and | 106 // Note: Foreign entries are detected on the client side and |
98 // MarkAsForeignEntry is called in that case, so that detection | 107 // MarkAsForeignEntry is called in that case, so that detection |
99 // step is skipped here. See WebApplicationCacheHostImpl.cc | 108 // step is skipped here. See WebApplicationCacheHostImpl.cc |
100 | 109 |
101 if (cache_document_was_loaded_from != kNoCacheId) { | 110 if (cache_document_was_loaded_from != kNoCacheId) { |
102 LoadSelectedCache(cache_document_was_loaded_from); | 111 LoadSelectedCache(cache_document_was_loaded_from); |
103 return; | 112 return; |
104 } | 113 } |
105 | 114 |
| 115 // Hackery for navcontroller semantics where the controller gets a crack |
| 116 // and any and all subresource requests <period> for any documents in its |
| 117 // controlled namespace. We force the containing cache to be associated. |
| 118 if (main_cache_releaser && |
| 119 main_cache_releaser->owning_group()->IsFakeNavControllerGroup() && |
| 120 main_cache_releaser->FindInterceptNamespace(document_url)) { |
| 121 LoadSelectedCache(main_cache_releaser->cache_id()); |
| 122 return; |
| 123 } |
| 124 |
106 if (!manifest_url.is_empty() && | 125 if (!manifest_url.is_empty() && |
107 (manifest_url.GetOrigin() == document_url.GetOrigin())) { | 126 (manifest_url.GetOrigin() == document_url.GetOrigin())) { |
108 DCHECK(!first_party_url_.is_empty()); | 127 DCHECK(!first_party_url_.is_empty()); |
109 AppCachePolicy* policy = service()->appcache_policy(); | 128 AppCachePolicy* policy = service()->appcache_policy(); |
110 if (policy && | 129 if (policy && |
111 !policy->CanCreateAppCache(manifest_url, first_party_url_)) { | 130 !policy->CanCreateAppCache(manifest_url, first_party_url_)) { |
112 FinishCacheSelection(NULL, NULL); | 131 FinishCacheSelection(NULL, NULL); |
113 std::vector<int> host_ids(1, host_id_); | 132 std::vector<int> host_ids(1, host_id_); |
114 frontend_->OnEventRaised(host_ids, CHECKING_EVENT); | 133 frontend_->OnEventRaised(host_ids, CHECKING_EVENT); |
115 frontend_->OnErrorEventRaised( | 134 frontend_->OnErrorEventRaised( |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 pending_get_status_callback_.is_null()); | 215 pending_get_status_callback_.is_null()); |
197 | 216 |
198 pending_start_update_callback_ = callback; | 217 pending_start_update_callback_ = callback; |
199 pending_callback_param_ = callback_param; | 218 pending_callback_param_ = callback_param; |
200 if (is_selection_pending()) | 219 if (is_selection_pending()) |
201 return; | 220 return; |
202 | 221 |
203 DoPendingStartUpdate(); | 222 DoPendingStartUpdate(); |
204 } | 223 } |
205 | 224 |
| 225 static void CreateControllerManifest(const GURL& manifest_url, |
| 226 const string16& pattern, |
| 227 const GURL& script_url, |
| 228 Manifest* manifest) { |
| 229 LOG(ERROR) << "CreateControllerManifest(" << manifest_url << ", " << pattern <
< ", " << script_url << ")"; |
| 230 // right now we only support prefix-like patterns |
| 231 std::string pattern_utf8 = UTF16ToUTF8(pattern); |
| 232 DCHECK(*pattern_utf8.rbegin() == '*') << "Only prefix patterns supported " <<
pattern_utf8; |
| 233 base::StringPiece prefix_pattern(pattern_utf8.c_str(), pattern_utf8.length() -
1); |
| 234 |
| 235 GURL namespace_url = manifest_url; // .Resolve(pattern); |
| 236 manifest->intercept_namespaces.push_back( |
| 237 Namespace(INTERCEPT_NAMESPACE, namespace_url, |
| 238 script_url, true, true)); |
| 239 LOG(ERROR) << " Created with namespace = " << namespace_url; |
| 240 } |
| 241 |
| 242 void AppCacheHost::RegisterController(const GURL& document_url, |
| 243 const string16& pattern, |
| 244 const GURL& script_url) { |
| 245 LOG(ERROR) << "Browser process got registerController(" << pattern << ", " <<
script_url << ")"; |
| 246 |
| 247 if (!controller_pattern_.empty()) { |
| 248 // You should be able to register any number of controllers at |
| 249 // different prefixes, but we're not setup to do that. |
| 250 LOG(ERROR) << "Trying to register pattern '" << pattern << "' with '" << scr
ipt_url << "' but '" << controller_pattern_ << " has already been registered wit
h '"<< controller_script_url_ << "'"; |
| 251 return; |
| 252 } |
| 253 |
| 254 controller_pattern_ = pattern; |
| 255 controller_script_url_ = script_url; |
| 256 controller_manifest_url_ = document_url.Resolve(pattern); |
| 257 controller_group_ = NULL; |
| 258 controller_cache_ = NULL; |
| 259 service_->storage()->LoadOrCreateGroup(controller_manifest_url_, this); |
| 260 } |
| 261 |
| 262 void AppCacheHost::UnregisterController(const GURL& document_url, |
| 263 const string16& pattern) { |
| 264 // Clear out old state so register can be called again from the containing pag
e. |
| 265 if (controller_group_) |
| 266 controller_group_->RemoveUpdateObserver(this); |
| 267 controller_pattern_ = string16(); |
| 268 controller_script_url_ = GURL(); |
| 269 controller_manifest_url_ = GURL(); |
| 270 controller_group_ = NULL; |
| 271 controller_cache_ = NULL; |
| 272 |
| 273 // Delete the the 'controller cache' to unregister. |
| 274 service_->DeleteAppCacheGroup(document_url.Resolve(pattern), net::CompletionCa
llback()); |
| 275 } |
| 276 |
206 void AppCacheHost::DoPendingStartUpdate() { | 277 void AppCacheHost::DoPendingStartUpdate() { |
207 DCHECK_EQ(false, pending_start_update_callback_.is_null()); | 278 DCHECK_EQ(false, pending_start_update_callback_.is_null()); |
208 | 279 |
209 // 6.9.8 Application cache API | 280 // 6.9.8 Application cache API |
210 bool success = false; | 281 bool success = false; |
211 if (associated_cache_.get() && associated_cache_->owning_group()) { | 282 if (associated_cache_.get() && associated_cache_->owning_group()) { |
212 AppCacheGroup* group = associated_cache_->owning_group(); | 283 AppCacheGroup* group = associated_cache_->owning_group(); |
213 if (!group->is_obsolete() && !group->is_being_deleted()) { | 284 if (!group->is_obsolete() && !group->is_being_deleted()) { |
214 success = true; | 285 success = true; |
215 group->StartUpdate(); | 286 group->StartUpdate(); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 } | 398 } |
328 | 399 |
329 void AppCacheHost::LoadOrCreateGroup(const GURL& manifest_url) { | 400 void AppCacheHost::LoadOrCreateGroup(const GURL& manifest_url) { |
330 DCHECK(manifest_url.is_valid()); | 401 DCHECK(manifest_url.is_valid()); |
331 pending_selected_manifest_url_ = manifest_url; | 402 pending_selected_manifest_url_ = manifest_url; |
332 service_->storage()->LoadOrCreateGroup(manifest_url, this); | 403 service_->storage()->LoadOrCreateGroup(manifest_url, this); |
333 } | 404 } |
334 | 405 |
335 void AppCacheHost::OnGroupLoaded(AppCacheGroup* group, | 406 void AppCacheHost::OnGroupLoaded(AppCacheGroup* group, |
336 const GURL& manifest_url) { | 407 const GURL& manifest_url) { |
| 408 // special case |
| 409 if (manifest_url == controller_manifest_url_) { |
| 410 OnControllerGroupLoaded(group); |
| 411 return; |
| 412 } |
| 413 |
337 DCHECK(manifest_url == pending_selected_manifest_url_); | 414 DCHECK(manifest_url == pending_selected_manifest_url_); |
338 pending_selected_manifest_url_ = GURL(); | 415 pending_selected_manifest_url_ = GURL(); |
339 FinishCacheSelection(NULL, group); | 416 FinishCacheSelection(NULL, group); |
340 } | 417 } |
341 | 418 |
| 419 void AppCacheHost::OnControllerGroupLoaded(AppCacheGroup* group) { |
| 420 DCHECK(group); |
| 421 controller_group_ = group; // hang onto it to keep it alive |
| 422 if (group->HasCache()) { |
| 423 // We already have a controller camping on this pattern. |
| 424 // TODO: Need to see if it's exe handler url matches controller_script_url_, |
| 425 // and to update/recreate if it doesn't match, for now assume it matches |
| 426 // and just use it. |
| 427 controller_cache_ = group->newest_complete_cache(); |
| 428 frontend_->OnControllerReady(host_id_); |
| 429 return; |
| 430 } |
| 431 |
| 432 appcache::Manifest manifest; |
| 433 CreateControllerManifest(controller_manifest_url_, |
| 434 controller_pattern_, |
| 435 controller_script_url_, |
| 436 &manifest); |
| 437 // Nothing exists yet, need to run the update algo for the first time. |
| 438 group->AddUpdateObserver(this); |
| 439 group->StartUpdateWithFakeManifest(&manifest); |
| 440 } |
| 441 |
| 442 void AppCacheHost::OnControllerUpdateComplete(AppCacheGroup* group) { |
| 443 if (group->HasCache()) |
| 444 controller_cache_ = group->newest_complete_cache(); |
| 445 DCHECK(controller_cache_); |
| 446 frontend_->OnControllerReady(host_id_); |
| 447 } |
| 448 |
342 void AppCacheHost::LoadSelectedCache(int64 cache_id) { | 449 void AppCacheHost::LoadSelectedCache(int64 cache_id) { |
343 DCHECK(cache_id != kNoCacheId); | 450 DCHECK(cache_id != kNoCacheId); |
344 pending_selected_cache_id_ = cache_id; | 451 pending_selected_cache_id_ = cache_id; |
345 service_->storage()->LoadCache(cache_id, this); | 452 service_->storage()->LoadCache(cache_id, this); |
346 } | 453 } |
347 | 454 |
348 void AppCacheHost::OnCacheLoaded(AppCache* cache, int64 cache_id) { | 455 void AppCacheHost::OnCacheLoaded(AppCache* cache, int64 cache_id) { |
349 if (cache_id == pending_main_resource_cache_id_) { | 456 if (cache_id == pending_main_resource_cache_id_) { |
350 pending_main_resource_cache_id_ = kNoCacheId; | 457 pending_main_resource_cache_id_ = kNoCacheId; |
351 main_resource_cache_ = cache; | 458 main_resource_cache_ = cache; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 } | 525 } |
419 | 526 |
420 void AppCacheHost::ObserveGroupBeingUpdated(AppCacheGroup* group) { | 527 void AppCacheHost::ObserveGroupBeingUpdated(AppCacheGroup* group) { |
421 DCHECK(!group_being_updated_.get()); | 528 DCHECK(!group_being_updated_.get()); |
422 group_being_updated_ = group; | 529 group_being_updated_ = group; |
423 newest_cache_of_group_being_updated_ = group->newest_complete_cache(); | 530 newest_cache_of_group_being_updated_ = group->newest_complete_cache(); |
424 group->AddUpdateObserver(this); | 531 group->AddUpdateObserver(this); |
425 } | 532 } |
426 | 533 |
427 void AppCacheHost::OnUpdateComplete(AppCacheGroup* group) { | 534 void AppCacheHost::OnUpdateComplete(AppCacheGroup* group) { |
| 535 group->RemoveUpdateObserver(this); |
| 536 |
| 537 if (group == controller_group_) { |
| 538 OnControllerUpdateComplete(group); |
| 539 return; |
| 540 } |
| 541 |
428 DCHECK_EQ(group, group_being_updated_); | 542 DCHECK_EQ(group, group_being_updated_); |
429 group->RemoveUpdateObserver(this); | |
430 | 543 |
431 // Add a reference to the newest complete cache. | 544 // Add a reference to the newest complete cache. |
432 SetSwappableCache(group); | 545 SetSwappableCache(group); |
433 | 546 |
434 group_being_updated_ = NULL; | 547 group_being_updated_ = NULL; |
435 newest_cache_of_group_being_updated_ = NULL; | 548 newest_cache_of_group_being_updated_ = NULL; |
436 | 549 |
437 if (associated_cache_info_pending_ && associated_cache_.get() && | 550 if (associated_cache_info_pending_ && associated_cache_.get() && |
438 associated_cache_->is_complete()) { | 551 associated_cache_->is_complete()) { |
439 AppCacheInfo info; | 552 AppCacheInfo info; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 associated_cache_info_pending_ = cache && !cache->is_complete(); | 619 associated_cache_info_pending_ = cache && !cache->is_complete(); |
507 AppCacheInfo info; | 620 AppCacheInfo info; |
508 if (cache) | 621 if (cache) |
509 cache->AssociateHost(this); | 622 cache->AssociateHost(this); |
510 | 623 |
511 FillCacheInfo(cache, manifest_url, GetStatus(), &info); | 624 FillCacheInfo(cache, manifest_url, GetStatus(), &info); |
512 frontend_->OnCacheSelected(host_id_, info); | 625 frontend_->OnCacheSelected(host_id_, info); |
513 } | 626 } |
514 | 627 |
515 } // namespace appcache | 628 } // namespace appcache |
OLD | NEW |