@@ -3,7 +3,7 @@ use crate::db::types::Feature;
3
3
use crate :: {
4
4
db:: Pool ,
5
5
impl_webpage,
6
- web:: { page:: WebPage , MetaData } ,
6
+ web:: { cache :: CachePolicy , page:: WebPage , MetaData } ,
7
7
} ;
8
8
use iron:: { IronResult , Request , Response , Url } ;
9
9
use router:: Router ;
@@ -30,10 +30,10 @@ pub fn build_features_handler(req: &mut Request) -> IronResult<Response> {
30
30
let req_version = router. find ( "version" ) ;
31
31
32
32
let mut conn = extension ! ( req, Pool ) . get ( ) ?;
33
- let ( version, version_or_latest) =
33
+ let ( version, version_or_latest, is_latest_url ) =
34
34
match match_version ( & mut conn, name, req_version) . and_then ( |m| m. assume_exact ( ) ) ? {
35
- MatchSemver :: Exact ( ( version, _) ) => ( version. clone ( ) , version) ,
36
- MatchSemver :: Latest ( ( version, _) ) => ( version, "latest" . to_string ( ) ) ,
35
+ MatchSemver :: Exact ( ( version, _) ) => ( version. clone ( ) , version, false ) ,
36
+ MatchSemver :: Latest ( ( version, _) ) => ( version, "latest" . to_string ( ) , true ) ,
37
37
38
38
MatchSemver :: Semver ( ( version, _) ) => {
39
39
let url = ctry ! (
@@ -46,7 +46,7 @@ pub fn build_features_handler(req: &mut Request) -> IronResult<Response> {
46
46
) ) ,
47
47
) ;
48
48
49
- return Ok ( super :: redirect ( url) ) ;
49
+ return Ok ( super :: cached_redirect ( url, CachePolicy :: ForeverInCdn ) ) ;
50
50
}
51
51
} ;
52
52
let rows = ctry ! (
@@ -70,7 +70,7 @@ pub fn build_features_handler(req: &mut Request) -> IronResult<Response> {
70
70
default_len = result. 1 ;
71
71
}
72
72
73
- FeaturesPage {
73
+ let mut response = FeaturesPage {
74
74
metadata : cexpect ! (
75
75
req,
76
76
MetaData :: from_crate( & mut conn, name, & version, & version_or_latest)
@@ -79,7 +79,13 @@ pub fn build_features_handler(req: &mut Request) -> IronResult<Response> {
79
79
default_len,
80
80
canonical_url : format ! ( "https://docs.rs/crate/{}/latest/features" , name) ,
81
81
}
82
- . into_response ( req)
82
+ . into_response ( req) ?;
83
+ response. extensions . insert :: < CachePolicy > ( if is_latest_url {
84
+ CachePolicy :: ForeverInCdn
85
+ } else {
86
+ CachePolicy :: ForeverInCdnAndStaleInBrowser
87
+ } ) ;
88
+ Ok ( response)
83
89
}
84
90
85
91
fn order_features_and_count_default_len ( raw : Vec < Feature > ) -> ( Vec < Feature > , usize ) {
@@ -121,12 +127,9 @@ fn get_feature_map(raw: Vec<Feature>) -> HashMap<String, Feature> {
121
127
122
128
#[ cfg( test) ]
123
129
mod tests {
130
+ use super :: * ;
124
131
use crate :: db:: types:: Feature ;
125
- use crate :: test:: wrapper;
126
- use crate :: web:: features:: {
127
- get_feature_map, get_tree_structure_from_default, order_features_and_count_default_len,
128
- DEFAULT_NAME ,
129
- } ;
132
+ use crate :: test:: { assert_cache_control, assert_redirect_cached, wrapper} ;
130
133
use reqwest:: StatusCode ;
131
134
use std:: collections:: HashMap ;
132
135
@@ -246,6 +249,46 @@ mod tests {
246
249
assert_eq ! ( features[ 1 ] , non_default) ;
247
250
}
248
251
252
+ #[ test]
253
+ fn semver_redirect ( ) {
254
+ wrapper ( |env| {
255
+ env. fake_release ( )
256
+ . name ( "foo" )
257
+ . version ( "0.2.1" )
258
+ . features ( HashMap :: new ( ) )
259
+ . create ( ) ?;
260
+
261
+ assert_redirect_cached (
262
+ "/crate/foo/~0.2/features" ,
263
+ "/crate/foo/0.2.1/features" ,
264
+ CachePolicy :: ForeverInCdn ,
265
+ env. frontend ( ) ,
266
+ & env. config ( ) ,
267
+ ) ?;
268
+ Ok ( ( ) )
269
+ } ) ;
270
+ }
271
+
272
+ #[ test]
273
+ fn specific_version_correctly_cached ( ) {
274
+ wrapper ( |env| {
275
+ env. fake_release ( )
276
+ . name ( "foo" )
277
+ . version ( "0.2.0" )
278
+ . features ( HashMap :: new ( ) )
279
+ . create ( ) ?;
280
+
281
+ let resp = env. frontend ( ) . get ( "/crate/foo/0.2.0/features" ) . send ( ) ?;
282
+ assert ! ( resp. status( ) . is_success( ) ) ;
283
+ assert_cache_control (
284
+ & resp,
285
+ CachePolicy :: ForeverInCdnAndStaleInBrowser ,
286
+ & env. config ( ) ,
287
+ ) ;
288
+ Ok ( ( ) )
289
+ } ) ;
290
+ }
291
+
249
292
#[ test]
250
293
fn latest_200 ( ) {
251
294
wrapper ( |env| {
@@ -262,6 +305,8 @@ mod tests {
262
305
. create ( ) ?;
263
306
264
307
let resp = env. frontend ( ) . get ( "/crate/foo/latest/features" ) . send ( ) ?;
308
+ assert ! ( resp. status( ) . is_success( ) ) ;
309
+ assert_cache_control ( & resp, CachePolicy :: ForeverInCdn , & env. config ( ) ) ;
265
310
assert ! ( resp. url( ) . as_str( ) . ends_with( "/crate/foo/latest/features" ) ) ;
266
311
let body = String :: from_utf8 ( resp. bytes ( ) . unwrap ( ) . to_vec ( ) ) . unwrap ( ) ;
267
312
assert ! ( body. contains( "<a href=\" /crate/foo/latest/builds\" " ) ) ;
0 commit comments