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