watermelon_proto/headers/
value.rs1use alloc::string::String;
2use core::{
3 fmt::{self, Display},
4 ops::Deref,
5};
6
7use bytestring::ByteString;
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
25pub struct HeaderValue(ByteString);
26
27impl HeaderValue {
28 #[must_use]
34 pub fn from_static(value: &'static str) -> Self {
35 Self::try_from(ByteString::from_static(value)).expect("invalid HeaderValue")
36 }
37
38 #[must_use]
51 #[expect(
52 clippy::missing_panics_doc,
53 reason = "The header validation is only made in debug"
54 )]
55 pub fn from_dangerous_value(value: ByteString) -> Self {
56 if cfg!(debug_assertions) {
57 if let Err(err) = validate_header_value(&value) {
58 panic!("HeaderValue {value:?} isn't valid {err:?}");
59 }
60 }
61 Self(value)
62 }
63
64 #[must_use]
65 pub fn as_str(&self) -> &str {
66 &self.0
67 }
68}
69
70impl Display for HeaderValue {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 Display::fmt(&self.0, f)
73 }
74}
75
76impl TryFrom<ByteString> for HeaderValue {
77 type Error = HeaderValueValidateError;
78
79 fn try_from(value: ByteString) -> Result<Self, Self::Error> {
80 validate_header_value(&value)?;
81 Ok(Self::from_dangerous_value(value))
82 }
83}
84
85impl TryFrom<String> for HeaderValue {
86 type Error = HeaderValueValidateError;
87
88 fn try_from(value: String) -> Result<Self, Self::Error> {
89 validate_header_value(&value)?;
90 Ok(Self::from_dangerous_value(value.into()))
91 }
92}
93
94impl From<HeaderValue> for ByteString {
95 fn from(value: HeaderValue) -> Self {
96 value.0
97 }
98}
99
100impl AsRef<[u8]> for HeaderValue {
101 fn as_ref(&self) -> &[u8] {
102 self.as_str().as_bytes()
103 }
104}
105
106impl AsRef<str> for HeaderValue {
107 fn as_ref(&self) -> &str {
108 self.as_str()
109 }
110}
111
112impl Deref for HeaderValue {
113 type Target = str;
114
115 fn deref(&self) -> &Self::Target {
116 self.as_str()
117 }
118}
119
120#[derive(Debug, thiserror::Error)]
122pub enum HeaderValueValidateError {
123 #[error("HeaderValue is empty")]
125 Empty,
126 #[error("HeaderValue is too long")]
128 TooLong,
129 #[error("HeaderValue contained an illegal whitespace character")]
131 IllegalCharacter,
132}
133
134fn validate_header_value(header_value: &str) -> Result<(), HeaderValueValidateError> {
135 if header_value.is_empty() {
136 return Err(HeaderValueValidateError::Empty);
137 }
138
139 if header_value.len() > 1024 {
140 return Err(HeaderValueValidateError::TooLong);
142 }
143
144 if header_value.chars().any(char::is_whitespace) {
145 return Err(HeaderValueValidateError::IllegalCharacter);
148 }
149
150 Ok(())
151}