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 |