| 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/renderer/appcache/web_application_cache_host_impl.h" | |
| 6 | |
| 7 #include "base/compiler_specific.h" | |
| 8 #include "base/id_map.h" | |
| 9 #include "base/strings/string_util.h" | |
| 10 #include "base/strings/stringprintf.h" | |
| 11 #include "third_party/WebKit/public/web/WebDataSource.h" | |
| 12 #include "third_party/WebKit/public/web/WebFrame.h" | |
| 13 #include "third_party/WebKit/public/platform/WebURL.h" | |
| 14 #include "third_party/WebKit/public/platform/WebURLRequest.h" | |
| 15 #include "third_party/WebKit/public/platform/WebURLResponse.h" | |
| 16 | |
| 17 using WebKit::WebApplicationCacheHost; | |
| 18 using WebKit::WebApplicationCacheHostClient; | |
| 19 using WebKit::WebDataSource; | |
| 20 using WebKit::WebFrame; | |
| 21 using WebKit::WebURLRequest; | |
| 22 using WebKit::WebURL; | |
| 23 using WebKit::WebURLResponse; | |
| 24 using WebKit::WebVector; | |
| 25 | |
| 26 namespace appcache { | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 // Note: the order of the elements in this array must match those | |
| 31 // of the EventID enum in appcache_interfaces.h. | |
| 32 const char* kEventNames[] = { | |
| 33 "Checking", "Error", "NoUpdate", "Downloading", "Progress", | |
| 34 "UpdateReady", "Cached", "Obsolete" | |
| 35 }; | |
| 36 | |
| 37 typedef IDMap<WebApplicationCacheHostImpl> HostsMap; | |
| 38 | |
| 39 HostsMap* all_hosts() { | |
| 40 static HostsMap* map = new HostsMap; | |
| 41 return map; | |
| 42 } | |
| 43 | |
| 44 GURL ClearUrlRef(const GURL& url) { | |
| 45 if (!url.has_ref()) | |
| 46 return url; | |
| 47 GURL::Replacements replacements; | |
| 48 replacements.ClearRef(); | |
| 49 return url.ReplaceComponents(replacements); | |
| 50 } | |
| 51 | |
| 52 } // anon namespace | |
| 53 | |
| 54 WebApplicationCacheHostImpl* WebApplicationCacheHostImpl::FromId(int id) { | |
| 55 return all_hosts()->Lookup(id); | |
| 56 } | |
| 57 | |
| 58 WebApplicationCacheHostImpl* WebApplicationCacheHostImpl::FromFrame( | |
| 59 const WebFrame* frame) { | |
| 60 if (!frame) | |
| 61 return NULL; | |
| 62 WebDataSource* data_source = frame->dataSource(); | |
| 63 if (!data_source) | |
| 64 return NULL; | |
| 65 return static_cast<WebApplicationCacheHostImpl*> | |
| 66 (data_source->applicationCacheHost()); | |
| 67 } | |
| 68 | |
| 69 WebApplicationCacheHostImpl::WebApplicationCacheHostImpl( | |
| 70 WebApplicationCacheHostClient* client, | |
| 71 AppCacheBackend* backend) | |
| 72 : client_(client), | |
| 73 backend_(backend), | |
| 74 host_id_(all_hosts()->Add(this)), | |
| 75 status_(UNCACHED), | |
| 76 is_scheme_supported_(false), | |
| 77 is_get_method_(false), | |
| 78 is_new_master_entry_(MAYBE), | |
| 79 was_select_cache_called_(false) { | |
| 80 DCHECK(client && backend && (host_id_ != kNoHostId)); | |
| 81 | |
| 82 backend_->RegisterHost(host_id_); | |
| 83 } | |
| 84 | |
| 85 WebApplicationCacheHostImpl::~WebApplicationCacheHostImpl() { | |
| 86 backend_->UnregisterHost(host_id_); | |
| 87 all_hosts()->Remove(host_id_); | |
| 88 } | |
| 89 | |
| 90 void WebApplicationCacheHostImpl::OnCacheSelected( | |
| 91 const appcache::AppCacheInfo& info) { | |
| 92 cache_info_ = info; | |
| 93 client_->didChangeCacheAssociation(); | |
| 94 } | |
| 95 | |
| 96 void WebApplicationCacheHostImpl::OnStatusChanged(appcache::Status status) { | |
| 97 // TODO(michaeln): delete me, not used | |
| 98 } | |
| 99 | |
| 100 void WebApplicationCacheHostImpl::OnEventRaised(appcache::EventID event_id) { | |
| 101 DCHECK(event_id != PROGRESS_EVENT); // See OnProgressEventRaised. | |
| 102 DCHECK(event_id != ERROR_EVENT); // See OnErrorEventRaised. | |
| 103 | |
| 104 // Emit logging output prior to calling out to script as we can get | |
| 105 // deleted within the script event handler. | |
| 106 const char* kFormatString = "Application Cache %s event"; | |
| 107 std::string message = base::StringPrintf(kFormatString, | |
| 108 kEventNames[event_id]); | |
| 109 OnLogMessage(LOG_INFO, message); | |
| 110 | |
| 111 switch (event_id) { | |
| 112 case CHECKING_EVENT: | |
| 113 status_ = CHECKING; | |
| 114 break; | |
| 115 case DOWNLOADING_EVENT: | |
| 116 status_ = DOWNLOADING; | |
| 117 break; | |
| 118 case UPDATE_READY_EVENT: | |
| 119 status_ = UPDATE_READY; | |
| 120 break; | |
| 121 case CACHED_EVENT: | |
| 122 case NO_UPDATE_EVENT: | |
| 123 status_ = IDLE; | |
| 124 break; | |
| 125 case OBSOLETE_EVENT: | |
| 126 status_ = OBSOLETE; | |
| 127 break; | |
| 128 default: | |
| 129 NOTREACHED(); | |
| 130 break; | |
| 131 } | |
| 132 | |
| 133 client_->notifyEventListener(static_cast<EventID>(event_id)); | |
| 134 } | |
| 135 | |
| 136 void WebApplicationCacheHostImpl::OnProgressEventRaised( | |
| 137 const GURL& url, int num_total, int num_complete) { | |
| 138 // Emit logging output prior to calling out to script as we can get | |
| 139 // deleted within the script event handler. | |
| 140 const char* kFormatString = "Application Cache Progress event (%d of %d) %s"; | |
| 141 std::string message = base::StringPrintf(kFormatString, num_complete, | |
| 142 num_total, url.spec().c_str()); | |
| 143 OnLogMessage(LOG_INFO, message); | |
| 144 status_ = DOWNLOADING; | |
| 145 client_->notifyProgressEventListener(url, num_total, num_complete); | |
| 146 } | |
| 147 | |
| 148 void WebApplicationCacheHostImpl::OnErrorEventRaised( | |
| 149 const std::string& message) { | |
| 150 // Emit logging output prior to calling out to script as we can get | |
| 151 // deleted within the script event handler. | |
| 152 const char* kFormatString = "Application Cache Error event: %s"; | |
| 153 std::string full_message = base::StringPrintf(kFormatString, | |
| 154 message.c_str()); | |
| 155 OnLogMessage(LOG_ERROR, full_message); | |
| 156 | |
| 157 status_ = cache_info_.is_complete ? IDLE : UNCACHED; | |
| 158 client_->notifyEventListener(static_cast<EventID>(ERROR_EVENT)); | |
| 159 } | |
| 160 | |
| 161 void WebApplicationCacheHostImpl::willStartMainResourceRequest( | |
| 162 WebURLRequest& request, const WebFrame* frame) { | |
| 163 request.setAppCacheHostID(host_id_); | |
| 164 | |
| 165 original_main_resource_url_ = ClearUrlRef(request.url()); | |
| 166 | |
| 167 std::string method = request.httpMethod().utf8(); | |
| 168 is_get_method_ = (method == kHttpGETMethod); | |
| 169 DCHECK(method == StringToUpperASCII(method)); | |
| 170 | |
| 171 if (frame) { | |
| 172 const WebFrame* spawning_frame = frame->parent(); | |
| 173 if (!spawning_frame) | |
| 174 spawning_frame = frame->opener(); | |
| 175 if (!spawning_frame) | |
| 176 spawning_frame = frame; | |
| 177 | |
| 178 WebApplicationCacheHostImpl* spawning_host = FromFrame(spawning_frame); | |
| 179 if (spawning_host && (spawning_host != this) && | |
| 180 (spawning_host->status_ != UNCACHED)) { | |
| 181 backend_->SetSpawningHostId(host_id_, spawning_host->host_id()); | |
| 182 } | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 void WebApplicationCacheHostImpl::willStartSubResourceRequest( | |
| 187 WebURLRequest& request) { | |
| 188 request.setAppCacheHostID(host_id_); | |
| 189 } | |
| 190 | |
| 191 void WebApplicationCacheHostImpl::selectCacheWithoutManifest() { | |
| 192 if (was_select_cache_called_) | |
| 193 return; | |
| 194 was_select_cache_called_ = true; | |
| 195 | |
| 196 status_ = (document_response_.appCacheID() == kNoCacheId) ? | |
| 197 UNCACHED : CHECKING; | |
| 198 is_new_master_entry_ = NO; | |
| 199 backend_->SelectCache(host_id_, document_url_, | |
| 200 document_response_.appCacheID(), | |
| 201 GURL()); | |
| 202 } | |
| 203 | |
| 204 bool WebApplicationCacheHostImpl::selectCacheWithManifest( | |
| 205 const WebURL& manifest_url) { | |
| 206 if (was_select_cache_called_) | |
| 207 return true; | |
| 208 was_select_cache_called_ = true; | |
| 209 | |
| 210 GURL manifest_gurl(ClearUrlRef(manifest_url)); | |
| 211 | |
| 212 // 6.9.6 The application cache selection algorithm | |
| 213 // Check for new 'master' entries. | |
| 214 if (document_response_.appCacheID() == kNoCacheId) { | |
| 215 if (is_scheme_supported_ && is_get_method_ && | |
| 216 (manifest_gurl.GetOrigin() == document_url_.GetOrigin())) { | |
| 217 status_ = CHECKING; | |
| 218 is_new_master_entry_ = YES; | |
| 219 } else { | |
| 220 status_ = UNCACHED; | |
| 221 is_new_master_entry_ = NO; | |
| 222 manifest_gurl = GURL(); | |
| 223 } | |
| 224 backend_->SelectCache(host_id_, document_url_, | |
| 225 kNoCacheId, manifest_gurl); | |
| 226 return true; | |
| 227 } | |
| 228 | |
| 229 DCHECK_EQ(NO, is_new_master_entry_); | |
| 230 | |
| 231 // 6.9.6 The application cache selection algorithm | |
| 232 // Check for 'foreign' entries. | |
| 233 GURL document_manifest_gurl(document_response_.appCacheManifestURL()); | |
| 234 if (document_manifest_gurl != manifest_gurl) { | |
| 235 backend_->MarkAsForeignEntry(host_id_, document_url_, | |
| 236 document_response_.appCacheID()); | |
| 237 status_ = UNCACHED; | |
| 238 return false; // the navigation will be restarted | |
| 239 } | |
| 240 | |
| 241 status_ = CHECKING; | |
| 242 | |
| 243 // Its a 'master' entry thats already in the cache. | |
| 244 backend_->SelectCache(host_id_, document_url_, | |
| 245 document_response_.appCacheID(), | |
| 246 manifest_gurl); | |
| 247 return true; | |
| 248 } | |
| 249 | |
| 250 void WebApplicationCacheHostImpl::didReceiveResponseForMainResource( | |
| 251 const WebURLResponse& response) { | |
| 252 document_response_ = response; | |
| 253 document_url_ = ClearUrlRef(document_response_.url()); | |
| 254 if (document_url_ != original_main_resource_url_) | |
| 255 is_get_method_ = true; // A redirect was involved. | |
| 256 original_main_resource_url_ = GURL(); | |
| 257 | |
| 258 is_scheme_supported_ = IsSchemeSupported(document_url_); | |
| 259 if ((document_response_.appCacheID() != kNoCacheId) || | |
| 260 !is_scheme_supported_ || !is_get_method_) | |
| 261 is_new_master_entry_ = NO; | |
| 262 } | |
| 263 | |
| 264 void WebApplicationCacheHostImpl::didReceiveDataForMainResource( | |
| 265 const char* data, int len) { | |
| 266 if (is_new_master_entry_ == NO) | |
| 267 return; | |
| 268 // TODO(michaeln): write me | |
| 269 } | |
| 270 | |
| 271 void WebApplicationCacheHostImpl::didFinishLoadingMainResource(bool success) { | |
| 272 if (is_new_master_entry_ == NO) | |
| 273 return; | |
| 274 // TODO(michaeln): write me | |
| 275 } | |
| 276 | |
| 277 WebApplicationCacheHost::Status WebApplicationCacheHostImpl::status() { | |
| 278 return static_cast<WebApplicationCacheHost::Status>(status_); | |
| 279 } | |
| 280 | |
| 281 bool WebApplicationCacheHostImpl::startUpdate() { | |
| 282 if (!backend_->StartUpdate(host_id_)) | |
| 283 return false; | |
| 284 if (status_ == IDLE || status_ == UPDATE_READY) | |
| 285 status_ = CHECKING; | |
| 286 else | |
| 287 status_ = backend_->GetStatus(host_id_); | |
| 288 return true; | |
| 289 } | |
| 290 | |
| 291 bool WebApplicationCacheHostImpl::swapCache() { | |
| 292 if (!backend_->SwapCache(host_id_)) | |
| 293 return false; | |
| 294 status_ = backend_->GetStatus(host_id_); | |
| 295 return true; | |
| 296 } | |
| 297 | |
| 298 void WebApplicationCacheHostImpl::getAssociatedCacheInfo( | |
| 299 WebApplicationCacheHost::CacheInfo* info) { | |
| 300 info->manifestURL = cache_info_.manifest_url; | |
| 301 if (!cache_info_.is_complete) | |
| 302 return; | |
| 303 info->creationTime = cache_info_.creation_time.ToDoubleT(); | |
| 304 info->updateTime = cache_info_.last_update_time.ToDoubleT(); | |
| 305 info->totalSize = cache_info_.size; | |
| 306 } | |
| 307 | |
| 308 void WebApplicationCacheHostImpl::getResourceList( | |
| 309 WebVector<ResourceInfo>* resources) { | |
| 310 if (!cache_info_.is_complete) | |
| 311 return; | |
| 312 std::vector<AppCacheResourceInfo> resource_infos; | |
| 313 backend_->GetResourceList(host_id_, &resource_infos); | |
| 314 | |
| 315 WebVector<ResourceInfo> web_resources(resource_infos.size()); | |
| 316 for (size_t i = 0; i < resource_infos.size(); ++i) { | |
| 317 web_resources[i].size = resource_infos[i].size; | |
| 318 web_resources[i].isMaster = resource_infos[i].is_master; | |
| 319 web_resources[i].isExplicit = resource_infos[i].is_explicit; | |
| 320 web_resources[i].isManifest = resource_infos[i].is_manifest; | |
| 321 web_resources[i].isForeign = resource_infos[i].is_foreign; | |
| 322 web_resources[i].isFallback = resource_infos[i].is_fallback; | |
| 323 web_resources[i].url = resource_infos[i].url; | |
| 324 } | |
| 325 resources->swap(web_resources); | |
| 326 } | |
| 327 | |
| 328 } // appcache namespace | |
| OLD | NEW |