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.
5 #include "chrome/browser/renderer_host/offline_resource_throttle.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 "content/public/browser/appcache_service.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/resource_controller.h"
19 #include "content/public/browser/resource_request_info.h"
20 #include "content/public/browser/web_contents.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/net_util.h"
23 #include "net/base/network_change_notifier.h"
24 #include "net/url_request/url_request.h"
25 #include "net/url_request/url_request_context.h"
26 #include "url/url_constants.h"
28 using content::BrowserThread
;
29 using content::RenderViewHost
;
30 using content::WebContents
;
35 int render_process_id
,
38 const chromeos::OfflineLoadPage::CompletionCallback
& callback
) {
39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
41 // Check again on UI thread and proceed if it's connected.
42 if (!net::NetworkChangeNotifier::IsOffline()) {
43 BrowserThread::PostTask(
44 BrowserThread::IO
, FROM_HERE
, base::Bind(callback
, true));
46 RenderViewHost
* render_view_host
=
47 RenderViewHost::FromID(render_process_id
, render_view_id
);
48 WebContents
* web_contents
= render_view_host
?
49 WebContents::FromRenderViewHost(render_view_host
) : NULL
;
50 // There is a chance that the tab closed after we decided to show
51 // the offline page on the IO thread and before we actually show the
52 // offline page here on the UI thread.
54 (new chromeos::OfflineLoadPage(web_contents
, url
, callback
))->Show();
60 OfflineResourceThrottle::OfflineResourceThrottle(
61 net::URLRequest
* request
,
62 content::AppCacheService
* appcache_service
)
64 appcache_service_(appcache_service
) {
65 DCHECK(appcache_service
);
68 OfflineResourceThrottle::~OfflineResourceThrottle() {
69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
71 if (!appcache_completion_callback_
.IsCancelled())
72 appcache_completion_callback_
.Cancel();
75 void OfflineResourceThrottle::WillStartRequest(bool* defer
) {
76 if (!ShouldShowOfflinePage(request_
->url()))
79 DVLOG(1) << "WillStartRequest: this=" << this << ", url=" << request_
->url();
81 const GURL
* url
= &(request_
->url());
82 const GURL
* first_party
= &(request_
->first_party_for_cookies());
84 // Anticipate a client-side HSTS based redirect from HTTP to HTTPS, and
85 // ask the appcache about the HTTPS url instead of the HTTP url.
87 if (request_
->GetHSTSRedirect(&redirect_url
)) {
88 if (url
->GetOrigin() == first_party
->GetOrigin())
89 first_party
= &redirect_url
;
93 DCHECK(appcache_completion_callback_
.IsCancelled());
95 appcache_completion_callback_
.Reset(
96 base::Bind(&OfflineResourceThrottle::OnCanHandleOfflineComplete
,
98 appcache_service_
->CanHandleMainResourceOffline(
100 appcache_completion_callback_
.callback());
105 const char* OfflineResourceThrottle::GetNameForLogging() const {
106 return "OfflineResourceThrottle";
109 void OfflineResourceThrottle::OnBlockingPageComplete(bool proceed
) {
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
113 controller()->Resume();
115 controller()->Cancel();
119 bool OfflineResourceThrottle::IsRemote(const GURL
& url
) const {
120 return !net::IsLocalhost(url
.host()) && (url
.SchemeIs(url::kFtpScheme
) ||
121 url
.SchemeIs(url::kHttpScheme
) ||
122 url
.SchemeIs(url::kHttpsScheme
));
125 bool OfflineResourceThrottle::ShouldShowOfflinePage(const GURL
& url
) const {
126 // If the network is disconnected while loading other resources, we'll simply
127 // show broken link/images.
128 return IsRemote(url
) && net::NetworkChangeNotifier::IsOffline();
131 void OfflineResourceThrottle::OnCanHandleOfflineComplete(int rv
) {
132 appcache_completion_callback_
.Cancel();
135 controller()->Resume();
137 const content::ResourceRequestInfo
* info
=
138 content::ResourceRequestInfo::ForRequest(request_
);
139 BrowserThread::PostTask(
148 &OfflineResourceThrottle::OnBlockingPageComplete
,