| 1 | use super::{DecoderError, NeedMore}; |
| 2 | use crate::ext::Protocol; |
| 3 | |
| 4 | use bytes::Bytes; |
| 5 | use http::header::{HeaderName, HeaderValue}; |
| 6 | use http::{Method, StatusCode}; |
| 7 | use std::fmt; |
| 8 | |
| 9 | /// HTTP/2 Header |
| 10 | #[derive (Debug, Clone, Eq, PartialEq)] |
| 11 | pub enum Header<T = HeaderName> { |
| 12 | Field { name: T, value: HeaderValue }, |
| 13 | // TODO: Change these types to `http::uri` types. |
| 14 | Authority(BytesStr), |
| 15 | Method(Method), |
| 16 | Scheme(BytesStr), |
| 17 | Path(BytesStr), |
| 18 | Protocol(Protocol), |
| 19 | Status(StatusCode), |
| 20 | } |
| 21 | |
| 22 | /// The header field name |
| 23 | #[derive (Debug, Clone, Eq, PartialEq, Hash)] |
| 24 | pub enum Name<'a> { |
| 25 | Field(&'a HeaderName), |
| 26 | Authority, |
| 27 | Method, |
| 28 | Scheme, |
| 29 | Path, |
| 30 | Protocol, |
| 31 | Status, |
| 32 | } |
| 33 | |
| 34 | #[doc (hidden)] |
| 35 | #[derive (Clone, Eq, PartialEq, Default)] |
| 36 | pub struct BytesStr(Bytes); |
| 37 | |
| 38 | pub fn len(name: &HeaderName, value: &HeaderValue) -> usize { |
| 39 | let n: &str = name.as_ref(); |
| 40 | 32 + n.len() + value.len() |
| 41 | } |
| 42 | |
| 43 | impl Header<Option<HeaderName>> { |
| 44 | pub fn reify(self) -> Result<Header, HeaderValue> { |
| 45 | use self::Header::*; |
| 46 | |
| 47 | Ok(match self { |
| 48 | Field { |
| 49 | name: Some(n: HeaderName), |
| 50 | value: HeaderValue, |
| 51 | } => Field { name: n, value }, |
| 52 | Field { name: None, value: HeaderValue } => return Err(value), |
| 53 | Authority(v: BytesStr) => Authority(v), |
| 54 | Method(v: Method) => Method(v), |
| 55 | Scheme(v: BytesStr) => Scheme(v), |
| 56 | Path(v: BytesStr) => Path(v), |
| 57 | Protocol(v: Protocol) => Protocol(v), |
| 58 | Status(v: StatusCode) => Status(v), |
| 59 | }) |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | impl Header { |
| 64 | pub fn new(name: Bytes, value: Bytes) -> Result<Header, DecoderError> { |
| 65 | if name.is_empty() { |
| 66 | return Err(DecoderError::NeedMore(NeedMore::UnexpectedEndOfStream)); |
| 67 | } |
| 68 | if name[0] == b':' { |
| 69 | match &name[1..] { |
| 70 | b"authority" => { |
| 71 | let value = BytesStr::try_from(value)?; |
| 72 | Ok(Header::Authority(value)) |
| 73 | } |
| 74 | b"method" => { |
| 75 | let method = Method::from_bytes(&value)?; |
| 76 | Ok(Header::Method(method)) |
| 77 | } |
| 78 | b"scheme" => { |
| 79 | let value = BytesStr::try_from(value)?; |
| 80 | Ok(Header::Scheme(value)) |
| 81 | } |
| 82 | b"path" => { |
| 83 | let value = BytesStr::try_from(value)?; |
| 84 | Ok(Header::Path(value)) |
| 85 | } |
| 86 | b"protocol" => { |
| 87 | let value = Protocol::try_from(value)?; |
| 88 | Ok(Header::Protocol(value)) |
| 89 | } |
| 90 | b"status" => { |
| 91 | let status = StatusCode::from_bytes(&value)?; |
| 92 | Ok(Header::Status(status)) |
| 93 | } |
| 94 | _ => Err(DecoderError::InvalidPseudoheader), |
| 95 | } |
| 96 | } else { |
| 97 | // HTTP/2 requires lower case header names |
| 98 | let name = HeaderName::from_lowercase(&name)?; |
| 99 | let value = HeaderValue::from_bytes(&value)?; |
| 100 | |
| 101 | Ok(Header::Field { name, value }) |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | pub fn len(&self) -> usize { |
| 106 | match *self { |
| 107 | Header::Field { |
| 108 | ref name, |
| 109 | ref value, |
| 110 | } => len(name, value), |
| 111 | Header::Authority(ref v) => 32 + 10 + v.len(), |
| 112 | Header::Method(ref v) => 32 + 7 + v.as_ref().len(), |
| 113 | Header::Scheme(ref v) => 32 + 7 + v.len(), |
| 114 | Header::Path(ref v) => 32 + 5 + v.len(), |
| 115 | Header::Protocol(ref v) => 32 + 9 + v.as_str().len(), |
| 116 | Header::Status(_) => 32 + 7 + 3, |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | /// Returns the header name |
| 121 | pub fn name(&self) -> Name { |
| 122 | match *self { |
| 123 | Header::Field { ref name, .. } => Name::Field(name), |
| 124 | Header::Authority(..) => Name::Authority, |
| 125 | Header::Method(..) => Name::Method, |
| 126 | Header::Scheme(..) => Name::Scheme, |
| 127 | Header::Path(..) => Name::Path, |
| 128 | Header::Protocol(..) => Name::Protocol, |
| 129 | Header::Status(..) => Name::Status, |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | pub fn value_slice(&self) -> &[u8] { |
| 134 | match *self { |
| 135 | Header::Field { ref value, .. } => value.as_ref(), |
| 136 | Header::Authority(ref v) => v.as_ref(), |
| 137 | Header::Method(ref v) => v.as_ref().as_ref(), |
| 138 | Header::Scheme(ref v) => v.as_ref(), |
| 139 | Header::Path(ref v) => v.as_ref(), |
| 140 | Header::Protocol(ref v) => v.as_ref(), |
| 141 | Header::Status(ref v) => v.as_str().as_ref(), |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | pub fn value_eq(&self, other: &Header) -> bool { |
| 146 | match *self { |
| 147 | Header::Field { ref value, .. } => { |
| 148 | let a = value; |
| 149 | match *other { |
| 150 | Header::Field { ref value, .. } => a == value, |
| 151 | _ => false, |
| 152 | } |
| 153 | } |
| 154 | Header::Authority(ref a) => match *other { |
| 155 | Header::Authority(ref b) => a == b, |
| 156 | _ => false, |
| 157 | }, |
| 158 | Header::Method(ref a) => match *other { |
| 159 | Header::Method(ref b) => a == b, |
| 160 | _ => false, |
| 161 | }, |
| 162 | Header::Scheme(ref a) => match *other { |
| 163 | Header::Scheme(ref b) => a == b, |
| 164 | _ => false, |
| 165 | }, |
| 166 | Header::Path(ref a) => match *other { |
| 167 | Header::Path(ref b) => a == b, |
| 168 | _ => false, |
| 169 | }, |
| 170 | Header::Protocol(ref a) => match *other { |
| 171 | Header::Protocol(ref b) => a == b, |
| 172 | _ => false, |
| 173 | }, |
| 174 | Header::Status(ref a) => match *other { |
| 175 | Header::Status(ref b) => a == b, |
| 176 | _ => false, |
| 177 | }, |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | pub fn is_sensitive(&self) -> bool { |
| 182 | match *self { |
| 183 | Header::Field { ref value, .. } => value.is_sensitive(), |
| 184 | // TODO: Technically these other header values can be sensitive too. |
| 185 | _ => false, |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | pub fn skip_value_index(&self) -> bool { |
| 190 | use http::header; |
| 191 | |
| 192 | match *self { |
| 193 | Header::Field { ref name, .. } => matches!( |
| 194 | *name, |
| 195 | header::AGE |
| 196 | | header::AUTHORIZATION |
| 197 | | header::CONTENT_LENGTH |
| 198 | | header::ETAG |
| 199 | | header::IF_MODIFIED_SINCE |
| 200 | | header::IF_NONE_MATCH |
| 201 | | header::LOCATION |
| 202 | | header::COOKIE |
| 203 | | header::SET_COOKIE |
| 204 | ), |
| 205 | Header::Path(..) => true, |
| 206 | _ => false, |
| 207 | } |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | // Mostly for tests |
| 212 | impl From<Header> for Header<Option<HeaderName>> { |
| 213 | fn from(src: Header) -> Self { |
| 214 | match src { |
| 215 | Header::Field { name: HeaderName, value: HeaderValue } => Header::Field { |
| 216 | name: Some(name), |
| 217 | value, |
| 218 | }, |
| 219 | Header::Authority(v: BytesStr) => Header::Authority(v), |
| 220 | Header::Method(v: Method) => Header::Method(v), |
| 221 | Header::Scheme(v: BytesStr) => Header::Scheme(v), |
| 222 | Header::Path(v: BytesStr) => Header::Path(v), |
| 223 | Header::Protocol(v: Protocol) => Header::Protocol(v), |
| 224 | Header::Status(v: StatusCode) => Header::Status(v), |
| 225 | } |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | impl<'a> Name<'a> { |
| 230 | pub fn into_entry(self, value: Bytes) -> Result<Header, DecoderError> { |
| 231 | match self { |
| 232 | Name::Field(name) => Ok(Header::Field { |
| 233 | name: name.clone(), |
| 234 | value: HeaderValue::from_bytes(&value)?, |
| 235 | }), |
| 236 | Name::Authority => Ok(Header::Authority(BytesStr::try_from(value)?)), |
| 237 | Name::Method => Ok(Header::Method(Method::from_bytes(&value)?)), |
| 238 | Name::Scheme => Ok(Header::Scheme(BytesStr::try_from(value)?)), |
| 239 | Name::Path => Ok(Header::Path(BytesStr::try_from(value)?)), |
| 240 | Name::Protocol => Ok(Header::Protocol(Protocol::try_from(value)?)), |
| 241 | Name::Status => { |
| 242 | match StatusCode::from_bytes(&value) { |
| 243 | Ok(status) => Ok(Header::Status(status)), |
| 244 | // TODO: better error handling |
| 245 | Err(_) => Err(DecoderError::InvalidStatusCode), |
| 246 | } |
| 247 | } |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | pub fn as_slice(&self) -> &[u8] { |
| 252 | match *self { |
| 253 | Name::Field(ref name) => name.as_ref(), |
| 254 | Name::Authority => b":authority" , |
| 255 | Name::Method => b":method" , |
| 256 | Name::Scheme => b":scheme" , |
| 257 | Name::Path => b":path" , |
| 258 | Name::Protocol => b":protocol" , |
| 259 | Name::Status => b":status" , |
| 260 | } |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | // ===== impl BytesStr ===== |
| 265 | |
| 266 | impl BytesStr { |
| 267 | pub(crate) const fn from_static(value: &'static str) -> Self { |
| 268 | BytesStr(Bytes::from_static(value.as_bytes())) |
| 269 | } |
| 270 | |
| 271 | pub(crate) fn from(value: &str) -> Self { |
| 272 | BytesStr(Bytes::copy_from_slice(data:value.as_bytes())) |
| 273 | } |
| 274 | |
| 275 | #[doc (hidden)] |
| 276 | pub fn try_from(bytes: Bytes) -> Result<Self, std::str::Utf8Error> { |
| 277 | std::str::from_utf8(bytes.as_ref())?; |
| 278 | Ok(BytesStr(bytes)) |
| 279 | } |
| 280 | |
| 281 | pub(crate) fn as_str(&self) -> &str { |
| 282 | // Safety: check valid utf-8 in constructor |
| 283 | unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) } |
| 284 | } |
| 285 | |
| 286 | pub(crate) fn into_inner(self) -> Bytes { |
| 287 | self.0 |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | impl std::ops::Deref for BytesStr { |
| 292 | type Target = str; |
| 293 | fn deref(&self) -> &str { |
| 294 | self.as_str() |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | impl AsRef<[u8]> for BytesStr { |
| 299 | fn as_ref(&self) -> &[u8] { |
| 300 | self.0.as_ref() |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | impl fmt::Debug for BytesStr { |
| 305 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 306 | self.0.fmt(f) |
| 307 | } |
| 308 | } |
| 309 | |