Skip to main content

sark_http/payload/response/headers/
name.rs

1use std::borrow::Cow;
2
3use crate::{
4    field::{self, storage},
5    payload::response::headers::Error,
6};
7
8/// An ordinary lowercase application header outside framework-managed names.
9#[derive(Copy, Debug, PartialEq, Eq)]
10#[repr(transparent)]
11pub struct Name<T>(pub(in crate::payload::response::headers) field::Lower<T>);
12
13impl<T: Copy> Clone for Name<T> {
14    fn clone(&self) -> Self {
15        *self
16    }
17}
18
19impl<T: storage::Bytes> Name<T> {
20    pub fn new(name: field::Lower<T>) -> Result<Self, Error> {
21        if Name::<&[u8]>::is_managed(name.as_bytes()) {
22            return Err(Error::Managed);
23        }
24        Ok(Self(name))
25    }
26
27    pub fn borrow(&self) -> Name<&[u8]> {
28        Name(self.0.borrow())
29    }
30
31    pub fn as_bytes(&self) -> &[u8] {
32        self.0.as_bytes()
33    }
34}
35
36impl<T: storage::Bytes> AsRef<[u8]> for Name<T> {
37    fn as_ref(&self) -> &[u8] {
38        self.as_bytes()
39    }
40}
41
42impl<T: storage::Text> Name<T> {
43    pub fn as_str(&self) -> &str {
44        self.0.as_str()
45    }
46}
47
48impl<T: storage::Text> AsRef<str> for Name<T> {
49    fn as_ref(&self) -> &str {
50        self.as_str()
51    }
52}
53
54impl<T> Name<T> {
55    pub fn into_inner(self) -> field::Lower<T> {
56        self.0
57    }
58}
59
60impl<'a> Name<&'a [u8]> {
61    pub const fn try_bytes(name: &'a [u8]) -> Result<Self, Error> {
62        let name = match field::Lower::try_bytes(name) {
63            Ok(name) => name,
64            Err(error) => return Err(Error::Syntax(error)),
65        };
66        if Self::is_managed(name.get()) {
67            return Err(Error::Managed);
68        }
69        Ok(Self(name))
70    }
71
72    pub const fn is_managed(name: &[u8]) -> bool {
73        name.eq_ignore_ascii_case(b"date")
74            || name.eq_ignore_ascii_case(b"server")
75            || name.eq_ignore_ascii_case(b"content-length")
76            || name.eq_ignore_ascii_case(b"connection")
77            || name.eq_ignore_ascii_case(b"transfer-encoding")
78            || name.eq_ignore_ascii_case(b"keep-alive")
79            || name.eq_ignore_ascii_case(b"proxy-connection")
80            || name.eq_ignore_ascii_case(b"upgrade")
81            || name.eq_ignore_ascii_case(b"te")
82    }
83
84    pub const fn get(self) -> &'a [u8] {
85        self.0.get()
86    }
87}
88
89impl Name<Cow<'_, str>> {
90    pub const CONTENT_TYPE: Self = Self(field::Lower::CONTENT_TYPE);
91}