Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/librustdoc/html/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use super::static_files::{STATIC_FILES, StaticFiles};
use crate::externalfiles::ExternalHtml;
use crate::html::render::{StylePath, ensure_trailing_slash};

#[cfg(test)]
mod tests;

pub(crate) struct Layout {
pub(crate) logo: String,
pub(crate) favicon: String,
Expand Down Expand Up @@ -68,6 +71,13 @@ struct PageLayout<'a> {
display_krate_version_extra: &'a str,
}

impl PageLayout<'_> {
/// See [`may_remove_crossorigin`].
fn static_root_path_may_remove_crossorigin(&self) -> bool {
may_remove_crossorigin(&self.static_root_path)
}
}

pub(crate) use crate::html::render::sidebar::filters;

pub(crate) fn render<T: Display, S: Display>(
Expand Down Expand Up @@ -134,3 +144,22 @@ pub(crate) fn redirect(url: &str) -> String {
</html>"##,
)
}

/// Conservatively determines if `href` is relative to the current origin,
/// so that `crossorigin` may be safely removed from `<link>` elements.
pub(crate) fn may_remove_crossorigin(href: &str) -> bool {
// Reject scheme-relative URLs (`//example.com/`).
if href.starts_with("//") {
return false;
}
// URL is interpreted as having a scheme iff: it starts with an ascii alpha, and only
// contains ascii alphanumeric or `+` `-` `.` up to the `:`.
// https://url.spec.whatwg.org/#url-parsing
let has_scheme = href.split_once(':').is_some_and(|(scheme, _rest)| {
let mut chars = scheme.chars();
chars.next().is_some_and(|c| c.is_ascii_alphabetic())
&& chars.all(|c| c.is_ascii_alphanumeric() || c == '+' || c == '-' || c == '.')
});
// Reject anything with a scheme (`http:`, etc.).
!has_scheme
}
24 changes: 24 additions & 0 deletions src/librustdoc/html/layout/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#[test]
fn test_may_remove_crossorigin() {
use super::may_remove_crossorigin;

assert!(may_remove_crossorigin("font.woff2"));
assert!(may_remove_crossorigin("/font.woff2"));
assert!(may_remove_crossorigin("./font.woff2"));
assert!(may_remove_crossorigin(":D/font.woff2"));
assert!(may_remove_crossorigin("../font.woff2"));

assert!(!may_remove_crossorigin("//example.com/static.files"));
assert!(!may_remove_crossorigin("http://example.com/static.files"));
assert!(!may_remove_crossorigin("https://example.com/static.files"));
assert!(!may_remove_crossorigin("https://example.com:8080/static.files"));

assert!(!may_remove_crossorigin("ftp://example.com/static.files"));
assert!(!may_remove_crossorigin("blob:http://example.com/static.files"));
assert!(!may_remove_crossorigin("javascript:alert('Hello, world!')"));
assert!(!may_remove_crossorigin("//./C:"));
assert!(!may_remove_crossorigin("file:////C:"));
assert!(!may_remove_crossorigin("file:///./C:"));
assert!(!may_remove_crossorigin("data:,Hello%2C%20World%21"));
assert!(!may_remove_crossorigin("hi...:hello"));
}
2 changes: 1 addition & 1 deletion src/librustdoc/html/templates/page.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<meta name="description" content="{{page.description}}"> {# #}
<title>{{page.title}}</title> {# #}
<script>if(window.location.protocol!=="file:") {# Hack to skip preloading fonts locally - see #98769 #}
document.head.insertAdjacentHTML("beforeend","{{files.source_serif_4_regular}},{{files.fira_sans_italic}},{{files.fira_sans_regular}},{{files.fira_sans_medium_italic}},{{files.fira_sans_medium}},{{files.source_code_pro_regular}},{{files.source_code_pro_semibold}}".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}${f}">`).join("")) {# #}
document.head.insertAdjacentHTML("beforeend","{{files.source_serif_4_regular}},{{files.fira_sans_italic}},{{files.fira_sans_regular}},{{files.fira_sans_medium_italic}},{{files.fira_sans_medium}},{{files.source_code_pro_regular}},{{files.source_code_pro_semibold}}".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"{% if !static_root_path_may_remove_crossorigin() %} crossorigin{% endif %} href="{{static_root_path|safe}}${f}">`).join("")) {# #}
</script> {# #}
<link rel="stylesheet" {#+ #}
href="{{static_root_path|safe}}{{files.normalize_css}}"> {# #}
Expand Down
Loading