xref: /aosp_15_r20/external/pigweed/pw_grpc/connection.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_grpc/connection.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <cinttypes>
18*61c4878aSAndroid Build Coastguard Worker #include <cstring>
19*61c4878aSAndroid Build Coastguard Worker #include <string_view>
20*61c4878aSAndroid Build Coastguard Worker #include <type_traits>
21*61c4878aSAndroid Build Coastguard Worker 
22*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_chrono/system_clock.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_grpc_private/hpack.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_preprocessor/compiler.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_status/try.h"
28*61c4878aSAndroid Build Coastguard Worker 
29*61c4878aSAndroid Build Coastguard Worker namespace pw::grpc {
30*61c4878aSAndroid Build Coastguard Worker namespace internal {
31*61c4878aSAndroid Build Coastguard Worker 
32*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6
33*61c4878aSAndroid Build Coastguard Worker // Enum names left in naming style of RFC
34*61c4878aSAndroid Build Coastguard Worker enum class FrameType : uint8_t {
35*61c4878aSAndroid Build Coastguard Worker   DATA = 0x00,
36*61c4878aSAndroid Build Coastguard Worker   HEADERS = 0x01,
37*61c4878aSAndroid Build Coastguard Worker   PRIORITY = 0x02,
38*61c4878aSAndroid Build Coastguard Worker   RST_STREAM = 0x03,
39*61c4878aSAndroid Build Coastguard Worker   SETTINGS = 0x04,
40*61c4878aSAndroid Build Coastguard Worker   PUSH_PROMISE = 0x05,
41*61c4878aSAndroid Build Coastguard Worker   PING = 0x06,
42*61c4878aSAndroid Build Coastguard Worker   GOAWAY = 0x07,
43*61c4878aSAndroid Build Coastguard Worker   WINDOW_UPDATE = 0x08,
44*61c4878aSAndroid Build Coastguard Worker   CONTINUATION = 0x09,
45*61c4878aSAndroid Build Coastguard Worker };
46*61c4878aSAndroid Build Coastguard Worker 
47*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §4.1
48*61c4878aSAndroid Build Coastguard Worker constexpr size_t kFrameHeaderEncodedSize = 9;
49*61c4878aSAndroid Build Coastguard Worker struct FrameHeader {
50*61c4878aSAndroid Build Coastguard Worker   uint32_t payload_length;
51*61c4878aSAndroid Build Coastguard Worker   FrameType type;
52*61c4878aSAndroid Build Coastguard Worker   uint8_t flags;
53*61c4878aSAndroid Build Coastguard Worker   StreamId stream_id;
54*61c4878aSAndroid Build Coastguard Worker };
55*61c4878aSAndroid Build Coastguard Worker 
56*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §7
57*61c4878aSAndroid Build Coastguard Worker // Enum names left in naming style of RFC
58*61c4878aSAndroid Build Coastguard Worker enum class Http2Error : uint32_t {
59*61c4878aSAndroid Build Coastguard Worker   NO_ERROR = 0x00,
60*61c4878aSAndroid Build Coastguard Worker   PROTOCOL_ERROR = 0x01,
61*61c4878aSAndroid Build Coastguard Worker   INTERNAL_ERROR = 0x02,
62*61c4878aSAndroid Build Coastguard Worker   FLOW_CONTROL_ERROR = 0x03,
63*61c4878aSAndroid Build Coastguard Worker   SETTINGS_TIMEOUT = 0x04,
64*61c4878aSAndroid Build Coastguard Worker   STREAM_CLOSED = 0x05,
65*61c4878aSAndroid Build Coastguard Worker   FRAME_SIZE_ERROR = 0x06,
66*61c4878aSAndroid Build Coastguard Worker   REFUSED_STREAM = 0x07,
67*61c4878aSAndroid Build Coastguard Worker   CANCEL = 0x08,
68*61c4878aSAndroid Build Coastguard Worker   COMPRESSION_ERROR = 0x09,
69*61c4878aSAndroid Build Coastguard Worker   CONNECT_ERROR = 0x0a,
70*61c4878aSAndroid Build Coastguard Worker   ENHANCE_YOUR_CALM = 0x0b,
71*61c4878aSAndroid Build Coastguard Worker   INADEQUATE_SECURITY = 0x0c,
72*61c4878aSAndroid Build Coastguard Worker   HTTP_1_1_REQUIRED = 0x0d,
73*61c4878aSAndroid Build Coastguard Worker };
74*61c4878aSAndroid Build Coastguard Worker 
75*61c4878aSAndroid Build Coastguard Worker }  // namespace internal
76*61c4878aSAndroid Build Coastguard Worker 
77*61c4878aSAndroid Build Coastguard Worker namespace {
78*61c4878aSAndroid Build Coastguard Worker 
79*61c4878aSAndroid Build Coastguard Worker using internal::FrameHeader;
80*61c4878aSAndroid Build Coastguard Worker using internal::FrameType;
81*61c4878aSAndroid Build Coastguard Worker using internal::Http2Error;
82*61c4878aSAndroid Build Coastguard Worker using internal::kMaxConcurrentStreams;
83*61c4878aSAndroid Build Coastguard Worker using internal::kMaxGrpcMessageSize;
84*61c4878aSAndroid Build Coastguard Worker 
85*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §3.4
86*61c4878aSAndroid Build Coastguard Worker constexpr std::string_view kExpectedConnectionPrefaceLiteral(
87*61c4878aSAndroid Build Coastguard Worker     "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n");
88*61c4878aSAndroid Build Coastguard Worker 
89*61c4878aSAndroid Build Coastguard Worker static_assert(kMaxMethodNameSize == kHpackMaxStringSize);
90*61c4878aSAndroid Build Coastguard Worker 
91*61c4878aSAndroid Build Coastguard Worker enum {
92*61c4878aSAndroid Build Coastguard Worker   FLAGS_ACK = 0x01,
93*61c4878aSAndroid Build Coastguard Worker   FLAGS_END_STREAM = 0x01,
94*61c4878aSAndroid Build Coastguard Worker   FLAGS_END_HEADERS = 0x04,
95*61c4878aSAndroid Build Coastguard Worker   FLAGS_PADDED = 0x08,
96*61c4878aSAndroid Build Coastguard Worker   FLAGS_PRIORITY = 0x20,
97*61c4878aSAndroid Build Coastguard Worker };
98*61c4878aSAndroid Build Coastguard Worker 
99*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.5.2
100*61c4878aSAndroid Build Coastguard Worker enum SettingType : uint16_t {
101*61c4878aSAndroid Build Coastguard Worker   SETTINGS_HEADER_TABLE_SIZE = 0x01,
102*61c4878aSAndroid Build Coastguard Worker   SETTINGS_ENABLE_PUSH = 0x02,
103*61c4878aSAndroid Build Coastguard Worker   SETTINGS_MAX_CONCURRENT_STREAMS = 0x03,
104*61c4878aSAndroid Build Coastguard Worker   SETTINGS_INITIAL_WINDOW_SIZE = 0x04,
105*61c4878aSAndroid Build Coastguard Worker   SETTINGS_MAX_FRAME_SIZE = 0x05,
106*61c4878aSAndroid Build Coastguard Worker   SETTINGS_MAX_HEADER_LIST_SIZE = 0x06,
107*61c4878aSAndroid Build Coastguard Worker };
108*61c4878aSAndroid Build Coastguard Worker 
ReadExactly(stream::Reader & reader,ByteSpan buffer)109*61c4878aSAndroid Build Coastguard Worker Status ReadExactly(stream::Reader& reader, ByteSpan buffer) {
110*61c4878aSAndroid Build Coastguard Worker   size_t bytes_read = 0;
111*61c4878aSAndroid Build Coastguard Worker   while (bytes_read < buffer.size()) {
112*61c4878aSAndroid Build Coastguard Worker     PW_TRY_ASSIGN(auto out, reader.Read(buffer.subspan(bytes_read)));
113*61c4878aSAndroid Build Coastguard Worker     bytes_read += out.size();
114*61c4878aSAndroid Build Coastguard Worker   }
115*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
116*61c4878aSAndroid Build Coastguard Worker }
117*61c4878aSAndroid Build Coastguard Worker 
ReadFrameHeader(stream::Reader & reader)118*61c4878aSAndroid Build Coastguard Worker Result<FrameHeader> ReadFrameHeader(stream::Reader& reader) {
119*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, internal::kFrameHeaderEncodedSize> buffer;
120*61c4878aSAndroid Build Coastguard Worker   PW_TRY(ReadExactly(reader, buffer));
121*61c4878aSAndroid Build Coastguard Worker 
122*61c4878aSAndroid Build Coastguard Worker   // RFC 9113 §4.1
123*61c4878aSAndroid Build Coastguard Worker   FrameHeader out;
124*61c4878aSAndroid Build Coastguard Worker   ByteBuilder builder(as_writable_bytes(span{buffer}));
125*61c4878aSAndroid Build Coastguard Worker   auto it = builder.begin();
126*61c4878aSAndroid Build Coastguard Worker   auto type_and_length = it.ReadUint32(endian::big);
127*61c4878aSAndroid Build Coastguard Worker   out.payload_length = type_and_length >> 8;
128*61c4878aSAndroid Build Coastguard Worker   out.type = static_cast<FrameType>(type_and_length & 0xff);
129*61c4878aSAndroid Build Coastguard Worker   out.flags = it.ReadUint8();
130*61c4878aSAndroid Build Coastguard Worker   out.stream_id = it.ReadUint32(endian::big) & 0x7fffffff;
131*61c4878aSAndroid Build Coastguard Worker   return out;
132*61c4878aSAndroid Build Coastguard Worker }
133*61c4878aSAndroid Build Coastguard Worker 
134*61c4878aSAndroid Build Coastguard Worker template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
ToNetworkOrder(T value)135*61c4878aSAndroid Build Coastguard Worker constexpr T ToNetworkOrder(T value) {
136*61c4878aSAndroid Build Coastguard Worker   return bytes::ConvertOrder(/*from=*/endian::native,
137*61c4878aSAndroid Build Coastguard Worker                              /*to=*/endian::big,
138*61c4878aSAndroid Build Coastguard Worker                              value);
139*61c4878aSAndroid Build Coastguard Worker }
140*61c4878aSAndroid Build Coastguard Worker 
141*61c4878aSAndroid Build Coastguard Worker template <typename T, std::enable_if_t<std::is_enum_v<T>, bool> = true>
ToNetworkOrder(T value)142*61c4878aSAndroid Build Coastguard Worker constexpr std::underlying_type_t<T> ToNetworkOrder(T value) {
143*61c4878aSAndroid Build Coastguard Worker   return ToNetworkOrder(static_cast<std::underlying_type_t<T>>(value));
144*61c4878aSAndroid Build Coastguard Worker }
145*61c4878aSAndroid Build Coastguard Worker 
146*61c4878aSAndroid Build Coastguard Worker // Use this instead of FrameHeader when writing frames.
PW_PACKED(struct)147*61c4878aSAndroid Build Coastguard Worker PW_PACKED(struct) WireFrameHeader {
148*61c4878aSAndroid Build Coastguard Worker   WireFrameHeader(FrameHeader h)
149*61c4878aSAndroid Build Coastguard Worker       : payload_length_and_type(ToNetworkOrder(h.payload_length << 8 |
150*61c4878aSAndroid Build Coastguard Worker                                                static_cast<uint32_t>(h.type))),
151*61c4878aSAndroid Build Coastguard Worker         flags(h.flags),
152*61c4878aSAndroid Build Coastguard Worker         stream_id(ToNetworkOrder(h.stream_id)) {}
153*61c4878aSAndroid Build Coastguard Worker 
154*61c4878aSAndroid Build Coastguard Worker   uint32_t payload_length_and_type;
155*61c4878aSAndroid Build Coastguard Worker   uint8_t flags;
156*61c4878aSAndroid Build Coastguard Worker   uint32_t stream_id;
157*61c4878aSAndroid Build Coastguard Worker };
158*61c4878aSAndroid Build Coastguard Worker 
159*61c4878aSAndroid Build Coastguard Worker template <typename T>
AsBytes(T & object)160*61c4878aSAndroid Build Coastguard Worker ConstByteSpan AsBytes(T& object) {
161*61c4878aSAndroid Build Coastguard Worker   return as_bytes(span<T, 1>{&object, 1});
162*61c4878aSAndroid Build Coastguard Worker }
163*61c4878aSAndroid Build Coastguard Worker 
164*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.1
SendData(SendQueue & send_queue,StreamId stream_id,ConstByteSpan payload1,ConstByteSpan payload2)165*61c4878aSAndroid Build Coastguard Worker Status SendData(SendQueue& send_queue,
166*61c4878aSAndroid Build Coastguard Worker                 StreamId stream_id,
167*61c4878aSAndroid Build Coastguard Worker                 ConstByteSpan payload1,
168*61c4878aSAndroid Build Coastguard Worker                 ConstByteSpan payload2) {
169*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Send DATA with id=%" PRIu32 " len1=%" PRIu32
170*61c4878aSAndroid Build Coastguard Worker                " len2=%" PRIu32,
171*61c4878aSAndroid Build Coastguard Worker                stream_id,
172*61c4878aSAndroid Build Coastguard Worker                static_cast<uint32_t>(payload1.size()),
173*61c4878aSAndroid Build Coastguard Worker                static_cast<uint32_t>(payload2.size()));
174*61c4878aSAndroid Build Coastguard Worker   WireFrameHeader frame(FrameHeader{
175*61c4878aSAndroid Build Coastguard Worker       .payload_length =
176*61c4878aSAndroid Build Coastguard Worker           static_cast<uint32_t>(payload1.size() + payload2.size()),
177*61c4878aSAndroid Build Coastguard Worker       .type = FrameType::DATA,
178*61c4878aSAndroid Build Coastguard Worker       .flags = 0,
179*61c4878aSAndroid Build Coastguard Worker       .stream_id = stream_id,
180*61c4878aSAndroid Build Coastguard Worker   });
181*61c4878aSAndroid Build Coastguard Worker   std::array<ConstByteSpan, 3> data_vector = {AsBytes(frame)};
182*61c4878aSAndroid Build Coastguard Worker   size_t i = 1;
183*61c4878aSAndroid Build Coastguard Worker   if (!payload1.empty()) {
184*61c4878aSAndroid Build Coastguard Worker     data_vector[i++] = payload1;
185*61c4878aSAndroid Build Coastguard Worker   }
186*61c4878aSAndroid Build Coastguard Worker   if (!payload2.empty()) {
187*61c4878aSAndroid Build Coastguard Worker     data_vector[i++] = payload2;
188*61c4878aSAndroid Build Coastguard Worker   }
189*61c4878aSAndroid Build Coastguard Worker   PW_TRY(send_queue.SendBytesVector(span{data_vector.data(), i}));
190*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
191*61c4878aSAndroid Build Coastguard Worker }
192*61c4878aSAndroid Build Coastguard Worker 
193*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.2
SendHeaders(SendQueue & send_queue,StreamId stream_id,ConstByteSpan payload1,ConstByteSpan payload2,bool end_stream)194*61c4878aSAndroid Build Coastguard Worker Status SendHeaders(SendQueue& send_queue,
195*61c4878aSAndroid Build Coastguard Worker                    StreamId stream_id,
196*61c4878aSAndroid Build Coastguard Worker                    ConstByteSpan payload1,
197*61c4878aSAndroid Build Coastguard Worker                    ConstByteSpan payload2,
198*61c4878aSAndroid Build Coastguard Worker                    bool end_stream) {
199*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Send HEADERS with id=%" PRIu32 " len1=%" PRIu32
200*61c4878aSAndroid Build Coastguard Worker                " len2=%" PRIu32 " end=%d",
201*61c4878aSAndroid Build Coastguard Worker                stream_id,
202*61c4878aSAndroid Build Coastguard Worker                static_cast<uint32_t>(payload1.size()),
203*61c4878aSAndroid Build Coastguard Worker                static_cast<uint32_t>(payload2.size()),
204*61c4878aSAndroid Build Coastguard Worker                end_stream);
205*61c4878aSAndroid Build Coastguard Worker   WireFrameHeader frame(FrameHeader{
206*61c4878aSAndroid Build Coastguard Worker       .payload_length =
207*61c4878aSAndroid Build Coastguard Worker           static_cast<uint32_t>(payload1.size() + payload2.size()),
208*61c4878aSAndroid Build Coastguard Worker       .type = FrameType::HEADERS,
209*61c4878aSAndroid Build Coastguard Worker       .flags = FLAGS_END_HEADERS,
210*61c4878aSAndroid Build Coastguard Worker       .stream_id = stream_id,
211*61c4878aSAndroid Build Coastguard Worker   });
212*61c4878aSAndroid Build Coastguard Worker 
213*61c4878aSAndroid Build Coastguard Worker   if (end_stream) {
214*61c4878aSAndroid Build Coastguard Worker     frame.flags |= FLAGS_END_STREAM;
215*61c4878aSAndroid Build Coastguard Worker   }
216*61c4878aSAndroid Build Coastguard Worker 
217*61c4878aSAndroid Build Coastguard Worker   std::array<ConstByteSpan, 3> headers_vector = {AsBytes(frame)};
218*61c4878aSAndroid Build Coastguard Worker   size_t i = 1;
219*61c4878aSAndroid Build Coastguard Worker   if (!payload1.empty()) {
220*61c4878aSAndroid Build Coastguard Worker     headers_vector[i++] = payload1;
221*61c4878aSAndroid Build Coastguard Worker   }
222*61c4878aSAndroid Build Coastguard Worker   if (!payload2.empty()) {
223*61c4878aSAndroid Build Coastguard Worker     headers_vector[i++] = payload2;
224*61c4878aSAndroid Build Coastguard Worker   }
225*61c4878aSAndroid Build Coastguard Worker   PW_TRY(send_queue.SendBytesVector(span{headers_vector.data(), i}));
226*61c4878aSAndroid Build Coastguard Worker 
227*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
228*61c4878aSAndroid Build Coastguard Worker }
229*61c4878aSAndroid Build Coastguard Worker 
230*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.4
SendRstStream(SendQueue & send_queue,StreamId stream_id,Http2Error code)231*61c4878aSAndroid Build Coastguard Worker Status SendRstStream(SendQueue& send_queue,
232*61c4878aSAndroid Build Coastguard Worker                      StreamId stream_id,
233*61c4878aSAndroid Build Coastguard Worker                      Http2Error code) {
234*61c4878aSAndroid Build Coastguard Worker   PW_PACKED(struct) RstStreamFrame {
235*61c4878aSAndroid Build Coastguard Worker     WireFrameHeader header;
236*61c4878aSAndroid Build Coastguard Worker     uint32_t error_code;
237*61c4878aSAndroid Build Coastguard Worker   };
238*61c4878aSAndroid Build Coastguard Worker   RstStreamFrame frame{
239*61c4878aSAndroid Build Coastguard Worker       .header = WireFrameHeader(FrameHeader{
240*61c4878aSAndroid Build Coastguard Worker           .payload_length = 4,
241*61c4878aSAndroid Build Coastguard Worker           .type = FrameType::RST_STREAM,
242*61c4878aSAndroid Build Coastguard Worker           .flags = 0,
243*61c4878aSAndroid Build Coastguard Worker           .stream_id = stream_id,
244*61c4878aSAndroid Build Coastguard Worker       }),
245*61c4878aSAndroid Build Coastguard Worker       .error_code = ToNetworkOrder(code),
246*61c4878aSAndroid Build Coastguard Worker   };
247*61c4878aSAndroid Build Coastguard Worker   PW_TRY(send_queue.SendBytes(AsBytes(frame)));
248*61c4878aSAndroid Build Coastguard Worker 
249*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
250*61c4878aSAndroid Build Coastguard Worker }
251*61c4878aSAndroid Build Coastguard Worker 
252*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.9
SendWindowUpdates(SendQueue & send_queue,StreamId stream_id,uint32_t increment)253*61c4878aSAndroid Build Coastguard Worker Status SendWindowUpdates(SendQueue& send_queue,
254*61c4878aSAndroid Build Coastguard Worker                          StreamId stream_id,
255*61c4878aSAndroid Build Coastguard Worker                          uint32_t increment) {
256*61c4878aSAndroid Build Coastguard Worker   // It is illegal to send updates with increment=0.
257*61c4878aSAndroid Build Coastguard Worker   if (increment == 0) {
258*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
259*61c4878aSAndroid Build Coastguard Worker   }
260*61c4878aSAndroid Build Coastguard Worker   if (increment & 0x80000000) {
261*61c4878aSAndroid Build Coastguard Worker     // Upper bit is reserved, error.
262*61c4878aSAndroid Build Coastguard Worker     return Status::InvalidArgument();
263*61c4878aSAndroid Build Coastguard Worker   }
264*61c4878aSAndroid Build Coastguard Worker 
265*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Send WINDOW_UPDATE frames with id=%" PRIu32
266*61c4878aSAndroid Build Coastguard Worker                " increment=%" PRIu32,
267*61c4878aSAndroid Build Coastguard Worker                stream_id,
268*61c4878aSAndroid Build Coastguard Worker                increment);
269*61c4878aSAndroid Build Coastguard Worker 
270*61c4878aSAndroid Build Coastguard Worker   PW_PACKED(struct) WindowUpdateFrame {
271*61c4878aSAndroid Build Coastguard Worker     WireFrameHeader header;
272*61c4878aSAndroid Build Coastguard Worker     uint32_t increment;
273*61c4878aSAndroid Build Coastguard Worker   };
274*61c4878aSAndroid Build Coastguard Worker   WindowUpdateFrame frames[2] = {
275*61c4878aSAndroid Build Coastguard Worker       {
276*61c4878aSAndroid Build Coastguard Worker           .header = WireFrameHeader(FrameHeader{
277*61c4878aSAndroid Build Coastguard Worker               .payload_length = 4,
278*61c4878aSAndroid Build Coastguard Worker               .type = FrameType::WINDOW_UPDATE,
279*61c4878aSAndroid Build Coastguard Worker               .flags = 0,
280*61c4878aSAndroid Build Coastguard Worker               .stream_id = 0,
281*61c4878aSAndroid Build Coastguard Worker           }),
282*61c4878aSAndroid Build Coastguard Worker           .increment = ToNetworkOrder(increment),
283*61c4878aSAndroid Build Coastguard Worker       },
284*61c4878aSAndroid Build Coastguard Worker       {
285*61c4878aSAndroid Build Coastguard Worker           .header = WireFrameHeader(FrameHeader{
286*61c4878aSAndroid Build Coastguard Worker               .payload_length = 4,
287*61c4878aSAndroid Build Coastguard Worker               .type = FrameType::WINDOW_UPDATE,
288*61c4878aSAndroid Build Coastguard Worker               .flags = 0,
289*61c4878aSAndroid Build Coastguard Worker               .stream_id = stream_id,
290*61c4878aSAndroid Build Coastguard Worker           }),
291*61c4878aSAndroid Build Coastguard Worker           .increment = ToNetworkOrder(increment),
292*61c4878aSAndroid Build Coastguard Worker       },
293*61c4878aSAndroid Build Coastguard Worker   };
294*61c4878aSAndroid Build Coastguard Worker   PW_TRY(send_queue.SendBytes(as_bytes(span{frames})));
295*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
296*61c4878aSAndroid Build Coastguard Worker }
297*61c4878aSAndroid Build Coastguard Worker 
298*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.5
SendSettingsAck(SendQueue & send_queue)299*61c4878aSAndroid Build Coastguard Worker Status SendSettingsAck(SendQueue& send_queue) {
300*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Send SETTINGS ACK");
301*61c4878aSAndroid Build Coastguard Worker   WireFrameHeader frame(FrameHeader{
302*61c4878aSAndroid Build Coastguard Worker       .payload_length = 0,
303*61c4878aSAndroid Build Coastguard Worker       .type = FrameType::SETTINGS,
304*61c4878aSAndroid Build Coastguard Worker       .flags = FLAGS_ACK,
305*61c4878aSAndroid Build Coastguard Worker       .stream_id = 0,
306*61c4878aSAndroid Build Coastguard Worker   });
307*61c4878aSAndroid Build Coastguard Worker   PW_TRY(send_queue.SendBytes(AsBytes(frame)));
308*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
309*61c4878aSAndroid Build Coastguard Worker }
310*61c4878aSAndroid Build Coastguard Worker 
311*61c4878aSAndroid Build Coastguard Worker }  // namespace
312*61c4878aSAndroid Build Coastguard Worker 
Connection(stream::ReaderWriter & socket,SendQueue & send_queue,RequestCallbacks & callbacks,allocator::Allocator * message_assembly_allocator)313*61c4878aSAndroid Build Coastguard Worker Connection::Connection(stream::ReaderWriter& socket,
314*61c4878aSAndroid Build Coastguard Worker                        SendQueue& send_queue,
315*61c4878aSAndroid Build Coastguard Worker                        RequestCallbacks& callbacks,
316*61c4878aSAndroid Build Coastguard Worker                        allocator::Allocator* message_assembly_allocator)
317*61c4878aSAndroid Build Coastguard Worker     : socket_(socket),
318*61c4878aSAndroid Build Coastguard Worker       send_queue_(send_queue),
319*61c4878aSAndroid Build Coastguard Worker       reader_(*this, callbacks),
320*61c4878aSAndroid Build Coastguard Worker       writer_(*this) {
321*61c4878aSAndroid Build Coastguard Worker   LockState()->message_assembly_allocator_ = message_assembly_allocator;
322*61c4878aSAndroid Build Coastguard Worker }
323*61c4878aSAndroid Build Coastguard Worker 
ProcessFrame()324*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::ProcessFrame() {
325*61c4878aSAndroid Build Coastguard Worker   if (!received_connection_preface_) {
326*61c4878aSAndroid Build Coastguard Worker     return Status::FailedPrecondition();
327*61c4878aSAndroid Build Coastguard Worker   }
328*61c4878aSAndroid Build Coastguard Worker 
329*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(auto frame, ReadFrameHeader(connection_.socket_.as_reader()));
330*61c4878aSAndroid Build Coastguard Worker   switch (frame.type) {
331*61c4878aSAndroid Build Coastguard Worker     // Frames that we handle.
332*61c4878aSAndroid Build Coastguard Worker     case FrameType::DATA:
333*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessDataFrame(frame));
334*61c4878aSAndroid Build Coastguard Worker       break;
335*61c4878aSAndroid Build Coastguard Worker     case FrameType::HEADERS:
336*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessHeadersFrame(frame));
337*61c4878aSAndroid Build Coastguard Worker       break;
338*61c4878aSAndroid Build Coastguard Worker     case FrameType::PRIORITY:
339*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessIgnoredFrame(frame));
340*61c4878aSAndroid Build Coastguard Worker       break;
341*61c4878aSAndroid Build Coastguard Worker     case FrameType::RST_STREAM:
342*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessRstStreamFrame(frame));
343*61c4878aSAndroid Build Coastguard Worker       break;
344*61c4878aSAndroid Build Coastguard Worker     case FrameType::SETTINGS:
345*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessSettingsFrame(frame, /*send_ack=*/true));
346*61c4878aSAndroid Build Coastguard Worker       break;
347*61c4878aSAndroid Build Coastguard Worker     case FrameType::PING:
348*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessPingFrame(frame));
349*61c4878aSAndroid Build Coastguard Worker       break;
350*61c4878aSAndroid Build Coastguard Worker     case FrameType::WINDOW_UPDATE:
351*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessWindowUpdateFrame(frame));
352*61c4878aSAndroid Build Coastguard Worker       break;
353*61c4878aSAndroid Build Coastguard Worker 
354*61c4878aSAndroid Build Coastguard Worker     // Frames that trigger an immediate connection close.
355*61c4878aSAndroid Build Coastguard Worker     case FrameType::GOAWAY:
356*61c4878aSAndroid Build Coastguard Worker       PW_LOG_ERROR("Client sent GOAWAY");
357*61c4878aSAndroid Build Coastguard Worker       // don't bother sending GOAWAY in response
358*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
359*61c4878aSAndroid Build Coastguard Worker     case FrameType::PUSH_PROMISE:
360*61c4878aSAndroid Build Coastguard Worker       PW_LOG_ERROR("Client sent PUSH_PROMISE");
361*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::PROTOCOL_ERROR);
362*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
363*61c4878aSAndroid Build Coastguard Worker     case FrameType::CONTINUATION:
364*61c4878aSAndroid Build Coastguard Worker       PW_LOG_ERROR("Client sent CONTINUATION: unsupported");
365*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::INTERNAL_ERROR);
366*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
367*61c4878aSAndroid Build Coastguard Worker   }
368*61c4878aSAndroid Build Coastguard Worker 
369*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
370*61c4878aSAndroid Build Coastguard Worker }
371*61c4878aSAndroid Build Coastguard Worker 
372*61c4878aSAndroid Build Coastguard Worker pw::Result<std::reference_wrapper<Connection::Stream>>
LookupStream(StreamId id)373*61c4878aSAndroid Build Coastguard Worker Connection::SharedState::LookupStream(StreamId id) {
374*61c4878aSAndroid Build Coastguard Worker   for (size_t i = 0; i < streams.size(); i++) {
375*61c4878aSAndroid Build Coastguard Worker     if (streams[i].id == id) {
376*61c4878aSAndroid Build Coastguard Worker       return streams[i];
377*61c4878aSAndroid Build Coastguard Worker     }
378*61c4878aSAndroid Build Coastguard Worker   }
379*61c4878aSAndroid Build Coastguard Worker   return Status::NotFound();
380*61c4878aSAndroid Build Coastguard Worker }
381*61c4878aSAndroid Build Coastguard Worker 
SendResponseMessage(StreamId stream_id,ConstByteSpan message)382*61c4878aSAndroid Build Coastguard Worker Status Connection::Writer::SendResponseMessage(StreamId stream_id,
383*61c4878aSAndroid Build Coastguard Worker                                                ConstByteSpan message) {
384*61c4878aSAndroid Build Coastguard Worker   auto state = connection_.LockState();
385*61c4878aSAndroid Build Coastguard Worker   auto stream = state->LookupStream(stream_id);
386*61c4878aSAndroid Build Coastguard Worker   if (!stream.ok()) {
387*61c4878aSAndroid Build Coastguard Worker     return Status::NotFound();
388*61c4878aSAndroid Build Coastguard Worker   }
389*61c4878aSAndroid Build Coastguard Worker 
390*61c4878aSAndroid Build Coastguard Worker   if (message.size() > kMaxGrpcMessageSize) {
391*61c4878aSAndroid Build Coastguard Worker     PW_LOG_WARN("Message %" PRIu32 " bytes on id=%" PRIu32
392*61c4878aSAndroid Build Coastguard Worker                 " exceeds maximum message size",
393*61c4878aSAndroid Build Coastguard Worker                 static_cast<uint32_t>(message.size()),
394*61c4878aSAndroid Build Coastguard Worker                 stream_id);
395*61c4878aSAndroid Build Coastguard Worker     return Status::InvalidArgument();
396*61c4878aSAndroid Build Coastguard Worker   }
397*61c4878aSAndroid Build Coastguard Worker 
398*61c4878aSAndroid Build Coastguard Worker   // This should block until there is enough send window.
399*61c4878aSAndroid Build Coastguard Worker   if (static_cast<int32_t>(message.size()) > stream->get().send_window ||
400*61c4878aSAndroid Build Coastguard Worker       static_cast<int32_t>(message.size()) > state->connection_send_window) {
401*61c4878aSAndroid Build Coastguard Worker     PW_LOG_WARN("Not enough window to send %" PRIu32 " bytes on id=%" PRIu32,
402*61c4878aSAndroid Build Coastguard Worker                 static_cast<uint32_t>(message.size()),
403*61c4878aSAndroid Build Coastguard Worker                 stream_id);
404*61c4878aSAndroid Build Coastguard Worker     return Status::ResourceExhausted();
405*61c4878aSAndroid Build Coastguard Worker   }
406*61c4878aSAndroid Build Coastguard Worker 
407*61c4878aSAndroid Build Coastguard Worker   auto status = OkStatus();
408*61c4878aSAndroid Build Coastguard Worker   if (!stream->get().started_response) {
409*61c4878aSAndroid Build Coastguard Worker     stream->get().started_response = true;
410*61c4878aSAndroid Build Coastguard Worker     status = SendHeaders(connection_.send_queue_,
411*61c4878aSAndroid Build Coastguard Worker                          stream_id,
412*61c4878aSAndroid Build Coastguard Worker                          ResponseHeadersPayload(),
413*61c4878aSAndroid Build Coastguard Worker                          ConstByteSpan(),
414*61c4878aSAndroid Build Coastguard Worker                          /*end_stream=*/false);
415*61c4878aSAndroid Build Coastguard Worker   }
416*61c4878aSAndroid Build Coastguard Worker   if (status.ok()) {
417*61c4878aSAndroid Build Coastguard Worker     // Write a Length-Prefixed-Message payload.
418*61c4878aSAndroid Build Coastguard Worker     ByteBuffer<5> prefix;
419*61c4878aSAndroid Build Coastguard Worker     prefix.PutUint8(0);
420*61c4878aSAndroid Build Coastguard Worker     prefix.PutUint32(message.size(), endian::big);
421*61c4878aSAndroid Build Coastguard Worker     status = SendData(connection_.send_queue_, stream_id, prefix, message);
422*61c4878aSAndroid Build Coastguard Worker   }
423*61c4878aSAndroid Build Coastguard Worker   if (!status.ok()) {
424*61c4878aSAndroid Build Coastguard Worker     PW_LOG_WARN("Failed sending response message on id=%" PRIu32 " error=%d",
425*61c4878aSAndroid Build Coastguard Worker                 stream_id,
426*61c4878aSAndroid Build Coastguard Worker                 status.code());
427*61c4878aSAndroid Build Coastguard Worker     return Status::Unavailable();
428*61c4878aSAndroid Build Coastguard Worker   }
429*61c4878aSAndroid Build Coastguard Worker   stream->get().send_window -= message.size();
430*61c4878aSAndroid Build Coastguard Worker   state->connection_send_window -= message.size();
431*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
432*61c4878aSAndroid Build Coastguard Worker }
433*61c4878aSAndroid Build Coastguard Worker 
SendResponseComplete(StreamId stream_id,Status response_code)434*61c4878aSAndroid Build Coastguard Worker Status Connection::Writer::SendResponseComplete(StreamId stream_id,
435*61c4878aSAndroid Build Coastguard Worker                                                 Status response_code) {
436*61c4878aSAndroid Build Coastguard Worker   auto state = connection_.LockState();
437*61c4878aSAndroid Build Coastguard Worker   auto stream = state->LookupStream(stream_id);
438*61c4878aSAndroid Build Coastguard Worker   if (!stream.ok()) {
439*61c4878aSAndroid Build Coastguard Worker     return Status::NotFound();
440*61c4878aSAndroid Build Coastguard Worker   }
441*61c4878aSAndroid Build Coastguard Worker 
442*61c4878aSAndroid Build Coastguard Worker   Status status;
443*61c4878aSAndroid Build Coastguard Worker   if (!stream->get().started_response) {
444*61c4878aSAndroid Build Coastguard Worker     // If the response has not started yet, we need to include the initial
445*61c4878aSAndroid Build Coastguard Worker     // headers.
446*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG("Conn.SendResponseWithTrailers id=%" PRIu32 " code=%d",
447*61c4878aSAndroid Build Coastguard Worker                  stream_id,
448*61c4878aSAndroid Build Coastguard Worker                  response_code.code());
449*61c4878aSAndroid Build Coastguard Worker     status = SendHeaders(connection_.send_queue_,
450*61c4878aSAndroid Build Coastguard Worker                          stream_id,
451*61c4878aSAndroid Build Coastguard Worker                          ResponseHeadersPayload(),
452*61c4878aSAndroid Build Coastguard Worker                          ResponseTrailersPayload(response_code),
453*61c4878aSAndroid Build Coastguard Worker                          /*end_stream=*/true);
454*61c4878aSAndroid Build Coastguard Worker   } else {
455*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG("Conn.SendTrailers id=%" PRIu32 " code=%d",
456*61c4878aSAndroid Build Coastguard Worker                  stream_id,
457*61c4878aSAndroid Build Coastguard Worker                  response_code.code());
458*61c4878aSAndroid Build Coastguard Worker     status = SendHeaders(connection_.send_queue_,
459*61c4878aSAndroid Build Coastguard Worker                          stream_id,
460*61c4878aSAndroid Build Coastguard Worker                          ConstByteSpan(),
461*61c4878aSAndroid Build Coastguard Worker                          ResponseTrailersPayload(response_code),
462*61c4878aSAndroid Build Coastguard Worker                          /*end_stream=*/true);
463*61c4878aSAndroid Build Coastguard Worker   }
464*61c4878aSAndroid Build Coastguard Worker 
465*61c4878aSAndroid Build Coastguard Worker   if (!status.ok()) {
466*61c4878aSAndroid Build Coastguard Worker     PW_LOG_WARN("Failed sending response complete on id=%" PRIu32 " error=%d",
467*61c4878aSAndroid Build Coastguard Worker                 stream_id,
468*61c4878aSAndroid Build Coastguard Worker                 status.code());
469*61c4878aSAndroid Build Coastguard Worker     return Status::Unavailable();
470*61c4878aSAndroid Build Coastguard Worker   }
471*61c4878aSAndroid Build Coastguard Worker 
472*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.CloseStream id=%" PRIu32, stream_id);
473*61c4878aSAndroid Build Coastguard Worker   stream->get().Reset();
474*61c4878aSAndroid Build Coastguard Worker 
475*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
476*61c4878aSAndroid Build Coastguard Worker }
477*61c4878aSAndroid Build Coastguard Worker 
CreateStream(StreamId id)478*61c4878aSAndroid Build Coastguard Worker pw::Status Connection::Reader::CreateStream(StreamId id) {
479*61c4878aSAndroid Build Coastguard Worker   auto state = connection_.LockState();
480*61c4878aSAndroid Build Coastguard Worker   for (size_t i = 0; i < state->streams.size(); i++) {
481*61c4878aSAndroid Build Coastguard Worker     if (state->streams[i].id != 0) {
482*61c4878aSAndroid Build Coastguard Worker       continue;
483*61c4878aSAndroid Build Coastguard Worker     }
484*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG("Conn.CreateStream id=%" PRIu32 " at slot=%" PRIu32,
485*61c4878aSAndroid Build Coastguard Worker                  id,
486*61c4878aSAndroid Build Coastguard Worker                  static_cast<uint32_t>(i));
487*61c4878aSAndroid Build Coastguard Worker     state->streams[i].id = id;
488*61c4878aSAndroid Build Coastguard Worker     state->streams[i].half_closed = false;
489*61c4878aSAndroid Build Coastguard Worker     state->streams[i].started_response = false;
490*61c4878aSAndroid Build Coastguard Worker     state->streams[i].send_window = initial_send_window_;
491*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
492*61c4878aSAndroid Build Coastguard Worker   }
493*61c4878aSAndroid Build Coastguard Worker   PW_LOG_WARN("Conn.CreateStream id=%" PRIu32 " OUT OF SPACE", id);
494*61c4878aSAndroid Build Coastguard Worker   return Status::ResourceExhausted();
495*61c4878aSAndroid Build Coastguard Worker }
496*61c4878aSAndroid Build Coastguard Worker 
CloseStream(Connection::Stream & stream)497*61c4878aSAndroid Build Coastguard Worker void Connection::Reader::CloseStream(Connection::Stream& stream) {
498*61c4878aSAndroid Build Coastguard Worker   StreamId id = stream.id;
499*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.CloseStream id=%" PRIu32, id);
500*61c4878aSAndroid Build Coastguard Worker   stream.Reset();
501*61c4878aSAndroid Build Coastguard Worker   callbacks_.OnCancel(id);
502*61c4878aSAndroid Build Coastguard Worker }
503*61c4878aSAndroid Build Coastguard Worker 
504*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §3.4
ProcessConnectionPreface()505*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::ProcessConnectionPreface() {
506*61c4878aSAndroid Build Coastguard Worker   if (received_connection_preface_) {
507*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
508*61c4878aSAndroid Build Coastguard Worker   }
509*61c4878aSAndroid Build Coastguard Worker 
510*61c4878aSAndroid Build Coastguard Worker   callbacks_.OnNewConnection();
511*61c4878aSAndroid Build Coastguard Worker 
512*61c4878aSAndroid Build Coastguard Worker   // The preface starts with a literal string.
513*61c4878aSAndroid Build Coastguard Worker   auto literal = span{payload_scratch_}.subspan(
514*61c4878aSAndroid Build Coastguard Worker       0, kExpectedConnectionPrefaceLiteral.size());
515*61c4878aSAndroid Build Coastguard Worker 
516*61c4878aSAndroid Build Coastguard Worker   PW_TRY(ReadExactly(connection_.socket_.as_reader(), literal));
517*61c4878aSAndroid Build Coastguard Worker   if (std::memcmp(literal.data(),
518*61c4878aSAndroid Build Coastguard Worker                   kExpectedConnectionPrefaceLiteral.data(),
519*61c4878aSAndroid Build Coastguard Worker                   kExpectedConnectionPrefaceLiteral.size()) != 0) {
520*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR("Invalid connection preface literal");
521*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
522*61c4878aSAndroid Build Coastguard Worker   }
523*61c4878aSAndroid Build Coastguard Worker 
524*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Preface received literal");
525*61c4878aSAndroid Build Coastguard Worker 
526*61c4878aSAndroid Build Coastguard Worker   // Client must send a SETTINGS frames.
527*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(auto client_frame,
528*61c4878aSAndroid Build Coastguard Worker                 ReadFrameHeader(connection_.socket_.as_reader()));
529*61c4878aSAndroid Build Coastguard Worker   if (client_frame.type != FrameType::SETTINGS) {
530*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR(
531*61c4878aSAndroid Build Coastguard Worker         "Connection preface missing SETTINGS frame, found frame.type=%d",
532*61c4878aSAndroid Build Coastguard Worker         static_cast<int>(client_frame.type));
533*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
534*61c4878aSAndroid Build Coastguard Worker   }
535*61c4878aSAndroid Build Coastguard Worker 
536*61c4878aSAndroid Build Coastguard Worker   // Don't send an ACK yet, we'll do that below.
537*61c4878aSAndroid Build Coastguard Worker   PW_TRY(ProcessSettingsFrame(client_frame, /*send_ack=*/false));
538*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Preface received SETTINGS");
539*61c4878aSAndroid Build Coastguard Worker 
540*61c4878aSAndroid Build Coastguard Worker   // We must send a SETTINGS frame.
541*61c4878aSAndroid Build Coastguard Worker   // RFC 9113 §6.5.2
542*61c4878aSAndroid Build Coastguard Worker   PW_PACKED(struct) Setting {
543*61c4878aSAndroid Build Coastguard Worker     uint16_t id;
544*61c4878aSAndroid Build Coastguard Worker     uint32_t value;
545*61c4878aSAndroid Build Coastguard Worker   };
546*61c4878aSAndroid Build Coastguard Worker   PW_PACKED(struct) SettingsFrame {
547*61c4878aSAndroid Build Coastguard Worker     WireFrameHeader header;
548*61c4878aSAndroid Build Coastguard Worker     Setting settings[2];
549*61c4878aSAndroid Build Coastguard Worker   };
550*61c4878aSAndroid Build Coastguard Worker   SettingsFrame server_frame{
551*61c4878aSAndroid Build Coastguard Worker       .header = WireFrameHeader(FrameHeader{
552*61c4878aSAndroid Build Coastguard Worker           .payload_length = 12,
553*61c4878aSAndroid Build Coastguard Worker           .type = FrameType::SETTINGS,
554*61c4878aSAndroid Build Coastguard Worker           .flags = 0,
555*61c4878aSAndroid Build Coastguard Worker           .stream_id = 0,
556*61c4878aSAndroid Build Coastguard Worker       }),
557*61c4878aSAndroid Build Coastguard Worker       .settings =
558*61c4878aSAndroid Build Coastguard Worker           {
559*61c4878aSAndroid Build Coastguard Worker               {
560*61c4878aSAndroid Build Coastguard Worker                   .id = ToNetworkOrder(SETTINGS_HEADER_TABLE_SIZE),
561*61c4878aSAndroid Build Coastguard Worker                   .value = ToNetworkOrder(kHpackDynamicHeaderTableSize),
562*61c4878aSAndroid Build Coastguard Worker               },
563*61c4878aSAndroid Build Coastguard Worker               {
564*61c4878aSAndroid Build Coastguard Worker                   .id = ToNetworkOrder(SETTINGS_MAX_CONCURRENT_STREAMS),
565*61c4878aSAndroid Build Coastguard Worker                   .value = ToNetworkOrder(kMaxConcurrentStreams),
566*61c4878aSAndroid Build Coastguard Worker               },
567*61c4878aSAndroid Build Coastguard Worker           },
568*61c4878aSAndroid Build Coastguard Worker   };
569*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Send SETTINGS");
570*61c4878aSAndroid Build Coastguard Worker   PW_TRY(connection_.send_queue_.SendBytes(AsBytes(server_frame)));
571*61c4878aSAndroid Build Coastguard Worker 
572*61c4878aSAndroid Build Coastguard Worker   // We must ack the client's SETTINGS frame *after* sending our SETTINGS.
573*61c4878aSAndroid Build Coastguard Worker   PW_TRY(SendSettingsAck(connection_.send_queue_));
574*61c4878aSAndroid Build Coastguard Worker 
575*61c4878aSAndroid Build Coastguard Worker   received_connection_preface_ = true;
576*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Preface complete");
577*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
578*61c4878aSAndroid Build Coastguard Worker }
579*61c4878aSAndroid Build Coastguard Worker 
580*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.1
ProcessDataFrame(const FrameHeader & frame)581*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::ProcessDataFrame(const FrameHeader& frame) {
582*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Recv DATA id=%" PRIu32 " flags=0x%x len=%" PRIu32,
583*61c4878aSAndroid Build Coastguard Worker                frame.stream_id,
584*61c4878aSAndroid Build Coastguard Worker                frame.flags,
585*61c4878aSAndroid Build Coastguard Worker                frame.payload_length);
586*61c4878aSAndroid Build Coastguard Worker 
587*61c4878aSAndroid Build Coastguard Worker   if (frame.stream_id == 0) {
588*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.1: "If a DATA frame is received whose Stream Identifier field
589*61c4878aSAndroid Build Coastguard Worker     // is 0x00, the recipient MUST respond with a connection error of type
590*61c4878aSAndroid Build Coastguard Worker     // PROTOCOL_ERROR."
591*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::PROTOCOL_ERROR);
592*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
593*61c4878aSAndroid Build Coastguard Worker   }
594*61c4878aSAndroid Build Coastguard Worker 
595*61c4878aSAndroid Build Coastguard Worker   // From RFC 9113 §6.9: "A receiver that receives a flow-controlled frame MUST
596*61c4878aSAndroid Build Coastguard Worker   // always account for its contribution against the connection flow-control
597*61c4878aSAndroid Build Coastguard Worker   // window, unless the receiver treats this as a connection error. This is
598*61c4878aSAndroid Build Coastguard Worker   // necessary even if the frame is in error. The sender counts the frame toward
599*61c4878aSAndroid Build Coastguard Worker   // the flow-control window, but if the receiver does not, the flow-control
600*61c4878aSAndroid Build Coastguard Worker   // window at the sender and receiver can become different."
601*61c4878aSAndroid Build Coastguard Worker   //
602*61c4878aSAndroid Build Coastguard Worker   // To simplify this, we send WINDOW_UPDATE frames eagerly.
603*61c4878aSAndroid Build Coastguard Worker   //
604*61c4878aSAndroid Build Coastguard Worker   // In the future we should do something less chatty.
605*61c4878aSAndroid Build Coastguard Worker   PW_TRY(SendWindowUpdates(
606*61c4878aSAndroid Build Coastguard Worker       connection_.send_queue_, frame.stream_id, frame.payload_length));
607*61c4878aSAndroid Build Coastguard Worker 
608*61c4878aSAndroid Build Coastguard Worker   {
609*61c4878aSAndroid Build Coastguard Worker     auto state = connection_.LockState();
610*61c4878aSAndroid Build Coastguard Worker     auto stream = state->LookupStream(frame.stream_id);
611*61c4878aSAndroid Build Coastguard Worker     if (!stream.ok()) {
612*61c4878aSAndroid Build Coastguard Worker       PW_LOG_DEBUG("Ignoring DATA on closed stream id=%" PRIu32,
613*61c4878aSAndroid Build Coastguard Worker                    frame.stream_id);
614*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessIgnoredFrame(frame));
615*61c4878aSAndroid Build Coastguard Worker       // Stream has been fully closed: silently ignore.
616*61c4878aSAndroid Build Coastguard Worker       return OkStatus();
617*61c4878aSAndroid Build Coastguard Worker     }
618*61c4878aSAndroid Build Coastguard Worker 
619*61c4878aSAndroid Build Coastguard Worker     if (stream->get().half_closed) {
620*61c4878aSAndroid Build Coastguard Worker       PW_LOG_ERROR("Recv DATA on half-closed stream id=%" PRIu32,
621*61c4878aSAndroid Build Coastguard Worker                    frame.stream_id);
622*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessIgnoredFrame(frame));
623*61c4878aSAndroid Build Coastguard Worker       // RFC 9113 §6.1: "If a DATA frame is received whose stream is not in the
624*61c4878aSAndroid Build Coastguard Worker       // "open" or "half-closed (local)" state, the recipient MUST respond with
625*61c4878aSAndroid Build Coastguard Worker       // a stream error of type STREAM_CLOSED."
626*61c4878aSAndroid Build Coastguard Worker       PW_TRY(SendRstStreamAndClose(stream->get(), Http2Error::STREAM_CLOSED));
627*61c4878aSAndroid Build Coastguard Worker       return OkStatus();
628*61c4878aSAndroid Build Coastguard Worker     }
629*61c4878aSAndroid Build Coastguard Worker   }
630*61c4878aSAndroid Build Coastguard Worker 
631*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(auto payload, ReadFramePayload(frame));
632*61c4878aSAndroid Build Coastguard Worker 
633*61c4878aSAndroid Build Coastguard Worker   // Drop padding.
634*61c4878aSAndroid Build Coastguard Worker   if ((frame.flags & FLAGS_PADDED) != 0) {
635*61c4878aSAndroid Build Coastguard Worker     if (payload.size() < 1) {
636*61c4878aSAndroid Build Coastguard Worker       // RFC 9113 §4.2: "An endpoint MUST send an error code of FRAME_SIZE_ERROR
637*61c4878aSAndroid Build Coastguard Worker       // if a frame ... is too small to contain mandatory frame data."
638*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::FRAME_SIZE_ERROR);
639*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
640*61c4878aSAndroid Build Coastguard Worker     }
641*61c4878aSAndroid Build Coastguard Worker 
642*61c4878aSAndroid Build Coastguard Worker     uint32_t pad_length = static_cast<uint32_t>(payload[0]);
643*61c4878aSAndroid Build Coastguard Worker     if (pad_length >= frame.payload_length) {
644*61c4878aSAndroid Build Coastguard Worker       // RFC 9113 §6.1: "If the length of the padding is the length of the frame
645*61c4878aSAndroid Build Coastguard Worker       // payload or greater, the recipient MUST treat this as a connection error
646*61c4878aSAndroid Build Coastguard Worker       // of type PROTOCOL_ERROR."
647*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::PROTOCOL_ERROR);
648*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
649*61c4878aSAndroid Build Coastguard Worker     }
650*61c4878aSAndroid Build Coastguard Worker     payload = payload.subspan(1, payload.size() - pad_length - 1);
651*61c4878aSAndroid Build Coastguard Worker   }
652*61c4878aSAndroid Build Coastguard Worker 
653*61c4878aSAndroid Build Coastguard Worker   auto state = connection_.LockState();
654*61c4878aSAndroid Build Coastguard Worker   auto maybe_stream = state->LookupStream(frame.stream_id);
655*61c4878aSAndroid Build Coastguard Worker   if (!maybe_stream.ok()) {
656*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
657*61c4878aSAndroid Build Coastguard Worker   }
658*61c4878aSAndroid Build Coastguard Worker   Stream* stream = &maybe_stream->get();
659*61c4878aSAndroid Build Coastguard Worker 
660*61c4878aSAndroid Build Coastguard Worker   // Parse repeated grpc Length-Prefix-Message.
661*61c4878aSAndroid Build Coastguard Worker   // https://github.com/grpc/grpc/blob/v1.60.x/doc/PROTOCOL-HTTP2.md#requests
662*61c4878aSAndroid Build Coastguard Worker   while (!payload.empty()) {
663*61c4878aSAndroid Build Coastguard Worker     uint32_t message_length;
664*61c4878aSAndroid Build Coastguard Worker 
665*61c4878aSAndroid Build Coastguard Worker     // If we aren't reassembling a message, read the next length prefix.
666*61c4878aSAndroid Build Coastguard Worker     if (!stream->assembly_buffer) {
667*61c4878aSAndroid Build Coastguard Worker       size_t read = std::min(5 - static_cast<size_t>(stream->prefix_received),
668*61c4878aSAndroid Build Coastguard Worker                              payload.size());
669*61c4878aSAndroid Build Coastguard Worker       std::copy(payload.begin(),
670*61c4878aSAndroid Build Coastguard Worker                 payload.begin() + read,
671*61c4878aSAndroid Build Coastguard Worker                 stream->prefix_buffer.data() + stream->prefix_received);
672*61c4878aSAndroid Build Coastguard Worker       stream->prefix_received += read;
673*61c4878aSAndroid Build Coastguard Worker       payload = payload.subspan(read);
674*61c4878aSAndroid Build Coastguard Worker 
675*61c4878aSAndroid Build Coastguard Worker       // Read the length prefix.
676*61c4878aSAndroid Build Coastguard Worker       if (stream->prefix_received < 5) {
677*61c4878aSAndroid Build Coastguard Worker         continue;
678*61c4878aSAndroid Build Coastguard Worker       }
679*61c4878aSAndroid Build Coastguard Worker       stream->prefix_received = 0;
680*61c4878aSAndroid Build Coastguard Worker 
681*61c4878aSAndroid Build Coastguard Worker       ByteBuilder builder(stream->prefix_buffer);
682*61c4878aSAndroid Build Coastguard Worker       auto it = builder.begin();
683*61c4878aSAndroid Build Coastguard Worker       auto message_compressed = it.ReadUint8();
684*61c4878aSAndroid Build Coastguard Worker       message_length = it.ReadUint32(endian::big);
685*61c4878aSAndroid Build Coastguard Worker       if (message_compressed != 0) {
686*61c4878aSAndroid Build Coastguard Worker         PW_LOG_ERROR("Unsupported: grpc message is compressed");
687*61c4878aSAndroid Build Coastguard Worker         PW_TRY(SendRstStreamAndClose(*stream, Http2Error::INTERNAL_ERROR));
688*61c4878aSAndroid Build Coastguard Worker         return OkStatus();
689*61c4878aSAndroid Build Coastguard Worker       }
690*61c4878aSAndroid Build Coastguard Worker 
691*61c4878aSAndroid Build Coastguard Worker       if (message_length > payload.size()) {
692*61c4878aSAndroid Build Coastguard Worker         // gRPC message is split across DATA frames, must allocate buffer.
693*61c4878aSAndroid Build Coastguard Worker         if (!state->message_assembly_allocator_) {
694*61c4878aSAndroid Build Coastguard Worker           PW_LOG_ERROR(
695*61c4878aSAndroid Build Coastguard Worker               "Unsupported: split grpc message without allocator provided");
696*61c4878aSAndroid Build Coastguard Worker           PW_TRY(SendRstStreamAndClose(*stream, Http2Error::INTERNAL_ERROR));
697*61c4878aSAndroid Build Coastguard Worker           return OkStatus();
698*61c4878aSAndroid Build Coastguard Worker         }
699*61c4878aSAndroid Build Coastguard Worker 
700*61c4878aSAndroid Build Coastguard Worker         stream->assembly_buffer = static_cast<std::byte*>(
701*61c4878aSAndroid Build Coastguard Worker             state->message_assembly_allocator_->Allocate(
702*61c4878aSAndroid Build Coastguard Worker                 allocator::Layout(message_length)));
703*61c4878aSAndroid Build Coastguard Worker         if (stream->assembly_buffer == nullptr) {
704*61c4878aSAndroid Build Coastguard Worker           PW_LOG_ERROR("Partial message reassembly buffer allocation failed");
705*61c4878aSAndroid Build Coastguard Worker           PW_TRY(SendRstStreamAndClose(*stream, Http2Error::INTERNAL_ERROR));
706*61c4878aSAndroid Build Coastguard Worker           return OkStatus();
707*61c4878aSAndroid Build Coastguard Worker         }
708*61c4878aSAndroid Build Coastguard Worker         stream->message_length = message_length;
709*61c4878aSAndroid Build Coastguard Worker         stream->message_received = 0;
710*61c4878aSAndroid Build Coastguard Worker         continue;
711*61c4878aSAndroid Build Coastguard Worker       }
712*61c4878aSAndroid Build Coastguard Worker     }
713*61c4878aSAndroid Build Coastguard Worker 
714*61c4878aSAndroid Build Coastguard Worker     pw::ByteSpan message;
715*61c4878aSAndroid Build Coastguard Worker 
716*61c4878aSAndroid Build Coastguard Worker     // Reading message payload.
717*61c4878aSAndroid Build Coastguard Worker     if (stream->assembly_buffer != nullptr) {
718*61c4878aSAndroid Build Coastguard Worker       uint32_t read =
719*61c4878aSAndroid Build Coastguard Worker           std::min(stream->message_length - stream->message_received,
720*61c4878aSAndroid Build Coastguard Worker                    static_cast<uint32_t>(payload.size()));
721*61c4878aSAndroid Build Coastguard Worker       std::copy(payload.begin(),
722*61c4878aSAndroid Build Coastguard Worker                 payload.begin() + read,
723*61c4878aSAndroid Build Coastguard Worker                 stream->assembly_buffer + stream->message_received);
724*61c4878aSAndroid Build Coastguard Worker       payload = payload.subspan(read);
725*61c4878aSAndroid Build Coastguard Worker       stream->message_received += read;
726*61c4878aSAndroid Build Coastguard Worker       if (stream->message_received < stream->message_length) {
727*61c4878aSAndroid Build Coastguard Worker         continue;
728*61c4878aSAndroid Build Coastguard Worker       }
729*61c4878aSAndroid Build Coastguard Worker       // Fully received message.
730*61c4878aSAndroid Build Coastguard Worker       message = pw::span(stream->assembly_buffer, stream->message_length);
731*61c4878aSAndroid Build Coastguard Worker     } else {
732*61c4878aSAndroid Build Coastguard Worker       message = payload.subspan(0, message_length);
733*61c4878aSAndroid Build Coastguard Worker       payload = payload.subspan(message_length);
734*61c4878aSAndroid Build Coastguard Worker     }
735*61c4878aSAndroid Build Coastguard Worker 
736*61c4878aSAndroid Build Coastguard Worker     // Release state lock before callback, reacquire after.
737*61c4878aSAndroid Build Coastguard Worker     connection_.UnlockState(std::move(state));
738*61c4878aSAndroid Build Coastguard Worker     const auto status = callbacks_.OnMessage(frame.stream_id, message);
739*61c4878aSAndroid Build Coastguard Worker     state = connection_.LockState();
740*61c4878aSAndroid Build Coastguard Worker     maybe_stream = state->LookupStream(frame.stream_id);
741*61c4878aSAndroid Build Coastguard Worker     if (!maybe_stream.ok()) {
742*61c4878aSAndroid Build Coastguard Worker       return OkStatus();
743*61c4878aSAndroid Build Coastguard Worker     }
744*61c4878aSAndroid Build Coastguard Worker     stream = &maybe_stream->get();
745*61c4878aSAndroid Build Coastguard Worker 
746*61c4878aSAndroid Build Coastguard Worker     if (!status.ok()) {
747*61c4878aSAndroid Build Coastguard Worker       PW_TRY(SendRstStreamAndClose(*stream, Http2Error::INTERNAL_ERROR));
748*61c4878aSAndroid Build Coastguard Worker       return OkStatus();
749*61c4878aSAndroid Build Coastguard Worker     }
750*61c4878aSAndroid Build Coastguard Worker 
751*61c4878aSAndroid Build Coastguard Worker     if (stream->assembly_buffer != nullptr) {
752*61c4878aSAndroid Build Coastguard Worker       state->message_assembly_allocator_->Deallocate(stream->assembly_buffer);
753*61c4878aSAndroid Build Coastguard Worker       stream->assembly_buffer = nullptr;
754*61c4878aSAndroid Build Coastguard Worker       stream->message_length = 0;
755*61c4878aSAndroid Build Coastguard Worker       stream->message_received = 0;
756*61c4878aSAndroid Build Coastguard Worker     }
757*61c4878aSAndroid Build Coastguard Worker   }
758*61c4878aSAndroid Build Coastguard Worker 
759*61c4878aSAndroid Build Coastguard Worker   // grpc requires every request stream to end with an empty DATA frame with
760*61c4878aSAndroid Build Coastguard Worker   // FLAGS_END_STREAM. If a client sends FLAGS_END_STREAM with a non-empty
761*61c4878aSAndroid Build Coastguard Worker   // payload, it's not specified how the server should respond. We choose to
762*61c4878aSAndroid Build Coastguard Worker   // accept the payload before ending the stream.
763*61c4878aSAndroid Build Coastguard Worker   // See: https://github.com/grpc/grpc/blob/v1.60.x/doc/PROTOCOL-HTTP2.md.
764*61c4878aSAndroid Build Coastguard Worker   if ((frame.flags & FLAGS_END_STREAM) != 0) {
765*61c4878aSAndroid Build Coastguard Worker     stream->half_closed = true;
766*61c4878aSAndroid Build Coastguard Worker     connection_.UnlockState(std::move(state));
767*61c4878aSAndroid Build Coastguard Worker     callbacks_.OnHalfClose(frame.stream_id);
768*61c4878aSAndroid Build Coastguard Worker   }
769*61c4878aSAndroid Build Coastguard Worker 
770*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
771*61c4878aSAndroid Build Coastguard Worker }
772*61c4878aSAndroid Build Coastguard Worker 
773*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.2
ProcessHeadersFrame(const FrameHeader & frame)774*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::ProcessHeadersFrame(const FrameHeader& frame) {
775*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Recv HEADERS id=%" PRIu32 " len=%" PRIu32,
776*61c4878aSAndroid Build Coastguard Worker                frame.stream_id,
777*61c4878aSAndroid Build Coastguard Worker                frame.payload_length);
778*61c4878aSAndroid Build Coastguard Worker 
779*61c4878aSAndroid Build Coastguard Worker   if (frame.stream_id == 0) {
780*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.2: "If a HEADERS frame is received whose Stream Identifier
781*61c4878aSAndroid Build Coastguard Worker     // field is 0x00, the recipient MUST respond with a connection error of type
782*61c4878aSAndroid Build Coastguard Worker     // PROTOCOL_ERROR."
783*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::PROTOCOL_ERROR);
784*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
785*61c4878aSAndroid Build Coastguard Worker   }
786*61c4878aSAndroid Build Coastguard Worker   if (frame.stream_id % 2 != 1 || frame.stream_id <= last_stream_id_) {
787*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §5.1.1: "Streams initiated by a client MUST use odd-numbered
788*61c4878aSAndroid Build Coastguard Worker     // stream identifiers ... The identifier of a newly established stream MUST
789*61c4878aSAndroid Build Coastguard Worker     // be numerically greater than all streams that the initiating endpoint has
790*61c4878aSAndroid Build Coastguard Worker     // opened ... An endpoint that receives an unexpected stream identifier MUST
791*61c4878aSAndroid Build Coastguard Worker     // respond with a connection error of type PROTOCOL_ERROR."
792*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::PROTOCOL_ERROR);
793*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
794*61c4878aSAndroid Build Coastguard Worker   }
795*61c4878aSAndroid Build Coastguard Worker 
796*61c4878aSAndroid Build Coastguard Worker   last_stream_id_ = frame.stream_id;
797*61c4878aSAndroid Build Coastguard Worker 
798*61c4878aSAndroid Build Coastguard Worker   {
799*61c4878aSAndroid Build Coastguard Worker     auto state = connection_.LockState();
800*61c4878aSAndroid Build Coastguard Worker     if (auto stream = state->LookupStream(frame.stream_id); stream.ok()) {
801*61c4878aSAndroid Build Coastguard Worker       PW_LOG_DEBUG("Client sent HEADERS after the first stream message");
802*61c4878aSAndroid Build Coastguard Worker       PW_TRY(ProcessIgnoredFrame(frame));
803*61c4878aSAndroid Build Coastguard Worker       // grpc requests cannot contain trailers.
804*61c4878aSAndroid Build Coastguard Worker       // See: https://github.com/grpc/grpc/blob/v1.60.x/doc/PROTOCOL-HTTP2.md.
805*61c4878aSAndroid Build Coastguard Worker       PW_TRY(SendRstStreamAndClose(stream->get(), Http2Error::PROTOCOL_ERROR));
806*61c4878aSAndroid Build Coastguard Worker       return OkStatus();
807*61c4878aSAndroid Build Coastguard Worker     }
808*61c4878aSAndroid Build Coastguard Worker   }
809*61c4878aSAndroid Build Coastguard Worker 
810*61c4878aSAndroid Build Coastguard Worker   if ((frame.flags & FLAGS_END_STREAM) != 0) {
811*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG("Client sent HEADERS with END_STREAM");
812*61c4878aSAndroid Build Coastguard Worker     PW_TRY(ProcessIgnoredFrame(frame));
813*61c4878aSAndroid Build Coastguard Worker     // grpc requests must send END_STREAM in an empty DATA frame.
814*61c4878aSAndroid Build Coastguard Worker     // See: https://github.com/grpc/grpc/blob/v1.60.x/doc/PROTOCOL-HTTP2.md.
815*61c4878aSAndroid Build Coastguard Worker     PW_TRY(SendRstStream(
816*61c4878aSAndroid Build Coastguard Worker         connection_.send_queue_, frame.stream_id, Http2Error::PROTOCOL_ERROR));
817*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
818*61c4878aSAndroid Build Coastguard Worker   }
819*61c4878aSAndroid Build Coastguard Worker   if ((frame.flags & FLAGS_END_HEADERS) == 0) {
820*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR("Client sent HEADERS frame without END_HEADERS: unsupported");
821*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::INTERNAL_ERROR);
822*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
823*61c4878aSAndroid Build Coastguard Worker   }
824*61c4878aSAndroid Build Coastguard Worker 
825*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(auto payload, ReadFramePayload(frame));
826*61c4878aSAndroid Build Coastguard Worker 
827*61c4878aSAndroid Build Coastguard Worker   // Drop padding.
828*61c4878aSAndroid Build Coastguard Worker   if ((frame.flags & FLAGS_PADDED) != 0) {
829*61c4878aSAndroid Build Coastguard Worker     if (payload.size() < 1) {
830*61c4878aSAndroid Build Coastguard Worker       // RFC 9113 §4.2: "An endpoint MUST send an error code of FRAME_SIZE_ERROR
831*61c4878aSAndroid Build Coastguard Worker       // if a frame ... is too small to contain mandatory frame data. A frame
832*61c4878aSAndroid Build Coastguard Worker       // size error in a frame that could alter the state of the entire
833*61c4878aSAndroid Build Coastguard Worker       // connection MUST be treated as a connection error"
834*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::FRAME_SIZE_ERROR);
835*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
836*61c4878aSAndroid Build Coastguard Worker     }
837*61c4878aSAndroid Build Coastguard Worker     uint32_t pad_length = static_cast<uint32_t>(payload[0]);
838*61c4878aSAndroid Build Coastguard Worker     if (pad_length >= frame.payload_length) {
839*61c4878aSAndroid Build Coastguard Worker       // RFC 9113 §6.2: "If the length of the padding is the length of the frame
840*61c4878aSAndroid Build Coastguard Worker       // payload or greater, the recipient MUST treat this as a connection error
841*61c4878aSAndroid Build Coastguard Worker       // of type PROTOCOL_ERROR."
842*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::PROTOCOL_ERROR);
843*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
844*61c4878aSAndroid Build Coastguard Worker     }
845*61c4878aSAndroid Build Coastguard Worker     payload = payload.subspan(1, payload.size() - pad_length - 1);
846*61c4878aSAndroid Build Coastguard Worker   }
847*61c4878aSAndroid Build Coastguard Worker 
848*61c4878aSAndroid Build Coastguard Worker   // Drop priority fields.
849*61c4878aSAndroid Build Coastguard Worker   if ((frame.flags & FLAGS_PRIORITY) != 0) {
850*61c4878aSAndroid Build Coastguard Worker     if (payload.size() < 5) {
851*61c4878aSAndroid Build Coastguard Worker       // RFC 9113 §4.2: "An endpoint MUST send an error code of FRAME_SIZE_ERROR
852*61c4878aSAndroid Build Coastguard Worker       // if a frame ... is too small to contain mandatory frame data."
853*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::FRAME_SIZE_ERROR);
854*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
855*61c4878aSAndroid Build Coastguard Worker     }
856*61c4878aSAndroid Build Coastguard Worker     payload = payload.subspan(5);
857*61c4878aSAndroid Build Coastguard Worker   }
858*61c4878aSAndroid Build Coastguard Worker 
859*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(auto method_name, HpackParseRequestHeaders(payload));
860*61c4878aSAndroid Build Coastguard Worker   if (!CreateStream(frame.stream_id).ok()) {
861*61c4878aSAndroid Build Coastguard Worker     PW_LOG_WARN("Too many streams, rejecting id=%" PRIu32, frame.stream_id);
862*61c4878aSAndroid Build Coastguard Worker     return SendRstStream(
863*61c4878aSAndroid Build Coastguard Worker         connection_.send_queue_, frame.stream_id, Http2Error::REFUSED_STREAM);
864*61c4878aSAndroid Build Coastguard Worker   }
865*61c4878aSAndroid Build Coastguard Worker 
866*61c4878aSAndroid Build Coastguard Worker   if (const auto status = callbacks_.OnNew(frame.stream_id, method_name);
867*61c4878aSAndroid Build Coastguard Worker       !status.ok()) {
868*61c4878aSAndroid Build Coastguard Worker     auto state = connection_.LockState();
869*61c4878aSAndroid Build Coastguard Worker     if (auto stream = state->LookupStream(frame.stream_id); stream.ok()) {
870*61c4878aSAndroid Build Coastguard Worker       return SendRstStreamAndClose(stream->get(), Http2Error::INTERNAL_ERROR);
871*61c4878aSAndroid Build Coastguard Worker     }
872*61c4878aSAndroid Build Coastguard Worker   }
873*61c4878aSAndroid Build Coastguard Worker 
874*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
875*61c4878aSAndroid Build Coastguard Worker }
876*61c4878aSAndroid Build Coastguard Worker 
877*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.4
ProcessRstStreamFrame(const FrameHeader & frame)878*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::ProcessRstStreamFrame(const FrameHeader& frame) {
879*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Recv RST_STREAM id=%" PRIu32 " len=%" PRIu32,
880*61c4878aSAndroid Build Coastguard Worker                frame.stream_id,
881*61c4878aSAndroid Build Coastguard Worker                frame.payload_length);
882*61c4878aSAndroid Build Coastguard Worker 
883*61c4878aSAndroid Build Coastguard Worker   if (frame.stream_id == 0) {
884*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.4: "If a RST_STREAM frame is received with a stream
885*61c4878aSAndroid Build Coastguard Worker     // identifier of 0x00, the recipient MUST treat this as a connection error
886*61c4878aSAndroid Build Coastguard Worker     // of type PROTOCOL_ERROR".
887*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::PROTOCOL_ERROR);
888*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
889*61c4878aSAndroid Build Coastguard Worker   }
890*61c4878aSAndroid Build Coastguard Worker   if (frame.stream_id > last_stream_id_) {
891*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.4: "If a RST_STREAM frame identifying an idle stream is
892*61c4878aSAndroid Build Coastguard Worker     // received, the recipient MUST treat this as a connection error of type
893*61c4878aSAndroid Build Coastguard Worker     // PROTOCOL_ERROR."
894*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::PROTOCOL_ERROR);
895*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
896*61c4878aSAndroid Build Coastguard Worker   }
897*61c4878aSAndroid Build Coastguard Worker   if (frame.payload_length != 4) {
898*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.4: "A RST_STREAM frame with a length other than 4 octets MUST
899*61c4878aSAndroid Build Coastguard Worker     // be treated as a connection error of type FRAME_SIZE_ERROR."
900*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::FRAME_SIZE_ERROR);
901*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
902*61c4878aSAndroid Build Coastguard Worker   }
903*61c4878aSAndroid Build Coastguard Worker 
904*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(auto payload, ReadFramePayload(frame));
905*61c4878aSAndroid Build Coastguard Worker   ByteBuilder builder(payload);
906*61c4878aSAndroid Build Coastguard Worker   auto error_code = builder.begin().ReadUint32(endian::big);
907*61c4878aSAndroid Build Coastguard Worker 
908*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.RstStream id=%" PRIu32 " error=%" PRIu32,
909*61c4878aSAndroid Build Coastguard Worker                frame.stream_id,
910*61c4878aSAndroid Build Coastguard Worker                error_code);
911*61c4878aSAndroid Build Coastguard Worker   auto state = connection_.LockState();
912*61c4878aSAndroid Build Coastguard Worker   if (auto stream = state->LookupStream(frame.stream_id); stream.ok()) {
913*61c4878aSAndroid Build Coastguard Worker     CloseStream(stream->get());
914*61c4878aSAndroid Build Coastguard Worker   }
915*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
916*61c4878aSAndroid Build Coastguard Worker }
917*61c4878aSAndroid Build Coastguard Worker 
918*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.5
ProcessSettingsFrame(const FrameHeader & frame,bool send_ack)919*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::ProcessSettingsFrame(const FrameHeader& frame,
920*61c4878aSAndroid Build Coastguard Worker                                                 bool send_ack) {
921*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Recv SETTINGS len=%" PRIu32 " flags=0x%x",
922*61c4878aSAndroid Build Coastguard Worker                frame.payload_length,
923*61c4878aSAndroid Build Coastguard Worker                frame.flags);
924*61c4878aSAndroid Build Coastguard Worker 
925*61c4878aSAndroid Build Coastguard Worker   if ((frame.flags & FLAGS_ACK) != 0) {
926*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.5: "Receipt of a SETTINGS frame with the ACK flag set and a
927*61c4878aSAndroid Build Coastguard Worker     // length field value other than 0 MUST be treated as a connection error of
928*61c4878aSAndroid Build Coastguard Worker     // type FRAME_SIZE_ERROR."
929*61c4878aSAndroid Build Coastguard Worker     if (frame.payload_length != 0) {
930*61c4878aSAndroid Build Coastguard Worker       PW_LOG_ERROR("Invalid SETTINGS frame: has ACK with non-empty payload");
931*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::FRAME_SIZE_ERROR);
932*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
933*61c4878aSAndroid Build Coastguard Worker     }
934*61c4878aSAndroid Build Coastguard Worker     // Don't ACK an ACK.
935*61c4878aSAndroid Build Coastguard Worker     send_ack = false;
936*61c4878aSAndroid Build Coastguard Worker   } else {
937*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.5: "A SETTINGS frame with a length other than a multiple of 6
938*61c4878aSAndroid Build Coastguard Worker     // octets MUST be treated as a connection error of type FRAME_SIZE_ERROR."
939*61c4878aSAndroid Build Coastguard Worker     if (frame.payload_length % 6 != 0) {
940*61c4878aSAndroid Build Coastguard Worker       PW_LOG_ERROR("Invalid SETTINGS frame: payload size invalid");
941*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::FRAME_SIZE_ERROR);
942*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
943*61c4878aSAndroid Build Coastguard Worker     }
944*61c4878aSAndroid Build Coastguard Worker   }
945*61c4878aSAndroid Build Coastguard Worker 
946*61c4878aSAndroid Build Coastguard Worker   if (frame.stream_id != 0) {
947*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.5: "If an endpoint receives a SETTINGS frame whose Stream
948*61c4878aSAndroid Build Coastguard Worker     // Identifier field is anything other than 0x00, the endpoint MUST respond
949*61c4878aSAndroid Build Coastguard Worker     // with a connection error of type PROTOCOL_ERROR."
950*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::PROTOCOL_ERROR);
951*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
952*61c4878aSAndroid Build Coastguard Worker   }
953*61c4878aSAndroid Build Coastguard Worker 
954*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(auto payload, ReadFramePayload(frame));
955*61c4878aSAndroid Build Coastguard Worker 
956*61c4878aSAndroid Build Coastguard Worker   // RFC 9113 §6.5.2
957*61c4878aSAndroid Build Coastguard Worker   ByteBuilder builder(payload);
958*61c4878aSAndroid Build Coastguard Worker   for (auto it = builder.begin(); it != builder.end();) {
959*61c4878aSAndroid Build Coastguard Worker     auto id = it.ReadUint16(endian::big);
960*61c4878aSAndroid Build Coastguard Worker     auto value = it.ReadUint32(endian::big);
961*61c4878aSAndroid Build Coastguard Worker     PW_LOG_DEBUG("Applying SETTING id=%" PRIu16 " value=%" PRIu32, id, value);
962*61c4878aSAndroid Build Coastguard Worker     switch (id) {
963*61c4878aSAndroid Build Coastguard Worker       case SETTINGS_INITIAL_WINDOW_SIZE: {
964*61c4878aSAndroid Build Coastguard Worker         // RFC 9113 §6.5.2: "Values above the maximum flow-control window size
965*61c4878aSAndroid Build Coastguard Worker         // of 2^31-1 MUST be treated as a connection error of type
966*61c4878aSAndroid Build Coastguard Worker         // FLOW_CONTROL_ERROR."
967*61c4878aSAndroid Build Coastguard Worker         if ((value & (1 << 31)) != 0) {
968*61c4878aSAndroid Build Coastguard Worker           SendGoAway(Http2Error::FLOW_CONTROL_ERROR);
969*61c4878aSAndroid Build Coastguard Worker           return Status::Internal();
970*61c4878aSAndroid Build Coastguard Worker         }
971*61c4878aSAndroid Build Coastguard Worker         // RFC 9113 §6.9.2: "When the value of SETTINGS_INITIAL_WINDOW_SIZE
972*61c4878aSAndroid Build Coastguard Worker         // changes, a receiver MUST adjust the size of all stream flow-control
973*61c4878aSAndroid Build Coastguard Worker         // windows that it maintains by the difference between the new value and
974*61c4878aSAndroid Build Coastguard Worker         // the old value."
975*61c4878aSAndroid Build Coastguard Worker         int32_t newval = static_cast<int32_t>(value);
976*61c4878aSAndroid Build Coastguard Worker         int32_t delta = newval - initial_send_window_;
977*61c4878aSAndroid Build Coastguard Worker         auto state = connection_.LockState();
978*61c4878aSAndroid Build Coastguard Worker         for (size_t i = 0; i < state->streams.size(); i++) {
979*61c4878aSAndroid Build Coastguard Worker           if (state->streams[i].id == 0) {
980*61c4878aSAndroid Build Coastguard Worker             continue;
981*61c4878aSAndroid Build Coastguard Worker           }
982*61c4878aSAndroid Build Coastguard Worker           if (PW_ADD_OVERFLOW(state->streams[i].send_window,
983*61c4878aSAndroid Build Coastguard Worker                               delta,
984*61c4878aSAndroid Build Coastguard Worker                               &state->streams[i].send_window)) {
985*61c4878aSAndroid Build Coastguard Worker             SendGoAway(Http2Error::FLOW_CONTROL_ERROR);
986*61c4878aSAndroid Build Coastguard Worker             return Status::Internal();
987*61c4878aSAndroid Build Coastguard Worker           }
988*61c4878aSAndroid Build Coastguard Worker         }
989*61c4878aSAndroid Build Coastguard Worker         initial_send_window_ = newval;
990*61c4878aSAndroid Build Coastguard Worker         break;
991*61c4878aSAndroid Build Coastguard Worker       }
992*61c4878aSAndroid Build Coastguard Worker       case SETTINGS_MAX_FRAME_SIZE:
993*61c4878aSAndroid Build Coastguard Worker         // RFC 9113 §6.5.2: "Values outside this range MUST be treated as a
994*61c4878aSAndroid Build Coastguard Worker         // connection error of type PROTOCOL_ERROR".
995*61c4878aSAndroid Build Coastguard Worker         if (value < 16384 || 16777215 < value) {
996*61c4878aSAndroid Build Coastguard Worker           SendGoAway(Http2Error::PROTOCOL_ERROR);
997*61c4878aSAndroid Build Coastguard Worker           return Status::Internal();
998*61c4878aSAndroid Build Coastguard Worker         }
999*61c4878aSAndroid Build Coastguard Worker         // We never send frame payloads larger than 16384, so we don't need to
1000*61c4878aSAndroid Build Coastguard Worker         // track the client's preference.
1001*61c4878aSAndroid Build Coastguard Worker         break;
1002*61c4878aSAndroid Build Coastguard Worker       // Ignore these.
1003*61c4878aSAndroid Build Coastguard Worker       // SETTINGS_HEADER_TABLE_SIZE: our responses don't use the dynamic table
1004*61c4878aSAndroid Build Coastguard Worker       // SETTINGS_ENABLE_PUSH: we don't support push
1005*61c4878aSAndroid Build Coastguard Worker       // SETTINGS_MAX_CONCURRENT_STREAMS: we don't support push
1006*61c4878aSAndroid Build Coastguard Worker       // SETTINGS_MAX_HEADER_LIST_SIZE: we send very tiny response HEADERS
1007*61c4878aSAndroid Build Coastguard Worker       default:
1008*61c4878aSAndroid Build Coastguard Worker         break;
1009*61c4878aSAndroid Build Coastguard Worker     }
1010*61c4878aSAndroid Build Coastguard Worker   }
1011*61c4878aSAndroid Build Coastguard Worker 
1012*61c4878aSAndroid Build Coastguard Worker   if (send_ack) {
1013*61c4878aSAndroid Build Coastguard Worker     PW_TRY(SendSettingsAck(connection_.send_queue_));
1014*61c4878aSAndroid Build Coastguard Worker   }
1015*61c4878aSAndroid Build Coastguard Worker 
1016*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
1017*61c4878aSAndroid Build Coastguard Worker }
1018*61c4878aSAndroid Build Coastguard Worker 
1019*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.7
ProcessPingFrame(const FrameHeader & frame)1020*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::ProcessPingFrame(const FrameHeader& frame) {
1021*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Recv PING len=%" PRIu32, frame.payload_length);
1022*61c4878aSAndroid Build Coastguard Worker 
1023*61c4878aSAndroid Build Coastguard Worker   if (frame.stream_id != 0) {
1024*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.7: "If a PING frame is received with a Stream Identifier
1025*61c4878aSAndroid Build Coastguard Worker     // field value other than 0x00, the recipient MUST respond with a connection
1026*61c4878aSAndroid Build Coastguard Worker     // error of type PROTOCOL_ERROR."
1027*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::PROTOCOL_ERROR);
1028*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
1029*61c4878aSAndroid Build Coastguard Worker   }
1030*61c4878aSAndroid Build Coastguard Worker   if (frame.payload_length != 8) {
1031*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.7: "Receipt of a PING frame with a length field value other
1032*61c4878aSAndroid Build Coastguard Worker     // than 8 MUST be treated as a connection error of type FRAME_SIZE_ERROR."
1033*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::FRAME_SIZE_ERROR);
1034*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
1035*61c4878aSAndroid Build Coastguard Worker   }
1036*61c4878aSAndroid Build Coastguard Worker 
1037*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(auto payload, ReadFramePayload(frame));
1038*61c4878aSAndroid Build Coastguard Worker 
1039*61c4878aSAndroid Build Coastguard Worker   // Don't ACK an ACK.
1040*61c4878aSAndroid Build Coastguard Worker   if ((frame.flags & FLAGS_ACK) != 0) {
1041*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
1042*61c4878aSAndroid Build Coastguard Worker   }
1043*61c4878aSAndroid Build Coastguard Worker 
1044*61c4878aSAndroid Build Coastguard Worker   // Send an ACK.
1045*61c4878aSAndroid Build Coastguard Worker   PW_PACKED(struct) PingFrame {
1046*61c4878aSAndroid Build Coastguard Worker     WireFrameHeader header;
1047*61c4878aSAndroid Build Coastguard Worker     uint64_t opaque_data;
1048*61c4878aSAndroid Build Coastguard Worker   };
1049*61c4878aSAndroid Build Coastguard Worker   ByteBuilder builder(payload);
1050*61c4878aSAndroid Build Coastguard Worker   PingFrame ack_frame = {
1051*61c4878aSAndroid Build Coastguard Worker       .header = WireFrameHeader(FrameHeader{
1052*61c4878aSAndroid Build Coastguard Worker           .payload_length = 8,
1053*61c4878aSAndroid Build Coastguard Worker           .type = FrameType::PING,
1054*61c4878aSAndroid Build Coastguard Worker           .flags = FLAGS_ACK,
1055*61c4878aSAndroid Build Coastguard Worker           .stream_id = 0,
1056*61c4878aSAndroid Build Coastguard Worker       }),
1057*61c4878aSAndroid Build Coastguard Worker       // Since we're going to echo this, read as native endian so it gets echoed
1058*61c4878aSAndroid Build Coastguard Worker       // exactly as-is.
1059*61c4878aSAndroid Build Coastguard Worker       .opaque_data = builder.begin().ReadUint64(endian::native),
1060*61c4878aSAndroid Build Coastguard Worker   };
1061*61c4878aSAndroid Build Coastguard Worker   PW_TRY(connection_.send_queue_.SendBytes(AsBytes(ack_frame)));
1062*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
1063*61c4878aSAndroid Build Coastguard Worker }
1064*61c4878aSAndroid Build Coastguard Worker 
1065*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.9
ProcessWindowUpdateFrame(const FrameHeader & frame)1066*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::ProcessWindowUpdateFrame(const FrameHeader& frame) {
1067*61c4878aSAndroid Build Coastguard Worker   PW_LOG_DEBUG("Conn.Recv WINDOW_UPDATE id=%" PRIu32 " len=%" PRIu32,
1068*61c4878aSAndroid Build Coastguard Worker                frame.stream_id,
1069*61c4878aSAndroid Build Coastguard Worker                frame.payload_length);
1070*61c4878aSAndroid Build Coastguard Worker 
1071*61c4878aSAndroid Build Coastguard Worker   if (frame.payload_length != 4) {
1072*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.9: "A WINDOW_UPDATE frame with a length other than 4 octets
1073*61c4878aSAndroid Build Coastguard Worker     // MUST be treated as a connection error of type FRAME_SIZE_ERROR."
1074*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::FRAME_SIZE_ERROR);
1075*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
1076*61c4878aSAndroid Build Coastguard Worker   }
1077*61c4878aSAndroid Build Coastguard Worker 
1078*61c4878aSAndroid Build Coastguard Worker   // Read window size increment.
1079*61c4878aSAndroid Build Coastguard Worker   PW_TRY_ASSIGN(auto payload, ReadFramePayload(frame));
1080*61c4878aSAndroid Build Coastguard Worker   ByteBuilder builder(payload);
1081*61c4878aSAndroid Build Coastguard Worker   int32_t delta = static_cast<int32_t>(builder.begin().ReadUint32(endian::big) &
1082*61c4878aSAndroid Build Coastguard Worker                                        0x7fffffff);
1083*61c4878aSAndroid Build Coastguard Worker 
1084*61c4878aSAndroid Build Coastguard Worker   auto state = connection_.LockState();
1085*61c4878aSAndroid Build Coastguard Worker   auto stream = state->LookupStream(frame.stream_id);
1086*61c4878aSAndroid Build Coastguard Worker 
1087*61c4878aSAndroid Build Coastguard Worker   if (delta == 0) {
1088*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §6.9: "A receiver MUST treat a WINDOW_UPDATE frame with an
1089*61c4878aSAndroid Build Coastguard Worker     // increment of 0 as a stream error of type PROTOCOL_ERROR; errors on the
1090*61c4878aSAndroid Build Coastguard Worker     // connection flow-control window MUST be treated as a connection error."
1091*61c4878aSAndroid Build Coastguard Worker     if (frame.stream_id == 0) {
1092*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::PROTOCOL_ERROR);
1093*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
1094*61c4878aSAndroid Build Coastguard Worker     } else {
1095*61c4878aSAndroid Build Coastguard Worker       if (!stream.ok()) {
1096*61c4878aSAndroid Build Coastguard Worker         // Already closed
1097*61c4878aSAndroid Build Coastguard Worker         return OkStatus();
1098*61c4878aSAndroid Build Coastguard Worker       }
1099*61c4878aSAndroid Build Coastguard Worker       PW_TRY(SendRstStreamAndClose(stream->get(), Http2Error::PROTOCOL_ERROR));
1100*61c4878aSAndroid Build Coastguard Worker       return OkStatus();
1101*61c4878aSAndroid Build Coastguard Worker     }
1102*61c4878aSAndroid Build Coastguard Worker   }
1103*61c4878aSAndroid Build Coastguard Worker 
1104*61c4878aSAndroid Build Coastguard Worker   // RFC 9113 §6.9.1: "If a sender receives a WINDOW_UPDATE that causes a
1105*61c4878aSAndroid Build Coastguard Worker   // flow-control window to exceed 2^31-1 bytes, it MUST terminate either the
1106*61c4878aSAndroid Build Coastguard Worker   // stream or the connection, as appropriate ... with an error code of
1107*61c4878aSAndroid Build Coastguard Worker   // FLOW_CONTROL_ERROR"
1108*61c4878aSAndroid Build Coastguard Worker   if (frame.stream_id == 0) {
1109*61c4878aSAndroid Build Coastguard Worker     if (PW_ADD_OVERFLOW(state->connection_send_window,
1110*61c4878aSAndroid Build Coastguard Worker                         delta,
1111*61c4878aSAndroid Build Coastguard Worker                         &state->connection_send_window)) {
1112*61c4878aSAndroid Build Coastguard Worker       SendGoAway(Http2Error::FLOW_CONTROL_ERROR);
1113*61c4878aSAndroid Build Coastguard Worker       return Status::Internal();
1114*61c4878aSAndroid Build Coastguard Worker     }
1115*61c4878aSAndroid Build Coastguard Worker   } else if (stream.ok()) {
1116*61c4878aSAndroid Build Coastguard Worker     if (PW_ADD_OVERFLOW(
1117*61c4878aSAndroid Build Coastguard Worker             stream->get().send_window, delta, &stream->get().send_window)) {
1118*61c4878aSAndroid Build Coastguard Worker       PW_TRY(
1119*61c4878aSAndroid Build Coastguard Worker           SendRstStreamAndClose(stream->get(), Http2Error::FLOW_CONTROL_ERROR));
1120*61c4878aSAndroid Build Coastguard Worker       return OkStatus();
1121*61c4878aSAndroid Build Coastguard Worker     }
1122*61c4878aSAndroid Build Coastguard Worker   }
1123*61c4878aSAndroid Build Coastguard Worker 
1124*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
1125*61c4878aSAndroid Build Coastguard Worker }
1126*61c4878aSAndroid Build Coastguard Worker 
1127*61c4878aSAndroid Build Coastguard Worker // Advance past the payload.
ProcessIgnoredFrame(const FrameHeader & frame)1128*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::ProcessIgnoredFrame(const FrameHeader& frame) {
1129*61c4878aSAndroid Build Coastguard Worker   PW_TRY(ReadFramePayload(frame));
1130*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
1131*61c4878aSAndroid Build Coastguard Worker }
1132*61c4878aSAndroid Build Coastguard Worker 
ReadFramePayload(const FrameHeader & frame)1133*61c4878aSAndroid Build Coastguard Worker Result<ByteSpan> Connection::Reader::ReadFramePayload(
1134*61c4878aSAndroid Build Coastguard Worker     const FrameHeader& frame) {
1135*61c4878aSAndroid Build Coastguard Worker   if (frame.payload_length == 0) {
1136*61c4878aSAndroid Build Coastguard Worker     return ByteSpan();
1137*61c4878aSAndroid Build Coastguard Worker   }
1138*61c4878aSAndroid Build Coastguard Worker   if (frame.payload_length > payload_scratch_.size()) {
1139*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR("Frame type=%d payload too large: %" PRIu32 " > %" PRIu32,
1140*61c4878aSAndroid Build Coastguard Worker                  static_cast<int>(frame.type),
1141*61c4878aSAndroid Build Coastguard Worker                  frame.payload_length,
1142*61c4878aSAndroid Build Coastguard Worker                  static_cast<uint32_t>(payload_scratch_.size()));
1143*61c4878aSAndroid Build Coastguard Worker     SendGoAway(Http2Error::FRAME_SIZE_ERROR);
1144*61c4878aSAndroid Build Coastguard Worker     return Status::Internal();
1145*61c4878aSAndroid Build Coastguard Worker   }
1146*61c4878aSAndroid Build Coastguard Worker   auto payload = span{payload_scratch_}.subspan(0, frame.payload_length);
1147*61c4878aSAndroid Build Coastguard Worker   PW_TRY(ReadExactly(connection_.socket_.as_reader(), payload));
1148*61c4878aSAndroid Build Coastguard Worker   return payload;
1149*61c4878aSAndroid Build Coastguard Worker }
1150*61c4878aSAndroid Build Coastguard Worker 
1151*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.8
SendGoAway(Http2Error code)1152*61c4878aSAndroid Build Coastguard Worker void Connection::Reader::SendGoAway(Http2Error code) {
1153*61c4878aSAndroid Build Coastguard Worker   if (!received_connection_preface_) {
1154*61c4878aSAndroid Build Coastguard Worker     // RFC 9113 §3.4: "A GOAWAY frame MAY be omitted in this case, since an
1155*61c4878aSAndroid Build Coastguard Worker     // invalid preface indicates that the peer is not using HTTP/2."
1156*61c4878aSAndroid Build Coastguard Worker     return;
1157*61c4878aSAndroid Build Coastguard Worker   }
1158*61c4878aSAndroid Build Coastguard Worker 
1159*61c4878aSAndroid Build Coastguard Worker   // Close all open streams.
1160*61c4878aSAndroid Build Coastguard Worker   {
1161*61c4878aSAndroid Build Coastguard Worker     auto state = connection_.LockState();
1162*61c4878aSAndroid Build Coastguard Worker     for (size_t i = 0; i < state->streams.size(); i++) {
1163*61c4878aSAndroid Build Coastguard Worker       if (state->streams[i].id != 0) {
1164*61c4878aSAndroid Build Coastguard Worker         CloseStream(state->streams[i]);
1165*61c4878aSAndroid Build Coastguard Worker       }
1166*61c4878aSAndroid Build Coastguard Worker     }
1167*61c4878aSAndroid Build Coastguard Worker   }
1168*61c4878aSAndroid Build Coastguard Worker 
1169*61c4878aSAndroid Build Coastguard Worker   PW_PACKED(struct) GoAwayFrame {
1170*61c4878aSAndroid Build Coastguard Worker     WireFrameHeader header;
1171*61c4878aSAndroid Build Coastguard Worker     uint32_t last_stream_id;
1172*61c4878aSAndroid Build Coastguard Worker     uint32_t error_code;
1173*61c4878aSAndroid Build Coastguard Worker   };
1174*61c4878aSAndroid Build Coastguard Worker   GoAwayFrame frame{
1175*61c4878aSAndroid Build Coastguard Worker       .header = WireFrameHeader(FrameHeader{
1176*61c4878aSAndroid Build Coastguard Worker           .payload_length = 8,
1177*61c4878aSAndroid Build Coastguard Worker           .type = FrameType::GOAWAY,
1178*61c4878aSAndroid Build Coastguard Worker           .flags = 0,
1179*61c4878aSAndroid Build Coastguard Worker           .stream_id = 0,
1180*61c4878aSAndroid Build Coastguard Worker       }),
1181*61c4878aSAndroid Build Coastguard Worker       .last_stream_id = ToNetworkOrder(last_stream_id_),
1182*61c4878aSAndroid Build Coastguard Worker       .error_code = ToNetworkOrder(code),
1183*61c4878aSAndroid Build Coastguard Worker   };
1184*61c4878aSAndroid Build Coastguard Worker   // Ignore errors since we're about to close the connection anyway.
1185*61c4878aSAndroid Build Coastguard Worker   connection_.send_queue_.SendBytes(AsBytes(frame)).IgnoreError();
1186*61c4878aSAndroid Build Coastguard Worker }
1187*61c4878aSAndroid Build Coastguard Worker 
1188*61c4878aSAndroid Build Coastguard Worker // RFC 9113 §6.4
SendRstStreamAndClose(Stream & stream,Http2Error code)1189*61c4878aSAndroid Build Coastguard Worker Status Connection::Reader::SendRstStreamAndClose(Stream& stream,
1190*61c4878aSAndroid Build Coastguard Worker                                                  Http2Error code) {
1191*61c4878aSAndroid Build Coastguard Worker   // Ignore errors as we are closing anyways.
1192*61c4878aSAndroid Build Coastguard Worker   SendRstStream(connection_.send_queue_, stream.id, code).IgnoreError();
1193*61c4878aSAndroid Build Coastguard Worker   CloseStream(stream);
1194*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
1195*61c4878aSAndroid Build Coastguard Worker }
1196*61c4878aSAndroid Build Coastguard Worker 
1197*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::grpc
1198