1 // Copyright 2016 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 "quiche/http2/http2_constants.h"
6
7 #include "absl/strings/str_cat.h"
8 #include "absl/strings/str_format.h"
9 #include "absl/strings/string_view.h"
10 #include "quiche/common/platform/api/quiche_flag_utils.h"
11 #include "quiche/common/platform/api/quiche_flags.h"
12 #include "quiche/common/platform/api/quiche_logging.h"
13
14 namespace http2 {
15
Http2FrameTypeToString(Http2FrameType v)16 std::string Http2FrameTypeToString(Http2FrameType v) {
17 switch (v) {
18 case Http2FrameType::DATA:
19 return "DATA";
20 case Http2FrameType::HEADERS:
21 return "HEADERS";
22 case Http2FrameType::PRIORITY:
23 return "PRIORITY";
24 case Http2FrameType::RST_STREAM:
25 return "RST_STREAM";
26 case Http2FrameType::SETTINGS:
27 return "SETTINGS";
28 case Http2FrameType::PUSH_PROMISE:
29 return "PUSH_PROMISE";
30 case Http2FrameType::PING:
31 return "PING";
32 case Http2FrameType::GOAWAY:
33 return "GOAWAY";
34 case Http2FrameType::WINDOW_UPDATE:
35 return "WINDOW_UPDATE";
36 case Http2FrameType::CONTINUATION:
37 return "CONTINUATION";
38 case Http2FrameType::ALTSVC:
39 return "ALTSVC";
40 case Http2FrameType::PRIORITY_UPDATE:
41 return "PRIORITY_UPDATE";
42 }
43 return absl::StrCat("UnknownFrameType(", static_cast<int>(v), ")");
44 }
45
Http2FrameTypeToString(uint8_t v)46 std::string Http2FrameTypeToString(uint8_t v) {
47 return Http2FrameTypeToString(static_cast<Http2FrameType>(v));
48 }
49
Http2FrameFlagsToString(Http2FrameType type,uint8_t flags)50 std::string Http2FrameFlagsToString(Http2FrameType type, uint8_t flags) {
51 std::string s;
52 // Closure to append flag name |v| to the std::string |s|,
53 // and to clear |bit| from |flags|.
54 auto append_and_clear = [&s, &flags](absl::string_view v, uint8_t bit) {
55 if (!s.empty()) {
56 s.push_back('|');
57 }
58 absl::StrAppend(&s, v);
59 flags ^= bit;
60 };
61 if (flags & 0x01) {
62 if (type == Http2FrameType::DATA || type == Http2FrameType::HEADERS) {
63 append_and_clear("END_STREAM", Http2FrameFlag::END_STREAM);
64 } else if (type == Http2FrameType::SETTINGS ||
65 type == Http2FrameType::PING) {
66 append_and_clear("ACK", Http2FrameFlag::ACK);
67 }
68 }
69 if (flags & 0x04) {
70 if (type == Http2FrameType::HEADERS ||
71 type == Http2FrameType::PUSH_PROMISE ||
72 type == Http2FrameType::CONTINUATION) {
73 append_and_clear("END_HEADERS", Http2FrameFlag::END_HEADERS);
74 }
75 }
76 if (flags & 0x08) {
77 if (type == Http2FrameType::DATA || type == Http2FrameType::HEADERS ||
78 type == Http2FrameType::PUSH_PROMISE) {
79 append_and_clear("PADDED", Http2FrameFlag::PADDED);
80 }
81 }
82 if (flags & 0x20) {
83 if (type == Http2FrameType::HEADERS) {
84 append_and_clear("PRIORITY", Http2FrameFlag::PRIORITY);
85 }
86 }
87 if (flags != 0) {
88 append_and_clear(absl::StrFormat("0x%02x", flags), flags);
89 }
90 QUICHE_DCHECK_EQ(0, flags);
91 return s;
92 }
Http2FrameFlagsToString(uint8_t type,uint8_t flags)93 std::string Http2FrameFlagsToString(uint8_t type, uint8_t flags) {
94 return Http2FrameFlagsToString(static_cast<Http2FrameType>(type), flags);
95 }
96
Http2ErrorCodeToString(uint32_t v)97 std::string Http2ErrorCodeToString(uint32_t v) {
98 switch (v) {
99 case 0x0:
100 return "NO_ERROR";
101 case 0x1:
102 return "PROTOCOL_ERROR";
103 case 0x2:
104 return "INTERNAL_ERROR";
105 case 0x3:
106 return "FLOW_CONTROL_ERROR";
107 case 0x4:
108 return "SETTINGS_TIMEOUT";
109 case 0x5:
110 return "STREAM_CLOSED";
111 case 0x6:
112 return "FRAME_SIZE_ERROR";
113 case 0x7:
114 return "REFUSED_STREAM";
115 case 0x8:
116 return "CANCEL";
117 case 0x9:
118 return "COMPRESSION_ERROR";
119 case 0xa:
120 return "CONNECT_ERROR";
121 case 0xb:
122 return "ENHANCE_YOUR_CALM";
123 case 0xc:
124 return "INADEQUATE_SECURITY";
125 case 0xd:
126 return "HTTP_1_1_REQUIRED";
127 }
128 return absl::StrCat("UnknownErrorCode(0x", absl::Hex(v), ")");
129 }
Http2ErrorCodeToString(Http2ErrorCode v)130 std::string Http2ErrorCodeToString(Http2ErrorCode v) {
131 return Http2ErrorCodeToString(static_cast<uint32_t>(v));
132 }
133
Http2SettingsParameterToString(uint32_t v)134 std::string Http2SettingsParameterToString(uint32_t v) {
135 switch (v) {
136 case 0x1:
137 return "HEADER_TABLE_SIZE";
138 case 0x2:
139 return "ENABLE_PUSH";
140 case 0x3:
141 return "MAX_CONCURRENT_STREAMS";
142 case 0x4:
143 return "INITIAL_WINDOW_SIZE";
144 case 0x5:
145 return "MAX_FRAME_SIZE";
146 case 0x6:
147 return "MAX_HEADER_LIST_SIZE";
148 }
149 return absl::StrCat("UnknownSettingsParameter(0x", absl::Hex(v), ")");
150 }
Http2SettingsParameterToString(Http2SettingsParameter v)151 std::string Http2SettingsParameterToString(Http2SettingsParameter v) {
152 return Http2SettingsParameterToString(static_cast<uint32_t>(v));
153 }
154
155 // Invalid HTTP/2 header names according to
156 // https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.2.
157 // TODO(b/78024822): Consider adding "upgrade" to this set.
158 constexpr char const* kHttp2InvalidHeaderNames[] = {
159 "connection", "host", "keep-alive", "proxy-connection",
160 "transfer-encoding", "",
161 };
162
163 constexpr char const* kHttp2InvalidHeaderNamesOld[] = {
164 "connection", "host", "keep-alive", "proxy-connection", "transfer-encoding",
165 };
166
GetInvalidHttp2HeaderSet()167 const InvalidHeaderSet& GetInvalidHttp2HeaderSet() {
168 if (!GetQuicheReloadableFlag(quic, quic_verify_request_headers_2)) {
169 static const auto* invalid_header_set_old =
170 new InvalidHeaderSet(std::begin(http2::kHttp2InvalidHeaderNamesOld),
171 std::end(http2::kHttp2InvalidHeaderNamesOld));
172 return *invalid_header_set_old;
173 }
174 QUICHE_RELOADABLE_FLAG_COUNT_N(quic_verify_request_headers_2, 3, 3);
175 static const auto* invalid_header_set =
176 new InvalidHeaderSet(std::begin(http2::kHttp2InvalidHeaderNames),
177 std::end(http2::kHttp2InvalidHeaderNames));
178 return *invalid_header_set;
179 }
180
181 } // namespace http2
182