diff --git a/Tests/LibWeb/Text/expected/css/style-sheet-with-byte-order-mark.txt b/Tests/LibWeb/Text/expected/css/style-sheet-with-byte-order-mark.txt
new file mode 100644
index 0000000000..ba69e3e181
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/css/style-sheet-with-byte-order-mark.txt
@@ -0,0 +1 @@
+PASS
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/input/css/style-sheet-with-byte-order-mark.css b/Tests/LibWeb/Text/input/css/style-sheet-with-byte-order-mark.css
new file mode 100644
index 0000000000..9ab1f3a39c
--- /dev/null
+++ b/Tests/LibWeb/Text/input/css/style-sheet-with-byte-order-mark.css
@@ -0,0 +1,7 @@
+.pass {
+ display: block;
+}
+
+div {
+ display: none;
+}
diff --git a/Tests/LibWeb/Text/input/css/style-sheet-with-byte-order-mark.html b/Tests/LibWeb/Text/input/css/style-sheet-with-byte-order-mark.html
new file mode 100644
index 0000000000..08274e9a83
--- /dev/null
+++ b/Tests/LibWeb/Text/input/css/style-sheet-with-byte-order-mark.html
@@ -0,0 +1 @@
+
PASS
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.cpp
index d4512833b7..be46859861 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.cpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -341,18 +342,41 @@ void HTMLLinkElement::process_stylesheet_resource(bool success, Fetch::Infrastru
// The CSS environment encoding is the result of running the following steps: [CSSSYNTAX]
// 1. If the element has a charset attribute, get an encoding from that attribute's value. If that succeeds, return the resulting encoding. [ENCODING]
// 2. Otherwise, return the document's character encoding. [DOM]
- m_loaded_style_sheet = parse_css_stylesheet(CSS::Parser::ParsingContext(document(), *response.url()), body_bytes.template get());
- if (m_loaded_style_sheet) {
- m_loaded_style_sheet->set_owner_node(this);
- m_loaded_style_sheet->set_media(attribute(HTML::AttributeNames::media));
- document().style_sheets().add_sheet(*m_loaded_style_sheet);
+ DeprecatedString encoding;
+ if (auto charset = attribute(HTML::AttributeNames::charset); !charset.is_null())
+ encoding = charset;
+ else
+ encoding = document().encoding_or_default();
+
+ auto decoder = TextCodec::decoder_for(encoding);
+
+ if (!decoder.has_value()) {
+ // If we don't support the encoding yet, let's error out instead of trying to decode it as something it's most likely not.
+ dbgln("FIXME: Style sheet encoding '{}' is not supported yet", encoding);
+ dispatch_event(*DOM::Event::create(realm(), HTML::EventNames::error).release_value_but_fixme_should_propagate_errors());
} else {
- dbgln_if(CSS_LOADER_DEBUG, "HTMLLinkElement: Failed to parse stylesheet: {}", resource()->url());
- }
+ auto const& encoded_string = body_bytes.get();
+ auto maybe_decoded_string = TextCodec::convert_input_to_utf8_using_given_decoder_unless_there_is_a_byte_order_mark(*decoder, encoded_string);
+ if (maybe_decoded_string.is_error()) {
+ dbgln("Style sheet {} claimed to be '{}' but decoding failed", response.url().value_or(AK::URL()), encoding);
+ dispatch_event(*DOM::Event::create(realm(), HTML::EventNames::error).release_value_but_fixme_should_propagate_errors());
+ } else {
+ auto const decoded_string = maybe_decoded_string.release_value();
+ m_loaded_style_sheet = parse_css_stylesheet(CSS::Parser::ParsingContext(document(), *response.url()), decoded_string);
- // 2. Fire an event named load at el.
- dispatch_event(*DOM::Event::create(realm(), HTML::EventNames::load).release_value_but_fixme_should_propagate_errors());
+ if (m_loaded_style_sheet) {
+ m_loaded_style_sheet->set_owner_node(this);
+ m_loaded_style_sheet->set_media(attribute(HTML::AttributeNames::media));
+ document().style_sheets().add_sheet(*m_loaded_style_sheet);
+ } else {
+ dbgln_if(CSS_LOADER_DEBUG, "HTMLLinkElement: Failed to parse stylesheet: {}", resource()->url());
+ }
+
+ // 2. Fire an event named load at el.
+ dispatch_event(*DOM::Event::create(realm(), HTML::EventNames::load).release_value_but_fixme_should_propagate_errors());
+ }
+ }
}
// 5. Otherwise, fire an event named error at el.
else {