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,23 @@ 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 {
48
+ entries : vec ! [ ] ,
49
+ wildcard : false ,
50
+ }
47
51
}
48
52
49
53
/// Create a new instance from headers.
@@ -54,17 +58,19 @@ impl IfMatch {
54
58
None => return Ok ( None ) ,
55
59
} ;
56
60
61
+ let mut wildcard = false ;
57
62
for value in headers {
58
63
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 ;
63
68
}
69
+ entries. push ( ETag :: from_str ( part) ?) ;
64
70
}
65
71
}
66
72
67
- Ok ( Some ( Self { entries } ) )
73
+ Ok ( Some ( Self { entries, wildcard } ) )
68
74
}
69
75
70
76
/// Sets the `If-Match` header.
@@ -80,11 +86,17 @@ impl IfMatch {
80
86
/// Get the `HeaderValue`.
81
87
pub fn value ( & self ) -> HeaderValue {
82
88
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 ( ) {
85
90
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 ( ) ,
88
100
} ;
89
101
}
90
102
@@ -93,10 +105,20 @@ impl IfMatch {
93
105
}
94
106
95
107
/// 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 > ) {
97
109
self . entries . push ( directive. into ( ) ) ;
98
110
}
99
111
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
+
100
122
/// An iterator visiting all server entries.
101
123
pub fn iter ( & self ) -> Iter < ' _ > {
102
124
Iter {
@@ -113,7 +135,7 @@ impl IfMatch {
113
135
}
114
136
115
137
impl IntoIterator for IfMatch {
116
- type Item = MatchDirective ;
138
+ type Item = ETag ;
117
139
type IntoIter = IntoIter ;
118
140
119
141
#[ inline]
@@ -125,7 +147,7 @@ impl IntoIterator for IfMatch {
125
147
}
126
148
127
149
impl < ' a > IntoIterator for & ' a IfMatch {
128
- type Item = & ' a MatchDirective ;
150
+ type Item = & ' a ETag ;
129
151
type IntoIter = Iter < ' a > ;
130
152
131
153
#[ inline]
@@ -135,7 +157,7 @@ impl<'a> IntoIterator for &'a IfMatch {
135
157
}
136
158
137
159
impl < ' a > IntoIterator for & ' a mut IfMatch {
138
- type Item = & ' a mut MatchDirective ;
160
+ type Item = & ' a mut ETag ;
139
161
type IntoIter = IterMut < ' a > ;
140
162
141
163
#[ inline]
@@ -147,11 +169,11 @@ impl<'a> IntoIterator for &'a mut IfMatch {
147
169
/// A borrowing iterator over entries in `IfMatch`.
148
170
#[ derive( Debug ) ]
149
171
pub struct IntoIter {
150
- inner : std:: vec:: IntoIter < MatchDirective > ,
172
+ inner : std:: vec:: IntoIter < ETag > ,
151
173
}
152
174
153
175
impl Iterator for IntoIter {
154
- type Item = MatchDirective ;
176
+ type Item = ETag ;
155
177
156
178
fn next ( & mut self ) -> Option < Self :: Item > {
157
179
self . inner . next ( )
@@ -166,11 +188,11 @@ impl Iterator for IntoIter {
166
188
/// A lending iterator over entries in `IfMatch`.
167
189
#[ derive( Debug ) ]
168
190
pub struct Iter < ' a > {
169
- inner : slice:: Iter < ' a , MatchDirective > ,
191
+ inner : slice:: Iter < ' a , ETag > ,
170
192
}
171
193
172
194
impl < ' a > Iterator for Iter < ' a > {
173
- type Item = & ' a MatchDirective ;
195
+ type Item = & ' a ETag ;
174
196
175
197
fn next ( & mut self ) -> Option < Self :: Item > {
176
198
self . inner . next ( )
@@ -185,11 +207,11 @@ impl<'a> Iterator for Iter<'a> {
185
207
/// A mutable iterator over entries in `IfMatch`.
186
208
#[ derive( Debug ) ]
187
209
pub struct IterMut < ' a > {
188
- inner : slice:: IterMut < ' a , MatchDirective > ,
210
+ inner : slice:: IterMut < ' a , ETag > ,
189
211
}
190
212
191
213
impl < ' a > Iterator for IterMut < ' a > {
192
- type Item = & ' a mut MatchDirective ;
214
+ type Item = & ' a mut ETag ;
193
215
194
216
fn next ( & mut self ) -> Option < Self :: Item > {
195
217
self . inner . next ( )
@@ -235,8 +257,33 @@ mod test {
235
257
236
258
let entries = IfMatch :: from_headers ( res) ?. unwrap ( ) ;
237
259
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
+ ) ;
240
287
Ok ( ( ) )
241
288
}
242
289
}
0 commit comments