1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/core/frames/quic_frame.h"
6
7 #include "quiche/quic/core/frames/quic_new_connection_id_frame.h"
8 #include "quiche/quic/core/frames/quic_retire_connection_id_frame.h"
9 #include "quiche/quic/core/quic_constants.h"
10 #include "quiche/quic/core/quic_types.h"
11 #include "quiche/quic/platform/api/quic_bug_tracker.h"
12 #include "quiche/quic/platform/api/quic_logging.h"
13 #include "quiche/common/platform/api/quiche_mem_slice.h"
14 #include "quiche/common/quiche_buffer_allocator.h"
15
16 namespace quic {
17
QuicFrame()18 QuicFrame::QuicFrame() {}
19
QuicFrame(QuicPaddingFrame padding_frame)20 QuicFrame::QuicFrame(QuicPaddingFrame padding_frame)
21 : padding_frame(padding_frame) {}
22
QuicFrame(QuicStreamFrame stream_frame)23 QuicFrame::QuicFrame(QuicStreamFrame stream_frame)
24 : stream_frame(stream_frame) {}
25
QuicFrame(QuicHandshakeDoneFrame handshake_done_frame)26 QuicFrame::QuicFrame(QuicHandshakeDoneFrame handshake_done_frame)
27 : handshake_done_frame(handshake_done_frame) {}
28
QuicFrame(QuicCryptoFrame * crypto_frame)29 QuicFrame::QuicFrame(QuicCryptoFrame* crypto_frame)
30 : type(CRYPTO_FRAME), crypto_frame(crypto_frame) {}
31
QuicFrame(QuicAckFrame * frame)32 QuicFrame::QuicFrame(QuicAckFrame* frame) : type(ACK_FRAME), ack_frame(frame) {}
33
QuicFrame(QuicMtuDiscoveryFrame frame)34 QuicFrame::QuicFrame(QuicMtuDiscoveryFrame frame)
35 : mtu_discovery_frame(frame) {}
36
QuicFrame(QuicStopWaitingFrame frame)37 QuicFrame::QuicFrame(QuicStopWaitingFrame frame) : stop_waiting_frame(frame) {}
38
QuicFrame(QuicPingFrame frame)39 QuicFrame::QuicFrame(QuicPingFrame frame) : ping_frame(frame) {}
40
QuicFrame(QuicRstStreamFrame * frame)41 QuicFrame::QuicFrame(QuicRstStreamFrame* frame)
42 : type(RST_STREAM_FRAME), rst_stream_frame(frame) {}
43
QuicFrame(QuicConnectionCloseFrame * frame)44 QuicFrame::QuicFrame(QuicConnectionCloseFrame* frame)
45 : type(CONNECTION_CLOSE_FRAME), connection_close_frame(frame) {}
46
QuicFrame(QuicGoAwayFrame * frame)47 QuicFrame::QuicFrame(QuicGoAwayFrame* frame)
48 : type(GOAWAY_FRAME), goaway_frame(frame) {}
49
QuicFrame(QuicWindowUpdateFrame frame)50 QuicFrame::QuicFrame(QuicWindowUpdateFrame frame)
51 : window_update_frame(frame) {}
52
QuicFrame(QuicBlockedFrame frame)53 QuicFrame::QuicFrame(QuicBlockedFrame frame) : blocked_frame(frame) {}
54
QuicFrame(QuicNewConnectionIdFrame * frame)55 QuicFrame::QuicFrame(QuicNewConnectionIdFrame* frame)
56 : type(NEW_CONNECTION_ID_FRAME), new_connection_id_frame(frame) {}
57
QuicFrame(QuicRetireConnectionIdFrame * frame)58 QuicFrame::QuicFrame(QuicRetireConnectionIdFrame* frame)
59 : type(RETIRE_CONNECTION_ID_FRAME), retire_connection_id_frame(frame) {}
60
QuicFrame(QuicMaxStreamsFrame frame)61 QuicFrame::QuicFrame(QuicMaxStreamsFrame frame) : max_streams_frame(frame) {}
62
QuicFrame(QuicStreamsBlockedFrame frame)63 QuicFrame::QuicFrame(QuicStreamsBlockedFrame frame)
64 : streams_blocked_frame(frame) {}
65
QuicFrame(QuicPathResponseFrame frame)66 QuicFrame::QuicFrame(QuicPathResponseFrame frame)
67 : path_response_frame(frame) {}
68
QuicFrame(QuicPathChallengeFrame frame)69 QuicFrame::QuicFrame(QuicPathChallengeFrame frame)
70 : path_challenge_frame(frame) {}
71
QuicFrame(QuicStopSendingFrame frame)72 QuicFrame::QuicFrame(QuicStopSendingFrame frame) : stop_sending_frame(frame) {}
73
QuicFrame(QuicMessageFrame * frame)74 QuicFrame::QuicFrame(QuicMessageFrame* frame)
75 : type(MESSAGE_FRAME), message_frame(frame) {}
76
QuicFrame(QuicNewTokenFrame * frame)77 QuicFrame::QuicFrame(QuicNewTokenFrame* frame)
78 : type(NEW_TOKEN_FRAME), new_token_frame(frame) {}
79
QuicFrame(QuicAckFrequencyFrame * frame)80 QuicFrame::QuicFrame(QuicAckFrequencyFrame* frame)
81 : type(ACK_FREQUENCY_FRAME), ack_frequency_frame(frame) {}
82
DeleteFrames(QuicFrames * frames)83 void DeleteFrames(QuicFrames* frames) {
84 for (QuicFrame& frame : *frames) {
85 DeleteFrame(&frame);
86 }
87 frames->clear();
88 }
89
DeleteFrame(QuicFrame * frame)90 void DeleteFrame(QuicFrame* frame) {
91 #if QUIC_FRAME_DEBUG
92 // If the frame is not inlined, check that it can be safely deleted.
93 if (frame->type != PADDING_FRAME && frame->type != MTU_DISCOVERY_FRAME &&
94 frame->type != PING_FRAME && frame->type != MAX_STREAMS_FRAME &&
95 frame->type != STOP_WAITING_FRAME &&
96 frame->type != STREAMS_BLOCKED_FRAME && frame->type != STREAM_FRAME &&
97 frame->type != HANDSHAKE_DONE_FRAME &&
98 frame->type != WINDOW_UPDATE_FRAME && frame->type != BLOCKED_FRAME &&
99 frame->type != STOP_SENDING_FRAME &&
100 frame->type != PATH_CHALLENGE_FRAME &&
101 frame->type != PATH_RESPONSE_FRAME) {
102 QUICHE_CHECK(!frame->delete_forbidden) << *frame;
103 }
104 #endif // QUIC_FRAME_DEBUG
105 switch (frame->type) {
106 // Frames smaller than a pointer are inlined, so don't need to be deleted.
107 case PADDING_FRAME:
108 case MTU_DISCOVERY_FRAME:
109 case PING_FRAME:
110 case MAX_STREAMS_FRAME:
111 case STOP_WAITING_FRAME:
112 case STREAMS_BLOCKED_FRAME:
113 case STREAM_FRAME:
114 case HANDSHAKE_DONE_FRAME:
115 case WINDOW_UPDATE_FRAME:
116 case BLOCKED_FRAME:
117 case STOP_SENDING_FRAME:
118 case PATH_CHALLENGE_FRAME:
119 case PATH_RESPONSE_FRAME:
120 break;
121 case ACK_FRAME:
122 delete frame->ack_frame;
123 break;
124 case RST_STREAM_FRAME:
125 delete frame->rst_stream_frame;
126 break;
127 case CONNECTION_CLOSE_FRAME:
128 delete frame->connection_close_frame;
129 break;
130 case GOAWAY_FRAME:
131 delete frame->goaway_frame;
132 break;
133 case NEW_CONNECTION_ID_FRAME:
134 delete frame->new_connection_id_frame;
135 break;
136 case RETIRE_CONNECTION_ID_FRAME:
137 delete frame->retire_connection_id_frame;
138 break;
139 case MESSAGE_FRAME:
140 delete frame->message_frame;
141 break;
142 case CRYPTO_FRAME:
143 delete frame->crypto_frame;
144 break;
145 case NEW_TOKEN_FRAME:
146 delete frame->new_token_frame;
147 break;
148 case ACK_FREQUENCY_FRAME:
149 delete frame->ack_frequency_frame;
150 break;
151 case NUM_FRAME_TYPES:
152 QUICHE_DCHECK(false) << "Cannot delete type: " << frame->type;
153 }
154 }
155
RemoveFramesForStream(QuicFrames * frames,QuicStreamId stream_id)156 void RemoveFramesForStream(QuicFrames* frames, QuicStreamId stream_id) {
157 auto it = frames->begin();
158 while (it != frames->end()) {
159 if (it->type != STREAM_FRAME || it->stream_frame.stream_id != stream_id) {
160 ++it;
161 continue;
162 }
163 it = frames->erase(it);
164 }
165 }
166
IsControlFrame(QuicFrameType type)167 bool IsControlFrame(QuicFrameType type) {
168 switch (type) {
169 case RST_STREAM_FRAME:
170 case GOAWAY_FRAME:
171 case WINDOW_UPDATE_FRAME:
172 case BLOCKED_FRAME:
173 case STREAMS_BLOCKED_FRAME:
174 case MAX_STREAMS_FRAME:
175 case PING_FRAME:
176 case STOP_SENDING_FRAME:
177 case NEW_CONNECTION_ID_FRAME:
178 case RETIRE_CONNECTION_ID_FRAME:
179 case HANDSHAKE_DONE_FRAME:
180 case ACK_FREQUENCY_FRAME:
181 case NEW_TOKEN_FRAME:
182 return true;
183 default:
184 return false;
185 }
186 }
187
GetControlFrameId(const QuicFrame & frame)188 QuicControlFrameId GetControlFrameId(const QuicFrame& frame) {
189 switch (frame.type) {
190 case RST_STREAM_FRAME:
191 return frame.rst_stream_frame->control_frame_id;
192 case GOAWAY_FRAME:
193 return frame.goaway_frame->control_frame_id;
194 case WINDOW_UPDATE_FRAME:
195 return frame.window_update_frame.control_frame_id;
196 case BLOCKED_FRAME:
197 return frame.blocked_frame.control_frame_id;
198 case STREAMS_BLOCKED_FRAME:
199 return frame.streams_blocked_frame.control_frame_id;
200 case MAX_STREAMS_FRAME:
201 return frame.max_streams_frame.control_frame_id;
202 case PING_FRAME:
203 return frame.ping_frame.control_frame_id;
204 case STOP_SENDING_FRAME:
205 return frame.stop_sending_frame.control_frame_id;
206 case NEW_CONNECTION_ID_FRAME:
207 return frame.new_connection_id_frame->control_frame_id;
208 case RETIRE_CONNECTION_ID_FRAME:
209 return frame.retire_connection_id_frame->control_frame_id;
210 case HANDSHAKE_DONE_FRAME:
211 return frame.handshake_done_frame.control_frame_id;
212 case ACK_FREQUENCY_FRAME:
213 return frame.ack_frequency_frame->control_frame_id;
214 case NEW_TOKEN_FRAME:
215 return frame.new_token_frame->control_frame_id;
216 default:
217 return kInvalidControlFrameId;
218 }
219 }
220
SetControlFrameId(QuicControlFrameId control_frame_id,QuicFrame * frame)221 void SetControlFrameId(QuicControlFrameId control_frame_id, QuicFrame* frame) {
222 switch (frame->type) {
223 case RST_STREAM_FRAME:
224 frame->rst_stream_frame->control_frame_id = control_frame_id;
225 return;
226 case GOAWAY_FRAME:
227 frame->goaway_frame->control_frame_id = control_frame_id;
228 return;
229 case WINDOW_UPDATE_FRAME:
230 frame->window_update_frame.control_frame_id = control_frame_id;
231 return;
232 case BLOCKED_FRAME:
233 frame->blocked_frame.control_frame_id = control_frame_id;
234 return;
235 case PING_FRAME:
236 frame->ping_frame.control_frame_id = control_frame_id;
237 return;
238 case STREAMS_BLOCKED_FRAME:
239 frame->streams_blocked_frame.control_frame_id = control_frame_id;
240 return;
241 case MAX_STREAMS_FRAME:
242 frame->max_streams_frame.control_frame_id = control_frame_id;
243 return;
244 case STOP_SENDING_FRAME:
245 frame->stop_sending_frame.control_frame_id = control_frame_id;
246 return;
247 case NEW_CONNECTION_ID_FRAME:
248 frame->new_connection_id_frame->control_frame_id = control_frame_id;
249 return;
250 case RETIRE_CONNECTION_ID_FRAME:
251 frame->retire_connection_id_frame->control_frame_id = control_frame_id;
252 return;
253 case HANDSHAKE_DONE_FRAME:
254 frame->handshake_done_frame.control_frame_id = control_frame_id;
255 return;
256 case ACK_FREQUENCY_FRAME:
257 frame->ack_frequency_frame->control_frame_id = control_frame_id;
258 return;
259 case NEW_TOKEN_FRAME:
260 frame->new_token_frame->control_frame_id = control_frame_id;
261 return;
262 default:
263 QUIC_BUG(quic_bug_12594_1)
264 << "Try to set control frame id of a frame without control frame id";
265 }
266 }
267
CopyRetransmittableControlFrame(const QuicFrame & frame)268 QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame) {
269 QuicFrame copy;
270 switch (frame.type) {
271 case RST_STREAM_FRAME:
272 copy = QuicFrame(new QuicRstStreamFrame(*frame.rst_stream_frame));
273 break;
274 case GOAWAY_FRAME:
275 copy = QuicFrame(new QuicGoAwayFrame(*frame.goaway_frame));
276 break;
277 case WINDOW_UPDATE_FRAME:
278 copy = QuicFrame(QuicWindowUpdateFrame(frame.window_update_frame));
279 break;
280 case BLOCKED_FRAME:
281 copy = QuicFrame(QuicBlockedFrame(frame.blocked_frame));
282 break;
283 case PING_FRAME:
284 copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id));
285 break;
286 case STOP_SENDING_FRAME:
287 copy = QuicFrame(QuicStopSendingFrame(frame.stop_sending_frame));
288 break;
289 case NEW_CONNECTION_ID_FRAME:
290 copy = QuicFrame(
291 new QuicNewConnectionIdFrame(*frame.new_connection_id_frame));
292 break;
293 case RETIRE_CONNECTION_ID_FRAME:
294 copy = QuicFrame(
295 new QuicRetireConnectionIdFrame(*frame.retire_connection_id_frame));
296 break;
297 case STREAMS_BLOCKED_FRAME:
298 copy = QuicFrame(QuicStreamsBlockedFrame(frame.streams_blocked_frame));
299 break;
300 case MAX_STREAMS_FRAME:
301 copy = QuicFrame(QuicMaxStreamsFrame(frame.max_streams_frame));
302 break;
303 case HANDSHAKE_DONE_FRAME:
304 copy = QuicFrame(
305 QuicHandshakeDoneFrame(frame.handshake_done_frame.control_frame_id));
306 break;
307 case ACK_FREQUENCY_FRAME:
308 copy = QuicFrame(new QuicAckFrequencyFrame(*frame.ack_frequency_frame));
309 break;
310 case NEW_TOKEN_FRAME:
311 copy = QuicFrame(new QuicNewTokenFrame(*frame.new_token_frame));
312 break;
313 default:
314 QUIC_BUG(quic_bug_10533_1)
315 << "Try to copy a non-retransmittable control frame: " << frame;
316 copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId));
317 break;
318 }
319 return copy;
320 }
321
CopyQuicFrame(quiche::QuicheBufferAllocator * allocator,const QuicFrame & frame)322 QuicFrame CopyQuicFrame(quiche::QuicheBufferAllocator* allocator,
323 const QuicFrame& frame) {
324 QuicFrame copy;
325 switch (frame.type) {
326 case PADDING_FRAME:
327 copy = QuicFrame(QuicPaddingFrame(frame.padding_frame));
328 break;
329 case RST_STREAM_FRAME:
330 copy = QuicFrame(new QuicRstStreamFrame(*frame.rst_stream_frame));
331 break;
332 case CONNECTION_CLOSE_FRAME:
333 copy = QuicFrame(
334 new QuicConnectionCloseFrame(*frame.connection_close_frame));
335 break;
336 case GOAWAY_FRAME:
337 copy = QuicFrame(new QuicGoAwayFrame(*frame.goaway_frame));
338 break;
339 case WINDOW_UPDATE_FRAME:
340 copy = QuicFrame(QuicWindowUpdateFrame(frame.window_update_frame));
341 break;
342 case BLOCKED_FRAME:
343 copy = QuicFrame(QuicBlockedFrame(frame.blocked_frame));
344 break;
345 case STOP_WAITING_FRAME:
346 copy = QuicFrame(QuicStopWaitingFrame(frame.stop_waiting_frame));
347 break;
348 case PING_FRAME:
349 copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id));
350 break;
351 case CRYPTO_FRAME:
352 copy = QuicFrame(new QuicCryptoFrame(*frame.crypto_frame));
353 break;
354 case STREAM_FRAME:
355 copy = QuicFrame(QuicStreamFrame(frame.stream_frame));
356 break;
357 case ACK_FRAME:
358 copy = QuicFrame(new QuicAckFrame(*frame.ack_frame));
359 break;
360 case MTU_DISCOVERY_FRAME:
361 copy = QuicFrame(QuicMtuDiscoveryFrame(frame.mtu_discovery_frame));
362 break;
363 case NEW_CONNECTION_ID_FRAME:
364 copy = QuicFrame(
365 new QuicNewConnectionIdFrame(*frame.new_connection_id_frame));
366 break;
367 case MAX_STREAMS_FRAME:
368 copy = QuicFrame(QuicMaxStreamsFrame(frame.max_streams_frame));
369 break;
370 case STREAMS_BLOCKED_FRAME:
371 copy = QuicFrame(QuicStreamsBlockedFrame(frame.streams_blocked_frame));
372 break;
373 case PATH_RESPONSE_FRAME:
374 copy = QuicFrame(QuicPathResponseFrame(frame.path_response_frame));
375 break;
376 case PATH_CHALLENGE_FRAME:
377 copy = QuicFrame(QuicPathChallengeFrame(frame.path_challenge_frame));
378 break;
379 case STOP_SENDING_FRAME:
380 copy = QuicFrame(QuicStopSendingFrame(frame.stop_sending_frame));
381 break;
382 case MESSAGE_FRAME:
383 copy = QuicFrame(new QuicMessageFrame(frame.message_frame->message_id));
384 copy.message_frame->data = frame.message_frame->data;
385 copy.message_frame->message_length = frame.message_frame->message_length;
386 for (const auto& slice : frame.message_frame->message_data) {
387 quiche::QuicheBuffer buffer =
388 quiche::QuicheBuffer::Copy(allocator, slice.AsStringView());
389 copy.message_frame->message_data.push_back(
390 quiche::QuicheMemSlice(std::move(buffer)));
391 }
392 break;
393 case NEW_TOKEN_FRAME:
394 copy = QuicFrame(new QuicNewTokenFrame(*frame.new_token_frame));
395 break;
396 case RETIRE_CONNECTION_ID_FRAME:
397 copy = QuicFrame(
398 new QuicRetireConnectionIdFrame(*frame.retire_connection_id_frame));
399 break;
400 case HANDSHAKE_DONE_FRAME:
401 copy = QuicFrame(
402 QuicHandshakeDoneFrame(frame.handshake_done_frame.control_frame_id));
403 break;
404 case ACK_FREQUENCY_FRAME:
405 copy = QuicFrame(new QuicAckFrequencyFrame(*frame.ack_frequency_frame));
406 break;
407 default:
408 QUIC_BUG(quic_bug_10533_2) << "Cannot copy frame: " << frame;
409 copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId));
410 break;
411 }
412 return copy;
413 }
414
CopyQuicFrames(quiche::QuicheBufferAllocator * allocator,const QuicFrames & frames)415 QuicFrames CopyQuicFrames(quiche::QuicheBufferAllocator* allocator,
416 const QuicFrames& frames) {
417 QuicFrames copy;
418 for (const auto& frame : frames) {
419 copy.push_back(CopyQuicFrame(allocator, frame));
420 }
421 return copy;
422 }
423
operator <<(std::ostream & os,const QuicFrame & frame)424 std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) {
425 switch (frame.type) {
426 case PADDING_FRAME: {
427 os << "type { PADDING_FRAME } " << frame.padding_frame;
428 break;
429 }
430 case RST_STREAM_FRAME: {
431 os << "type { RST_STREAM_FRAME } " << *(frame.rst_stream_frame);
432 break;
433 }
434 case CONNECTION_CLOSE_FRAME: {
435 os << "type { CONNECTION_CLOSE_FRAME } "
436 << *(frame.connection_close_frame);
437 break;
438 }
439 case GOAWAY_FRAME: {
440 os << "type { GOAWAY_FRAME } " << *(frame.goaway_frame);
441 break;
442 }
443 case WINDOW_UPDATE_FRAME: {
444 os << "type { WINDOW_UPDATE_FRAME } " << frame.window_update_frame;
445 break;
446 }
447 case BLOCKED_FRAME: {
448 os << "type { BLOCKED_FRAME } " << frame.blocked_frame;
449 break;
450 }
451 case STREAM_FRAME: {
452 os << "type { STREAM_FRAME } " << frame.stream_frame;
453 break;
454 }
455 case ACK_FRAME: {
456 os << "type { ACK_FRAME } " << *(frame.ack_frame);
457 break;
458 }
459 case STOP_WAITING_FRAME: {
460 os << "type { STOP_WAITING_FRAME } " << frame.stop_waiting_frame;
461 break;
462 }
463 case PING_FRAME: {
464 os << "type { PING_FRAME } " << frame.ping_frame;
465 break;
466 }
467 case CRYPTO_FRAME: {
468 os << "type { CRYPTO_FRAME } " << *(frame.crypto_frame);
469 break;
470 }
471 case MTU_DISCOVERY_FRAME: {
472 os << "type { MTU_DISCOVERY_FRAME } ";
473 break;
474 }
475 case NEW_CONNECTION_ID_FRAME:
476 os << "type { NEW_CONNECTION_ID } " << *(frame.new_connection_id_frame);
477 break;
478 case RETIRE_CONNECTION_ID_FRAME:
479 os << "type { RETIRE_CONNECTION_ID } "
480 << *(frame.retire_connection_id_frame);
481 break;
482 case MAX_STREAMS_FRAME:
483 os << "type { MAX_STREAMS } " << frame.max_streams_frame;
484 break;
485 case STREAMS_BLOCKED_FRAME:
486 os << "type { STREAMS_BLOCKED } " << frame.streams_blocked_frame;
487 break;
488 case PATH_RESPONSE_FRAME:
489 os << "type { PATH_RESPONSE } " << frame.path_response_frame;
490 break;
491 case PATH_CHALLENGE_FRAME:
492 os << "type { PATH_CHALLENGE } " << frame.path_challenge_frame;
493 break;
494 case STOP_SENDING_FRAME:
495 os << "type { STOP_SENDING } " << frame.stop_sending_frame;
496 break;
497 case MESSAGE_FRAME:
498 os << "type { MESSAGE_FRAME }" << *(frame.message_frame);
499 break;
500 case NEW_TOKEN_FRAME:
501 os << "type { NEW_TOKEN_FRAME }" << *(frame.new_token_frame);
502 break;
503 case HANDSHAKE_DONE_FRAME:
504 os << "type { HANDSHAKE_DONE_FRAME } " << frame.handshake_done_frame;
505 break;
506 case ACK_FREQUENCY_FRAME:
507 os << "type { ACK_FREQUENCY_FRAME } " << *(frame.ack_frequency_frame);
508 break;
509 default: {
510 QUIC_LOG(ERROR) << "Unknown frame type: " << frame.type;
511 break;
512 }
513 }
514 return os;
515 }
516
QuicFrameToString(const QuicFrame & frame)517 QUIC_EXPORT_PRIVATE std::string QuicFrameToString(const QuicFrame& frame) {
518 std::ostringstream os;
519 os << frame;
520 return os.str();
521 }
522
QuicFramesToString(const QuicFrames & frames)523 std::string QuicFramesToString(const QuicFrames& frames) {
524 std::ostringstream os;
525 for (const QuicFrame& frame : frames) {
526 os << frame;
527 }
528 return os.str();
529 }
530
531 } // namespace quic
532