Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: content/browser/loader/async_revalidation_driver.cc

Issue 1041993004: content::ResourceDispatcherHostImpl changes for stale-while-revalidate (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@s-w-r-yhirano-patch
Patch Set: Workaround iwyu bug in prerender_resource Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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/async_revalidation_driver.h"
6
7 #include "base/location.h"
8 #include "base/logging.h"
9 #include "base/metrics/user_metrics_action.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "base/time/time.h"
13 #include "content/public/browser/user_metrics.h"
14 #include "net/base/net_errors.h"
15 #include "net/cert/cert_status_flags.h"
16 #include "net/http/http_transaction_factory.h"
17 #include "net/http/http_util.h"
18 #include "net/ssl/ssl_info.h"
19 #include "net/url_request/url_request.h"
20 #include "net/url_request/url_request_context.h"
21 #include "net/url_request/url_request_status.h"
22
23 using base::TimeDelta;
24 using base::TimeTicks;
25
26 namespace content {
27
28 namespace {
29 // This matches the maximum allocation size of AsyncResourceHandler.
30 const int kReadBufSize = 32 * 1024;
31 const int kReadTimeoutSeconds = 5 * 60;
32 }
33
34 AsyncRevalidationKey::AsyncRevalidationKey(
35 const ResourceContext* resource_context,
36 const net::HttpCache* http_cache,
37 const GURL& url)
38 : resource_context(resource_context),
39 http_cache(http_cache),
40 url_key(net::HttpUtil::SpecForRequest(url)) {}
41
42 AsyncRevalidationKey::AsyncRevalidationKey(
43 const ResourceContext* resource_context)
44 : resource_context(resource_context), http_cache(nullptr), url_key() {}
45
46 AsyncRevalidationKey::AsyncRevalidationKey(const AsyncRevalidationKey& rhs)
47 : resource_context(rhs.resource_context),
48 http_cache(rhs.http_cache),
49 url_key(rhs.url_key) {}
50
51 AsyncRevalidationKey::~AsyncRevalidationKey() {}
52
53 // The use of base::Unretained() in the initialisation of read_timer_ is safe
54 // because base::Timer guarantees not to call the callback after being
55 // destroyed.
56 AsyncRevalidationDriver::AsyncRevalidationDriver(
57 scoped_ptr<net::URLRequest> request,
58 scoped_ptr<ResourceThrottle> throttle,
59 const base::Closure& completion_callback)
60 : read_timer_(FROM_HERE,
61 TimeDelta::FromSeconds(kReadTimeoutSeconds),
62 base::Bind(&AsyncRevalidationDriver::OnReadTimeout,
63 base::Unretained(this)),
64 false),
65 request_(request.Pass()),
66 throttle_(throttle.Pass()),
67 completion_callback_(completion_callback),
68 weak_ptr_factory_(this) {
69 request_->set_delegate(this);
70 throttle_->set_controller(this);
71 }
72
73 AsyncRevalidationDriver::~AsyncRevalidationDriver() {
74 weak_ptr_factory_.InvalidateWeakPtrs();
75 // Run ResourceThrottle destructor before we tear-down the rest of our state
76 // as the ResourceThrottle may want to inspect the URLRequest and other state.
77 throttle_.reset();
78 }
79
80 void AsyncRevalidationDriver::StartRequest() {
81 RecordAction(base::UserMetricsAction("AsyncRevalidationCreated"));
82 // Give the handler a chance to delay the URLRequest from being started.
83 bool defer_start = false;
84 throttle_->WillStartRequest(&defer_start);
85
86 if (defer_start) {
87 RecordDefer(DEFERRED_START);
88 } else {
89 StartRequestInternal();
90 }
91 }
92
93 void AsyncRevalidationDriver::CancelRequest() {
94 CancelRequestInternal(net::ERR_ABORTED);
95 }
96
97 void AsyncRevalidationDriver::OnReceivedRedirect(
98 net::URLRequest* unused,
99 const net::RedirectInfo& redirect_info,
100 bool* defer) {
101 DCHECK_EQ(request_.get(), unused);
102
103 DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
104 RecordAction(base::UserMetricsAction("AsyncRevalidationRedirected"));
105 CancelRequest();
106 }
107
108 void AsyncRevalidationDriver::OnAuthRequired(
109 net::URLRequest* unused,
110 net::AuthChallengeInfo* auth_info) {
111 DCHECK_EQ(request_.get(), unused);
112 request_->CancelAuth();
davidben 2015/10/08 21:57:51 This needs to cancel the request; CancelAuth is to
Adam Rice 2015/10/13 22:53:16 Done.
113 }
114
115 void AsyncRevalidationDriver::OnCertificateRequested(
116 net::URLRequest* unused,
117 net::SSLCertRequestInfo* cert_info) {
118 DCHECK_EQ(request_.get(), unused);
119 CancelRequestInternal(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
davidben 2015/10/08 21:57:51 The default implementation already cancels.
Adam Rice 2015/10/13 22:53:16 Removed.
120 }
121
122 void AsyncRevalidationDriver::OnSSLCertificateError(
123 net::URLRequest* unused,
124 const net::SSLInfo& ssl_info,
125 bool fatal) {
126 DCHECK_EQ(request_.get(), unused);
127 CancelRequestInternal(net::MapCertStatusToNetError(ssl_info.cert_status));
davidben 2015/10/08 21:57:51 The default implementation already cancels.
Adam Rice 2015/10/13 22:53:16 Removed.
128 }
129
130 void AsyncRevalidationDriver::OnBeforeNetworkStart(net::URLRequest* unused,
131 bool* defer) {
132 DCHECK_EQ(request_.get(), unused);
133
134 // Give the ResourceThrottle a chance to delay the URLRequest from using the
135 // network.
136 throttle_->WillStartUsingNetwork(defer);
137 if (*defer)
138 RecordDefer(DEFERRED_NETWORK_START);
139 }
140
141 void AsyncRevalidationDriver::OnResponseStarted(net::URLRequest* unused) {
142 DCHECK_EQ(request_.get(), unused);
143
144 DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
145
146 if (!request_->status().is_success()) {
147 DCHECK(!has_already_failed_);
148 has_already_failed_ = true;
149 ResponseCompleted();
150 return;
151 }
152
153 bool defer = false;
154 throttle_->WillProcessResponse(&defer);
155 if (defer) {
156 RecordDefer(DEFERRED_READ); // Read first chunk when resumed.
157 return;
158 }
159
160 if (request_->status().is_success()) {
161 StartReading(false); // Read the first chunk.
162 } else {
163 DCHECK(!has_already_failed_);
164 has_already_failed_ = true;
165 ResponseCompleted();
166 }
167 }
168
169 void AsyncRevalidationDriver::OnReadCompleted(net::URLRequest* unused,
170 int bytes_read) {
171 DCHECK_EQ(request_.get(), unused);
172 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
173 << " bytes_read = " << bytes_read;
174
175 // bytes_read == -1 always implies an error.
176 if (bytes_read == -1 || !request_->status().is_success()) {
177 if (!has_already_failed_) {
178 has_already_failed_ = true;
179 ResponseCompleted();
180 }
181 return;
182 }
183
184 DCHECK_GE(bytes_read, 0);
185 DCHECK(request_->status().is_success());
186 DCHECK(!is_deferred());
187
188 if (bytes_read > 0) {
189 StartReading(true); // Read the next chunk.
190 } else {
191 // URLRequest reported an EOF. Call ResponseCompleted.
192 DCHECK_EQ(0, bytes_read);
193 ResponseCompleted();
194 }
195 }
196
197 void AsyncRevalidationDriver::Resume() {
198 DeferredStage stage = deferred_stage_;
199 deferred_stage_ = DEFERRED_NONE;
200 switch (stage) {
201 case DEFERRED_NONE:
202 NOTREACHED();
203 break;
204 case DEFERRED_START:
205 StartRequestInternal();
206 break;
207 case DEFERRED_NETWORK_START:
208 request_->ResumeNetworkStart();
209 break;
210 case DEFERRED_READ:
211 base::ThreadTaskRunnerHandle::Get()->PostTask(
212 FROM_HERE, base::Bind(&AsyncRevalidationDriver::ResumeReading,
213 weak_ptr_factory_.GetWeakPtr()));
214 break;
215 }
216 }
217
218 void AsyncRevalidationDriver::Cancel() {
219 NOTREACHED();
220 }
221
222 void AsyncRevalidationDriver::CancelAndIgnore() {
223 NOTREACHED();
224 }
225
226 void AsyncRevalidationDriver::CancelWithError(int error_code) {
227 NOTREACHED();
228 }
229
230 void AsyncRevalidationDriver::StartRequestInternal() {
231 DCHECK(!request_->is_pending());
232
233 // TODO(ricea): This seems like it will never call ResponseCompleted().
234 if (!request_->status().is_success())
235 return;
davidben 2015/10/08 21:57:51 This isn't possible, unless you implement Cancel,
Adam Rice 2015/10/13 22:53:16 Thanks. Removed.
Adam Rice 2015/10/22 18:16:12 This turned out to be possible with the sequence o
236
237 request_->Start();
238 }
239
240 void AsyncRevalidationDriver::CancelRequestInternal(int error) {
241 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec();
242
243 bool was_pending = request_->is_pending();
244
245 request_->CancelWithError(error);
246
247 if (!was_pending) {
248 // If the request isn't in flight, then we won't get an asynchronous
249 // notification from the request, so we have to signal ourselves to finish
250 // this request.
251 base::ThreadTaskRunnerHandle::Get()->PostTask(
252 FROM_HERE, base::Bind(&AsyncRevalidationDriver::ResponseCompleted,
253 weak_ptr_factory_.GetWeakPtr()));
254 }
255 }
256
257 void AsyncRevalidationDriver::CompleteResponseStarted() {
258 bool defer = false;
259 throttle_->WillProcessResponse(&defer);
260 if (defer)
261 RecordDefer(DEFERRED_READ); // Read first chunk when resumed.
262 }
263
264 void AsyncRevalidationDriver::StartReading(bool is_continuation) {
265 int bytes_read = 0;
266 ReadMore(&bytes_read);
267
268 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
269 if (request_->status().is_io_pending())
270 return;
271
272 if (!is_continuation || bytes_read <= 0) {
273 OnReadCompleted(request_.get(), bytes_read);
274 } else {
275 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
276 // thread in case the URLRequest can provide data synchronously.
277 base::ThreadTaskRunnerHandle::Get()->PostTask(
278 FROM_HERE,
279 base::Bind(&AsyncRevalidationDriver::OnReadCompleted,
280 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
281 }
282 }
283
284 void AsyncRevalidationDriver::ResumeReading() {
285 DCHECK(!is_deferred());
286
287 if (request_->status().is_success()) {
288 StartReading(false); // Read the next chunk (OK to complete synchronously).
289 } else {
290 ResponseCompleted();
291 }
292 }
293
294 void AsyncRevalidationDriver::ReadMore(int* bytes_read) {
295 DCHECK(!is_deferred());
296
297 if (!read_buffer_)
298 read_buffer_ = new net::IOBuffer(kReadBufSize);
299
300 read_timer_.Reset();
301 request_->Read(read_buffer_.get(), kReadBufSize, bytes_read);
302
303 // No need to check the return value here as we'll detect errors by
304 // inspecting the URLRequest's status.
305 }
306
307 void AsyncRevalidationDriver::ResponseCompleted() {
308 DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
309 completion_callback_.Run();
310 }
311
312 void AsyncRevalidationDriver::OnReadTimeout() {
313 RecordAction(base::UserMetricsAction("AsyncRevalidationTimeout"));
314 CancelRequestInternal(net::ERR_TIMED_OUT);
315 }
316
317 void AsyncRevalidationDriver::RecordDefer(DeferredStage deferred_stage) {
318 request_->LogBlockedBy(throttle_->GetNameForLogging());
319 DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
320 deferred_stage_ = deferred_stage;
321 }
322
323 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698