• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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