@@ -17,7 +17,6 @@ use crate::{
1717use anyhow:: { Context , Result } ;
1818use axum:: {
1919 extract:: { Extension , Path } ,
20- http:: Uri ,
2120 response:: { IntoResponse , Response as AxumResponse } ,
2221} ;
2322use chrono:: { DateTime , Utc } ;
@@ -491,12 +490,11 @@ impl_axum_webpage! {
491490}
492491
493492#[ tracing:: instrument]
494- pub ( crate ) async fn get_all_platforms (
493+ pub ( crate ) async fn get_all_platforms_inner (
495494 Path ( params) : Path < RustdocHtmlParams > ,
496495 Extension ( pool) : Extension < Pool > ,
497- uri : Uri ,
496+ is_crate_root : bool ,
498497) -> AxumResult < AxumResponse > {
499- let is_crate_root = uri. path ( ) . starts_with ( "/-/menus/platforms/crate/" ) ;
500498 let req_path: String = params. path . unwrap_or_default ( ) ;
501499 let req_path: Vec < & str > = req_path. split ( '/' ) . collect ( ) ;
502500
@@ -590,16 +588,23 @@ pub(crate) async fn get_all_platforms(
590588 . unwrap_or ( & releases[ 0 ] ) ;
591589
592590 // The path within this crate version's rustdoc output
591+ let inner;
593592 let ( target, inner_path) = {
594593 let mut inner_path = req_path. clone ( ) ;
595594
596- let target = if inner_path. len ( ) > 1 && doc_targets. iter ( ) . any ( |s| s == inner_path[ 0 ] ) {
597- inner_path. remove ( 0 )
595+ let target = if inner_path. len ( ) > 1
596+ && doc_targets
597+ . iter ( )
598+ . any ( |s| Some ( s) == params. target . as_ref ( ) )
599+ {
600+ inner_path. remove ( 0 ) ;
601+ params. target . as_ref ( ) . unwrap ( )
598602 } else {
599603 ""
600604 } ;
601605
602- ( target, inner_path. join ( "/" ) )
606+ inner = inner_path. join ( "/" ) ;
607+ ( target, inner. trim_end_matches ( '/' ) )
603608 } ;
604609 let inner_path = if inner_path. is_empty ( ) {
605610 format ! ( "{name}/index.html" )
@@ -630,6 +635,21 @@ pub(crate) async fn get_all_platforms(
630635 Ok ( res. into_response ( ) )
631636}
632637
638+ pub ( crate ) async fn get_all_platforms_root (
639+ Path ( mut params) : Path < RustdocHtmlParams > ,
640+ pool : Extension < Pool > ,
641+ ) -> AxumResult < AxumResponse > {
642+ params. path = None ;
643+ get_all_platforms_inner ( Path ( params) , pool, true ) . await
644+ }
645+
646+ pub ( crate ) async fn get_all_platforms (
647+ params : Path < RustdocHtmlParams > ,
648+ pool : Extension < Pool > ,
649+ ) -> AxumResult < AxumResponse > {
650+ get_all_platforms_inner ( params, pool, false ) . await
651+ }
652+
633653#[ cfg( test) ]
634654mod tests {
635655 use super :: * ;
@@ -1242,22 +1262,26 @@ mod tests {
12421262
12431263 #[ test]
12441264 fn platform_links_are_direct_and_without_nofollow ( ) {
1245- fn check_links ( response_text : String , ajax : bool , should_contain_redirect : bool ) {
1246- let platform_links: Vec < ( String , String ) > = kuchikiki:: parse_html ( )
1265+ fn check_links (
1266+ response_text : String ,
1267+ ajax : bool ,
1268+ should_contain_redirect : bool ,
1269+ ) -> Vec < ( String , String , String ) > {
1270+ let platform_links: Vec < ( String , String , String ) > = kuchikiki:: parse_html ( )
12471271 . one ( response_text)
12481272 . select ( & format ! ( r#"{}li a"# , if ajax { "" } else { "#platforms " } ) )
12491273 . expect ( "invalid selector" )
12501274 . map ( |el| {
12511275 let attributes = el. attributes . borrow ( ) ;
12521276 let url = attributes. get ( "href" ) . expect ( "href" ) . to_string ( ) ;
12531277 let rel = attributes. get ( "rel" ) . unwrap_or ( "" ) . to_string ( ) ;
1254- ( url, rel)
1278+ ( el . text_contents ( ) , url, rel)
12551279 } )
12561280 . collect ( ) ;
12571281
12581282 assert_eq ! ( platform_links. len( ) , 2 ) ;
12591283
1260- for ( url, rel) in platform_links {
1284+ for ( _ , url, rel) in & platform_links {
12611285 assert_eq ! (
12621286 url. contains( "/target-redirect/" ) ,
12631287 should_contain_redirect,
@@ -1269,25 +1293,53 @@ mod tests {
12691293 assert_eq ! ( rel, "nofollow" ) ;
12701294 }
12711295 }
1296+ return platform_links;
12721297 }
12731298
12741299 fn run_check_links (
12751300 env : & TestEnvironment ,
12761301 url : & str ,
12771302 extra : & str ,
12781303 should_contain_redirect : bool ,
1304+ ) {
1305+ run_check_links_redir (
1306+ env,
1307+ url,
1308+ extra,
1309+ should_contain_redirect,
1310+ should_contain_redirect,
1311+ )
1312+ }
1313+
1314+ fn run_check_links_redir (
1315+ env : & TestEnvironment ,
1316+ url : & str ,
1317+ extra : & str ,
1318+ should_contain_redirect : bool ,
1319+ ajax_should_contain_redirect : bool ,
12791320 ) {
12801321 let response = env. frontend ( ) . get ( url) . send ( ) . unwrap ( ) ;
12811322 assert ! ( response. status( ) . is_success( ) ) ;
1282- check_links ( response. text ( ) . unwrap ( ) , false , should_contain_redirect) ;
1323+ let list1 = check_links ( response. text ( ) . unwrap ( ) , false , should_contain_redirect) ;
12831324 // Same test with AJAX endpoint.
12841325 let response = env
12851326 . frontend ( )
12861327 . get ( & format ! ( "/-/menus/platforms{url}{extra}" ) )
12871328 . send ( )
12881329 . unwrap ( ) ;
12891330 assert ! ( response. status( ) . is_success( ) ) ;
1290- check_links ( response. text ( ) . unwrap ( ) , true , should_contain_redirect) ;
1331+ let list2 = check_links ( response. text ( ) . unwrap ( ) , true , ajax_should_contain_redirect) ;
1332+ if should_contain_redirect == ajax_should_contain_redirect {
1333+ assert_eq ! ( list1, list2) ;
1334+ } else {
1335+ // If redirects differ, we only check platform names.
1336+ assert ! (
1337+ list1. iter( ) . zip( & list2) . all( |( a, b) | a. 0 == b. 0 ) ,
1338+ "{:?} != {:?}" ,
1339+ list1,
1340+ list2,
1341+ ) ;
1342+ }
12911343 }
12921344
12931345 wrapper ( |env| {
@@ -1299,8 +1351,16 @@ mod tests {
12991351 . rustdoc_file ( "x86_64-pc-windows-msvc/dummy/struct.A.html" )
13001352 . default_target ( "x86_64-unknown-linux-gnu" )
13011353 . add_target ( "x86_64-pc-windows-msvc" )
1354+ . source_file ( "README.md" , b"storage readme" )
13021355 . create ( ) ?;
13031356
1357+ // FIXME: For some reason, there are target-redirects on non-AJAX lists on docs.rs
1358+ // crate pages other than the "default" one.
1359+ run_check_links_redir ( env, "/crate/dummy/0.4.0/features" , "" , true , false ) ;
1360+ run_check_links_redir ( env, "/crate/dummy/0.4.0/builds" , "" , true , false ) ;
1361+ run_check_links_redir ( env, "/crate/dummy/0.4.0/source/" , "" , true , false ) ;
1362+ run_check_links_redir ( env, "/crate/dummy/0.4.0/source/README.md" , "" , true , false ) ;
1363+
13041364 run_check_links ( env, "/crate/dummy/0.4.0" , "" , false ) ;
13051365 run_check_links ( env, "/dummy/latest/dummy" , "/" , true ) ;
13061366 run_check_links ( env, "/dummy/0.4.0/x86_64-pc-windows-msvc/dummy" , "/" , true ) ;
0 commit comments