1
1
//! Apply the HTTP method if the ETag matches.
2
2
3
- use crate :: conditional:: MatchDirective ;
3
+ use crate :: conditional:: ETag ;
4
4
use crate :: headers:: { HeaderName , HeaderValue , Headers , ToHeaderValues , IF_MATCH } ;
5
5
6
6
use std:: fmt:: { self , Debug , Write } ;
@@ -31,19 +31,20 @@ use std::slice;
31
31
///
32
32
/// let entries = IfMatch::from_headers(res)?.unwrap();
33
33
/// 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()));
36
36
/// #
37
37
/// # Ok(()) }
38
38
/// ```
39
39
pub struct IfMatch {
40
- entries : Vec < MatchDirective > ,
40
+ entries : Vec < ETag > ,
41
+ wildcard : bool ,
41
42
}
42
43
43
44
impl IfMatch {
44
45
/// Create a new instance of `IfMatch`.
45
46
pub fn new ( ) -> Self {
46
- Self { entries : vec ! [ ] }
47
+ Self { entries : vec ! [ ] , wildcard : false }
47
48
}
48
49
49
50
/// Create a new instance from headers.
@@ -54,17 +55,20 @@ impl IfMatch {
54
55
None => return Ok ( None ) ,
55
56
} ;
56
57
58
+ let mut wildcard = false ;
57
59
for value in headers {
58
60
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 ) ;
61
+ let part = part . trim ( ) ;
62
+ if part == "*" {
63
+ wildcard = true ;
64
+ continue ;
63
65
}
66
+ entries. push ( ETag :: from_str ( part) ?) ;
64
67
}
65
68
}
66
69
67
- Ok ( Some ( Self { entries } ) )
70
+ Ok ( Some ( Self { entries, wildcard } ) )
71
+
68
72
}
69
73
70
74
/// Sets the `If-Match` header.
@@ -80,11 +84,17 @@ impl IfMatch {
80
84
/// Get the `HeaderValue`.
81
85
pub fn value ( & self ) -> HeaderValue {
82
86
let mut output = String :: new ( ) ;
83
- for ( n, directive) in self . entries . iter ( ) . enumerate ( ) {
84
- let directive: HeaderValue = directive. clone ( ) . into ( ) ;
87
+ for ( n, etag) in self . entries . iter ( ) . enumerate ( ) {
85
88
match n {
86
- 0 => write ! ( output, "{}" , directive) . unwrap ( ) ,
87
- _ => write ! ( output, ", {}" , directive) . unwrap ( ) ,
89
+ 0 => write ! ( output, "{}" , etag. to_string( ) ) . unwrap ( ) ,
90
+ _ => write ! ( output, ", {}" , etag. to_string( ) ) . unwrap ( ) ,
91
+ } ;
92
+ }
93
+
94
+ if self . wildcard {
95
+ match output. len ( ) {
96
+ 0 => write ! ( output, "*" ) . unwrap ( ) ,
97
+ _ => write ! ( output, ", *" ) . unwrap ( ) ,
88
98
} ;
89
99
}
90
100
@@ -93,10 +103,20 @@ impl IfMatch {
93
103
}
94
104
95
105
/// Push a directive into the list of entries.
96
- pub fn push ( & mut self , directive : impl Into < MatchDirective > ) {
106
+ pub fn push ( & mut self , directive : impl Into < ETag > ) {
97
107
self . entries . push ( directive. into ( ) ) ;
98
108
}
99
109
110
+ /// Returns `true` if a wildcard directive was set.
111
+ pub fn wildcard ( & self ) -> bool {
112
+ self . wildcard
113
+ }
114
+
115
+ /// Set the wildcard directive.
116
+ pub fn set_wildcard ( & mut self , wildcard : bool ) {
117
+ self . wildcard = wildcard
118
+ }
119
+
100
120
/// An iterator visiting all server entries.
101
121
pub fn iter ( & self ) -> Iter < ' _ > {
102
122
Iter {
@@ -113,7 +133,7 @@ impl IfMatch {
113
133
}
114
134
115
135
impl IntoIterator for IfMatch {
116
- type Item = MatchDirective ;
136
+ type Item = ETag ;
117
137
type IntoIter = IntoIter ;
118
138
119
139
#[ inline]
@@ -125,7 +145,7 @@ impl IntoIterator for IfMatch {
125
145
}
126
146
127
147
impl < ' a > IntoIterator for & ' a IfMatch {
128
- type Item = & ' a MatchDirective ;
148
+ type Item = & ' a ETag ;
129
149
type IntoIter = Iter < ' a > ;
130
150
131
151
#[ inline]
@@ -135,7 +155,7 @@ impl<'a> IntoIterator for &'a IfMatch {
135
155
}
136
156
137
157
impl < ' a > IntoIterator for & ' a mut IfMatch {
138
- type Item = & ' a mut MatchDirective ;
158
+ type Item = & ' a mut ETag ;
139
159
type IntoIter = IterMut < ' a > ;
140
160
141
161
#[ inline]
@@ -147,11 +167,11 @@ impl<'a> IntoIterator for &'a mut IfMatch {
147
167
/// A borrowing iterator over entries in `IfMatch`.
148
168
#[ derive( Debug ) ]
149
169
pub struct IntoIter {
150
- inner : std:: vec:: IntoIter < MatchDirective > ,
170
+ inner : std:: vec:: IntoIter < ETag > ,
151
171
}
152
172
153
173
impl Iterator for IntoIter {
154
- type Item = MatchDirective ;
174
+ type Item = ETag ;
155
175
156
176
fn next ( & mut self ) -> Option < Self :: Item > {
157
177
self . inner . next ( )
@@ -166,11 +186,11 @@ impl Iterator for IntoIter {
166
186
/// A lending iterator over entries in `IfMatch`.
167
187
#[ derive( Debug ) ]
168
188
pub struct Iter < ' a > {
169
- inner : slice:: Iter < ' a , MatchDirective > ,
189
+ inner : slice:: Iter < ' a , ETag > ,
170
190
}
171
191
172
192
impl < ' a > Iterator for Iter < ' a > {
173
- type Item = & ' a MatchDirective ;
193
+ type Item = & ' a ETag ;
174
194
175
195
fn next ( & mut self ) -> Option < Self :: Item > {
176
196
self . inner . next ( )
@@ -185,11 +205,11 @@ impl<'a> Iterator for Iter<'a> {
185
205
/// A mutable iterator over entries in `IfMatch`.
186
206
#[ derive( Debug ) ]
187
207
pub struct IterMut < ' a > {
188
- inner : slice:: IterMut < ' a , MatchDirective > ,
208
+ inner : slice:: IterMut < ' a , ETag > ,
189
209
}
190
210
191
211
impl < ' a > Iterator for IterMut < ' a > {
192
- type Item = & ' a mut MatchDirective ;
212
+ type Item = & ' a mut ETag ;
193
213
194
214
fn next ( & mut self ) -> Option < Self :: Item > {
195
215
self . inner . next ( )
@@ -235,8 +255,24 @@ mod test {
235
255
236
256
let entries = IfMatch :: from_headers ( res) ?. unwrap ( ) ;
237
257
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( ) ) ) ;
258
+ assert_eq ! ( entries. next( ) . unwrap( ) , & ETag :: new( "0xcafebeef" . to_string( ) ) ) ;
259
+ assert_eq ! ( entries. next( ) . unwrap( ) , & ETag :: new( "0xbeefcafe" . to_string( ) ) ) ;
260
+ Ok ( ( ) )
261
+ }
262
+
263
+ #[ test]
264
+ fn wildcard ( ) -> crate :: Result < ( ) > {
265
+ let mut entries = IfMatch :: new ( ) ;
266
+ entries. push ( ETag :: new ( "0xcafebeef" . to_string ( ) ) ) ;
267
+ entries. set_wildcard ( true ) ;
268
+
269
+ let mut res = Response :: new ( 200 ) ;
270
+ entries. apply ( & mut res) ;
271
+
272
+ let entries = IfMatch :: from_headers ( res) ?. unwrap ( ) ;
273
+ assert_eq ! ( entries. wildcard( ) , true ) ;
274
+ let mut entries = entries. iter ( ) ;
275
+ assert_eq ! ( entries. next( ) . unwrap( ) , & ETag :: new( "0xcafebeef" . to_string( ) ) ) ;
240
276
Ok ( ( ) )
241
277
}
242
278
}
0 commit comments