Skip to main content

rama_http_headers/common/
te.rs

1use crate::specifier::QualityValue;
2use rama_utils::collections::NonEmptySmallVec;
3
4rama_utils::macros::enums::enum_builder! {
5    /// Directive for the [`Te`] header.
6    @String
7    pub enum TeDirective {
8        /// A format using the [Lempel-Ziv-Welch](https://en.wikipedia.org/wiki/LZW) (LZW) algorithm
9        /// is accepted as a transfer coding name.
10        Compress => "compress",
11        /// Using the zlib structure (defined in [RFC 1950](https://datatracker.ietf.org/doc/html/rfc1950))
12        /// is accepted as a transfer coding name.
13        Deflate => "deflate",
14        /// A format using the [Lempel-Ziv coding](https://en.wikipedia.org/wiki/LZ77_and_LZ78#LZ77)(LZ77),
15        /// with a 32-bit CRC is accepted as a transfer coding name.
16        Gzip => "gzip",
17        /// Indicates that the client will not discard trailer fields in a
18        /// [chunked transfer coding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Transfer-Encoding#chunked).
19        Trailers => "trailers",
20    }
21}
22
23derive_non_empty_flat_csv_header! {
24    #[header(name = TE, sep = Comma)]
25    #[derive(Clone, Debug, PartialEq)]
26    /// `TE` header, defined in
27    /// [RFC7230](https://datatracker.ietf.org/doc/html/rfc7230#section-4.3)
28    ///
29    /// As RFC7230 states, "The "TE" header field in a request indicates what transfer codings,
30    /// besides chunked, the client is willing to accept in response, and
31    /// whether or not the client is willing to accept trailer fields in a
32    /// chunked transfer coding."
33    ///
34    /// For HTTP/1.1 compliant clients `chunked` transfer codings are assumed to be acceptable and
35    /// so should never appear in this header.
36    ///
37    /// # ABNF
38    ///
39    /// ```text
40    /// TE        = "TE" ":" #( t-codings )
41    /// t-codings = "trailers" | ( transfer-extension [ accept-params ] )
42    /// ```
43    ///
44    /// # Example values
45    /// * `trailers`
46    /// * `trailers, deflate;q=0.5`
47    pub struct Te(pub NonEmptySmallVec<2, QualityValue<TeDirective>>);
48}
49
50impl Te {
51    /// Create a `TE: trailers` header.
52    #[must_use]
53    pub fn trailers() -> Self {
54        Self(NonEmptySmallVec::new(QualityValue::new_value(
55            TeDirective::Trailers,
56        )))
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::super::{test_decode, test_encode};
63    use super::*;
64    use crate::specifier::Quality;
65
66    #[test]
67    fn decode_header_compress() {
68        let Te(direcives) = test_decode(&["compress"]).unwrap();
69
70        assert_eq!(direcives.len(), 1);
71        assert_eq!(direcives[0].value.as_str(), "compress");
72        assert_eq!(direcives[0].quality, Quality::one());
73    }
74
75    #[test]
76    fn decode_header_trailers_deflate() {
77        let Te(direcives) = test_decode(&["trailers, deflate;q=0.5"]).unwrap();
78
79        assert_eq!(direcives.len(), 2);
80        assert_eq!(direcives[0].value.as_str(), "trailers");
81        assert_eq!(direcives[0].quality, Quality::one());
82        assert_eq!(direcives[1].value.as_str(), "deflate");
83        assert_eq!(direcives[1].quality, Quality::new_clamped(500));
84    }
85
86    #[test]
87    fn decode_header_trailers_deflate_split() {
88        let Te(direcives) = test_decode(&["trailers", "deflate;q=0.5"]).unwrap();
89
90        assert_eq!(direcives.len(), 2);
91        assert_eq!(direcives[0].value.as_str(), "trailers");
92        assert_eq!(direcives[0].quality, Quality::one());
93        assert_eq!(direcives[1].value.as_str(), "deflate");
94        assert_eq!(direcives[1].quality, Quality::new_clamped(500));
95    }
96
97    #[test]
98    fn encode() {
99        let te = Te::trailers();
100        let headers = test_encode(te);
101        assert_eq!(headers["te"], "trailers");
102    }
103}