1 // Copyright (C) 2019, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright notice,
9 //       this list of conditions and the following disclaimer.
10 //
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 //! The qlog crate is an implementation of the [qlog main schema] and [qlog QUIC
28 //! and HTTP/3 events] that attempts to closely follow the format of the qlog
29 //! [TypeScript schema]. This is just a data model and no support is provided
30 //! for logging IO, applications can decide themselves the most appropriate
31 //! method.
32 //!
33 //! The crate uses Serde for conversion between Rust and JSON.
34 //!
35 //! [qlog main schema]: https://tools.ietf.org/html/draft-marx-qlog-main-schema
36 //! [qlog QUIC and HTTP/3 events]:
37 //! https://quiclog.github.io/internet-drafts/draft-marx-qlog-event-definitions-quic-h3
38 //! [TypeScript schema]:
39 //! https://github.com/quiclog/qlog/blob/master/TypeScript/draft-01/QLog.ts
40 //!
41 //! Overview
42 //! ---------------
43 //! qlog is a hierarchical logging format, with a rough structure of:
44 //!
45 //! * Log
46 //!   * Trace(s)
47 //!     * Event(s)
48 //!
49 //! In practice, a single QUIC connection maps to a single Trace file with one
50 //! or more Events. Applications can decide whether to combine Traces from
51 //! different connections into the same Log.
52 //!
53 //! ## Traces
54 //!
55 //! A [`Trace`] contains metadata such as the [`VantagePoint`] of capture and
56 //! the [`Configuration`] of the `Trace`.
57 //!
58 //! A very important part of the `Trace` is the definition of `event_fields`. A
59 //! qlog Event is a vector of [`EventField`]; this provides great flexibility to
60 //! log events with any number of `EventFields` in any order. The `event_fields`
61 //! property describes the format of event logging and it is important that
62 //! events comply with that format. Failing to do so it going to cause problems
63 //! for qlog analysis tools. For information is available at
64 //! https://tools.ietf.org/html/draft-marx-qlog-main-schema-01#section-3.3.4
65 //!
66 //! In order to make using qlog a bit easier, this crate expects a qlog Event to
67 //! consist of the following EventFields in the following order:
68 //! [`EventField::RelativeTime`], [`EventField::Category`],
69 //! [`EventField::Event`] and [`EventField::Data`]. A set of methods are
70 //! provided to assist in creating a Trace and appending events to it in this
71 //! format.
72 //!
73 //! ## Writing out logs
74 //! As events occur during the connection, the application appends them to the
75 //! trace. The qlog crate supports two modes of writing logs: the buffered mode
76 //! stores everything in memory and requires the application to serialize and
77 //! write the output, the streaming mode progressively writes serialized JSON
78 //! output to a writer designated by the application.
79 //!
80 //! ### Creating a Trace
81 //!
82 //! A typical application needs a single qlog [`Trace`] that it appends QUIC
83 //! and/or HTTP/3 events to:
84 //!
85 //! ```
86 //! let mut trace = qlog::Trace::new(
87 //!     qlog::VantagePoint {
88 //!         name: Some("Example client".to_string()),
89 //!         ty: qlog::VantagePointType::Client,
90 //!         flow: None,
91 //!     },
92 //!     Some("Example qlog trace".to_string()),
93 //!     Some("Example qlog trace description".to_string()),
94 //!     Some(qlog::Configuration {
95 //!         time_offset: Some("0".to_string()),
96 //!         time_units: Some(qlog::TimeUnits::Ms),
97 //!         original_uris: None,
98 //!     }),
99 //!     None,
100 //! );
101 //! ```
102 //!
103 //! ## Adding events
104 //!
105 //! Qlog Events are added to [`qlog::Trace.events`].
106 //!
107 //! It is recommended to use the provided utility methods to append semantically
108 //! valid events to a trace. However, there is nothing preventing you from
109 //! creating the events manually.
110 //!
111 //! The following example demonstrates how to log a QUIC packet
112 //! containing a single Crypto frame. It uses the [`QuicFrame::crypto()`],
113 //! [`packet_sent_min()`] and [`push_event()`] methods to create and log a
114 //! PacketSent event and its EventData.
115 //!
116 //! ```
117 //! # let mut trace = qlog::Trace::new (
118 //! #     qlog::VantagePoint {
119 //! #         name: Some("Example client".to_string()),
120 //! #         ty: qlog::VantagePointType::Client,
121 //! #         flow: None,
122 //! #     },
123 //! #     Some("Example qlog trace".to_string()),
124 //! #     Some("Example qlog trace description".to_string()),
125 //! #     Some(qlog::Configuration {
126 //! #         time_offset: Some("0".to_string()),
127 //! #         time_units: Some(qlog::TimeUnits::Ms),
128 //! #         original_uris: None,
129 //! #     }),
130 //! #     None
131 //! # );
132 //!
133 //! let scid = [0x7e, 0x37, 0xe4, 0xdc, 0xc6, 0x68, 0x2d, 0xa8];
134 //! let dcid = [0x36, 0xce, 0x10, 0x4e, 0xee, 0x50, 0x10, 0x1c];
135 //!
136 //! let pkt_hdr = qlog::PacketHeader::new(
137 //!     0,
138 //!     Some(1251),
139 //!     Some(1224),
140 //!     Some(0xff00001b),
141 //!     Some(b"7e37e4dcc6682da8"),
142 //!     Some(&dcid),
143 //! );
144 //!
145 //! let frames =
146 //!     vec![qlog::QuicFrame::crypto("0".to_string(), "1000".to_string())];
147 //!
148 //! let event = qlog::event::Event::packet_sent_min(
149 //!     qlog::PacketType::Initial,
150 //!     pkt_hdr,
151 //!     Some(frames),
152 //! );
153 //!
154 //! trace.push_event(std::time::Duration::new(0, 0), event);
155 //! ```
156 //!
157 //! ### Serializing
158 //!
159 //! The qlog crate has only been tested with `serde_json`, however
160 //! other serializer targets might work.
161 //!
162 //! For example, serializing the trace created above:
163 //!
164 //! ```
165 //! # let mut trace = qlog::Trace::new (
166 //! #     qlog::VantagePoint {
167 //! #         name: Some("Example client".to_string()),
168 //! #         ty: qlog::VantagePointType::Client,
169 //! #         flow: None,
170 //! #     },
171 //! #     Some("Example qlog trace".to_string()),
172 //! #     Some("Example qlog trace description".to_string()),
173 //! #     Some(qlog::Configuration {
174 //! #         time_offset: Some("0".to_string()),
175 //! #         time_units: Some(qlog::TimeUnits::Ms),
176 //! #         original_uris: None,
177 //! #     }),
178 //! #     None
179 //! # );
180 //! serde_json::to_string_pretty(&trace).unwrap();
181 //! ```
182 //!
183 //! which would generate the following:
184 //!
185 //! ```ignore
186 //! {
187 //!   "vantage_point": {
188 //!     "name": "Example client",
189 //!     "type": "client"
190 //!   },
191 //!   "title": "Example qlog trace",
192 //!   "description": "Example qlog trace description",
193 //!   "configuration": {
194 //!     "time_units": "ms",
195 //!     "time_offset": "0"
196 //!   },
197 //!   "event_fields": [
198 //!     "relative_time",
199 //!     "category",
200 //!     "event",
201 //!     "data"
202 //!   ],
203 //!   "events": [
204 //!     [
205 //!       "0",
206 //!       "transport",
207 //!       "packet_sent",
208 //!       {
209 //!         "packet_type": "initial",
210 //!         "header": {
211 //!           "packet_number": "0",
212 //!           "packet_size": 1251,
213 //!           "payload_length": 1224,
214 //!           "version": "ff00001b",
215 //!           "scil": "8",
216 //!           "dcil": "8",
217 //!           "scid": "7e37e4dcc6682da8",
218 //!           "dcid": "36ce104eee50101c"
219 //!         },
220 //!         "frames": [
221 //!           {
222 //!             "frame_type": "crypto",
223 //!             "offset": "0",
224 //!             "length": "100",
225 //!           }
226 //!         ]
227 //!       }
228 //!     ]
229 //!   ]
230 //! }
231 //! ```
232 //!
233 //! Streaming Mode
234 //! --------------
235 //!
236 //! Create the trace:
237 //!
238 //! ```
239 //! let mut trace = qlog::Trace::new(
240 //!     qlog::VantagePoint {
241 //!         name: Some("Example client".to_string()),
242 //!         ty: qlog::VantagePointType::Client,
243 //!         flow: None,
244 //!     },
245 //!     Some("Example qlog trace".to_string()),
246 //!     Some("Example qlog trace description".to_string()),
247 //!     Some(qlog::Configuration {
248 //!         time_offset: Some("0".to_string()),
249 //!         time_units: Some(qlog::TimeUnits::Ms),
250 //!         original_uris: None,
251 //!     }),
252 //!     None,
253 //! );
254 //! ```
255 //! Create an object with the [`Write`] trait:
256 //!
257 //! ```
258 //! let mut file = std::fs::File::create("foo.qlog").unwrap();
259 //! ```
260 //!
261 //! Create a [`QlogStreamer`] and start serialization to foo.qlog
262 //! using [`start_log()`]:
263 //!
264 //! ```
265 //! # let mut trace = qlog::Trace::new(
266 //! #    qlog::VantagePoint {
267 //! #        name: Some("Example client".to_string()),
268 //! #        ty: qlog::VantagePointType::Client,
269 //! #        flow: None,
270 //! #    },
271 //! #    Some("Example qlog trace".to_string()),
272 //! #    Some("Example qlog trace description".to_string()),
273 //! #    Some(qlog::Configuration {
274 //! #        time_offset: Some("0".to_string()),
275 //! #        time_units: Some(qlog::TimeUnits::Ms),
276 //! #        original_uris: None,
277 //! #    }),
278 //! #    None,
279 //! # );
280 //! # let mut file = std::fs::File::create("foo.qlog").unwrap();
281 //! let mut streamer = qlog::QlogStreamer::new(
282 //!     qlog::QLOG_VERSION.to_string(),
283 //!     Some("Example qlog".to_string()),
284 //!     Some("Example qlog description".to_string()),
285 //!     None,
286 //!     std::time::Instant::now(),
287 //!     trace,
288 //!     Box::new(file),
289 //! );
290 //!
291 //! streamer.start_log().ok();
292 //! ```
293 //!
294 //! ### Adding simple events
295 //!
296 //! Once logging has started you can stream events. Simple events
297 //! can be written in one step using [`add_event()`]:
298 //!
299 //! ```
300 //! # let mut trace = qlog::Trace::new(
301 //! #    qlog::VantagePoint {
302 //! #        name: Some("Example client".to_string()),
303 //! #        ty: qlog::VantagePointType::Client,
304 //! #        flow: None,
305 //! #    },
306 //! #    Some("Example qlog trace".to_string()),
307 //! #    Some("Example qlog trace description".to_string()),
308 //! #    Some(qlog::Configuration {
309 //! #        time_offset: Some("0".to_string()),
310 //! #        time_units: Some(qlog::TimeUnits::Ms),
311 //! #        original_uris: None,
312 //! #    }),
313 //! #    None,
314 //! # );
315 //! # let mut file = std::fs::File::create("foo.qlog").unwrap();
316 //! # let mut streamer = qlog::QlogStreamer::new(
317 //! #     qlog::QLOG_VERSION.to_string(),
318 //! #     Some("Example qlog".to_string()),
319 //! #     Some("Example qlog description".to_string()),
320 //! #     None,
321 //! #     std::time::Instant::now(),
322 //! #     trace,
323 //! #     Box::new(file),
324 //! # );
325 //! let event = qlog::event::Event::metrics_updated_min();
326 //! streamer.add_event(event).ok();
327 //! ```
328 //!
329 //! ### Adding events with frames
330 //! Some events contain optional arrays of QUIC frames. If the
331 //! event has `Some(Vec<QuicFrame>)`, even if it is empty, the
332 //! streamer enters a frame serializing mode that must be
333 //! finalized before other events can be logged.
334 //!
335 //! In this example, a `PacketSent` event is created with an
336 //! empty frame array and frames are written out later:
337 //!
338 //! ```
339 //! # let mut trace = qlog::Trace::new(
340 //! #    qlog::VantagePoint {
341 //! #        name: Some("Example client".to_string()),
342 //! #        ty: qlog::VantagePointType::Client,
343 //! #        flow: None,
344 //! #    },
345 //! #    Some("Example qlog trace".to_string()),
346 //! #    Some("Example qlog trace description".to_string()),
347 //! #    Some(qlog::Configuration {
348 //! #        time_offset: Some("0".to_string()),
349 //! #        time_units: Some(qlog::TimeUnits::Ms),
350 //! #        original_uris: None,
351 //! #    }),
352 //! #    None,
353 //! # );
354 //! # let mut file = std::fs::File::create("foo.qlog").unwrap();
355 //! # let mut streamer = qlog::QlogStreamer::new(
356 //! #     qlog::QLOG_VERSION.to_string(),
357 //! #     Some("Example qlog".to_string()),
358 //! #     Some("Example qlog description".to_string()),
359 //! #     None,
360 //! #     std::time::Instant::now(),
361 //! #     trace,
362 //! #     Box::new(file),
363 //! # );
364 //! let qlog_pkt_hdr = qlog::PacketHeader::with_type(
365 //!     qlog::PacketType::OneRtt,
366 //!     0,
367 //!     Some(1251),
368 //!     Some(1224),
369 //!     Some(0xff00001b),
370 //!     Some(b"7e37e4dcc6682da8"),
371 //!     Some(b"36ce104eee50101c"),
372 //! );
373 //!
374 //! let event = qlog::event::Event::packet_sent_min(
375 //!     qlog::PacketType::OneRtt,
376 //!     qlog_pkt_hdr,
377 //!     Some(Vec::new()),
378 //! );
379 //!
380 //! streamer.add_event(event).ok();
381 //! ```
382 //!
383 //! In this example, the frames contained in the QUIC packet
384 //! are PING and PADDING. Each frame is written using the
385 //! [`add_frame()`] method. Frame writing is concluded with
386 //! [`finish_frames()`].
387 //!
388 //! ```
389 //! # let mut trace = qlog::Trace::new(
390 //! #    qlog::VantagePoint {
391 //! #        name: Some("Example client".to_string()),
392 //! #        ty: qlog::VantagePointType::Client,
393 //! #        flow: None,
394 //! #    },
395 //! #    Some("Example qlog trace".to_string()),
396 //! #    Some("Example qlog trace description".to_string()),
397 //! #    Some(qlog::Configuration {
398 //! #        time_offset: Some("0".to_string()),
399 //! #        time_units: Some(qlog::TimeUnits::Ms),
400 //! #        original_uris: None,
401 //! #    }),
402 //! #    None,
403 //! # );
404 //! # let mut file = std::fs::File::create("foo.qlog").unwrap();
405 //! # let mut streamer = qlog::QlogStreamer::new(
406 //! #     qlog::QLOG_VERSION.to_string(),
407 //! #     Some("Example qlog".to_string()),
408 //! #     Some("Example qlog description".to_string()),
409 //! #     None,
410 //! #     std::time::Instant::now(),
411 //! #     trace,
412 //! #     Box::new(file),
413 //! # );
414 //!
415 //! let ping = qlog::QuicFrame::ping();
416 //! let padding = qlog::QuicFrame::padding();
417 //!
418 //! streamer.add_frame(ping, false).ok();
419 //! streamer.add_frame(padding, false).ok();
420 //!
421 //! streamer.finish_frames().ok();
422 //! ```
423 //!
424 //! Once all events have have been written, the log
425 //! can be finalized with [`finish_log()`]:
426 //!
427 //! ```
428 //! # let mut trace = qlog::Trace::new(
429 //! #    qlog::VantagePoint {
430 //! #        name: Some("Example client".to_string()),
431 //! #        ty: qlog::VantagePointType::Client,
432 //! #        flow: None,
433 //! #    },
434 //! #    Some("Example qlog trace".to_string()),
435 //! #    Some("Example qlog trace description".to_string()),
436 //! #    Some(qlog::Configuration {
437 //! #        time_offset: Some("0".to_string()),
438 //! #        time_units: Some(qlog::TimeUnits::Ms),
439 //! #        original_uris: None,
440 //! #    }),
441 //! #    None,
442 //! # );
443 //! # let mut file = std::fs::File::create("foo.qlog").unwrap();
444 //! # let mut streamer = qlog::QlogStreamer::new(
445 //! #     qlog::QLOG_VERSION.to_string(),
446 //! #     Some("Example qlog".to_string()),
447 //! #     Some("Example qlog description".to_string()),
448 //! #     None,
449 //! #     std::time::Instant::now(),
450 //! #     trace,
451 //! #     Box::new(file),
452 //! # );
453 //! streamer.finish_log().ok();
454 //! ```
455 //!
456 //! ### Serializing
457 //!
458 //! Serialization to JSON occurs as methods on the [`QlogStreamer`]
459 //! are called. No additional steps are required.
460 //!
461 //! [`Trace`]: struct.Trace.html
462 //! [`VantagePoint`]: struct.VantagePoint.html
463 //! [`Configuration`]: struct.Configuration.html
464 //! [`EventField`]: enum.EventField.html
465 //! [`EventField::RelativeTime`]: enum.EventField.html#variant.RelativeTime
466 //! [`EventField::Category`]: enum.EventField.html#variant.Category
467 //! [`EventField::Type`]: enum.EventField.html#variant.Type
468 //! [`EventField::Data`]: enum.EventField.html#variant.Data
469 //! [`qlog::Trace.events`]: struct.Trace.html#structfield.events
470 //! [`push_event()`]: struct.Trace.html#method.push_event
471 //! [`packet_sent_min()`]: event/struct.Event.html#method.packet_sent_min
472 //! [`QuicFrame::crypto()`]: enum.QuicFrame.html#variant.Crypto
473 //! [`QlogStreamer`]: struct.QlogStreamer.html
474 //! [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
475 //! [`start_log()`]: struct.QlogStreamer.html#method.start_log
476 //! [`add_event()`]: struct.QlogStreamer.html#method.add_event
477 //! [`add_frame()`]: struct.QlogStreamer.html#method.add_frame
478 //! [`finish_frames()`]: struct.QlogStreamer.html#method.finish_frames
479 //! [`finish_log()`]: struct.QlogStreamer.html#method.finish_log
480 
481 use serde::Serialize;
482 
483 /// A quiche qlog error.
484 #[derive(Debug)]
485 pub enum Error {
486     /// There is no more work to do.
487     Done,
488 
489     /// The operation cannot be completed because it was attempted
490     /// in an invalid state.
491     InvalidState,
492 
493     /// I/O error.
494     IoError(std::io::Error),
495 }
496 
497 impl std::fmt::Display for Error {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result498     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
499         write!(f, "{:?}", self)
500     }
501 }
502 
503 impl std::error::Error for Error {
source(&self) -> Option<&(dyn std::error::Error + 'static)>504     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
505         None
506     }
507 }
508 
509 impl std::convert::From<std::io::Error> for Error {
from(err: std::io::Error) -> Self510     fn from(err: std::io::Error) -> Self {
511         Error::IoError(err)
512     }
513 }
514 
515 pub const QLOG_VERSION: &str = "draft-02-wip";
516 
517 /// A specialized [`Result`] type for quiche qlog operations.
518 ///
519 /// This type is used throughout the public API for any operation that
520 /// can produce an error.
521 ///
522 /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
523 pub type Result<T> = std::result::Result<T, Error>;
524 
525 #[serde_with::skip_serializing_none]
526 #[derive(Serialize, Clone)]
527 pub struct Qlog {
528     pub qlog_version: String,
529     pub title: Option<String>,
530     pub description: Option<String>,
531     pub summary: Option<String>,
532 
533     pub traces: Vec<Trace>,
534 }
535 
536 impl Default for Qlog {
default() -> Self537     fn default() -> Self {
538         Qlog {
539             qlog_version: QLOG_VERSION.to_string(),
540             title: Some("Default qlog title".to_string()),
541             description: Some("Default qlog description".to_string()),
542             summary: Some("Default qlog title".to_string()),
543             traces: Vec::new(),
544         }
545     }
546 }
547 
548 #[derive(PartialEq)]
549 pub enum StreamerState {
550     Initial,
551     Ready,
552     WritingFrames,
553     Finished,
554 }
555 
556 /// A helper object specialized for streaming JSON-serialized qlog to a
557 /// [`Write`] trait.
558 ///
559 /// The object is responsible for the `Qlog` object that contains the provided
560 /// `Trace`.
561 ///
562 /// Serialization is progressively driven by method calls; once log streaming is
563 /// started, `event::Events` can be written using `add_event()`. Some events
564 /// can contain an array of `QuicFrame`s, when writing such an event, the
565 /// streamer enters a frame-serialization mode where frames are be progressively
566 /// written using `add_frame()`. This mode is concluded using
567 /// `finished_frames()`. While serializing frames, any attempts to log
568 /// additional events are ignored.
569 ///
570 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
571 pub struct QlogStreamer {
572     start_time: std::time::Instant,
573     writer: Box<dyn std::io::Write + Send + Sync>,
574     qlog: Qlog,
575     state: StreamerState,
576     first_event: bool,
577     first_frame: bool,
578 }
579 
580 impl QlogStreamer {
581     /// Creates a QlogStreamer object.
582     ///
583     /// It owns a `Qlog` object that contains the provided `Trace`, which must
584     /// have the following ordered-set of names EventFields:
585     ///
586     /// ["relative_time", "category", "event".to_string(), "data"]
587     ///
588     /// All serialization will be written to the provided `Write`.
new( qlog_version: String, title: Option<String>, description: Option<String>, summary: Option<String>, start_time: std::time::Instant, trace: Trace, writer: Box<dyn std::io::Write + Send + Sync>, ) -> Self589     pub fn new(
590         qlog_version: String, title: Option<String>, description: Option<String>,
591         summary: Option<String>, start_time: std::time::Instant, trace: Trace,
592         writer: Box<dyn std::io::Write + Send + Sync>,
593     ) -> Self {
594         let qlog = Qlog {
595             qlog_version,
596             title,
597             description,
598             summary,
599             traces: vec![trace],
600         };
601 
602         QlogStreamer {
603             start_time,
604             writer,
605             qlog,
606             state: StreamerState::Initial,
607             first_event: true,
608             first_frame: false,
609         }
610     }
611 
612     /// Starts qlog streaming serialization.
613     ///
614     /// This writes out the JSON-serialized form of all information up to qlog
615     /// `Trace`'s array of `EventField`s. EventFields are separately appended
616     /// using functions that accept and `event::Event`.
start_log(&mut self) -> Result<()>617     pub fn start_log(&mut self) -> Result<()> {
618         if self.state != StreamerState::Initial {
619             return Err(Error::Done);
620         }
621 
622         // A qlog contains a trace holding a vector of events that we want to
623         // serialize in a streaming manner. So at the start of serialization,
624         // take off all closing delimiters, and leave us in a state to accept
625         // new events.
626         match serde_json::to_string(&self.qlog) {
627             Ok(mut out) => {
628                 out.truncate(out.len() - 4);
629 
630                 self.writer.as_mut().write_all(out.as_bytes())?;
631 
632                 self.state = StreamerState::Ready;
633 
634                 self.first_event = self.qlog.traces[0].events.is_empty();
635             },
636 
637             _ => return Err(Error::Done),
638         }
639 
640         Ok(())
641     }
642 
643     /// Finishes qlog streaming serialization.
644     ///
645     /// The JSON-serialized output has remaining close delimiters added.
646     /// After this is called, no more serialization will occur.
finish_log(&mut self) -> Result<()>647     pub fn finish_log(&mut self) -> Result<()> {
648         if self.state == StreamerState::Initial ||
649             self.state == StreamerState::Finished
650         {
651             return Err(Error::InvalidState);
652         }
653 
654         self.writer.as_mut().write_all(b"]}]}")?;
655 
656         self.state = StreamerState::Finished;
657 
658         self.writer.as_mut().flush()?;
659 
660         Ok(())
661     }
662 
663     /// Writes a JSON-serialized `EventField`s.
664     ///
665     /// Some qlog events can contain `QuicFrames`. If this is detected `true` is
666     /// returned and the streamer enters a frame-serialization mode that is only
667     /// concluded by `finish_frames()`. In this mode, attempts to log additional
668     /// events are ignored.
669     ///
670     /// If the event contains no array of `QuicFrames` return `false`.
add_event(&mut self, event: event::Event) -> Result<bool>671     pub fn add_event(&mut self, event: event::Event) -> Result<bool> {
672         if self.state != StreamerState::Ready {
673             return Err(Error::InvalidState);
674         }
675 
676         let event_time = if cfg!(test) {
677             std::time::Duration::from_secs(0)
678         } else {
679             self.start_time.elapsed()
680         };
681 
682         let rel = match &self.qlog.traces[0].configuration {
683             Some(conf) => match conf.time_units {
684                 Some(TimeUnits::Ms) => event_time.as_millis().to_string(),
685 
686                 Some(TimeUnits::Us) => event_time.as_micros().to_string(),
687 
688                 None => String::from(""),
689             },
690 
691             None => String::from(""),
692         };
693 
694         let (ev_data, contains_frames) = match serde_json::to_string(&event.data)
695         {
696             Ok(mut ev_data_out) =>
697                 if let Some(f) = event.data.contains_quic_frames() {
698                     ev_data_out.truncate(ev_data_out.len() - 2);
699 
700                     if f == 0 {
701                         self.first_frame = true;
702                     }
703 
704                     (ev_data_out, true)
705                 } else {
706                     (ev_data_out, false)
707                 },
708 
709             _ => return Err(Error::Done),
710         };
711 
712         let maybe_comma = if self.first_event {
713             self.first_event = false;
714             ""
715         } else {
716             ","
717         };
718 
719         let maybe_terminate = if contains_frames { "" } else { "]" };
720 
721         let ev_time = serde_json::to_string(&EventField::RelativeTime(rel)).ok();
722         let ev_cat =
723             serde_json::to_string(&EventField::Category(event.category)).ok();
724         let ev_ty = serde_json::to_string(&EventField::Event(event.ty)).ok();
725 
726         if let (Some(ev_time), Some(ev_cat), Some(ev_ty)) =
727             (ev_time, ev_cat, ev_ty)
728         {
729             let out = format!(
730                 "{}[{},{},{},{}{}",
731                 maybe_comma, ev_time, ev_cat, ev_ty, ev_data, maybe_terminate
732             );
733 
734             self.writer.as_mut().write_all(out.as_bytes())?;
735 
736             if contains_frames {
737                 self.state = StreamerState::WritingFrames
738             } else {
739                 self.state = StreamerState::Ready
740             };
741 
742             return Ok(contains_frames);
743         }
744 
745         Err(Error::Done)
746     }
747 
748     /// Writes a JSON-serialized `QuicFrame`.
749     ///
750     /// Only valid while in the frame-serialization mode.
add_frame(&mut self, frame: QuicFrame, last: bool) -> Result<()>751     pub fn add_frame(&mut self, frame: QuicFrame, last: bool) -> Result<()> {
752         if self.state != StreamerState::WritingFrames {
753             return Err(Error::InvalidState);
754         }
755 
756         match serde_json::to_string(&frame) {
757             Ok(mut out) => {
758                 if !self.first_frame {
759                     out.insert(0, ',');
760                 } else {
761                     self.first_frame = false;
762                 }
763 
764                 self.writer.as_mut().write_all(out.as_bytes())?;
765 
766                 if last {
767                     self.finish_frames()?;
768                 }
769             },
770 
771             _ => return Err(Error::Done),
772         }
773 
774         Ok(())
775     }
776 
777     /// Concludes `QuicFrame` streaming serialization.
778     ///
779     /// Only valid while in the frame-serialization mode.
finish_frames(&mut self) -> Result<()>780     pub fn finish_frames(&mut self) -> Result<()> {
781         if self.state != StreamerState::WritingFrames {
782             return Err(Error::InvalidState);
783         }
784 
785         self.writer.as_mut().write_all(b"]}]")?;
786         self.state = StreamerState::Ready;
787 
788         Ok(())
789     }
790 
791     /// Returns the writer.
792     #[allow(clippy::borrowed_box)]
writer(&self) -> &Box<dyn std::io::Write + Send + Sync>793     pub fn writer(&self) -> &Box<dyn std::io::Write + Send + Sync> {
794         &self.writer
795     }
796 }
797 
798 #[serde_with::skip_serializing_none]
799 #[derive(Serialize, Clone)]
800 pub struct Trace {
801     pub vantage_point: VantagePoint,
802     pub title: Option<String>,
803     pub description: Option<String>,
804 
805     pub configuration: Option<Configuration>,
806 
807     pub common_fields: Option<CommonFields>,
808     pub event_fields: Vec<String>,
809 
810     pub events: Vec<Vec<EventField>>,
811 }
812 
813 /// Helper functions for using a qlog trace.
814 impl Trace {
815     /// Creates a new qlog trace with the hard-coded event_fields
816     /// ["relative_time", "category", "event", "data"]
new( vantage_point: VantagePoint, title: Option<String>, description: Option<String>, configuration: Option<Configuration>, common_fields: Option<CommonFields>, ) -> Self817     pub fn new(
818         vantage_point: VantagePoint, title: Option<String>,
819         description: Option<String>, configuration: Option<Configuration>,
820         common_fields: Option<CommonFields>,
821     ) -> Self {
822         Trace {
823             vantage_point,
824             title,
825             description,
826             configuration,
827             common_fields,
828             event_fields: vec![
829                 "relative_time".to_string(),
830                 "category".to_string(),
831                 "event".to_string(),
832                 "data".to_string(),
833             ],
834             events: Vec::new(),
835         }
836     }
837 
push_event( &mut self, relative_time: std::time::Duration, event: crate::event::Event, )838     pub fn push_event(
839         &mut self, relative_time: std::time::Duration, event: crate::event::Event,
840     ) {
841         let rel = match &self.configuration {
842             Some(conf) => match conf.time_units {
843                 Some(TimeUnits::Ms) => relative_time.as_millis().to_string(),
844 
845                 Some(TimeUnits::Us) => relative_time.as_micros().to_string(),
846 
847                 None => String::from(""),
848             },
849 
850             None => String::from(""),
851         };
852 
853         self.events.push(vec![
854             EventField::RelativeTime(rel),
855             EventField::Category(event.category),
856             EventField::Event(event.ty),
857             EventField::Data(event.data),
858         ]);
859     }
860 }
861 
862 #[serde_with::skip_serializing_none]
863 #[derive(Serialize, Clone)]
864 pub struct VantagePoint {
865     pub name: Option<String>,
866 
867     #[serde(rename = "type")]
868     pub ty: VantagePointType,
869 
870     pub flow: Option<VantagePointType>,
871 }
872 
873 #[derive(Serialize, Clone)]
874 #[serde(rename_all = "snake_case")]
875 pub enum VantagePointType {
876     Client,
877     Server,
878     Network,
879     Unknown,
880 }
881 
882 #[derive(Serialize, Clone)]
883 #[serde(rename_all = "snake_case")]
884 pub enum TimeUnits {
885     Ms,
886     Us,
887 }
888 
889 #[serde_with::skip_serializing_none]
890 #[derive(Serialize, Clone)]
891 pub struct Configuration {
892     pub time_units: Option<TimeUnits>,
893     pub time_offset: Option<String>,
894 
895     pub original_uris: Option<Vec<String>>,
896     /* TODO
897      * additionalUserSpecifiedProperty */
898 }
899 
900 impl Default for Configuration {
default() -> Self901     fn default() -> Self {
902         Configuration {
903             time_units: Some(TimeUnits::Ms),
904             time_offset: Some("0".to_string()),
905             original_uris: None,
906         }
907     }
908 }
909 
910 #[serde_with::skip_serializing_none]
911 #[derive(Serialize, Clone, Default)]
912 pub struct CommonFields {
913     pub group_id: Option<String>,
914     pub protocol_type: Option<String>,
915 
916     pub reference_time: Option<String>,
917     /* TODO
918      * additionalUserSpecifiedProperty */
919 }
920 
921 #[derive(Serialize, Clone)]
922 #[serde(untagged)]
923 pub enum EventType {
924     ConnectivityEventType(ConnectivityEventType),
925 
926     TransportEventType(TransportEventType),
927 
928     SecurityEventType(SecurityEventType),
929 
930     RecoveryEventType(RecoveryEventType),
931 
932     Http3EventType(Http3EventType),
933 
934     QpackEventType(QpackEventType),
935 
936     GenericEventType(GenericEventType),
937 }
938 
939 #[derive(Serialize, Clone)]
940 #[serde(untagged)]
941 #[allow(clippy::large_enum_variant)]
942 pub enum EventField {
943     RelativeTime(String),
944 
945     Category(EventCategory),
946 
947     Event(EventType),
948 
949     Data(EventData),
950 }
951 
952 #[derive(Serialize, Clone)]
953 #[serde(rename_all = "snake_case")]
954 pub enum EventCategory {
955     Connectivity,
956     Security,
957     Transport,
958     Recovery,
959     Http,
960     Qpack,
961 
962     Error,
963     Warning,
964     Info,
965     Debug,
966     Verbose,
967     Simulation,
968 }
969 
970 #[derive(Serialize, Clone)]
971 #[serde(rename_all = "snake_case")]
972 pub enum ConnectivityEventType {
973     ServerListening,
974     ConnectionStarted,
975     ConnectionIdUpdated,
976     SpinBitUpdated,
977     ConnectionStateUpdated,
978 }
979 
980 #[derive(Serialize, Clone)]
981 #[serde(rename_all = "snake_case")]
982 pub enum TransportEventType {
983     ParametersSet,
984 
985     DatagramsSent,
986     DatagramsReceived,
987     DatagramDropped,
988 
989     PacketSent,
990     PacketReceived,
991     PacketDropped,
992     PacketBuffered,
993 
994     FramesProcessed,
995 
996     StreamStateUpdated,
997 }
998 
999 #[derive(Serialize, Clone)]
1000 #[serde(rename_all = "snake_case")]
1001 pub enum TransportEventTrigger {
1002     Line,
1003     Retransmit,
1004     KeysUnavailable,
1005 }
1006 
1007 #[derive(Serialize, Clone)]
1008 #[serde(rename_all = "snake_case")]
1009 pub enum SecurityEventType {
1010     KeyUpdated,
1011     KeyRetired,
1012 }
1013 
1014 #[derive(Serialize, Clone)]
1015 #[serde(rename_all = "snake_case")]
1016 pub enum SecurityEventTrigger {
1017     Tls,
1018     Implicit,
1019     RemoteUpdate,
1020     LocalUpdate,
1021 }
1022 
1023 #[derive(Serialize, Clone)]
1024 #[serde(rename_all = "snake_case")]
1025 pub enum RecoveryEventType {
1026     ParametersSet,
1027     MetricsUpdated,
1028     CongestionStateUpdated,
1029     LossTimerSet,
1030     LossTimerTriggered,
1031     PacketLost,
1032     MarkedForRetransmit,
1033 }
1034 
1035 #[derive(Serialize, Clone)]
1036 #[serde(rename_all = "snake_case")]
1037 pub enum RecoveryEventTrigger {
1038     AckReceived,
1039     PacketSent,
1040     Alarm,
1041     Unknown,
1042 }
1043 
1044 // ================================================================== //
1045 
1046 #[derive(Serialize, Clone)]
1047 #[serde(rename_all = "snake_case")]
1048 pub enum KeyType {
1049     ServerInitialSecret,
1050     ClientInitialSecret,
1051 
1052     ServerHandshakeSecret,
1053     ClientHandshakeSecret,
1054 
1055     Server0RttSecret,
1056     Client0RttSecret,
1057 
1058     Server1RttSecret,
1059     Client1RttSecret,
1060 }
1061 
1062 #[derive(Serialize, Clone)]
1063 #[serde(rename_all = "snake_case")]
1064 pub enum ConnectionState {
1065     Attempted,
1066     Reset,
1067     Handshake,
1068     Active,
1069     Keepalive,
1070     Draining,
1071     Closed,
1072 }
1073 
1074 #[derive(Serialize, Clone)]
1075 #[serde(rename_all = "snake_case")]
1076 pub enum TransportOwner {
1077     Local,
1078     Remote,
1079 }
1080 
1081 #[derive(Serialize, Clone)]
1082 pub struct PreferredAddress {
1083     pub ip_v4: String,
1084     pub ip_v6: String,
1085 
1086     pub port_v4: u64,
1087     pub port_v6: u64,
1088 
1089     pub connection_id: String,
1090     pub stateless_reset_token: String,
1091 }
1092 
1093 #[derive(Serialize, Clone)]
1094 #[serde(rename_all = "snake_case")]
1095 pub enum StreamSide {
1096     Sending,
1097     Receiving,
1098 }
1099 
1100 #[derive(Serialize, Clone)]
1101 #[serde(rename_all = "snake_case")]
1102 pub enum StreamState {
1103     // bidirectional stream states, draft-23 3.4.
1104     Idle,
1105     Open,
1106     HalfClosedLocal,
1107     HalfClosedRemote,
1108     Closed,
1109 
1110     // sending-side stream states, draft-23 3.1.
1111     Ready,
1112     Send,
1113     DataSent,
1114     ResetSent,
1115     ResetReceived,
1116 
1117     // receive-side stream states, draft-23 3.2.
1118     Receive,
1119     SizeKnown,
1120     DataRead,
1121     ResetRead,
1122 
1123     // both-side states
1124     DataReceived,
1125 
1126     // qlog-defined
1127     Destroyed,
1128 }
1129 
1130 #[derive(Serialize, Clone)]
1131 #[serde(rename_all = "snake_case")]
1132 pub enum TimerType {
1133     Ack,
1134     Pto,
1135 }
1136 
1137 #[derive(Serialize, Clone)]
1138 #[serde(rename_all = "snake_case")]
1139 pub enum H3Owner {
1140     Local,
1141     Remote,
1142 }
1143 
1144 #[derive(Serialize, Clone)]
1145 #[serde(rename_all = "snake_case")]
1146 pub enum H3StreamType {
1147     Data,
1148     Control,
1149     Push,
1150     Reserved,
1151     QpackEncode,
1152     QpackDecode,
1153 }
1154 
1155 #[derive(Serialize, Clone)]
1156 #[serde(rename_all = "snake_case")]
1157 pub enum H3DataRecipient {
1158     Application,
1159     Transport,
1160 }
1161 
1162 #[derive(Serialize, Clone)]
1163 #[serde(rename_all = "snake_case")]
1164 pub enum H3PushDecision {
1165     Claimed,
1166     Abandoned,
1167 }
1168 
1169 #[derive(Serialize, Clone)]
1170 #[serde(rename_all = "snake_case")]
1171 pub enum QpackOwner {
1172     Local,
1173     Remote,
1174 }
1175 
1176 #[derive(Serialize, Clone)]
1177 #[serde(rename_all = "snake_case")]
1178 pub enum QpackStreamState {
1179     Blocked,
1180     Unblocked,
1181 }
1182 
1183 #[derive(Serialize, Clone)]
1184 #[serde(rename_all = "snake_case")]
1185 pub enum QpackUpdateType {
1186     Added,
1187     Evicted,
1188 }
1189 
1190 #[derive(Serialize, Clone)]
1191 pub struct QpackDynamicTableEntry {
1192     pub index: u64,
1193     pub name: Option<String>,
1194     pub value: Option<String>,
1195 }
1196 
1197 #[derive(Serialize, Clone)]
1198 pub struct QpackHeaderBlockPrefix {
1199     pub required_insert_count: u64,
1200     pub sign_bit: bool,
1201     pub delta_base: u64,
1202 }
1203 
1204 #[serde_with::skip_serializing_none]
1205 #[derive(Serialize, Clone)]
1206 #[serde(untagged)]
1207 #[allow(clippy::large_enum_variant)]
1208 pub enum EventData {
1209     // ================================================================== //
1210     // CONNECTIVITY
1211     ServerListening {
1212         ip_v4: Option<String>,
1213         ip_v6: Option<String>,
1214         port_v4: u64,
1215         port_v6: u64,
1216 
1217         quic_versions: Option<Vec<String>>,
1218         alpn_values: Option<Vec<String>>,
1219 
1220         stateless_reset_required: Option<bool>,
1221     },
1222 
1223     ConnectionStarted {
1224         ip_version: String,
1225         src_ip: String,
1226         dst_ip: String,
1227 
1228         protocol: Option<String>,
1229         src_port: u64,
1230         dst_port: u64,
1231 
1232         quic_version: Option<String>,
1233         src_cid: Option<String>,
1234         dst_cid: Option<String>,
1235     },
1236 
1237     ConnectionIdUpdated {
1238         src_old: Option<String>,
1239         src_new: Option<String>,
1240 
1241         dst_old: Option<String>,
1242         dst_new: Option<String>,
1243     },
1244 
1245     SpinBitUpdated {
1246         state: bool,
1247     },
1248 
1249     ConnectionStateUpdated {
1250         old: Option<ConnectionState>,
1251         new: ConnectionState,
1252     },
1253 
1254     // ================================================================== //
1255     // SECURITY
1256     KeyUpdated {
1257         key_type: KeyType,
1258         old: Option<String>,
1259         new: String,
1260         generation: Option<u64>,
1261     },
1262 
1263     KeyRetired {
1264         key_type: KeyType,
1265         key: Option<String>,
1266         generation: Option<u64>,
1267     },
1268 
1269     // ================================================================== //
1270     // TRANSPORT
1271     TransportParametersSet {
1272         owner: Option<TransportOwner>,
1273 
1274         resumption_allowed: Option<bool>,
1275         early_data_enabled: Option<bool>,
1276         alpn: Option<String>,
1277         version: Option<String>,
1278         tls_cipher: Option<String>,
1279 
1280         original_connection_id: Option<String>,
1281         stateless_reset_token: Option<String>,
1282         disable_active_migration: Option<bool>,
1283 
1284         idle_timeout: Option<u64>,
1285         max_packet_size: Option<u64>,
1286         ack_delay_exponent: Option<u64>,
1287         max_ack_delay: Option<u64>,
1288         active_connection_id_limit: Option<u64>,
1289 
1290         initial_max_data: Option<String>,
1291         initial_max_stream_data_bidi_local: Option<String>,
1292         initial_max_stream_data_bidi_remote: Option<String>,
1293         initial_max_stream_data_uni: Option<String>,
1294         initial_max_streams_bidi: Option<String>,
1295         initial_max_streams_uni: Option<String>,
1296 
1297         preferred_address: Option<PreferredAddress>,
1298     },
1299 
1300     DatagramsReceived {
1301         count: Option<u64>,
1302         byte_length: Option<u64>,
1303     },
1304 
1305     DatagramsSent {
1306         count: Option<u64>,
1307         byte_length: Option<u64>,
1308     },
1309 
1310     DatagramDropped {
1311         byte_length: Option<u64>,
1312     },
1313 
1314     PacketReceived {
1315         packet_type: PacketType,
1316         header: PacketHeader,
1317         // `frames` is defined here in the QLog schema specification. However,
1318         // our streaming serializer requires serde to put the object at the end,
1319         // so we define it there and depend on serde's preserve_order feature.
1320         is_coalesced: Option<bool>,
1321 
1322         raw_encrypted: Option<String>,
1323         raw_decrypted: Option<String>,
1324         frames: Option<Vec<QuicFrame>>,
1325     },
1326 
1327     PacketSent {
1328         packet_type: PacketType,
1329         header: PacketHeader,
1330         // `frames` is defined here in the QLog schema specification. However,
1331         // our streaming serializer requires serde to put the object at the end,
1332         // so we define it there and depend on serde's preserve_order feature.
1333         is_coalesced: Option<bool>,
1334 
1335         raw_encrypted: Option<String>,
1336         raw_decrypted: Option<String>,
1337         frames: Option<Vec<QuicFrame>>,
1338     },
1339 
1340     PacketDropped {
1341         packet_type: Option<PacketType>,
1342         packet_size: Option<u64>,
1343 
1344         raw: Option<String>,
1345     },
1346 
1347     PacketBuffered {
1348         packet_type: PacketType,
1349         packet_number: String,
1350     },
1351 
1352     StreamStateUpdated {
1353         stream_id: String,
1354         stream_type: Option<StreamType>,
1355 
1356         old: Option<StreamState>,
1357         new: StreamState,
1358 
1359         stream_side: Option<StreamSide>,
1360     },
1361 
1362     FramesProcessed {
1363         frames: Vec<QuicFrame>,
1364     },
1365 
1366     // ================================================================== //
1367     // RECOVERY
1368     RecoveryParametersSet {
1369         reordering_threshold: Option<u64>,
1370         time_threshold: Option<u64>,
1371         timer_granularity: Option<u64>,
1372         initial_rtt: Option<u64>,
1373 
1374         max_datagram_size: Option<u64>,
1375         initial_congestion_window: Option<u64>,
1376         minimum_congestion_window: Option<u64>,
1377         loss_reduction_factor: Option<u64>,
1378         persistent_congestion_threshold: Option<u64>,
1379     },
1380 
1381     MetricsUpdated {
1382         min_rtt: Option<u64>,
1383         smoothed_rtt: Option<u64>,
1384         latest_rtt: Option<u64>,
1385         rtt_variance: Option<u64>,
1386 
1387         max_ack_delay: Option<u64>,
1388         pto_count: Option<u64>,
1389 
1390         congestion_window: Option<u64>,
1391         bytes_in_flight: Option<u64>,
1392 
1393         ssthresh: Option<u64>,
1394 
1395         // qlog defined
1396         packets_in_flight: Option<u64>,
1397         in_recovery: Option<bool>,
1398 
1399         pacing_rate: Option<u64>,
1400     },
1401 
1402     CongestionStateUpdated {
1403         old: Option<String>,
1404         new: String,
1405     },
1406 
1407     LossTimerSet {
1408         timer_type: Option<TimerType>,
1409         timeout: Option<String>,
1410     },
1411 
1412     PacketLost {
1413         packet_type: PacketType,
1414         packet_number: String,
1415 
1416         header: Option<PacketHeader>,
1417         frames: Vec<QuicFrame>,
1418     },
1419 
1420     MarkedForRetransmit {
1421         frames: Vec<QuicFrame>,
1422     },
1423 
1424     // ================================================================== //
1425     // HTTP/3
1426     H3ParametersSet {
1427         owner: Option<H3Owner>,
1428 
1429         max_header_list_size: Option<u64>,
1430         max_table_capacity: Option<u64>,
1431         blocked_streams_count: Option<u64>,
1432 
1433         push_allowed: Option<bool>,
1434 
1435         waits_for_settings: Option<bool>,
1436     },
1437 
1438     H3StreamTypeSet {
1439         stream_id: String,
1440         owner: Option<H3Owner>,
1441 
1442         old: Option<H3StreamType>,
1443         new: H3StreamType,
1444     },
1445 
1446     H3FrameCreated {
1447         stream_id: String,
1448         frame: Http3Frame,
1449         byte_length: Option<String>,
1450 
1451         raw: Option<String>,
1452     },
1453 
1454     H3FrameParsed {
1455         stream_id: String,
1456         frame: Http3Frame,
1457         byte_length: Option<String>,
1458 
1459         raw: Option<String>,
1460     },
1461 
1462     H3DataMoved {
1463         stream_id: String,
1464         offset: Option<String>,
1465         length: Option<u64>,
1466 
1467         from: Option<H3DataRecipient>,
1468         to: Option<H3DataRecipient>,
1469 
1470         raw: Option<String>,
1471     },
1472 
1473     H3PushResolved {
1474         push_id: Option<String>,
1475         stream_id: Option<String>,
1476 
1477         decision: Option<H3PushDecision>,
1478     },
1479 
1480     // ================================================================== //
1481     // QPACK
1482     QpackStateUpdated {
1483         owner: Option<QpackOwner>,
1484 
1485         dynamic_table_capacity: Option<u64>,
1486         dynamic_table_size: Option<u64>,
1487 
1488         known_received_count: Option<u64>,
1489         current_insert_count: Option<u64>,
1490     },
1491 
1492     QpackStreamStateUpdated {
1493         stream_id: String,
1494 
1495         state: QpackStreamState,
1496     },
1497 
1498     QpackDynamicTableUpdated {
1499         update_type: QpackUpdateType,
1500 
1501         entries: Vec<QpackDynamicTableEntry>,
1502     },
1503 
1504     QpackHeadersEncoded {
1505         stream_id: Option<String>,
1506 
1507         headers: Option<HttpHeader>,
1508 
1509         block_prefix: QpackHeaderBlockPrefix,
1510         header_block: Vec<QpackHeaderBlockRepresentation>,
1511 
1512         raw: Option<String>,
1513     },
1514 
1515     QpackHeadersDecoded {
1516         stream_id: Option<String>,
1517 
1518         headers: Option<HttpHeader>,
1519 
1520         block_prefix: QpackHeaderBlockPrefix,
1521         header_block: Vec<QpackHeaderBlockRepresentation>,
1522 
1523         raw: Option<String>,
1524     },
1525 
1526     QpackInstructionSent {
1527         instruction: QPackInstruction,
1528         byte_length: Option<String>,
1529 
1530         raw: Option<String>,
1531     },
1532 
1533     QpackInstructionReceived {
1534         instruction: QPackInstruction,
1535         byte_length: Option<String>,
1536 
1537         raw: Option<String>,
1538     },
1539 
1540     // ================================================================== //
1541     // Generic
1542     ConnectionError {
1543         code: Option<ConnectionErrorCode>,
1544         description: Option<String>,
1545     },
1546 
1547     ApplicationError {
1548         code: Option<ApplicationErrorCode>,
1549         description: Option<String>,
1550     },
1551 
1552     InternalError {
1553         code: Option<u64>,
1554         description: Option<String>,
1555     },
1556 
1557     InternalWarning {
1558         code: Option<u64>,
1559         description: Option<String>,
1560     },
1561 
1562     Message {
1563         message: String,
1564     },
1565 
1566     Marker {
1567         marker_type: String,
1568         message: Option<String>,
1569     },
1570 }
1571 
1572 impl EventData {
1573     /// Returns size of `EventData` array of `QuicFrame`s if it exists.
contains_quic_frames(&self) -> Option<usize>1574     pub fn contains_quic_frames(&self) -> Option<usize> {
1575         // For some EventData variants, the frame array is optional
1576         // but for others it is mandatory.
1577         match self {
1578             EventData::PacketSent { frames, .. } |
1579             EventData::PacketReceived { frames, .. } =>
1580                 if let Some(f) = frames {
1581                     Some(f.len())
1582                 } else {
1583                     None
1584                 },
1585 
1586             EventData::PacketLost { frames, .. } |
1587             EventData::MarkedForRetransmit { frames } |
1588             EventData::FramesProcessed { frames } => Some(frames.len()),
1589 
1590             _ => None,
1591         }
1592     }
1593 }
1594 
1595 #[derive(Serialize, Clone)]
1596 #[serde(rename_all = "snake_case")]
1597 pub enum PacketType {
1598     Initial,
1599     Handshake,
1600 
1601     #[serde(rename = "0RTT")]
1602     ZeroRtt,
1603 
1604     #[serde(rename = "1RTT")]
1605     OneRtt,
1606 
1607     Retry,
1608     VersionNegotiation,
1609     Unknown,
1610 }
1611 
1612 #[derive(Serialize, Clone)]
1613 #[serde(rename_all = "snake_case")]
1614 pub enum Http3EventType {
1615     ParametersSet,
1616     StreamTypeSet,
1617     FrameCreated,
1618     FrameParsed,
1619     DataMoved,
1620     PushResolved,
1621 }
1622 
1623 #[derive(Serialize, Clone)]
1624 #[serde(rename_all = "snake_case")]
1625 pub enum QpackEventType {
1626     StateUpdated,
1627     StreamStateUpdated,
1628     DynamicTableUpdated,
1629     HeadersEncoded,
1630     HeadersDecoded,
1631     InstructionSent,
1632     InstructionReceived,
1633 }
1634 
1635 #[derive(Serialize, Clone)]
1636 #[serde(rename_all = "snake_case")]
1637 pub enum QuicFrameTypeName {
1638     Padding,
1639     Ping,
1640     Ack,
1641     ResetStream,
1642     StopSending,
1643     Crypto,
1644     NewToken,
1645     Stream,
1646     MaxData,
1647     MaxStreamData,
1648     MaxStreams,
1649     DataBlocked,
1650     StreamDataBlocked,
1651     StreamsBlocked,
1652     NewConnectionId,
1653     RetireConnectionId,
1654     PathChallenge,
1655     PathResponse,
1656     ConnectionClose,
1657     ApplicationClose,
1658     HandshakeDone,
1659     Datagram,
1660     Unknown,
1661 }
1662 
1663 // TODO: search for pub enum Error { to see how best to encode errors in qlog.
1664 #[serde_with::skip_serializing_none]
1665 #[derive(Clone, Serialize)]
1666 pub struct PacketHeader {
1667     pub packet_number: String,
1668     pub packet_size: Option<u64>,
1669     pub payload_length: Option<u64>,
1670     pub version: Option<String>,
1671     pub scil: Option<String>,
1672     pub dcil: Option<String>,
1673     pub scid: Option<String>,
1674     pub dcid: Option<String>,
1675 }
1676 
1677 impl PacketHeader {
1678     /// Creates a new PacketHeader.
new( packet_number: u64, packet_size: Option<u64>, payload_length: Option<u64>, version: Option<u32>, scid: Option<&[u8]>, dcid: Option<&[u8]>, ) -> Self1679     pub fn new(
1680         packet_number: u64, packet_size: Option<u64>,
1681         payload_length: Option<u64>, version: Option<u32>, scid: Option<&[u8]>,
1682         dcid: Option<&[u8]>,
1683     ) -> Self {
1684         let (scil, scid) = match scid {
1685             Some(cid) => (
1686                 Some(cid.len().to_string()),
1687                 Some(format!("{}", HexSlice::new(&cid))),
1688             ),
1689 
1690             None => (None, None),
1691         };
1692 
1693         let (dcil, dcid) = match dcid {
1694             Some(cid) => (
1695                 Some(cid.len().to_string()),
1696                 Some(format!("{}", HexSlice::new(&cid))),
1697             ),
1698 
1699             None => (None, None),
1700         };
1701 
1702         let version = match version {
1703             Some(v) => Some(format!("{:x?}", v)),
1704 
1705             None => None,
1706         };
1707 
1708         PacketHeader {
1709             packet_number: packet_number.to_string(),
1710             packet_size,
1711             payload_length,
1712             version,
1713             scil,
1714             dcil,
1715             scid,
1716             dcid,
1717         }
1718     }
1719 
1720     /// Creates a new PacketHeader.
1721     ///
1722     /// Once a QUIC connection has formed, version, dcid and scid are stable, so
1723     /// there are space benefits to not logging them in every packet, especially
1724     /// PacketType::OneRtt.
with_type( ty: PacketType, packet_number: u64, packet_size: Option<u64>, payload_length: Option<u64>, version: Option<u32>, scid: Option<&[u8]>, dcid: Option<&[u8]>, ) -> Self1725     pub fn with_type(
1726         ty: PacketType, packet_number: u64, packet_size: Option<u64>,
1727         payload_length: Option<u64>, version: Option<u32>, scid: Option<&[u8]>,
1728         dcid: Option<&[u8]>,
1729     ) -> Self {
1730         match ty {
1731             PacketType::OneRtt => PacketHeader::new(
1732                 packet_number,
1733                 packet_size,
1734                 payload_length,
1735                 None,
1736                 None,
1737                 None,
1738             ),
1739 
1740             _ => PacketHeader::new(
1741                 packet_number,
1742                 packet_size,
1743                 payload_length,
1744                 version,
1745                 scid,
1746                 dcid,
1747             ),
1748         }
1749     }
1750 }
1751 
1752 #[derive(Serialize, Clone)]
1753 #[serde(rename_all = "snake_case")]
1754 pub enum StreamType {
1755     Bidirectional,
1756     Unidirectional,
1757 }
1758 
1759 #[derive(Serialize, Clone)]
1760 #[serde(rename_all = "snake_case")]
1761 pub enum ErrorSpace {
1762     TransportError,
1763     ApplicationError,
1764 }
1765 
1766 #[derive(Serialize, Clone)]
1767 #[serde(rename_all = "snake_case")]
1768 pub enum GenericEventType {
1769     ConnectionError,
1770     ApplicationError,
1771     InternalError,
1772     InternalWarning,
1773 
1774     Message,
1775     Marker,
1776 }
1777 
1778 #[derive(Serialize, Clone)]
1779 #[serde(untagged)]
1780 pub enum ConnectionErrorCode {
1781     TransportError(TransportError),
1782     CryptoError(CryptoError),
1783     Value(u64),
1784 }
1785 
1786 #[derive(Serialize, Clone)]
1787 #[serde(untagged)]
1788 pub enum ApplicationErrorCode {
1789     ApplicationError(ApplicationError),
1790     Value(u64),
1791 }
1792 
1793 #[derive(Serialize, Clone)]
1794 #[serde(rename_all = "snake_case")]
1795 pub enum TransportError {
1796     NoError,
1797     InternalError,
1798     ServerBusy,
1799     FlowControlError,
1800     StreamLimitError,
1801     StreamStateError,
1802     FinalSizeError,
1803     FrameEncodingError,
1804     TransportParameterError,
1805     ProtocolViolation,
1806     InvalidMigration,
1807     CryptoBufferExceeded,
1808     Unknown,
1809 }
1810 
1811 // TODO
1812 #[derive(Serialize, Clone)]
1813 #[serde(rename_all = "snake_case")]
1814 pub enum CryptoError {
1815     Prefix,
1816 }
1817 
1818 #[derive(Serialize, Clone)]
1819 #[serde(rename_all = "snake_case")]
1820 pub enum ApplicationError {
1821     HttpNoError,
1822     HttpGeneralProtocolError,
1823     HttpInternalError,
1824     HttpRequestCancelled,
1825     HttpIncompleteRequest,
1826     HttpConnectError,
1827     HttpFrameError,
1828     HttpExcessiveLoad,
1829     HttpVersionFallback,
1830     HttpIdError,
1831     HttpStreamCreationError,
1832     HttpClosedCriticalStream,
1833     HttpEarlyResponse,
1834     HttpMissingSettings,
1835     HttpUnexpectedFrame,
1836     HttpRequestRejection,
1837     HttpSettingsError,
1838     Unknown,
1839 }
1840 
1841 #[serde_with::skip_serializing_none]
1842 #[derive(Serialize, Clone)]
1843 #[serde(untagged)]
1844 pub enum QuicFrame {
1845     Padding {
1846         frame_type: QuicFrameTypeName,
1847     },
1848 
1849     Ping {
1850         frame_type: QuicFrameTypeName,
1851     },
1852 
1853     Ack {
1854         frame_type: QuicFrameTypeName,
1855         ack_delay: Option<String>,
1856         acked_ranges: Option<Vec<(u64, u64)>>,
1857 
1858         ect1: Option<String>,
1859 
1860         ect0: Option<String>,
1861 
1862         ce: Option<String>,
1863     },
1864 
1865     ResetStream {
1866         frame_type: QuicFrameTypeName,
1867         stream_id: String,
1868         error_code: u64,
1869         final_size: String,
1870     },
1871 
1872     StopSending {
1873         frame_type: QuicFrameTypeName,
1874         stream_id: String,
1875         error_code: u64,
1876     },
1877 
1878     Crypto {
1879         frame_type: QuicFrameTypeName,
1880         offset: String,
1881         length: String,
1882     },
1883 
1884     NewToken {
1885         frame_type: QuicFrameTypeName,
1886         length: String,
1887         token: String,
1888     },
1889 
1890     Stream {
1891         frame_type: QuicFrameTypeName,
1892         stream_id: String,
1893         offset: String,
1894         length: String,
1895         fin: bool,
1896 
1897         raw: Option<String>,
1898     },
1899 
1900     MaxData {
1901         frame_type: QuicFrameTypeName,
1902         maximum: String,
1903     },
1904 
1905     MaxStreamData {
1906         frame_type: QuicFrameTypeName,
1907         stream_id: String,
1908         maximum: String,
1909     },
1910 
1911     MaxStreams {
1912         frame_type: QuicFrameTypeName,
1913         stream_type: StreamType,
1914         maximum: String,
1915     },
1916 
1917     DataBlocked {
1918         frame_type: QuicFrameTypeName,
1919         limit: String,
1920     },
1921 
1922     StreamDataBlocked {
1923         frame_type: QuicFrameTypeName,
1924         stream_id: String,
1925         limit: String,
1926     },
1927 
1928     StreamsBlocked {
1929         frame_type: QuicFrameTypeName,
1930         stream_type: StreamType,
1931         limit: String,
1932     },
1933 
1934     NewConnectionId {
1935         frame_type: QuicFrameTypeName,
1936         sequence_number: String,
1937         retire_prior_to: String,
1938         length: u64,
1939         connection_id: String,
1940         reset_token: String,
1941     },
1942 
1943     RetireConnectionId {
1944         frame_type: QuicFrameTypeName,
1945         sequence_number: String,
1946     },
1947 
1948     PathChallenge {
1949         frame_type: QuicFrameTypeName,
1950 
1951         data: Option<String>,
1952     },
1953 
1954     PathResponse {
1955         frame_type: QuicFrameTypeName,
1956 
1957         data: Option<String>,
1958     },
1959 
1960     ConnectionClose {
1961         frame_type: QuicFrameTypeName,
1962         error_space: ErrorSpace,
1963         error_code: u64,
1964         raw_error_code: u64,
1965         reason: String,
1966 
1967         trigger_frame_type: Option<String>,
1968     },
1969 
1970     HandshakeDone {
1971         frame_type: QuicFrameTypeName,
1972     },
1973 
1974     Datagram {
1975         frame_type: QuicFrameTypeName,
1976         length: String,
1977 
1978         raw: Option<String>,
1979     },
1980 
1981     Unknown {
1982         frame_type: QuicFrameTypeName,
1983         raw_frame_type: u64,
1984     },
1985 }
1986 
1987 impl QuicFrame {
padding() -> Self1988     pub fn padding() -> Self {
1989         QuicFrame::Padding {
1990             frame_type: QuicFrameTypeName::Padding,
1991         }
1992     }
1993 
ping() -> Self1994     pub fn ping() -> Self {
1995         QuicFrame::Ping {
1996             frame_type: QuicFrameTypeName::Ping,
1997         }
1998     }
1999 
ack( ack_delay: Option<String>, acked_ranges: Option<Vec<(u64, u64)>>, ect1: Option<String>, ect0: Option<String>, ce: Option<String>, ) -> Self2000     pub fn ack(
2001         ack_delay: Option<String>, acked_ranges: Option<Vec<(u64, u64)>>,
2002         ect1: Option<String>, ect0: Option<String>, ce: Option<String>,
2003     ) -> Self {
2004         QuicFrame::Ack {
2005             frame_type: QuicFrameTypeName::Ack,
2006             ack_delay,
2007             acked_ranges,
2008             ect1,
2009             ect0,
2010             ce,
2011         }
2012     }
2013 
reset_stream( stream_id: String, error_code: u64, final_size: String, ) -> Self2014     pub fn reset_stream(
2015         stream_id: String, error_code: u64, final_size: String,
2016     ) -> Self {
2017         QuicFrame::ResetStream {
2018             frame_type: QuicFrameTypeName::ResetStream,
2019             stream_id,
2020             error_code,
2021             final_size,
2022         }
2023     }
2024 
stop_sending(stream_id: String, error_code: u64) -> Self2025     pub fn stop_sending(stream_id: String, error_code: u64) -> Self {
2026         QuicFrame::StopSending {
2027             frame_type: QuicFrameTypeName::StopSending,
2028             stream_id,
2029             error_code,
2030         }
2031     }
2032 
crypto(offset: String, length: String) -> Self2033     pub fn crypto(offset: String, length: String) -> Self {
2034         QuicFrame::Crypto {
2035             frame_type: QuicFrameTypeName::Crypto,
2036             offset,
2037             length,
2038         }
2039     }
2040 
new_token(length: String, token: String) -> Self2041     pub fn new_token(length: String, token: String) -> Self {
2042         QuicFrame::NewToken {
2043             frame_type: QuicFrameTypeName::NewToken,
2044             length,
2045             token,
2046         }
2047     }
2048 
stream( stream_id: String, offset: String, length: String, fin: bool, raw: Option<String>, ) -> Self2049     pub fn stream(
2050         stream_id: String, offset: String, length: String, fin: bool,
2051         raw: Option<String>,
2052     ) -> Self {
2053         QuicFrame::Stream {
2054             frame_type: QuicFrameTypeName::Stream,
2055             stream_id,
2056             offset,
2057             length,
2058             fin,
2059             raw,
2060         }
2061     }
2062 
max_data(maximum: String) -> Self2063     pub fn max_data(maximum: String) -> Self {
2064         QuicFrame::MaxData {
2065             frame_type: QuicFrameTypeName::MaxData,
2066             maximum,
2067         }
2068     }
2069 
max_stream_data(stream_id: String, maximum: String) -> Self2070     pub fn max_stream_data(stream_id: String, maximum: String) -> Self {
2071         QuicFrame::MaxStreamData {
2072             frame_type: QuicFrameTypeName::MaxStreamData,
2073             stream_id,
2074             maximum,
2075         }
2076     }
2077 
max_streams(stream_type: StreamType, maximum: String) -> Self2078     pub fn max_streams(stream_type: StreamType, maximum: String) -> Self {
2079         QuicFrame::MaxStreams {
2080             frame_type: QuicFrameTypeName::MaxStreams,
2081             stream_type,
2082             maximum,
2083         }
2084     }
2085 
data_blocked(limit: String) -> Self2086     pub fn data_blocked(limit: String) -> Self {
2087         QuicFrame::DataBlocked {
2088             frame_type: QuicFrameTypeName::DataBlocked,
2089             limit,
2090         }
2091     }
2092 
stream_data_blocked(stream_id: String, limit: String) -> Self2093     pub fn stream_data_blocked(stream_id: String, limit: String) -> Self {
2094         QuicFrame::StreamDataBlocked {
2095             frame_type: QuicFrameTypeName::StreamDataBlocked,
2096             stream_id,
2097             limit,
2098         }
2099     }
2100 
streams_blocked(stream_type: StreamType, limit: String) -> Self2101     pub fn streams_blocked(stream_type: StreamType, limit: String) -> Self {
2102         QuicFrame::StreamsBlocked {
2103             frame_type: QuicFrameTypeName::StreamsBlocked,
2104             stream_type,
2105             limit,
2106         }
2107     }
2108 
new_connection_id( sequence_number: String, retire_prior_to: String, length: u64, connection_id: String, reset_token: String, ) -> Self2109     pub fn new_connection_id(
2110         sequence_number: String, retire_prior_to: String, length: u64,
2111         connection_id: String, reset_token: String,
2112     ) -> Self {
2113         QuicFrame::NewConnectionId {
2114             frame_type: QuicFrameTypeName::NewConnectionId,
2115             sequence_number,
2116             retire_prior_to,
2117             length,
2118             connection_id,
2119             reset_token,
2120         }
2121     }
2122 
retire_connection_id(sequence_number: String) -> Self2123     pub fn retire_connection_id(sequence_number: String) -> Self {
2124         QuicFrame::RetireConnectionId {
2125             frame_type: QuicFrameTypeName::RetireConnectionId,
2126             sequence_number,
2127         }
2128     }
2129 
path_challenge(data: Option<String>) -> Self2130     pub fn path_challenge(data: Option<String>) -> Self {
2131         QuicFrame::PathChallenge {
2132             frame_type: QuicFrameTypeName::PathChallenge,
2133             data,
2134         }
2135     }
2136 
path_response(data: Option<String>) -> Self2137     pub fn path_response(data: Option<String>) -> Self {
2138         QuicFrame::PathResponse {
2139             frame_type: QuicFrameTypeName::PathResponse,
2140             data,
2141         }
2142     }
2143 
connection_close( error_space: ErrorSpace, error_code: u64, raw_error_code: u64, reason: String, trigger_frame_type: Option<String>, ) -> Self2144     pub fn connection_close(
2145         error_space: ErrorSpace, error_code: u64, raw_error_code: u64,
2146         reason: String, trigger_frame_type: Option<String>,
2147     ) -> Self {
2148         QuicFrame::ConnectionClose {
2149             frame_type: QuicFrameTypeName::ConnectionClose,
2150             error_space,
2151             error_code,
2152             raw_error_code,
2153             reason,
2154             trigger_frame_type,
2155         }
2156     }
2157 
handshake_done() -> Self2158     pub fn handshake_done() -> Self {
2159         QuicFrame::HandshakeDone {
2160             frame_type: QuicFrameTypeName::HandshakeDone,
2161         }
2162     }
2163 
datagram(length: String, raw: Option<String>) -> Self2164     pub fn datagram(length: String, raw: Option<String>) -> Self {
2165         QuicFrame::Datagram {
2166             frame_type: QuicFrameTypeName::Datagram,
2167             length,
2168             raw,
2169         }
2170     }
2171 
unknown(raw_frame_type: u64) -> Self2172     pub fn unknown(raw_frame_type: u64) -> Self {
2173         QuicFrame::Unknown {
2174             frame_type: QuicFrameTypeName::Unknown,
2175             raw_frame_type,
2176         }
2177     }
2178 }
2179 
2180 // ================================================================== //
2181 #[derive(Serialize, Clone)]
2182 #[serde(rename_all = "snake_case")]
2183 pub enum Http3FrameTypeName {
2184     Data,
2185     Headers,
2186     CancelPush,
2187     Settings,
2188     PushPromise,
2189     Goaway,
2190     MaxPushId,
2191     DuplicatePush,
2192     Reserved,
2193     Unknown,
2194 }
2195 
2196 #[derive(Serialize, Clone)]
2197 pub struct HttpHeader {
2198     pub name: String,
2199     pub value: String,
2200 }
2201 
2202 #[derive(Serialize, Clone)]
2203 pub struct Setting {
2204     pub name: String,
2205     pub value: String,
2206 }
2207 
2208 #[derive(Serialize, Clone)]
2209 pub enum Http3Frame {
2210     Data {
2211         frame_type: Http3FrameTypeName,
2212 
2213         raw: Option<String>,
2214     },
2215 
2216     Headers {
2217         frame_type: Http3FrameTypeName,
2218         headers: Vec<HttpHeader>,
2219     },
2220 
2221     CancelPush {
2222         frame_type: Http3FrameTypeName,
2223         push_id: String,
2224     },
2225 
2226     Settings {
2227         frame_type: Http3FrameTypeName,
2228         settings: Vec<Setting>,
2229     },
2230 
2231     PushPromise {
2232         frame_type: Http3FrameTypeName,
2233         push_id: String,
2234         headers: Vec<HttpHeader>,
2235     },
2236 
2237     Goaway {
2238         frame_type: Http3FrameTypeName,
2239         stream_id: String,
2240     },
2241 
2242     MaxPushId {
2243         frame_type: Http3FrameTypeName,
2244         push_id: String,
2245     },
2246 
2247     DuplicatePush {
2248         frame_type: Http3FrameTypeName,
2249         push_id: String,
2250     },
2251 
2252     Reserved {
2253         frame_type: Http3FrameTypeName,
2254     },
2255 
2256     Unknown {
2257         frame_type: Http3FrameTypeName,
2258     },
2259 }
2260 
2261 impl Http3Frame {
data(raw: Option<String>) -> Self2262     pub fn data(raw: Option<String>) -> Self {
2263         Http3Frame::Data {
2264             frame_type: Http3FrameTypeName::Data,
2265             raw,
2266         }
2267     }
2268 
headers(headers: Vec<HttpHeader>) -> Self2269     pub fn headers(headers: Vec<HttpHeader>) -> Self {
2270         Http3Frame::Headers {
2271             frame_type: Http3FrameTypeName::Headers,
2272             headers,
2273         }
2274     }
2275 
cancel_push(push_id: String) -> Self2276     pub fn cancel_push(push_id: String) -> Self {
2277         Http3Frame::CancelPush {
2278             frame_type: Http3FrameTypeName::CancelPush,
2279             push_id,
2280         }
2281     }
2282 
settings(settings: Vec<Setting>) -> Self2283     pub fn settings(settings: Vec<Setting>) -> Self {
2284         Http3Frame::Settings {
2285             frame_type: Http3FrameTypeName::Settings,
2286             settings,
2287         }
2288     }
2289 
push_promise(push_id: String, headers: Vec<HttpHeader>) -> Self2290     pub fn push_promise(push_id: String, headers: Vec<HttpHeader>) -> Self {
2291         Http3Frame::PushPromise {
2292             frame_type: Http3FrameTypeName::PushPromise,
2293             push_id,
2294             headers,
2295         }
2296     }
2297 
goaway(stream_id: String) -> Self2298     pub fn goaway(stream_id: String) -> Self {
2299         Http3Frame::Goaway {
2300             frame_type: Http3FrameTypeName::Goaway,
2301             stream_id,
2302         }
2303     }
2304 
max_push_id(push_id: String) -> Self2305     pub fn max_push_id(push_id: String) -> Self {
2306         Http3Frame::MaxPushId {
2307             frame_type: Http3FrameTypeName::MaxPushId,
2308             push_id,
2309         }
2310     }
2311 
duplicate_push(push_id: String) -> Self2312     pub fn duplicate_push(push_id: String) -> Self {
2313         Http3Frame::DuplicatePush {
2314             frame_type: Http3FrameTypeName::DuplicatePush,
2315             push_id,
2316         }
2317     }
2318 
reserved() -> Self2319     pub fn reserved() -> Self {
2320         Http3Frame::Reserved {
2321             frame_type: Http3FrameTypeName::Reserved,
2322         }
2323     }
2324 
unknown() -> Self2325     pub fn unknown() -> Self {
2326         Http3Frame::Unknown {
2327             frame_type: Http3FrameTypeName::Unknown,
2328         }
2329     }
2330 }
2331 
2332 #[derive(Serialize, Clone)]
2333 #[serde(rename_all = "snake_case")]
2334 pub enum QpackInstructionTypeName {
2335     SetDynamicTableCapacityInstruction,
2336     InsertWithNameReferenceInstruction,
2337     InsertWithoutNameReferenceInstruction,
2338     DuplicateInstruction,
2339     HeaderAcknowledgementInstruction,
2340     StreamCancellationInstruction,
2341     InsertCountIncrementInstruction,
2342 }
2343 
2344 #[derive(Serialize, Clone)]
2345 #[serde(rename_all = "snake_case")]
2346 pub enum QpackTableType {
2347     Static,
2348     Dynamic,
2349 }
2350 
2351 #[derive(Serialize, Clone)]
2352 pub enum QPackInstruction {
2353     SetDynamicTableCapacityInstruction {
2354         instruction_type: QpackInstructionTypeName,
2355 
2356         capacity: u64,
2357     },
2358 
2359     InsertWithNameReferenceInstruction {
2360         instruction_type: QpackInstructionTypeName,
2361 
2362         table_type: QpackTableType,
2363 
2364         name_index: u64,
2365 
2366         huffman_encoded_value: bool,
2367         value_length: u64,
2368         value: String,
2369     },
2370 
2371     InsertWithoutNameReferenceInstruction {
2372         instruction_type: QpackInstructionTypeName,
2373 
2374         huffman_encoded_name: bool,
2375         name_length: u64,
2376         name: String,
2377 
2378         huffman_encoded_value: bool,
2379         value_length: u64,
2380         value: String,
2381     },
2382 
2383     DuplicateInstruction {
2384         instruction_type: QpackInstructionTypeName,
2385 
2386         index: u64,
2387     },
2388 
2389     HeaderAcknowledgementInstruction {
2390         instruction_type: QpackInstructionTypeName,
2391 
2392         stream_id: String,
2393     },
2394 
2395     StreamCancellationInstruction {
2396         instruction_type: QpackInstructionTypeName,
2397 
2398         stream_id: String,
2399     },
2400 
2401     InsertCountIncrementInstruction {
2402         instruction_type: QpackInstructionTypeName,
2403 
2404         increment: u64,
2405     },
2406 }
2407 
2408 #[derive(Serialize, Clone)]
2409 #[serde(rename_all = "snake_case")]
2410 pub enum QpackHeaderBlockRepresentationTypeName {
2411     IndexedHeaderField,
2412     LiteralHeaderFieldWithName,
2413     LiteralHeaderFieldWithoutName,
2414 }
2415 
2416 #[derive(Serialize, Clone)]
2417 pub enum QpackHeaderBlockRepresentation {
2418     IndexedHeaderField {
2419         header_field_type: QpackHeaderBlockRepresentationTypeName,
2420 
2421         table_type: QpackTableType,
2422         index: u64,
2423 
2424         is_post_base: Option<bool>,
2425     },
2426 
2427     LiteralHeaderFieldWithName {
2428         header_field_type: QpackHeaderBlockRepresentationTypeName,
2429 
2430         preserve_literal: bool,
2431         table_type: QpackTableType,
2432         name_index: u64,
2433 
2434         huffman_encoded_value: bool,
2435         value_length: u64,
2436         value: String,
2437 
2438         is_post_base: Option<bool>,
2439     },
2440 
2441     LiteralHeaderFieldWithoutName {
2442         header_field_type: QpackHeaderBlockRepresentationTypeName,
2443 
2444         preserve_literal: bool,
2445         table_type: QpackTableType,
2446         name_index: u64,
2447 
2448         huffman_encoded_name: bool,
2449         name_length: u64,
2450         name: String,
2451 
2452         huffman_encoded_value: bool,
2453         value_length: u64,
2454         value: String,
2455 
2456         is_post_base: Option<bool>,
2457     },
2458 }
2459 
2460 pub struct HexSlice<'a>(&'a [u8]);
2461 
2462 impl<'a> HexSlice<'a> {
new<T>(data: &'a T) -> HexSlice<'a> where T: ?Sized + AsRef<[u8]> + 'a,2463     pub fn new<T>(data: &'a T) -> HexSlice<'a>
2464     where
2465         T: ?Sized + AsRef<[u8]> + 'a,
2466     {
2467         HexSlice(data.as_ref())
2468     }
2469 
maybe_string<T>(data: Option<&'a T>) -> Option<String> where T: ?Sized + AsRef<[u8]> + 'a,2470     pub fn maybe_string<T>(data: Option<&'a T>) -> Option<String>
2471     where
2472         T: ?Sized + AsRef<[u8]> + 'a,
2473     {
2474         match data {
2475             Some(d) => Some(format!("{}", HexSlice::new(d))),
2476 
2477             None => None,
2478         }
2479     }
2480 }
2481 
2482 impl<'a> std::fmt::Display for HexSlice<'a> {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result2483     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2484         for byte in self.0 {
2485             write!(f, "{:02x}", byte)?;
2486         }
2487         Ok(())
2488     }
2489 }
2490 
2491 #[doc(hidden)]
2492 pub mod testing {
2493     use super::*;
2494 
make_pkt_hdr() -> PacketHeader2495     pub fn make_pkt_hdr() -> PacketHeader {
2496         let scid = [0x7e, 0x37, 0xe4, 0xdc, 0xc6, 0x68, 0x2d, 0xa8];
2497         let dcid = [0x36, 0xce, 0x10, 0x4e, 0xee, 0x50, 0x10, 0x1c];
2498 
2499         PacketHeader::new(
2500             0,
2501             Some(1251),
2502             Some(1224),
2503             Some(0xff00_0018),
2504             Some(&scid),
2505             Some(&dcid),
2506         )
2507     }
2508 
make_trace() -> Trace2509     pub fn make_trace() -> Trace {
2510         Trace::new(
2511             VantagePoint {
2512                 name: None,
2513                 ty: VantagePointType::Server,
2514                 flow: None,
2515             },
2516             Some("Quiche qlog trace".to_string()),
2517             Some("Quiche qlog trace description".to_string()),
2518             Some(Configuration {
2519                 time_offset: Some("0".to_string()),
2520                 time_units: Some(TimeUnits::Ms),
2521                 original_uris: None,
2522             }),
2523             None,
2524         )
2525     }
2526 }
2527 
2528 #[cfg(test)]
2529 mod tests {
2530     use super::*;
2531     use testing::*;
2532 
2533     #[test]
packet_header()2534     fn packet_header() {
2535         let pkt_hdr = make_pkt_hdr();
2536 
2537         let log_string = r#"{
2538   "packet_number": "0",
2539   "packet_size": 1251,
2540   "payload_length": 1224,
2541   "version": "ff000018",
2542   "scil": "8",
2543   "dcil": "8",
2544   "scid": "7e37e4dcc6682da8",
2545   "dcid": "36ce104eee50101c"
2546 }"#;
2547 
2548         assert_eq!(serde_json::to_string_pretty(&pkt_hdr).unwrap(), log_string);
2549     }
2550 
2551     #[test]
packet_sent_event_no_frames()2552     fn packet_sent_event_no_frames() {
2553         let log_string = r#"{
2554   "packet_type": "initial",
2555   "header": {
2556     "packet_number": "0",
2557     "packet_size": 1251,
2558     "payload_length": 1224,
2559     "version": "ff00001b",
2560     "scil": "8",
2561     "dcil": "8",
2562     "scid": "7e37e4dcc6682da8",
2563     "dcid": "36ce104eee50101c"
2564   }
2565 }"#;
2566 
2567         let scid = [0x7e, 0x37, 0xe4, 0xdc, 0xc6, 0x68, 0x2d, 0xa8];
2568         let dcid = [0x36, 0xce, 0x10, 0x4e, 0xee, 0x50, 0x10, 0x1c];
2569         let pkt_hdr = PacketHeader::new(
2570             0,
2571             Some(1251),
2572             Some(1224),
2573             Some(0xff00001b),
2574             Some(&scid),
2575             Some(&dcid),
2576         );
2577 
2578         let pkt_sent_evt = EventData::PacketSent {
2579             raw_encrypted: None,
2580             raw_decrypted: None,
2581             packet_type: PacketType::Initial,
2582             header: pkt_hdr.clone(),
2583             frames: None,
2584             is_coalesced: None,
2585         };
2586 
2587         assert_eq!(
2588             serde_json::to_string_pretty(&pkt_sent_evt).unwrap(),
2589             log_string
2590         );
2591     }
2592 
2593     #[test]
packet_sent_event_some_frames()2594     fn packet_sent_event_some_frames() {
2595         let log_string = r#"{
2596   "packet_type": "initial",
2597   "header": {
2598     "packet_number": "0",
2599     "packet_size": 1251,
2600     "payload_length": 1224,
2601     "version": "ff000018",
2602     "scil": "8",
2603     "dcil": "8",
2604     "scid": "7e37e4dcc6682da8",
2605     "dcid": "36ce104eee50101c"
2606   },
2607   "frames": [
2608     {
2609       "frame_type": "padding"
2610     },
2611     {
2612       "frame_type": "ping"
2613     },
2614     {
2615       "frame_type": "stream",
2616       "stream_id": "0",
2617       "offset": "0",
2618       "length": "100",
2619       "fin": true
2620     }
2621   ]
2622 }"#;
2623 
2624         let pkt_hdr = make_pkt_hdr();
2625 
2626         let mut frames = Vec::new();
2627         frames.push(QuicFrame::padding());
2628 
2629         frames.push(QuicFrame::ping());
2630 
2631         frames.push(QuicFrame::stream(
2632             "0".to_string(),
2633             "0".to_string(),
2634             "100".to_string(),
2635             true,
2636             None,
2637         ));
2638 
2639         let pkt_sent_evt = EventData::PacketSent {
2640             raw_encrypted: None,
2641             raw_decrypted: None,
2642             packet_type: PacketType::Initial,
2643             header: pkt_hdr.clone(),
2644             frames: Some(frames),
2645             is_coalesced: None,
2646         };
2647 
2648         assert_eq!(
2649             serde_json::to_string_pretty(&pkt_sent_evt).unwrap(),
2650             log_string
2651         );
2652     }
2653 
2654     #[test]
trace_no_events()2655     fn trace_no_events() {
2656         let log_string = r#"{
2657   "vantage_point": {
2658     "type": "server"
2659   },
2660   "title": "Quiche qlog trace",
2661   "description": "Quiche qlog trace description",
2662   "configuration": {
2663     "time_units": "ms",
2664     "time_offset": "0"
2665   },
2666   "event_fields": [
2667     "relative_time",
2668     "category",
2669     "event",
2670     "data"
2671   ],
2672   "events": []
2673 }"#;
2674 
2675         let trace = make_trace();
2676 
2677         assert_eq!(serde_json::to_string_pretty(&trace).unwrap(), log_string);
2678     }
2679 
2680     #[test]
trace_single_transport_event()2681     fn trace_single_transport_event() {
2682         let log_string = r#"{
2683   "vantage_point": {
2684     "type": "server"
2685   },
2686   "title": "Quiche qlog trace",
2687   "description": "Quiche qlog trace description",
2688   "configuration": {
2689     "time_units": "ms",
2690     "time_offset": "0"
2691   },
2692   "event_fields": [
2693     "relative_time",
2694     "category",
2695     "event",
2696     "data"
2697   ],
2698   "events": [
2699     [
2700       "0",
2701       "transport",
2702       "packet_sent",
2703       {
2704         "packet_type": "initial",
2705         "header": {
2706           "packet_number": "0",
2707           "packet_size": 1251,
2708           "payload_length": 1224,
2709           "version": "ff000018",
2710           "scil": "8",
2711           "dcil": "8",
2712           "scid": "7e37e4dcc6682da8",
2713           "dcid": "36ce104eee50101c"
2714         },
2715         "frames": [
2716           {
2717             "frame_type": "stream",
2718             "stream_id": "0",
2719             "offset": "0",
2720             "length": "100",
2721             "fin": true
2722           }
2723         ]
2724       }
2725     ]
2726   ]
2727 }"#;
2728 
2729         let mut trace = make_trace();
2730 
2731         let pkt_hdr = make_pkt_hdr();
2732 
2733         let frames = vec![QuicFrame::stream(
2734             "0".to_string(),
2735             "0".to_string(),
2736             "100".to_string(),
2737             true,
2738             None,
2739         )];
2740         let event = event::Event::packet_sent_min(
2741             PacketType::Initial,
2742             pkt_hdr,
2743             Some(frames),
2744         );
2745 
2746         trace.push_event(std::time::Duration::new(0, 0), event);
2747 
2748         assert_eq!(serde_json::to_string_pretty(&trace).unwrap(), log_string);
2749     }
2750 
2751     #[test]
test_event_validity()2752     fn test_event_validity() {
2753         // Test a single event in each category
2754 
2755         let ev = event::Event::server_listening_min(443, 443);
2756         assert!(ev.is_valid());
2757 
2758         let ev = event::Event::transport_parameters_set_min();
2759         assert!(ev.is_valid());
2760 
2761         let ev = event::Event::recovery_parameters_set_min();
2762         assert!(ev.is_valid());
2763 
2764         let ev = event::Event::h3_parameters_set_min();
2765         assert!(ev.is_valid());
2766 
2767         let ev = event::Event::qpack_state_updated_min();
2768         assert!(ev.is_valid());
2769 
2770         let ev = event::Event {
2771             category: EventCategory::Error,
2772             ty: EventType::GenericEventType(GenericEventType::ConnectionError),
2773             data: EventData::ConnectionError {
2774                 code: None,
2775                 description: None,
2776             },
2777         };
2778 
2779         assert!(ev.is_valid());
2780     }
2781 
2782     #[test]
bogus_event_validity()2783     fn bogus_event_validity() {
2784         // Test a single event in each category
2785 
2786         let mut ev = event::Event::server_listening_min(443, 443);
2787         ev.category = EventCategory::Simulation;
2788         assert!(!ev.is_valid());
2789 
2790         let mut ev = event::Event::transport_parameters_set_min();
2791         ev.category = EventCategory::Simulation;
2792         assert!(!ev.is_valid());
2793 
2794         let mut ev = event::Event::recovery_parameters_set_min();
2795         ev.category = EventCategory::Simulation;
2796         assert!(!ev.is_valid());
2797 
2798         let mut ev = event::Event::h3_parameters_set_min();
2799         ev.category = EventCategory::Simulation;
2800         assert!(!ev.is_valid());
2801 
2802         let mut ev = event::Event::qpack_state_updated_min();
2803         ev.category = EventCategory::Simulation;
2804         assert!(!ev.is_valid());
2805 
2806         let ev = event::Event {
2807             category: EventCategory::Error,
2808             ty: EventType::GenericEventType(GenericEventType::ConnectionError),
2809             data: EventData::FramesProcessed { frames: Vec::new() },
2810         };
2811 
2812         assert!(!ev.is_valid());
2813     }
2814 
2815     #[test]
serialization_states()2816     fn serialization_states() {
2817         let v: Vec<u8> = Vec::new();
2818         let buff = std::io::Cursor::new(v);
2819         let writer = Box::new(buff);
2820 
2821         let mut trace = make_trace();
2822         let pkt_hdr = make_pkt_hdr();
2823 
2824         let frame1 = QuicFrame::stream(
2825             "40".to_string(),
2826             "40".to_string(),
2827             "400".to_string(),
2828             true,
2829             None,
2830         );
2831 
2832         let event1 = event::Event::packet_sent_min(
2833             PacketType::Handshake,
2834             pkt_hdr.clone(),
2835             Some(vec![frame1]),
2836         );
2837 
2838         trace.push_event(std::time::Duration::new(0, 0), event1);
2839 
2840         let frame2 = QuicFrame::stream(
2841             "0".to_string(),
2842             "0".to_string(),
2843             "100".to_string(),
2844             true,
2845             None,
2846         );
2847 
2848         let frame3 = QuicFrame::stream(
2849             "0".to_string(),
2850             "0".to_string(),
2851             "100".to_string(),
2852             true,
2853             None,
2854         );
2855 
2856         let event2 = event::Event::packet_sent_min(
2857             PacketType::Initial,
2858             pkt_hdr.clone(),
2859             Some(Vec::new()),
2860         );
2861 
2862         let event3 = event::Event::packet_sent(
2863             PacketType::Initial,
2864             pkt_hdr,
2865             Some(Vec::new()),
2866             None,
2867             Some("encrypted_foo".to_string()),
2868             Some("decrypted_foo".to_string()),
2869         );
2870 
2871         let mut s = QlogStreamer::new(
2872             "version".to_string(),
2873             Some("title".to_string()),
2874             Some("description".to_string()),
2875             None,
2876             std::time::Instant::now(),
2877             trace,
2878             writer,
2879         );
2880 
2881         // Before the log is started all other operations should fail.
2882         assert!(match s.add_event(event2.clone()) {
2883             Err(Error::InvalidState) => true,
2884             _ => false,
2885         });
2886         assert!(match s.add_frame(frame2.clone(), false) {
2887             Err(Error::InvalidState) => true,
2888             _ => false,
2889         });
2890         assert!(match s.finish_frames() {
2891             Err(Error::InvalidState) => true,
2892             _ => false,
2893         });
2894         assert!(match s.finish_log() {
2895             Err(Error::InvalidState) => true,
2896             _ => false,
2897         });
2898 
2899         // Once a log is started, can't write frames before an event.
2900         assert!(match s.start_log() {
2901             Ok(()) => true,
2902             _ => false,
2903         });
2904         assert!(match s.add_frame(frame2.clone(), true) {
2905             Err(Error::InvalidState) => true,
2906             _ => false,
2907         });
2908         assert!(match s.finish_frames() {
2909             Err(Error::InvalidState) => true,
2910             _ => false,
2911         });
2912 
2913         // Some events hold frames; can't write any more events until frame
2914         // writing is concluded.
2915         assert!(match s.add_event(event2.clone()) {
2916             Ok(true) => true,
2917             _ => false,
2918         });
2919         assert!(match s.add_event(event2.clone()) {
2920             Err(Error::InvalidState) => true,
2921             _ => false,
2922         });
2923 
2924         // While writing frames, can't write events.
2925         assert!(match s.add_frame(frame2.clone(), false) {
2926             Ok(()) => true,
2927             _ => false,
2928         });
2929 
2930         assert!(match s.add_event(event2.clone()) {
2931             Err(Error::InvalidState) => true,
2932             _ => false,
2933         });
2934         assert!(match s.finish_frames() {
2935             Ok(()) => true,
2936             _ => false,
2937         });
2938 
2939         // Adding an event that includes both frames and raw data should
2940         // be allowed.
2941         assert!(match s.add_event(event3.clone()) {
2942             Ok(true) => true,
2943             _ => false,
2944         });
2945         assert!(match s.add_frame(frame3.clone(), false) {
2946             Ok(()) => true,
2947             _ => false,
2948         });
2949         assert!(match s.finish_frames() {
2950             Ok(()) => true,
2951             _ => false,
2952         });
2953 
2954         assert!(match s.finish_log() {
2955             Ok(()) => true,
2956             _ => false,
2957         });
2958 
2959         let r = s.writer();
2960         let w: &Box<std::io::Cursor<Vec<u8>>> = unsafe { std::mem::transmute(r) };
2961 
2962         let log_string = r#"{"qlog_version":"version","title":"title","description":"description","traces":[{"vantage_point":{"type":"server"},"title":"Quiche qlog trace","description":"Quiche qlog trace description","configuration":{"time_units":"ms","time_offset":"0"},"event_fields":["relative_time","category","event","data"],"events":[["0","transport","packet_sent",{"packet_type":"handshake","header":{"packet_number":"0","packet_size":1251,"payload_length":1224,"version":"ff000018","scil":"8","dcil":"8","scid":"7e37e4dcc6682da8","dcid":"36ce104eee50101c"},"frames":[{"frame_type":"stream","stream_id":"40","offset":"40","length":"400","fin":true}]}],["0","transport","packet_sent",{"packet_type":"initial","header":{"packet_number":"0","packet_size":1251,"payload_length":1224,"version":"ff000018","scil":"8","dcil":"8","scid":"7e37e4dcc6682da8","dcid":"36ce104eee50101c"},"frames":[{"frame_type":"stream","stream_id":"0","offset":"0","length":"100","fin":true}]}],["0","transport","packet_sent",{"packet_type":"initial","header":{"packet_number":"0","packet_size":1251,"payload_length":1224,"version":"ff000018","scil":"8","dcil":"8","scid":"7e37e4dcc6682da8","dcid":"36ce104eee50101c"},"raw_encrypted":"encrypted_foo","raw_decrypted":"decrypted_foo","frames":[{"frame_type":"stream","stream_id":"0","offset":"0","length":"100","fin":true}]}]]}]}"#;
2963 
2964         let written_string = std::str::from_utf8(w.as_ref().get_ref()).unwrap();
2965 
2966         assert_eq!(log_string, written_string);
2967     }
2968 }
2969 
2970 pub mod event;
2971