Line data Source code
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 0 : 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 447 : virtual ~FrameInspector() = default; 100 : 101 : protected: 102 0 : virtual bool frameStart(uint8_t) { return true; } 103 1 : virtual void frameDataStart() {} 104 0 : virtual void frameData(uint8_t*, uint64_t) {} 105 0 : 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 : }; 117 : 118 : class Decoder : public FrameInspector { 119 : public: 120 : // Decodes the given buffer with GRPC data frame. Drains the input buffer when 121 : // decoding succeeded (returns true). If the input is not sufficient to make a 122 : // complete GRPC data frame, it will be buffered in the decoder. If a decoding 123 : // error happened, the input buffer remains unchanged. 124 : // @param input supplies the binary octets wrapped in a GRPC data frame. 125 : // @param output supplies the buffer to store the decoded data. 126 : // @return bool whether the decoding succeeded or not. 127 : bool decode(Buffer::Instance& input, std::vector<Frame>& output); 128 : 129 : // Determine the length of the current frame being decoded. This is useful when supplying a 130 : // partial frame to decode() and wanting to know how many more bytes need to be read to complete 131 : // the frame. 132 0 : uint32_t length() const { return frame_.length_; } 133 : 134 : // Indicates whether it has buffered any partial data. 135 0 : bool hasBufferedData() const { return state_ != State::FhFlag; } 136 : 137 : protected: 138 : bool frameStart(uint8_t) override; 139 : void frameDataStart() override; 140 : void frameData(uint8_t*, uint64_t) override; 141 : void frameDataEnd() override; 142 : 143 : private: 144 : Frame frame_; 145 : std::vector<Frame>* output_{nullptr}; 146 : bool decoding_error_{false}; 147 : }; 148 : 149 : } // namespace Grpc 150 : } // namespace Envoy