mirror of
https://github.com/servo/servo.git
synced 2025-06-10 01:23:13 +00:00
* Properly store link relations Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Send fetch request for prefetch links We don't actually *do* anything with the response yet (handle errors etc) but its a first step. Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Fire load/error events for prefetch loads Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Set prefetch destination/cors setting correctly Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update WPT expectations Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Fix ./mach test-tidy errors Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Set correct "Accept" value for prefetch requests Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Add spec text to individual steps Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
131 lines
4.9 KiB
Rust
131 lines
4.9 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use html5ever::{local_name, namespace_url, ns};
|
|
use malloc_size_of::malloc_size_of_is_0;
|
|
use style::str::HTML_SPACE_CHARACTERS;
|
|
|
|
use crate::dom::types::Element;
|
|
|
|
bitflags::bitflags! {
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct LinkRelations: u32 {
|
|
const ALTERNATE = 1;
|
|
const AUTHOR = 1 << 1;
|
|
const BOOKMARK = 1 << 2;
|
|
const CANONICAL = 1 << 3;
|
|
const DNS_PREFETCH = 1 << 4;
|
|
const EXPECT = 1 << 5;
|
|
const EXTERNAL = 1 << 6;
|
|
const HELP = 1 << 7;
|
|
const ICON = 1 << 8;
|
|
const LICENSE = 1 << 9;
|
|
const NEXT = 1 << 10;
|
|
const MANIFEST = 1 << 11;
|
|
const MODULE_PRELOAD = 1 << 12;
|
|
const NO_FOLLOW = 1 << 13;
|
|
const NO_OPENER = 1 << 14;
|
|
const NO_REFERRER = 1 << 15;
|
|
const OPENER = 1 << 16;
|
|
const PING_BACK = 1 << 17;
|
|
const PRECONNECT = 1 << 18;
|
|
const PREFETCH = 1 << 19;
|
|
const PRELOAD = 1 << 20;
|
|
const PREV = 1 << 21;
|
|
const PRIVACY_POLICY = 1 << 22;
|
|
const SEARCH = 1 << 23;
|
|
const STYLESHEET = 1 << 24;
|
|
const TAG = 1 << 25;
|
|
const TermsOfService = 1 << 26;
|
|
}
|
|
}
|
|
|
|
impl LinkRelations {
|
|
pub fn for_element(element: &Element) -> Self {
|
|
let rel = element.get_attribute(&ns!(), &local_name!("rel")).map(|e| {
|
|
let value = e.value();
|
|
(**value).to_owned()
|
|
});
|
|
|
|
// FIXME: for a, area and form elements we need to allow a different
|
|
// set of attributes
|
|
let mut relations = rel
|
|
.map(|attribute| {
|
|
attribute
|
|
.split(HTML_SPACE_CHARACTERS)
|
|
.map(Self::from_single_keyword_for_link_element)
|
|
.collect()
|
|
})
|
|
.unwrap_or(Self::empty());
|
|
|
|
// For historical reasons, "rev=made" is treated as if the "author" relation was specified
|
|
let has_legacy_author_relation = element
|
|
.get_attribute(&ns!(), &local_name!("rev"))
|
|
.is_some_and(|rev| &**rev.value() == "made");
|
|
if has_legacy_author_relation {
|
|
relations |= Self::AUTHOR;
|
|
}
|
|
|
|
relations
|
|
}
|
|
|
|
/// Parse one of the relations allowed for the `<link>` element
|
|
///
|
|
/// If the keyword is invalid then `Self::empty` is returned.
|
|
fn from_single_keyword_for_link_element(keyword: &str) -> Self {
|
|
if keyword.eq_ignore_ascii_case("alternate") {
|
|
Self::ALTERNATE
|
|
} else if keyword.eq_ignore_ascii_case("canonical") {
|
|
Self::CANONICAL
|
|
} else if keyword.eq_ignore_ascii_case("author") {
|
|
Self::AUTHOR
|
|
} else if keyword.eq_ignore_ascii_case("dns-prefetch") {
|
|
Self::DNS_PREFETCH
|
|
} else if keyword.eq_ignore_ascii_case("expect") {
|
|
Self::EXPECT
|
|
} else if keyword.eq_ignore_ascii_case("help") {
|
|
Self::HELP
|
|
} else if keyword.eq_ignore_ascii_case("icon") ||
|
|
keyword.eq_ignore_ascii_case("shortcut icon") ||
|
|
keyword.eq_ignore_ascii_case("apple-touch-icon")
|
|
{
|
|
// TODO: "apple-touch-icon" is not in the spec. Where did it come from? Do we need it?
|
|
// There is also "apple-touch-icon-precomposed" listed in
|
|
// https://github.com/servo/servo/blob/e43e4778421be8ea30db9d5c553780c042161522/components/script/dom/htmllinkelement.rs#L452-L467
|
|
Self::ICON
|
|
} else if keyword.eq_ignore_ascii_case("manifest") {
|
|
Self::MANIFEST
|
|
} else if keyword.eq_ignore_ascii_case("modulepreload") {
|
|
Self::MODULE_PRELOAD
|
|
} else if keyword.eq_ignore_ascii_case("license") ||
|
|
keyword.eq_ignore_ascii_case("copyright")
|
|
{
|
|
Self::LICENSE
|
|
} else if keyword.eq_ignore_ascii_case("next") {
|
|
Self::NEXT
|
|
} else if keyword.eq_ignore_ascii_case("pingback") {
|
|
Self::PING_BACK
|
|
} else if keyword.eq_ignore_ascii_case("preconnect") {
|
|
Self::PRECONNECT
|
|
} else if keyword.eq_ignore_ascii_case("prefetch") {
|
|
Self::PREFETCH
|
|
} else if keyword.eq_ignore_ascii_case("preload") {
|
|
Self::PRELOAD
|
|
} else if keyword.eq_ignore_ascii_case("prev") || keyword.eq_ignore_ascii_case("previous") {
|
|
Self::PREV
|
|
} else if keyword.eq_ignore_ascii_case("privacy-policy") {
|
|
Self::PRIVACY_POLICY
|
|
} else if keyword.eq_ignore_ascii_case("search") {
|
|
Self::SEARCH
|
|
} else if keyword.eq_ignore_ascii_case("stylesheet") {
|
|
Self::STYLESHEET
|
|
} else if keyword.eq_ignore_ascii_case("terms-of-service") {
|
|
Self::TermsOfService
|
|
} else {
|
|
Self::empty()
|
|
}
|
|
}
|
|
}
|
|
|
|
malloc_size_of_is_0!(LinkRelations);
|