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(¤t_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(¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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