soyokaze 0.6.3

HTTP/1/2/3 Library Crate
Documentation
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
//! The types every HTTP version shares.
//!
//! A [`Message`] is a request or a response, whichever version framed it, and
//! carries its [`Headers`] and [`Body`] alongside the connection and transport
//! facts a handler may want to see. What one connection may spend on the
//! peer's behalf is bounded by [`Limits`].

use std::fmt;
use std::str::FromStr;

use bytes::Bytes;

use crate::errors::Error;
use crate::helpers::compression::Compression;
use crate::helpers::fields::HeaderField;
use crate::helpers::scan;
use crate::helpers::text::Text;
use crate::tls::Security;

/// The transport family a version runs over, and a port carries.
///
/// Which HTTP versions a port can negotiate is exactly the question of
/// whether the two agree here: [`Port::carries`] asks it, and nothing keys on
/// a particular version number, so a future version is routed by what it runs
/// over rather than by name.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TransportKind {
    /// An ordered byte stream: TCP, or a Unix domain socket.
    Stream,
    /// QUIC, over UDP.
    QUIC,
}

/// Somewhere a server listens or a client dials.
///
/// The variant picks the transport, which in turn bounds the HTTP versions
/// that can be negotiated: a port carries exactly the versions whose
/// [`Version::transport`] matches its own, which [`Port::carries`] answers.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Port {
    /// A Unix domain socket at the given filesystem path.
    UDS(String),
    /// A TCP port.
    TCP(u16),
    /// A UDP port carrying QUIC.
    QUIC(u16),
}

impl Port {
    /// The transport family this port carries.
    pub fn transport(&self) -> TransportKind {
        match self {
            Self::UDS(_) | Self::TCP(_) => TransportKind::Stream,
            Self::QUIC(_) => TransportKind::QUIC,
        }
    }

    /// Whether this port can carry `version`, by transport family.
    pub fn carries(&self, version: Version) -> bool {
        self.transport() == version.transport()
    }

    /// The versions this port offers, from those it was configured with.
    ///
    /// A port offers what it [`Port::carries`], in the order given. A QUIC
    /// port keeps only the most preferred of them: QUIC settles its ALPN when
    /// the endpoint is stood up, before any connection arrives, so such a port
    /// has to offer the one version it will actually run rather than offer
    /// several and then turn away whichever a peer picks. A stream transport
    /// negotiates per connection, so it offers them all.
    pub fn offers(&self, versions: &[Version]) -> Vec<Version> {
        let mut offered: Vec<Version> = versions.iter().copied().filter(|version| self.carries(*version)).collect();

        if self.transport() == TransportKind::QUIC {
            offered.truncate(1);
        }

        offered
    }
}

/// An absolute URL, split into the parts a request needs.
///
/// `target` is the request target — the path, query and fragment as one string
/// — and is never empty; [`URL::parse`] substitutes `/` when the URL carries
/// no path.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct URL {
    /// The scheme, lowercased (`http`, `https`, `ws`, `wss`, ...).
    pub scheme: String,
    /// The host, without the brackets an IPv6 literal wears in a URL.
    pub host: String,
    /// The port, defaulted from the scheme when the URL omits one.
    pub port: u16,
    /// The request target, beginning with `/`.
    pub target: String,
}

impl URL {
    /// The port a scheme implies: 443 for `https` and `wss`, 80 otherwise.
    pub fn default_port(scheme: &str) -> u16 {
        match scheme {
            "https" | "wss" => 443,
            _ => 80,
        }
    }

    /// Whether a string may be sent as a request target.
    ///
    /// Non-empty, and carrying neither whitespace nor a control octet: an
    /// HTTP/1.x start line delimits the target with spaces and ends with CRLF,
    /// so either would let one request read as two. HTTP/2 and HTTP/3 carry
    /// the same string as `:path` and hold it to the same rule, since a
    /// message framed there may be forwarded over HTTP/1.1 later.
    ///
    /// This is the decoded-text counterpart of [`Octets::is_target_bytes`],
    /// which the HTTP/1 parser applies to the octets of a start line before
    /// they are known to be UTF-8.
    ///
    /// [`Octets::is_target_bytes`]: crate::protocol::h1::Octets::is_target_bytes
    pub fn is_target(target: &str) -> bool {
        !target.is_empty() && scan::all_visible(target.as_bytes())
    }

    /// Whether a string may be sent as an authority.
    ///
    /// The host and, where there is one, the port — what a `Host` field and an
    /// `:authority` pseudo-header carry. Unlike [`URL::is_host`] this admits
    /// the `:` a port hangs off and the brackets an IPv6 literal wears, since
    /// the authority is written with them; what it refuses is whitespace and
    /// control octets, which would break the field it is written into.
    pub fn is_authority(authority: &str) -> bool {
        !authority.is_empty() && scan::all_visible(authority.as_bytes())
    }

    /// Whether a string may be sent as the host of an authority.
    ///
    /// Non-empty, and carrying nothing that would let the authority break out
    /// of the `Host` field or the `:authority` pseudo-header it is written
    /// into: no whitespace, no control octet, and none of the delimiters an
    /// authority is parsed with. A colon is among them: the port hangs off one,
    /// and the only host that carries one of its own is an IPv6 literal, which
    /// wears brackets and is unwrapped before this is asked.
    pub fn is_host(host: &str) -> bool {
        !host.is_empty()
            && host.bytes().all(|byte| byte > 0x20 && byte != 0x7f && !b"/?#@[]:".contains(&byte))
    }

    /// Whether the scheme asks for TLS.
    pub fn secure(&self) -> bool {
        matches!(self.scheme.as_str(), "https" | "wss")
    }

    /// The authority as it belongs in a `Host` field or an `:authority` pseudo-header.
    ///
    /// An IPv6 host is bracketed, and the port is omitted when it is the one
    /// the scheme implies.
    pub fn authority(&self) -> String {
        Self::authority_of(&self.scheme, &self.host, self.port)
    }

    /// [`URL::authority`] for parts that are not held in a [`URL`].
    ///
    /// A caller that dialled a host and a port directly, rather than parsing a
    /// URL, still owes its requests the same authority.
    pub fn authority_of(scheme: &str, host: &str, port: u16) -> String {
        let bracketed = host.contains(':');
        let default = port == Self::default_port(scheme);

        match (bracketed, default) {
            (true, true) => format!("[{host}]"),
            (true, false) => format!("[{host}]:{port}"),
            (false, true) => host.to_owned(),
            (false, false) => format!("{host}:{port}"),
        }
    }

