Home | History | Annotate | Download | only in http
      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.
      4 
      5 #include "net/http/http_stream_factory.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/strings/string_split.h"
     10 #include "net/base/host_mapping_rules.h"
     11 #include "net/base/host_port_pair.h"
     12 #include "url/gurl.h"
     13 
     14 namespace net {
     15 
     16 // WARNING: If you modify or add any static flags, you must keep them in sync
     17 // with |ResetStaticSettingsToInit|. This is critical for unit test isolation.
     18 
     19 // static
     20 std::vector<std::string>* HttpStreamFactory::next_protos_ = NULL;
     21 // static
     22 bool HttpStreamFactory::enabled_protocols_[NUM_ALTERNATE_PROTOCOLS];
     23 // static
     24 bool HttpStreamFactory::spdy_enabled_ = true;
     25 // static
     26 bool HttpStreamFactory::use_alternate_protocols_ = false;
     27 // static
     28 bool HttpStreamFactory::force_spdy_over_ssl_ = true;
     29 // static
     30 bool HttpStreamFactory::force_spdy_always_ = false;
     31 // static
     32 std::list<HostPortPair>* HttpStreamFactory::forced_spdy_exclusions_ = NULL;
     33 
     34 HttpStreamFactory::~HttpStreamFactory() {}
     35 
     36 // static
     37 void HttpStreamFactory::ResetStaticSettingsToInit() {
     38   // WARNING: These must match the initializers above.
     39   delete next_protos_;
     40   delete forced_spdy_exclusions_;
     41   next_protos_ = NULL;
     42   spdy_enabled_ = true;
     43   use_alternate_protocols_ = false;
     44   force_spdy_over_ssl_ = true;
     45   force_spdy_always_ = false;
     46   forced_spdy_exclusions_ = NULL;
     47   for (int i = 0; i < NUM_ALTERNATE_PROTOCOLS; ++i)
     48     enabled_protocols_[i] = false;
     49 }
     50 
     51 void HttpStreamFactory::ProcessAlternateProtocol(
     52     const base::WeakPtr<HttpServerProperties>& http_server_properties,
     53     const std::string& alternate_protocol_str,
     54     const HostPortPair& http_host_port_pair) {
     55   std::vector<std::string> port_protocol_vector;
     56   base::SplitString(alternate_protocol_str, ':', &port_protocol_vector);
     57   if (port_protocol_vector.size() != 2) {
     58     DLOG(WARNING) << kAlternateProtocolHeader
     59                   << " header has too many tokens: "
     60                   << alternate_protocol_str;
     61     return;
     62   }
     63 
     64   int port;
     65   if (!base::StringToInt(port_protocol_vector[0], &port) ||
     66       port <= 0 || port >= 1 << 16) {
     67     DLOG(WARNING) << kAlternateProtocolHeader
     68                   << " header has unrecognizable port: "
     69                   << port_protocol_vector[0];
     70     return;
     71   }
     72 
     73   AlternateProtocol protocol =
     74       AlternateProtocolFromString(port_protocol_vector[1]);
     75   if (protocol < NUM_ALTERNATE_PROTOCOLS && !enabled_protocols_[protocol])
     76     protocol = ALTERNATE_PROTOCOL_BROKEN;
     77 
     78   if (protocol == ALTERNATE_PROTOCOL_BROKEN) {
     79     // Currently, we only recognize the npn-spdy protocol.
     80     DLOG(WARNING) << kAlternateProtocolHeader
     81                   << " header has unrecognized protocol: "
     82                   << port_protocol_vector[1];
     83     return;
     84   }
     85 
     86   HostPortPair host_port(http_host_port_pair);
     87   const HostMappingRules* mapping_rules = GetHostMappingRules();
     88   if (mapping_rules)
     89     mapping_rules->RewriteHost(&host_port);
     90 
     91   if (http_server_properties->HasAlternateProtocol(host_port)) {
     92     const PortAlternateProtocolPair existing_alternate =
     93         http_server_properties->GetAlternateProtocol(host_port);
     94     // If we think the alternate protocol is broken, don't change it.
     95     if (existing_alternate.protocol == ALTERNATE_PROTOCOL_BROKEN)
     96       return;
     97   }
     98 
     99   http_server_properties->SetAlternateProtocol(host_port, port, protocol);
    100 }
    101 
    102 GURL HttpStreamFactory::ApplyHostMappingRules(const GURL& url,
    103                                               HostPortPair* endpoint) {
    104   const HostMappingRules* mapping_rules = GetHostMappingRules();
    105   if (mapping_rules && mapping_rules->RewriteHost(endpoint)) {
    106     url_canon::Replacements<char> replacements;
    107     const std::string port_str = base::IntToString(endpoint->port());
    108     replacements.SetPort(port_str.c_str(),
    109                          url_parse::Component(0, port_str.size()));
    110     replacements.SetHost(endpoint->host().c_str(),
    111                          url_parse::Component(0, endpoint->host().size()));
    112     return url.ReplaceComponents(replacements);
    113   }
    114   return url;
    115 }
    116 
    117 // static
    118 void HttpStreamFactory::add_forced_spdy_exclusion(const std::string& value) {
    119   HostPortPair pair = HostPortPair::FromURL(GURL(value));
    120   if (!forced_spdy_exclusions_)
    121     forced_spdy_exclusions_ = new std::list<HostPortPair>();
    122   forced_spdy_exclusions_->push_back(pair);
    123 }
    124 
    125 // static
    126 bool HttpStreamFactory::HasSpdyExclusion(const HostPortPair& endpoint) {
    127   std::list<HostPortPair>* exclusions = forced_spdy_exclusions_;
    128   if (!exclusions)
    129     return false;
    130 
    131   std::list<HostPortPair>::const_iterator it;
    132   for (it = exclusions->begin(); it != exclusions->end(); ++it)
    133     if (it->Equals(endpoint))
    134       return true;
    135   return false;
    136 }
    137 
    138 // static
    139 void HttpStreamFactory::EnableNpnSpdy() {
    140   set_use_alternate_protocols(true);
    141   std::vector<NextProto> next_protos;
    142   next_protos.push_back(kProtoHTTP11);
    143   next_protos.push_back(kProtoQUIC1SPDY3);
    144   next_protos.push_back(kProtoSPDY2);
    145   SetNextProtos(next_protos);
    146 }
    147 
    148 // static
    149 void HttpStreamFactory::EnableNpnHttpOnly() {
    150   // Avoid alternate protocol in this case. Otherwise, browser will try SSL
    151   // and then fallback to http. This introduces extra load.
    152   set_use_alternate_protocols(false);
    153   std::vector<NextProto> next_protos;
    154   next_protos.push_back(kProtoHTTP11);
    155   SetNextProtos(next_protos);
    156 }
    157 
    158 // static
    159 void HttpStreamFactory::EnableNpnSpdy3() {
    160   set_use_alternate_protocols(true);
    161   std::vector<NextProto> next_protos;
    162   next_protos.push_back(kProtoHTTP11);
    163   next_protos.push_back(kProtoQUIC1SPDY3);
    164   next_protos.push_back(kProtoSPDY2);
    165   next_protos.push_back(kProtoSPDY3);
    166   SetNextProtos(next_protos);
    167 }
    168 
    169 // static
    170 void HttpStreamFactory::EnableNpnSpdy31() {
    171   set_use_alternate_protocols(true);
    172   std::vector<NextProto> next_protos;
    173   next_protos.push_back(kProtoHTTP11);
    174   next_protos.push_back(kProtoQUIC1SPDY3);
    175   next_protos.push_back(kProtoSPDY2);
    176   next_protos.push_back(kProtoSPDY3);
    177   next_protos.push_back(kProtoSPDY31);
    178   SetNextProtos(next_protos);
    179 }
    180 
    181 // static
    182 void HttpStreamFactory::EnableNpnSpdy4a2() {
    183   set_use_alternate_protocols(true);
    184   std::vector<NextProto> next_protos;
    185   next_protos.push_back(kProtoHTTP11);
    186   next_protos.push_back(kProtoQUIC1SPDY3);
    187   next_protos.push_back(kProtoSPDY2);
    188   next_protos.push_back(kProtoSPDY3);
    189   next_protos.push_back(kProtoSPDY31);
    190   next_protos.push_back(kProtoSPDY4a2);
    191   SetNextProtos(next_protos);
    192 }
    193 
    194 // static
    195 void HttpStreamFactory::EnableNpnHttp2Draft04() {
    196   set_use_alternate_protocols(true);
    197   std::vector<NextProto> next_protos;
    198   next_protos.push_back(kProtoHTTP11);
    199   next_protos.push_back(kProtoQUIC1SPDY3);
    200   next_protos.push_back(kProtoSPDY2);
    201   next_protos.push_back(kProtoSPDY3);
    202   next_protos.push_back(kProtoSPDY31);
    203   next_protos.push_back(kProtoSPDY4a2);
    204   next_protos.push_back(kProtoHTTP2Draft04);
    205   SetNextProtos(next_protos);
    206 }
    207 
    208 // static
    209 void HttpStreamFactory::SetNextProtos(const std::vector<NextProto>& value) {
    210   if (!next_protos_)
    211     next_protos_ = new std::vector<std::string>;
    212 
    213   next_protos_->clear();
    214 
    215   for (uint32 i = 0; i < NUM_ALTERNATE_PROTOCOLS; ++i)
    216     enabled_protocols_[i] = false;
    217 
    218   // TODO(rtenneti): bug 116575 - consider combining the NextProto and
    219   // AlternateProtocol.
    220   for (uint32 i = 0; i < value.size(); ++i) {
    221     NextProto proto = value[i];
    222     // Add the protocol to the TLS next protocol list, except for QUIC
    223     // since it uses UDP.
    224     if (proto != kProtoQUIC1SPDY3) {
    225       next_protos_->push_back(SSLClientSocket::NextProtoToString(proto));
    226     }
    227 
    228     // Enable the corresponding alternate protocol, except for HTTP
    229     // which has not corresponding alternative.
    230     if (proto != kProtoHTTP11) {
    231       AlternateProtocol alternate = AlternateProtocolFromNextProto(proto);
    232       if (alternate == UNINITIALIZED_ALTERNATE_PROTOCOL) {
    233         NOTREACHED() << "Invalid next proto: " << proto;
    234         continue;
    235       }
    236       enabled_protocols_[alternate] = true;
    237     }
    238   }
    239 }
    240 
    241 HttpStreamFactory::HttpStreamFactory() {}
    242 
    243 }  // namespace net
    244