// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/http/http_alternate_protocols.h" #include "base/logging.h" #include "base/stringprintf.h" #include "base/stl_util-inl.h" namespace net { const char HttpAlternateProtocols::kHeader[] = "Alternate-Protocol"; const char* const HttpAlternateProtocols::kProtocolStrings[] = { "npn-spdy/1", "npn-spdy/2", }; const char* HttpAlternateProtocols::ProtocolToString( HttpAlternateProtocols::Protocol protocol) { switch (protocol) { case HttpAlternateProtocols::NPN_SPDY_1: case HttpAlternateProtocols::NPN_SPDY_2: return HttpAlternateProtocols::kProtocolStrings[protocol]; case HttpAlternateProtocols::BROKEN: return "Broken"; case HttpAlternateProtocols::UNINITIALIZED: return "Uninitialized"; default: NOTREACHED(); return ""; } } std::string HttpAlternateProtocols::PortProtocolPair::ToString() const { return base::StringPrintf("%d:%s", port, HttpAlternateProtocols::ProtocolToString(protocol)); } // static HttpAlternateProtocols::PortProtocolPair* HttpAlternateProtocols::forced_alternate_protocol_ = NULL; HttpAlternateProtocols::HttpAlternateProtocols() {} HttpAlternateProtocols::~HttpAlternateProtocols() {} bool HttpAlternateProtocols::HasAlternateProtocolFor( const HostPortPair& http_host_port_pair) const { return ContainsKey(protocol_map_, http_host_port_pair) || forced_alternate_protocol_; } bool HttpAlternateProtocols::HasAlternateProtocolFor( const std::string& host, uint16 port) const { HostPortPair http_host_port_pair(host, port); return HasAlternateProtocolFor(http_host_port_pair); } HttpAlternateProtocols::PortProtocolPair HttpAlternateProtocols::GetAlternateProtocolFor( const HostPortPair& http_host_port_pair) const { DCHECK(HasAlternateProtocolFor(http_host_port_pair)); // First check the map. ProtocolMap::const_iterator it = protocol_map_.find(http_host_port_pair); if (it != protocol_map_.end()) return it->second; // We must be forcing an alternate. DCHECK(forced_alternate_protocol_); return *forced_alternate_protocol_; } HttpAlternateProtocols::PortProtocolPair HttpAlternateProtocols::GetAlternateProtocolFor( const std::string& host, uint16 port) const { HostPortPair http_host_port_pair(host, port); return GetAlternateProtocolFor(http_host_port_pair); } void HttpAlternateProtocols::SetAlternateProtocolFor( const HostPortPair& http_host_port_pair, uint16 alternate_port, Protocol alternate_protocol) { if (alternate_protocol == BROKEN) { LOG(DFATAL) << "Call MarkBrokenAlternateProtocolFor() instead."; return; } PortProtocolPair alternate; alternate.port = alternate_port; alternate.protocol = alternate_protocol; if (HasAlternateProtocolFor(http_host_port_pair)) { const PortProtocolPair existing_alternate = GetAlternateProtocolFor(http_host_port_pair); if (existing_alternate.protocol == BROKEN) { DVLOG(1) << "Ignore alternate protocol since it's known to be broken."; return; } if (alternate_protocol != BROKEN && !existing_alternate.Equals(alternate)) { LOG(WARNING) << "Changing the alternate protocol for: " << http_host_port_pair.ToString() << " from [Port: " << existing_alternate.port << ", Protocol: " << existing_alternate.protocol << "] to [Port: " << alternate_port << ", Protocol: " << alternate_protocol << "]."; } } protocol_map_[http_host_port_pair] = alternate; } void HttpAlternateProtocols::MarkBrokenAlternateProtocolFor( const HostPortPair& http_host_port_pair) { protocol_map_[http_host_port_pair].protocol = BROKEN; } // static void HttpAlternateProtocols::ForceAlternateProtocol( const PortProtocolPair& pair) { // Note: we're going to leak this. if (forced_alternate_protocol_) delete forced_alternate_protocol_; forced_alternate_protocol_ = new PortProtocolPair(pair); } // static void HttpAlternateProtocols::DisableForcedAlternateProtocol() { delete forced_alternate_protocol_; forced_alternate_protocol_ = NULL; } } // namespace net