rtsp_types/headers/
content_type.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/// `Content-Type` header ([RFC 7826 section 18.19](https://tools.ietf.org/html/rfc7826#section-18.19)).
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct ContentType {
11    /// Media type.
12    pub media_type: super::MediaType,
13    /// Media subtype.
14    pub media_subtype: String,
15    /// Optional media parameters.
16    pub params: Vec<(String, Option<String>)>,
17}
18
19impl super::TypedHeader for ContentType {
20    fn from_headers(headers: impl AsRef<Headers>) -> Result<Option<Self>, HeaderParseError> {
21        use super::parser_helpers::split_once;
22
23        let headers = headers.as_ref();
24
25        let header = match headers.get(&CONTENT_TYPE) {
26            None => return Ok(None),
27            Some(header) => header,
28        };
29
30        let content_type = header.as_str();
31
32        let (media_type, params) = match split_once(content_type, ';') {
33            None => (content_type, Vec::new()),
34            Some((media_type, params_string)) => {
35                let mut params = Vec::new();
36                for param in params_string.split(';') {
37                    let param = param.trim();
38                    if let Some((param, value)) = split_once(param, '=') {
39                        params.push((String::from(param), Some(String::from(value))));
40                    } else {
41                        params.push((String::from(param), None));
42                    }
43                }
44
45                (media_type, params)
46            }
47        };
48
49        let (media_type, media_subtype) = split_once(media_type, '/').ok_or(HeaderParseError)?;
50        let media_type = media_type.parse().map_err(|_| HeaderParseError)?;
51
52        Ok(Some(ContentType {
53            media_type,
54            media_subtype: media_subtype.into(),
55            params,
56        }))
57    }
58
59    fn insert_into(&self, mut headers: impl AsMut<Headers>) {
60        use std::fmt::Write;
61
62        let headers = headers.as_mut();
63
64        let mut content_type = String::new();
65        write!(
66            &mut content_type,
67            "{}/{}",
68            self.media_type, self.media_subtype
69        )
70        .unwrap();
71
72        for param in &self.params {
73            content_type.push(';');
74            if let Some(ref value) = param.1 {
75                write!(&mut content_type, "{}={}", param.0, value).unwrap();
76            } else {
77                content_type.push_str(&param.0);
78            }
79        }
80
81        headers.insert(CONTENT_TYPE, content_type);
82    }
83}