1 // Copyright (c) 2010 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_alternate_protocols.h"
6
7 #include "base/logging.h"
8 #include "base/stringprintf.h"
9 #include "base/stl_util-inl.h"
10
11 namespace net {
12
13 const char HttpAlternateProtocols::kHeader[] = "Alternate-Protocol";
14 const char* const HttpAlternateProtocols::kProtocolStrings[] = {
15 "npn-spdy/1",
16 "npn-spdy/2",
17 };
18
ProtocolToString(HttpAlternateProtocols::Protocol protocol)19 const char* HttpAlternateProtocols::ProtocolToString(
20 HttpAlternateProtocols::Protocol protocol) {
21 switch (protocol) {
22 case HttpAlternateProtocols::NPN_SPDY_1:
23 case HttpAlternateProtocols::NPN_SPDY_2:
24 return HttpAlternateProtocols::kProtocolStrings[protocol];
25 case HttpAlternateProtocols::BROKEN:
26 return "Broken";
27 case HttpAlternateProtocols::UNINITIALIZED:
28 return "Uninitialized";
29 default:
30 NOTREACHED();
31 return "";
32 }
33 }
34
35
ToString() const36 std::string HttpAlternateProtocols::PortProtocolPair::ToString() const {
37 return base::StringPrintf("%d:%s", port,
38 HttpAlternateProtocols::ProtocolToString(protocol));
39 }
40
41 // static
42 HttpAlternateProtocols::PortProtocolPair*
43 HttpAlternateProtocols::forced_alternate_protocol_ = NULL;
44
HttpAlternateProtocols()45 HttpAlternateProtocols::HttpAlternateProtocols() {}
~HttpAlternateProtocols()46 HttpAlternateProtocols::~HttpAlternateProtocols() {}
47
HasAlternateProtocolFor(const HostPortPair & http_host_port_pair) const48 bool HttpAlternateProtocols::HasAlternateProtocolFor(
49 const HostPortPair& http_host_port_pair) const {
50 return ContainsKey(protocol_map_, http_host_port_pair) ||
51 forced_alternate_protocol_;
52 }
53
HasAlternateProtocolFor(const std::string & host,uint16 port) const54 bool HttpAlternateProtocols::HasAlternateProtocolFor(
55 const std::string& host, uint16 port) const {
56 HostPortPair http_host_port_pair(host, port);
57 return HasAlternateProtocolFor(http_host_port_pair);
58 }
59
60 HttpAlternateProtocols::PortProtocolPair
GetAlternateProtocolFor(const HostPortPair & http_host_port_pair) const61 HttpAlternateProtocols::GetAlternateProtocolFor(
62 const HostPortPair& http_host_port_pair) const {
63 DCHECK(HasAlternateProtocolFor(http_host_port_pair));
64
65 // First check the map.
66 ProtocolMap::const_iterator it = protocol_map_.find(http_host_port_pair);
67 if (it != protocol_map_.end())
68 return it->second;
69
70 // We must be forcing an alternate.
71 DCHECK(forced_alternate_protocol_);
72 return *forced_alternate_protocol_;
73 }
74
75 HttpAlternateProtocols::PortProtocolPair
GetAlternateProtocolFor(const std::string & host,uint16 port) const76 HttpAlternateProtocols::GetAlternateProtocolFor(
77 const std::string& host, uint16 port) const {
78 HostPortPair http_host_port_pair(host, port);
79 return GetAlternateProtocolFor(http_host_port_pair);
80 }
81
SetAlternateProtocolFor(const HostPortPair & http_host_port_pair,uint16 alternate_port,Protocol alternate_protocol)82 void HttpAlternateProtocols::SetAlternateProtocolFor(
83 const HostPortPair& http_host_port_pair,
84 uint16 alternate_port,
85 Protocol alternate_protocol) {
86 if (alternate_protocol == BROKEN) {
87 LOG(DFATAL) << "Call MarkBrokenAlternateProtocolFor() instead.";
88 return;
89 }
90
91 PortProtocolPair alternate;
92 alternate.port = alternate_port;
93 alternate.protocol = alternate_protocol;
94 if (HasAlternateProtocolFor(http_host_port_pair)) {
95 const PortProtocolPair existing_alternate =
96 GetAlternateProtocolFor(http_host_port_pair);
97
98 if (existing_alternate.protocol == BROKEN) {
99 DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
100 return;
101 }
102
103 if (alternate_protocol != BROKEN && !existing_alternate.Equals(alternate)) {
104 LOG(WARNING) << "Changing the alternate protocol for: "
105 << http_host_port_pair.ToString()
106 << " from [Port: " << existing_alternate.port
107 << ", Protocol: " << existing_alternate.protocol
108 << "] to [Port: " << alternate_port
109 << ", Protocol: " << alternate_protocol
110 << "].";
111 }
112 }
113
114 protocol_map_[http_host_port_pair] = alternate;
115 }
116
MarkBrokenAlternateProtocolFor(const HostPortPair & http_host_port_pair)117 void HttpAlternateProtocols::MarkBrokenAlternateProtocolFor(
118 const HostPortPair& http_host_port_pair) {
119 protocol_map_[http_host_port_pair].protocol = BROKEN;
120 }
121
122 // static
ForceAlternateProtocol(const PortProtocolPair & pair)123 void HttpAlternateProtocols::ForceAlternateProtocol(
124 const PortProtocolPair& pair) {
125 // Note: we're going to leak this.
126 if (forced_alternate_protocol_)
127 delete forced_alternate_protocol_;
128 forced_alternate_protocol_ = new PortProtocolPair(pair);
129 }
130
131 // static
DisableForcedAlternateProtocol()132 void HttpAlternateProtocols::DisableForcedAlternateProtocol() {
133 delete forced_alternate_protocol_;
134 forced_alternate_protocol_ = NULL;
135 }
136
137 } // namespace net
138