15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_stream_factory_impl.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <string>
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_log.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_network_session.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_pipelined_connection.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_pipelined_host.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_pipelined_stream.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_server_properties.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_stream_factory_impl_job.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_stream_factory_impl_request.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_http_stream.h"
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const PortAlternateProtocolPair kNoAlternateProtocol = {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  0,  UNINITIALIZED_ALTERNATE_PROTOCOL
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL UpgradeUrlToHttps(const GURL& original_url, int port) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL::Replacements replacements;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // new_sheme and new_port need to be in scope here because GURL::Replacements
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // references the memory contained by them directly.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string new_scheme = "https";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string new_port = base::IntToString(port);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  replacements.SetSchemeStr(new_scheme);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  replacements.SetPortStr(new_port);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return original_url.ReplaceComponents(replacements);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochHttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session,
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                             bool for_websockets)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : session_(session),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_pipelined_host_pool_(this, NULL,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                session_->http_server_properties(),
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                session_->force_http_pipelining()),
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      for_websockets_(for_websockets) {}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpStreamFactoryImpl::~HttpStreamFactoryImpl() {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(request_map_.empty());
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(spdy_session_request_map_.empty());
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(http_pipelining_request_map_.empty());
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<const Job*> tmp_job_set;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tmp_job_set.swap(orphaned_job_set_);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end());
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(orphaned_job_set_.empty());
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tmp_job_set.clear();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tmp_job_set.swap(preconnect_job_set_);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end());
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(preconnect_job_set_.empty());
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpStreamRequest* HttpStreamFactoryImpl::RequestStream(
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const HttpRequestInfo& request_info,
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RequestPriority priority,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SSLConfig& server_ssl_config,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SSLConfig& proxy_ssl_config,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpStreamRequest::Delegate* delegate,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BoundNetLog& net_log) {
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!for_websockets_);
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return RequestStreamInternal(request_info,
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               priority,
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               server_ssl_config,
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               proxy_ssl_config,
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               delegate,
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               NULL,
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               net_log);
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochHttpStreamRequest* HttpStreamFactoryImpl::RequestWebSocketStream(
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const HttpRequestInfo& request_info,
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RequestPriority priority,
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const SSLConfig& server_ssl_config,
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const SSLConfig& proxy_ssl_config,
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    HttpStreamRequest::Delegate* delegate,
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    WebSocketStreamBase::Factory* factory,
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const BoundNetLog& net_log) {
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(for_websockets_);
94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(factory);
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return RequestStreamInternal(request_info,
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               priority,
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               server_ssl_config,
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               proxy_ssl_config,
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               delegate,
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               factory,
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               net_log);
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochHttpStreamRequest* HttpStreamFactoryImpl::RequestStreamInternal(
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const HttpRequestInfo& request_info,
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    RequestPriority priority,
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const SSLConfig& server_ssl_config,
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const SSLConfig& proxy_ssl_config,
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    HttpStreamRequest::Delegate* delegate,
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    WebSocketStreamBase::Factory* websocket_stream_factory,
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const BoundNetLog& net_log) {
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Request* request = new Request(request_info.url,
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 this,
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 delegate,
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 websocket_stream_factory,
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 net_log);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL alternate_url;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PortAlternateProtocolPair alternate =
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetAlternateProtocolRequestFor(request_info.url, &alternate_url);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Job* alternate_job = NULL;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (alternate.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Never share connection with other jobs for FTP requests.
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!request_info.url.SchemeIs("ftp"));
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpRequestInfo alternate_request_info = request_info;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    alternate_request_info.url = alternate_url;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    alternate_job =
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new Job(this, session_, alternate_request_info, priority,
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                server_ssl_config, proxy_ssl_config, net_log.net_log());
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->AttachJob(alternate_job);
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    alternate_job->MarkAsAlternate(request_info.url, alternate);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Job* job = new Job(this, session_, request_info, priority,
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     server_ssl_config, proxy_ssl_config, net_log.net_log());
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->AttachJob(job);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alternate_job) {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Never share connection with other jobs for FTP requests.
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!request_info.url.SchemeIs("ftp"));
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    job->WaitFor(alternate_job);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure to wait until we call WaitFor(), before starting
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |alternate_job|, otherwise |alternate_job| will not notify |job|
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // appropriately.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    alternate_job->Start(request);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Even if |alternate_job| has already finished, it won't have notified the
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // request yet, since we defer that to the next iteration of the MessageLoop,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so starting |job| is always safe.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  job->Start(request);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return request;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpStreamFactoryImpl::PreconnectStreams(
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int num_streams,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const HttpRequestInfo& request_info,
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RequestPriority priority,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SSLConfig& server_ssl_config,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SSLConfig& proxy_ssl_config) {
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!for_websockets_);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL alternate_url;
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PortAlternateProtocolPair alternate =
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetAlternateProtocolRequestFor(request_info.url, &alternate_url);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Job* job = NULL;
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (alternate.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpRequestInfo alternate_request_info = request_info;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    alternate_request_info.url = alternate_url;
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    job = new Job(this, session_, alternate_request_info, priority,
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  server_ssl_config, proxy_ssl_config, session_->net_log());
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    job->MarkAsAlternate(request_info.url, alternate);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    job = new Job(this, session_, request_info, priority,
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  server_ssl_config, proxy_ssl_config, session_->net_log());
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preconnect_job_set_.insert(job);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  job->Preconnect(num_streams);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::Value* HttpStreamFactoryImpl::PipelineInfoToValue() const {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return http_pipelined_host_pool_.PipelineInfoToValue();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const HostMappingRules* HttpStreamFactoryImpl::GetHostMappingRules() const {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return session_->params().host_mapping_rules;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PortAlternateProtocolPair HttpStreamFactoryImpl::GetAlternateProtocolRequestFor(
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& original_url,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL* alternate_url) const {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!use_alternate_protocols())
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return kNoAlternateProtocol;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (original_url.SchemeIs("ftp"))
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return kNoAlternateProtocol;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HostPortPair origin = HostPortPair(original_url.HostNoBrackets(),
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     original_url.EffectiveIntPort());
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const HttpServerProperties& http_server_properties =
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *session_->http_server_properties();
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!http_server_properties.HasAlternateProtocol(origin))
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return kNoAlternateProtocol;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PortAlternateProtocolPair alternate =
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      http_server_properties.GetAlternateProtocol(origin);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alternate.protocol == ALTERNATE_PROTOCOL_BROKEN)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return kNoAlternateProtocol;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(NPN_SPDY_1, alternate.protocol);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(NUM_ALTERNATE_PROTOCOLS, alternate.protocol);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alternate.protocol < NPN_SPDY_2)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return kNoAlternateProtocol;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some shared unix systems may have user home directories (like
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://foo.com/~mike) which allow users to emit headers.  This is a bad
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // idea already, but with Alternate-Protocol, it provides the ability for a
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // single user on a multi-user system to hijack the alternate protocol.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These systems also enforce ports <1024 as restricted ports.  So don't
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // allow protocol upgrades to user-controllable ports.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kUnrestrictedPort = 1024;
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!session_->params().enable_user_alternate_protocol_ports &&
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (alternate.port >= kUnrestrictedPort &&
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       origin.port() < kUnrestrictedPort))
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return kNoAlternateProtocol;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  origin.set_port(alternate.port);
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (alternate.protocol >= NPN_SPDY_MINIMUM_VERSION &&
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      alternate.protocol <= NPN_SPDY_MAXIMUM_VERSION) {
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!spdy_enabled())
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return kNoAlternateProtocol;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (HttpStreamFactory::HasSpdyExclusion(origin))
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return kNoAlternateProtocol;
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *alternate_url = UpgradeUrlToHttps(original_url, alternate.port);
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_EQ(QUIC, alternate.protocol);
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!session_->params().enable_quic ||
2417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        !(original_url.SchemeIs("http") ||
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          session_->params().enable_quic_https)) {
2437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        return kNoAlternateProtocol;
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(rch):  Figure out how to make QUIC iteract with PAC
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // scripts.  By not re-writing the URL, we will query the PAC script
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // for the proxy to use to reach the original URL via TCP.  But
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the alternate request will be going via UDP to a different port.
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *alternate_url = original_url;
250eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return alternate;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpStreamFactoryImpl::OrphanJob(Job* job, const Request* request) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsKey(request_map_, job));
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(request_map_[job], request);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!ContainsKey(orphaned_job_set_, job));
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_map_.erase(job);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  orphaned_job_set_.insert(job);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  job->Orphan(request);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid HttpStreamFactoryImpl::OnNewSpdySessionReady(
266ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const base::WeakPtr<SpdySession>& spdy_session,
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool direct,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SSLConfig& used_ssl_config,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProxyInfo& used_proxy_info,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool was_npn_negotiated,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NextProto protocol_negotiated,
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool using_spdy,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BoundNetLog& net_log) {
274ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while (true) {
275ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!spdy_session)
276ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
277ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const SpdySessionKey& spdy_session_key = spdy_session->spdy_session_key();
278ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Each iteration may empty out the RequestSet for |spdy_session_key| in
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |spdy_session_request_map_|. So each time, check for RequestSet and use
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the first one.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(willchan): If it's important, switch RequestSet out for a FIFO
283ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // queue (Order by priority first, then FIFO within same priority). Unclear
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that it matters here.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ContainsKey(spdy_session_request_map_, spdy_session_key))
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Request* request = *spdy_session_request_map_[spdy_session_key].begin();
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->Complete(was_npn_negotiated,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      protocol_negotiated,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      using_spdy,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      net_log);
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (for_websockets_) {
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      WebSocketStreamBase::Factory* factory =
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          request->websocket_stream_factory();
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      DCHECK(factory);
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      bool use_relative_url = direct || request->url().SchemeIs("wss");
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      request->OnWebSocketStreamReady(
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          NULL,
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          used_ssl_config,
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          used_proxy_info,
301ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          factory->CreateSpdyStream(spdy_session, use_relative_url));
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    } else {
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      bool use_relative_url = direct || request->url().SchemeIs("https");
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      request->OnStreamReady(
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          NULL,
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          used_ssl_config,
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          used_proxy_info,
308ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          new SpdyHttpStream(spdy_session, use_relative_url));
309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mbelshe): Alert other valid requests.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpStreamFactoryImpl::OnOrphanedJobComplete(const Job* job) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  orphaned_job_set_.erase(job);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete job;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpStreamFactoryImpl::OnPreconnectsComplete(const Job* job) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preconnect_job_set_.erase(job);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete job;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnPreconnectsCompleteInternal();
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpStreamFactoryImpl::OnHttpPipelinedHostHasAdditionalCapacity(
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpPipelinedHost* host) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (ContainsKey(http_pipelining_request_map_, host->GetKey())) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HttpPipelinedStream* stream =
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        http_pipelined_host_pool_.CreateStreamOnExistingPipeline(
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            host->GetKey());
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!stream) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Request* request = *http_pipelining_request_map_[host->GetKey()].begin();
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->Complete(stream->was_npn_negotiated(),
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      stream->protocol_negotiated(),
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      false,  // not using_spdy
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      stream->net_log());
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->OnStreamReady(NULL,
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           stream->used_ssl_config(),
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           stream->used_proxy_info(),
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           stream);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpStreamFactoryImpl::AbortPipelinedRequestsWithKey(
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Job* job, const HttpPipelinedHost::Key& key, int status,
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SSLConfig& used_ssl_config) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RequestVector requests_to_fail = http_pipelining_request_map_[key];
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (RequestVector::const_iterator it = requests_to_fail.begin();
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != requests_to_fail.end(); ++it) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Request* request = *it;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (request == request_map_[job]) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->OnStreamFailed(NULL, status, used_ssl_config);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
362