    /// Splits an absolute URL into its parts.
    ///
    /// Userinfo is discarded, an IPv6 literal is unwrapped from its brackets,
    /// and a missing port is filled in from the scheme.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Protocol`] when the URL carries no scheme, when an
    /// IPv6 authority is malformed, when the port is not a number, when the
    /// URL carries no host or one [`URL::is_host`] refuses, or when the
    /// request target is one [`URL::is_target`] refuses — which is what stops
    /// a URL carrying a CRLF from writing a second request line.
    pub fn parse(text: &str) -> Result<Self, Error> {
        let (scheme, rest) = text.split_once("://").ok_or_else(|| Error::Protocol(format!("url {text:?} has no scheme")))?;
        let scheme = scheme.to_ascii_lowercase();

        let end = rest.find(['/', '?', '#']).unwrap_or(rest.len());
        let (authority, tail) = rest.split_at(end);
        let target = if tail.is_empty() { "/".to_owned() } else { tail.to_owned() };

        if !Self::is_target(&target) {
            return Err(Error::Protocol(format!("request target {target:?} is malformed")));
        }

        let authority = authority.rsplit('@').next().unwrap_or(authority);

        let (host, port) = if let Some(rest) = authority.strip_prefix('[') {
            let (host, after) = rest
                .split_once(']')
                .ok_or_else(|| Error::Protocol("IPv6 authority is missing its closing bracket".into()))?;

            let port = match after.strip_prefix(':') {
                Some(digits) => Some(digits.parse().map_err(|_| Error::Protocol(format!("port {digits:?} is not a number")))?),
                None if after.is_empty() => None,
                None => return Err(Error::Protocol("IPv6 authority has trailing characters".into())),
            };

            if host.is_empty() || !host.bytes().all(|byte| byte.is_ascii_hexdigit() || byte == b':' || byte == b'.') {
                return Err(Error::Protocol(format!("IPv6 authority {host:?} is malformed")));
            }

            (host.to_owned(), port)
        } else if let Some((host, digits)) = authority.rsplit_once(':') {
            let port = digits.parse().map_err(|_| Error::Protocol(format!("port {digits:?} is not a number")))?;
            (host.to_owned(), Some(port))
        } else {
            (authority.to_owned(), None)
        };

        if host.is_empty() {
            return Err(Error::Protocol(format!("url {text:?} has no host")));
        }

        // A bracketed literal has already been checked as one; anything else
        // reaching here with a colon was never an authority this could read.
        if !authority.starts_with('[') && !Self::is_host(&host) {
            return Err(Error::Protocol(format!("host {host:?} is malformed")));
        }

        let port = port.unwrap_or(Self::default_port(&scheme));
        Ok(Self { scheme, host, port, target })
    }
}

/// An HTTP version.
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Version {
    /// HTTP/1.0.
    V1_0,
    /// HTTP/1.1.
    V1_1,
    /// HTTP/2.
    V2_0,
    /// HTTP/3.
    V3_0,
}

impl Version {
    /// The ALPN protocol identifier that selects this version.
    pub fn alpn(&self) -> &'static str {
        match self {
            Self::V1_0 => "http/1.0",
            Self::V1_1 => "http/1.1",
            Self::V2_0 => "h2",
            Self::V3_0 => "h3",
        }
    }

    /// The version an ALPN protocol identifier selects, if it names one.
    pub fn from_alpn(alpn: &[u8]) -> Option<Self> {
        match alpn {
            b"http/1.0" => Some(Self::V1_0),
            b"http/1.1" => Some(Self::V1_1),
            b"h2" => Some(Self::V2_0),
            b"h3" => Some(Self::V3_0),
            _ => None,
        }
    }

    /// The major version number, which is what most version tests care about.
    pub fn major(&self) -> u8 {
        match self {
            Self::V1_0 | Self::V1_1 => 1,
            Self::V2_0 => 2,
            Self::V3_0 => 3,
        }
    }

    /// The transport family this version runs over.
    pub fn transport(&self) -> TransportKind {
        match self {
            Self::V1_0 | Self::V1_1 | Self::V2_0 => TransportKind::Stream,
            Self::V3_0 => TransportKind::QUIC,
        }
    }

    /// The version as it is written in an HTTP/1.x start line.
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::V1_0 => "HTTP/1.0",
            Self::V1_1 => "HTTP/1.1",
            Self::V2_0 => "HTTP/2",
            Self::V3_0 => "HTTP/3",
        }
    }
}

impl fmt::Display for Version {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl FromStr for Version {
    type Err = ();

    fn from_str(text: &str) -> Result<Self, Self::Err> {
        match text {
            "HTTP/1.0" => Ok(Self::V1_0),
            "HTTP/1.1" => Ok(Self::V1_1),
            "HTTP/2" => Ok(Self::V2_0),
            "HTTP/3" => Ok(Self::V3_0),
            _ => Err(()),
        }
    }
}

/// ALPN: what versions are offered, and what the handshake settled on.
///
/// The mapping between a [`Version`] and its protocol identifier lives on
/// [`Version::alpn`] and [`Version::from_alpn`]; what is here is the list
/// handling around it — offering several, and reading back the choice.
pub struct ALPN;

impl ALPN {
    /// The ALPN protocol identifiers for a list of versions, one per entry.
    pub fn list(versions: &[Version]) -> Vec<Vec<u8>> {
        versions.iter().map(|version| version.alpn().as_bytes().to_vec()).collect()
    }

    /// [`ALPN::list`] in wire form: each length-prefixed, run together.
    pub fn wire(versions: &[Version]) -> Vec<u8> {
        let mut out = Vec::new();

        for version in versions {
            let protocol = version.alpn().as_bytes();
            out.push(protocol.len() as u8);
            out.extend_from_slice(protocol);
        }

        out
    }

