@@ -292,7 +292,7 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
292
292
let path_in_latest = if !is_latest_version {
293
293
let mut latest_path = req_path. clone ( ) ;
294
294
latest_path[ 2 ] = & latest_version;
295
- path_for_version ( & latest_path, & crate_details. target_name , & conn)
295
+ path_for_version ( & latest_path, & crate_details. doc_targets , & conn)
296
296
} else {
297
297
Default :: default ( )
298
298
} ;
@@ -302,7 +302,7 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
302
302
let mut inner_path = req_path. clone ( ) ;
303
303
// Drop the `rustdoc/:crate/:version[/:platform]` prefix
304
304
inner_path. drain ( ..3 ) ;
305
- if inner_path[ 0 ] != crate_details. target_name {
305
+ if inner_path. len ( ) > 1 && crate_details. doc_targets . iter ( ) . any ( |s| s == inner_path [ 0 ] ) {
306
306
inner_path. remove ( 0 ) ;
307
307
}
308
308
inner_path. join ( "/" )
@@ -331,7 +331,7 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
331
331
/// `rustdoc/crate/version[/platform]/module/[kind.name.html|index.html]`
332
332
///
333
333
/// Returns a path that can be appended to `/crate/version/` to create a complete URL.
334
- fn path_for_version ( req_path : & [ & str ] , target_name : & str , conn : & Connection ) -> String {
334
+ fn path_for_version ( req_path : & [ & str ] , known_platforms : & [ String ] , conn : & Connection ) -> String {
335
335
// Simple case: page exists in the latest version, so just change the version number
336
336
if File :: from_path ( & conn, & req_path. join ( "/" ) ) . is_some ( ) {
337
337
// NOTE: this adds 'index.html' if it wasn't there before
@@ -351,12 +351,8 @@ fn path_for_version(req_path: &[&str], target_name: &str, conn: &Connection) ->
351
351
. expect ( "paths should be of the form <kind>.<name>.html" )
352
352
} ;
353
353
// check if req_path[3] is the platform choice or the name of the crate
354
- // rustdoc generates a ../settings.html page, so if req_path[3] is not
355
- // the target, that doesn't necessarily mean it's a platform.
356
- // we also can't check if it's in TARGETS, since some targets have been
357
- // removed (looking at you, i686-apple-darwin)
358
354
let concat_path;
359
- let crate_root = if req_path[ 3 ] != target_name && req_path. len ( ) >= 5 {
355
+ let crate_root = if known_platforms . iter ( ) . any ( |s| s == req_path[ 3 ] ) && req_path. len ( ) >= 5 {
360
356
concat_path = format ! ( "{}/{}" , req_path[ 3 ] , req_path[ 4 ] ) ;
361
357
& concat_path
362
358
} else {
@@ -375,52 +371,39 @@ pub fn target_redirect_handler(req: &mut Request) -> IronResult<Response> {
375
371
376
372
let crate_details = cexpect ! ( CrateDetails :: new( & conn, & name, & version) ) ;
377
373
378
- // /crate/:name/:version/target-redirect/:target/*path
379
- let ( target, path) = {
380
- let mut path = req. url . path ( ) ;
381
- path. drain ( ..4 ) ;
382
- let target = path[ 0 ] ;
383
- if target == crate_details. metadata . default_target {
384
- path. remove ( 0 ) ;
374
+ // [crate, :name, :version, target-redirect, :target, *path]
375
+ // is transformed to
376
+ // [rustdoc, :name, :version, :target?, *path]
377
+ // path might be empty, but target is guaranteed to be there because of the route used
378
+ let file_path = {
379
+ let mut file_path = req. url . path ( ) ;
380
+ file_path[ 0 ] = "rustdoc" ;
381
+ file_path. remove ( 3 ) ;
382
+ if file_path[ 3 ] == crate_details. metadata . default_target {
383
+ file_path. remove ( 3 ) ;
384
+ } else if file_path[ 4 ] != crate_details. target_name {
385
+ // For non-default targets we only redirect to paths within the current crate
386
+ file_path. drain ( 4 ..) ;
387
+ file_path. push ( & crate_details. target_name ) ;
388
+ file_path. push ( "index.html" ) ;
385
389
}
386
- ( target, path. join ( "/" ) )
390
+ if let Some ( last) = file_path. last_mut ( ) {
391
+ if * last == "" {
392
+ * last = "index.html" ;
393
+ }
394
+ }
395
+ file_path
387
396
} ;
388
397
389
- let file_path = format ! (
390
- "rustdoc/{name}/{version}/{path}" ,
398
+ let path = path_for_version ( & file_path, & crate_details. doc_targets , & conn) ;
399
+ let url = format ! (
400
+ "{base}/{name}/{version}/{path}" ,
401
+ base = base,
391
402
name = name,
392
403
version = version,
393
404
path = path
394
405
) ;
395
406
396
- // if the current page is not present on the other platform, link to the index page for the crate instead
397
- let url = if File :: from_path ( & conn, & file_path) . is_some ( ) {
398
- format ! (
399
- "{base}/{name}/{version}/{path}" ,
400
- base = base,
401
- name = name,
402
- version = version,
403
- path = path
404
- )
405
- } else if target == crate_details. metadata . default_target {
406
- format ! (
407
- "{base}/{name}/{version}/{target_name}/index.html" ,
408
- base = base,
409
- name = name,
410
- version = version,
411
- target_name = crate_details. target_name
412
- )
413
- } else {
414
- format ! (
415
- "{base}/{name}/{version}/{target}/{target_name}/index.html" ,
416
- base = base,
417
- name = name,
418
- version = version,
419
- target = target,
420
- target_name = crate_details. target_name
421
- )
422
- } ;
423
-
424
407
let url = ctry ! ( Url :: parse( & url) ) ;
425
408
let mut resp = Response :: with ( ( status:: Found , Redirect ( url) ) ) ;
426
409
resp. headers . set ( Expires ( HttpDate ( time:: now ( ) ) ) ) ;
@@ -661,6 +644,8 @@ mod test {
661
644
// check it searches for removed pages
662
645
let redirect =
663
646
latest_version_redirect ( "/dummy/0.1.0/dummy/struct.will-be-deleted.html" , & web) ?;
647
+ // This must be a double redirect to deal with crates that failed to build in the
648
+ // latest version
664
649
assert_eq ! ( redirect, "/dummy/0.2.0/dummy?search=will-be-deleted" ) ;
665
650
assert_redirect (
666
651
"/dummy/0.2.0/dummy?search=will-be-deleted" ,
@@ -1037,8 +1022,8 @@ mod test {
1037
1022
. add_target ( "x86_64-pc-windows-msvc" )
1038
1023
. create ( ) ?;
1039
1024
1040
- // For top-level items we redirect to the target-specific doc root as the top-level
1041
- // items can't know which target they're for
1025
+ // For top-level items on non-default platforms we redirect to the target-specific doc
1026
+ // root as the top-level items can't know which target they're for
1042
1027
assert_platform_links (
1043
1028
web,
1044
1029
"/dummy/0.4.0/settings.html" ,
@@ -1047,7 +1032,7 @@ mod test {
1047
1032
"x86_64-pc-windows-msvc" ,
1048
1033
"/dummy/0.4.0/x86_64-pc-windows-msvc/dummy/index.html" ,
1049
1034
) ,
1050
- ( "x86_64-unknown-linux-gnu" , "/dummy/0.4.0/dummy/index .html" ) ,
1035
+ ( "x86_64-unknown-linux-gnu" , "/dummy/0.4.0/settings .html" ) ,
1051
1036
] ,
1052
1037
) ?;
1053
1038
@@ -1093,7 +1078,7 @@ mod test {
1093
1078
& [
1094
1079
(
1095
1080
"x86_64-pc-windows-msvc" ,
1096
- "/dummy/0.4.0/x86_64-pc-windows-msvc/dummy/index.html " ,
1081
+ "/dummy/0.4.0/x86_64-pc-windows-msvc/dummy?search=DefaultOnly " ,
1097
1082
) ,
1098
1083
(
1099
1084
"x86_64-unknown-linux-gnu" ,
@@ -1140,7 +1125,10 @@ mod test {
1140
1125
"x86_64-pc-windows-msvc" ,
1141
1126
"/dummy/0.4.0/x86_64-pc-windows-msvc/dummy/struct.WindowsOnly.html" ,
1142
1127
) ,
1143
- ( "x86_64-unknown-linux-gnu" , "/dummy/0.4.0/dummy/index.html" ) ,
1128
+ (
1129
+ "x86_64-unknown-linux-gnu" ,
1130
+ "/dummy/0.4.0/dummy/?search=WindowsOnly" ,
1131
+ ) ,
1144
1132
] ,
1145
1133
) ?;
1146
1134
0 commit comments