OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/appcache/appcache_host.h" | 5 #include "webkit/appcache/appcache_host.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "webkit/appcache/appcache.h" | 8 #include "webkit/appcache/appcache.h" |
9 #include "webkit/appcache/appcache_group.h" | 9 #include "webkit/appcache/appcache_group.h" |
10 #include "webkit/appcache/appcache_interfaces.h" | 10 #include "webkit/appcache/appcache_interfaces.h" |
| 11 #include "webkit/appcache/appcache_request_handler.h" |
| 12 #include "webkit/appcache/appcache_service.h" |
11 | 13 |
12 namespace appcache { | 14 namespace appcache { |
13 | 15 |
14 AppCacheHost::AppCacheHost(int host_id, AppCacheFrontend* frontend) | 16 AppCacheHost::AppCacheHost(int host_id, AppCacheFrontend* frontend, |
15 : host_id_(host_id), | 17 AppCacheService* service) |
16 selected_cache_(NULL), | 18 : host_id_(host_id), pending_selected_cache_id_(kNoCacheId), |
17 group_(NULL), | 19 frontend_(frontend), service_(service), |
18 frontend_(frontend) { | 20 pending_get_status_callback_(NULL), pending_start_update_callback_(NULL), |
| 21 pending_swap_cache_callback_(NULL), pending_callback_param_(NULL) { |
19 } | 22 } |
20 | 23 |
21 AppCacheHost::~AppCacheHost() { | 24 AppCacheHost::~AppCacheHost() { |
22 if (selected_cache_) | 25 if (associated_cache_.get()) |
23 set_selected_cache(NULL); | 26 associated_cache_->UnassociateHost(this); |
24 DCHECK(!group_); | 27 service_->CancelLoads(this); |
25 } | 28 } |
26 | 29 |
27 void AppCacheHost::set_selected_cache(AppCache *cache) { | 30 void AppCacheHost::SelectCache(const GURL& document_url, |
28 if (selected_cache_) | 31 const int64 cache_document_was_loaded_from, |
29 selected_cache_->UnassociateHost(this); | 32 const GURL& manifest_url) { |
30 | 33 DCHECK(!pending_start_update_callback_ && |
31 selected_cache_ = cache; | 34 !pending_swap_cache_callback_ && |
| 35 !pending_get_status_callback_); |
| 36 |
| 37 // First we handle an unusual case of SelectCache being called a second |
| 38 // time. Generally this shouldn't happen, but with bad content I think |
| 39 // this can occur... <html manifest=foo> <html manifest=bar></html></html> |
| 40 // We handle this by killing whatever loading we have initiated, and by |
| 41 // unassociating any hosts we currently have associated... and starting |
| 42 // anew with the inputs to this SelectCache call. |
| 43 // TODO(michaeln): at some point determine what behavior the algorithms |
| 44 // described in the HTML5 draft produce and have our impl produce those |
| 45 // results (or suggest changes to the algorihtms described in the spec |
| 46 // if the resulting behavior is just too insane). |
| 47 if (is_selection_pending()) { |
| 48 service_->CancelLoads(this); |
| 49 pending_selected_manifest_url_ = GURL::EmptyGURL(); |
| 50 pending_selected_cache_id_ = kNoCacheId; |
| 51 } else if (associated_cache()) { |
| 52 AssociateCache(NULL); |
| 53 } |
| 54 new_master_entry_url_ = GURL::EmptyGURL(); |
| 55 |
| 56 // 6.9.6 The application cache selection algorithm. |
| 57 // The algorithm is started here and continues in FinishCacheSelection, |
| 58 // after cache or group loading is complete. |
| 59 // Note: foriegn entries are detected on the client side and |
| 60 // MarkAsForeignEntry is called in that case, so that detection |
| 61 // step is skipped here. |
| 62 |
| 63 if (cache_document_was_loaded_from != kNoCacheId) { |
| 64 LoadCache(cache_document_was_loaded_from); |
| 65 return; |
| 66 } |
| 67 |
| 68 if (!manifest_url.is_empty() && |
| 69 (manifest_url.GetOrigin() == document_url.GetOrigin())) { |
| 70 new_master_entry_url_ = document_url; |
| 71 LoadOrCreateGroup(manifest_url); |
| 72 return; |
| 73 } |
| 74 |
| 75 // TODO(michaeln): If there was a manifest URL, the user agent may report |
| 76 // to the user that it was ignored, to aid in application development. |
| 77 FinishCacheSelection(NULL, NULL); |
| 78 } |
| 79 |
| 80 void AppCacheHost::MarkAsForeignEntry(const GURL& document_url, |
| 81 int64 cache_document_was_loaded_from) { |
| 82 service_->MarkAsForeignEntry(document_url, cache_document_was_loaded_from); |
| 83 SelectCache(document_url, kNoCacheId, GURL::EmptyGURL()); |
| 84 } |
| 85 |
| 86 void AppCacheHost::GetStatusWithCallback(GetStatusCallback* callback, |
| 87 void* callback_param) { |
| 88 DCHECK(!pending_start_update_callback_ && |
| 89 !pending_swap_cache_callback_ && |
| 90 !pending_get_status_callback_); |
| 91 |
| 92 pending_get_status_callback_ = callback; |
| 93 pending_callback_param_ = callback_param; |
| 94 if (is_selection_pending()) |
| 95 return; |
| 96 |
| 97 DoPendingGetStatus(); |
| 98 } |
| 99 |
| 100 void AppCacheHost::DoPendingGetStatus() { |
| 101 DCHECK(pending_get_status_callback_); |
| 102 |
| 103 pending_get_status_callback_->Run( |
| 104 GetStatus(), pending_callback_param_); |
| 105 |
| 106 pending_get_status_callback_ = NULL; |
| 107 pending_callback_param_ = NULL; |
| 108 } |
| 109 |
| 110 void AppCacheHost::StartUpdateWithCallback(StartUpdateCallback* callback, |
| 111 void* callback_param) { |
| 112 DCHECK(!pending_start_update_callback_ && |
| 113 !pending_swap_cache_callback_ && |
| 114 !pending_get_status_callback_); |
| 115 |
| 116 pending_start_update_callback_ = callback; |
| 117 pending_callback_param_ = callback_param; |
| 118 if (is_selection_pending()) |
| 119 return; |
| 120 |
| 121 DoPendingStartUpdate(); |
| 122 } |
| 123 |
| 124 void AppCacheHost::DoPendingStartUpdate() { |
| 125 DCHECK(pending_start_update_callback_); |
| 126 |
| 127 // TODO(michaeln): start an update if appropiate to do so |
| 128 pending_start_update_callback_->Run( |
| 129 false, pending_callback_param_); |
| 130 |
| 131 pending_start_update_callback_ = NULL; |
| 132 pending_callback_param_ = NULL; |
| 133 } |
| 134 |
| 135 void AppCacheHost::SwapCacheWithCallback(SwapCacheCallback* callback, |
| 136 void* callback_param) { |
| 137 DCHECK(!pending_start_update_callback_ && |
| 138 !pending_swap_cache_callback_ && |
| 139 !pending_get_status_callback_); |
| 140 |
| 141 pending_swap_cache_callback_ = callback; |
| 142 pending_callback_param_ = callback_param; |
| 143 if (is_selection_pending()) |
| 144 return; |
| 145 |
| 146 DoPendingSwapCache(); |
| 147 } |
| 148 |
| 149 void AppCacheHost::DoPendingSwapCache() { |
| 150 DCHECK(pending_swap_cache_callback_); |
| 151 |
| 152 // TODO(michaeln): swap if we have a cache that can be swapped. |
| 153 pending_swap_cache_callback_->Run( |
| 154 false, pending_callback_param_); |
| 155 |
| 156 pending_swap_cache_callback_ = NULL; |
| 157 pending_callback_param_ = NULL; |
| 158 } |
| 159 |
| 160 AppCacheRequestHandler* AppCacheHost::CreateRequestHandler( |
| 161 URLRequest* request, |
| 162 bool is_main_request) { |
| 163 if (is_main_request) |
| 164 return new AppCacheRequestHandler(this); |
| 165 |
| 166 if (associated_cache() && associated_cache()->is_complete()) |
| 167 return new AppCacheRequestHandler(associated_cache()); |
| 168 |
| 169 return NULL; |
| 170 } |
| 171 |
| 172 Status AppCacheHost::GetStatus() { |
| 173 // TODO(michaeln): determine a real status value |
| 174 Status status = associated_cache() ? IDLE : UNCACHED; |
| 175 return status; |
| 176 } |
| 177 |
| 178 void AppCacheHost::LoadOrCreateGroup(const GURL& manifest_url) { |
| 179 DCHECK(manifest_url.is_valid()); |
| 180 pending_selected_manifest_url_ = manifest_url; |
| 181 service_->LoadOrCreateGroup(manifest_url, this); |
| 182 } |
| 183 |
| 184 void AppCacheHost::GroupLoadedCallback( |
| 185 AppCacheGroup* group, const GURL& manifest_url) { |
| 186 DCHECK(manifest_url == pending_selected_manifest_url_); |
| 187 pending_selected_manifest_url_ = GURL::EmptyGURL(); |
| 188 FinishCacheSelection(NULL, group); |
| 189 } |
| 190 |
| 191 void AppCacheHost::LoadCache(int64 cache_id) { |
| 192 DCHECK(cache_id != kNoCacheId); |
| 193 pending_selected_cache_id_ = cache_id; |
| 194 service_->LoadCache(cache_id, this); |
| 195 } |
| 196 |
| 197 void AppCacheHost::CacheLoadedCallback(AppCache* cache, int64 cache_id) { |
| 198 DCHECK(cache_id == pending_selected_cache_id_); |
| 199 pending_selected_cache_id_ = kNoCacheId; |
| 200 if (cache) |
| 201 FinishCacheSelection(cache, NULL); |
| 202 else |
| 203 FinishCacheSelection(NULL, NULL); |
| 204 } |
| 205 |
| 206 void AppCacheHost::FinishCacheSelection( |
| 207 AppCache *cache, AppCacheGroup* group) { |
| 208 DCHECK(!associated_cache()); |
| 209 |
| 210 // 6.9.6 The application cache selection algorithm |
| 211 if (cache) { |
| 212 // If document was loaded from an application cache, Associate document |
| 213 // with the application cache from which it was loaded. Invoke the |
| 214 // application cache update process for that cache and with the browsing |
| 215 // context being navigated. |
| 216 DCHECK(cache->owning_group()); |
| 217 DCHECK(new_master_entry_url_.is_empty()); |
| 218 AssociateCache(cache); |
| 219 cache->owning_group()->StartUpdateWithHost(this); |
| 220 |
| 221 } else if (group) { |
| 222 // If document was loaded using HTTP GET or equivalent, and, there is a |
| 223 // manifest URL, and manifest URL has the same origin as document. |
| 224 // Invoke the application cache update process for manifest URL, with |
| 225 // the browsing context being navigated, and with document and the |
| 226 // resource from which document was loaded as the new master resourse. |
| 227 DCHECK(new_master_entry_url_.is_valid()); |
| 228 AssociateCache(NULL); // The UpdateJob may produce one for us later. |
| 229 group->StartUpdateWithNewMasterEntry(this, new_master_entry_url_); |
| 230 |
| 231 } else { |
| 232 // Otherwise, the Document is not associated with any application cache. |
| 233 AssociateCache(NULL); |
| 234 } |
| 235 |
| 236 // Respond to pending callbacks now that we have a selection. |
| 237 if (pending_get_status_callback_) |
| 238 DoPendingGetStatus(); |
| 239 else if (pending_start_update_callback_) |
| 240 DoPendingStartUpdate(); |
| 241 else if (pending_swap_cache_callback_) |
| 242 DoPendingSwapCache(); |
| 243 } |
| 244 |
| 245 void AppCacheHost::AssociateCache(AppCache* cache) { |
| 246 if (associated_cache_.get()) { |
| 247 associated_cache_->UnassociateHost(this); |
| 248 group_ = NULL; |
| 249 } |
| 250 |
| 251 associated_cache_ = cache; |
32 | 252 |
33 if (cache) { | 253 if (cache) { |
34 cache->AssociateHost(this); | 254 cache->AssociateHost(this); |
35 group_ = cache->owning_group(); | 255 group_ = cache->owning_group(); |
| 256 frontend_->OnCacheSelected(host_id_, cache->cache_id(), GetStatus()); |
36 } else { | 257 } else { |
37 group_ = NULL; | 258 frontend_->OnCacheSelected(host_id_, kNoCacheId, UNCACHED); |
38 } | 259 } |
39 } | 260 } |
40 | 261 |
41 } // namespace appcache | 262 } // namespace appcache |
OLD | NEW |