Skip to content

Commit 975ad8f

Browse files
authored
Merge pull request #266 from http-rs/expect
Add `other::Expect` header
2 parents 4599842 + 52961f7 commit 975ad8f

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

src/other/expect.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use crate::ensure_eq_status;
2+
use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, EXPECT};
3+
4+
use std::fmt::Debug;
5+
use std::option;
6+
7+
/// HTTP `Expect` header
8+
///
9+
/// [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect)
10+
///
11+
/// # Specifications
12+
///
13+
/// - [RFC 7231, section 5.1.1: Expect](https://tools.ietf.org/html/rfc7231#section-5.1.1)
14+
///
15+
/// # Examples
16+
///
17+
/// ```
18+
/// # fn main() -> http_types::Result<()> {
19+
/// #
20+
/// use http_types::Response;
21+
/// use http_types::other::Expect;
22+
///
23+
/// let expect = Expect::new();
24+
///
25+
/// let mut res = Response::new(200);
26+
/// expect.apply(&mut res);
27+
///
28+
/// let expect = Expect::from_headers(res)?.unwrap();
29+
/// assert_eq!(expect, Expect::new());
30+
/// #
31+
/// # Ok(()) }
32+
/// ```
33+
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
34+
pub struct Expect {
35+
_priv: (),
36+
}
37+
38+
impl Expect {
39+
/// Create a new instance of `Expect`.
40+
pub fn new() -> Self {
41+
Self { _priv: () }
42+
}
43+
44+
/// Create an instance of `Expect` from a `Headers` instance.
45+
pub fn from_headers(headers: impl AsRef<Headers>) -> crate::Result<Option<Self>> {
46+
let headers = match headers.as_ref().get(EXPECT) {
47+
Some(headers) => headers,
48+
None => return Ok(None),
49+
};
50+
51+
// If we successfully parsed the header then there's always at least one
52+
// entry. We want the last entry.
53+
let header = headers.iter().last().unwrap();
54+
ensure_eq_status!(header, "100-continue", 400, "malformed `Expect` header");
55+
56+
Ok(Some(Self { _priv: () }))
57+
}
58+
59+
/// Insert a `HeaderName` + `HeaderValue` pair into a `Headers` instance.
60+
pub fn apply(&self, mut headers: impl AsMut<Headers>) {
61+
headers.as_mut().insert(EXPECT, self.value());
62+
}
63+
64+
/// Get the `HeaderName`.
65+
pub fn name(&self) -> HeaderName {
66+
EXPECT
67+
}
68+
69+
/// Get the `HeaderValue`.
70+
pub fn value(&self) -> HeaderValue {
71+
let value = "100-continue";
72+
// SAFETY: the internal string is validated to be ASCII.
73+
unsafe { HeaderValue::from_bytes_unchecked(value.into()) }
74+
}
75+
}
76+
77+
impl ToHeaderValues for Expect {
78+
type Iter = option::IntoIter<HeaderValue>;
79+
fn to_header_values(&self) -> crate::Result<Self::Iter> {
80+
// A HeaderValue will always convert into itself.
81+
Ok(self.value().to_header_values().unwrap())
82+
}
83+
}
84+
85+
#[cfg(test)]
86+
mod test {
87+
use super::*;
88+
use crate::headers::Headers;
89+
90+
#[test]
91+
fn smoke() -> crate::Result<()> {
92+
let expect = Expect::new();
93+
94+
let mut headers = Headers::new();
95+
expect.apply(&mut headers);
96+
97+
let expect = Expect::from_headers(headers)?.unwrap();
98+
assert_eq!(expect, Expect::new());
99+
Ok(())
100+
}
101+
102+
#[test]
103+
fn bad_request_on_parse_error() -> crate::Result<()> {
104+
let mut headers = Headers::new();
105+
headers.insert(EXPECT, "<nori ate the tag. yum.>");
106+
let err = Expect::from_headers(headers).unwrap_err();
107+
assert_eq!(err.status(), 400);
108+
Ok(())
109+
}
110+
}

src/other/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Miscellaneous HTTP headers.
22
33
mod date;
4+
mod expect;
45

56
pub use date::Date;
7+
pub use expect::Expect;

0 commit comments

Comments
 (0)