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