/proc/self/cwd/source/common/grpc/codec.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "source/common/grpc/codec.h" |
2 | | |
3 | | #include <array> |
4 | | #include <cstdint> |
5 | | #include <memory> |
6 | | #include <vector> |
7 | | |
8 | | #include "source/common/buffer/buffer_impl.h" |
9 | | |
10 | | #include "absl/container/fixed_array.h" |
11 | | |
12 | | namespace Envoy { |
13 | | namespace Grpc { |
14 | | |
15 | 1.12k | Encoder::Encoder() = default; |
16 | | |
17 | 1.12k | void Encoder::newFrame(uint8_t flags, uint64_t length, std::array<uint8_t, 5>& output) { |
18 | 1.12k | output[0] = flags; |
19 | 1.12k | absl::big_endian::Store32(&output[1], length); |
20 | 1.12k | } |
21 | | |
22 | 0 | void Encoder::prependFrameHeader(uint8_t flags, Buffer::Instance& buffer) { |
23 | 0 | prependFrameHeader(flags, buffer, buffer.length()); |
24 | 0 | } |
25 | | |
26 | 1 | void Encoder::prependFrameHeader(uint8_t flags, Buffer::Instance& buffer, uint32_t message_length) { |
27 | | // Compute the size of the payload and construct the length prefix. |
28 | 1 | std::array<uint8_t, Grpc::GRPC_FRAME_HEADER_SIZE> frame; |
29 | 1 | Grpc::Encoder().newFrame(flags, message_length, frame); |
30 | 1 | Buffer::OwnedImpl frame_buffer(frame.data(), frame.size()); |
31 | 1 | buffer.prepend(frame_buffer); |
32 | 1 | } |
33 | | |
34 | 16.9k | absl::Status Decoder::decode(Buffer::Instance& input, std::vector<Frame>& output) { |
35 | | // Make sure those flags are set to initial state. |
36 | 16.9k | decoding_error_ = false; |
37 | 16.9k | is_frame_oversized_ = false; |
38 | 16.9k | output_ = &output; |
39 | 16.9k | inspect(input); |
40 | 16.9k | output_ = nullptr; |
41 | | |
42 | 16.9k | if (decoding_error_) { |
43 | 634 | return absl::InternalError("Grpc decoding error"); |
44 | 634 | } |
45 | | |
46 | 16.2k | if (is_frame_oversized_) { |
47 | 0 | return absl::ResourceExhaustedError("Grpc frame length exceeds limit"); |
48 | 0 | } |
49 | | |
50 | 16.2k | input.drain(input.length()); |
51 | 16.2k | return absl::OkStatus(); |
52 | 16.2k | } |
53 | | |
54 | 50.9k | bool Decoder::frameStart(uint8_t flags) { |
55 | | // Unsupported flags. |
56 | 50.9k | if (flags & ~GRPC_FH_COMPRESSED) { |
57 | 634 | decoding_error_ = true; |
58 | 634 | return false; |
59 | 634 | } |
60 | 50.3k | frame_.flags_ = flags; |
61 | 50.3k | return true; |
62 | 50.9k | } |
63 | | |
64 | 49.6k | void Decoder::frameDataStart() { |
65 | 49.6k | frame_.length_ = length_; |
66 | 49.6k | frame_.data_ = std::make_unique<Buffer::OwnedImpl>(); |
67 | 49.6k | } |
68 | | |
69 | 10.5k | void Decoder::frameData(uint8_t* mem, uint64_t length) { frame_.data_->add(mem, length); } |
70 | | |
71 | 48.8k | void Decoder::frameDataEnd() { |
72 | 48.8k | output_->push_back(std::move(frame_)); |
73 | 48.8k | frame_.flags_ = 0; |
74 | 48.8k | frame_.length_ = 0; |
75 | 48.8k | frame_.data_ = nullptr; |
76 | 48.8k | } |
77 | | |
78 | 17.2k | uint64_t FrameInspector::inspect(const Buffer::Instance& data) { |
79 | 17.2k | uint64_t delta = 0; |
80 | 17.2k | for (const Buffer::RawSlice& slice : data.getRawSlices()) { |
81 | 14.0k | uint8_t* mem = reinterpret_cast<uint8_t*>(slice.mem_); |
82 | 14.0k | uint8_t* end = mem + slice.len_; |
83 | 275k | while (mem < end) { |
84 | 261k | uint8_t c = *mem; |
85 | 261k | switch (state_) { |
86 | 50.9k | case State::FhFlag: |
87 | 50.9k | if (!frameStart(c)) { |
88 | 634 | return delta; |
89 | 634 | } |
90 | 50.3k | count_ += 1; |
91 | 50.3k | delta += 1; |
92 | 50.3k | state_ = State::FhLen0; |
93 | 50.3k | mem++; |
94 | 50.3k | break; |
95 | 50.1k | case State::FhLen0: |
96 | 50.1k | length_as_bytes_[0] = c; |
97 | 50.1k | state_ = State::FhLen1; |
98 | 50.1k | mem++; |
99 | 50.1k | break; |
100 | 50.1k | case State::FhLen1: |
101 | 50.1k | length_as_bytes_[1] = c; |
102 | 50.1k | state_ = State::FhLen2; |
103 | 50.1k | mem++; |
104 | 50.1k | break; |
105 | 50.1k | case State::FhLen2: |
106 | 50.1k | length_as_bytes_[2] = c; |
107 | 50.1k | state_ = State::FhLen3; |
108 | 50.1k | mem++; |
109 | 50.1k | break; |
110 | 49.6k | case State::FhLen3: |
111 | 49.6k | length_as_bytes_[3] = c; |
112 | 49.6k | length_ = absl::big_endian::Load32(length_as_bytes_); |
113 | | // Compares the frame length against maximum length when `max_frame_length_` is configured, |
114 | 49.6k | if (max_frame_length_ != 0 && length_ > max_frame_length_) { |
115 | | // Set the flag to indicate the over-limit error and return. |
116 | 0 | is_frame_oversized_ = true; |
117 | 0 | return delta; |
118 | 0 | } |
119 | 49.6k | frameDataStart(); |
120 | 49.6k | if (length_ == 0) { |
121 | 44.3k | frameDataEnd(); |
122 | 44.3k | state_ = State::FhFlag; |
123 | 44.3k | } else { |
124 | 5.36k | state_ = State::Data; |
125 | 5.36k | } |
126 | 49.6k | mem++; |
127 | 49.6k | break; |
128 | 10.5k | case State::Data: |
129 | 10.5k | uint64_t remain_in_buffer = end - mem; |
130 | 10.5k | if (remain_in_buffer <= length_) { |
131 | 8.36k | frameData(mem, remain_in_buffer); |
132 | 8.36k | mem += remain_in_buffer; |
133 | 8.36k | length_ -= remain_in_buffer; |
134 | 8.36k | } else { |
135 | 2.18k | frameData(mem, length_); |
136 | 2.18k | mem += length_; |
137 | 2.18k | length_ = 0; |
138 | 2.18k | } |
139 | 10.5k | if (length_ == 0) { |
140 | 4.60k | frameDataEnd(); |
141 | 4.60k | state_ = State::FhFlag; |
142 | 4.60k | } |
143 | 10.5k | break; |
144 | 261k | } |
145 | 261k | } |
146 | 14.0k | } |
147 | 16.5k | return delta; |
148 | 17.2k | } |
149 | | |
150 | | } // namespace Grpc |
151 | | } // namespace Envoy |