prerender_resource_handler.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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 "chrome/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
13namespace {
14
15bool ShouldPrerender(const GURL& url, const ResourceResponse* response) {
16  if (!response)
17    return false;
18  const ResourceResponseHead& rrh = response->response_head;
19  if (!url.is_valid())
20    return false;
21  if (!rrh.headers)
22    return false;
23  if (!(url.SchemeIs("http") || url.SchemeIs("https")))
24    return false;
25  if (rrh.mime_type != "text/html")
26    return false;
27  if (rrh.headers->response_code() != 200)
28    return false;
29  return true;
30}
31
32}  // namespace
33
34PrerenderResourceHandler* PrerenderResourceHandler::MaybeCreate(
35    const net::URLRequest& request,
36    ChromeURLRequestContext* context,
37    ResourceHandler* next_handler) {
38  if (!context || !context->prerender_manager())
39    return NULL;
40  if (!(request.load_flags() & net::LOAD_PREFETCH))
41    return NULL;
42  if (request.method() != "GET")
43    return NULL;
44  return new PrerenderResourceHandler(next_handler,
45                                      context->prerender_manager());
46}
47
48PrerenderResourceHandler::PrerenderResourceHandler(
49    ResourceHandler* next_handler,
50    PrerenderManager* prerender_manager)
51    : next_handler_(next_handler),
52      prerender_manager_(prerender_manager),
53      ALLOW_THIS_IN_INITIALIZER_LIST(
54          prerender_callback_(NewCallback(
55              this, &PrerenderResourceHandler::StartPrerender))) {
56  DCHECK(next_handler);
57  DCHECK(prerender_manager);
58}
59
60// This constructor is only used from unit tests.
61PrerenderResourceHandler::PrerenderResourceHandler(
62    ResourceHandler* next_handler,
63    PrerenderCallback* callback)
64    : next_handler_(next_handler),
65      prerender_callback_(callback) {
66  DCHECK(next_handler);
67  DCHECK(callback);
68}
69
70PrerenderResourceHandler::~PrerenderResourceHandler() {
71}
72
73bool PrerenderResourceHandler::OnUploadProgress(int request_id,
74                                                uint64 position,
75                                                uint64 size) {
76  return next_handler_->OnUploadProgress(request_id, position, size);
77}
78
79bool PrerenderResourceHandler::OnRequestRedirected(int request_id,
80                                                   const GURL& url,
81                                                   ResourceResponse* response,
82                                                   bool* defer) {
83  bool will_redirect = next_handler_->OnRequestRedirected(
84      request_id, url, response, defer);
85  if (will_redirect) {
86    alias_urls_.push_back(url);
87    url_ = url;
88  }
89  return will_redirect;
90}
91
92bool PrerenderResourceHandler::OnResponseStarted(int request_id,
93                                                 ResourceResponse* response) {
94  if (ShouldPrerender(url_, response)) {
95    BrowserThread::PostTask(
96        BrowserThread::UI,
97        FROM_HERE,
98        NewRunnableMethod(
99            this,
100            &PrerenderResourceHandler::RunCallbackFromUIThread,
101            url_,
102            alias_urls_));
103  }
104  return next_handler_->OnResponseStarted(request_id, response);
105}
106
107bool PrerenderResourceHandler::OnWillStart(int request_id,
108                                           const GURL& url,
109                                           bool* defer) {
110  bool will_start = next_handler_->OnWillStart(request_id, url, defer);
111  if (will_start) {
112    alias_urls_.push_back(url);
113    url_ = url;
114  }
115  return will_start;
116}
117
118bool PrerenderResourceHandler::OnWillRead(int request_id,
119                                          net::IOBuffer** buf,
120                                          int* buf_size,
121                                          int min_size) {
122  return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
123}
124
125bool PrerenderResourceHandler::OnReadCompleted(int request_id,
126                                               int* bytes_read) {
127  return next_handler_->OnReadCompleted(request_id, bytes_read);
128}
129
130bool PrerenderResourceHandler::OnResponseCompleted(
131    int request_id,
132    const net::URLRequestStatus& status,
133    const std::string& security_info) {
134  return next_handler_->OnResponseCompleted(request_id, status, security_info);
135}
136
137void PrerenderResourceHandler::OnRequestClosed() {
138  next_handler_->OnRequestClosed();
139}
140
141void PrerenderResourceHandler::RunCallbackFromUIThread(const GURL& url,
142                                                       const std::vector<GURL>&
143                                                       alias_urls) {
144  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145  prerender_callback_->Run(url, alias_urls);
146}
147
148void PrerenderResourceHandler::StartPrerender(const GURL& url,
149                                              const std::vector<GURL>&
150                                              alias_urls) {
151  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152  prerender_manager_->AddPreload(url, alias_urls);
153}
154