| // Copyright 2016 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. | |
| #ifndef QUICHE_HTTP2_HTTP2_STRUCTURES_H_ | |
| #define QUICHE_HTTP2_HTTP2_STRUCTURES_H_ | |
| // Defines structs for various fixed sized structures in HTTP/2. | |
| // | |
| // Those structs with multiple fields have constructors that take arguments in | |
| // the same order as their encoding (which may be different from their order | |
| // in the struct). For single field structs, use aggregate initialization if | |
| // desired, e.g.: | |
| // | |
| // Http2RstStreamFields var{Http2ErrorCode::ENHANCE_YOUR_CALM}; | |
| // or: | |
| // SomeFunc(Http2RstStreamFields{Http2ErrorCode::ENHANCE_YOUR_CALM}); | |
| // | |
| // Each struct includes a static method EncodedSize which returns the number | |
| // of bytes of the encoding. | |
| // | |
| // With the exception of Http2FrameHeader, all the types are named | |
| // Http2<X>Fields, where X is the title-case form of the frame which always | |
| // includes the fields; the "always" is to cover the case of the PRIORITY frame; | |
| // its fields optionally appear in the HEADERS frame, but the struct is called | |
| // Http2PriorityFields. | |
| #include <stddef.h> | |
| #include <cstdint> | |
| #include <ostream> | |
| #include "net/third_party/quiche/src/http2/http2_constants.h" | |
| #include "net/third_party/quiche/src/http2/platform/api/http2_export.h" | |
| #include "net/third_party/quiche/src/http2/platform/api/http2_logging.h" | |
| #include "net/third_party/quiche/src/http2/platform/api/http2_string.h" | |
| namespace http2 { | |
| struct HTTP2_EXPORT_PRIVATE Http2FrameHeader { | |
| Http2FrameHeader() {} | |
| Http2FrameHeader(uint32_t payload_length, | |
| Http2FrameType type, | |
| uint8_t flags, | |
| uint32_t stream_id) | |
| : payload_length(payload_length), | |
| stream_id(stream_id), | |
| type(type), | |
| flags(static_cast<Http2FrameFlag>(flags)) { | |
| DCHECK_LT(payload_length, static_cast<uint32_t>(1 << 24)) | |
| << "Payload Length is only a 24 bit field\n" | |
| << ToString(); | |
| } | |
| static constexpr size_t EncodedSize() { return 9; } | |
| // Keep the current value of those flags that are in | |
| // valid_flags, and clear all the others. | |
| void RetainFlags(uint8_t valid_flags) { | |
| flags = static_cast<Http2FrameFlag>(flags & valid_flags); | |
| } | |
| // Returns true if any of the flags in flag_mask are set, | |
| // otherwise false. | |
| bool HasAnyFlags(uint8_t flag_mask) const { return 0 != (flags & flag_mask); } | |
| // Is the END_STREAM flag set? | |
| bool IsEndStream() const { | |
| DCHECK(type == Http2FrameType::DATA || type == Http2FrameType::HEADERS) | |
| << ToString(); | |
| return (flags & Http2FrameFlag::END_STREAM) != 0; | |
| } | |
| // Is the ACK flag set? | |
| bool IsAck() const { | |
| DCHECK(type == Http2FrameType::SETTINGS || type == Http2FrameType::PING) | |
| << ToString(); | |
| return (flags & Http2FrameFlag::ACK) != 0; | |
| } | |
| // Is the END_HEADERS flag set? | |
| bool IsEndHeaders() const { | |
| DCHECK(type == Http2FrameType::HEADERS || | |
| type == Http2FrameType::PUSH_PROMISE || | |
| type == Http2FrameType::CONTINUATION) | |
| << ToString(); | |
| return (flags & Http2FrameFlag::END_HEADERS) != 0; | |
| } | |
| // Is the PADDED flag set? | |
| bool IsPadded() const { | |
| DCHECK(type == Http2FrameType::DATA || type == Http2FrameType::HEADERS || | |
| type == Http2FrameType::PUSH_PROMISE) | |
| << ToString(); | |
| return (flags & Http2FrameFlag::PADDED) != 0; | |
| } | |
| // Is the PRIORITY flag set? | |
| bool HasPriority() const { | |
| DCHECK_EQ(type, Http2FrameType::HEADERS) << ToString(); | |
| return (flags & Http2FrameFlag::PRIORITY) != 0; | |
| } | |
| // Does the encoding of this header start with "HTTP/", indicating that it | |
| // might be from a non-HTTP/2 server. | |
| bool IsProbableHttpResponse() const; | |
| // Produce strings useful for debugging/logging messages. | |
| Http2String ToString() const; | |
| Http2String FlagsToString() const; | |
| // 24 bit length of the payload after the header, including any padding. | |
| // First field in encoding. | |
| uint32_t payload_length; // 24 bits | |
| // 31 bit stream id, with high bit (32nd bit) reserved (must be zero), | |
| // and is cleared during decoding. | |
| // Fourth field in encoding. | |
| uint32_t stream_id; | |
| // Type of the frame. | |
| // Second field in encoding. | |
| Http2FrameType type; | |
| // Flag bits, with interpretations that depend upon the frame type. | |
| // Flag bits not used by the frame type are cleared. | |
| // Third field in encoding. | |
| Http2FrameFlag flags; | |
| }; | |
| HTTP2_EXPORT_PRIVATE bool operator==(const Http2FrameHeader& a, | |
| const Http2FrameHeader& b); | |
| HTTP2_EXPORT_PRIVATE inline bool operator!=(const Http2FrameHeader& a, | |
| const Http2FrameHeader& b) { | |
| return !(a == b); | |
| } | |
| HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
| const Http2FrameHeader& v); | |
| // Http2PriorityFields: | |
| struct HTTP2_EXPORT_PRIVATE Http2PriorityFields { | |
| Http2PriorityFields() {} | |
| Http2PriorityFields(uint32_t stream_dependency, | |
| uint32_t weight, | |
| bool is_exclusive) | |
| : stream_dependency(stream_dependency), | |
| weight(weight), | |
| is_exclusive(is_exclusive) { | |
| // Can't have the high-bit set in the stream id because we need to use | |
| // that for the EXCLUSIVE flag bit. | |
| DCHECK_EQ(stream_dependency, stream_dependency & StreamIdMask()) | |
| << "Stream Dependency is only a 31-bit field.\n" | |
| << ToString(); | |
| DCHECK_LE(1u, weight) << "Weight is too small."; | |
| DCHECK_LE(weight, 256u) << "Weight is too large."; | |
| } | |
| static constexpr size_t EncodedSize() { return 5; } | |
| // Produce strings useful for debugging/logging messages. | |
| Http2String ToString() const; | |
| // A 31-bit stream identifier for the stream that this stream depends on. | |
| uint32_t stream_dependency; | |
| // Weight (1 to 256) is encoded as a byte in the range 0 to 255, so we | |
| // add one when decoding, and store it in a field larger than a byte. | |
| uint32_t weight; | |
| // A single-bit flag indicating that the stream dependency is exclusive; | |
| // extracted from high bit of stream dependency field during decoding. | |
| bool is_exclusive; | |
| }; | |
| HTTP2_EXPORT_PRIVATE bool operator==(const Http2PriorityFields& a, | |
| const Http2PriorityFields& b); | |
| HTTP2_EXPORT_PRIVATE inline bool operator!=(const Http2PriorityFields& a, | |
| const Http2PriorityFields& b) { | |
| return !(a == b); | |
| } | |
| HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
| const Http2PriorityFields& v); | |
| // Http2RstStreamFields: | |
| struct Http2RstStreamFields { | |
| static constexpr size_t EncodedSize() { return 4; } | |
| bool IsSupportedErrorCode() const { | |
| return IsSupportedHttp2ErrorCode(error_code); | |
| } | |
| Http2ErrorCode error_code; | |
| }; | |
| HTTP2_EXPORT_PRIVATE bool operator==(const Http2RstStreamFields& a, | |
| const Http2RstStreamFields& b); | |
| HTTP2_EXPORT_PRIVATE inline bool operator!=(const Http2RstStreamFields& a, | |
| const Http2RstStreamFields& b) { | |
| return !(a == b); | |
| } | |
| HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
| const Http2RstStreamFields& v); | |
| // Http2SettingFields: | |
| struct Http2SettingFields { | |
| Http2SettingFields() {} | |
| Http2SettingFields(Http2SettingsParameter parameter, uint32_t value) | |
| : parameter(parameter), value(value) {} | |
| static constexpr size_t EncodedSize() { return 6; } | |
| bool IsSupportedParameter() const { | |
| return IsSupportedHttp2SettingsParameter(parameter); | |
| } | |
| Http2SettingsParameter parameter; | |
| uint32_t value; | |
| }; | |
| HTTP2_EXPORT_PRIVATE bool operator==(const Http2SettingFields& a, | |
| const Http2SettingFields& b); | |
| HTTP2_EXPORT_PRIVATE inline bool operator!=(const Http2SettingFields& a, | |
| const Http2SettingFields& b) { | |
| return !(a == b); | |
| } | |
| HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
| const Http2SettingFields& v); | |
| // Http2PushPromiseFields: | |
| struct Http2PushPromiseFields { | |
| static constexpr size_t EncodedSize() { return 4; } | |
| uint32_t promised_stream_id; | |
| }; | |
| HTTP2_EXPORT_PRIVATE bool operator==(const Http2PushPromiseFields& a, | |
| const Http2PushPromiseFields& b); | |
| HTTP2_EXPORT_PRIVATE inline bool operator!=(const Http2PushPromiseFields& a, | |
| const Http2PushPromiseFields& b) { | |
| return !(a == b); | |
| } | |
| HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
| const Http2PushPromiseFields& v); | |
| // Http2PingFields: | |
| struct Http2PingFields { | |
| static constexpr size_t EncodedSize() { return 8; } | |
| uint8_t opaque_bytes[8]; | |
| }; | |
| HTTP2_EXPORT_PRIVATE bool operator==(const Http2PingFields& a, | |
| const Http2PingFields& b); | |
| HTTP2_EXPORT_PRIVATE inline bool operator!=(const Http2PingFields& a, | |
| const Http2PingFields& b) { | |
| return !(a == b); | |
| } | |
| HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
| const Http2PingFields& v); | |
| // Http2GoAwayFields: | |
| struct Http2GoAwayFields { | |
| Http2GoAwayFields() {} | |
| Http2GoAwayFields(uint32_t last_stream_id, Http2ErrorCode error_code) | |
| : last_stream_id(last_stream_id), error_code(error_code) {} | |
| static constexpr size_t EncodedSize() { return 8; } | |
| bool IsSupportedErrorCode() const { | |
| return IsSupportedHttp2ErrorCode(error_code); | |
| } | |
| uint32_t last_stream_id; | |
| Http2ErrorCode error_code; | |
| }; | |
| HTTP2_EXPORT_PRIVATE bool operator==(const Http2GoAwayFields& a, | |
| const Http2GoAwayFields& b); | |
| HTTP2_EXPORT_PRIVATE inline bool operator!=(const Http2GoAwayFields& a, | |
| const Http2GoAwayFields& b) { | |
| return !(a == b); | |
| } | |
| HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
| const Http2GoAwayFields& v); | |
| // Http2WindowUpdateFields: | |
| struct Http2WindowUpdateFields { | |
| static constexpr size_t EncodedSize() { return 4; } | |
| // 31-bit, unsigned increase in the window size (only positive values are | |
| // allowed). The high-bit is reserved for the future. | |
| uint32_t window_size_increment; | |
| }; | |
| HTTP2_EXPORT_PRIVATE bool operator==(const Http2WindowUpdateFields& a, | |
| const Http2WindowUpdateFields& b); | |
| HTTP2_EXPORT_PRIVATE inline bool operator!=(const Http2WindowUpdateFields& a, | |
| const Http2WindowUpdateFields& b) { | |
| return !(a == b); | |
| } | |
| HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
| const Http2WindowUpdateFields& v); | |
| // Http2AltSvcFields: | |
| struct Http2AltSvcFields { | |
| static constexpr size_t EncodedSize() { return 2; } | |
| // This is the one fixed size portion of the ALTSVC payload. | |
| uint16_t origin_length; | |
| }; | |
| HTTP2_EXPORT_PRIVATE bool operator==(const Http2AltSvcFields& a, | |
| const Http2AltSvcFields& b); | |
| HTTP2_EXPORT_PRIVATE inline bool operator!=(const Http2AltSvcFields& a, | |
| const Http2AltSvcFields& b) { | |
| return !(a == b); | |
| } | |
| HTTP2_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& out, | |
| const Http2AltSvcFields& v); | |
| } // namespace http2 | |
| #endif // QUICHE_HTTP2_HTTP2_STRUCTURES_H_ |