    /// Picks a protocol from what a client offered.
    ///
    /// The server's preference wins: `offered` is walked in order and the first
    /// entry the client also lists is chosen. `None` when nothing overlaps,
    /// which must fail the handshake rather than fall back to something
    /// unnegotiated.
    pub fn select<'a>(offered: &[Vec<u8>], client: &'a [u8]) -> Option<&'a [u8]> {
        for wanted in offered {
            let mut index = 0;

            while index < client.len() {
                let length = client[index] as usize;
                let end = index + 1 + length;

                let Some(protocol) = client.get(index + 1..end) else {
                    break;
                };

                if protocol == wanted.as_slice() {
                    return Some(protocol);
                }

                index = end;
            }
        }

        None
    }

    /// The version a completed handshake settled on.
    ///
    /// A peer that selected nothing falls back to HTTP/1.x, which predates
    /// ALPN, and only when that was on offer.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Version`] when the peer selected nothing and no HTTP/1.x
    /// was offered, or selected something outside `versions`.
    pub fn negotiated(alpn: Option<&[u8]>, versions: &[Version]) -> Result<Version, Error> {
        let Some(alpn) = alpn else {
            return versions
                .iter()
                .copied()
                .find(|version| version.major() == 1)
                .ok_or_else(|| Error::Version("the peer selected no protocol".into()));
        };

        Version::from_alpn(alpn)
            .filter(|version| versions.contains(version))
            .ok_or_else(|| Error::Version(format!("the peer selected {:?}", String::from_utf8_lossy(alpn))))
    }
}

/// A request method.
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Method {
    /// `GET`.
    GET,
    /// `HEAD`.
    HEAD,
    /// `POST`.
    POST,
    /// `PUT`.
    PUT,
    /// `DELETE`.
    DELETE,
    /// `CONNECT`, which tunnels rather than carrying a message.
    CONNECT,
    /// `OPTIONS`.
    OPTIONS,
    /// `TRACE`.
    TRACE,
    /// `PATCH`.
    PATCH,
}

impl Method {
    /// The method name as it appears on the wire.
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::GET => "GET",
            Self::HEAD => "HEAD",
            Self::POST => "POST",
            Self::PUT => "PUT",
            Self::DELETE => "DELETE",
            Self::CONNECT => "CONNECT",
            Self::OPTIONS => "OPTIONS",
            Self::TRACE => "TRACE",
            Self::PATCH => "PATCH",
        }
    }

    /// Whether the method is read-only, so that issuing it changes nothing.
    pub fn safe(&self) -> bool {
        matches!(self, Self::GET | Self::HEAD | Self::OPTIONS | Self::TRACE)
    }

    /// Whether repeating the method has the same effect as issuing it once.
    ///
    /// Every safe method is idempotent, as are `PUT` and `DELETE`.
    pub fn idempotent(&self) -> bool {
        self.safe() || matches!(self, Self::PUT | Self::DELETE)
    }
}

impl fmt::Display for Method {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl FromStr for Method {
    type Err = ();

    fn from_str(text: &str) -> Result<Self, Self::Err> {
        match text {
            "GET" => Ok(Self::GET),
            "HEAD" => Ok(Self::HEAD),
            "POST" => Ok(Self::POST),
            "PUT" => Ok(Self::PUT),
            "DELETE" => Ok(Self::DELETE),
            "CONNECT" => Ok(Self::CONNECT),
            "OPTIONS" => Ok(Self::OPTIONS),
            "TRACE" => Ok(Self::TRACE),
            "PATCH" => Ok(Self::PATCH),
            _ => Err(()),
        }
    }
}

/// What one end of a connection is doing on it.
///
/// The role decides which side sends requests, which stream identifiers may be
/// opened, and whether the crate fills in server-side fields such as `Date`.
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Role {
    /// Originates requests on its own behalf.
    UserAgent,
    /// Answers requests for the resources it holds.
    Origin,
    /// Forwards requests, acting as a client towards the next hop.
    Proxy,
    /// Answers requests on behalf of something behind it.
    Gateway,
    /// Relays octets without interpreting the messages inside them.
    Tunnel,
}

impl Role {
    /// Whether this role sends requests and reads responses.
    pub fn is_client(&self) -> bool {
        matches!(self, Self::UserAgent | Self::Proxy)
    }

    /// Whether this role reads requests and sends responses.
    pub fn is_server(&self) -> bool {
        matches!(self, Self::Origin | Self::Gateway)
    }
}

/// How field names are cased when they are written out.
///
/// HTTP/1.x field names are case-insensitive but conventionally written in
/// title case; HTTP/2 and HTTP/3 require lowercase. Names are always stored
/// lowercase and re-cased on the way out.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HeaderCase {
    /// `Content-Length`: each dash-separated word capitalised.
    Title,
    /// `content-length`: entirely lowercase.
    Lower,
}

impl HeaderCase {
    /// Appends `name` to `out` in this casing.
    pub fn write(&self, name: &str, out: &mut bytes::BytesMut) {
        let start = out.len();
        out.extend_from_slice(name.as_bytes());
        self.apply_in_place(&mut out[start..]);
    }

    /// Re-cases a field name already written into `written`.
    pub fn apply_in_place(&self, written: &mut [u8]) {
        written.make_ascii_lowercase();

        if matches!(self, Self::Title) {
            if let Some(first) = written.first_mut() {
                *first = first.to_ascii_uppercase();
            }

            let mut at = 0;
            while let Some(offset) = scan::find(&written[at..], b'-') {
                at += offset + 1;

                match written.get_mut(at) {
                    Some(octet) => *octet = octet.to_ascii_uppercase(),
                    None => break,
                }
            }
        }
    }

    /// Returns `name` in this casing.
    pub fn apply(&self, name: &str) -> String {
        let mut out = bytes::BytesMut::with_capacity(name.len());
        self.write(name, &mut out);
        String::from_utf8(Vec::from(out)).unwrap_or_default()
    }

    /// The casing a version expects: title case for HTTP/1.x, lowercase above.
    pub fn from_version(version: Version) -> Self {
        match version {
            Version::V1_0 | Version::V1_1 => Self::Title,
            Version::V2_0 => Self::Lower,
            Version::V3_0 => Self::Lower,
        }
    }
}

/// The payload of a message.
///
/// [`Body::Data`] and [`Body::Text`] are held in memory and their length is
/// known without doing any work; [`Body::File`] names a path that is read only
/// when the body is actually sent, so its length is not known in advance.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Body {
    /// Octets held in memory.
    Data(Bytes),
    /// A UTF-8 string held in memory.
    Text(String),
    /// A filesystem path, read when the body is needed.
    File(String),
}

