1use std::convert::TryFrom;
5use std::{fmt, str::FromStr};
6
7use bytes::{Bytes, BytesMut};
8use http::Error as HttpError;
9use mime::Mime;
10use percent_encoding::{AsciiSet, CONTROLS};
11
12pub use http::header::*;
13
14use crate::error::ParseError;
15use crate::httpmessage::HttpMessage;
16
17mod common;
18pub(crate) mod map;
19mod shared;
20pub use self::common::*;
21#[doc(hidden)]
22pub use self::shared::*;
23
24#[doc(hidden)]
25pub use self::map::GetAll;
26pub use self::map::HeaderMap;
27
28pub trait Header
30where
31 Self: IntoHeaderValue,
32{
33 fn name() -> HeaderName;
35
36 fn parse<T: HttpMessage>(msg: &T) -> Result<Self, ParseError>;
38}
39
40pub trait IntoHeaderValue: Sized {
42 type Error: Into<HttpError>;
44
45 fn try_into(self) -> Result<HeaderValue, Self::Error>;
47}
48
49impl IntoHeaderValue for HeaderValue {
50 type Error = InvalidHeaderValue;
51
52 #[inline]
53 fn try_into(self) -> Result<HeaderValue, Self::Error> {
54 Ok(self)
55 }
56}
57
58impl<'a> IntoHeaderValue for &'a str {
59 type Error = InvalidHeaderValue;
60
61 #[inline]
62 fn try_into(self) -> Result<HeaderValue, Self::Error> {
63 self.parse()
64 }
65}
66
67impl<'a> IntoHeaderValue for &'a [u8] {
68 type Error = InvalidHeaderValue;
69
70 #[inline]
71 fn try_into(self) -> Result<HeaderValue, Self::Error> {
72 HeaderValue::from_bytes(self)
73 }
74}
75
76impl IntoHeaderValue for Bytes {
77 type Error = InvalidHeaderValue;
78
79 #[inline]
80 fn try_into(self) -> Result<HeaderValue, Self::Error> {
81 HeaderValue::from_maybe_shared(self)
82 }
83}
84
85impl IntoHeaderValue for Vec<u8> {
86 type Error = InvalidHeaderValue;
87
88 #[inline]
89 fn try_into(self) -> Result<HeaderValue, Self::Error> {
90 HeaderValue::try_from(self)
91 }
92}
93
94impl IntoHeaderValue for String {
95 type Error = InvalidHeaderValue;
96
97 #[inline]
98 fn try_into(self) -> Result<HeaderValue, Self::Error> {
99 HeaderValue::try_from(self)
100 }
101}
102
103impl IntoHeaderValue for usize {
104 type Error = InvalidHeaderValue;
105
106 #[inline]
107 fn try_into(self) -> Result<HeaderValue, Self::Error> {
108 let s = format!("{}", self);
109 HeaderValue::try_from(s)
110 }
111}
112
113impl IntoHeaderValue for u64 {
114 type Error = InvalidHeaderValue;
115
116 #[inline]
117 fn try_into(self) -> Result<HeaderValue, Self::Error> {
118 let s = format!("{}", self);
119 HeaderValue::try_from(s)
120 }
121}
122
123impl IntoHeaderValue for Mime {
124 type Error = InvalidHeaderValue;
125
126 #[inline]
127 fn try_into(self) -> Result<HeaderValue, Self::Error> {
128 HeaderValue::try_from(format!("{}", self))
129 }
130}
131
132#[derive(Copy, Clone, PartialEq, Debug)]
134pub enum ContentEncoding {
135 Auto,
137 Br,
139 Deflate,
141 Gzip,
143 Identity,
145}
146
147impl ContentEncoding {
148 #[inline]
149 pub fn is_compression(self) -> bool {
151 match self {
152 ContentEncoding::Identity | ContentEncoding::Auto => false,
153 _ => true,
154 }
155 }
156
157 #[inline]
158 pub fn as_str(self) -> &'static str {
160 match self {
161 ContentEncoding::Br => "br",
162 ContentEncoding::Gzip => "gzip",
163 ContentEncoding::Deflate => "deflate",
164 ContentEncoding::Identity | ContentEncoding::Auto => "identity",
165 }
166 }
167
168 #[inline]
169 pub fn quality(self) -> f64 {
171 match self {
172 ContentEncoding::Br => 1.1,
173 ContentEncoding::Gzip => 1.0,
174 ContentEncoding::Deflate => 0.9,
175 ContentEncoding::Identity | ContentEncoding::Auto => 0.1,
176 }
177 }
178}
179
180impl<'a> From<&'a str> for ContentEncoding {
181 fn from(s: &'a str) -> ContentEncoding {
182 let s = s.trim();
183
184 if s.eq_ignore_ascii_case("br") {
185 ContentEncoding::Br
186 } else if s.eq_ignore_ascii_case("gzip") {
187 ContentEncoding::Gzip
188 } else if s.eq_ignore_ascii_case("deflate") {
189 ContentEncoding::Deflate
190 } else {
191 ContentEncoding::Identity
192 }
193 }
194}
195
196#[doc(hidden)]
197pub(crate) struct Writer {
198 buf: BytesMut,
199}
200
201impl Writer {
202 fn new() -> Writer {
203 Writer {
204 buf: BytesMut::new(),
205 }
206 }
207 fn take(&mut self) -> Bytes {
208 self.buf.split().freeze()
209 }
210}
211
212impl fmt::Write for Writer {
213 #[inline]
214 fn write_str(&mut self, s: &str) -> fmt::Result {
215 self.buf.extend_from_slice(s.as_bytes());
216 Ok(())
217 }
218
219 #[inline]
220 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
221 fmt::write(self, args)
222 }
223}
224
225#[inline]
226#[doc(hidden)]
227pub fn from_comma_delimited<'a, I: Iterator<Item = &'a HeaderValue> + 'a, T: FromStr>(
229 all: I,
230) -> Result<Vec<T>, ParseError> {
231 let mut result = Vec::new();
232 for h in all {
233 let s = h.to_str().map_err(|_| ParseError::Header)?;
234 result.extend(
235 s.split(',')
236 .filter_map(|x| match x.trim() {
237 "" => None,
238 y => Some(y),
239 })
240 .filter_map(|x| x.trim().parse().ok()),
241 )
242 }
243 Ok(result)
244}
245
246#[inline]
247#[doc(hidden)]
248pub fn from_one_raw_str<T: FromStr>(val: Option<&HeaderValue>) -> Result<T, ParseError> {
250 if let Some(line) = val {
251 let line = line.to_str().map_err(|_| ParseError::Header)?;
252 if !line.is_empty() {
253 return T::from_str(line).or(Err(ParseError::Header));
254 }
255 }
256 Err(ParseError::Header)
257}
258
259#[inline]
260#[doc(hidden)]
261pub fn fmt_comma_delimited<T>(f: &mut fmt::Formatter<'_>, parts: &[T]) -> fmt::Result
263where
264 T: fmt::Display,
265{
266 let mut iter = parts.iter();
267 if let Some(part) = iter.next() {
268 fmt::Display::fmt(part, f)?;
269 }
270 for part in iter {
271 f.write_str(", ")?;
272 fmt::Display::fmt(part, f)?;
273 }
274 Ok(())
275}
276
277#[derive(Clone, Debug, PartialEq)]
284pub struct ExtendedValue {
285 pub charset: Charset,
287 pub language_tag: Option<LanguageTag>,
289 pub value: Vec<u8>,
291}
292
293pub fn parse_extended_value(
329 val: &str,
330) -> Result<ExtendedValue, crate::error::ParseError> {
331 let mut parts = val.splitn(3, '\'');
333
334 let charset: Charset = match parts.next() {
336 None => return Err(crate::error::ParseError::Header),
337 Some(n) => FromStr::from_str(n).map_err(|_| crate::error::ParseError::Header)?,
338 };
339
340 let language_tag: Option<LanguageTag> = match parts.next() {
342 None => return Err(crate::error::ParseError::Header),
343 Some("") => None,
344 Some(s) => match s.parse() {
345 Ok(lt) => Some(lt),
346 Err(_) => return Err(crate::error::ParseError::Header),
347 },
348 };
349
350 let value: Vec<u8> = match parts.next() {
352 None => return Err(crate::error::ParseError::Header),
353 Some(v) => percent_encoding::percent_decode(v.as_bytes()).collect(),
354 };
355
356 Ok(ExtendedValue {
357 value,
358 charset,
359 language_tag,
360 })
361}
362
363impl fmt::Display for ExtendedValue {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 let encoded_value =
366 percent_encoding::percent_encode(&self.value[..], HTTP_VALUE);
367 if let Some(ref lang) = self.language_tag {
368 write!(f, "{}'{}'{}", self.charset, lang, encoded_value)
369 } else {
370 write!(f, "{}''{}", self.charset, encoded_value)
371 }
372 }
373}
374
375pub fn http_percent_encode(f: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result {
380 let encoded = percent_encoding::percent_encode(bytes, HTTP_VALUE);
381 fmt::Display::fmt(&encoded, f)
382}
383
384impl From<http::HeaderMap> for HeaderMap {
386 fn from(map: http::HeaderMap) -> HeaderMap {
387 let mut new_map = HeaderMap::with_capacity(map.capacity());
388 for (h, v) in map.iter() {
389 new_map.append(h.clone(), v.clone());
390 }
391 new_map
392 }
393}
394
395pub(crate) const HTTP_VALUE: &AsciiSet = &CONTROLS
398 .add(b' ')
399 .add(b'"')
400 .add(b'%')
401 .add(b'\'')
402 .add(b'(')
403 .add(b')')
404 .add(b'*')
405 .add(b',')
406 .add(b'/')
407 .add(b':')
408 .add(b';')
409 .add(b'<')
410 .add(b'-')
411 .add(b'>')
412 .add(b'?')
413 .add(b'[')
414 .add(b'\\')
415 .add(b']')
416 .add(b'{')
417 .add(b'}');
418
419#[cfg(test)]
420mod tests {
421 use super::shared::Charset;
422 use super::{parse_extended_value, ExtendedValue};
423 use language_tags::LanguageTag;
424
425 #[test]
426 fn test_parse_extended_value_with_encoding_and_language_tag() {
427 let expected_language_tag = "en".parse::<LanguageTag>().unwrap();
428 let result = parse_extended_value("iso-8859-1'en'%A3%20rates");
431 assert!(result.is_ok());
432 let extended_value = result.unwrap();
433 assert_eq!(Charset::Iso_8859_1, extended_value.charset);
434 assert!(extended_value.language_tag.is_some());
435 assert_eq!(expected_language_tag, extended_value.language_tag.unwrap());
436 assert_eq!(
437 vec![163, b' ', b'r', b'a', b't', b'e', b's'],
438 extended_value.value
439 );
440 }
441
442 #[test]
443 fn test_parse_extended_value_with_encoding() {
444 let result = parse_extended_value("UTF-8''%c2%a3%20and%20%e2%82%ac%20rates");
448 assert!(result.is_ok());
449 let extended_value = result.unwrap();
450 assert_eq!(Charset::Ext("UTF-8".to_string()), extended_value.charset);
451 assert!(extended_value.language_tag.is_none());
452 assert_eq!(
453 vec![
454 194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a',
455 b't', b'e', b's',
456 ],
457 extended_value.value
458 );
459 }
460
461 #[test]
462 fn test_parse_extended_value_missing_language_tag_and_encoding() {
463 let result = parse_extended_value("foo%20bar.html");
465 assert!(result.is_err());
466 }
467
468 #[test]
469 fn test_parse_extended_value_partially_formatted() {
470 let result = parse_extended_value("UTF-8'missing third part");
471 assert!(result.is_err());
472 }
473
474 #[test]
475 fn test_parse_extended_value_partially_formatted_blank() {
476 let result = parse_extended_value("blank second part'");
477 assert!(result.is_err());
478 }
479
480 #[test]
481 fn test_fmt_extended_value_with_encoding_and_language_tag() {
482 let extended_value = ExtendedValue {
483 charset: Charset::Iso_8859_1,
484 language_tag: Some("en".parse().expect("Could not parse language tag")),
485 value: vec![163, b' ', b'r', b'a', b't', b'e', b's'],
486 };
487 assert_eq!("ISO-8859-1'en'%A3%20rates", format!("{}", extended_value));
488 }
489
490 #[test]
491 fn test_fmt_extended_value_with_encoding() {
492 let extended_value = ExtendedValue {
493 charset: Charset::Ext("UTF-8".to_string()),
494 language_tag: None,
495 value: vec![
496 194, 163, b' ', b'a', b'n', b'd', b' ', 226, 130, 172, b' ', b'r', b'a',
497 b't', b'e', b's',
498 ],
499 };
500 assert_eq!(
501 "UTF-8''%C2%A3%20and%20%E2%82%AC%20rates",
502 format!("{}", extended_value)
503 );
504 }
505}