• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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