Home | History | Annotate | Download | only in prerender
      1 // Copyright (c) 2011 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/prerender/prerender_resource_handler.h"
      6 
      7 #include "chrome/browser/net/chrome_url_request_context.h"
      8 #include "content/common/resource_response.h"
      9 #include "net/base/load_flags.h"
     10 #include "net/http/http_response_headers.h"
     11 #include "net/url_request/url_request.h"
     12 
     13 namespace prerender {
     14 
     15 namespace {
     16 
     17 bool ShouldPrerenderURL(const GURL& url) {
     18   if (!url.is_valid())
     19     return false;
     20   if (!url.SchemeIs("http")) {
     21     RecordFinalStatus(FINAL_STATUS_HTTPS);
     22     return false;
     23   }
     24   return true;
     25 }
     26 
     27 bool ValidateAliasURLs(const std::vector<GURL>& urls) {
     28   for (std::vector<GURL>::const_iterator it = urls.begin();
     29        it != urls.end();
     30        ++it) {
     31     if (!ShouldPrerenderURL(*it))
     32       return false;
     33   }
     34   return true;
     35 }
     36 
     37 bool ShouldPrerender(const ResourceResponse* response) {
     38   if (!response)
     39     return false;
     40   const ResourceResponseHead& rrh = response->response_head;
     41   if (!rrh.headers)
     42     return false;
     43   if (rrh.mime_type != "text/html")
     44     return false;
     45   if (rrh.headers->response_code() != 200)
     46     return false;
     47   return true;
     48 }
     49 
     50 }  // namespace
     51 
     52 PrerenderResourceHandler* PrerenderResourceHandler::MaybeCreate(
     53     const net::URLRequest& request,
     54     ChromeURLRequestContext* context,
     55     ResourceHandler* next_handler,
     56     bool is_from_prerender,
     57     int child_id,
     58     int route_id) {
     59   if (!context || !context->prerender_manager())
     60     return NULL;
     61   if (!(request.load_flags() & net::LOAD_PREFETCH))
     62     return NULL;
     63   if (!ShouldPrerenderURL(request.url()))
     64     return NULL;
     65   if (request.method() != "GET")
     66     return NULL;
     67 
     68   return new PrerenderResourceHandler(request,
     69                                       next_handler,
     70                                       context->prerender_manager(),
     71                                       is_from_prerender,
     72                                       child_id,
     73                                       route_id);
     74 }
     75 
     76 PrerenderResourceHandler::PrerenderResourceHandler(
     77     const net::URLRequest& request,
     78     ResourceHandler* next_handler,
     79     PrerenderManager* prerender_manager,
     80     bool make_pending,
     81     int child_id,
     82     int route_id)
     83     : next_handler_(next_handler),
     84       prerender_manager_(prerender_manager),
     85       ALLOW_THIS_IN_INITIALIZER_LIST(
     86           prerender_callback_(NewCallback(
     87               this, &PrerenderResourceHandler::StartPrerender))),
     88       request_(request),
     89       child_id_(child_id),
     90       route_id_(route_id),
     91       make_pending_(make_pending) {
     92   DCHECK(next_handler);
     93   DCHECK(prerender_manager);
     94 }
     95 
     96 PrerenderResourceHandler::PrerenderResourceHandler(
     97     const net::URLRequest& request,
     98     ResourceHandler* next_handler,
     99     PrerenderCallback* callback)
    100     : next_handler_(next_handler),
    101       prerender_callback_(callback),
    102       request_(request) {
    103   DCHECK(next_handler);
    104   DCHECK(callback);
    105 }
    106 
    107 PrerenderResourceHandler::~PrerenderResourceHandler() {
    108 }
    109 
    110 bool PrerenderResourceHandler::OnUploadProgress(int request_id,
    111                                                 uint64 position,
    112                                                 uint64 size) {
    113   return next_handler_->OnUploadProgress(request_id, position, size);
    114 }
    115 
    116 bool PrerenderResourceHandler::OnRequestRedirected(int request_id,
    117                                                    const GURL& url,
    118                                                    ResourceResponse* response,
    119                                                    bool* defer) {
    120   bool will_redirect = next_handler_->OnRequestRedirected(
    121       request_id, url, response, defer);
    122   if (will_redirect) {
    123     if (!ShouldPrerenderURL(url))
    124       return false;
    125     alias_urls_.push_back(url);
    126     url_ = url;
    127   }
    128   return will_redirect;
    129 }
    130 
    131 bool PrerenderResourceHandler::OnResponseStarted(int request_id,
    132                                                  ResourceResponse* response) {
    133   if (ShouldPrerender(response)) {
    134     DCHECK(ValidateAliasURLs(alias_urls_));
    135     BrowserThread::PostTask(
    136         BrowserThread::UI,
    137         FROM_HERE,
    138         NewRunnableMethod(
    139             this,
    140             &PrerenderResourceHandler::RunCallbackFromUIThread,
    141             std::make_pair(child_id_, route_id_),
    142             url_,
    143             alias_urls_,
    144             GURL(request_.referrer()),
    145             make_pending_));
    146   }
    147   return next_handler_->OnResponseStarted(request_id, response);
    148 }
    149 
    150 bool PrerenderResourceHandler::OnWillStart(int request_id,
    151                                            const GURL& url,
    152                                            bool* defer) {
    153   bool will_start = next_handler_->OnWillStart(request_id, url, defer);
    154   if (will_start) {
    155     if (!ShouldPrerenderURL(url))
    156       return false;
    157     alias_urls_.push_back(url);
    158     url_ = url;
    159   }
    160   return will_start;
    161 }
    162 
    163 bool PrerenderResourceHandler::OnWillRead(int request_id,
    164                                           net::IOBuffer** buf,
    165                                           int* buf_size,
    166                                           int min_size) {
    167   return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
    168 }
    169 
    170 bool PrerenderResourceHandler::OnReadCompleted(int request_id,
    171                                                int* bytes_read) {
    172   return next_handler_->OnReadCompleted(request_id, bytes_read);
    173 }
    174 
    175 bool PrerenderResourceHandler::OnResponseCompleted(
    176     int request_id,
    177     const net::URLRequestStatus& status,
    178     const std::string& security_info) {
    179   return next_handler_->OnResponseCompleted(request_id, status, security_info);
    180 }
    181 
    182 void PrerenderResourceHandler::OnRequestClosed() {
    183   next_handler_->OnRequestClosed();
    184 }
    185 
    186 void PrerenderResourceHandler::RunCallbackFromUIThread(
    187     const std::pair<int, int>& child_route_id_pair,
    188     const GURL& url,
    189     const std::vector<GURL>& alias_urls,
    190     const GURL& referrer,
    191     bool make_pending) {
    192   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    193   prerender_callback_->Run(child_route_id_pair,
    194                            url, alias_urls, referrer,
    195                            make_pending);
    196 }
    197 
    198 void PrerenderResourceHandler::StartPrerender(
    199     const std::pair<int, int>& child_route_id_pair,
    200     const GURL& url,
    201     const std::vector<GURL>& alias_urls,
    202     const GURL& referrer,
    203     bool make_pending) {
    204   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    205   if (!prerender_manager_->is_enabled())
    206     return;
    207   if (make_pending) {
    208     prerender_manager_->AddPendingPreload(child_route_id_pair,
    209                                           url, alias_urls, referrer);
    210   } else {
    211     prerender_manager_->AddPreload(url, alias_urls, referrer);
    212   }
    213 }
    214 
    215 }  // namespace prerender
    216