Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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_request.h" | 5 #include "net/http/http_stream_factory_impl_request.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/stl_util-inl.h" | 8 #include "base/stl_util-inl.h" |
| 9 #include "net/http/http_stream_factory_impl_job.h" | 9 #include "net/http/http_stream_factory_impl_job.h" |
| 10 #include "net/spdy/spdy_http_stream.h" | |
| 11 #include "net/spdy/spdy_session.h" | |
| 10 | 12 |
| 11 namespace net { | 13 namespace net { |
| 12 | 14 |
| 13 HttpStreamFactoryImpl::Request::Request(const GURL& url, | 15 HttpStreamFactoryImpl::Request::Request(const GURL& url, |
| 14 HttpStreamFactoryImpl* factory, | 16 HttpStreamFactoryImpl* factory, |
| 15 HttpStreamRequest::Delegate* delegate, | 17 HttpStreamRequest::Delegate* delegate, |
| 16 const BoundNetLog& net_log) | 18 const BoundNetLog& net_log) |
| 17 : url_(url), | 19 : url_(url), |
| 18 factory_(factory), | 20 factory_(factory), |
| 19 delegate_(delegate), | 21 delegate_(delegate), |
| 20 net_log_(net_log), | 22 net_log_(net_log), |
| 21 job_(NULL), | |
| 22 completed_(false), | 23 completed_(false), |
| 23 was_alternate_protocol_available_(false), | 24 was_alternate_protocol_available_(false), |
| 24 was_npn_negotiated_(false), | 25 was_npn_negotiated_(false), |
| 25 using_spdy_(false) { | 26 using_spdy_(false) { |
| 26 DCHECK(factory_); | 27 DCHECK(factory_); |
| 27 DCHECK(delegate_); | 28 DCHECK(delegate_); |
| 28 | 29 |
| 29 net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_REQUEST, NULL); | 30 net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_REQUEST, NULL); |
| 30 } | 31 } |
| 31 | 32 |
| 32 HttpStreamFactoryImpl::Request::~Request() { | 33 HttpStreamFactoryImpl::Request::~Request() { |
| 34 if (bound_job_.get()) | |
| 35 DCHECK(jobs_.empty()); | |
| 36 else | |
| 37 DCHECK(!jobs_.empty()); | |
| 38 | |
| 33 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_REQUEST, NULL); | 39 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_REQUEST, NULL); |
| 34 | 40 |
| 35 factory_->request_map_.erase(job_); | 41 for (std::set<Job*>::iterator it = jobs_.begin(); it != jobs_.end(); ++it) |
| 42 factory_->request_map_.erase(*it); | |
| 36 | 43 |
| 37 // TODO(willchan): Remove this when we decouple requests and jobs. | 44 STLDeleteElements(&jobs_); |
| 38 delete job_; | |
| 39 | 45 |
| 40 RemoveRequestFromSpdySessionRequestMap(); | 46 RemoveRequestFromSpdySessionRequestMap(); |
| 41 } | 47 } |
| 42 | 48 |
| 43 void HttpStreamFactoryImpl::Request::SetSpdySessionKey( | 49 void HttpStreamFactoryImpl::Request::SetSpdySessionKey( |
| 44 const HostPortProxyPair& spdy_session_key) { | 50 const HostPortProxyPair& spdy_session_key) { |
| 45 DCHECK(!spdy_session_key_.get()); | 51 DCHECK(!spdy_session_key_.get()); |
| 46 spdy_session_key_.reset(new HostPortProxyPair(spdy_session_key)); | 52 spdy_session_key_.reset(new HostPortProxyPair(spdy_session_key)); |
| 47 RequestSet& request_set = | 53 RequestSet& request_set = |
| 48 factory_->spdy_session_request_map_[spdy_session_key]; | 54 factory_->spdy_session_request_map_[spdy_session_key]; |
| 49 DCHECK(!ContainsKey(request_set, this)); | 55 DCHECK(!ContainsKey(request_set, this)); |
| 50 request_set.insert(this); | 56 request_set.insert(this); |
| 51 } | 57 } |
| 52 | 58 |
| 53 void HttpStreamFactoryImpl::Request::BindJob(HttpStreamFactoryImpl::Job* job) { | 59 void HttpStreamFactoryImpl::Request::AttachJob(Job* job) { |
| 54 DCHECK(job); | 60 DCHECK(job); |
| 55 DCHECK(!job_); | 61 jobs_.insert(job); |
| 56 job_ = job; | 62 factory_->request_map_[job] = this; |
| 57 } | 63 } |
| 58 | 64 |
| 59 void HttpStreamFactoryImpl::Request::Complete( | 65 void HttpStreamFactoryImpl::Request::Complete( |
| 60 bool was_alternate_protocol_available, | 66 bool was_alternate_protocol_available, |
| 61 bool was_npn_negotiated, | 67 bool was_npn_negotiated, |
| 62 bool using_spdy, | 68 bool using_spdy, |
| 63 const NetLog::Source& job_source) { | 69 const NetLog::Source& job_source) { |
| 64 DCHECK(!completed_); | 70 DCHECK(!completed_); |
| 65 completed_ = true; | 71 completed_ = true; |
| 66 was_alternate_protocol_available_ = was_alternate_protocol_available; | 72 was_alternate_protocol_available_ = was_alternate_protocol_available; |
| 67 was_npn_negotiated_ = was_npn_negotiated; | 73 was_npn_negotiated_ = was_npn_negotiated; |
| 68 using_spdy_ = using_spdy; | 74 using_spdy_ = using_spdy; |
| 69 net_log_.AddEvent( | 75 net_log_.AddEvent( |
| 70 NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_JOB, | 76 NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_JOB, |
| 71 make_scoped_refptr(new NetLogSourceParameter( | 77 make_scoped_refptr(new NetLogSourceParameter( |
| 72 "source_dependency", job_source))); | 78 "source_dependency", job_source))); |
| 73 } | 79 } |
| 74 | 80 |
| 75 void HttpStreamFactoryImpl::Request::OnStreamReady( | 81 void HttpStreamFactoryImpl::Request::OnStreamReady( |
| 82 Job* job, | |
| 76 const SSLConfig& used_ssl_config, | 83 const SSLConfig& used_ssl_config, |
| 77 const ProxyInfo& used_proxy_info, | 84 const ProxyInfo& used_proxy_info, |
| 78 HttpStream* stream) { | 85 HttpStream* stream) { |
| 79 DCHECK(stream); | 86 DCHECK(stream); |
| 80 DCHECK(completed_); | 87 DCHECK(completed_); |
| 88 | |
| 89 // |job| should only be NULL if we're being serviced by a late bound | |
| 90 // SpdySession (one that was not created by a job in our |jobs_| set). | |
| 91 if (!job) { | |
| 92 DCHECK(!bound_job_.get()); | |
| 93 DCHECK(!jobs_.empty()); | |
| 94 // NOTE(willchan): We do *NOT* call OrphanJobs() here. The reason is because | |
| 95 // we *WANT* to cancel the unnecessary Jobs from other requests if another | |
| 96 // Job completes first. | |
| 97 // TODO(mbelshe): Revisit this when we implement ip connection pooling of | |
|
willchan no longer on Chromium
2011/03/01 00:22:42
Please chime in on this.
| |
| 98 // SpdySessions. Do we want to orphan the jobs for a different hostname so | |
| 99 // they complete? Or do we want to prevent connecting a new SpdySession if | |
| 100 // we've already got one available for a different hostname where the ip | |
| 101 // address matches up? | |
| 102 } else if (!bound_job_.get()) { | |
| 103 // We may have other jobs in |jobs_|. For example, if we start multiple jobs | |
| 104 // for Alternate-Protocol. | |
| 105 OrphanJobsExcept(job); | |
| 106 } else { | |
| 107 DCHECK(jobs_.empty()); | |
| 108 } | |
| 81 delegate_->OnStreamReady(used_ssl_config, used_proxy_info, stream); | 109 delegate_->OnStreamReady(used_ssl_config, used_proxy_info, stream); |
| 82 } | 110 } |
| 83 | 111 |
| 84 void HttpStreamFactoryImpl::Request::OnStreamFailed( | 112 void HttpStreamFactoryImpl::Request::OnStreamFailed( |
| 113 Job* job, | |
| 85 int status, | 114 int status, |
| 86 const SSLConfig& used_ssl_config) { | 115 const SSLConfig& used_ssl_config) { |
| 87 DCHECK_NE(OK, status); | 116 DCHECK_NE(OK, status); |
| 117 if (!bound_job_.get()) | |
| 118 OrphanJobsExcept(job); | |
| 119 else | |
| 120 DCHECK(jobs_.empty()); | |
| 88 delegate_->OnStreamFailed(status, used_ssl_config); | 121 delegate_->OnStreamFailed(status, used_ssl_config); |
| 89 } | 122 } |
| 90 | 123 |
| 91 void HttpStreamFactoryImpl::Request::OnCertificateError( | 124 void HttpStreamFactoryImpl::Request::OnCertificateError( |
| 125 Job* job, | |
| 92 int status, | 126 int status, |
| 93 const SSLConfig& used_ssl_config, | 127 const SSLConfig& used_ssl_config, |
| 94 const SSLInfo& ssl_info) { | 128 const SSLInfo& ssl_info) { |
| 95 DCHECK_NE(OK, status); | 129 DCHECK_NE(OK, status); |
| 130 if (!bound_job_.get()) | |
| 131 OrphanJobsExcept(job); | |
| 132 else | |
| 133 DCHECK(jobs_.empty()); | |
| 96 delegate_->OnCertificateError(status, used_ssl_config, ssl_info); | 134 delegate_->OnCertificateError(status, used_ssl_config, ssl_info); |
| 97 } | 135 } |
| 98 | 136 |
| 99 void HttpStreamFactoryImpl::Request::OnNeedsProxyAuth( | 137 void HttpStreamFactoryImpl::Request::OnNeedsProxyAuth( |
| 138 Job* job, | |
| 100 const HttpResponseInfo& proxy_response, | 139 const HttpResponseInfo& proxy_response, |
| 101 const SSLConfig& used_ssl_config, | 140 const SSLConfig& used_ssl_config, |
| 102 const ProxyInfo& used_proxy_info, | 141 const ProxyInfo& used_proxy_info, |
| 103 HttpAuthController* auth_controller) { | 142 HttpAuthController* auth_controller) { |
| 143 if (!bound_job_.get()) | |
| 144 OrphanJobsExcept(job); | |
| 145 else | |
| 146 DCHECK(jobs_.empty()); | |
| 104 delegate_->OnNeedsProxyAuth( | 147 delegate_->OnNeedsProxyAuth( |
| 105 proxy_response, used_ssl_config, used_proxy_info, auth_controller); | 148 proxy_response, used_ssl_config, used_proxy_info, auth_controller); |
| 106 } | 149 } |
| 107 | 150 |
| 108 void HttpStreamFactoryImpl::Request::OnNeedsClientAuth( | 151 void HttpStreamFactoryImpl::Request::OnNeedsClientAuth( |
| 152 Job* job, | |
| 109 const SSLConfig& used_ssl_config, | 153 const SSLConfig& used_ssl_config, |
| 110 SSLCertRequestInfo* cert_info) { | 154 SSLCertRequestInfo* cert_info) { |
| 155 if (!bound_job_.get()) | |
| 156 OrphanJobsExcept(job); | |
| 157 else | |
| 158 DCHECK(jobs_.empty()); | |
| 111 delegate_->OnNeedsClientAuth(used_ssl_config, cert_info); | 159 delegate_->OnNeedsClientAuth(used_ssl_config, cert_info); |
| 112 } | 160 } |
| 113 | 161 |
| 114 void HttpStreamFactoryImpl::Request::OnHttpsProxyTunnelResponse( | 162 void HttpStreamFactoryImpl::Request::OnHttpsProxyTunnelResponse( |
| 163 Job *job, | |
| 115 const HttpResponseInfo& response_info, | 164 const HttpResponseInfo& response_info, |
| 116 const SSLConfig& used_ssl_config, | 165 const SSLConfig& used_ssl_config, |
| 117 const ProxyInfo& used_proxy_info, | 166 const ProxyInfo& used_proxy_info, |
| 118 HttpStream* stream) { | 167 HttpStream* stream) { |
| 168 if (!bound_job_.get()) | |
| 169 OrphanJobsExcept(job); | |
| 170 else | |
| 171 DCHECK(jobs_.empty()); | |
| 119 delegate_->OnHttpsProxyTunnelResponse( | 172 delegate_->OnHttpsProxyTunnelResponse( |
| 120 response_info, used_ssl_config, used_proxy_info, stream); | 173 response_info, used_ssl_config, used_proxy_info, stream); |
| 121 } | 174 } |
| 122 | 175 |
| 123 int HttpStreamFactoryImpl::Request::RestartTunnelWithProxyAuth( | 176 int HttpStreamFactoryImpl::Request::RestartTunnelWithProxyAuth( |
| 124 const string16& username, | 177 const string16& username, |
| 125 const string16& password) { | 178 const string16& password) { |
| 126 // We're restarting the job, so ditch the old key. Note that we could actually | 179 DCHECK(bound_job_.get()); |
| 127 // keep it around and eliminate the DCHECK in set_spdy_session_key() that | 180 return bound_job_->RestartTunnelWithProxyAuth(username, password); |
| 128 // |spdy_session_key_| is NULL, but I prefer to keep the assertion. | |
| 129 RemoveRequestFromSpdySessionRequestMap(); | |
| 130 return job_->RestartTunnelWithProxyAuth(username, password); | |
| 131 } | 181 } |
| 132 | 182 |
| 133 LoadState HttpStreamFactoryImpl::Request::GetLoadState() const { | 183 LoadState HttpStreamFactoryImpl::Request::GetLoadState() const { |
| 134 return factory_->GetLoadState(*this); | 184 if (bound_job_.get()) |
| 185 return bound_job_->GetLoadState(); | |
| 186 DCHECK(!jobs_.empty()); | |
| 187 | |
| 188 // Just pick the first one. | |
| 189 return (*jobs_.begin())->GetLoadState(); | |
| 135 } | 190 } |
| 136 | 191 |
| 137 bool HttpStreamFactoryImpl::Request::was_alternate_protocol_available() const { | 192 bool HttpStreamFactoryImpl::Request::was_alternate_protocol_available() const { |
| 138 DCHECK(completed_); | 193 DCHECK(completed_); |
| 139 return was_alternate_protocol_available_; | 194 return was_alternate_protocol_available_; |
| 140 } | 195 } |
| 141 | 196 |
| 142 bool HttpStreamFactoryImpl::Request::was_npn_negotiated() const { | 197 bool HttpStreamFactoryImpl::Request::was_npn_negotiated() const { |
| 143 DCHECK(completed_); | 198 DCHECK(completed_); |
| 144 return was_npn_negotiated_; | 199 return was_npn_negotiated_; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 158 RequestSet& request_set = | 213 RequestSet& request_set = |
| 159 spdy_session_request_map[*spdy_session_key_]; | 214 spdy_session_request_map[*spdy_session_key_]; |
| 160 DCHECK(ContainsKey(request_set, this)); | 215 DCHECK(ContainsKey(request_set, this)); |
| 161 request_set.erase(this); | 216 request_set.erase(this); |
| 162 if (request_set.empty()) | 217 if (request_set.empty()) |
| 163 spdy_session_request_map.erase(*spdy_session_key_); | 218 spdy_session_request_map.erase(*spdy_session_key_); |
| 164 spdy_session_key_.reset(); | 219 spdy_session_key_.reset(); |
| 165 } | 220 } |
| 166 } | 221 } |
| 167 | 222 |
| 223 void HttpStreamFactoryImpl::Request::OnSpdySessionReady( | |
| 224 Job* job, | |
| 225 scoped_refptr<SpdySession> spdy_session, | |
| 226 bool direct) { | |
| 227 DCHECK(job); | |
| 228 DCHECK(job->using_spdy()); | |
| 229 | |
| 230 // The first case is the usual case. | |
| 231 if (!bound_job_.get()) { | |
| 232 OrphanJobsExcept(job); | |
| 233 } else { // This is the case for HTTPS proxy tunneling. | |
| 234 DCHECK_EQ(bound_job_.get(), job); | |
| 235 DCHECK(jobs_.empty()); | |
| 236 } | |
| 237 | |
| 238 // Cache these values in case the job gets deleted. | |
| 239 const SSLConfig used_ssl_config = job->ssl_config(); | |
| 240 const ProxyInfo used_proxy_info = job->proxy_info(); | |
| 241 const bool was_alternate_protocol_available = | |
| 242 job->was_alternate_protocol_available(); | |
| 243 const bool was_npn_negotiated = job->was_npn_negotiated(); | |
| 244 const bool using_spdy = job->using_spdy(); | |
| 245 const NetLog::Source source = job->net_log().source(); | |
| 246 | |
| 247 Complete(was_alternate_protocol_available, | |
| 248 was_npn_negotiated, | |
| 249 using_spdy, | |
| 250 source); | |
| 251 | |
| 252 // Cache this so we can still use it if the request is deleted. | |
| 253 HttpStreamFactoryImpl* factory = factory_; | |
| 254 | |
| 255 bool use_relative_url = direct || url().SchemeIs("https"); | |
| 256 delegate_->OnStreamReady( | |
| 257 job->ssl_config(), | |
| 258 job->proxy_info(), | |
| 259 new SpdyHttpStream(spdy_session, use_relative_url)); | |
| 260 // |this| may be deleted after this point. | |
| 261 factory->OnSpdySessionReady( | |
| 262 spdy_session, direct, used_ssl_config, used_proxy_info, | |
| 263 was_alternate_protocol_available, was_npn_negotiated, using_spdy, source); | |
| 264 } | |
| 265 | |
| 266 void HttpStreamFactoryImpl::Request::OrphanJobsExcept(Job* job) { | |
| 267 DCHECK(job); | |
| 268 DCHECK(!bound_job_.get()); | |
| 269 DCHECK(ContainsKey(jobs_, job)); | |
| 270 bound_job_.reset(job); | |
| 271 jobs_.erase(job); | |
| 272 factory_->request_map_.erase(job); | |
| 273 | |
| 274 OrphanJobs(); | |
| 275 } | |
| 276 | |
| 277 void HttpStreamFactoryImpl::Request::OrphanJobs() { | |
| 278 RemoveRequestFromSpdySessionRequestMap(); | |
| 279 | |
| 280 std::set<Job*> tmp; | |
| 281 tmp.swap(jobs_); | |
| 282 | |
| 283 for (std::set<Job*>::iterator it = tmp.begin(); it != tmp.end(); ++it) | |
| 284 factory_->OrphanJob(*it, this); | |
| 285 } | |
| 286 | |
| 168 } // namespace net | 287 } // namespace net |
| OLD | NEW |