Coverage Report

Created: 2024-09-19 09:45

/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