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