/proc/self/cwd/source/common/grpc/codec.h
Line | Count | Source (jump to first uncovered line) |
1 | | #pragma once |
2 | | |
3 | | #include <array> |
4 | | #include <cstdint> |
5 | | #include <vector> |
6 | | |
7 | | #include "envoy/buffer/buffer.h" |
8 | | |
9 | | namespace Envoy { |
10 | | namespace Grpc { |
11 | | // Last bit for an expanded message without compression. |
12 | | const uint8_t GRPC_FH_DEFAULT = 0b0u; |
13 | | // Last bit for a compressed message. |
14 | | const uint8_t GRPC_FH_COMPRESSED = 0b1u; |
15 | | // Bit specifies end-of-stream response in Connect. |
16 | | const uint8_t CONNECT_FH_EOS = 0b10u; |
17 | | |
18 | | constexpr uint64_t GRPC_FRAME_HEADER_SIZE = sizeof(uint8_t) + sizeof(uint32_t); |
19 | | |
20 | | enum class CompressionAlgorithm { None, Gzip }; |
21 | | |
22 | | struct Frame { |
23 | | uint8_t flags_; |
24 | | uint32_t length_; |
25 | | Buffer::InstancePtr data_; |
26 | | }; |
27 | | |
28 | | class Encoder { |
29 | | public: |
30 | | Encoder(); |
31 | | |
32 | | // Creates a new GRPC data frame with the given flags and length. |
33 | | // @param flags supplies the GRPC data frame flags. |
34 | | // @param length supplies the GRPC data frame length. |
35 | | // @param output the buffer to store the encoded data. Its size must be 5. |
36 | | void newFrame(uint8_t flags, uint64_t length, std::array<uint8_t, 5>& output); |
37 | | |
38 | | // Prepend the gRPC frame into the buffer. |
39 | | // @param flags supplies the GRPC data frame flags. |
40 | | // @param buffer the full buffer with the message payload. |
41 | | void prependFrameHeader(uint8_t flags, Buffer::Instance& buffer); |
42 | | |
43 | | // Prepend the gRPC frame into the buffer. |
44 | | // @param flags supplies the GRPC data frame flags. |
45 | | // @param buffer the buffer with the first part of the message payload. |
46 | | // @param message_length the total length of the message, which may be longer |
47 | | // than buffer. |
48 | | void prependFrameHeader(uint8_t flags, Buffer::Instance& buffer, uint32_t message_length); |
49 | | }; |
50 | | |
51 | | // Wire format (http://www.grpc.io/docs/guides/wire.html) of GRPC data frame |
52 | | // header: |
53 | | // |
54 | | // --------------------------------------------------------------------- |
55 | | // |R|R|R|R|R|R|R|C| L | L | L | L | |
56 | | // --------------------------------------------------------------------- |
57 | | // Flag (1 byte) Message Length (4 bytes) |
58 | | // |
59 | | // A fixed header consists of five bytes. |
60 | | // The first byte is the Flag. The last one "C" bit indicates if the message |
61 | | // is compressed or not (0 is uncompressed, 1 is compressed). The other seven |
62 | | // "R" bits are reserved for future use. |
63 | | // The next four "L" bytes represent the message length in BigEndian format. |
64 | | enum class State { |
65 | | // Waiting for decoding the flags (1 byte) of the GRPC data frame. |
66 | | FhFlag, |
67 | | // Waiting for decoding the 1st byte of the length (4 bytes in total) of the |
68 | | // GRPC data frame. |
69 | | FhLen0, |
70 | | // Waiting for decoding the 2nd byte of the length (4 bytes in total) of the |
71 | | // GRPC data frame. |
72 | | FhLen1, |
73 | | // Waiting for decoding the 3rd byte of the length (4 bytes in total) of the |
74 | | // GRPC data frame. |
75 | | FhLen2, |
76 | | // Waiting for decoding the 4th byte of the length (4 bytes in total) of the |
77 | | // GRPC data frame. |
78 | | FhLen3, |
79 | | // Waiting for decoding the data. |
80 | | Data, |
81 | | }; |
82 | | |
83 | | class FrameInspector { |
84 | | public: |
85 | | // Inspects the given buffer with GRPC data frame and updates the frame count. |
86 | | // Invokes visitor callbacks for each frame in the following sequence: |
87 | | // "frameStart frameDataStart frameData* frameDataEnd" |
88 | | // If frameStart returns false, then the inspector aborts. |
89 | | // Returns the increase in the frame count. |
90 | | uint64_t inspect(const Buffer::Instance& input); |
91 | | |
92 | | // Returns the current frame count, corresponding to the request/response |
93 | | // message count. Counter is incremented on a frame start. |
94 | 104 | uint64_t frameCount() const { return count_; } |
95 | | |
96 | | // Returns the current state in the frame parsing. |
97 | 0 | State state() const { return state_; } |
98 | | |
99 | 22.7k | virtual ~FrameInspector() = default; |
100 | | |
101 | | protected: |
102 | 26 | virtual bool frameStart(uint8_t) { return true; } |
103 | 52 | virtual void frameDataStart() {} |
104 | 17 | virtual void frameData(uint8_t*, uint64_t) {} |
105 | 25 | virtual void frameDataEnd() {} |
106 | | |
107 | | State state_{State::FhFlag}; |
108 | | union { |
109 | | // Note that this union does not rely on bytes being arranged accurately for a |
110 | | // uint32_t, it merely shares the storage. absl::big_endian is used to deserialize |
111 | | // the bytes correctly once they are populated. |
112 | | uint32_t length_{0}; |
113 | | uint8_t length_as_bytes_[4]; |
114 | | }; |
115 | | uint64_t count_{0}; |
116 | | // Default value 0 means there is no limitation on maximum frame length. |
117 | | uint32_t max_frame_length_{0}; |
118 | | // When `max_frame_length_` is configured, this flag will be true if frame length is larger than |
119 | | // `max_frame_length_`. |
120 | | bool is_frame_oversized_{false}; |
121 | | }; |
122 | | |
123 | | class Decoder : public FrameInspector { |
124 | | public: |
125 | | // Decodes the given buffer with GRPC data frame. Drains the input buffer when |
126 | | // decoding succeeded (returns true). If the input is not sufficient to make a |
127 | | // complete GRPC data frame, it will be buffered in the decoder. If a decoding |
128 | | // error happened, the input buffer remains unchanged. |
129 | | // @param input supplies the binary octets wrapped in a GRPC data frame. |
130 | | // @param output supplies the buffer to store the decoded data. |
131 | | // @return absl::status whether the decoding succeeded or not. |
132 | | absl::Status decode(Buffer::Instance& input, std::vector<Frame>& output); |
133 | | |
134 | | // Determine the length of the current frame being decoded. This is useful when supplying a |
135 | | // partial frame to decode() and wanting to know how many more bytes need to be read to complete |
136 | | // the frame. |
137 | 0 | uint32_t length() const { return frame_.length_; } |
138 | | |
139 | | // Indicates whether it has buffered any partial data. |
140 | 0 | bool hasBufferedData() const { return state_ != State::FhFlag; } |
141 | | |
142 | | // Configures the maximum frame length. |
143 | 935 | void setMaxFrameLength(uint32_t max_frame_length) { max_frame_length_ = max_frame_length; } |
144 | | |
145 | | protected: |
146 | | bool frameStart(uint8_t) override; |
147 | | void frameDataStart() override; |
148 | | void frameData(uint8_t*, uint64_t) override; |
149 | | void frameDataEnd() override; |
150 | | |
151 | | private: |
152 | | Frame frame_; |
153 | | std::vector<Frame>* output_{nullptr}; |
154 | | bool decoding_error_{false}; |
155 | | }; |
156 | | |
157 | | } // namespace Grpc |
158 | | } // namespace Envoy |