Skip to content

Commit 7bf4ab6

Browse files
authored
Merge pull request #247 from http-rs/no-directives
Remove directives
2 parents 9b533a3 + be88520 commit 7bf4ab6

File tree

9 files changed

+288
-323
lines changed

9 files changed

+288
-323
lines changed

src/conditional/etag.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, ETAG};
22
use crate::{Error, StatusCode};
33

4-
use std::fmt::Debug;
4+
use std::fmt::{self, Debug, Display};
55
use std::option;
66

77
/// HTTP Entity Tags.
@@ -79,10 +79,7 @@ impl ETag {
7979

8080
/// Get the `HeaderValue`.
8181
pub fn value(&self) -> HeaderValue {
82-
let s = match self {
83-
Self::Strong(s) => format!(r#""{}""#, s),
84-
Self::Weak(s) => format!(r#"W/"{}""#, s),
85-
};
82+
let s = self.to_string();
8683
// SAFETY: the internal string is validated to be ASCII.
8784
unsafe { HeaderValue::from_bytes_unchecked(s.into()) }
8885
}
@@ -133,6 +130,15 @@ impl ETag {
133130
}
134131
}
135132

133+
impl Display for ETag {
134+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135+
match self {
136+
Self::Strong(s) => write!(f, r#""{}""#, s),
137+
Self::Weak(s) => write!(f, r#"W/"{}""#, s),
138+
}
139+
}
140+
}
141+
136142
impl ToHeaderValues for ETag {
137143
type Iter = option::IntoIter<HeaderValue>;
138144
fn to_header_values(&self) -> crate::Result<Self::Iter> {

src/conditional/if_match.rs

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Apply the HTTP method if the ETag matches.
22
3-
use crate::conditional::MatchDirective;
3+
use crate::conditional::ETag;
44
use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, IF_MATCH};
55

66
use std::fmt::{self, Debug, Write};
@@ -31,19 +31,23 @@ use std::slice;
3131
///
3232
/// let entries = IfMatch::from_headers(res)?.unwrap();
3333
/// let mut entries = entries.iter();
34-
/// assert_eq!(entries.next().unwrap(), ETag::new("0xcafebeef".to_string()));
35-
/// assert_eq!(entries.next().unwrap(), ETag::new("0xbeefcafe".to_string()));
34+
/// assert_eq!(entries.next().unwrap(), &ETag::new("0xcafebeef".to_string()));
35+
/// assert_eq!(entries.next().unwrap(), &ETag::new("0xbeefcafe".to_string()));
3636
/// #
3737
/// # Ok(()) }
3838
/// ```
3939
pub struct IfMatch {
40-
entries: Vec<MatchDirective>,
40+
entries: Vec<ETag>,
41+
wildcard: bool,
4142
}
4243

4344
impl IfMatch {
4445
/// Create a new instance of `IfMatch`.
4546
pub fn new() -> Self {
46-
Self { entries: vec![] }
47+
Self {
48+
entries: vec![],
49+
wildcard: false,
50+
}
4751
}
4852

4953
/// Create a new instance from headers.
@@ -54,17 +58,19 @@ impl IfMatch {
5458
None => return Ok(None),
5559
};
5660

61+
let mut wildcard = false;
5762
for value in headers {
5863
for part in value.as_str().trim().split(',') {
59-
// Try and parse a directive from a str. If the directive is
60-
// unkown we skip it.
61-
if let Some(entry) = MatchDirective::from_str(part)? {
62-
entries.push(entry);
64+
let part = part.trim();
65+
if part == "*" {
66+
wildcard = true;
67+
continue;
6368
}
69+
entries.push(ETag::from_str(part)?);
6470
}
6571
}
6672

67-
Ok(Some(Self { entries }))
73+
Ok(Some(Self { entries, wildcard }))
6874
}
6975

7076
/// Sets the `If-Match` header.
@@ -80,11 +86,17 @@ impl IfMatch {
8086
/// Get the `HeaderValue`.
8187
pub fn value(&self) -> HeaderValue {
8288
let mut output = String::new();
83-
for (n, directive) in self.entries.iter().enumerate() {
84-
let directive: HeaderValue = directive.clone().into();
89+
for (n, etag) in self.entries.iter().enumerate() {
8590
match n {
86-
0 => write!(output, "{}", directive).unwrap(),
87-
_ => write!(output, ", {}", directive).unwrap(),
91+
0 => write!(output, "{}", etag.to_string()).unwrap(),
92+
_ => write!(output, ", {}", etag.to_string()).unwrap(),
93+
};
94+
}
95+
96+
if self.wildcard {
97+
match output.len() {
98+
0 => write!(output, "*").unwrap(),
99+
_ => write!(output, ", *").unwrap(),
88100
};
89101
}
90102

@@ -93,10 +105,20 @@ impl IfMatch {
93105
}
94106

95107
/// Push a directive into the list of entries.
96-
pub fn push(&mut self, directive: impl Into<MatchDirective>) {
108+
pub fn push(&mut self, directive: impl Into<ETag>) {
97109
self.entries.push(directive.into());
98110
}
99111

112+
/// Returns `true` if a wildcard directive was set.
113+
pub fn wildcard(&self) -> bool {
114+
self.wildcard
115+
}
116+
117+
/// Set the wildcard directive.
118+
pub fn set_wildcard(&mut self, wildcard: bool) {
119+
self.wildcard = wildcard
120+
}
121+
100122
/// An iterator visiting all server entries.
101123
pub fn iter(&self) -> Iter<'_> {
102124
Iter {
@@ -113,7 +135,7 @@ impl IfMatch {
113135
}
114136

115137
impl IntoIterator for IfMatch {
116-
type Item = MatchDirective;
138+
type Item = ETag;
117139
type IntoIter = IntoIter;
118140

119141
#[inline]
@@ -125,7 +147,7 @@ impl IntoIterator for IfMatch {
125147
}
126148

127149
impl<'a> IntoIterator for &'a IfMatch {
128-
type Item = &'a MatchDirective;
150+
type Item = &'a ETag;
129151
type IntoIter = Iter<'a>;
130152

131153
#[inline]
@@ -135,7 +157,7 @@ impl<'a> IntoIterator for &'a IfMatch {
135157
}
136158

137159
impl<'a> IntoIterator for &'a mut IfMatch {
138-
type Item = &'a mut MatchDirective;
160+
type Item = &'a mut ETag;
139161
type IntoIter = IterMut<'a>;
140162

141163
#[inline]
@@ -147,11 +169,11 @@ impl<'a> IntoIterator for &'a mut IfMatch {
147169
/// A borrowing iterator over entries in `IfMatch`.
148170
#[derive(Debug)]
149171
pub struct IntoIter {
150-
inner: std::vec::IntoIter<MatchDirective>,
172+
inner: std::vec::IntoIter<ETag>,
151173
}
152174

153175
impl Iterator for IntoIter {
154-
type Item = MatchDirective;
176+
type Item = ETag;
155177

156178
fn next(&mut self) -> Option<Self::Item> {
157179
self.inner.next()
@@ -166,11 +188,11 @@ impl Iterator for IntoIter {
166188
/// A lending iterator over entries in `IfMatch`.
167189
#[derive(Debug)]
168190
pub struct Iter<'a> {
169-
inner: slice::Iter<'a, MatchDirective>,
191+
inner: slice::Iter<'a, ETag>,
170192
}
171193

172194
impl<'a> Iterator for Iter<'a> {
173-
type Item = &'a MatchDirective;
195+
type Item = &'a ETag;
174196

175197
fn next(&mut self) -> Option<Self::Item> {
176198
self.inner.next()
@@ -185,11 +207,11 @@ impl<'a> Iterator for Iter<'a> {
185207
/// A mutable iterator over entries in `IfMatch`.
186208
#[derive(Debug)]
187209
pub struct IterMut<'a> {
188-
inner: slice::IterMut<'a, MatchDirective>,
210+
inner: slice::IterMut<'a, ETag>,
189211
}
190212

191213
impl<'a> Iterator for IterMut<'a> {
192-
type Item = &'a mut MatchDirective;
214+
type Item = &'a mut ETag;
193215

194216
fn next(&mut self) -> Option<Self::Item> {
195217
self.inner.next()
@@ -235,8 +257,33 @@ mod test {
235257

236258
let entries = IfMatch::from_headers(res)?.unwrap();
237259
let mut entries = entries.iter();
238-
assert_eq!(entries.next().unwrap(), ETag::new("0xcafebeef".to_string()));
239-
assert_eq!(entries.next().unwrap(), ETag::new("0xbeefcafe".to_string()));
260+
assert_eq!(
261+
entries.next().unwrap(),
262+
&ETag::new("0xcafebeef".to_string())
263+
);
264+
assert_eq!(
265+
entries.next().unwrap(),
266+
&ETag::new("0xbeefcafe".to_string())
267+
);
268+
Ok(())
269+
}
270+
271+
#[test]
272+
fn wildcard() -> crate::Result<()> {
273+
let mut entries = IfMatch::new();
274+
entries.push(ETag::new("0xcafebeef".to_string()));
275+
entries.set_wildcard(true);
276+
277+
let mut res = Response::new(200);
278+
entries.apply(&mut res);
279+
280+
let entries = IfMatch::from_headers(res)?.unwrap();
281+
assert_eq!(entries.wildcard(), true);
282+
let mut entries = entries.iter();
283+
assert_eq!(
284+
entries.next().unwrap(),
285+
&ETag::new("0xcafebeef".to_string())
286+
);
240287
Ok(())
241288
}
242289
}

0 commit comments

Comments
 (0)