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.
4
5#include "content/browser/loader/throttling_resource_handler.h"
6
7#include "content/public/browser/resource_throttle.h"
8#include "content/public/common/resource_response.h"
9
10namespace content {
11
12ThrottlingResourceHandler::ThrottlingResourceHandler(
13    scoped_ptr<ResourceHandler> next_handler,
14    int child_id,
15    int request_id,
16    ScopedVector<ResourceThrottle> throttles)
17    : LayeredResourceHandler(next_handler.Pass()),
18      deferred_stage_(DEFERRED_NONE),
19      request_id_(request_id),
20      throttles_(throttles.Pass()),
21      index_(0),
22      cancelled_by_resource_throttle_(false) {
23  for (size_t i = 0; i < throttles_.size(); ++i)
24    throttles_[i]->set_controller(this);
25}
26
27ThrottlingResourceHandler::~ThrottlingResourceHandler() {
28}
29
30bool ThrottlingResourceHandler::OnRequestRedirected(int request_id,
31                                                    const GURL& new_url,
32                                                    ResourceResponse* response,
33                                                    bool* defer) {
34  DCHECK_EQ(request_id_, request_id);
35  DCHECK(!cancelled_by_resource_throttle_);
36
37  *defer = false;
38  while (index_ < throttles_.size()) {
39    throttles_[index_]->WillRedirectRequest(new_url, defer);
40    index_++;
41    if (cancelled_by_resource_throttle_)
42      return false;
43    if (*defer) {
44      deferred_stage_ = DEFERRED_REDIRECT;
45      deferred_url_ = new_url;
46      deferred_response_ = response;
47      return true;  // Do not cancel.
48    }
49  }
50
51  index_ = 0;  // Reset for next time.
52
53  return next_handler_->OnRequestRedirected(request_id, new_url, response,
54                                            defer);
55}
56
57bool ThrottlingResourceHandler::OnWillStart(int request_id,
58                                            const GURL& url,
59                                            bool* defer) {
60  DCHECK_EQ(request_id_, request_id);
61  DCHECK(!cancelled_by_resource_throttle_);
62
63  *defer = false;
64  while (index_ < throttles_.size()) {
65    throttles_[index_]->WillStartRequest(defer);
66    index_++;
67    if (cancelled_by_resource_throttle_)
68      return false;
69    if (*defer) {
70      deferred_stage_ = DEFERRED_START;
71      deferred_url_ = url;
72      return true;  // Do not cancel.
73    }
74  }
75
76  index_ = 0;  // Reset for next time.
77
78  return next_handler_->OnWillStart(request_id, url, defer);
79}
80
81bool ThrottlingResourceHandler::OnResponseStarted(int request_id,
82                                                  ResourceResponse* response,
83                                                  bool* defer) {
84  DCHECK_EQ(request_id_, request_id);
85  DCHECK(!cancelled_by_resource_throttle_);
86
87  while (index_ < throttles_.size()) {
88    throttles_[index_]->WillProcessResponse(defer);
89    index_++;
90    if (cancelled_by_resource_throttle_)
91      return false;
92    if (*defer) {
93      deferred_stage_ = DEFERRED_RESPONSE;
94      deferred_response_ = response;
95      return true;  // Do not cancel.
96    }
97  }
98
99  index_ = 0;  // Reset for next time.
100
101  return next_handler_->OnResponseStarted(request_id, response, defer);
102}
103
104void ThrottlingResourceHandler::Cancel() {
105  cancelled_by_resource_throttle_ = true;
106  controller()->Cancel();
107}
108
109void ThrottlingResourceHandler::CancelAndIgnore() {
110  cancelled_by_resource_throttle_ = true;
111  controller()->CancelAndIgnore();
112}
113
114void ThrottlingResourceHandler::CancelWithError(int error_code) {
115  cancelled_by_resource_throttle_ = true;
116  controller()->CancelWithError(error_code);
117}
118
119void ThrottlingResourceHandler::Resume() {
120  DCHECK(!cancelled_by_resource_throttle_);
121
122  DeferredStage last_deferred_stage = deferred_stage_;
123  deferred_stage_ = DEFERRED_NONE;
124  switch (last_deferred_stage) {
125    case DEFERRED_NONE:
126      NOTREACHED();
127      break;
128    case DEFERRED_START:
129      ResumeStart();
130      break;
131    case DEFERRED_REDIRECT:
132      ResumeRedirect();
133      break;
134    case DEFERRED_RESPONSE:
135      ResumeResponse();
136      break;
137  }
138}
139
140void ThrottlingResourceHandler::ResumeStart() {
141  DCHECK(!cancelled_by_resource_throttle_);
142
143  GURL url = deferred_url_;
144  deferred_url_ = GURL();
145
146  bool defer = false;
147  if (!OnWillStart(request_id_, url, &defer)) {
148    controller()->Cancel();
149  } else if (!defer) {
150    controller()->Resume();
151  }
152}
153
154void ThrottlingResourceHandler::ResumeRedirect() {
155  DCHECK(!cancelled_by_resource_throttle_);
156
157  GURL new_url = deferred_url_;
158  deferred_url_ = GURL();
159  scoped_refptr<ResourceResponse> response;
160  deferred_response_.swap(response);
161
162  bool defer = false;
163  if (!OnRequestRedirected(request_id_, new_url, response.get(), &defer)) {
164    controller()->Cancel();
165  } else if (!defer) {
166    controller()->Resume();
167  }
168}
169
170void ThrottlingResourceHandler::ResumeResponse() {
171  DCHECK(!cancelled_by_resource_throttle_);
172
173  scoped_refptr<ResourceResponse> response;
174  deferred_response_.swap(response);
175
176  bool defer = false;
177  if (!OnResponseStarted(request_id_, response.get(), &defer)) {
178    controller()->Cancel();
179  } else if (!defer) {
180    controller()->Resume();
181  }
182}
183
184}  // namespace content
185