LCOV - code coverage report
Current view: top level - source/common/grpc - codec.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 2 9 22.2 %
Date: 2024-01-05 06:35:25 Functions: 2 9 22.2 %

          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

Generated by: LCOV version 1.15