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