summaryrefslogtreecommitdiffstats
path: root/doc/http3.md
blob: 9fc10851ee7901b201a2868125bf858acfbe20e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# Supported features
The HTTP3 dissector is a work in progress.

At the moment, the following aspects of HTTP3 are supported:
- Diseciton of different HTTP3 stream types
- Dissection of different HTTP3 frame types
- Dissection of HTTP header fields
- Dissection of QPACK instructions

In addition, the dissector suports decoding of the HTTP3
header fields. This ability requires `nghttp3` third-party library.

## High-level overview
The HTTP3 dissector is invoked by the QUIC dissector.

The essential call tree:
-  `dissect_http3`
   Main entry point. Depending on the stream type, invokes one of the following:
   -  `dissect_http3_uni_stream`
      Processes unidirectional streams, including the control streams,
      the QPACK encoder/decoder streams, and the HTTP3 server push streams.
      NOTE: the HTTP3 server push streams support is rudimental.
      -  `dissect_http3_qpack_enc`
         Dissects the QPACK encoder stream.
         If Wireshark was built with the optional `nghttp3` library,
         this function is also responsible on updating the state
         of the QPACK decoder.
   -  `dissect_http3_frame`
      Processed HTTP3 frames from the client-initiated bidirectional stream.
      Determines the frame type, and dispatches the call to one of the
      sub-dissectors:
      -  `dissect_http3_data`
         Dissects the `HTTP3_DATA` frames.
      -  `dissect_http3_headers`
         Dissects the `HTTP3_HEADER` frames.
         If Wireshark was built with the optional `nghttp3` library,
         this function attempts to decode the header fields, using
         the QPACK decoder.
      -  `dissect_http3_settings`
         Dissects the `HTTP3_SETTINGS` frames.

### Overview of the HTTP3 header dissection
The QPACK implementation from `nghttp3` requires a separate QPACK decoder instance
for every HTTP3 connection. The different HTTP3 streams that constitute a single
HTTP3 conneciton are sharing the same QPACK decoder instance.

The HTTP3 dissector interacts with the QPACK decoder in 2 ways:
-  On the reception of QPACK encoder data (which is delivered on a dedicated unidirectional stream),
   the dissector updates the connection's decoder instance.
-  On the reception of compressed HTTP3 headers, the dissector uses the connection's decoder
   to uncompress the HTTP headers.

If decompression succeeds, the dissector adds tree items to the packet tree. Otherwise,
the dissector adds expert info items.

The decompression can fail due to several reasons:
-  If the instruction count required by the compressed HTTP3 headers
   exceeds the maximal instruction count that the QPACK decoder is aware of,
   the decoding becomes "blocked". This situation can occure when the QUIC packets
   that carry the QPACK encoder instructions are dropped/reordered.
-  If the state of the decoder becomes invalid, which may happen when a "garbage"
   data is received on the QUIC stream.
-  Lastly, the decoding can fail if the underlying QUIC desegmentation is
   not working correctly.

### Overview of HTTP3 data frames dissection
The higher-level dissectors that could use HTTP3 (e.g. WebTransport) need to be able
to access the contents of a single HTTP3 stream as a contiguous span of data.

For that purpose, the HTTP3 dissector is defining a custom conversation finder.
See functions `http3_find_inner_conversation` and `http3_reset_inner_conversation`.

## Essential data structures
### File-level state
#### `HTTP3_CONN_INFO_MAP`
The `HTTP3_CONN_INFO_MAP` contains session-level information for every HTTP3 connection
in a PCAP file. This map is lazily allocated, and is cleared upon exiting the file scope.

### HTTP3 header caches
The dissector attempts to conserve memory, by avoding allocating memory for
duplicate header names/values. Instead, the dissector keeps the decoded names/values
in two caches: `HTTP3_HEADER_CACHE` and `HTTP3_HEADER_DEF_CACHE`. The former stores
the decoded HTTP3 header values, and the latter stores the decoded HTTP3 header names.

### Connection-level state
#### `http3_session_info_t`
The `http3_session_info_t` keeps the state of the QPACK decoder. Every HTTP3 connection
corresponds to a single session. In the future, the session may be shared between multiple
connections, to support connection migration or multipath HTTP3.
At the moment, there are no shared sessions.

### Stream-level state
#### `http3_stream_info_t`
The `http3_stream_info_t` keeps the information about the individual HTTP3 streams,
as well as mapping to the underlying QUIC streams.

### Frame-level state
#### `http3_header_field_t`
The `http3_header_field_t` keeps the information about a single HTTP header.
It contains both the encoded and the decoded representation of the header.
The actual decoded strings are stored in `HTTP3_HEADER_CACHE`/`HTTP3_HEADER_DEF_CACHE`;
the individual `http3_header_field_t` instances contain pointers to the strings.