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

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

Issue 2764683002: Remove stale-while-revalidate from content and chrome (Closed)
Patch Set: rebase Created 3 years, 9 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 <utility>
8
9 #include "base/callback_helpers.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/metrics/sparse_histogram.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "base/time/time.h"
18 #include "net/base/net_errors.h"
19 #include "net/url_request/url_request_status.h"
20
21 namespace content {
22
23 namespace {
24 // This matches the maximum allocation size of AsyncResourceHandler.
25 const int kReadBufSize = 32 * 1024;
26
27 // The time to wait for a response. Since this includes the time taken to
28 // connect, this has been set to match the connect timeout
29 // kTransportConnectJobTimeoutInSeconds.
30 const int kResponseTimeoutInSeconds = 240; // 4 minutes.
31
32 // This value should not be too large, as this request may be tying up a socket
33 // that could be used for something better. However, if it is too small, the
34 // cache entry will be truncated for no good reason.
35 // TODO(ricea): Find a more scientific way to set this timeout.
36 const int kReadTimeoutInSeconds = 30;
37 } // namespace
38
39 AsyncRevalidationDriver::AsyncRevalidationDriver(
40 std::unique_ptr<net::URLRequest> request,
41 std::unique_ptr<ResourceThrottle> throttle,
42 const base::Closure& completion_callback)
43 : request_(std::move(request)),
44 throttle_(std::move(throttle)),
45 completion_callback_(completion_callback),
46 weak_ptr_factory_(this) {
47 request_->set_delegate(this);
48 throttle_->set_delegate(this);
49 }
50
51 AsyncRevalidationDriver::~AsyncRevalidationDriver() {}
52
53 void AsyncRevalidationDriver::StartRequest() {
54 // Give the handler a chance to delay the URLRequest from being started.
55 bool defer_start = false;
56 throttle_->WillStartRequest(&defer_start);
57
58 if (defer_start) {
59 RecordDefer();
60 } else {
61 StartRequestInternal();
62 }
63 }
64
65 void AsyncRevalidationDriver::OnReceivedRedirect(
66 net::URLRequest* request,
67 const net::RedirectInfo& redirect_info,
68 bool* defer) {
69 DCHECK_EQ(request_.get(), request);
70
71 // The async revalidation should not follow redirects, because caching is
72 // a property of an individual HTTP resource.
73 DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
74 CancelRequestInternal(net::ERR_ABORTED, RESULT_GOT_REDIRECT);
75 }
76
77 void AsyncRevalidationDriver::OnAuthRequired(
78 net::URLRequest* request,
79 net::AuthChallengeInfo* auth_info) {
80 DCHECK_EQ(request_.get(), request);
81 // This error code doesn't have exactly the right semantics, but it should
82 // be sufficient to narrow down the problem in net logs.
83 CancelRequestInternal(net::ERR_ACCESS_DENIED, RESULT_AUTH_FAILED);
84 }
85
86 void AsyncRevalidationDriver::OnResponseStarted(net::URLRequest* request) {
87 DCHECK_EQ(request_.get(), request);
88
89 DVLOG(1) << "OnResponseStarted: " << request_->url().spec();
90
91 // We have the response. No need to wait any longer.
92 timer_.Stop();
93
94 if (!request_->status().is_success()) {
95 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AsyncRevalidation.ResponseError",
96 -request_->status().ToNetError());
97 ResponseCompleted(RESULT_NET_ERROR);
98 // |this| may be deleted after this point.
99 return;
100 }
101
102 const net::HttpResponseInfo& response_info = request_->response_info();
103 if (!response_info.response_time.is_null() && response_info.was_cached) {
104 // The cached entry was revalidated. No need to read it in.
105 ResponseCompleted(RESULT_REVALIDATED);
106 // |this| may be deleted after this point.
107 return;
108 }
109
110 bool defer = false;
111 throttle_->WillProcessResponse(&defer);
112 DCHECK(!defer);
113
114 // Set up the timer for reading the body. This use of base::Unretained() is
115 // guaranteed safe by the semantics of base::OneShotTimer.
116 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kReadTimeoutInSeconds),
117 base::Bind(&AsyncRevalidationDriver::OnTimeout,
118 base::Unretained(this), RESULT_BODY_TIMEOUT));
119 StartReading(false); // Read the first chunk.
120 }
121
122 void AsyncRevalidationDriver::OnReadCompleted(net::URLRequest* request,
123 int bytes_read) {
124 // request_ could be NULL if a timeout happened while OnReadCompleted() was
125 // queued to run asynchronously.
126 if (!request_)
127 return;
128 DCHECK_EQ(request_.get(), request);
129 DCHECK(!is_deferred_);
130 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
131 << " bytes_read = " << bytes_read;
132
133 // bytes_read == 0 is EOF.
134 if (bytes_read == 0) {
135 ResponseCompleted(RESULT_LOADED);
136 return;
137 }
138 // bytes_read == -1 is an error.
139 if (bytes_read == -1 || !request_->status().is_success()) {
140 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AsyncRevalidation.ReadError",
141 -request_->status().ToNetError());
142 ResponseCompleted(RESULT_READ_ERROR);
143 // |this| may be deleted after this point.
144 return;
145 }
146
147 DCHECK_GT(bytes_read, 0);
148 StartReading(true); // Read the next chunk.
149 }
150
151 void AsyncRevalidationDriver::Resume() {
152 DCHECK(is_deferred_);
153 DCHECK(request_);
154 is_deferred_ = false;
155 request_->LogUnblocked();
156 StartRequestInternal();
157 }
158
159 void AsyncRevalidationDriver::Cancel() {
160 NOTREACHED();
161 }
162
163 void AsyncRevalidationDriver::CancelAndIgnore() {
164 NOTREACHED();
165 }
166
167 void AsyncRevalidationDriver::CancelWithError(int error_code) {
168 NOTREACHED();
169 }
170
171 void AsyncRevalidationDriver::StartRequestInternal() {
172 DCHECK(request_);
173 DCHECK(!request_->is_pending());
174
175 // Start the response timer. This use of base::Unretained() is guaranteed safe
176 // by the semantics of base::OneShotTimer.
177 timer_.Start(FROM_HERE,
178 base::TimeDelta::FromSeconds(kResponseTimeoutInSeconds),
179 base::Bind(&AsyncRevalidationDriver::OnTimeout,
180 base::Unretained(this), RESULT_RESPONSE_TIMEOUT));
181 request_->Start();
182 }
183
184 void AsyncRevalidationDriver::CancelRequestInternal(
185 int error,
186 AsyncRevalidationResult result) {
187 DVLOG(1) << "CancelRequestInternal: " << request_->url().spec();
188
189 // Set the error code since this will be reported to the NetworkDelegate and
190 // recorded in the NetLog.
191 request_->CancelWithError(error);
192
193 // The ResourceScheduler needs to be able to examine the request when the
194 // ResourceThrottle is destroyed, so delete it first.
195 throttle_.reset();
196
197 // Destroy the request so that it doesn't try to send an asynchronous
198 // notification of completion.
199 request_.reset();
200
201 // Cancel timer to prevent OnTimeout() being called.
202 timer_.Stop();
203
204 ResponseCompleted(result);
205 // |this| may deleted after this point.
206 }
207
208 void AsyncRevalidationDriver::StartReading(bool is_continuation) {
209 int bytes_read = 0;
210 ReadMore(&bytes_read);
211
212 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
213 if (request_->status().is_io_pending())
214 return;
215
216 if (!is_continuation || bytes_read <= 0) {
217 OnReadCompleted(request_.get(), bytes_read);
218 } else {
219 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
220 // thread in case the URLRequest can provide data synchronously.
221 scoped_refptr<base::SingleThreadTaskRunner> single_thread_task_runner =
222 base::ThreadTaskRunnerHandle::Get();
223 single_thread_task_runner->PostTask(
224 FROM_HERE,
225 base::Bind(&AsyncRevalidationDriver::OnReadCompleted,
226 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
227 }
228 }
229
230 void AsyncRevalidationDriver::ReadMore(int* bytes_read) {
231 DCHECK(!is_deferred_);
232
233 if (!read_buffer_)
234 read_buffer_ = new net::IOBuffer(kReadBufSize);
235
236 timer_.Reset();
237 request_->Read(read_buffer_.get(), kReadBufSize, bytes_read);
238
239 // No need to check the return value here as we'll detect errors by
240 // inspecting the URLRequest's status.
241 }
242
243 void AsyncRevalidationDriver::ResponseCompleted(
244 AsyncRevalidationResult result) {
245 DVLOG(1) << "ResponseCompleted: "
246 << (request_ ? request_->url().spec() : "(request deleted)")
247 << "result = " << result;
248 UMA_HISTOGRAM_ENUMERATION("Net.AsyncRevalidation.Result", result, RESULT_MAX);
249 DCHECK(!completion_callback_.is_null());
250 base::ResetAndReturn(&completion_callback_).Run();
251 // |this| may be deleted after this point.
252 }
253
254 void AsyncRevalidationDriver::OnTimeout(AsyncRevalidationResult result) {
255 CancelRequestInternal(net::ERR_TIMED_OUT, result);
256 }
257
258 void AsyncRevalidationDriver::RecordDefer() {
259 request_->LogBlockedBy(throttle_->GetNameForLogging());
260 DCHECK(!is_deferred_);
261 is_deferred_ = true;
262 }
263
264 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/loader/async_revalidation_driver.h ('k') | content/browser/loader/async_revalidation_driver_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698