impl Body {
    /// The length in octets, or `None` when the body is a file that has not been read.
    pub fn len(&self) -> Option<usize> {
        match self {
            Self::Data(data) => Some(data.len()),
            Self::Text(text) => Some(text.len()),
            Self::File(_) => None,
        }
    }

    /// Whether the body is known to be empty.
    ///
    /// A [`Body::File`] is never reported empty, because its length is unknown
    /// until it is read.
    pub fn is_empty(&self) -> bool {
        self.len() == Some(0)
    }

    /// The body as octets, reading the file if there is one.
    ///
    /// The filesystem read is boxed, so that a caller awaiting this does not
    /// carry its state machine on the far commoner path where the body is
    /// already in memory.
    ///
    /// # Errors
    ///
    /// Returns the I/O error from reading a [`Body::File`].
    pub async fn bytes(&self) -> Result<Bytes, std::io::Error> {
        match self {
            Self::Data(data) => Ok(data.clone()),
            Self::Text(text) => Ok(Bytes::copy_from_slice(text.as_bytes())),
            Self::File(path) => Ok(Bytes::from(Box::pin(tokio::fs::read(path)).await?)),
        }
    }

    /// Consumes the body and returns its octets, reading the file if there is one.
    ///
    /// The filesystem read is boxed, for the reason [`Body::bytes`] gives.
    ///
    /// # Errors
    ///
    /// Returns the I/O error from reading a [`Body::File`].
    pub async fn into_bytes(self) -> Result<Bytes, std::io::Error> {
        match self.into_inline() {
            Ok(data) => Ok(data),
            Err(path) => Ok(Bytes::from(Box::pin(tokio::fs::read(path)).await?)),
        }
    }

    /// Consumes the body and returns its octets without touching the filesystem.
    ///
    /// # Errors
    ///
    /// Returns the path as the error when the body is a [`Body::File`], so the
    /// caller can decide how to read it.
    pub fn into_inline(self) -> Result<Bytes, String> {
        match self {
            Self::Data(data) => Ok(data),
            Self::Text(text) => Ok(Bytes::from(text.into_bytes())),
            Self::File(path) => Err(path),
        }
    }

    /// The octets already in memory, or `None` for a [`Body::File`].
    pub fn inline(&self) -> Option<Bytes> {
        match self {
            Self::Data(data) => Some(data.clone()),
            Self::Text(text) => Some(Bytes::copy_from_slice(text.as_bytes())),
            Self::File(_) => None,
        }
    }
}

/// A field section: an ordered list of name and value pairs.
///
/// Order is preserved, and a name may repeat — HTTP allows several fields with
/// the same name, and `set-cookie` in particular must never be folded
/// together. Names are stored lowercase and compared case-insensitively.
///
/// Two sections are equal when they hold the same fields in the same order.
#[derive(Debug, Clone)]
pub struct Headers {
    fields: Vec<HeaderField>,
    present: u32,
}

impl Headers {
    /// `1 << index` when `matched`, and zero otherwise.
    #[inline]
    pub fn bit(matched: bool, index: u32) -> u32 {
        (matched as u32) << index
    }

    /// The presence bit that stands for a well-known field name, or zero.
    ///
    /// [`Headers`] keeps the bitwise or of these over every field it holds,
    /// which lets a lookup for one of these names rule itself out without
    /// walking the list. The name must already be lowercase. Names outside the
    /// set map to zero, and a zero always forces the full walk.
    #[inline]
    pub fn well_known(name: &str) -> u32 {
        let octets = name.as_bytes();

        let Some(first) = octets.first() else {
            return 0;
        };

        match (octets.len(), first) {
            (2, b't') => Self::bit(name == "te", 0),
            (4, b'h') => Self::bit(name == "host", 1),
            (4, b'd') => Self::bit(name == "date", 2),
            (6, b's') => Self::bit(name == "server", 3),
            (6, b'c') => Self::bit(name == "cookie", 4),
            (7, b'u') => Self::bit(name == "upgrade", 5),
            (8, b'l') => Self::bit(name == "location", 6),
            (10, b'c') => Self::bit(name == "connection", 7),
            (10, b'k') => Self::bit(name == "keep-alive", 8),
            (10, b's') => Self::bit(name == "set-cookie", 9),
            (12, b'c') => Self::bit(name == "content-type", 10),
            (14, b'c') => Self::bit(name == "content-length", 11),
            (15, b'a') => Self::bit(name == "accept-encoding", 12),
            (16, b'c') => Self::bit(name == "content-encoding", 13),
            (16, b'p') => Self::bit(name == "proxy-connection", 14),
            (17, b't') => Self::bit(name == "transfer-encoding", 15),
            (25, b's') => Self::bit(name == "strict-transport-security", 16),
            _ => 0,
        }
    }

    /// An empty section.
    pub fn new() -> Self {
        Self { fields: Vec::new(), present: 0 }
    }

    /// The most entries a section is ever asked to make room for in advance.
    ///
    /// Room is an optimisation and nothing more — a section grows past this as
    /// fields are added — so a caller asking for more than any field section
    /// could hold is asking for an allocation the machine will refuse, and a
    /// refused allocation ends the process rather than the call. Above this the
    /// ask is taken as this.
    pub const MAXIMUM_CAPACITY: usize = 64 * 1024;

    /// An empty section with room for `fields` entries.
    ///
    /// The room asked for is held to [`Headers::MAXIMUM_CAPACITY`].
    pub fn with_capacity(fields: usize) -> Self {
        Self { fields: Vec::with_capacity(fields.min(Self::MAXIMUM_CAPACITY)), present: 0 }
    }

    /// The number of fields, counting repeats separately.
    #[inline]
    pub fn len(&self) -> usize {
        self.fields.len()
    }

