@@ -7,6 +7,7 @@ use util::{self, csv, Seconds};
77use HeaderValue ;
88
99/// `Cache-Control` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.2)
10+ /// with extensions in [RFC8246](https://www.rfc-editor.org/rfc/rfc8246)
1011///
1112/// The `Cache-Control` header field is used to specify directives for
1213/// caches along the request/response chain. Such cache directives are
@@ -43,16 +44,32 @@ pub struct CacheControl {
4344 s_max_age : Option < Seconds > ,
4445}
4546
46- bitflags ! {
47- struct Flags : u32 {
48- const NO_CACHE = 0b00000001 ;
49- const NO_STORE = 0b00000010 ;
50- const NO_TRANSFORM = 0b00000100 ;
51- const ONLY_IF_CACHED = 0b00001000 ;
52- const MUST_REVALIDATE = 0b00010000 ;
53- const PUBLIC = 0b00100000 ;
54- const PRIVATE = 0b01000000 ;
55- const PROXY_REVALIDATE = 0b10000000 ;
47+ #[ derive( Debug , Clone , PartialEq ) ]
48+ struct Flags {
49+ bits : u64 ,
50+ }
51+
52+ impl Flags {
53+ const NO_CACHE : Self = Self { bits : 0b000000001 } ;
54+ const NO_STORE : Self = Self { bits : 0b000000010 } ;
55+ const NO_TRANSFORM : Self = Self { bits : 0b000000100 } ;
56+ const ONLY_IF_CACHED : Self = Self { bits : 0b000001000 } ;
57+ const MUST_REVALIDATE : Self = Self { bits : 0b000010000 } ;
58+ const PUBLIC : Self = Self { bits : 0b000100000 } ;
59+ const PRIVATE : Self = Self { bits : 0b001000000 } ;
60+ const PROXY_REVALIDATE : Self = Self { bits : 0b010000000 } ;
61+ const IMMUTABLE : Self = Self { bits : 0b100000000 } ;
62+
63+ fn empty ( ) -> Self {
64+ Self { bits : 0 }
65+ }
66+
67+ fn contains ( & self , flag : Self ) -> bool {
68+ ( self . bits & flag. bits ) != 0
69+ }
70+
71+ fn insert ( & mut self , flag : Self ) {
72+ self . bits |= flag. bits ;
5673 }
5774}
5875
@@ -100,6 +117,11 @@ impl CacheControl {
100117 self . flags . contains ( Flags :: PRIVATE )
101118 }
102119
120+ /// Check if the `immutable` directive is set.
121+ pub fn immutable ( & self ) -> bool {
122+ self . flags . contains ( Flags :: IMMUTABLE )
123+ }
124+
103125 /// Get the value of the `max-age` directive if set.
104126 pub fn max_age ( & self ) -> Option < Duration > {
105127 self . max_age . map ( Into :: into)
@@ -158,27 +180,33 @@ impl CacheControl {
158180 self
159181 }
160182
183+ /// Set the `immutable` directive.
184+ pub fn with_immutable ( mut self ) -> Self {
185+ self . flags . insert ( Flags :: IMMUTABLE ) ;
186+ self
187+ }
188+
161189 /// Set the `max-age` directive.
162- pub fn with_max_age ( mut self , seconds : Duration ) -> Self {
163- self . max_age = Some ( seconds . into ( ) ) ;
190+ pub fn with_max_age ( mut self , duration : Duration ) -> Self {
191+ self . max_age = Some ( duration . into ( ) ) ;
164192 self
165193 }
166194
167195 /// Set the `max-stale` directive.
168- pub fn with_max_stale ( mut self , seconds : Duration ) -> Self {
169- self . max_stale = Some ( seconds . into ( ) ) ;
196+ pub fn with_max_stale ( mut self , duration : Duration ) -> Self {
197+ self . max_stale = Some ( duration . into ( ) ) ;
170198 self
171199 }
172200
173201 /// Set the `min-fresh` directive.
174- pub fn with_min_fresh ( mut self , seconds : Duration ) -> Self {
175- self . min_fresh = Some ( seconds . into ( ) ) ;
202+ pub fn with_min_fresh ( mut self , duration : Duration ) -> Self {
203+ self . min_fresh = Some ( duration . into ( ) ) ;
176204 self
177205 }
178206
179207 /// Set the `s-maxage` directive.
180- pub fn with_s_max_age ( mut self , seconds : Duration ) -> Self {
181- self . s_max_age = Some ( seconds . into ( ) ) ;
208+ pub fn with_s_max_age ( mut self , duration : Duration ) -> Self {
209+ self . s_max_age = Some ( duration . into ( ) ) ;
182210 self
183211 }
184212}
@@ -236,6 +264,9 @@ impl FromIterator<KnownDirective> for FromIter {
236264 Directive :: Private => {
237265 cc. flags . insert ( Flags :: PRIVATE ) ;
238266 }
267+ Directive :: Immutable => {
268+ cc. flags . insert ( Flags :: IMMUTABLE ) ;
269+ }
239270 Directive :: ProxyRevalidate => {
240271 cc. flags . insert ( Flags :: PROXY_REVALIDATE ) ;
241272 }
@@ -278,6 +309,7 @@ impl<'a> fmt::Display for Fmt<'a> {
278309 if_flag ( Flags :: MUST_REVALIDATE , Directive :: MustRevalidate ) ,
279310 if_flag ( Flags :: PUBLIC , Directive :: Public ) ,
280311 if_flag ( Flags :: PRIVATE , Directive :: Private ) ,
312+ if_flag ( Flags :: IMMUTABLE , Directive :: Immutable ) ,
281313 if_flag ( Flags :: PROXY_REVALIDATE , Directive :: ProxyRevalidate ) ,
282314 self . 0
283315 . max_age
@@ -325,6 +357,7 @@ enum Directive {
325357 MustRevalidate ,
326358 Public ,
327359 Private ,
360+ Immutable ,
328361 ProxyRevalidate ,
329362 SMaxAge ( u64 ) ,
330363}
@@ -345,6 +378,7 @@ impl fmt::Display for Directive {
345378 Directive :: MustRevalidate => "must-revalidate" ,
346379 Directive :: Public => "public" ,
347380 Directive :: Private => "private" ,
381+ Directive :: Immutable => "immutable" ,
348382 Directive :: ProxyRevalidate => "proxy-revalidate" ,
349383 Directive :: SMaxAge ( secs) => return write ! ( f, "s-maxage={}" , secs) ,
350384 } ,
@@ -364,6 +398,7 @@ impl FromStr for KnownDirective {
364398 "must-revalidate" => Directive :: MustRevalidate ,
365399 "public" => Directive :: Public ,
366400 "private" => Directive :: Private ,
401+ "immutable" => Directive :: Immutable ,
367402 "proxy-revalidate" => Directive :: ProxyRevalidate ,
368403 "" => return Err ( ( ) ) ,
369404 _ => match s. find ( '=' ) {
@@ -428,9 +463,18 @@ mod tests {
428463 ) ;
429464 }
430465
466+ #[ test]
467+ fn test_immutable ( ) {
468+ let cc = CacheControl :: new ( ) . with_immutable ( ) ;
469+ let headers = test_encode ( cc. clone ( ) ) ;
470+ assert_eq ! ( headers[ "cache-control" ] , "immutable" ) ;
471+ assert_eq ! ( test_decode:: <CacheControl >( & [ "immutable" ] ) . unwrap( ) , cc) ;
472+ assert ! ( cc. immutable( ) ) ;
473+ }
474+
431475 #[ test]
432476 fn test_parse_bad_syntax ( ) {
433- assert_eq ! ( test_decode:: <CacheControl >( & [ "max-age=lolz" ] ) , None , ) ;
477+ assert_eq ! ( test_decode:: <CacheControl >( & [ "max-age=lolz" ] ) , None ) ;
434478 }
435479
436480 #[ test]
0 commit comments