offline_resource_throttle.cc revision 116680a4aac90f2aa7413d9095a592090648e557
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/renderer_host/offline_resource_throttle.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/offline/offline_load_page.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/net/chrome_url_request_context.h"
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/browser/appcache_service.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/resource_controller.h"
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "content/public/browser/resource_request_info.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/network_change_notifier.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context.h"
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "url/url_constants.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderViewHost;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShowOfflinePage(
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_process_id,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_view_id,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const chromeos::OfflineLoadPage::CompletionCallback& callback) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check again on UI thread and proceed if it's connected.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!net::NetworkChangeNotifier::IsOffline()) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::IO, FROM_HERE, base::Bind(callback, true));
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RenderViewHost* render_view_host =
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RenderViewHost::FromID(render_process_id, render_view_id);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WebContents* web_contents = render_view_host ?
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        WebContents::FromRenderViewHost(render_view_host) : NULL;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is a chance that the tab closed after we decided to show
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the offline page on the IO thread and before we actually show the
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // offline page here on the UI thread.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (web_contents)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (new chromeos::OfflineLoadPage(web_contents, url, callback))->Show();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OfflineResourceThrottle::OfflineResourceThrottle(
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequest* request,
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    content::AppCacheService* appcache_service)
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : request_(request),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      appcache_service_(appcache_service) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(appcache_service);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OfflineResourceThrottle::~OfflineResourceThrottle() {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!appcache_completion_callback_.IsCancelled())
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appcache_completion_callback_.Cancel();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OfflineResourceThrottle::WillStartRequest(bool* defer) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShouldShowOfflinePage(request_->url()))
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "WillStartRequest: this=" << this << ", url=" << request_->url();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GURL* url = &(request_->url());
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GURL* first_party = &(request_->first_party_for_cookies());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Anticipate a client-side HSTS based redirect from HTTP to HTTPS, and
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ask the appcache about the HTTPS url instead of the HTTP url.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL redirect_url;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (request_->GetHSTSRedirect(&redirect_url)) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url->GetOrigin() == first_party->GetOrigin())
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_party = &redirect_url;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url = &redirect_url;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(appcache_completion_callback_.IsCancelled());
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appcache_completion_callback_.Reset(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&OfflineResourceThrottle::OnCanHandleOfflineComplete,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 AsWeakPtr()));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appcache_service_->CanHandleMainResourceOffline(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *url, *first_party,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      appcache_completion_callback_.callback());
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *defer = true;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const char* OfflineResourceThrottle::GetNameForLogging() const {
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return "OfflineResourceThrottle";
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OfflineResourceThrottle::OnBlockingPageComplete(bool proceed) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (proceed) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller()->Resume();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller()->Cancel();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OfflineResourceThrottle::IsRemote(const GURL& url) const {
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return !net::IsLocalhost(url.host()) && (url.SchemeIs(url::kFtpScheme) ||
122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                           url.SchemeIs(url::kHttpScheme) ||
123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                           url.SchemeIs(url::kHttpsScheme));
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OfflineResourceThrottle::ShouldShowOfflinePage(const GURL& url) const {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the network is disconnected while loading other resources, we'll simply
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // show broken link/images.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsRemote(url) && net::NetworkChangeNotifier::IsOffline();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OfflineResourceThrottle::OnCanHandleOfflineComplete(int rv) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  appcache_completion_callback_.Cancel();
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv == net::OK) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller()->Resume();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const content::ResourceRequestInfo* info =
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        content::ResourceRequestInfo::ForRequest(request_);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::UI,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            &ShowOfflinePage,
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            info->GetChildID(),
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            info->GetRouteID(),
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            request_->url(),
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            base::Bind(
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                &OfflineResourceThrottle::OnBlockingPageComplete,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                AsWeakPtr())));
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
153