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

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: Functional change: An initial redirect leg is now async revalidated. s-w-r is still ignored after t… Created 5 years, 1 month 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 <utility>
8
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/metrics/user_metrics_action.h"
12 #include "base/single_thread_task_runner.h"
davidben 2015/11/23 23:40:41 Unused?
Adam Rice 2015/11/25 19:39:39 Used. I've rewritten the code to make the use expl
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "content/public/browser/user_metrics.h"
16 #include "net/base/net_errors.h"
17 #include "net/cert/cert_status_flags.h"
davidben 2015/11/23 23:40:40 Unused?
Adam Rice 2015/11/25 19:39:39 Removed.
18 #include "net/ssl/ssl_info.h"
davidben 2015/11/23 23:40:40 Unused?
Adam Rice 2015/11/25 19:39:39 Removed.
19 #include "net/url_request/url_request_context.h"
davidben 2015/11/23 23:40:40 Unused?
Adam Rice 2015/11/25 19:39:39 Removed.
20 #include "net/url_request/url_request_status.h"
21
22 namespace content {
23
24 namespace {
25 // This matches the maximum allocation size of AsyncResourceHandler.
26 const int kReadBufSize = 32 * 1024;
27
28 // This value should not be too large, as this request may be tying up a socket
29 // that could be used for something better. However, if it is too small, the
30 // cache entry will be truncated for no good reason.
davidben 2015/11/23 23:40:40 I don't believe this comment is right. If we time
Adam Rice 2015/11/25 19:39:39 This value isn't used for the response timeout. In
31 // TODO(ricea): Find a more scientific way to set this timeout.
32 const int kReadTimeoutSeconds = 30;
33 }
34
35 // The use of base::Unretained() in the initialisation of read_timer_ is safe
36 // because base::Timer guarantees not to call the callback after being
37 // destroyed.
38 AsyncRevalidationDriver::AsyncRevalidationDriver(
39 scoped_ptr<net::URLRequest> request,
40 scoped_ptr<ResourceThrottle> throttle,
41 const base::Closure& completion_callback)
42 : read_timer_(FROM_HERE,
43 base::TimeDelta::FromSeconds(kReadTimeoutSeconds),
44 base::Bind(&AsyncRevalidationDriver::OnReadTimeout,
45 base::Unretained(this)),
46 false),
47 request_(std::move(request)),
48 throttle_(std::move(throttle)),
49 completion_callback_(completion_callback),
50 weak_ptr_factory_(this) {
51 request_->set_delegate(this);
52 throttle_->set_controller(this);
53 }
54
55 AsyncRevalidationDriver::~AsyncRevalidationDriver() {
davidben 2015/11/23 23:40:40 But for releasing the completion callback, this is
Adam Rice 2015/11/25 19:39:39 Removed.
56 weak_ptr_factory_.InvalidateWeakPtrs();
57 // Run ResourceThrottle destructor before we tear-down the rest of our state
58 // as the ResourceThrottle may want to inspect the URLRequest and other state.
59 throttle_.reset();
60 }
61
62 void AsyncRevalidationDriver::StartRequest() {
63 RecordAction(base::UserMetricsAction("AsyncRevalidationCreated"));
64 // Give the handler a chance to delay the URLRequest from being started.
65 bool defer_start = false;
66 throttle_->WillStartRequest(&defer_start);
67
68 if (defer_start) {
69 RecordDefer();
70 } else {
71 StartRequestInternal();
72 }
73 }
74
75 void AsyncRevalidationDriver::CancelRequest() {
76 CancelRequestInternal(net::ERR_ABORTED);
77 }
78
79 void AsyncRevalidationDriver::OnReceivedRedirect(
80 net::URLRequest* unused,
davidben 2015/11/23 23:40:40 Nit: Match the header file's variable names.
Adam Rice 2015/11/25 19:39:39 Done.
81 const net::RedirectInfo& redirect_info,
82 bool* defer) {
83 DCHECK_EQ(request_.get(), unused);
84
85 // The async revalidation should not follow redirects, because caching is
86 // a property of an individual HTTP resource.
87 DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
88 RecordAction(base::UserMetricsAction("AsyncRevalidationRedirected"));
89 CancelRequest();
90 }
91
92 void AsyncRevalidationDriver::OnAuthRequired(
93 net::URLRequest* unused,
94 net::AuthChallengeInfo* auth_info) {
95 DCHECK_EQ(request_.get(), unused);
96 // This error code doesn't have exactly the right semantics, but it should
97 // be sufficient to narrow down the problem in net logs.
98 request_->CancelWithError(net::ERR_ACCESS_DENIED);
99 }
100
101 void AsyncRevalidationDriver::OnBeforeNetworkStart(net::URLRequest* unused,
102 bool* defer) {
103 DCHECK_EQ(request_.get(), unused);
104
105 // Verify that the ResourceScheduler does not defer here.
106 throttle_->WillStartUsingNetwork(defer);
107 DCHECK(!*defer);
108 }
109
110 void AsyncRevalidationDriver::OnResponseStarted(net::URLRequest* unused) {
111 DCHECK_EQ(request_.get(), unused);
112
113 DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
114
115 if (!request_->status().is_success()) {
116 ResponseCompleted();
117 return;
118 }
119
120 const net::HttpResponseInfo& response_info = request_->response_info();
121 if (!response_info.response_time.is_null() && response_info.was_cached) {
davidben 2015/11/23 23:40:40 What is the response_time check for?
Adam Rice 2015/11/25 19:39:39 From the comment on the was_cached member in http_
122 // The cached entry was revalidated. No need to read it in.
123 ResponseCompleted();
124 return;
125 }
126
127 bool defer = false;
128 throttle_->WillProcessResponse(&defer);
129 DCHECK(!defer);
130
131 if (request_->status().is_success()) {
davidben 2015/11/23 23:40:40 You've already checked this. The ResourceLoader co
Adam Rice 2015/11/25 19:39:39 Okay, that makes sense. Removed.
132 StartReading(false); // Read the first chunk.
133 } else {
134 ResponseCompleted();
135 }
136 }
137
138 void AsyncRevalidationDriver::OnReadCompleted(net::URLRequest* unused,
139 int bytes_read) {
140 DCHECK_EQ(request_.get(), unused);
141 DCHECK(!is_deferred_);
142 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
143 << " bytes_read = " << bytes_read;
144
145 // bytes_read == -1 is an error.
146 // bytes_read == 0 is EOF.
147 if (bytes_read == -1 || bytes_read == 0 || !request_->status().is_success()) {
148 ResponseCompleted();
149 return;
150 }
151
152 DCHECK_GT(bytes_read, 0);
153 StartReading(true); // Read the next chunk.
154 }
155
156 void AsyncRevalidationDriver::Resume() {
157 DCHECK(is_deferred_);
158 is_deferred_ = false;
159 StartRequestInternal();
160 }
161
162 void AsyncRevalidationDriver::Cancel() {
163 NOTREACHED();
164 }
165
166 void AsyncRevalidationDriver::CancelAndIgnore() {
167 NOTREACHED();
168 }
169
170 void AsyncRevalidationDriver::CancelWithError(int error_code) {
171 NOTREACHED();
172 }
173
174 void AsyncRevalidationDriver::StartRequestInternal() {
175 DCHECK(!request_->is_pending());
176
177 // This can happen if Resume() is called after CancelRequest().
178 // Since CancelRequest() will have called ResponseCompleted() asynchronously,
179 // it's not necessary to call it again.
180 if (!request_->status().is_success())
181 return;
182
183 request_->Start();
184 }
185
186 void AsyncRevalidationDriver::CancelRequestInternal(int error) {
187 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec();
188
189 bool was_pending = request_->is_pending();
190
191 request_->CancelWithError(error);
192
193 if (!was_pending) {
194 // If the request isn't in flight, then we won't get an asynchronous
195 // notification from the request, so we have to signal ourselves to finish
196 // this request.
197 base::ThreadTaskRunnerHandle::Get()->PostTask(
198 FROM_HERE, base::Bind(&AsyncRevalidationDriver::ResponseCompleted,
199 weak_ptr_factory_.GetWeakPtr()));
200 }
201 }
202
203 void AsyncRevalidationDriver::StartReading(bool is_continuation) {
204 int bytes_read = 0;
205 ReadMore(&bytes_read);
206
207 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
208 if (request_->status().is_io_pending())
209 return;
210
211 if (!is_continuation || bytes_read <= 0) {
212 OnReadCompleted(request_.get(), bytes_read);
213 } else {
214 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
215 // thread in case the URLRequest can provide data synchronously.
216 base::ThreadTaskRunnerHandle::Get()->PostTask(
217 FROM_HERE,
218 base::Bind(&AsyncRevalidationDriver::OnReadCompleted,
219 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
220 }
221 }
222
223 void AsyncRevalidationDriver::ReadMore(int* bytes_read) {
224 DCHECK(!is_deferred_);
225
226 if (!read_buffer_)
227 read_buffer_ = new net::IOBuffer(kReadBufSize);
228
229 read_timer_.Reset();
230 request_->Read(read_buffer_.get(), kReadBufSize, bytes_read);
231
232 // No need to check the return value here as we'll detect errors by
233 // inspecting the URLRequest's status.
234 }
235
236 void AsyncRevalidationDriver::ResponseCompleted() {
237 DVLOG(1) << "ResponseCompleted: " << request_->url().spec();
238 // When this class cancels a redirect, URLRequest calls both the
239 // OnResponseStarted() and OnReadCompleted() callbacks. This class should not
240 // run |completion_callback_| twice.
241 //
242 // TODO(ricea): Work out why URLRequest calls both methods on cancellation and
243 // make it stop.
davidben 2015/11/23 23:40:40 Is this still happening? In the previous version,
Adam Rice 2015/11/25 19:39:39 Yes, still happening. It might just be a feature o
davidben 2015/12/07 23:56:03 And confirmed. Sigh. https://crbug.com/564820. (Mi
244 if (completion_callback_.is_null())
245 return;
246 base::Closure completion_callback(completion_callback_);
247 completion_callback_.Reset();
248 completion_callback.Run();
davidben 2015/11/23 23:40:40 base::ResetAndReturn(&completion_callback_).Run();
davidben 2015/11/23 23:40:40 Add: // |this| may be deleted after this point.
Adam Rice 2015/11/25 19:39:39 Thank you! I knew that existed but I couldn't reme
Adam Rice 2015/11/25 19:39:39 Done.
249 }
250
251 void AsyncRevalidationDriver::OnReadTimeout() {
252 RecordAction(base::UserMetricsAction("AsyncRevalidationTimeout"));
253 CancelRequestInternal(net::ERR_TIMED_OUT);
254 }
255
256 void AsyncRevalidationDriver::RecordDefer() {
257 request_->LogBlockedBy(throttle_->GetNameForLogging());
258 DCHECK(!is_deferred_);
259 is_deferred_ = true;
260 }
261
262 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698