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