ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / net / http / http_stream_factory_impl.cc
blob235122d2e834ae363f77203bc88277c5ad2c96e5
1 // Copyright (c) 2012 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.
5 #include "net/http/http_stream_factory_impl.h"
7 #include <string>
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "net/base/net_log.h"
13 #include "net/base/net_util.h"
14 #include "net/http/http_network_session.h"
15 #include "net/http/http_server_properties.h"
16 #include "net/http/http_stream_factory_impl_job.h"
17 #include "net/http/http_stream_factory_impl_request.h"
18 #include "net/spdy/spdy_http_stream.h"
19 #include "url/gurl.h"
21 namespace net {
23 namespace {
25 GURL UpgradeUrlToHttps(const GURL& original_url, int port) {
26 GURL::Replacements replacements;
27 // new_port needs to be in scope here because GURL::Replacements references
28 // the memory contained by it directly.
29 const std::string new_port = base::IntToString(port);
30 replacements.SetSchemeStr("https");
31 replacements.SetPortStr(new_port);
32 return original_url.ReplaceComponents(replacements);
35 } // namespace
37 HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session,
38 bool for_websockets)
39 : session_(session),
40 for_websockets_(for_websockets) {}
42 HttpStreamFactoryImpl::~HttpStreamFactoryImpl() {
43 DCHECK(request_map_.empty());
44 DCHECK(spdy_session_request_map_.empty());
46 std::set<const Job*> tmp_job_set;
47 tmp_job_set.swap(orphaned_job_set_);
48 STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end());
49 DCHECK(orphaned_job_set_.empty());
51 tmp_job_set.clear();
52 tmp_job_set.swap(preconnect_job_set_);
53 STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end());
54 DCHECK(preconnect_job_set_.empty());
57 HttpStreamRequest* HttpStreamFactoryImpl::RequestStream(
58 const HttpRequestInfo& request_info,
59 RequestPriority priority,
60 const SSLConfig& server_ssl_config,
61 const SSLConfig& proxy_ssl_config,
62 HttpStreamRequest::Delegate* delegate,
63 const BoundNetLog& net_log) {
64 DCHECK(!for_websockets_);
65 return RequestStreamInternal(request_info,
66 priority,
67 server_ssl_config,
68 proxy_ssl_config,
69 delegate,
70 NULL,
71 net_log);
74 HttpStreamRequest* HttpStreamFactoryImpl::RequestWebSocketHandshakeStream(
75 const HttpRequestInfo& request_info,
76 RequestPriority priority,
77 const SSLConfig& server_ssl_config,
78 const SSLConfig& proxy_ssl_config,
79 HttpStreamRequest::Delegate* delegate,
80 WebSocketHandshakeStreamBase::CreateHelper* create_helper,
81 const BoundNetLog& net_log) {
82 DCHECK(for_websockets_);
83 DCHECK(create_helper);
84 return RequestStreamInternal(request_info,
85 priority,
86 server_ssl_config,
87 proxy_ssl_config,
88 delegate,
89 create_helper,
90 net_log);
93 HttpStreamRequest* HttpStreamFactoryImpl::RequestStreamInternal(
94 const HttpRequestInfo& request_info,
95 RequestPriority priority,
96 const SSLConfig& server_ssl_config,
97 const SSLConfig& proxy_ssl_config,
98 HttpStreamRequest::Delegate* delegate,
99 WebSocketHandshakeStreamBase::CreateHelper*
100 websocket_handshake_stream_create_helper,
101 const BoundNetLog& net_log) {
102 Request* request = new Request(request_info.url,
103 this,
104 delegate,
105 websocket_handshake_stream_create_helper,
106 net_log);
108 GURL alternate_url;
109 AlternateProtocolInfo alternate =
110 GetAlternateProtocolRequestFor(request_info.url, &alternate_url);
111 Job* alternate_job = NULL;
112 if (alternate.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL) {
113 // Never share connection with other jobs for FTP requests.
114 DCHECK(!request_info.url.SchemeIs("ftp"));
116 HttpRequestInfo alternate_request_info = request_info;
117 alternate_request_info.url = alternate_url;
118 alternate_job =
119 new Job(this, session_, alternate_request_info, priority,
120 server_ssl_config, proxy_ssl_config, net_log.net_log());
121 request->AttachJob(alternate_job);
122 alternate_job->MarkAsAlternate(request_info.url, alternate);
125 Job* job = new Job(this, session_, request_info, priority,
126 server_ssl_config, proxy_ssl_config, net_log.net_log());
127 request->AttachJob(job);
128 if (alternate_job) {
129 // Never share connection with other jobs for FTP requests.
130 DCHECK(!request_info.url.SchemeIs("ftp"));
132 job->WaitFor(alternate_job);
133 // Make sure to wait until we call WaitFor(), before starting
134 // |alternate_job|, otherwise |alternate_job| will not notify |job|
135 // appropriately.
136 alternate_job->Start(request);
138 // Even if |alternate_job| has already finished, it won't have notified the
139 // request yet, since we defer that to the next iteration of the MessageLoop,
140 // so starting |job| is always safe.
141 job->Start(request);
142 return request;
145 void HttpStreamFactoryImpl::PreconnectStreams(
146 int num_streams,
147 const HttpRequestInfo& request_info,
148 RequestPriority priority,
149 const SSLConfig& server_ssl_config,
150 const SSLConfig& proxy_ssl_config) {
151 DCHECK(!for_websockets_);
152 GURL alternate_url;
153 AlternateProtocolInfo alternate =
154 GetAlternateProtocolRequestFor(request_info.url, &alternate_url);
155 Job* job = NULL;
156 if (alternate.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL) {
157 HttpRequestInfo alternate_request_info = request_info;
158 alternate_request_info.url = alternate_url;
159 job = new Job(this, session_, alternate_request_info, priority,
160 server_ssl_config, proxy_ssl_config, session_->net_log());
161 job->MarkAsAlternate(request_info.url, alternate);
162 } else {
163 job = new Job(this, session_, request_info, priority,
164 server_ssl_config, proxy_ssl_config, session_->net_log());
166 preconnect_job_set_.insert(job);
167 job->Preconnect(num_streams);
170 const HostMappingRules* HttpStreamFactoryImpl::GetHostMappingRules() const {
171 return session_->params().host_mapping_rules;
174 AlternateProtocolInfo HttpStreamFactoryImpl::GetAlternateProtocolRequestFor(
175 const GURL& original_url,
176 GURL* alternate_url) {
177 const AlternateProtocolInfo kNoAlternateProtocol;
179 if (!session_->params().use_alternate_protocols)
180 return kNoAlternateProtocol;
182 if (original_url.SchemeIs("ftp"))
183 return kNoAlternateProtocol;
185 HostPortPair origin = HostPortPair::FromURL(original_url);
186 HttpServerProperties& http_server_properties =
187 *session_->http_server_properties();
188 const AlternateProtocolInfo alternate =
189 http_server_properties.GetAlternateProtocol(origin);
191 if (alternate.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
192 return kNoAlternateProtocol;
193 if (alternate.is_broken) {
194 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_BROKEN);
195 return kNoAlternateProtocol;
197 if (!IsAlternateProtocolValid(alternate.protocol)) {
198 NOTREACHED();
199 return kNoAlternateProtocol;
202 // Some shared unix systems may have user home directories (like
203 // http://foo.com/~mike) which allow users to emit headers. This is a bad
204 // idea already, but with Alternate-Protocol, it provides the ability for a
205 // single user on a multi-user system to hijack the alternate protocol.
206 // These systems also enforce ports <1024 as restricted ports. So don't
207 // allow protocol upgrades to user-controllable ports.
208 const int kUnrestrictedPort = 1024;
209 if (!session_->params().enable_user_alternate_protocol_ports &&
210 (alternate.port >= kUnrestrictedPort &&
211 origin.port() < kUnrestrictedPort))
212 return kNoAlternateProtocol;
214 origin.set_port(alternate.port);
215 if (alternate.protocol >= NPN_SPDY_MINIMUM_VERSION &&
216 alternate.protocol <= NPN_SPDY_MAXIMUM_VERSION) {
217 if (!HttpStreamFactory::spdy_enabled())
218 return kNoAlternateProtocol;
220 if (session_->HasSpdyExclusion(origin))
221 return kNoAlternateProtocol;
223 *alternate_url = UpgradeUrlToHttps(original_url, alternate.port);
224 } else {
225 DCHECK_EQ(QUIC, alternate.protocol);
226 if (!session_->params().enable_quic)
227 return kNoAlternateProtocol;
229 // TODO(rch): Figure out how to make QUIC iteract with PAC
230 // scripts. By not re-writing the URL, we will query the PAC script
231 // for the proxy to use to reach the original URL via TCP. But
232 // the alternate request will be going via UDP to a different port.
233 *alternate_url = original_url;
235 return alternate;
238 void HttpStreamFactoryImpl::OrphanJob(Job* job, const Request* request) {
239 DCHECK(ContainsKey(request_map_, job));
240 DCHECK_EQ(request_map_[job], request);
241 DCHECK(!ContainsKey(orphaned_job_set_, job));
243 request_map_.erase(job);
245 orphaned_job_set_.insert(job);
246 job->Orphan(request);
249 void HttpStreamFactoryImpl::OnNewSpdySessionReady(
250 const base::WeakPtr<SpdySession>& spdy_session,
251 bool direct,
252 const SSLConfig& used_ssl_config,
253 const ProxyInfo& used_proxy_info,
254 bool was_npn_negotiated,
255 NextProto protocol_negotiated,
256 bool using_spdy,
257 const BoundNetLog& net_log) {
258 while (true) {
259 if (!spdy_session)
260 break;
261 const SpdySessionKey& spdy_session_key = spdy_session->spdy_session_key();
262 // Each iteration may empty out the RequestSet for |spdy_session_key| in
263 // |spdy_session_request_map_|. So each time, check for RequestSet and use
264 // the first one.
266 // TODO(willchan): If it's important, switch RequestSet out for a FIFO
267 // queue (Order by priority first, then FIFO within same priority). Unclear
268 // that it matters here.
269 if (!ContainsKey(spdy_session_request_map_, spdy_session_key))
270 break;
271 Request* request = *spdy_session_request_map_[spdy_session_key].begin();
272 request->Complete(was_npn_negotiated,
273 protocol_negotiated,
274 using_spdy,
275 net_log);
276 if (for_websockets_) {
277 // TODO(ricea): Restore this code path when WebSocket over SPDY
278 // implementation is ready.
279 NOTREACHED();
280 } else {
281 bool use_relative_url = direct || request->url().SchemeIs("https");
282 request->OnStreamReady(
283 NULL,
284 used_ssl_config,
285 used_proxy_info,
286 new SpdyHttpStream(spdy_session, use_relative_url));
289 // TODO(mbelshe): Alert other valid requests.
292 void HttpStreamFactoryImpl::OnOrphanedJobComplete(const Job* job) {
293 orphaned_job_set_.erase(job);
294 delete job;
297 void HttpStreamFactoryImpl::OnPreconnectsComplete(const Job* job) {
298 preconnect_job_set_.erase(job);
299 delete job;
300 OnPreconnectsCompleteInternal();
303 } // namespace net