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_VALID_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 bool HttpStreamFactory::IsProtocolEnabled(AlternateProtocol protocol) {
     38   DCHECK(IsAlternateProtocolValid(protocol));
     39   return enabled_protocols_[
     40       protocol - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION];
     41 }
     42 
     43 // static
     44 void HttpStreamFactory::SetProtocolEnabled(AlternateProtocol protocol) {
     45   DCHECK(IsAlternateProtocolValid(protocol));
     46   enabled_protocols_[
     47       protocol - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION] = true;
     48 }
     49 
     50 // static
     51 void HttpStreamFactory::ResetEnabledProtocols() {
     52   for (int i = ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION;
     53        i <= ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION; ++i) {
     54     enabled_protocols_[i - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION] = false;
     55   }
     56 }
     57 
     58 // static
     59 void HttpStreamFactory::ResetStaticSettingsToInit() {
     60   // WARNING: These must match the initializers above.
     61   delete next_protos_;
     62   delete forced_spdy_exclusions_;
     63   next_protos_ = NULL;
     64   spdy_enabled_ = true;
     65   use_alternate_protocols_ = false;
     66   force_spdy_over_ssl_ = true;
     67   force_spdy_always_ = false;
     68   forced_spdy_exclusions_ = NULL;
     69   ResetEnabledProtocols();
     70 }
     71 
     72 void HttpStreamFactory::ProcessAlternateProtocol(
     73     const base::WeakPtr<HttpServerProperties>& http_server_properties,
     74     const std::string& alternate_protocol_str,
     75     const HostPortPair& http_host_port_pair) {
     76   std::vector<std::string> port_protocol_vector;
     77   base::SplitString(alternate_protocol_str, ':', &port_protocol_vector);
     78   if (port_protocol_vector.size() != 2) {
     79     DVLOG(1) << kAlternateProtocolHeader
     80              << " header has too many tokens: "
     81              << alternate_protocol_str;
     82     return;
     83   }
     84 
     85   int port;
     86   if (!base::StringToInt(port_protocol_vector[0], &port) ||
     87       port <= 0 || port >= 1 << 16) {
     88     DVLOG(1) << kAlternateProtocolHeader
     89              << " header has unrecognizable port: "
     90              << port_protocol_vector[0];
     91     return;
     92   }
     93 
     94   AlternateProtocol protocol =
     95       AlternateProtocolFromString(port_protocol_vector[1]);
     96   if (IsAlternateProtocolValid(protocol) && !IsProtocolEnabled(protocol)) {
     97     protocol = ALTERNATE_PROTOCOL_BROKEN;
     98   }
     99 
    100   if (protocol == ALTERNATE_PROTOCOL_BROKEN) {
    101     DVLOG(1) << kAlternateProtocolHeader
    102              << " header has unrecognized protocol: "
    103              << port_protocol_vector[1];
    104     return;
    105   }
    106 
    107   HostPortPair host_port(http_host_port_pair);
    108   const HostMappingRules* mapping_rules = GetHostMappingRules();
    109   if (mapping_rules)
    110     mapping_rules->RewriteHost(&host_port);
    111 
    112   if (http_server_properties->HasAlternateProtocol(host_port)) {
    113     const PortAlternateProtocolPair existing_alternate =
    114         http_server_properties->GetAlternateProtocol(host_port);
    115     // If we think the alternate protocol is broken, don't change it.
    116     if (existing_alternate.protocol == ALTERNATE_PROTOCOL_BROKEN)
    117       return;
    118   }
    119 
    120   http_server_properties->SetAlternateProtocol(host_port, port, protocol);
    121 }
    122 
    123 GURL HttpStreamFactory::ApplyHostMappingRules(const GURL& url,
    124                                               HostPortPair* endpoint) {
    125   const HostMappingRules* mapping_rules = GetHostMappingRules();
    126   if (mapping_rules && mapping_rules->RewriteHost(endpoint)) {
    127     url_canon::Replacements<char> replacements;
    128     const std::string port_str = base::IntToString(endpoint->port());
    129     replacements.SetPort(port_str.c_str(),
    130                          url_parse::Component(0, port_str.size()));
    131     replacements.SetHost(endpoint->host().c_str(),
    132                          url_parse::Component(0, endpoint->host().size()));
    133     return url.ReplaceComponents(replacements);
    134   }
    135   return url;
    136 }
    137 
    138 // static
    139 void HttpStreamFactory::add_forced_spdy_exclusion(const std::string& value) {
    140   HostPortPair pair = HostPortPair::FromURL(GURL(value));
    141   if (!forced_spdy_exclusions_)
    142     forced_spdy_exclusions_ = new std::list<HostPortPair>();
    143   forced_spdy_exclusions_->push_back(pair);
    144 }
    145 
    146 // static
    147 bool HttpStreamFactory::HasSpdyExclusion(const HostPortPair& endpoint) {
    148   std::list<HostPortPair>* exclusions = forced_spdy_exclusions_;
    149   if (!exclusions)
    150     return false;
    151 
    152   std::list<HostPortPair>::const_iterator it;
    153   for (it = exclusions->begin(); it != exclusions->end(); ++it)
    154     if (it->Equals(endpoint))
    155       return true;
    156   return false;
    157 }
    158 
    159 // static
    160 void HttpStreamFactory::EnableNpnHttpOnly() {
    161   // Avoid alternate protocol in this case. Otherwise, browser will try SSL
    162   // and then fallback to http. This introduces extra load.
    163   set_use_alternate_protocols(false);
    164   std::vector<NextProto> next_protos;
    165   next_protos.push_back(kProtoHTTP11);
    166   SetNextProtos(next_protos);
    167 }
    168 
    169 // static
    170 void HttpStreamFactory::EnableNpnSpdy3() {
    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(kProtoSPDY3);
    176   SetNextProtos(next_protos);
    177 }
    178 
    179 // static
    180 void HttpStreamFactory::EnableNpnSpdy31() {
    181   set_use_alternate_protocols(true);
    182   std::vector<NextProto> next_protos;
    183   next_protos.push_back(kProtoHTTP11);
    184   next_protos.push_back(kProtoQUIC1SPDY3);
    185   next_protos.push_back(kProtoSPDY3);
    186   next_protos.push_back(kProtoSPDY31);
    187   SetNextProtos(next_protos);
    188 }
    189 
    190 // static
    191 void HttpStreamFactory::EnableNpnSpdy31WithSpdy2() {
    192   set_use_alternate_protocols(true);
    193   std::vector<NextProto> next_protos;
    194   next_protos.push_back(kProtoHTTP11);
    195   next_protos.push_back(kProtoQUIC1SPDY3);
    196   next_protos.push_back(kProtoDeprecatedSPDY2);
    197   next_protos.push_back(kProtoSPDY3);
    198   next_protos.push_back(kProtoSPDY31);
    199   SetNextProtos(next_protos);
    200 }
    201 
    202 // static
    203 void HttpStreamFactory::EnableNpnSpdy4a2() {
    204   set_use_alternate_protocols(true);
    205   std::vector<NextProto> next_protos;
    206   next_protos.push_back(kProtoHTTP11);
    207   next_protos.push_back(kProtoQUIC1SPDY3);
    208   next_protos.push_back(kProtoSPDY3);
    209   next_protos.push_back(kProtoSPDY31);
    210   next_protos.push_back(kProtoSPDY4a2);
    211   SetNextProtos(next_protos);
    212 }
    213 
    214 // static
    215 void HttpStreamFactory::EnableNpnHttp2Draft04() {
    216   set_use_alternate_protocols(true);
    217   std::vector<NextProto> next_protos;
    218   next_protos.push_back(kProtoHTTP11);
    219   next_protos.push_back(kProtoQUIC1SPDY3);
    220   next_protos.push_back(kProtoSPDY3);
    221   next_protos.push_back(kProtoSPDY31);
    222   next_protos.push_back(kProtoSPDY4a2);
    223   next_protos.push_back(kProtoHTTP2Draft04);
    224   SetNextProtos(next_protos);
    225 }
    226 
    227 // static
    228 void HttpStreamFactory::SetNextProtos(const std::vector<NextProto>& value) {
    229   if (!next_protos_)
    230     next_protos_ = new std::vector<std::string>;
    231 
    232   next_protos_->clear();
    233 
    234   ResetEnabledProtocols();
    235 
    236   // TODO(rtenneti): bug 116575 - consider combining the NextProto and
    237   // AlternateProtocol.
    238   for (uint32 i = 0; i < value.size(); ++i) {
    239     NextProto proto = value[i];
    240     // Add the protocol to the TLS next protocol list, except for QUIC
    241     // since it uses UDP.
    242     if (proto != kProtoQUIC1SPDY3) {
    243       next_protos_->push_back(SSLClientSocket::NextProtoToString(proto));
    244     }
    245 
    246     // Enable the corresponding alternate protocol, except for HTTP
    247     // which has not corresponding alternative.
    248     if (proto != kProtoHTTP11) {
    249       AlternateProtocol alternate = AlternateProtocolFromNextProto(proto);
    250       if (!IsAlternateProtocolValid(alternate)) {
    251         NOTREACHED() << "Invalid next proto: " << proto;
    252         continue;
    253       }
    254       SetProtocolEnabled(alternate);
    255     }
    256   }
    257 }
    258 
    259 HttpStreamFactory::HttpStreamFactory() {}
    260 
    261 }  // namespace net
    262