1 // Copyright 2022 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <grpc/support/port_platform.h>
16 
17 #include "src/core/ext/transport/chaotic_good/frame.h"
18 
19 #include <string.h>
20 
21 #include <cstdint>
22 #include <limits>
23 #include <utility>
24 
25 #include "absl/status/status.h"
26 #include "absl/status/statusor.h"
27 
28 #include <grpc/slice.h>
29 #include <grpc/support/log.h>
30 
31 #include "src/core/lib/gprpp/bitset.h"
32 #include "src/core/lib/gprpp/no_destruct.h"
33 #include "src/core/lib/gprpp/status_helper.h"
34 #include "src/core/lib/slice/slice.h"
35 #include "src/core/lib/slice/slice_buffer.h"
36 
37 namespace grpc_core {
38 namespace chaotic_good {
39 
40 namespace {
__anon8c38c9af0202null41 const NoDestruct<Slice> kZeroSlice{[] {
42   // Frame header size is fixed to 24 bytes.
43   auto slice = GRPC_SLICE_MALLOC(24);
44   memset(GRPC_SLICE_START_PTR(slice), 0, 24);
45   return slice;
46 }()};
47 
48 class FrameSerializer {
49  public:
FrameSerializer(FrameType type,uint32_t stream_id)50   explicit FrameSerializer(FrameType type, uint32_t stream_id)
51       : header_{type, {}, stream_id, 0, 0, 0, 0} {
52     output_.AppendIndexed(kZeroSlice->Copy());
53   }
54   // If called, must be called before AddTrailers, Finish.
AddHeaders()55   SliceBuffer& AddHeaders() {
56     header_.flags.set(0);
57     return output_;
58   }
59   // If called, must be called before Finish.
AddTrailers()60   SliceBuffer& AddTrailers() {
61     header_.flags.set(1);
62     return output_;
63   }
64 
Finish()65   SliceBuffer Finish() {
66     header_.Serialize(
67         GRPC_SLICE_START_PTR(output_.c_slice_buffer()->slices[0]));
68     return std::move(output_);
69   }
70 
71  private:
72   FrameHeader header_;
73   SliceBuffer output_;
74 };
75 
76 class FrameDeserializer {
77  public:
FrameDeserializer(const FrameHeader & header,SliceBuffer & input)78   FrameDeserializer(const FrameHeader& header, SliceBuffer& input)
79       : header_(header), input_(input) {}
header() const80   const FrameHeader& header() const { return header_; }
81   // If called, must be called before ReceiveTrailers, Finish.
ReceiveHeaders()82   absl::StatusOr<SliceBuffer> ReceiveHeaders() {
83     return Take(header_.header_length);
84   }
85   // If called, must be called before Finish.
ReceiveTrailers()86   absl::StatusOr<SliceBuffer> ReceiveTrailers() {
87     return Take(header_.trailer_length);
88   }
89 
90   // Return message length to get payload size in data plane.
GetMessageLength() const91   uint32_t GetMessageLength() const { return header_.message_length; }
92   // Return message padding to get padding size in data plane.
GetMessagePadding() const93   uint32_t GetMessagePadding() const { return header_.message_padding; }
94 
Finish()95   absl::Status Finish() { return absl::OkStatus(); }
96 
97  private:
Take(uint32_t length)98   absl::StatusOr<SliceBuffer> Take(uint32_t length) {
99     if (length == 0) return SliceBuffer{};
100     if (input_.Length() < length) {
101       return absl::InvalidArgumentError(
102           "Frame too short (insufficient payload)");
103     }
104     SliceBuffer out;
105     input_.MoveFirstNBytesIntoSliceBuffer(length, out);
106     return std::move(out);
107   }
108   FrameHeader header_;
109   SliceBuffer& input_;
110 };
111 
112 template <typename Metadata>
ReadMetadata(HPackParser * parser,absl::StatusOr<SliceBuffer> maybe_slices,uint32_t stream_id,bool is_header,bool is_client)113 absl::StatusOr<Arena::PoolPtr<Metadata>> ReadMetadata(
114     HPackParser* parser, absl::StatusOr<SliceBuffer> maybe_slices,
115     uint32_t stream_id, bool is_header, bool is_client) {
116   if (!maybe_slices.ok()) return maybe_slices.status();
117   auto& slices = *maybe_slices;
118   Arena::PoolPtr<Metadata> metadata;
119   parser->BeginFrame(
120       metadata.get(), std::numeric_limits<uint32_t>::max(),
121       std::numeric_limits<uint32_t>::max(),
122       is_header ? HPackParser::Boundary::EndOfHeaders
123                 : HPackParser::Boundary::EndOfStream,
124       HPackParser::Priority::None,
125       HPackParser::LogInfo{stream_id,
126                            is_header ? HPackParser::LogInfo::Type::kHeaders
127                                      : HPackParser::LogInfo::Type::kTrailers,
128                            is_client});
129   for (size_t i = 0; i < slices.Count(); i++) {
130     GRPC_RETURN_IF_ERROR(
131         parser->Parse(slices.c_slice_at(i), i == slices.Count() - 1));
132   }
133   parser->FinishFrame();
134   return std::move(metadata);
135 }
136 }  // namespace
137 
Deserialize(HPackParser *,const FrameHeader & header,SliceBuffer & slice_buffer)138 absl::Status SettingsFrame::Deserialize(HPackParser*, const FrameHeader& header,
139                                         SliceBuffer& slice_buffer) {
140   if (header.type != FrameType::kSettings) {
141     return absl::InvalidArgumentError("Expected settings frame");
142   }
143   if (header.flags.any()) {
144     return absl::InvalidArgumentError("Unexpected flags");
145   }
146   FrameDeserializer deserializer(header, slice_buffer);
147   return deserializer.Finish();
148 }
149 
Serialize(HPackCompressor *) const150 SliceBuffer SettingsFrame::Serialize(HPackCompressor*) const {
151   FrameSerializer serializer(FrameType::kSettings, 0);
152   return serializer.Finish();
153 }
154 
Deserialize(HPackParser * parser,const FrameHeader & header,SliceBuffer & slice_buffer)155 absl::Status ClientFragmentFrame::Deserialize(HPackParser* parser,
156                                               const FrameHeader& header,
157                                               SliceBuffer& slice_buffer) {
158   if (header.stream_id == 0) {
159     return absl::InvalidArgumentError("Expected non-zero stream id");
160   }
161   stream_id = header.stream_id;
162   if (header.type != FrameType::kFragment) {
163     return absl::InvalidArgumentError("Expected fragment frame");
164   }
165   FrameDeserializer deserializer(header, slice_buffer);
166   if (header.flags.is_set(0)) {
167     auto r = ReadMetadata<ClientMetadata>(parser, deserializer.ReceiveHeaders(),
168                                           header.stream_id, true, true);
169     if (!r.ok()) return r.status();
170   }
171   if (header.flags.is_set(1)) {
172     if (header.trailer_length != 0) {
173       return absl::InvalidArgumentError("Unexpected trailer length");
174     }
175     end_of_stream = true;
176   } else {
177     end_of_stream = false;
178   }
179   return deserializer.Finish();
180 }
181 
Serialize(HPackCompressor * encoder) const182 SliceBuffer ClientFragmentFrame::Serialize(HPackCompressor* encoder) const {
183   GPR_ASSERT(stream_id != 0);
184   FrameSerializer serializer(FrameType::kFragment, stream_id);
185   if (headers.get() != nullptr) {
186     encoder->EncodeRawHeaders(*headers.get(), serializer.AddHeaders());
187   }
188   if (end_of_stream) {
189     serializer.AddTrailers();
190   }
191   return serializer.Finish();
192 }
193 
Deserialize(HPackParser * parser,const FrameHeader & header,SliceBuffer & slice_buffer)194 absl::Status ServerFragmentFrame::Deserialize(HPackParser* parser,
195                                               const FrameHeader& header,
196                                               SliceBuffer& slice_buffer) {
197   if (header.stream_id == 0) {
198     return absl::InvalidArgumentError("Expected non-zero stream id");
199   }
200   stream_id = header.stream_id;
201   if (header.type != FrameType::kFragment) {
202     return absl::InvalidArgumentError("Expected fragment frame");
203   }
204   FrameDeserializer deserializer(header, slice_buffer);
205   if (header.flags.is_set(0)) {
206     auto r = ReadMetadata<ServerMetadata>(parser, deserializer.ReceiveHeaders(),
207                                           header.stream_id, true, false);
208     if (!r.ok()) return r.status();
209   }
210   if (header.flags.is_set(1)) {
211     auto r = ReadMetadata<ServerMetadata>(
212         parser, deserializer.ReceiveTrailers(), header.stream_id, false, false);
213   }
214   return deserializer.Finish();
215 }
216 
Serialize(HPackCompressor * encoder) const217 SliceBuffer ServerFragmentFrame::Serialize(HPackCompressor* encoder) const {
218   GPR_ASSERT(stream_id != 0);
219   FrameSerializer serializer(FrameType::kFragment, stream_id);
220   if (headers.get() != nullptr) {
221     encoder->EncodeRawHeaders(*headers.get(), serializer.AddHeaders());
222   }
223   if (trailers.get() != nullptr) {
224     encoder->EncodeRawHeaders(*trailers.get(), serializer.AddTrailers());
225   }
226   return serializer.Finish();
227 }
228 
Deserialize(HPackParser *,const FrameHeader & header,SliceBuffer & slice_buffer)229 absl::Status CancelFrame::Deserialize(HPackParser*, const FrameHeader& header,
230                                       SliceBuffer& slice_buffer) {
231   if (header.type != FrameType::kCancel) {
232     return absl::InvalidArgumentError("Expected cancel frame");
233   }
234   if (header.flags.any()) {
235     return absl::InvalidArgumentError("Unexpected flags");
236   }
237   if (header.stream_id == 0) {
238     return absl::InvalidArgumentError("Expected non-zero stream id");
239   }
240   FrameDeserializer deserializer(header, slice_buffer);
241   stream_id = header.stream_id;
242   return deserializer.Finish();
243 }
244 
Serialize(HPackCompressor *) const245 SliceBuffer CancelFrame::Serialize(HPackCompressor*) const {
246   GPR_ASSERT(stream_id != 0);
247   FrameSerializer serializer(FrameType::kCancel, stream_id);
248   return serializer.Finish();
249 }
250 
251 }  // namespace chaotic_good
252 }  // namespace grpc_core
253