    /// Whether the section holds no fields at all.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.fields.is_empty()
    }

    /// Whether a stored name matches `name`, ignoring ASCII case.
    #[inline]
    pub fn named(stored: &str, name: &str) -> bool {
        if stored.len() != name.len() {
            return false;
        }

        match (stored.as_bytes().first(), name.as_bytes().first()) {
            (Some(stored), Some(name)) if !stored.eq_ignore_ascii_case(name) => return false,
            _ => {}
        }

        scan::same(stored.as_bytes(), name.as_bytes()) || stored.eq_ignore_ascii_case(name)
    }

    /// Whether the presence bits prove `name` is not here.
    ///
    /// Answers `false` for any name outside the well-known set, in which case
    /// the caller still has to walk the list.
    #[inline]
    pub fn absent(&self, name: &str) -> bool {
        let bit = Self::well_known(name);
        bit != 0 && self.present & bit == 0
    }

    /// Whether any field carries this name.
    #[inline]
    pub fn contains(&self, name: &str) -> bool {
        !self.absent(name) && self.fields.iter().any(|field| Self::named(&field.name, name))
    }

    /// The value of the first field with this name.
    #[inline]
    pub fn get(&self, name: &str) -> Option<&str> {
        if self.absent(name) {
            return None;
        }

        self.fields.iter().find(|field| Self::named(&field.name, name)).map(|field| field.value.as_str())
    }

    /// The values of every field with this name, in order.
    #[inline]
    pub fn get_all<'a>(&'a self, name: &'a str) -> impl Iterator<Item = &'a str> {
        let fields = if self.absent(name) { &self.fields[..0] } else { &self.fields[..] };

        fields.iter().filter(move |field| Self::named(&field.name, name)).map(|field| field.value.as_str())
    }

    /// Adds a field, keeping any field that already carries this name.
    ///
    /// The name is lowercased on the way in.
    pub fn append(&mut self, name: impl Into<Text>, value: impl Into<Text>) {
        let mut name = name.into();
        name.make_ascii_lowercase();

        self.present |= Self::well_known(&name);
        self.fields.push(HeaderField { name, value: value.into() });
    }

    /// [`Headers::append`] for a name already known to be lowercase.
    ///
    /// # Panics
    ///
    /// Debug builds assert that the name carries no uppercase ASCII.
    pub fn append_lowercase(&mut self, name: impl Into<Text>, value: impl Into<Text>) {
        let name = name.into();
        debug_assert!(!name.bytes().any(|byte| byte.is_ascii_uppercase()), "{name:?} is not lowercase");

        self.present |= Self::well_known(&name);
        self.fields.push(HeaderField { name, value: value.into() });
    }

    /// Adds a field, dropping every field that already carries this name.
    ///
    /// The new field goes at the end. The name is lowercased on the way in.
    pub fn insert(&mut self, name: impl Into<Text>, value: impl Into<Text>) {
        let mut name = name.into();
        name.make_ascii_lowercase();

        if !self.absent(&name) {
            self.fields.retain(|field| field.name != name);
        }

        self.present |= Self::well_known(&name);
        self.fields.push(HeaderField { name, value: value.into() });
    }

    /// Drops every field with this name, reporting whether any were there.
    pub fn remove(&mut self, name: &str) -> bool {
        if self.absent(name) {
            return false;
        }

        let len_before = self.fields.len();
        self.fields.retain(|field| !Self::named(&field.name, name));

        if self.fields.len() == len_before {
            return false;
        }

        self.present = Self::presence(&self.fields);
        true
    }

    /// Every field in order, as name and value pairs.
    #[inline]
    pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
        self.fields.iter().map(|field| (field.name.as_str(), field.value.as_str()))
    }

    /// Every field in order, as the [`HeaderField`]s they are stored as.
    ///
    /// This is what the binary versions build their field lists from: a
    /// section holds exactly the type [`hpack`] and [`qpack`] encode, and
    /// cloning a [`Text`] shares a long value rather than copying it, which
    /// [`Headers::iter`] and `&str` cannot.
    ///
    /// [`hpack`]: crate::helpers::hpack
    /// [`qpack`]: crate::helpers::qpack
    #[inline]
    pub fn fields(&self) -> &[HeaderField] {
        &self.fields
    }

    /// The presence bits standing for every well-known name in `fields`.
    #[inline]
    pub fn presence(fields: &[HeaderField]) -> u32 {
        fields.iter().fold(0, |present, field| present | Self::well_known(&field.name))
    }

    /// Takes an already-built field list as the section itself.
    ///
    /// This is what a decoded field block becomes: [`hpack`] and [`qpack`]
    /// hand back exactly the list a section is made of, so it is moved in
    /// rather than copied field by field into a second one.
    ///
    /// A name that is not lowercase is lowercased on the way in. The codecs
    /// hand back whatever the peer wrote, so that a receiver can refuse an
    /// uppercase name as the protocol requires — but a section that kept one
    /// would answer [`Headers::contains`] with `false` for a field it holds,
    /// since the presence bits are keyed on the lowercase name, and a lookup
    /// that misses a `Content-Length` a message carries is how two ends come
    /// to read one message two ways.
    ///
    /// [`hpack`]: crate::helpers::hpack
    /// [`qpack`]: crate::helpers::qpack
    pub fn from_fields(fields: Vec<HeaderField>) -> Self {
        let mut fields = fields;

        for field in &mut fields {
            if field.name.bytes().any(|byte| byte.is_ascii_uppercase()) {
                field.name.make_ascii_lowercase();
            }
        }

        Self { present: Self::presence(&fields), fields }
    }

    /// A section over fields already known to be lowercase, with the presence
    /// bits already worked out.
    ///
    /// [`Headers::from_fields`] walks the list twice more than the caller
    /// already did: once to lowercase the names and once to gather
    /// [`Headers::presence`]. A section HTTP/2 or HTTP/3 delivered has been
    /// walked field by field on the way in — the format requires lowercase
    /// names and the section was held to it — so both answers are already
    /// there, and this takes them rather than working them out again.
    ///
    /// # Panics
    ///
    /// Debug builds assert that the names are lowercase and that `present` is
    /// what [`Headers::presence`] would have said; release builds trust the
    /// caller, and a wrong `present` makes lookups miss fields that are there.
    pub fn adopt(fields: Vec<HeaderField>, present: u32) -> Self {
        debug_assert!(
            !fields.iter().any(|field| field.name.bytes().any(|byte| byte.is_ascii_uppercase())),
            "a field name handed to Headers::adopt is not lowercase"
        );
        debug_assert_eq!(present, Self::presence(&fields), "the presence bits handed to Headers::adopt are not the fields'");

        Self { fields, present }
    }

    /// Gives up the field list the section holds.
    pub fn into_fields(self) -> Vec<HeaderField> {
        self.fields
    }
}

