OLD | NEW |
---|---|
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/http_stream_factory_impl_job_controller.h" | 5 #include "net/http/http_stream_factory_impl_job_controller.h" |
6 | 6 |
7 #include "base/metrics/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "base/values.h" | 10 #include "base/values.h" |
(...skipping 20 matching lines...) Expand all Loading... | |
31 HttpStreamFactoryImpl* factory, | 31 HttpStreamFactoryImpl* factory, |
32 HttpStreamRequest::Delegate* delegate, | 32 HttpStreamRequest::Delegate* delegate, |
33 HttpNetworkSession* session, | 33 HttpNetworkSession* session, |
34 JobFactory* job_factory) | 34 JobFactory* job_factory) |
35 : factory_(factory), | 35 : factory_(factory), |
36 session_(session), | 36 session_(session), |
37 job_factory_(job_factory), | 37 job_factory_(job_factory), |
38 request_(nullptr), | 38 request_(nullptr), |
39 delegate_(delegate), | 39 delegate_(delegate), |
40 is_preconnect_(false), | 40 is_preconnect_(false), |
41 alternative_service_is_broken_(false), | |
41 job_bound_(false), | 42 job_bound_(false), |
42 main_job_is_blocked_(false), | 43 main_job_is_blocked_(false), |
43 bound_job_(nullptr), | 44 bound_job_(nullptr), |
44 can_start_alternative_proxy_job_(false), | 45 can_start_alternative_proxy_job_(false), |
45 ptr_factory_(this) { | 46 ptr_factory_(this) { |
46 DCHECK(factory); | 47 DCHECK(factory); |
47 } | 48 } |
48 | 49 |
49 HttpStreamFactoryImpl::JobController::~JobController() { | 50 HttpStreamFactoryImpl::JobController::~JobController() { |
50 main_job_.reset(); | 51 main_job_.reset(); |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
158 if (alternative_job_) { | 159 if (alternative_job_) { |
159 alternative_job_->SetPriority(priority); | 160 alternative_job_->SetPriority(priority); |
160 } | 161 } |
161 } | 162 } |
162 | 163 |
163 void HttpStreamFactoryImpl::JobController::OnStreamReady( | 164 void HttpStreamFactoryImpl::JobController::OnStreamReady( |
164 Job* job, | 165 Job* job, |
165 const SSLConfig& used_ssl_config, | 166 const SSLConfig& used_ssl_config, |
166 const ProxyInfo& used_proxy_info) { | 167 const ProxyInfo& used_proxy_info) { |
167 DCHECK(job); | 168 DCHECK(job); |
169 MaybeReportAlternativeServiceBroken(job); | |
168 | 170 |
169 if (job_bound_ && bound_job_ != job) { | 171 if (job_bound_ && bound_job_ != job) { |
170 // We have bound a job to the associated Request, |job| has been orphaned. | 172 // We have bound a job to the associated Request, |job| has been orphaned. |
171 OnOrphanedJobComplete(job); | 173 OnOrphanedJobComplete(job); |
172 return; | 174 return; |
173 } | 175 } |
174 std::unique_ptr<HttpStream> stream = job->ReleaseStream(); | 176 std::unique_ptr<HttpStream> stream = job->ReleaseStream(); |
175 DCHECK(stream); | 177 DCHECK(stream); |
176 | 178 |
177 MarkRequestComplete(job->was_npn_negotiated(), job->negotiated_protocol(), | 179 MarkRequestComplete(job->was_npn_negotiated(), job->negotiated_protocol(), |
178 job->using_spdy()); | 180 job->using_spdy()); |
179 | 181 |
180 if (!request_) | 182 if (!request_) |
181 return; | 183 return; |
182 DCHECK(!factory_->for_websockets_); | 184 DCHECK(!factory_->for_websockets_); |
183 DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type()); | 185 DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type()); |
184 OnJobSucceeded(job); | 186 OnJobSucceeded(job); |
185 request_->OnStreamReady(used_ssl_config, used_proxy_info, stream.release()); | 187 request_->OnStreamReady(used_ssl_config, used_proxy_info, stream.release()); |
186 } | 188 } |
187 | 189 |
188 void HttpStreamFactoryImpl::JobController::OnBidirectionalStreamImplReady( | 190 void HttpStreamFactoryImpl::JobController::OnBidirectionalStreamImplReady( |
189 Job* job, | 191 Job* job, |
190 const SSLConfig& used_ssl_config, | 192 const SSLConfig& used_ssl_config, |
191 const ProxyInfo& used_proxy_info) { | 193 const ProxyInfo& used_proxy_info) { |
192 DCHECK(job); | 194 DCHECK(job); |
195 MaybeReportAlternativeServiceBroken(job); | |
193 | 196 |
194 if (job_bound_ && bound_job_ != job) { | 197 if (job_bound_ && bound_job_ != job) { |
195 // We have bound a job to the associated Request, |job| has been orphaned. | 198 // We have bound a job to the associated Request, |job| has been orphaned. |
196 OnOrphanedJobComplete(job); | 199 OnOrphanedJobComplete(job); |
197 return; | 200 return; |
198 } | 201 } |
199 | 202 |
200 MarkRequestComplete(job->was_npn_negotiated(), job->negotiated_protocol(), | 203 MarkRequestComplete(job->was_npn_negotiated(), job->negotiated_protocol(), |
201 job->using_spdy()); | 204 job->using_spdy()); |
202 | 205 |
203 if (!request_) | 206 if (!request_) |
204 return; | 207 return; |
205 std::unique_ptr<BidirectionalStreamImpl> stream = | 208 std::unique_ptr<BidirectionalStreamImpl> stream = |
206 job->ReleaseBidirectionalStream(); | 209 job->ReleaseBidirectionalStream(); |
207 DCHECK(stream); | 210 DCHECK(stream); |
208 DCHECK(!factory_->for_websockets_); | 211 DCHECK(!factory_->for_websockets_); |
209 DCHECK_EQ(HttpStreamRequest::BIDIRECTIONAL_STREAM, request_->stream_type()); | 212 DCHECK_EQ(HttpStreamRequest::BIDIRECTIONAL_STREAM, request_->stream_type()); |
210 | 213 |
211 OnJobSucceeded(job); | 214 OnJobSucceeded(job); |
212 request_->OnBidirectionalStreamImplReady(used_ssl_config, used_proxy_info, | 215 request_->OnBidirectionalStreamImplReady(used_ssl_config, used_proxy_info, |
213 stream.release()); | 216 stream.release()); |
214 } | 217 } |
215 | 218 |
216 void HttpStreamFactoryImpl::JobController::OnWebSocketHandshakeStreamReady( | 219 void HttpStreamFactoryImpl::JobController::OnWebSocketHandshakeStreamReady( |
217 Job* job, | 220 Job* job, |
218 const SSLConfig& used_ssl_config, | 221 const SSLConfig& used_ssl_config, |
219 const ProxyInfo& used_proxy_info, | 222 const ProxyInfo& used_proxy_info, |
220 WebSocketHandshakeStreamBase* stream) { | 223 WebSocketHandshakeStreamBase* stream) { |
221 DCHECK(job); | 224 DCHECK(job); |
225 MaybeReportAlternativeServiceBroken(job); | |
222 | 226 |
223 MarkRequestComplete(job->was_npn_negotiated(), job->negotiated_protocol(), | 227 MarkRequestComplete(job->was_npn_negotiated(), job->negotiated_protocol(), |
224 job->using_spdy()); | 228 job->using_spdy()); |
225 | 229 |
226 if (!request_) | 230 if (!request_) |
227 return; | 231 return; |
228 DCHECK(factory_->for_websockets_); | 232 DCHECK(factory_->for_websockets_); |
229 DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type()); | 233 DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type()); |
230 DCHECK(stream); | 234 DCHECK(stream); |
231 | 235 |
(...skipping 17 matching lines...) Expand all Loading... | |
249 if (!request_) | 253 if (!request_) |
250 return; | 254 return; |
251 DCHECK_NE(OK, status); | 255 DCHECK_NE(OK, status); |
252 DCHECK(job); | 256 DCHECK(job); |
253 | 257 |
254 if (!bound_job_) { | 258 if (!bound_job_) { |
255 if (main_job_ && alternative_job_) { | 259 if (main_job_ && alternative_job_) { |
256 // Hey, we've got other jobs! Maybe one of them will succeed, let's just | 260 // Hey, we've got other jobs! Maybe one of them will succeed, let's just |
257 // ignore this failure. | 261 // ignore this failure. |
258 factory_->request_map_.erase(job); | 262 factory_->request_map_.erase(job); |
259 // Notify all the other jobs that this one failed. | |
260 if (job->job_type() == MAIN) { | 263 if (job->job_type() == MAIN) { |
261 alternative_job_->MarkOtherJobComplete(*job); | |
262 main_job_.reset(); | 264 main_job_.reset(); |
263 } else { | 265 } else { |
264 DCHECK(job->job_type() == ALTERNATIVE); | 266 DCHECK(job->job_type() == ALTERNATIVE); |
265 main_job_->MarkOtherJobComplete(*job); | |
266 alternative_job_.reset(); | 267 alternative_job_.reset(); |
267 } | 268 } |
268 return; | 269 return; |
269 } else { | 270 } else { |
270 BindJob(job); | 271 BindJob(job); |
271 } | 272 } |
272 } | 273 } |
273 | 274 |
274 request_->OnStreamFailed(status, used_ssl_config); | 275 request_->OnStreamFailed(status, used_ssl_config); |
275 } | 276 } |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
397 base::Unretained(alternative_job_.get()), | 398 base::Unretained(alternative_job_.get()), |
398 request_->stream_type())); | 399 request_->stream_type())); |
399 } | 400 } |
400 | 401 |
401 void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady( | 402 void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady( |
402 Job* job, | 403 Job* job, |
403 const base::WeakPtr<SpdySession>& spdy_session, | 404 const base::WeakPtr<SpdySession>& spdy_session, |
404 bool direct) { | 405 bool direct) { |
405 DCHECK(job); | 406 DCHECK(job); |
406 DCHECK(job->using_spdy()); | 407 DCHECK(job->using_spdy()); |
408 MaybeReportAlternativeServiceBroken(job); | |
407 | 409 |
408 bool is_job_orphaned = job_bound_ && bound_job_ != job; | 410 bool is_job_orphaned = job_bound_ && bound_job_ != job; |
409 | 411 |
410 // Cache these values in case the job gets deleted. | 412 // Cache these values in case the job gets deleted. |
411 const SSLConfig used_ssl_config = job->server_ssl_config(); | 413 const SSLConfig used_ssl_config = job->server_ssl_config(); |
412 const ProxyInfo used_proxy_info = job->proxy_info(); | 414 const ProxyInfo used_proxy_info = job->proxy_info(); |
413 const bool was_npn_negotiated = job->was_npn_negotiated(); | 415 const bool was_npn_negotiated = job->was_npn_negotiated(); |
414 const NextProto negotiated_protocol = job->negotiated_protocol(); | 416 const NextProto negotiated_protocol = job->negotiated_protocol(); |
415 const bool using_spdy = job->using_spdy(); | 417 const bool using_spdy = job->using_spdy(); |
416 const BoundNetLog net_log = job->net_log(); | 418 const BoundNetLog net_log = job->net_log(); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
497 base::Bind(&NetLogHttpStreamJobDelayCallback, main_job_wait_time_)); | 499 base::Bind(&NetLogHttpStreamJobDelayCallback, main_job_wait_time_)); |
498 | 500 |
499 main_job_->Resume(); | 501 main_job_->Resume(); |
500 main_job_wait_time_ = base::TimeDelta(); | 502 main_job_wait_time_ = base::TimeDelta(); |
501 } | 503 } |
502 | 504 |
503 void HttpStreamFactoryImpl::JobController::MaybeResumeMainJob( | 505 void HttpStreamFactoryImpl::JobController::MaybeResumeMainJob( |
504 Job* job, | 506 Job* job, |
505 const base::TimeDelta& delay) { | 507 const base::TimeDelta& delay) { |
506 DCHECK(job == main_job_.get() || job == alternative_job_.get()); | 508 DCHECK(job == main_job_.get() || job == alternative_job_.get()); |
509 if (job == alternative_job_.get()) | |
510 MaybeMarkAlternativeServiceBroken(job); | |
511 | |
507 if (!main_job_is_blocked_ || job != alternative_job_.get() || !main_job_) | 512 if (!main_job_is_blocked_ || job != alternative_job_.get() || !main_job_) |
508 return; | 513 return; |
509 | 514 |
510 main_job_is_blocked_ = false; | 515 main_job_is_blocked_ = false; |
511 | 516 |
512 if (!main_job_->is_waiting()) | 517 if (!main_job_->is_waiting()) |
513 return; | 518 return; |
514 | 519 |
515 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 520 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
516 FROM_HERE, | 521 FROM_HERE, |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
725 // another Job completes first. | 730 // another Job completes first. |
726 // TODO(mbelshe): Revisit this when we implement ip connection pooling of | 731 // TODO(mbelshe): Revisit this when we implement ip connection pooling of |
727 // SpdySessions. Do we want to orphan the jobs for a different hostname so | 732 // SpdySessions. Do we want to orphan the jobs for a different hostname so |
728 // they complete? Or do we want to prevent connecting a new SpdySession if | 733 // they complete? Or do we want to prevent connecting a new SpdySession if |
729 // we've already got one available for a different hostname where the ip | 734 // we've already got one available for a different hostname where the ip |
730 // address matches up? | 735 // address matches up? |
731 CancelJobs(); | 736 CancelJobs(); |
732 return; | 737 return; |
733 } | 738 } |
734 if (!bound_job_) { | 739 if (!bound_job_) { |
735 if (main_job_ && alternative_job_) { | 740 if (main_job_ && alternative_job_) |
736 job->ReportJobSucceededForRequest(); | 741 job->ReportJobSucceededForRequest(); |
737 // Notify all the other jobs that this one succeeded. | |
738 if (job->job_type() == MAIN) { | |
739 alternative_job_->MarkOtherJobComplete(*job); | |
740 } else { | |
741 DCHECK(job->job_type() == ALTERNATIVE); | |
742 main_job_->MarkOtherJobComplete(*job); | |
743 } | |
744 } | |
745 BindJob(job); | 742 BindJob(job); |
746 return; | 743 return; |
747 } | 744 } |
748 DCHECK(bound_job_); | 745 DCHECK(bound_job_); |
749 } | 746 } |
750 | 747 |
751 void HttpStreamFactoryImpl::JobController::MarkRequestComplete( | 748 void HttpStreamFactoryImpl::JobController::MarkRequestComplete( |
752 bool was_npn_negotiated, | 749 bool was_npn_negotiated, |
753 NextProto negotiated_protocol, | 750 NextProto negotiated_protocol, |
754 bool using_spdy) { | 751 bool using_spdy) { |
755 if (request_) | 752 if (request_) |
756 request_->Complete(was_npn_negotiated, negotiated_protocol, using_spdy); | 753 request_->Complete(was_npn_negotiated, negotiated_protocol, using_spdy); |
757 } | 754 } |
758 | 755 |
756 void HttpStreamFactoryImpl::JobController::MaybeMarkAlternativeServiceBroken( | |
757 Job* job) { | |
758 if (job->job_type() == MAIN || !job->alternative_broken()) | |
759 return; | |
760 | |
761 alternative_service_is_broken_ = true; | |
762 if (job->alternative_proxy_server().is_valid()) { | |
763 broken_alternative_proxy_server_ = job->alternative_proxy_server(); | |
764 } else { | |
765 DCHECK(!broken_alternative_proxy_server_.is_valid()); | |
766 broken_alternative_service_ = job->alternative_service(); | |
767 } | |
768 } | |
769 | |
770 void HttpStreamFactoryImpl::JobController::MaybeReportAlternativeServiceBroken( | |
771 Job* job) { | |
772 // Only report QUIC broken alternative service when main job succeeds. | |
773 if (job->job_type() == ALTERNATIVE) | |
774 return; | |
Ryan Hamilton
2016/09/13 23:23:15
As discussed offline, I think we need to make sure
| |
775 | |
776 if (!alternative_service_is_broken_) | |
777 return; | |
778 | |
779 if (broken_alternative_proxy_server_.is_valid()) { | |
780 ProxyDelegate* proxy_delegate = session_->params().proxy_delegate; | |
781 if (proxy_delegate) | |
782 proxy_delegate->OnAlternativeProxyBroken( | |
783 broken_alternative_proxy_server_); | |
784 } else { | |
785 HistogramBrokenAlternateProtocolLocation( | |
786 BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB_ALT); | |
787 session_->http_server_properties()->MarkAlternativeServiceBroken( | |
788 broken_alternative_service_); | |
789 } | |
790 session_->quic_stream_factory()->OnTcpJobCompleted(true); | |
791 } | |
792 | |
759 void HttpStreamFactoryImpl::JobController::MaybeNotifyFactoryOfCompletion() { | 793 void HttpStreamFactoryImpl::JobController::MaybeNotifyFactoryOfCompletion() { |
760 if (!request_ && !main_job_ && !alternative_job_) { | 794 if (!request_ && !main_job_ && !alternative_job_) { |
761 DCHECK(!bound_job_); | 795 DCHECK(!bound_job_); |
762 factory_->OnJobControllerComplete(this); | 796 factory_->OnJobControllerComplete(this); |
763 } | 797 } |
764 } | 798 } |
765 | 799 |
766 GURL HttpStreamFactoryImpl::JobController::ApplyHostMappingRules( | 800 GURL HttpStreamFactoryImpl::JobController::ApplyHostMappingRules( |
767 const GURL& url, | 801 const GURL& url, |
768 HostPortPair* endpoint) { | 802 HostPortPair* endpoint) { |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1003 if (!session_->params().enable_quic || | 1037 if (!session_->params().enable_quic || |
1004 session_->quic_stream_factory()->IsQuicDisabled( | 1038 session_->quic_stream_factory()->IsQuicDisabled( |
1005 alternative_proxy_server->host_port_pair().port())) { | 1039 alternative_proxy_server->host_port_pair().port())) { |
1006 return false; | 1040 return false; |
1007 } | 1041 } |
1008 } | 1042 } |
1009 | 1043 |
1010 return true; | 1044 return true; |
1011 } | 1045 } |
1012 } | 1046 } |
OLD | NEW |