Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / renderer_host / offline_resource_throttle.cc
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 "chrome/browser/renderer_host/offline_resource_throttle.h"
6
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/singleton.h"
12 #include "base/metrics/histogram.h"
13 #include "base/strings/string_util.h"
14 #include "chrome/browser/chromeos/offline/offline_load_page.h"
15 #include "chrome/browser/net/chrome_url_request_context.h"
16 #include "chrome/common/url_constants.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/resource_controller.h"
20 #include "content/public/browser/resource_request_info.h"
21 #include "content/public/browser/web_contents.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/net_util.h"
24 #include "net/base/network_change_notifier.h"
25 #include "net/url_request/url_request.h"
26 #include "net/url_request/url_request_context.h"
27 #include "webkit/browser/appcache/appcache_service.h"
28
29 using content::BrowserThread;
30 using content::RenderViewHost;
31 using content::WebContents;
32
33 namespace {
34
35 void ShowOfflinePage(
36     int render_process_id,
37     int render_view_id,
38     const GURL& url,
39     const chromeos::OfflineLoadPage::CompletionCallback& callback) {
40   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
41
42   // Check again on UI thread and proceed if it's connected.
43   if (!net::NetworkChangeNotifier::IsOffline()) {
44     BrowserThread::PostTask(
45         BrowserThread::IO, FROM_HERE, base::Bind(callback, true));
46   } else {
47     RenderViewHost* render_view_host =
48         RenderViewHost::FromID(render_process_id, render_view_id);
49     WebContents* web_contents = render_view_host ?
50         WebContents::FromRenderViewHost(render_view_host) : NULL;
51     // There is a chance that the tab closed after we decided to show
52     // the offline page on the IO thread and before we actually show the
53     // offline page here on the UI thread.
54     if (web_contents)
55       (new chromeos::OfflineLoadPage(web_contents, url, callback))->Show();
56   }
57 }
58
59 }  // namespace
60
61 OfflineResourceThrottle::OfflineResourceThrottle(
62     net::URLRequest* request,
63     appcache::AppCacheService* appcache_service)
64     : request_(request),
65       appcache_service_(appcache_service) {
66   DCHECK(appcache_service);
67 }
68
69 OfflineResourceThrottle::~OfflineResourceThrottle() {
70   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
71
72   if (!appcache_completion_callback_.IsCancelled())
73     appcache_completion_callback_.Cancel();
74 }
75
76 void OfflineResourceThrottle::WillStartRequest(bool* defer) {
77   if (!ShouldShowOfflinePage(request_->url()))
78     return;
79
80   DVLOG(1) << "WillStartRequest: this=" << this << ", url=" << request_->url();
81
82   const GURL* url = &(request_->url());
83   const GURL* first_party = &(request_->first_party_for_cookies());
84
85   // Anticipate a client-side HSTS based redirect from HTTP to HTTPS, and
86   // ask the appcache about the HTTPS url instead of the HTTP url.
87   GURL redirect_url;
88   if (request_->GetHSTSRedirect(&redirect_url)) {
89     if (url->GetOrigin() == first_party->GetOrigin())
90       first_party = &redirect_url;
91     url = &redirect_url;
92   }
93
94   DCHECK(appcache_completion_callback_.IsCancelled());
95
96   appcache_completion_callback_.Reset(
97       base::Bind(&OfflineResourceThrottle::OnCanHandleOfflineComplete,
98                  AsWeakPtr()));
99   appcache_service_->CanHandleMainResourceOffline(
100       *url, *first_party,
101       appcache_completion_callback_.callback());
102
103   *defer = true;
104 }
105
106 const char* OfflineResourceThrottle::GetNameForLogging() const {
107   return "OfflineResourceThrottle";
108 }
109
110 void OfflineResourceThrottle::OnBlockingPageComplete(bool proceed) {
111   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
112
113   if (proceed) {
114     controller()->Resume();
115   } else {
116     controller()->Cancel();
117   }
118 }
119
120 bool OfflineResourceThrottle::IsRemote(const GURL& url) const {
121   return !net::IsLocalhost(url.host()) && (url.SchemeIs(content::kFtpScheme) ||
122                                            url.SchemeIs(url::kHttpScheme) ||
123                                            url.SchemeIs(url::kHttpsScheme));
124 }
125
126 bool OfflineResourceThrottle::ShouldShowOfflinePage(const GURL& url) const {
127   // If the network is disconnected while loading other resources, we'll simply
128   // show broken link/images.
129   return IsRemote(url) && net::NetworkChangeNotifier::IsOffline();
130 }
131
132 void OfflineResourceThrottle::OnCanHandleOfflineComplete(int rv) {
133   appcache_completion_callback_.Cancel();
134
135   if (rv == net::OK) {
136     controller()->Resume();
137   } else {
138     const content::ResourceRequestInfo* info =
139         content::ResourceRequestInfo::ForRequest(request_);
140     BrowserThread::PostTask(
141         BrowserThread::UI,
142         FROM_HERE,
143         base::Bind(
144             &ShowOfflinePage,
145             info->GetChildID(),
146             info->GetRouteID(),
147             request_->url(),
148             base::Bind(
149                 &OfflineResourceThrottle::OnBlockingPageComplete,
150                 AsWeakPtr())));
151   }
152 }