1 // 2 // 3 // Copyright 2015 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // 17 // 18 19 #ifndef GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H 20 #define GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H 21 22 #include <grpc/slice.h> 23 #include <grpc/support/port_platform.h> 24 #include <stddef.h> 25 #include <stdint.h> 26 27 #include <string> 28 #include <utility> 29 #include <vector> 30 31 #include "absl/random/bit_gen_ref.h" 32 #include "absl/strings/str_cat.h" 33 #include "absl/strings/string_view.h" 34 #include "absl/types/optional.h" 35 #include "absl/types/span.h" 36 #include "absl/types/variant.h" 37 #include "src/core/ext/transport/chttp2/transport/hpack_parse_result.h" 38 #include "src/core/ext/transport/chttp2/transport/hpack_parser_table.h" 39 #include "src/core/ext/transport/chttp2/transport/legacy_frame.h" 40 #include "src/core/lib/iomgr/error.h" 41 #include "src/core/lib/slice/slice.h" 42 #include "src/core/lib/slice/slice_refcount.h" 43 #include "src/core/lib/transport/metadata_batch.h" 44 #include "src/core/telemetry/call_tracer.h" 45 #include "src/core/util/random_early_detection.h" 46 47 // IWYU pragma: no_include <type_traits> 48 49 namespace grpc_core { 50 51 // Top level interface for parsing a sequence of header, continuation frames. 52 class HPackParser { 53 public: 54 // What kind of stream boundary is provided by this frame? 55 enum class Boundary : uint8_t { 56 // More continuations are expected 57 None, 58 // This marks the end of headers, so data frames should follow 59 EndOfHeaders, 60 // This marks the end of headers *and* the end of the stream 61 EndOfStream 62 }; 63 // What kind of priority is represented in the next frame 64 enum class Priority : uint8_t { 65 // No priority field 66 None, 67 // Yes there's a priority field 68 Included 69 }; 70 // Details about a frame we only need to know for logging 71 struct LogInfo { 72 // The stream ID 73 uint32_t stream_id; 74 // Headers or trailers? 75 enum Type : uint8_t { 76 kHeaders, 77 kTrailers, 78 kDontKnow, 79 }; 80 Type type; 81 // Client or server? 82 bool is_client; 83 }; 84 85 HPackParser(); 86 ~HPackParser(); 87 88 // Non-copyable 89 HPackParser(const HPackParser&) = delete; 90 HPackParser& operator=(const HPackParser&) = delete; 91 HPackParser(HPackParser&&) = default; 92 HPackParser& operator=(HPackParser&&) = default; 93 94 // Begin parsing a new frame 95 // Sink receives each parsed header, 96 void BeginFrame(grpc_metadata_batch* metadata_buffer, 97 uint32_t metadata_size_soft_limit, 98 uint32_t metadata_size_hard_limit, Boundary boundary, 99 Priority priority, LogInfo log_info); 100 // Start throwing away any received headers after parsing them. StopBufferingFrame()101 void StopBufferingFrame() { metadata_buffer_ = nullptr; } 102 // Parse one slice worth of data 103 grpc_error_handle Parse(const grpc_slice& slice, bool is_last, 104 absl::BitGenRef bitsrc, 105 CallTracerAnnotationInterface* call_tracer); 106 // Reset state ready for the next BeginFrame 107 void FinishFrame(); 108 109 // Retrieve the associated hpack table (for tests, debugging) hpack_table()110 HPackTable* hpack_table() { return &state_.hpack_table; } 111 // Is the current frame a boundary of some sort is_boundary()112 bool is_boundary() const { return boundary_ != Boundary::None; } 113 // Is the current frame the end of a stream is_eof()114 bool is_eof() const { return boundary_ == Boundary::EndOfStream; } 115 116 // How many bytes are buffered (for tests to assert on) buffered_bytes()117 size_t buffered_bytes() const { return unparsed_bytes_.size(); } 118 119 private: 120 // Helper classes: see implementation 121 class Parser; 122 class Input; 123 124 // Helper to parse a string and turn it into a slice with appropriate memory 125 // management characteristics 126 class String { 127 public: 128 // StringResult carries both a HpackParseStatus and the parsed string 129 struct StringResult; 130 String()131 String() : value_(absl::Span<const uint8_t>()) {} 132 String(const String&) = delete; 133 String& operator=(const String&) = delete; String(String && other)134 String(String&& other) noexcept : value_(std::move(other.value_)) { 135 other.value_ = absl::Span<const uint8_t>(); 136 } 137 String& operator=(String&& other) noexcept { 138 value_ = std::move(other.value_); 139 other.value_ = absl::Span<const uint8_t>(); 140 return *this; 141 } 142 143 // Take the value and leave this empty 144 Slice Take(); 145 146 // Return a reference to the value as a string view 147 absl::string_view string_view() const; 148 149 // Parse a non-binary string 150 static StringResult Parse(Input* input, bool is_huff, size_t length); 151 152 // Parse a binary string 153 static StringResult ParseBinary(Input* input, bool is_huff, size_t length); 154 155 private: 156 void AppendBytes(const uint8_t* data, size_t length); String(std::vector<uint8_t> v)157 explicit String(std::vector<uint8_t> v) : value_(std::move(v)) {} String(absl::Span<const uint8_t> v)158 explicit String(absl::Span<const uint8_t> v) : value_(v) {} String(grpc_slice_refcount * r,const uint8_t * begin,const uint8_t * end)159 String(grpc_slice_refcount* r, const uint8_t* begin, const uint8_t* end) 160 : value_(Slice::FromRefcountAndBytes(r, begin, end)) {} 161 162 // Parse some huffman encoded bytes, using output(uint8_t b) to emit each 163 // decoded byte. 164 template <typename Out> 165 static HpackParseStatus ParseHuff(Input* input, uint32_t length, 166 Out output); 167 168 // Parse some uncompressed string bytes. 169 static StringResult ParseUncompressed(Input* input, uint32_t length, 170 uint32_t wire_size); 171 172 // Turn base64 encoded bytes into not base64 encoded bytes. 173 static StringResult Unbase64(String s); 174 175 // Main loop for Unbase64 176 static absl::optional<std::vector<uint8_t>> Unbase64Loop( 177 const uint8_t* cur, const uint8_t* end); 178 179 absl::variant<Slice, absl::Span<const uint8_t>, std::vector<uint8_t>> 180 value_; 181 }; 182 183 // Prefix for a string 184 struct StringPrefix { 185 // Number of bytes in input for string 186 uint32_t length; 187 // Is it huffman compressed 188 bool huff; 189 ToStringStringPrefix190 std::string ToString() const { 191 return absl::StrCat(length, " bytes ", 192 huff ? "huffman compressed" : "uncompressed"); 193 } 194 }; 195 196 // Current parse state 197 // ┌───┐ 198 // │Top│ 199 // └┬─┬┘ 200 // │┌▽────────────────┐ 201 // ││ParsingKeyLength │ 202 // │└┬───────────────┬┘ 203 // │┌▽─────────────┐┌▽──────────────┐ 204 // ││ParsingKeyBody││SkippingKeyBody│ 205 // │└┬─────────────┘└───┬───────────┘ 206 // ┌▽─▽────────────────┐┌▽──────────────────┐ 207 // │ParsingValueLength ││SkippingValueLength│ 208 // └┬─────────────────┬┘└┬──────────────────┘ 209 // ┌▽───────────────┐┌▽──▽─────────────┐ 210 // │ParsingValueBody││SkippingValueBody│ 211 // └────────────────┘└─────────────────┘ 212 enum class ParseState : uint8_t { 213 // Start of one opcode 214 kTop, 215 // Parsing a literal keys length 216 kParsingKeyLength, 217 // Parsing a literal key 218 kParsingKeyBody, 219 // Skipping a literal key 220 kSkippingKeyBody, 221 // Parsing a literal value length 222 kParsingValueLength, 223 // Parsing a literal value 224 kParsingValueBody, 225 // Reading a literal value length (so we can skip it) 226 kSkippingValueLength, 227 // Skipping a literal value 228 kSkippingValueBody, 229 }; 230 231 // Shared state for Parser instances between slices. 232 struct InterSliceState { 233 HPackTable hpack_table; 234 // Error so far for this frame (set by class Input) 235 HpackParseResult frame_error; 236 // Error so far for this field (set by class Input) 237 HpackParseResult field_error; 238 // Length of frame so far. 239 uint32_t frame_length = 0; 240 // Length of the string being parsed 241 uint32_t string_length; 242 // RED for overly large metadata sets 243 RandomEarlyDetection metadata_early_detection; 244 // Should the current header be added to the hpack table? 245 bool add_to_table; 246 // Is the string being parsed huffman compressed? 247 bool is_string_huff_compressed; 248 // Is the value being parsed binary? 249 bool is_binary_header; 250 // How many more dynamic table updates are allowed 251 uint8_t dynamic_table_updates_allowed; 252 // Current parse state 253 ParseState parse_state = ParseState::kTop; 254 absl::variant<const HPackTable::Memento*, Slice> key; 255 }; 256 257 grpc_error_handle ParseInput(Input input, bool is_last, 258 CallTracerAnnotationInterface* call_tracer); 259 void ParseInputInner(Input* input); 260 GPR_ATTRIBUTE_NOINLINE 261 void HandleMetadataSoftSizeLimitExceeded(Input* input); 262 263 // Target metadata buffer 264 grpc_metadata_batch* metadata_buffer_ = nullptr; 265 266 // Bytes that could not be parsed last parsing round 267 std::vector<uint8_t> unparsed_bytes_; 268 // How many bytes would be needed before progress could be made? 269 size_t min_progress_size_ = 0; 270 // Buffer kind of boundary 271 // TODO(ctiller): see if we can move this argument to Parse, and avoid 272 // buffering. 273 Boundary boundary_; 274 // Buffer priority 275 // TODO(ctiller): see if we can move this argument to Parse, and avoid 276 // buffering. 277 Priority priority_; 278 // Information for logging 279 LogInfo log_info_; 280 InterSliceState state_; 281 }; 282 283 } // namespace grpc_core 284 285 // wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for 286 // the transport 287 grpc_error_handle grpc_chttp2_header_parser_parse(void* hpack_parser, 288 grpc_chttp2_transport* t, 289 grpc_chttp2_stream* s, 290 const grpc_slice& slice, 291 int is_last); 292 293 #endif // GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H 294