@@ -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 } ;
@@ -500,12 +499,11 @@ impl_axum_webpage! {
500499}
501500
502501#[ tracing:: instrument]
503- pub ( crate ) async fn get_all_platforms (
502+ pub ( crate ) async fn get_all_platforms_inner (
504503 Path ( params) : Path < RustdocHtmlParams > ,
505504 Extension ( pool) : Extension < Pool > ,
506- uri : Uri ,
505+ is_crate_root : bool ,
507506) -> AxumResult < AxumResponse > {
508- let is_crate_root = uri. path ( ) . starts_with ( "/-/menus/platforms/crate/" ) ;
509507 let req_path: String = params. path . unwrap_or_default ( ) ;
510508 let req_path: Vec < & str > = req_path. split ( '/' ) . collect ( ) ;
511509
@@ -599,16 +597,23 @@ pub(crate) async fn get_all_platforms(
599597 . unwrap_or ( & releases[ 0 ] ) ;
600598
601599 // The path within this crate version's rustdoc output
600+ let inner;
602601 let ( target, inner_path) = {
603602 let mut inner_path = req_path. clone ( ) ;
604603
605- let target = if inner_path. len ( ) > 1 && doc_targets. iter ( ) . any ( |s| s == inner_path[ 0 ] ) {
606- inner_path. remove ( 0 )
604+ let target = if inner_path. len ( ) > 1
605+ && doc_targets
606+ . iter ( )
607+ . any ( |s| Some ( s) == params. target . as_ref ( ) )
608+ {
609+ inner_path. remove ( 0 ) ;
610+ params. target . as_ref ( ) . unwrap ( )
607611 } else {
608612 ""
609613 } ;
610614
611- ( target, inner_path. join ( "/" ) )
615+ inner = inner_path. join ( "/" ) ;
616+ ( target, inner. trim_end_matches ( '/' ) )
612617 } ;
613618 let inner_path = if inner_path. is_empty ( ) {
614619 format ! ( "{name}/index.html" )
@@ -639,6 +644,21 @@ pub(crate) async fn get_all_platforms(
639644 Ok ( res. into_response ( ) )
640645}
641646
647+ pub ( crate ) async fn get_all_platforms_root (
648+ Path ( mut params) : Path < RustdocHtmlParams > ,
649+ pool : Extension < Pool > ,
650+ ) -> AxumResult < AxumResponse > {
651+ params. path = None ;
652+ get_all_platforms_inner ( Path ( params) , pool, true ) . await
653+ }
654+
655+ pub ( crate ) async fn get_all_platforms (
656+ params : Path < RustdocHtmlParams > ,
657+ pool : Extension < Pool > ,
658+ ) -> AxumResult < AxumResponse > {
659+ get_all_platforms_inner ( params, pool, false ) . await
660+ }
661+
642662#[ cfg( test) ]
643663mod tests {
644664 use super :: * ;
@@ -1251,22 +1271,26 @@ mod tests {
12511271
12521272 #[ test]
12531273 fn platform_links_are_direct_and_without_nofollow ( ) {
1254- fn check_links ( response_text : String , ajax : bool , should_contain_redirect : bool ) {
1255- let platform_links: Vec < ( String , String ) > = kuchikiki:: parse_html ( )
1274+ fn check_links (
1275+ response_text : String ,
1276+ ajax : bool ,
1277+ should_contain_redirect : bool ,
1278+ ) -> Vec < ( String , String , String ) > {
1279+ let platform_links: Vec < ( String , String , String ) > = kuchikiki:: parse_html ( )
12561280 . one ( response_text)
12571281 . select ( & format ! ( r#"{}li a"# , if ajax { "" } else { "#platforms " } ) )
12581282 . expect ( "invalid selector" )
12591283 . map ( |el| {
12601284 let attributes = el. attributes . borrow ( ) ;
12611285 let url = attributes. get ( "href" ) . expect ( "href" ) . to_string ( ) ;
12621286 let rel = attributes. get ( "rel" ) . unwrap_or ( "" ) . to_string ( ) ;
1263- ( url, rel)
1287+ ( el . text_contents ( ) , url, rel)
12641288 } )
12651289 . collect ( ) ;
12661290
12671291 assert_eq ! ( platform_links. len( ) , 2 ) ;
12681292
1269- for ( url, rel) in platform_links {
1293+ for ( _ , url, rel) in & platform_links {
12701294 assert_eq ! (
12711295 url. contains( "/target-redirect/" ) ,
12721296 should_contain_redirect,
@@ -1278,25 +1302,53 @@ mod tests {
12781302 assert_eq ! ( rel, "nofollow" ) ;
12791303 }
12801304 }
1305+ platform_links
12811306 }
12821307
12831308 fn run_check_links (
12841309 env : & TestEnvironment ,
12851310 url : & str ,
12861311 extra : & str ,
12871312 should_contain_redirect : bool ,
1313+ ) {
1314+ run_check_links_redir (
1315+ env,
1316+ url,
1317+ extra,
1318+ should_contain_redirect,
1319+ should_contain_redirect,
1320+ )
1321+ }
1322+
1323+ fn run_check_links_redir (
1324+ env : & TestEnvironment ,
1325+ url : & str ,
1326+ extra : & str ,
1327+ should_contain_redirect : bool ,
1328+ ajax_should_contain_redirect : bool ,
12881329 ) {
12891330 let response = env. frontend ( ) . get ( url) . send ( ) . unwrap ( ) ;
12901331 assert ! ( response. status( ) . is_success( ) ) ;
1291- check_links ( response. text ( ) . unwrap ( ) , false , should_contain_redirect) ;
1332+ let list1 = check_links ( response. text ( ) . unwrap ( ) , false , should_contain_redirect) ;
12921333 // Same test with AJAX endpoint.
12931334 let response = env
12941335 . frontend ( )
12951336 . get ( & format ! ( "/-/menus/platforms{url}{extra}" ) )
12961337 . send ( )
12971338 . unwrap ( ) ;
12981339 assert ! ( response. status( ) . is_success( ) ) ;
1299- check_links ( response. text ( ) . unwrap ( ) , true , should_contain_redirect) ;
1340+ let list2 = check_links ( response. text ( ) . unwrap ( ) , true , ajax_should_contain_redirect) ;
1341+ if should_contain_redirect == ajax_should_contain_redirect {
1342+ assert_eq ! ( list1, list2) ;
1343+ } else {
1344+ // If redirects differ, we only check platform names.
1345+ assert ! (
1346+ list1. iter( ) . zip( & list2) . all( |( a, b) | a. 0 == b. 0 ) ,
1347+ "{:?} != {:?}" ,
1348+ list1,
1349+ list2,
1350+ ) ;
1351+ }
13001352 }
13011353
13021354 wrapper ( |env| {
@@ -1308,8 +1360,16 @@ mod tests {
13081360 . rustdoc_file ( "x86_64-pc-windows-msvc/dummy/struct.A.html" )
13091361 . default_target ( "x86_64-unknown-linux-gnu" )
13101362 . add_target ( "x86_64-pc-windows-msvc" )
1363+ . source_file ( "README.md" , b"storage readme" )
13111364 . create ( ) ?;
13121365
1366+ // FIXME: For some reason, there are target-redirects on non-AJAX lists on docs.rs
1367+ // crate pages other than the "default" one.
1368+ run_check_links_redir ( env, "/crate/dummy/0.4.0/features" , "" , true , false ) ;
1369+ run_check_links_redir ( env, "/crate/dummy/0.4.0/builds" , "" , true , false ) ;
1370+ run_check_links_redir ( env, "/crate/dummy/0.4.0/source/" , "" , true , false ) ;
1371+ run_check_links_redir ( env, "/crate/dummy/0.4.0/source/README.md" , "" , true , false ) ;
1372+
13131373 run_check_links ( env, "/crate/dummy/0.4.0" , "" , false ) ;
13141374 run_check_links ( env, "/dummy/latest/dummy" , "/" , true ) ;
13151375 run_check_links ( env, "/dummy/0.4.0/x86_64-pc-windows-msvc/dummy" , "/" , true ) ;
0 commit comments