impl PartialEq for Headers {
    fn eq(&self, other: &Self) -> bool {
        self.fields == other.fields
    }
}

impl Eq for Headers {}

impl Default for Headers {
    fn default() -> Self {
        Self::new()
    }
}

/// A stream identifier within one connection.
///
/// HTTP/1.x has no streams and leaves this unset. HTTP/2 numbers streams from
/// 1, and HTTP/3 uses the QUIC stream identifier.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StreamID(pub u64);

/// An opaque label for one connection, used to tell connections apart in logs
/// and to key state a handler wants to keep per peer.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ConnectionID(pub Bytes);

/// One HTTP request or response, whichever version framed it.
///
/// A message is a request when it carries a [`Message::method`] and a response
/// when it carries a [`Message::status_code`]; exactly one of the two is set
/// on a well-formed message. The remaining fields describe the connection the
/// message arrived on or is going out over, and are filled in by whichever
/// connection handled it.
#[derive(Debug, PartialEq, Eq)]
pub struct Message {
    /// The version that framed this message, or is about to.
    pub version: Version,

    /// The payload, if there is one.
    pub body: Option<Body>,
    /// The content coding the body is to go out in, if any.
    ///
    /// Set this before sending to have the body encoded on the way out, which
    /// is what [`Message::compress`] does and what every connection calls it
    /// for. On a message that was received it is stamped by the connection
    /// with the coding it took off the body, so it reads as what the body
    /// arrived in rather than what it will leave in.
    ///
    /// This is `Content-Encoding` and nothing else. `Transfer-Encoding` frames
    /// a body rather than codes it, and is left alone.
    pub compression: Option<Compression>,

    /// The field section that precedes the body.
    pub headers: Option<Headers>,
    /// The field section that follows the body, if the peer sent one.
    pub trailers: Option<Headers>,

    // Connection
    /// The stream this message belongs to, for HTTP/2 and HTTP/3.
    ///
    /// A server answering a request must echo the request's stream identifier
    /// back on the response, so the two are matched up.
    pub stream_id: Option<StreamID>,
    /// The connection this message arrived on.
    pub connection_id: Option<ConnectionID>,
    /// The address the request was received from, and its port.
    ///
    /// Stamped on by whichever connection received it, alongside
    /// [`Message::security`], and so set only on a request a server took off a
    /// connection. A response carries none, and neither does a message the
    /// caller built. A Unix socket connection carries none either: the address
    /// of an accepted Unix socket names nothing.
    pub client: Option<std::net::SocketAddr>,

    /// What the transport the message crossed turned out to be.
    ///
    /// Stamped on by whichever connection received it, by [`Security::apply`].
    /// A message the caller built has crossed nothing, so everything here
    /// reads as absent on one until it does.
    pub security: Security,

    // Request
    /// The request method, set on requests only.
    pub method: Option<Method>,
    /// The request target, set on requests only.
    ///
    /// Ordinarily a path; for a `CONNECT` without `:protocol`, an authority.
    pub target: Option<Text>,

    // Response
    /// The status code, set on responses only.
    pub status_code: Option<u16>,
}

impl Message {
    /// Whether this message leaves its stream open as a tunnel.
    ///
    /// `method` is the method of the request the stream carries. A `CONNECT`
    /// whose response succeeded is followed by tunnelled octets rather than by
    /// the end of the stream, which is what HTTP/2 and HTTP/3 both have to
    /// account for.
    pub fn tunneling(&self, method: Option<Method>) -> bool {
        method == Some(Method::CONNECT) && (self.is_request() || matches!(self.status_code, Some(200..=299)))
    }

    /// An empty message with an empty field section and nothing else set.
    ///
    /// It is neither a request nor a response until a method or a status code
    /// is set; [`Message::request`] and [`Message::response`] do that for you.
    pub fn new(version: Version) -> Self {
        Self {
            version,

            body: None,
            compression: None,

            headers: Some(Headers::new()),
            trailers: None,

            stream_id: None,
            connection_id: None,
            client: None,

            security: Security::default(),

            method: None,
            target: None,

            status_code: None,
        }
    }

    /// A request for `target`.
    pub fn request(method: Method, target: impl Into<Text>, version: Version) -> Self {
        Self { method: Some(method), target: Some(target.into()), ..Self::new(version) }
    }

    /// A response carrying `status_code`.
    pub fn response(status_code: u16, version: Version) -> Self {
        Self { status_code: Some(status_code), ..Self::new(version) }
    }

    /// Whether this message is a request.
    pub fn is_request(&self) -> bool {
        self.method.is_some()
    }

    /// Whether this message is a response.
    pub fn is_response(&self) -> bool {
        self.status_code.is_some()
    }

    /// Whether this is a 1xx response, which precedes the real one.
    pub fn is_informational(&self) -> bool {
        matches!(self.status_code, Some(100..=199))
    }

    /// Whether the message ends at its field section, whatever it carries.
    ///
    /// A 1xx, a 204 and a 304 carry no content by definition, and neither does
    /// any response to `HEAD`, however it is labelled — RFC 9112 §6.3 and RFC
    /// 9110 §9.3.2. `method` is the method of the request being answered, and
    /// is the only way to tell the last of those apart from an ordinary
    /// response; pass `None` on a request, which is never bodyless in this
    /// sense.
    ///
    /// Every version asks this before it writes a body, since a body written
    /// past a message that ends here is octets the peer will read as the next
    /// message.
    pub fn bodyless(&self, method: Option<Method>) -> bool {
        match self.status_code {
            Some(status_code) => matches!(status_code, 100..=199 | 204 | 304) || method == Some(Method::HEAD),
            None => false,
        }
    }

    /// Whether the body is currently carried compressed.
    ///
    /// Judged from `Content-Encoding` alone, which is the only thing that says
    /// so. A body this crate decoded has had the field taken off it, so a
    /// message that still carries one is still coded — including when the
    /// coding is one this crate does not implement, which is exactly the case
    /// a caller needs to be told about.
    pub fn compressed(&self) -> bool {
        self.headers.as_ref().is_some_and(|headers| Compression::encoded(headers.get_all("content-encoding")))
    }

