OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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.h" | 5 #include "net/http/http_stream_factory_impl.h" |
6 | 6 |
| 7 #include "base/string_number_conversions.h" |
7 #include "base/stl_util-inl.h" | 8 #include "base/stl_util-inl.h" |
8 #include "googleurl/src/gurl.h" | 9 #include "googleurl/src/gurl.h" |
9 #include "net/base/net_log.h" | 10 #include "net/base/net_log.h" |
10 #include "net/base/net_util.h" | 11 #include "net/base/net_util.h" |
11 #include "net/http/http_network_session.h" | 12 #include "net/http/http_network_session.h" |
12 #include "net/http/http_stream_factory_impl_job.h" | 13 #include "net/http/http_stream_factory_impl_job.h" |
13 #include "net/http/http_stream_factory_impl_request.h" | 14 #include "net/http/http_stream_factory_impl_request.h" |
14 #include "net/spdy/spdy_http_stream.h" | 15 #include "net/spdy/spdy_http_stream.h" |
15 | 16 |
16 namespace net { | 17 namespace net { |
17 | 18 |
| 19 namespace { |
| 20 |
| 21 bool HasSpdyExclusion(const HostPortPair& endpoint) { |
| 22 std::list<HostPortPair>* exclusions = |
| 23 HttpStreamFactory::forced_spdy_exclusions(); |
| 24 if (!exclusions) |
| 25 return false; |
| 26 |
| 27 std::list<HostPortPair>::const_iterator it; |
| 28 for (it = exclusions->begin(); it != exclusions->end(); it++) |
| 29 if (it->Equals(endpoint)) |
| 30 return true; |
| 31 return false; |
| 32 } |
| 33 |
| 34 GURL UpgradeUrlToHttps(const GURL& original_url) { |
| 35 GURL::Replacements replacements; |
| 36 // new_sheme and new_port need to be in scope here because GURL::Replacements |
| 37 // references the memory contained by them directly. |
| 38 const std::string new_scheme = "https"; |
| 39 const std::string new_port = base::IntToString(443); |
| 40 replacements.SetSchemeStr(new_scheme); |
| 41 replacements.SetPortStr(new_port); |
| 42 return original_url.ReplaceComponents(replacements); |
| 43 } |
| 44 |
| 45 } // namespace |
| 46 |
18 HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session) | 47 HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session) |
19 : session_(session) {} | 48 : session_(session) {} |
20 | 49 |
21 HttpStreamFactoryImpl::~HttpStreamFactoryImpl() { | 50 HttpStreamFactoryImpl::~HttpStreamFactoryImpl() { |
22 DCHECK(request_map_.empty()); | 51 DCHECK(request_map_.empty()); |
23 DCHECK(spdy_session_request_map_.empty()); | 52 DCHECK(spdy_session_request_map_.empty()); |
24 | 53 |
25 std::set<const Job*> tmp_job_set; | 54 std::set<const Job*> tmp_job_set; |
| 55 tmp_job_set.swap(orphaned_job_set_); |
| 56 STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end()); |
| 57 DCHECK(orphaned_job_set_.empty()); |
| 58 |
| 59 tmp_job_set.clear(); |
26 tmp_job_set.swap(preconnect_job_set_); | 60 tmp_job_set.swap(preconnect_job_set_); |
27 STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end()); | 61 STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end()); |
28 DCHECK(preconnect_job_set_.empty()); | 62 DCHECK(preconnect_job_set_.empty()); |
29 } | 63 } |
30 | 64 |
31 HttpStreamRequest* HttpStreamFactoryImpl::RequestStream( | 65 HttpStreamRequest* HttpStreamFactoryImpl::RequestStream( |
32 const HttpRequestInfo& request_info, | 66 const HttpRequestInfo& request_info, |
33 const SSLConfig& ssl_config, | 67 const SSLConfig& ssl_config, |
34 HttpStreamRequest::Delegate* delegate, | 68 HttpStreamRequest::Delegate* delegate, |
35 const BoundNetLog& net_log) { | 69 const BoundNetLog& net_log) { |
36 Job* job = new Job(this, session_); | |
37 Request* request = new Request(request_info.url, this, delegate, net_log); | 70 Request* request = new Request(request_info.url, this, delegate, net_log); |
| 71 |
| 72 GURL alternate_url; |
| 73 bool has_alternate_protocol = |
| 74 GetAlternateProtocolRequestFor(request_info.url, &alternate_url); |
| 75 Job* alternate_job = NULL; |
| 76 if (has_alternate_protocol) { |
| 77 HttpRequestInfo alternate_request_info = request_info; |
| 78 alternate_request_info.url = alternate_url; |
| 79 alternate_job = |
| 80 new Job(this, session_, alternate_request_info, ssl_config, net_log); |
| 81 request->AttachJob(alternate_job); |
| 82 alternate_job->MarkAsAlternate(request_info.url); |
| 83 } |
| 84 |
| 85 Job* job = new Job(this, session_, request_info, ssl_config, net_log); |
38 request->AttachJob(job); | 86 request->AttachJob(job); |
39 job->Start(request, request_info, ssl_config, net_log); | 87 if (alternate_job) { |
| 88 job->WaitFor(alternate_job); |
| 89 // Make sure to wait until we call WaitFor(), before starting |
| 90 // |alternate_job|, otherwise |alternate_job| will not notify |job| |
| 91 // appropriately. |
| 92 alternate_job->Start(request); |
| 93 } |
| 94 // Even if |alternate_job| has already finished, it won't have notified the |
| 95 // request yet, since we defer that to the next iteration of the MessageLoop, |
| 96 // so starting |job| is always safe. |
| 97 job->Start(request); |
40 return request; | 98 return request; |
41 } | 99 } |
42 | 100 |
43 void HttpStreamFactoryImpl::PreconnectStreams( | 101 void HttpStreamFactoryImpl::PreconnectStreams( |
44 int num_streams, | 102 int num_streams, |
45 const HttpRequestInfo& request_info, | 103 const HttpRequestInfo& request_info, |
46 const SSLConfig& ssl_config, | 104 const SSLConfig& ssl_config, |
47 const BoundNetLog& net_log) { | 105 const BoundNetLog& net_log) { |
48 Job* job = new Job(this, session_); | 106 GURL alternate_url; |
| 107 bool has_alternate_protocol = |
| 108 GetAlternateProtocolRequestFor(request_info.url, &alternate_url); |
| 109 Job* job = NULL; |
| 110 if (has_alternate_protocol) { |
| 111 HttpRequestInfo alternate_request_info = request_info; |
| 112 alternate_request_info.url = alternate_url; |
| 113 job = new Job(this, session_, alternate_request_info, ssl_config, net_log); |
| 114 job->MarkAsAlternate(request_info.url); |
| 115 } else { |
| 116 job = new Job(this, session_, request_info, ssl_config, net_log); |
| 117 } |
49 preconnect_job_set_.insert(job); | 118 preconnect_job_set_.insert(job); |
50 job->Preconnect(num_streams, request_info, ssl_config, net_log); | 119 job->Preconnect(num_streams); |
51 } | 120 } |
52 | 121 |
53 void HttpStreamFactoryImpl::AddTLSIntolerantServer(const GURL& url) { | 122 void HttpStreamFactoryImpl::AddTLSIntolerantServer(const HostPortPair& server) { |
54 tls_intolerant_servers_.insert(GetHostAndPort(url)); | 123 tls_intolerant_servers_.insert(server); |
55 } | 124 } |
56 | 125 |
57 bool HttpStreamFactoryImpl::IsTLSIntolerantServer(const GURL& url) const { | 126 bool HttpStreamFactoryImpl::IsTLSIntolerantServer( |
58 return ContainsKey(tls_intolerant_servers_, GetHostAndPort(url)); | 127 const HostPortPair& server) const { |
| 128 return ContainsKey(tls_intolerant_servers_, server); |
| 129 } |
| 130 |
| 131 bool HttpStreamFactoryImpl::GetAlternateProtocolRequestFor( |
| 132 const GURL& original_url, |
| 133 GURL* alternate_url) const { |
| 134 if (!spdy_enabled()) |
| 135 return false; |
| 136 |
| 137 if (!use_alternate_protocols()) |
| 138 return false; |
| 139 |
| 140 HostPortPair origin = HostPortPair(original_url.HostNoBrackets(), |
| 141 original_url.EffectiveIntPort()); |
| 142 |
| 143 const HttpAlternateProtocols& alternate_protocols = |
| 144 session_->alternate_protocols(); |
| 145 if (!alternate_protocols.HasAlternateProtocolFor(origin)) |
| 146 return false; |
| 147 |
| 148 HttpAlternateProtocols::PortProtocolPair alternate = |
| 149 alternate_protocols.GetAlternateProtocolFor(origin); |
| 150 if (alternate.protocol == HttpAlternateProtocols::BROKEN) |
| 151 return false; |
| 152 |
| 153 DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol); |
| 154 DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS, |
| 155 alternate.protocol); |
| 156 |
| 157 if (alternate.protocol != HttpAlternateProtocols::NPN_SPDY_2) |
| 158 return false; |
| 159 |
| 160 origin.set_port(alternate.port); |
| 161 if (HasSpdyExclusion(origin)) |
| 162 return false; |
| 163 |
| 164 *alternate_url = UpgradeUrlToHttps(original_url); |
| 165 return true; |
59 } | 166 } |
60 | 167 |
61 void HttpStreamFactoryImpl::OrphanJob(Job* job, const Request* request) { | 168 void HttpStreamFactoryImpl::OrphanJob(Job* job, const Request* request) { |
62 DCHECK(ContainsKey(request_map_, job)); | 169 DCHECK(ContainsKey(request_map_, job)); |
63 DCHECK_EQ(request_map_[job], request); | 170 DCHECK_EQ(request_map_[job], request); |
64 DCHECK(!ContainsKey(orphaned_job_set_, job)); | 171 DCHECK(!ContainsKey(orphaned_job_set_, job)); |
65 | 172 |
66 request_map_.erase(job); | 173 request_map_.erase(job); |
67 | 174 |
68 orphaned_job_set_.insert(job); | 175 orphaned_job_set_.insert(job); |
69 job->Orphan(request); | 176 job->Orphan(request); |
70 } | 177 } |
71 | 178 |
72 void HttpStreamFactoryImpl::OnSpdySessionReady( | 179 void HttpStreamFactoryImpl::OnSpdySessionReady( |
73 scoped_refptr<SpdySession> spdy_session, | 180 scoped_refptr<SpdySession> spdy_session, |
74 bool direct, | 181 bool direct, |
75 const SSLConfig& used_ssl_config, | 182 const SSLConfig& used_ssl_config, |
76 const ProxyInfo& used_proxy_info, | 183 const ProxyInfo& used_proxy_info, |
77 bool was_alternate_protocol_available, | |
78 bool was_npn_negotiated, | 184 bool was_npn_negotiated, |
79 bool using_spdy, | 185 bool using_spdy, |
80 const NetLog::Source& source) { | 186 const NetLog::Source& source) { |
81 const HostPortProxyPair& spdy_session_key = | 187 const HostPortProxyPair& spdy_session_key = |
82 spdy_session->host_port_proxy_pair(); | 188 spdy_session->host_port_proxy_pair(); |
83 while (!spdy_session->IsClosed()) { | 189 while (!spdy_session->IsClosed()) { |
84 // Each iteration may empty out the RequestSet for |spdy_session_key_ in | 190 // Each iteration may empty out the RequestSet for |spdy_session_key_ in |
85 // |spdy_session_request_map_|. So each time, check for RequestSet and use | 191 // |spdy_session_request_map_|. So each time, check for RequestSet and use |
86 // the first one. | 192 // the first one. |
87 // | 193 // |
88 // TODO(willchan): If it's important, switch RequestSet out for a FIFO | 194 // TODO(willchan): If it's important, switch RequestSet out for a FIFO |
89 // pqueue (Order by priority first, then FIFO within same priority). Unclear | 195 // pqueue (Order by priority first, then FIFO within same priority). Unclear |
90 // that it matters here. | 196 // that it matters here. |
91 if (!ContainsKey(spdy_session_request_map_, spdy_session_key)) | 197 if (!ContainsKey(spdy_session_request_map_, spdy_session_key)) |
92 break; | 198 break; |
93 Request* request = *spdy_session_request_map_[spdy_session_key].begin(); | 199 Request* request = *spdy_session_request_map_[spdy_session_key].begin(); |
94 request->Complete(was_alternate_protocol_available, | 200 request->Complete(was_npn_negotiated, |
95 was_npn_negotiated, | |
96 using_spdy, | 201 using_spdy, |
97 source); | 202 source); |
98 bool use_relative_url = direct || request->url().SchemeIs("https"); | 203 bool use_relative_url = direct || request->url().SchemeIs("https"); |
99 request->OnStreamReady(NULL, used_ssl_config, used_proxy_info, | 204 request->OnStreamReady(NULL, used_ssl_config, used_proxy_info, |
100 new SpdyHttpStream(spdy_session, use_relative_url)); | 205 new SpdyHttpStream(spdy_session, use_relative_url)); |
101 } | 206 } |
102 // TODO(mbelshe): Alert other valid requests. | 207 // TODO(mbelshe): Alert other valid requests. |
103 } | 208 } |
104 | 209 |
105 void HttpStreamFactoryImpl::OnOrphanedJobComplete(const Job* job) { | 210 void HttpStreamFactoryImpl::OnOrphanedJobComplete(const Job* job) { |
106 orphaned_job_set_.erase(job); | 211 orphaned_job_set_.erase(job); |
107 delete job; | 212 delete job; |
108 } | 213 } |
109 | 214 |
110 void HttpStreamFactoryImpl::OnPreconnectsComplete(const Job* job) { | 215 void HttpStreamFactoryImpl::OnPreconnectsComplete(const Job* job) { |
111 preconnect_job_set_.erase(job); | 216 preconnect_job_set_.erase(job); |
112 delete job; | 217 delete job; |
113 OnPreconnectsCompleteInternal(); | 218 OnPreconnectsCompleteInternal(); |
114 } | 219 } |
115 | 220 |
116 } // namespace net | 221 } // namespace net |
OLD | NEW |