5
5
use headers:: { CacheControl , HeaderMapExt } ;
6
6
use hyper:: { Body , Response } ;
7
7
8
+ // Cache-Control `max-age` variants
9
+ const MAX_AGE_ONE_HOUR : u64 = 60 * 60 ;
10
+ const MAX_AGE_ONE_DAY : u64 = 60 * 60 * 24_u64 ;
11
+ const MAX_AGE_ONE_YEAR : u64 = 60 * 60 * 24 * 365 ;
12
+
13
+ // `Cache-Control` list of extensions
8
14
const CACHE_EXT_ONE_HOUR : [ & str ; 4 ] = [ "atom" , "json" , "rss" , "xml" ] ;
9
15
const CACHE_EXT_ONE_YEAR : [ & str ; 32 ] = [
10
16
"avif" , "bmp" , "bz2" , "css" , "doc" , "gif" , "gz" , "htc" , "ico" , "jpeg" , "jpg" , "js" , "jxl" ,
@@ -15,18 +21,18 @@ const CACHE_EXT_ONE_YEAR: [&str; 32] = [
15
21
/// It appends a `Cache-Control` header to a response if that one is part of a set of file types.
16
22
pub fn append_headers ( uri : & str , resp : & mut Response < Body > ) {
17
23
// Default max-age value in seconds (one day)
18
- let mut max_age = 60 * 60 * 24_u64 ;
24
+ let mut max_age = MAX_AGE_ONE_DAY ;
19
25
20
26
if CACHE_EXT_ONE_HOUR
21
27
. iter ( )
22
28
. any ( |x| uri. ends_with ( & [ "." , * x] . concat ( ) ) )
23
29
{
24
- max_age = 60 * 60 ;
30
+ max_age = MAX_AGE_ONE_HOUR ;
25
31
} else if CACHE_EXT_ONE_YEAR
26
32
. iter ( )
27
33
. any ( |x| uri. ends_with ( & [ "." , * x] . concat ( ) ) )
28
34
{
29
- max_age = 60 * 60 * 24 * 365 ;
35
+ max_age = MAX_AGE_ONE_YEAR ;
30
36
}
31
37
32
38
let cache_control = CacheControl :: new ( )
@@ -39,3 +45,62 @@ pub fn append_headers(uri: &str, resp: &mut Response<Body>) {
39
45
fn duration_from_secs ( secs : u64 ) -> std:: time:: Duration {
40
46
std:: time:: Duration :: from_secs ( std:: cmp:: min ( secs, u32:: MAX as u64 ) )
41
47
}
48
+
49
+ #[ cfg( test) ]
50
+ mod tests {
51
+ use hyper:: { Body , Response , StatusCode } ;
52
+
53
+ use super :: {
54
+ append_headers, CACHE_EXT_ONE_HOUR , CACHE_EXT_ONE_YEAR , MAX_AGE_ONE_DAY , MAX_AGE_ONE_HOUR ,
55
+ MAX_AGE_ONE_YEAR ,
56
+ } ;
57
+
58
+ #[ tokio:: test]
59
+ async fn headers_one_hour ( ) {
60
+ let mut resp = Response :: new ( Body :: empty ( ) ) ;
61
+ * resp. status_mut ( ) = StatusCode :: OK ;
62
+
63
+ for ext in CACHE_EXT_ONE_HOUR . iter ( ) {
64
+ append_headers ( & [ "/some." , ext] . concat ( ) , & mut resp) ;
65
+
66
+ let cache_control = resp. headers ( ) . get ( http:: header:: CACHE_CONTROL ) . unwrap ( ) ;
67
+ assert_eq ! ( resp. status( ) , StatusCode :: OK ) ;
68
+ assert_eq ! (
69
+ cache_control. to_str( ) . unwrap( ) ,
70
+ format!( "public, max-age={}" , MAX_AGE_ONE_HOUR )
71
+ ) ;
72
+ }
73
+ }
74
+
75
+ #[ tokio:: test]
76
+ async fn headers_one_day_default ( ) {
77
+ let mut resp = Response :: new ( Body :: empty ( ) ) ;
78
+ * resp. status_mut ( ) = StatusCode :: OK ;
79
+
80
+ append_headers ( "/" , & mut resp) ;
81
+
82
+ let cache_control = resp. headers ( ) . get ( http:: header:: CACHE_CONTROL ) . unwrap ( ) ;
83
+ assert_eq ! ( resp. status( ) , StatusCode :: OK ) ;
84
+ assert_eq ! (
85
+ cache_control. to_str( ) . unwrap( ) ,
86
+ format!( "public, max-age={}" , MAX_AGE_ONE_DAY )
87
+ ) ;
88
+ }
89
+
90
+ #[ tokio:: test]
91
+ async fn headers_one_year ( ) {
92
+ let mut resp = Response :: new ( Body :: empty ( ) ) ;
93
+ * resp. status_mut ( ) = StatusCode :: OK ;
94
+
95
+ for ext in CACHE_EXT_ONE_YEAR . iter ( ) {
96
+ append_headers ( & [ "/some." , ext] . concat ( ) , & mut resp) ;
97
+
98
+ let cache_control = resp. headers ( ) . get ( http:: header:: CACHE_CONTROL ) . unwrap ( ) ;
99
+ assert_eq ! ( resp. status( ) , StatusCode :: OK ) ;
100
+ assert_eq ! (
101
+ cache_control. to_str( ) . unwrap( ) ,
102
+ format!( "public, max-age={}" , MAX_AGE_ONE_YEAR )
103
+ ) ;
104
+ }
105
+ }
106
+ }
0 commit comments