    /// The best coding this message's `Accept-Encoding` permits.
    ///
    /// Asked of a request by the connection that received it, so that the
    /// response it is answered with can be coded in something the peer reads.
    pub fn accepted(&self) -> Option<Compression> {
        self.headers.as_ref().and_then(|headers| Compression::accepted(headers.get_all("accept-encoding")))
    }

    /// Whether the message may carry content at all.
    ///
    /// A 1xx, a 204 and a 304 carry none by definition, and a partial response
    /// carries a range of a representation rather than the representation, so
    /// coding it afterwards would leave the range naming nothing.
    pub fn codable(&self) -> bool {
        let bodyless = matches!(self.status_code, Some(100..=199 | 204 | 304));
        let partial = self.status_code == Some(206) || self.headers.as_ref().is_some_and(|headers| headers.contains("content-range"));

        !bodyless && !partial && self.method != Some(Method::CONNECT)
    }

    /// Reads the body into memory, so that it can be coded and framed.
    ///
    /// A [`Body::File`] becomes a [`Body::Data`]; anything else is left as it
    /// is. This is the asynchronous half of sending a body, kept apart from
    /// [`Message::compress`] because the coding itself has to happen where a
    /// filesystem read cannot — inside the HTTP/3 worker, which frames its
    /// messages in QUIC callbacks.
    ///
    /// # Errors
    ///
    /// Returns [`Error::IO`] when the file cannot be read.
    pub async fn materialize(&mut self) -> Result<(), Error> {
        if let Some(body) = self.body.take() {
            self.body = Some(Body::Data(body.into_bytes().await?));
        }

        Ok(())
    }

    /// Encodes the body in [`Message::compression`], ready for it to go out.
    ///
    /// `accepted` is the coding the exchange permits, which is what
    /// [`Compression::Auto`] settles on; a client request has no exchange to
    /// consult and passes `None`, so `Auto` sends such a body as it stands
    /// rather than guessing at what an origin can read. An explicit coding is
    /// applied whatever `accepted` says, because the caller asked for it.
    ///
    /// Nothing is done to a body that already carries a `Content-Encoding`, to
    /// an absent or empty body, or to a message [`Message::codable`] refuses.
    /// `Content-Length` is corrected where the message carries one, and a
    /// response whose coding was settled from `Accept-Encoding` is given
    /// `Vary: Accept-Encoding`, without which a shared cache would hand one
    /// peer's coding to another. [`Message::compression`] ends up as the
    /// coding that was applied, or `None` when none was.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Protocol`] when the body has not been through
    /// [`Message::materialize`], and otherwise as [`Compression::encode`].
    pub fn compress(&mut self, accepted: Option<Compression>) -> Result<(), Error> {
        let Some(compression) = self.compression else {
            return Ok(());
        };

        let settled = match compression {
            Compression::Auto => accepted,
            coding => Some(coding),
        };

        let Some(coding) = settled else {
            self.compression = None;
            return Ok(());
        };

        if self.compressed() || !self.codable() || self.body.as_ref().is_none_or(Body::is_empty) {
            self.compression = None;
            return Ok(());
        }

        let Some(body) = self.body.as_ref().and_then(Body::inline) else {
            return Err(Error::Protocol("a body that is still a file cannot be coded".into()));
        };

        let encoded = coding.encode(&body)?;
        let length = encoded.len();
        let varying = compression == Compression::Auto && self.is_response();

        self.body = Some(Body::Data(encoded));
        self.compression = Some(coding);

        let headers = self.headers.get_or_insert_with(Headers::new);
        headers.append_lowercase("content-encoding", coding.as_str());

        if headers.contains("content-length") {
            headers.insert("content-length", length.to_string());
        }

        if varying && !headers.contains("vary") {
            headers.append_lowercase("vary", "Accept-Encoding");
        }

        Ok(())
    }

    /// Decodes a body that arrived coded, and takes the field off it.
    ///
    /// The counterpart of [`Message::compress`]: whatever `Content-Encoding`
    /// names is decoded, the field is removed, `Content-Length` is corrected,
    /// and [`Message::compression`] is stamped with what came off. A coding
    /// this crate does not implement, a field naming several, and an absent
    /// body are each left exactly as they arrived, so [`Message::compressed`]
    /// keeps answering yes for them.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Limit`] once the decoded body passes `max`, and
    /// otherwise as [`Compression::decode`].
    pub fn decompress(&mut self, max: u64) -> Result<(), Error> {
        let Some(headers) = self.headers.as_mut() else {
            return Ok(());
        };

        let Some(coding) = Compression::applied(headers.get_all("content-encoding")) else {
            return Ok(());
        };

        let Some(body) = self.body.as_ref().and_then(Body::inline) else {
            return Ok(());
        };

        let decoded = coding.decode(&body, max)?;
        let length = decoded.len();

        self.body = Some(Body::Data(decoded));
        self.compression = Some(coding);

        headers.remove("content-encoding");

        if headers.contains("content-length") {
            headers.insert("content-length", length.to_string());
        }

        Ok(())
    }
}

