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 #ifndef QUICHE_HTTP2_HTTP2_STRUCTURES_H_ 6 #define QUICHE_HTTP2_HTTP2_STRUCTURES_H_ 7 8 // Defines structs for various fixed sized structures in HTTP/2. 9 // 10 // Those structs with multiple fields have constructors that take arguments in 11 // the same order as their encoding (which may be different from their order 12 // in the struct). For single field structs, use aggregate initialization if 13 // desired, e.g.: 14 // 15 // Http2RstStreamFields var{Http2ErrorCode::ENHANCE_YOUR_CALM}; 16 // or: 17 // SomeFunc(Http2RstStreamFields{Http2ErrorCode::ENHANCE_YOUR_CALM}); 18 // 19 // Each struct includes a static method EncodedSize which returns the number 20 // of bytes of the encoding. 21 // 22 // With the exception of Http2FrameHeader, all the types are named 23 // Http2<X>Fields, where X is the title-case form of the frame which always 24 // includes the fields; the "always" is to cover the case of the PRIORITY frame; 25 // its fields optionally appear in the HEADERS frame, but the struct is called 26 // Http2PriorityFields. 27 28 #include <stddef.h> 29 30 #include <cstdint> 31 #include <ostream> 32 #include <string> 33 34 #include "quiche/http2/http2_constants.h" 35 #include "quiche/common/platform/api/quiche_export.h" 36 #include "quiche/common/platform/api/quiche_logging.h" 37 38 namespace http2 { 39 40 struct QUICHE_EXPORT Http2FrameHeader { Http2FrameHeaderHttp2FrameHeader41 Http2FrameHeader() {} Http2FrameHeaderHttp2FrameHeader42 Http2FrameHeader(uint32_t payload_length, Http2FrameType type, uint8_t flags, 43 uint32_t stream_id) 44 : payload_length(payload_length), 45 stream_id(stream_id), 46 type(type), 47 flags(flags) { 48 QUICHE_DCHECK_LT(payload_length, static_cast<uint32_t>(1 << 24)) 49 << "Payload Length is only a 24 bit field\n" 50 << ToString(); 51 } 52 EncodedSizeHttp2FrameHeader53 static constexpr size_t EncodedSize() { return 9; } 54 55 // Keep the current value of those flags that are in 56 // valid_flags, and clear all the others. RetainFlagsHttp2FrameHeader57 void RetainFlags(uint8_t valid_flags) { flags = (flags & valid_flags); } 58 59 // Returns true if any of the flags in flag_mask are set, 60 // otherwise false. HasAnyFlagsHttp2FrameHeader61 bool HasAnyFlags(uint8_t flag_mask) const { return 0 != (flags & flag_mask); } 62 63 // Is the END_STREAM flag set? IsEndStreamHttp2FrameHeader64 bool IsEndStream() const { 65 QUICHE_DCHECK(type == Http2FrameType::DATA || 66 type == Http2FrameType::HEADERS) 67 << ToString(); 68 return (flags & Http2FrameFlag::END_STREAM) != 0; 69 } 70 71 // Is the ACK flag set? IsAckHttp2FrameHeader72 bool IsAck() const { 73 QUICHE_DCHECK(type == Http2FrameType::SETTINGS || 74 type == Http2FrameType::PING) 75 << ToString(); 76 return (flags & Http2FrameFlag::ACK) != 0; 77 } 78 79 // Is the END_HEADERS flag set? IsEndHeadersHttp2FrameHeader80 bool IsEndHeaders() const { 81 QUICHE_DCHECK(type == Http2FrameType::HEADERS || 82 type == Http2FrameType::PUSH_PROMISE || 83 type == Http2FrameType::CONTINUATION) 84 << ToString(); 85 return (flags & Http2FrameFlag::END_HEADERS) != 0; 86 } 87 88 // Is the PADDED flag set? IsPaddedHttp2FrameHeader89 bool IsPadded() const { 90 QUICHE_DCHECK(type == Http2FrameType::DATA || 91 type == Http2FrameType::HEADERS || 92 type == Http2FrameType::PUSH_PROMISE) 93 << ToString(); 94 return (flags & Http2FrameFlag::PADDED) != 0; 95 } 96 97 // Is the PRIORITY flag set? HasPriorityHttp2FrameHeader98 bool HasPriority() const { 99 QUICHE_DCHECK_EQ(type, Http2FrameType::HEADERS) << ToString(); 100 return (flags & Http2FrameFlag::PRIORITY) != 0; 101 } 102 103 // Does the encoding of this header start with "HTTP/", indicating that it 104 // might be from a non-HTTP/2 server. 105 bool IsProbableHttpResponse() const; 106 107 // Produce strings useful for debugging/logging messages. 108 std::string ToString() const; 109 std::string FlagsToString() const; 110 111 // 24 bit length of the payload after the header, including any padding. 112 // First field in encoding. 113 uint32_t payload_length; // 24 bits 114 115 // 31 bit stream id, with high bit (32nd bit) reserved (must be zero), 116 // and is cleared during decoding. 117 // Fourth field in encoding. 118 uint32_t stream_id; 119 120 // Type of the frame. 121 // Second field in encoding. 122 Http2FrameType type; 123 124 // Flag bits, with interpretations that depend upon the frame type. 125 // Flag bits not used by the frame type are cleared. 126 // Third field in encoding. 127 uint8_t flags; 128 }; 129 130 QUICHE_EXPORT bool operator==(const Http2FrameHeader& a, 131 const Http2FrameHeader& b); 132 QUICHE_EXPORT inline bool operator!=(const Http2FrameHeader& a, 133 const Http2FrameHeader& b) { 134 return !(a == b); 135 } 136 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 137 const Http2FrameHeader& v); 138 139 // Http2PriorityFields: 140 141 struct QUICHE_EXPORT Http2PriorityFields { Http2PriorityFieldsHttp2PriorityFields142 Http2PriorityFields() {} Http2PriorityFieldsHttp2PriorityFields143 Http2PriorityFields(uint32_t stream_dependency, uint32_t weight, 144 bool is_exclusive) 145 : stream_dependency(stream_dependency), 146 weight(weight), 147 is_exclusive(is_exclusive) { 148 // Can't have the high-bit set in the stream id because we need to use 149 // that for the EXCLUSIVE flag bit. 150 QUICHE_DCHECK_EQ(stream_dependency, stream_dependency & StreamIdMask()) 151 << "Stream Dependency is only a 31-bit field.\n" 152 << ToString(); 153 QUICHE_DCHECK_LE(1u, weight) << "Weight is too small."; 154 QUICHE_DCHECK_LE(weight, 256u) << "Weight is too large."; 155 } EncodedSizeHttp2PriorityFields156 static constexpr size_t EncodedSize() { return 5; } 157 158 // Produce strings useful for debugging/logging messages. 159 std::string ToString() const; 160 161 // A 31-bit stream identifier for the stream that this stream depends on. 162 uint32_t stream_dependency; 163 164 // Weight (1 to 256) is encoded as a byte in the range 0 to 255, so we 165 // add one when decoding, and store it in a field larger than a byte. 166 uint32_t weight; 167 168 // A single-bit flag indicating that the stream dependency is exclusive; 169 // extracted from high bit of stream dependency field during decoding. 170 bool is_exclusive; 171 }; 172 173 QUICHE_EXPORT bool operator==(const Http2PriorityFields& a, 174 const Http2PriorityFields& b); 175 QUICHE_EXPORT inline bool operator!=(const Http2PriorityFields& a, 176 const Http2PriorityFields& b) { 177 return !(a == b); 178 } 179 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 180 const Http2PriorityFields& v); 181 182 // Http2RstStreamFields: 183 184 struct QUICHE_EXPORT Http2RstStreamFields { EncodedSizeHttp2RstStreamFields185 static constexpr size_t EncodedSize() { return 4; } IsSupportedErrorCodeHttp2RstStreamFields186 bool IsSupportedErrorCode() const { 187 return IsSupportedHttp2ErrorCode(error_code); 188 } 189 190 Http2ErrorCode error_code; 191 }; 192 193 QUICHE_EXPORT bool operator==(const Http2RstStreamFields& a, 194 const Http2RstStreamFields& b); 195 QUICHE_EXPORT inline bool operator!=(const Http2RstStreamFields& a, 196 const Http2RstStreamFields& b) { 197 return !(a == b); 198 } 199 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 200 const Http2RstStreamFields& v); 201 202 // Http2SettingFields: 203 204 struct QUICHE_EXPORT Http2SettingFields { Http2SettingFieldsHttp2SettingFields205 Http2SettingFields() {} Http2SettingFieldsHttp2SettingFields206 Http2SettingFields(Http2SettingsParameter parameter, uint32_t value) 207 : parameter(parameter), value(value) {} EncodedSizeHttp2SettingFields208 static constexpr size_t EncodedSize() { return 6; } IsSupportedParameterHttp2SettingFields209 bool IsSupportedParameter() const { 210 return IsSupportedHttp2SettingsParameter(parameter); 211 } 212 213 Http2SettingsParameter parameter; 214 uint32_t value; 215 }; 216 217 QUICHE_EXPORT bool operator==(const Http2SettingFields& a, 218 const Http2SettingFields& b); 219 QUICHE_EXPORT inline bool operator!=(const Http2SettingFields& a, 220 const Http2SettingFields& b) { 221 return !(a == b); 222 } 223 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 224 const Http2SettingFields& v); 225 226 // Http2PushPromiseFields: 227 228 struct QUICHE_EXPORT Http2PushPromiseFields { EncodedSizeHttp2PushPromiseFields229 static constexpr size_t EncodedSize() { return 4; } 230 231 uint32_t promised_stream_id; 232 }; 233 234 QUICHE_EXPORT bool operator==(const Http2PushPromiseFields& a, 235 const Http2PushPromiseFields& b); 236 QUICHE_EXPORT inline bool operator!=(const Http2PushPromiseFields& a, 237 const Http2PushPromiseFields& b) { 238 return !(a == b); 239 } 240 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 241 const Http2PushPromiseFields& v); 242 243 // Http2PingFields: 244 245 struct QUICHE_EXPORT Http2PingFields { EncodedSizeHttp2PingFields246 static constexpr size_t EncodedSize() { return 8; } 247 248 uint8_t opaque_bytes[8]; 249 }; 250 251 QUICHE_EXPORT bool operator==(const Http2PingFields& a, 252 const Http2PingFields& b); 253 QUICHE_EXPORT inline bool operator!=(const Http2PingFields& a, 254 const Http2PingFields& b) { 255 return !(a == b); 256 } 257 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 258 const Http2PingFields& v); 259 260 // Http2GoAwayFields: 261 262 struct QUICHE_EXPORT Http2GoAwayFields { Http2GoAwayFieldsHttp2GoAwayFields263 Http2GoAwayFields() {} Http2GoAwayFieldsHttp2GoAwayFields264 Http2GoAwayFields(uint32_t last_stream_id, Http2ErrorCode error_code) 265 : last_stream_id(last_stream_id), error_code(error_code) {} EncodedSizeHttp2GoAwayFields266 static constexpr size_t EncodedSize() { return 8; } IsSupportedErrorCodeHttp2GoAwayFields267 bool IsSupportedErrorCode() const { 268 return IsSupportedHttp2ErrorCode(error_code); 269 } 270 271 uint32_t last_stream_id; 272 Http2ErrorCode error_code; 273 }; 274 275 QUICHE_EXPORT bool operator==(const Http2GoAwayFields& a, 276 const Http2GoAwayFields& b); 277 QUICHE_EXPORT inline bool operator!=(const Http2GoAwayFields& a, 278 const Http2GoAwayFields& b) { 279 return !(a == b); 280 } 281 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 282 const Http2GoAwayFields& v); 283 284 // Http2WindowUpdateFields: 285 286 struct QUICHE_EXPORT Http2WindowUpdateFields { EncodedSizeHttp2WindowUpdateFields287 static constexpr size_t EncodedSize() { return 4; } 288 289 // 31-bit, unsigned increase in the window size (only positive values are 290 // allowed). The high-bit is reserved for the future. 291 uint32_t window_size_increment; 292 }; 293 294 QUICHE_EXPORT bool operator==(const Http2WindowUpdateFields& a, 295 const Http2WindowUpdateFields& b); 296 QUICHE_EXPORT inline bool operator!=(const Http2WindowUpdateFields& a, 297 const Http2WindowUpdateFields& b) { 298 return !(a == b); 299 } 300 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 301 const Http2WindowUpdateFields& v); 302 303 // Http2AltSvcFields: 304 305 struct QUICHE_EXPORT Http2AltSvcFields { EncodedSizeHttp2AltSvcFields306 static constexpr size_t EncodedSize() { return 2; } 307 308 // This is the one fixed size portion of the ALTSVC payload. 309 uint16_t origin_length; 310 }; 311 312 QUICHE_EXPORT bool operator==(const Http2AltSvcFields& a, 313 const Http2AltSvcFields& b); 314 QUICHE_EXPORT inline bool operator!=(const Http2AltSvcFields& a, 315 const Http2AltSvcFields& b) { 316 return !(a == b); 317 } 318 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 319 const Http2AltSvcFields& v); 320 321 // Http2PriorityUpdateFields: 322 323 struct QUICHE_EXPORT Http2PriorityUpdateFields { Http2PriorityUpdateFieldsHttp2PriorityUpdateFields324 Http2PriorityUpdateFields() {} Http2PriorityUpdateFieldsHttp2PriorityUpdateFields325 Http2PriorityUpdateFields(uint32_t prioritized_stream_id) 326 : prioritized_stream_id(prioritized_stream_id) {} EncodedSizeHttp2PriorityUpdateFields327 static constexpr size_t EncodedSize() { return 4; } 328 329 // Produce strings useful for debugging/logging messages. 330 std::string ToString() const; 331 332 // The 31-bit stream identifier of the stream whose priority is updated. 333 uint32_t prioritized_stream_id; 334 }; 335 336 QUICHE_EXPORT bool operator==(const Http2PriorityUpdateFields& a, 337 const Http2PriorityUpdateFields& b); 338 QUICHE_EXPORT inline bool operator!=(const Http2PriorityUpdateFields& a, 339 const Http2PriorityUpdateFields& b) { 340 return !(a == b); 341 } 342 QUICHE_EXPORT std::ostream& operator<<(std::ostream& out, 343 const Http2PriorityUpdateFields& v); 344 345 } // namespace http2 346 347 #endif // QUICHE_HTTP2_HTTP2_STRUCTURES_H_ 348