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 |
| 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 |