rtsp_types/headers/
session.rs

1// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
2//
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5use super::*;
6
7/// `Session` header ([RFC 7826 section 18.49](https://tools.ietf.org/html/rfc7826#section-18.49)).
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct Session(
11    /// Session identifier.
12    pub String,
13    /// Optional session timeout in seconds.
14    pub Option<u64>,
15);
16
17impl Session {
18    pub fn with_timeout(id: String, timeout: u64) -> Self {
19        Self(id, Some(timeout))
20    }
21}
22
23impl std::ops::Deref for Session {
24    type Target = str;
25
26    fn deref(&self) -> &Self::Target {
27        &self.0
28    }
29}
30
31impl AsRef<str> for Session {
32    fn as_ref(&self) -> &str {
33        &self.0
34    }
35}
36
37impl<'a> From<&'a str> for Session {
38    fn from(v: &'a str) -> Session {
39        Session(v.into(), None)
40    }
41}
42
43impl From<String> for Session {
44    fn from(v: String) -> Session {
45        Session(v, None)
46    }
47}
48
49impl super::TypedHeader for Session {
50    fn from_headers(headers: impl AsRef<Headers>) -> Result<Option<Self>, HeaderParseError> {
51        let headers = headers.as_ref();
52
53        let header = match headers.get(&SESSION) {
54            None => return Ok(None),
55            Some(header) => header,
56        };
57
58        let mut iter = header.as_str().split(';');
59
60        let session_id = iter.next().ok_or(HeaderParseError)?;
61        let timeout = iter
62            .find_map(|s| s.strip_prefix("timeout="))
63            .map(|s| s.parse::<u64>())
64            .transpose()
65            .map_err(|_| HeaderParseError)?;
66
67        Ok(Some(Session(session_id.into(), timeout)))
68    }
69
70    fn insert_into(&self, mut headers: impl AsMut<Headers>) {
71        let headers = headers.as_mut();
72
73        if let Some(timeout) = self.1 {
74            headers.insert(SESSION, format!("{};timeout={}", self.0, timeout));
75        } else {
76            headers.insert(SESSION, self.0.to_string());
77        }
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn test_from_headers() {
87        let strict_headers = [
88            ("12345678", Some(Session("12345678".to_string(), None))),
89            (
90                "12345678;timeout=60",
91                Some(Session("12345678".to_string(), Some(60))),
92            ),
93            (
94                "lskdjf238742dkjlskjd;timeout=60",
95                Some(Session("lskdjf238742dkjlskjd".to_string(), Some(60))),
96            ),
97            (
98                "alskdjalskjdalskjdalksjd;timeout=60",
99                Some(Session("alskdjalskjdalskjdalksjd".to_string(), Some(60))),
100            ),
101        ];
102
103        let loose_headers = [
104            (
105                "12345678;timeout=60;special",
106                Some(Session("12345678".to_string(), Some(60))),
107            ),
108            (
109                "12345678;timeout=60;393939393",
110                Some(Session("12345678".to_string(), Some(60))),
111            ),
112            (
113                "12345678;timeout=60;393;93;93;93",
114                Some(Session("12345678".to_string(), Some(60))),
115            ),
116            (
117                "12345678;special;timeout=600",
118                Some(Session("12345678".to_string(), Some(600))),
119            ),
120            (
121                "12345678;extra;extra;extra;timeout=600",
122                Some(Session("12345678".to_string(), Some(600))),
123            ),
124            (
125                "wjdl38ek98;timeout=60;special",
126                Some(Session("wjdl38ek98".to_string(), Some(60))),
127            ),
128            (
129                "wjdl38ek98;timeout=60;393939393",
130                Some(Session("wjdl38ek98".to_string(), Some(60))),
131            ),
132            (
133                "wjdl38ek98;timeout=60;393;93;93;93",
134                Some(Session("wjdl38ek98".to_string(), Some(60))),
135            ),
136            (
137                "wjdl38ek98;special;timeout=600",
138                Some(Session("wjdl38ek98".to_string(), Some(600))),
139            ),
140            (
141                "wjdl38ek98;extra;extra;extra;timeout=600",
142                Some(Session("wjdl38ek98".to_string(), Some(600))),
143            ),
144        ];
145
146        let bad_headers = [
147            "12345678;timeout=aa",
148            "12345678;timeout=a6a",
149            "12345678;timeout=!!!",
150            "12345678;timeout=18446744073709551616",
151            "12345678;timeout=18446744073709551616;special",
152            "12345678;special;timeout=18446744073709551616",
153            "12345678;timeout=-1",
154            "12345678;timeout=-2",
155        ];
156
157        let not_session_headers = [(AUTHORIZATION, "blah"), (ACCEPT, "application/sdp")];
158
159        for (header, expected) in strict_headers {
160            let mut test_headers = Headers::new();
161            test_headers.insert(SESSION, header);
162            let from_headers_result =
163                Session::from_headers(test_headers).expect("strict_headers should not error");
164
165            assert_eq!(from_headers_result, expected, "{header}");
166        }
167
168        for (header, expected) in loose_headers {
169            let mut test_headers = Headers::new();
170            test_headers.insert(SESSION, header);
171            let from_headers_result =
172                Session::from_headers(test_headers).expect("loose_errors should not error");
173
174            assert_eq!(from_headers_result, expected, "{header}");
175        }
176
177        for header in bad_headers {
178            let mut test_headers = Headers::new();
179            test_headers.insert(SESSION, header);
180
181            Session::from_headers(test_headers)
182                .expect_err("bad_headers should all give HeaderParserErrors");
183        }
184
185        for (header, value) in not_session_headers {
186            let mut test_headers = Headers::new();
187            test_headers.insert(header.clone(), value);
188            let from_headers_result =
189                Session::from_headers(test_headers).expect("not_session_headers should not error");
190
191            assert_eq!(from_headers_result, None, "{header}:{value}");
192        }
193    }
194}