OLD | NEW |
---|---|
(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" // For FROM_HERE | |
kinuko
2015/11/19 07:00:28
nit: I see you added these comments per review fee
Adam Rice
2015/11/19 21:13:52
Done.
Bence
2015/11/20 13:18:35
I genuinely couldn't find what these headers were
Adam Rice
2015/11/20 13:23:51
Absolutely no problem. I follow the philosophy tha
| |
8 #include "base/logging.h" | |
9 #include "base/metrics/user_metrics_action.h" | |
10 #include "base/single_thread_task_runner.h" // Gets a SingleThreadTaskRunner | |
11 #include "base/thread_task_runner_handle.h" // from ThreadTaskRunnerHandle. | |
kinuko
2015/11/19 07:00:28
These seem obvious from header names.
Adam Rice
2015/11/19 21:13:52
What's not obvious is that the SingleThreadTaskRun
Bence
2015/11/20 13:18:35
Ditto.
| |
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/ssl/ssl_info.h" | |
17 #include "net/url_request/url_request_context.h" | |
18 #include "net/url_request/url_request_status.h" | |
19 | |
20 namespace content { | |
21 | |
22 namespace { | |
23 // This matches the maximum allocation size of AsyncResourceHandler. | |
24 const int kReadBufSize = 32 * 1024; | |
25 const int kReadTimeoutSeconds = 5 * 60; | |
kinuko
2015/11/19 08:38:34
How is this timeout value chosen?
Adam Rice
2015/11/19 21:13:52
I don't remember. The most likely place is kDefaul
| |
26 } | |
27 | |
28 // The use of base::Unretained() in the initialisation of read_timer_ is safe | |
29 // because base::Timer guarantees not to call the callback after being | |
30 // destroyed. | |
31 AsyncRevalidationDriver::AsyncRevalidationDriver( | |
32 scoped_ptr<net::URLRequest> request, | |
33 scoped_ptr<ResourceThrottle> throttle, | |
34 const base::Closure& completion_callback) | |
35 : read_timer_(FROM_HERE, | |
36 base::TimeDelta::FromSeconds(kReadTimeoutSeconds), | |
37 base::Bind(&AsyncRevalidationDriver::OnReadTimeout, | |
38 base::Unretained(this)), | |
39 false), | |
40 request_(request.Pass()), | |
41 throttle_(throttle.Pass()), | |
kinuko
2015/11/19 07:00:28
nit: you could now use std::move for these
Adam Rice
2015/11/19 21:13:52
Done.
| |
42 completion_callback_(completion_callback), | |
43 weak_ptr_factory_(this) { | |
44 request_->set_delegate(this); | |
45 throttle_->set_controller(this); | |
46 } | |
47 | |
48 AsyncRevalidationDriver::~AsyncRevalidationDriver() { | |
49 weak_ptr_factory_.InvalidateWeakPtrs(); | |
50 // Run ResourceThrottle destructor before we tear-down the rest of our state | |
51 // as the ResourceThrottle may want to inspect the URLRequest and other state. | |
52 throttle_.reset(); | |
53 } | |
54 | |
55 void AsyncRevalidationDriver::StartRequest() { | |
56 RecordAction(base::UserMetricsAction("AsyncRevalidationCreated")); | |
57 // Give the handler a chance to delay the URLRequest from being started. | |
58 bool defer_start = false; | |
59 throttle_->WillStartRequest(&defer_start); | |
60 | |
61 if (defer_start) { | |
62 RecordDefer(); | |
63 } else { | |
64 StartRequestInternal(); | |
65 } | |
66 } | |
67 | |
68 void AsyncRevalidationDriver::CancelRequest() { | |
69 CancelRequestInternal(net::ERR_ABORTED); | |
70 } | |
71 | |
72 void AsyncRevalidationDriver::OnReceivedRedirect( | |
73 net::URLRequest* unused, | |
74 const net::RedirectInfo& redirect_info, | |
75 bool* defer) { | |
76 DCHECK_EQ(request_.get(), unused); | |
77 | |
78 // The async revalidation should not follow redirects, because caching is | |
79 // a property of an individual HTTP resource. | |
80 DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec(); | |
81 RecordAction(base::UserMetricsAction("AsyncRevalidationRedirected")); | |
82 CancelRequest(); | |
83 } | |
84 | |
85 void AsyncRevalidationDriver::OnAuthRequired( | |
86 net::URLRequest* unused, | |
87 net::AuthChallengeInfo* auth_info) { | |
88 DCHECK_EQ(request_.get(), unused); | |
89 // This error code doesn't have exactly the right semantics, but it should | |
90 // be sufficient to narrow down the problem in net logs. | |
91 request_->CancelWithError(net::ERR_ACCESS_DENIED); | |
kinuko
2015/11/19 07:00:28
Help me understand: for this case we don't need/wa
Adam Rice
2015/11/19 21:13:52
CancelRequest() would use ERR_ABORTED, which is ve
| |
92 } | |
93 | |
94 void AsyncRevalidationDriver::OnBeforeNetworkStart(net::URLRequest* unused, | |
95 bool* defer) { | |
96 DCHECK_EQ(request_.get(), unused); | |
97 | |
98 // Verify that the ResourceScheduler does not defer here. | |
99 throttle_->WillStartUsingNetwork(defer); | |
100 DCHECK(!defer); | |
kinuko
2015/11/19 07:00:29
!*defer ?
Adam Rice
2015/11/19 21:13:52
Oh. The tests in https://codereview.chromium.org/1
| |
101 } | |
102 | |
103 void AsyncRevalidationDriver::OnResponseStarted(net::URLRequest* unused) { | |
104 DCHECK_EQ(request_.get(), unused); | |
105 | |
106 DVLOG(1) << "OnResponseStarted: " << request_->url().spec(); | |
107 | |
108 if (!request_->status().is_success()) { | |
109 ResponseCompleted(); | |
110 return; | |
111 } | |
112 | |
113 const net::HttpResponseInfo& response_info = request_->response_info(); | |
114 if (!response_info.response_time.is_null() && response_info.was_cached) { | |
115 // The cached entry was revalidated. No need to read it in. | |
116 ResponseCompleted(); | |
117 return; | |
118 } | |
119 | |
120 bool defer = false; | |
121 throttle_->WillProcessResponse(&defer); | |
122 DCHECK(!defer); | |
123 | |
124 if (request_->status().is_success()) { | |
125 StartReading(false); // Read the first chunk. | |
126 } else { | |
127 ResponseCompleted(); | |
128 } | |
129 } | |
130 | |
131 void AsyncRevalidationDriver::OnReadCompleted(net::URLRequest* unused, | |
132 int bytes_read) { | |
133 DCHECK_EQ(request_.get(), unused); | |
134 DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\"" | |
135 << " bytes_read = " << bytes_read; | |
136 | |
137 // bytes_read == -1 always implies an error. | |
138 if (bytes_read == -1 || !request_->status().is_success()) { | |
139 ResponseCompleted(); | |
140 return; | |
141 } | |
142 | |
143 DCHECK_GE(bytes_read, 0); | |
144 DCHECK(request_->status().is_success()); | |
145 DCHECK(!is_deferred_); | |
146 | |
147 if (bytes_read > 0) { | |
148 StartReading(true); // Read the next chunk. | |
149 } else { | |
150 // URLRequest reported an EOF. | |
151 DCHECK_EQ(0, bytes_read); | |
kinuko
2015/11/19 07:00:28
nit: feels a bit verbose to me
Adam Rice
2015/11/19 21:13:52
I have made it less verbose. PTAL.
| |
152 ResponseCompleted(); | |
153 } | |
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::CompleteResponseStarted() { | |
kinuko
2015/11/19 07:00:28
Where is this used?
Adam Rice
2015/11/19 21:13:52
It's not. Thank you for checking. I moved the impl
| |
204 bool defer = false; | |
205 throttle_->WillProcessResponse(&defer); | |
206 DCHECK(!defer); | |
207 } | |
208 | |
209 void AsyncRevalidationDriver::StartReading(bool is_continuation) { | |
210 int bytes_read = 0; | |
211 ReadMore(&bytes_read); | |
212 | |
213 // If IO is pending, wait for the URLRequest to call OnReadCompleted. | |
214 if (request_->status().is_io_pending()) | |
215 return; | |
216 | |
217 if (!is_continuation || bytes_read <= 0) { | |
218 OnReadCompleted(request_.get(), bytes_read); | |
219 } else { | |
220 // Else, trigger OnReadCompleted asynchronously to avoid starving the IO | |
221 // thread in case the URLRequest can provide data synchronously. | |
222 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
223 FROM_HERE, | |
224 base::Bind(&AsyncRevalidationDriver::OnReadCompleted, | |
225 weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read)); | |
226 } | |
227 } | |
228 | |
229 void AsyncRevalidationDriver::ReadMore(int* bytes_read) { | |
230 DCHECK(!is_deferred_); | |
231 | |
232 if (!read_buffer_) | |
233 read_buffer_ = new net::IOBuffer(kReadBufSize); | |
234 | |
235 read_timer_.Reset(); | |
236 request_->Read(read_buffer_.get(), kReadBufSize, bytes_read); | |
237 | |
238 // No need to check the return value here as we'll detect errors by | |
239 // inspecting the URLRequest's status. | |
240 } | |
241 | |
242 void AsyncRevalidationDriver::ResponseCompleted() { | |
243 DVLOG(1) << "ResponseCompleted: " << request_->url().spec(); | |
244 // When this class cancels a redirect, URLRequest calls both the | |
245 // OnResponseStarted() and OnReadCompleted() callbacks. This class should not | |
246 // run |completion_callback_| twice. | |
247 // | |
248 // TODO(ricea): Work out why URLRequest calls both methods on cancellation and | |
249 // make it stop. | |
250 if (completion_callback_.is_null()) | |
251 return; | |
252 base::Closure completion_callback(completion_callback_); | |
253 completion_callback_.Reset(); | |
254 completion_callback.Run(); | |
255 } | |
256 | |
257 void AsyncRevalidationDriver::OnReadTimeout() { | |
258 RecordAction(base::UserMetricsAction("AsyncRevalidationTimeout")); | |
259 CancelRequestInternal(net::ERR_TIMED_OUT); | |
260 } | |
261 | |
262 void AsyncRevalidationDriver::RecordDefer() { | |
263 request_->LogBlockedBy(throttle_->GetNameForLogging()); | |
264 DCHECK(!is_deferred_); | |
265 is_deferred_ = true; | |
266 } | |
267 | |
268 } // namespace content | |
OLD | NEW |