14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/prerender/prerender_resource_throttle.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/prerender/prerender_final_status.h"
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/prerender/prerender_manager.h"
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/prerender/prerender_util.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/render_frame_host.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/resource_controller.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/resource_request_info.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/web_contents.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/url_request/url_request.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing content::ResourceType;
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace prerender {
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static const char kFollowOnlyWhenPrerenderShown[] =
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "follow-only-when-prerender-shown";
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PrerenderContents* g_prerender_contents_for_testing;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PrerenderResourceThrottle::OverridePrerenderContentsForTesting(
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PrerenderContents* contents) {
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_prerender_contents_for_testing = contents;
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PrerenderResourceThrottle::PrerenderResourceThrottle(net::URLRequest* request)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : request_(request) {
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void PrerenderResourceThrottle::WillStartRequest(bool* defer) {
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const content::ResourceRequestInfo* info =
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      content::ResourceRequestInfo::ForRequest(request_);
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *defer = true;
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::BrowserThread::PostTask(
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      content::BrowserThread::UI,
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&PrerenderResourceThrottle::WillStartRequestOnUI,
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 AsWeakPtr(), request_->method(), info->GetResourceType(),
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 info->GetChildID(), info->GetRenderFrameID(),
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 request_->url()));
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void PrerenderResourceThrottle::WillRedirectRequest(const GURL& new_url,
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                    bool* defer) {
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const content::ResourceRequestInfo* info =
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      content::ResourceRequestInfo::ForRequest(request_);
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *defer = true;
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string header;
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  request_->GetResponseHeaderByName(kFollowOnlyWhenPrerenderShown, &header);
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::BrowserThread::PostTask(
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      content::BrowserThread::UI,
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&PrerenderResourceThrottle::WillRedirectRequestOnUI,
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 AsWeakPtr(), header, info->GetResourceType(), info->IsAsync(),
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 info->GetChildID(), info->GetRenderFrameID(), new_url));
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const char* PrerenderResourceThrottle::GetNameForLogging() const {
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return "PrerenderResourceThrottle";
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void PrerenderResourceThrottle::Resume() {
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  controller()->Resume();
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void PrerenderResourceThrottle::Cancel() {
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  controller()->Cancel();
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PrerenderResourceThrottle::WillStartRequestOnUI(
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::WeakPtr<PrerenderResourceThrottle>& throttle,
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& method,
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ResourceType resource_type,
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int render_process_id,
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int render_frame_id,
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GURL& url) {
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool cancel = false;
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PrerenderContents* prerender_contents =
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PrerenderContentsFromRenderFrame(render_process_id, render_frame_id);
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (prerender_contents) {
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Abort any prerenders that spawn requests that use unsupported HTTP
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // methods or schemes.
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!PrerenderManager::IsValidHttpMethod(method)) {
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      prerender_contents->Destroy(FINAL_STATUS_INVALID_HTTP_METHOD);
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      cancel = true;
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else if (!PrerenderManager::DoesSubresourceURLHaveValidScheme(url)) {
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ReportUnsupportedPrerenderScheme(url);
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      cancel = true;
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_ANDROID)
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else if (resource_type == content::RESOURCE_TYPE_FAVICON) {
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Delay icon fetching until the contents are getting swapped in
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // to conserve network usage in mobile devices.
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      prerender_contents->AddResourceThrottle(throttle);
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::BrowserThread::PostTask(
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      content::BrowserThread::IO,
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(cancel ? &PrerenderResourceThrottle::Cancel :
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 &PrerenderResourceThrottle::Resume, throttle));
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PrerenderResourceThrottle::WillRedirectRequestOnUI(
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::WeakPtr<PrerenderResourceThrottle>& throttle,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& follow_only_when_prerender_shown_header,
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ResourceType resource_type,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool async,
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int render_process_id,
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int render_frame_id,
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GURL& new_url) {
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool cancel = false;
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PrerenderContents* prerender_contents =
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PrerenderContentsFromRenderFrame(render_process_id, render_frame_id);
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (prerender_contents) {
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Abort any prerenders with requests which redirect to invalid schemes.
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!PrerenderManager::DoesURLHaveValidScheme(new_url)) {
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ReportUnsupportedPrerenderScheme(new_url);
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      cancel = true;
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else if (follow_only_when_prerender_shown_header == "1" &&
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               resource_type != content::RESOURCE_TYPE_MAIN_FRAME) {
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Only defer redirects with the Follow-Only-When-Prerender-Shown
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // header. Do not defer redirects on main frame loads.
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!async) {
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Cancel on deferred synchronous requests. Those will
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // indefinitely hang up a renderer process.
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        prerender_contents->Destroy(FINAL_STATUS_BAD_DEFERRED_REDIRECT);
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        cancel = true;
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else {
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Defer the redirect until the prerender is used or canceled.
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        prerender_contents->AddResourceThrottle(throttle);
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::BrowserThread::PostTask(
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      content::BrowserThread::IO,
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(cancel ? &PrerenderResourceThrottle::Cancel :
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 &PrerenderResourceThrottle::Resume, throttle));
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PrerenderContents* PrerenderResourceThrottle::PrerenderContentsFromRenderFrame(
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int render_process_id, int render_frame_id) {
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (g_prerender_contents_for_testing)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return g_prerender_contents_for_testing;
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      render_process_id, render_frame_id);
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::WebContents* web_contents =
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      content::WebContents::FromRenderFrameHost(rfh);
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return PrerenderContents::FromWebContents(web_contents);
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace prerender
168