xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/adapter/callback_visitor.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 #include "quiche/http2/adapter/callback_visitor.h"
2 
3 #include "absl/strings/escaping.h"
4 #include "quiche/http2/adapter/http2_util.h"
5 #include "quiche/http2/adapter/nghttp2.h"
6 #include "quiche/http2/adapter/nghttp2_util.h"
7 #include "quiche/common/quiche_endian.h"
8 
9 // This visitor implementation needs visibility into the
10 // nghttp2_session_callbacks type. There's no public header, so we'll redefine
11 // the struct here.
12 #ifdef NGHTTP2_16
13 namespace {
14 using FunctionPtr = void (*)(void);
15 }  // namespace
16 
17 struct nghttp2_session_callbacks {
18   nghttp2_send_callback send_callback;
19   FunctionPtr send_callback2;
20   nghttp2_recv_callback recv_callback;
21   FunctionPtr recv_callback2;
22   nghttp2_on_frame_recv_callback on_frame_recv_callback;
23   nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback;
24   nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback;
25   nghttp2_before_frame_send_callback before_frame_send_callback;
26   nghttp2_on_frame_send_callback on_frame_send_callback;
27   nghttp2_on_frame_not_send_callback on_frame_not_send_callback;
28   nghttp2_on_stream_close_callback on_stream_close_callback;
29   nghttp2_on_begin_headers_callback on_begin_headers_callback;
30   nghttp2_on_header_callback on_header_callback;
31   nghttp2_on_header_callback2 on_header_callback2;
32   nghttp2_on_invalid_header_callback on_invalid_header_callback;
33   nghttp2_on_invalid_header_callback2 on_invalid_header_callback2;
34   nghttp2_select_padding_callback select_padding_callback;
35   FunctionPtr select_padding_callback2;
36   nghttp2_data_source_read_length_callback read_length_callback;
37   FunctionPtr read_length_callback2;
38   nghttp2_on_begin_frame_callback on_begin_frame_callback;
39   nghttp2_send_data_callback send_data_callback;
40   nghttp2_pack_extension_callback pack_extension_callback;
41   FunctionPtr pack_extension_callback2;
42   nghttp2_unpack_extension_callback unpack_extension_callback;
43   nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
44   nghttp2_error_callback error_callback;
45   nghttp2_error_callback2 error_callback2;
46 };
47 #else
48 struct nghttp2_session_callbacks {
49   nghttp2_send_callback send_callback;
50   nghttp2_recv_callback recv_callback;
51   nghttp2_on_frame_recv_callback on_frame_recv_callback;
52   nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback;
53   nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback;
54   nghttp2_before_frame_send_callback before_frame_send_callback;
55   nghttp2_on_frame_send_callback on_frame_send_callback;
56   nghttp2_on_frame_not_send_callback on_frame_not_send_callback;
57   nghttp2_on_stream_close_callback on_stream_close_callback;
58   nghttp2_on_begin_headers_callback on_begin_headers_callback;
59   nghttp2_on_header_callback on_header_callback;
60   nghttp2_on_header_callback2 on_header_callback2;
61   nghttp2_on_invalid_header_callback on_invalid_header_callback;
62   nghttp2_on_invalid_header_callback2 on_invalid_header_callback2;
63   nghttp2_select_padding_callback select_padding_callback;
64   nghttp2_data_source_read_length_callback read_length_callback;
65   nghttp2_on_begin_frame_callback on_begin_frame_callback;
66   nghttp2_send_data_callback send_data_callback;
67   nghttp2_pack_extension_callback pack_extension_callback;
68   nghttp2_unpack_extension_callback unpack_extension_callback;
69   nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
70   nghttp2_error_callback error_callback;
71   nghttp2_error_callback2 error_callback2;
72 };
73 #endif
74 
75 namespace http2 {
76 namespace adapter {
77 
CallbackVisitor(Perspective perspective,const nghttp2_session_callbacks & callbacks,void * user_data)78 CallbackVisitor::CallbackVisitor(Perspective perspective,
79                                  const nghttp2_session_callbacks& callbacks,
80                                  void* user_data)
81     : perspective_(perspective),
82       callbacks_(MakeCallbacksPtr(nullptr)),
83       user_data_(user_data) {
84   nghttp2_session_callbacks* c;
85   nghttp2_session_callbacks_new(&c);
86   *c = callbacks;
87   callbacks_ = MakeCallbacksPtr(c);
88   memset(&current_frame_, 0, sizeof(current_frame_));
89 }
90 
OnReadyToSend(absl::string_view serialized)91 int64_t CallbackVisitor::OnReadyToSend(absl::string_view serialized) {
92   if (!callbacks_->send_callback) {
93     return kSendError;
94   }
95   int64_t result = callbacks_->send_callback(
96       nullptr, ToUint8Ptr(serialized.data()), serialized.size(), 0, user_data_);
97   QUICHE_VLOG(1) << "CallbackVisitor::OnReadyToSend called with "
98                  << serialized.size() << " bytes, returning " << result;
99   QUICHE_VLOG(2) << (perspective_ == Perspective::kClient ? "Client" : "Server")
100                  << " sending: [" << absl::CEscape(serialized) << "]";
101   if (result > 0) {
102     return result;
103   } else if (result == NGHTTP2_ERR_WOULDBLOCK) {
104     return kSendBlocked;
105   } else {
106     return kSendError;
107   }
108 }
109 
OnConnectionError(ConnectionError)110 void CallbackVisitor::OnConnectionError(ConnectionError /*error*/) {
111   QUICHE_VLOG(1) << "OnConnectionError not implemented";
112 }
113 
OnFrameHeader(Http2StreamId stream_id,size_t length,uint8_t type,uint8_t flags)114 bool CallbackVisitor::OnFrameHeader(Http2StreamId stream_id, size_t length,
115                                     uint8_t type, uint8_t flags) {
116   QUICHE_VLOG(1) << "CallbackVisitor::OnFrameHeader(stream_id=" << stream_id
117                  << ", type=" << int(type) << ", length=" << length
118                  << ", flags=" << int(flags) << ")";
119   if (static_cast<FrameType>(type) == FrameType::CONTINUATION) {
120     if (static_cast<FrameType>(current_frame_.hd.type) != FrameType::HEADERS ||
121         current_frame_.hd.stream_id == 0 ||
122         current_frame_.hd.stream_id != stream_id) {
123       // CONTINUATION frames must follow HEADERS on the same stream. If no
124       // frames have been received, the type is initialized to zero, and the
125       // comparison will fail.
126       return false;
127     }
128     current_frame_.hd.length += length;
129     current_frame_.hd.flags |= flags;
130     QUICHE_DLOG_IF(ERROR, length == 0) << "Empty CONTINUATION!";
131     // Still need to deliver the CONTINUATION to the begin frame callback.
132     nghttp2_frame_hd hd;
133     memset(&hd, 0, sizeof(hd));
134     hd.stream_id = stream_id;
135     hd.length = length;
136     hd.type = type;
137     hd.flags = flags;
138     if (callbacks_->on_begin_frame_callback) {
139       const int result =
140           callbacks_->on_begin_frame_callback(nullptr, &hd, user_data_);
141       return result == 0;
142     }
143     return true;
144   }
145   // The general strategy is to clear |current_frame_| at the start of a new
146   // frame, accumulate frame information from the various callback events, then
147   // invoke the on_frame_recv_callback() with the accumulated frame data.
148   memset(&current_frame_, 0, sizeof(current_frame_));
149   current_frame_.hd.stream_id = stream_id;
150   current_frame_.hd.length = length;
151   current_frame_.hd.type = type;
152   current_frame_.hd.flags = flags;
153   if (callbacks_->on_begin_frame_callback) {
154     const int result = callbacks_->on_begin_frame_callback(
155         nullptr, &current_frame_.hd, user_data_);
156     return result == 0;
157   }
158   return true;
159 }
160 
OnSettingsStart()161 void CallbackVisitor::OnSettingsStart() {}
162 
OnSetting(Http2Setting setting)163 void CallbackVisitor::OnSetting(Http2Setting setting) {
164   settings_.push_back({setting.id, setting.value});
165 }
166 
OnSettingsEnd()167 void CallbackVisitor::OnSettingsEnd() {
168   current_frame_.settings.niv = settings_.size();
169   current_frame_.settings.iv = settings_.data();
170   QUICHE_VLOG(1) << "OnSettingsEnd, received settings of size "
171                  << current_frame_.settings.niv;
172   if (callbacks_->on_frame_recv_callback) {
173     const int result = callbacks_->on_frame_recv_callback(
174         nullptr, &current_frame_, user_data_);
175     QUICHE_DCHECK_EQ(0, result);
176   }
177   settings_.clear();
178 }
179 
OnSettingsAck()180 void CallbackVisitor::OnSettingsAck() {
181   // ACK is part of the flags, which were set in OnFrameHeader().
182   QUICHE_VLOG(1) << "OnSettingsAck()";
183   if (callbacks_->on_frame_recv_callback) {
184     const int result = callbacks_->on_frame_recv_callback(
185         nullptr, &current_frame_, user_data_);
186     QUICHE_DCHECK_EQ(0, result);
187   }
188 }
189 
OnBeginHeadersForStream(Http2StreamId stream_id)190 bool CallbackVisitor::OnBeginHeadersForStream(Http2StreamId stream_id) {
191   auto it = GetStreamInfo(stream_id);
192   if (it == stream_map_.end()) {
193     current_frame_.headers.cat = NGHTTP2_HCAT_HEADERS;
194   } else {
195     if (it->second.received_headers) {
196       // At least one headers frame has already been received.
197       QUICHE_VLOG(1)
198           << "Headers already received for stream " << stream_id
199           << ", these are trailers or headers following a 100 response";
200       current_frame_.headers.cat = NGHTTP2_HCAT_HEADERS;
201     } else {
202       switch (perspective_) {
203         case Perspective::kClient:
204           QUICHE_VLOG(1) << "First headers at the client for stream "
205                          << stream_id << "; these are response headers";
206           current_frame_.headers.cat = NGHTTP2_HCAT_RESPONSE;
207           break;
208         case Perspective::kServer:
209           QUICHE_VLOG(1) << "First headers at the server for stream "
210                          << stream_id << "; these are request headers";
211           current_frame_.headers.cat = NGHTTP2_HCAT_REQUEST;
212           break;
213       }
214     }
215     it->second.received_headers = true;
216   }
217   if (callbacks_->on_begin_headers_callback) {
218     const int result = callbacks_->on_begin_headers_callback(
219         nullptr, &current_frame_, user_data_);
220     return result == 0;
221   }
222   return true;
223 }
224 
OnHeaderForStream(Http2StreamId stream_id,absl::string_view name,absl::string_view value)225 Http2VisitorInterface::OnHeaderResult CallbackVisitor::OnHeaderForStream(
226     Http2StreamId stream_id, absl::string_view name, absl::string_view value) {
227   QUICHE_VLOG(2) << "OnHeaderForStream(stream_id=" << stream_id << ", name=["
228                  << absl::CEscape(name) << "], value=[" << absl::CEscape(value)
229                  << "])";
230   if (callbacks_->on_header_callback) {
231     const int result = callbacks_->on_header_callback(
232         nullptr, &current_frame_, ToUint8Ptr(name.data()), name.size(),
233         ToUint8Ptr(value.data()), value.size(), NGHTTP2_NV_FLAG_NONE,
234         user_data_);
235     if (result == 0) {
236       return HEADER_OK;
237     } else if (result == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
238       return HEADER_RST_STREAM;
239     } else {
240       // Assume NGHTTP2_ERR_CALLBACK_FAILURE.
241       return HEADER_CONNECTION_ERROR;
242     }
243   }
244   return HEADER_OK;
245 }
246 
OnEndHeadersForStream(Http2StreamId stream_id)247 bool CallbackVisitor::OnEndHeadersForStream(Http2StreamId stream_id) {
248   QUICHE_VLOG(1) << "OnEndHeadersForStream(stream_id=" << stream_id << ")";
249   if (callbacks_->on_frame_recv_callback) {
250     const int result = callbacks_->on_frame_recv_callback(
251         nullptr, &current_frame_, user_data_);
252     return result == 0;
253   }
254   return true;
255 }
256 
OnDataPaddingLength(Http2StreamId,size_t padding_length)257 bool CallbackVisitor::OnDataPaddingLength(Http2StreamId /*stream_id*/,
258                                           size_t padding_length) {
259   current_frame_.data.padlen = padding_length;
260   remaining_data_ -= padding_length;
261   if (remaining_data_ == 0 &&
262       (current_frame_.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0 &&
263       callbacks_->on_frame_recv_callback != nullptr) {
264     const int result = callbacks_->on_frame_recv_callback(
265         nullptr, &current_frame_, user_data_);
266     return result == 0;
267   }
268   return true;
269 }
270 
OnBeginDataForStream(Http2StreamId,size_t payload_length)271 bool CallbackVisitor::OnBeginDataForStream(Http2StreamId /*stream_id*/,
272                                            size_t payload_length) {
273   remaining_data_ = payload_length;
274   if (remaining_data_ == 0 &&
275       (current_frame_.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0 &&
276       callbacks_->on_frame_recv_callback != nullptr) {
277     const int result = callbacks_->on_frame_recv_callback(
278         nullptr, &current_frame_, user_data_);
279     return result == 0;
280   }
281   return true;
282 }
283 
OnDataForStream(Http2StreamId stream_id,absl::string_view data)284 bool CallbackVisitor::OnDataForStream(Http2StreamId stream_id,
285                                       absl::string_view data) {
286   QUICHE_VLOG(1) << "OnDataForStream(stream_id=" << stream_id
287                  << ", data.size()=" << data.size() << ")";
288   int result = 0;
289   if (callbacks_->on_data_chunk_recv_callback) {
290     result = callbacks_->on_data_chunk_recv_callback(
291         nullptr, current_frame_.hd.flags, stream_id, ToUint8Ptr(data.data()),
292         data.size(), user_data_);
293   }
294   remaining_data_ -= data.size();
295   if (result == 0 && remaining_data_ == 0 &&
296       (current_frame_.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0 &&
297       callbacks_->on_frame_recv_callback) {
298     // If the DATA frame contains the END_STREAM flag, `on_frame_recv` is
299     // invoked later.
300     result = callbacks_->on_frame_recv_callback(nullptr, &current_frame_,
301                                                 user_data_);
302   }
303   return result == 0;
304 }
305 
OnEndStream(Http2StreamId stream_id)306 bool CallbackVisitor::OnEndStream(Http2StreamId stream_id) {
307   QUICHE_VLOG(1) << "OnEndStream(stream_id=" << stream_id << ")";
308   int result = 0;
309   if (static_cast<FrameType>(current_frame_.hd.type) == FrameType::DATA &&
310       (current_frame_.hd.flags & NGHTTP2_FLAG_END_STREAM) != 0 &&
311       callbacks_->on_frame_recv_callback) {
312     // `on_frame_recv` is invoked here to ensure that the Http2Adapter
313     // implementation has successfully validated and processed the entire DATA
314     // frame.
315     result = callbacks_->on_frame_recv_callback(nullptr, &current_frame_,
316                                                 user_data_);
317   }
318   return result == 0;
319 }
320 
OnRstStream(Http2StreamId stream_id,Http2ErrorCode error_code)321 void CallbackVisitor::OnRstStream(Http2StreamId stream_id,
322                                   Http2ErrorCode error_code) {
323   QUICHE_VLOG(1) << "OnRstStream(stream_id=" << stream_id
324                  << ", error_code=" << static_cast<int>(error_code) << ")";
325   current_frame_.rst_stream.error_code = static_cast<uint32_t>(error_code);
326   if (callbacks_->on_frame_recv_callback) {
327     const int result = callbacks_->on_frame_recv_callback(
328         nullptr, &current_frame_, user_data_);
329     QUICHE_DCHECK_EQ(0, result);
330   }
331 }
332 
OnCloseStream(Http2StreamId stream_id,Http2ErrorCode error_code)333 bool CallbackVisitor::OnCloseStream(Http2StreamId stream_id,
334                                     Http2ErrorCode error_code) {
335   QUICHE_VLOG(1) << "OnCloseStream(stream_id=" << stream_id
336                  << ", error_code=" << static_cast<int>(error_code) << ")";
337   int result = 0;
338   if (callbacks_->on_stream_close_callback) {
339     result = callbacks_->on_stream_close_callback(
340         nullptr, stream_id, static_cast<uint32_t>(error_code), user_data_);
341   }
342   stream_map_.erase(stream_id);
343   if (stream_close_listener_) {
344     stream_close_listener_(stream_id);
345   }
346   return result == 0;
347 }
348 
OnPriorityForStream(Http2StreamId,Http2StreamId parent_stream_id,int weight,bool exclusive)349 void CallbackVisitor::OnPriorityForStream(Http2StreamId /*stream_id*/,
350                                           Http2StreamId parent_stream_id,
351                                           int weight, bool exclusive) {
352   current_frame_.priority.pri_spec.stream_id = parent_stream_id;
353   current_frame_.priority.pri_spec.weight = weight;
354   current_frame_.priority.pri_spec.exclusive = exclusive;
355   if (callbacks_->on_frame_recv_callback) {
356     const int result = callbacks_->on_frame_recv_callback(
357         nullptr, &current_frame_, user_data_);
358     QUICHE_DCHECK_EQ(0, result);
359   }
360 }
361 
OnPing(Http2PingId ping_id,bool is_ack)362 void CallbackVisitor::OnPing(Http2PingId ping_id, bool is_ack) {
363   QUICHE_VLOG(1) << "OnPing(ping_id=" << static_cast<int64_t>(ping_id)
364                  << ", is_ack=" << is_ack << ")";
365   uint64_t network_order_opaque_data =
366       quiche::QuicheEndian::HostToNet64(ping_id);
367   std::memcpy(current_frame_.ping.opaque_data, &network_order_opaque_data,
368               sizeof(network_order_opaque_data));
369   if (callbacks_->on_frame_recv_callback) {
370     const int result = callbacks_->on_frame_recv_callback(
371         nullptr, &current_frame_, user_data_);
372     QUICHE_DCHECK_EQ(0, result);
373   }
374 }
375 
OnPushPromiseForStream(Http2StreamId,Http2StreamId)376 void CallbackVisitor::OnPushPromiseForStream(
377     Http2StreamId /*stream_id*/, Http2StreamId /*promised_stream_id*/) {
378   QUICHE_LOG(DFATAL) << "Not implemented";
379 }
380 
OnGoAway(Http2StreamId last_accepted_stream_id,Http2ErrorCode error_code,absl::string_view opaque_data)381 bool CallbackVisitor::OnGoAway(Http2StreamId last_accepted_stream_id,
382                                Http2ErrorCode error_code,
383                                absl::string_view opaque_data) {
384   QUICHE_VLOG(1) << "OnGoAway(last_accepted_stream_id="
385                  << last_accepted_stream_id
386                  << ", error_code=" << static_cast<int>(error_code)
387                  << ", opaque_data=[" << absl::CEscape(opaque_data) << "])";
388   current_frame_.goaway.last_stream_id = last_accepted_stream_id;
389   current_frame_.goaway.error_code = static_cast<uint32_t>(error_code);
390   current_frame_.goaway.opaque_data = ToUint8Ptr(opaque_data.data());
391   current_frame_.goaway.opaque_data_len = opaque_data.size();
392   if (callbacks_->on_frame_recv_callback) {
393     const int result = callbacks_->on_frame_recv_callback(
394         nullptr, &current_frame_, user_data_);
395     return result == 0;
396   }
397   return true;
398 }
399 
OnWindowUpdate(Http2StreamId stream_id,int window_increment)400 void CallbackVisitor::OnWindowUpdate(Http2StreamId stream_id,
401                                      int window_increment) {
402   QUICHE_VLOG(1) << "OnWindowUpdate(stream_id=" << stream_id
403                  << ", delta=" << window_increment << ")";
404   current_frame_.window_update.window_size_increment = window_increment;
405   if (callbacks_->on_frame_recv_callback) {
406     const int result = callbacks_->on_frame_recv_callback(
407         nullptr, &current_frame_, user_data_);
408     QUICHE_DCHECK_EQ(0, result);
409   }
410 }
411 
PopulateFrame(nghttp2_frame & frame,uint8_t frame_type,Http2StreamId stream_id,size_t length,uint8_t flags,uint32_t error_code,bool sent_headers)412 void CallbackVisitor::PopulateFrame(nghttp2_frame& frame, uint8_t frame_type,
413                                     Http2StreamId stream_id, size_t length,
414                                     uint8_t flags, uint32_t error_code,
415                                     bool sent_headers) {
416   frame.hd.type = frame_type;
417   frame.hd.stream_id = stream_id;
418   frame.hd.length = length;
419   frame.hd.flags = flags;
420   const FrameType frame_type_enum = static_cast<FrameType>(frame_type);
421   if (frame_type_enum == FrameType::HEADERS) {
422     if (sent_headers) {
423       frame.headers.cat = NGHTTP2_HCAT_HEADERS;
424     } else {
425       switch (perspective_) {
426         case Perspective::kClient:
427           QUICHE_VLOG(1) << "First headers sent by the client for stream "
428                          << stream_id << "; these are request headers";
429           frame.headers.cat = NGHTTP2_HCAT_REQUEST;
430           break;
431         case Perspective::kServer:
432           QUICHE_VLOG(1) << "First headers sent by the server for stream "
433                          << stream_id << "; these are response headers";
434           frame.headers.cat = NGHTTP2_HCAT_RESPONSE;
435           break;
436       }
437     }
438   } else if (frame_type_enum == FrameType::RST_STREAM) {
439     frame.rst_stream.error_code = error_code;
440   } else if (frame_type_enum == FrameType::GOAWAY) {
441     frame.goaway.error_code = error_code;
442   }
443 }
444 
OnBeforeFrameSent(uint8_t frame_type,Http2StreamId stream_id,size_t length,uint8_t flags)445 int CallbackVisitor::OnBeforeFrameSent(uint8_t frame_type,
446                                        Http2StreamId stream_id, size_t length,
447                                        uint8_t flags) {
448   QUICHE_VLOG(1) << "OnBeforeFrameSent(stream_id=" << stream_id
449                  << ", type=" << int(frame_type) << ", length=" << length
450                  << ", flags=" << int(flags) << ")";
451   if (callbacks_->before_frame_send_callback) {
452     nghttp2_frame frame;
453     bool before_sent_headers = true;
454     auto it = GetStreamInfo(stream_id);
455     if (it != stream_map_.end()) {
456       before_sent_headers = it->second.before_sent_headers;
457       it->second.before_sent_headers = true;
458     }
459     // The implementation of the before_frame_send_callback doesn't look at the
460     // error code, so for now it's populated with 0.
461     PopulateFrame(frame, frame_type, stream_id, length, flags, /*error_code=*/0,
462                   before_sent_headers);
463     return callbacks_->before_frame_send_callback(nullptr, &frame, user_data_);
464   }
465   return 0;
466 }
467 
OnFrameSent(uint8_t frame_type,Http2StreamId stream_id,size_t length,uint8_t flags,uint32_t error_code)468 int CallbackVisitor::OnFrameSent(uint8_t frame_type, Http2StreamId stream_id,
469                                  size_t length, uint8_t flags,
470                                  uint32_t error_code) {
471   QUICHE_VLOG(1) << "OnFrameSent(stream_id=" << stream_id
472                  << ", type=" << int(frame_type) << ", length=" << length
473                  << ", flags=" << int(flags) << ", error_code=" << error_code
474                  << ")";
475   if (callbacks_->on_frame_send_callback) {
476     nghttp2_frame frame;
477     bool sent_headers = true;
478     auto it = GetStreamInfo(stream_id);
479     if (it != stream_map_.end()) {
480       sent_headers = it->second.sent_headers;
481       it->second.sent_headers = true;
482     }
483     PopulateFrame(frame, frame_type, stream_id, length, flags, error_code,
484                   sent_headers);
485     return callbacks_->on_frame_send_callback(nullptr, &frame, user_data_);
486   }
487   return 0;
488 }
489 
OnInvalidFrame(Http2StreamId stream_id,InvalidFrameError error)490 bool CallbackVisitor::OnInvalidFrame(Http2StreamId stream_id,
491                                      InvalidFrameError error) {
492   QUICHE_VLOG(1) << "OnInvalidFrame(" << stream_id << ", "
493                  << InvalidFrameErrorToString(error) << ")";
494   QUICHE_DCHECK_EQ(stream_id, current_frame_.hd.stream_id);
495   if (callbacks_->on_invalid_frame_recv_callback) {
496     return 0 ==
497            callbacks_->on_invalid_frame_recv_callback(
498                nullptr, &current_frame_, ToNgHttp2ErrorCode(error), user_data_);
499   }
500   return true;
501 }
502 
OnBeginMetadataForStream(Http2StreamId stream_id,size_t payload_length)503 void CallbackVisitor::OnBeginMetadataForStream(Http2StreamId stream_id,
504                                                size_t payload_length) {
505   QUICHE_VLOG(1) << "OnBeginMetadataForStream(stream_id=" << stream_id
506                  << ", payload_length=" << payload_length << ")";
507 }
508 
OnMetadataForStream(Http2StreamId stream_id,absl::string_view metadata)509 bool CallbackVisitor::OnMetadataForStream(Http2StreamId stream_id,
510                                           absl::string_view metadata) {
511   QUICHE_VLOG(1) << "OnMetadataForStream(stream_id=" << stream_id
512                  << ", len=" << metadata.size() << ")";
513   if (callbacks_->on_extension_chunk_recv_callback) {
514     int result = callbacks_->on_extension_chunk_recv_callback(
515         nullptr, &current_frame_.hd, ToUint8Ptr(metadata.data()),
516         metadata.size(), user_data_);
517     return result == 0;
518   }
519   return true;
520 }
521 
OnMetadataEndForStream(Http2StreamId stream_id)522 bool CallbackVisitor::OnMetadataEndForStream(Http2StreamId stream_id) {
523   if ((current_frame_.hd.flags & kMetadataEndFlag) == 0) {
524     QUICHE_VLOG(1) << "Expected kMetadataEndFlag during call to "
525                    << "OnMetadataEndForStream!";
526     return true;
527   }
528   QUICHE_VLOG(1) << "OnMetadataEndForStream(stream_id=" << stream_id << ")";
529   if (callbacks_->unpack_extension_callback) {
530     void* payload;
531     int result = callbacks_->unpack_extension_callback(
532         nullptr, &payload, &current_frame_.hd, user_data_);
533     if (result == 0 && callbacks_->on_frame_recv_callback) {
534       current_frame_.ext.payload = payload;
535       result = callbacks_->on_frame_recv_callback(nullptr, &current_frame_,
536                                                   user_data_);
537     }
538     return (result == 0);
539   }
540   return true;
541 }
542 
OnErrorDebug(absl::string_view message)543 void CallbackVisitor::OnErrorDebug(absl::string_view message) {
544   QUICHE_VLOG(1) << "OnErrorDebug(message=[" << absl::CEscape(message) << "])";
545   if (callbacks_->error_callback2) {
546     callbacks_->error_callback2(nullptr, -1, message.data(), message.size(),
547                                 user_data_);
548   }
549 }
550 
GetStreamInfo(Http2StreamId stream_id)551 CallbackVisitor::StreamInfoMap::iterator CallbackVisitor::GetStreamInfo(
552     Http2StreamId stream_id) {
553   auto it = stream_map_.find(stream_id);
554   if (it == stream_map_.end() && stream_id > stream_id_watermark_) {
555     auto p = stream_map_.insert({stream_id, {}});
556     it = p.first;
557     stream_id_watermark_ = stream_id;
558   }
559   return it;
560 }
561 
562 }  // namespace adapter
563 }  // namespace http2
564