Skip to content

Commit d065c06

Browse files
Fix crate pages handling target-redirect
1 parent a8be4b0 commit d065c06

File tree

4 files changed

+95
-17
lines changed

4 files changed

+95
-17
lines changed

src/web/crate_details.rs

+73-13
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use crate::{
1717
use anyhow::{Context, Result};
1818
use axum::{
1919
extract::{Extension, Path},
20-
http::Uri,
2120
response::{IntoResponse, Response as AxumResponse},
2221
};
2322
use 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)]
634654
mod 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);

src/web/routes.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,27 @@ pub(super) fn build_axum_routes() -> AxumRouter {
238238
)
239239
.route(
240240
"/-/menus/platforms/crate/:name/:version",
241-
get_internal(super::crate_details::get_all_platforms),
241+
get_internal(super::crate_details::get_all_platforms_root),
242+
)
243+
.route(
244+
"/-/menus/platforms/crate/:name/:version/features",
245+
get_internal(super::crate_details::get_all_platforms_root),
246+
)
247+
.route(
248+
"/-/menus/platforms/crate/:name/:version/builds",
249+
get_internal(super::crate_details::get_all_platforms_root),
250+
)
251+
.route(
252+
"/-/menus/platforms/crate/:name/:version/builds/*path",
253+
get_internal(super::crate_details::get_all_platforms_root),
254+
)
255+
.route(
256+
"/-/menus/platforms/crate/:name/:version/source/",
257+
get_internal(super::crate_details::get_all_platforms_root),
258+
)
259+
.route(
260+
"/-/menus/platforms/crate/:name/:version/source/*path",
261+
get_internal(super::crate_details::get_all_platforms_root),
242262
)
243263
.route(
244264
"/-/menus/platforms/crate/:name/:version/:target",

src/web/rustdoc.rs

-2
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,7 @@ pub(crate) struct RustdocHtmlParams {
357357
// both target and path are only used for matching the route.
358358
// The actual path is read from the request `Uri` because
359359
// we have some static filenames directly in the routes.
360-
#[allow(dead_code)]
361360
pub(crate) target: Option<String>,
362-
#[allow(dead_code)]
363361
pub(crate) path: Option<String>,
364362
}
365363

templates/rustdoc/topbar.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@
209209

210210
{# Build the dropdown list showing available targets #}
211211
<ul class="pure-menu-children" id="platforms">
212-
{%- if metadata.doc_targets|length < DEFAULT_MAX_TARGETS -%}
212+
{%- if metadata.doc_targets|length < 5 -%}
213213
{%- include "rustdoc/platforms.html" -%}
214214
{%- else -%}
215215
<span class="rotate">{{ "spinner" | fas }}</span>

0 commit comments

Comments
 (0)