/// What one connection is allowed to spend on the peer's behalf.
///
/// Every field is a ceiling: exceeding one produces [`Error::Limit`] and, for
/// the counters that exist to blunt floods, tears the connection down. The
/// defaults are meant to be usable as they stand for a public-facing server.
///
/// Timeouts are in seconds, and zero means wait forever.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Limits {
    /// In bytes, the total size of the HTTP message allowed for reception.
    pub max_message_size:      u64,
    /// In bytes, the size of the HTTP message body allowed for reception.
    pub max_message_body_size: u64,
    /// In bytes, the size a received body may reach once its content coding is undone.
    ///
    /// A compressed body is small on the wire and can be enormous once it is
    /// decoded, so [`Limits::max_message_body_size`] does not bound it: that
    /// counts the octets that arrived. Decoding past this produces
    /// [`Error::Limit`] and the decoded body is never held.
    pub max_decompressed_body_size: u64,

    /// In bytes, the request/status line ceiling.
    pub max_startline_size:    u32,
    /// In bytes, the whole header (or trailer) block.
    pub max_headers_size:      u64,
    /// The number of header fields allowed in one block.
    pub max_header_count:      u16,
    /// In bytes, the chunk-size line ceiling for chunked transfer encoding.
    pub max_chunk_header_size: u32,

    /// In bytes, how much room each read from a transport is given.
    ///
    /// Reads start at a fraction of this and ramp up to it as long as they
    /// keep coming back full, so a small message costs a small read while a
    /// large body reaches the full size. It sizes the read rather than capping
    /// it: a read that finds spare room already in the buffer may return more.
    /// See [`Buffer::set_chunk_size`].
    ///
    /// [`Buffer::set_chunk_size`]: crate::protocol::common::Buffer::set_chunk_size
    pub read_chunk_size: u64,
    /// In bytes, the buffer size above which an idle connection gives memory back.
    pub idle_capacity: u64,

    /// The number of connections a listener may negotiate at once (mitigates slow handshake floods).
    pub max_pending_handshakes: u32,

    /// In seconds, how long one connection may take to negotiate (0 waits forever).
    ///
    /// The deadline on everything between an accepted transport and a
    /// connection a handler can be given: the TLS handshake, or the wait for
    /// the first octets on a plaintext port. It is what bounds how long one of
    /// the [`Limits::max_pending_handshakes`] slots may be held, which is why
    /// it is shorter than [`Limits::read_timeout`] — a peer that has not begun
    /// speaking has not yet earned the patience given to one that has.
    pub handshake_timeout: f64,

    /// In seconds, how long one read may wait for the peer to deliver more octets (0 waits forever).
    pub read_timeout: f64,
    /// In seconds, how long one write may wait for the peer to accept more octets (0 waits forever).
    pub write_timeout: f64,
    /// In seconds, how long one whole message may take to arrive once it has begun (0 waits forever).
    pub receive_timeout: f64,
    /// In seconds, how long one whole message may take to send (0 waits forever).
    pub send_timeout: f64,

    // HTTP/1
    /// In bytes, the body size up to which the head and the body go out as one write.
    ///
    /// Below this, coalescing saves a syscall and a round trip; above it,
    /// copying the body into the head buffer costs more than the extra write.
    pub inline_body_size: u64,

    // HTTP/2 and HTTP/3
    /// The number of streams a peer may have open at once, per connection.
    pub max_concurrent_streams:     u32,
    /// In bytes, the unread message data one connection may hold across all of its streams.
    pub max_connection_buffer_size: u64,
    /// The number of streams a peer may reset before a response was sent, per connection (mitigates rapid reset floods).
    pub max_premature_resets:       u32,

    /// In bytes, the largest field compression encoder table this end will keep, whatever the peer allows.
    ///
    /// The HPACK table for HTTP/2 and the QPACK one for HTTP/3; both are this
    /// end's own ceiling, held to whether or not the peer permits more.
    pub max_encoder_table_size:     u64,

    // HTTP/2
    /// The number of frames a peer may send without advancing a stream, per connection (mitigates PING and SETTINGS floods).
    pub max_idle_frames:            u32,
    /// In bytes, the buffered output size at which a body write flushes rather than growing.
    pub output_high_water:          u64,

    // HTTP/3
    /// The number of requests one connection may serve over its lifetime before it is wound down with GOAWAY (0 serves forever).
    ///
    /// Distinct from [`Limits::max_concurrent_streams`], which bounds how many
    /// are open at once: this bounds the total. The QUIC stack underneath
    /// keeps a trace of every stream a connection has ever closed, so a
    /// connection that never ends grows without bound under continuous load;
    /// winding it down lets a well-behaved peer reconnect and gives all of
    /// that back.
    pub max_requests_per_connection: u64,
    /// In seconds, how long to wait for a blocking QPACK reference to resolve before failing the connection.
    pub qpack_block_timeout:        f64,
    /// The number of unidirectional streams a peer may open at once, per connection.
    pub max_peer_uni_streams:       u32,
    /// The number of unacknowledged QPACK field sections the encoder may track before it stops referencing the dynamic table.
    pub max_outstanding_sections:   u32,
    /// The number of streams that may wait QPACK-blocked at once, advertised as `SETTINGS_QPACK_BLOCKED_STREAMS`.
    pub max_blocked_streams:        u32,
    /// The number of reads or writes a tunnel will hold before it applies back pressure.
    pub tunnel_backlog:             u32,
    /// The number of commands or events queued between a connection handle and the worker driving it.
    pub command_backlog:            u32,

    // WebSocket
    /// In seconds, how long a close waits for the peer to echo it back before the transport is shut down.
    pub ws_linger_timeout: f64,
    /// The number of continuation frames allowed in one message.
    pub ws_max_fragments:  u16,

    // Client state
    /// The number of cookies one jar may hold across all origins.
    pub max_cookies:            u32,
    /// The number of cookies one jar may hold for a single domain.
    pub max_cookies_per_domain: u16,
    /// The number of hosts one HSTS store may remember.
    pub max_hsts_entries:       u32,
}

impl Default for Limits {
    fn default() -> Self {
        Self {
            max_message_size: 64 * 1024 * 1024,
            max_message_body_size: 64 * 1024 * 1024,
            max_decompressed_body_size: 256 * 1024 * 1024,

            max_startline_size: 8 * 1024,
            max_headers_size: 64 * 1024,
            max_header_count: 100,
            max_chunk_header_size: 128,

            read_chunk_size: 16 * 1024,
            idle_capacity: 64 * 1024,

            max_pending_handshakes: 256,

            handshake_timeout: 10.0,
            read_timeout: 30.0,
            write_timeout: 30.0,
            receive_timeout: 300.0,
            send_timeout: 1800.0,

            inline_body_size: 64 * 1024,

            max_concurrent_streams: 100,
            max_connection_buffer_size: 64 * 1024 * 1024,
            max_premature_resets: 1000,
            max_encoder_table_size: 64 * 1024,
            max_idle_frames: 1000,
            output_high_water: 64 * 1024,

            max_requests_per_connection: 10_000,
            qpack_block_timeout: 5.0,
            max_peer_uni_streams: 32,
            max_outstanding_sections: 512,
            max_blocked_streams: 16,
            tunnel_backlog: 32,
            command_backlog: 256,

            ws_linger_timeout: 10.0,
            ws_max_fragments: 4096,

            max_cookies: 3000,
            max_cookies_per_domain: 50,
            max_hsts_entries: 4096,
        }
    }
}