Ver código fonte

LibWeb: Make MimeSniff::MimeType::parse() infallible

It already returns an empty Optional for failures, so there's no need to
wrap it in an ErrorOr as well.
Andreas Kling 9 meses atrás
pai
commit
5c20bc2afc

+ 9 - 9
Tests/LibWeb/TestMimeSniff.cpp

@@ -38,7 +38,7 @@ TEST_CASE(determine_computed_mime_type_given_no_sniff_is_unset)
 TEST_CASE(determine_computed_mime_type_given_xml_mime_type_as_supplied_type)
 {
     auto xml_mime_type = "application/rss+xml"sv;
-    auto supplied_type = MUST(Web::MimeSniff::MimeType::parse(xml_mime_type)).release_value();
+    auto supplied_type = Web::MimeSniff::MimeType::parse(xml_mime_type).release_value();
     auto computed_mime_type = MUST(Web::MimeSniff::Resource::sniff("\x00"sv.bytes(), Web::MimeSniff::SniffingConfiguration { .supplied_type = supplied_type }));
 
     EXPECT_EQ(xml_mime_type, computed_mime_type.serialized());
@@ -85,7 +85,7 @@ TEST_CASE(determine_computed_mime_type_given_supplied_type_that_is_an_apache_bug
 
     // Cover all Apache bug MIME types.
     for (auto const& apache_bug_mime_type : apache_bug_mime_types) {
-        auto supplied_type = MUST(Web::MimeSniff::MimeType::parse(apache_bug_mime_type)).release_value();
+        auto supplied_type = Web::MimeSniff::MimeType::parse(apache_bug_mime_type).release_value();
         auto computed_mime_type = MUST(Web::MimeSniff::Resource::sniff("Hello world!"sv.bytes(),
             Web::MimeSniff::SniffingConfiguration { .scheme = "http"sv, .supplied_type = supplied_type }));
 
@@ -195,7 +195,7 @@ TEST_CASE(determine_computed_mime_type_in_image_sniffing_context)
 {
     // Cover case where supplied type is an XML MIME type.
     auto mime_type = "application/rss+xml"sv;
-    auto supplied_type = MUST(Web::MimeSniff::MimeType::parse(mime_type)).release_value();
+    auto supplied_type = Web::MimeSniff::MimeType::parse(mime_type).release_value();
     auto computed_mime_type = MUST(Web::MimeSniff::Resource::sniff(""sv.bytes(), Web::MimeSniff::SniffingConfiguration { .sniffing_context = Web::MimeSniff::SniffingContext::Image, .supplied_type = supplied_type }));
 
     EXPECT_EQ(mime_type, computed_mime_type.serialized());
@@ -218,7 +218,7 @@ TEST_CASE(determine_computed_mime_type_in_image_sniffing_context)
 
     // Cover case where we aren't dealing with an image MIME type.
     mime_type = "text/html"sv;
-    supplied_type = MUST(Web::MimeSniff::MimeType::parse("text/html"sv)).release_value();
+    supplied_type = Web::MimeSniff::MimeType::parse("text/html"sv).release_value();
     computed_mime_type = MUST(Web::MimeSniff::Resource::sniff(""sv.bytes(), Web::MimeSniff::SniffingConfiguration { .sniffing_context = Web::MimeSniff::SniffingContext::Image, .supplied_type = supplied_type }));
 
     EXPECT_EQ(mime_type, computed_mime_type.essence());
@@ -228,7 +228,7 @@ TEST_CASE(determine_computed_mime_type_in_audio_or_video_sniffing_context)
 {
     // Cover case where supplied type is an XML MIME type.
     auto mime_type = "application/rss+xml"sv;
-    auto supplied_type = MUST(Web::MimeSniff::MimeType::parse(mime_type)).release_value();
+    auto supplied_type = Web::MimeSniff::MimeType::parse(mime_type).release_value();
     auto computed_mime_type = MUST(Web::MimeSniff::Resource::sniff(""sv.bytes(), Web::MimeSniff::SniffingConfiguration {
                                                                                      .sniffing_context = Web::MimeSniff::SniffingContext::AudioOrVideo,
                                                                                      .supplied_type = supplied_type,
@@ -253,7 +253,7 @@ TEST_CASE(determine_computed_mime_type_in_audio_or_video_sniffing_context)
 
     // Cover case where we aren't dealing with an audio or video MIME type.
     mime_type = "text/html"sv;
-    supplied_type = MUST(Web::MimeSniff::MimeType::parse("text/html"sv)).release_value();
+    supplied_type = Web::MimeSniff::MimeType::parse("text/html"sv).release_value();
     computed_mime_type = MUST(Web::MimeSniff::Resource::sniff(""sv.bytes(), Web::MimeSniff::SniffingConfiguration {
                                                                                 .sniffing_context = Web::MimeSniff::SniffingContext::AudioOrVideo,
                                                                                 .supplied_type = supplied_type,
@@ -299,7 +299,7 @@ TEST_CASE(determine_computed_mime_type_in_a_font_context)
 {
     // Cover case where supplied type is an XML MIME type.
     auto mime_type = "application/rss+xml"sv;
-    auto supplied_type = MUST(Web::MimeSniff::MimeType::parse(mime_type)).release_value();
+    auto supplied_type = Web::MimeSniff::MimeType::parse(mime_type).release_value();
     auto computed_mime_type = MUST(Web::MimeSniff::Resource::sniff(""sv.bytes(), Web::MimeSniff::SniffingConfiguration {
                                                                                      .sniffing_context = Web::MimeSniff::SniffingContext::Font,
                                                                                      .supplied_type = supplied_type,
@@ -327,7 +327,7 @@ TEST_CASE(determine_computed_mime_type_in_a_font_context)
 
     // Cover case where we aren't dealing with a font MIME type.
     mime_type = "text/html"sv;
-    supplied_type = MUST(Web::MimeSniff::MimeType::parse("text/html"sv)).release_value();
+    supplied_type = Web::MimeSniff::MimeType::parse("text/html"sv).release_value();
     computed_mime_type = MUST(Web::MimeSniff::Resource::sniff(""sv.bytes(), Web::MimeSniff::SniffingConfiguration {
                                                                                 .sniffing_context = Web::MimeSniff::SniffingContext::Font,
                                                                                 .supplied_type = supplied_type,
@@ -374,7 +374,7 @@ TEST_CASE(determine_minimised_mime_type)
     mime_type_to_minimised_mime_type_map.set("application/zip"sv, ""sv);
 
     for (auto const& mime_type_to_minimised_mime_type : mime_type_to_minimised_mime_type_map) {
-        auto mime_type = MUST(Web::MimeSniff::MimeType::parse(mime_type_to_minimised_mime_type.key)).release_value();
+        auto mime_type = Web::MimeSniff::MimeType::parse(mime_type_to_minimised_mime_type.key).release_value();
         EXPECT_EQ(mime_type_to_minimised_mime_type.value, Web::MimeSniff::minimise_a_supported_mime_type(mime_type));
     }
 }

+ 1 - 1
Userland/Libraries/LibWeb/CSS/StyleComputer.cpp

@@ -181,7 +181,7 @@ void FontLoader::start_loading_next_url()
 ErrorOr<NonnullRefPtr<Gfx::Typeface>> FontLoader::try_load_font()
 {
     // FIXME: This could maybe use the format() provided in @font-face as well, since often the mime type is just application/octet-stream and we have to try every format
-    auto mime_type = MUST(MimeSniff::MimeType::parse(resource()->mime_type()));
+    auto mime_type = MimeSniff::MimeType::parse(resource()->mime_type());
     if (!mime_type.has_value() || !mime_type->is_font()) {
         mime_type = MUST(MimeSniff::Resource::sniff(resource()->encoded_data(), Web::MimeSniff::SniffingConfiguration { .sniffing_context = Web::MimeSniff::SniffingContext::Font }));
     }

+ 1 - 1
Userland/Libraries/LibWeb/Clipboard/Clipboard.cpp

@@ -44,7 +44,7 @@ void Clipboard::initialize(JS::Realm& realm)
 static String os_specific_well_known_format(StringView mime_type_string)
 {
     // NOTE: Here we always takes the Linux case, and defer to the chrome layer to handle OS specific implementations.
-    auto mime_type = MUST(MimeSniff::MimeType::parse(mime_type_string));
+    auto mime_type = MimeSniff::MimeType::parse(mime_type_string);
 
     // 1. Let wellKnownFormat be an empty string.
     String well_known_format {};

+ 2 - 2
Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.cpp

@@ -365,7 +365,7 @@ Optional<MimeSniff::MimeType> HeaderList::extract_mime_type() const
     // 6. For each value of values:
     for (auto const& value : *values) {
         // 1. Let temporaryMimeType be the result of parsing value.
-        auto temporary_mime_type = MUST(MimeSniff::MimeType::parse(value));
+        auto temporary_mime_type = MimeSniff::MimeType::parse(value);
 
         // 2. If temporaryMimeType is failure or its essence is "*/*", then continue.
         if (!temporary_mime_type.has_value() || temporary_mime_type->essence() == "*/*"sv)
@@ -523,7 +523,7 @@ bool is_cors_safelisted_request_header(Header const& header)
             return false;
 
         // 2. Let mimeType be the result of parsing the result of isomorphic decoding value.
-        auto mime_type = MimeSniff::MimeType::parse(StringView { value }).release_value_but_fixme_should_propagate_errors();
+        auto mime_type = MimeSniff::MimeType::parse(StringView { value });
 
         // 3. If mimeType is failure, then return false.
         if (!mime_type.has_value())

+ 1 - 1
Userland/Libraries/LibWeb/Fetch/Infrastructure/URL.cpp

@@ -97,7 +97,7 @@ ErrorOr<DataURL> process_data_url(URL::URL const& data_url)
     }
 
     // 13. Let mimeTypeRecord be the result of parsing mimeType.
-    auto mime_type_record = TRY(MimeSniff::MimeType::parse(mime_type));
+    auto mime_type_record = MimeSniff::MimeType::parse(mime_type);
 
     // 14. If mimeTypeRecord is failure, then set mimeTypeRecord to text/plain;charset=US-ASCII.
     if (!mime_type_record.has_value()) {

+ 1 - 1
Userland/Libraries/LibWeb/FileAPI/Blob.cpp

@@ -204,7 +204,7 @@ JS::NonnullGCPtr<Blob> Blob::create(JS::Realm& realm, Optional<Vector<BlobPart>>
 
         // NOTE: The spec is out of date, and we are supposed to call into the MimeType parser here.
         if (!options->type.is_empty()) {
-            auto maybe_parsed_type = MUST(Web::MimeSniff::MimeType::parse(options->type));
+            auto maybe_parsed_type = Web::MimeSniff::MimeType::parse(options->type);
 
             if (maybe_parsed_type.has_value())
                 type = maybe_parsed_type->serialized();

+ 1 - 1
Userland/Libraries/LibWeb/FileAPI/File.cpp

@@ -62,7 +62,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<File>> File::create(JS::Realm& realm, Vecto
         // FIXME: 2. Convert every character in t to ASCII lowercase.
 
         // NOTE: The spec is out of date, and we are supposed to call into the MimeType parser here.
-        auto maybe_parsed_type = MUST(Web::MimeSniff::MimeType::parse(options->type));
+        auto maybe_parsed_type = Web::MimeSniff::MimeType::parse(options->type);
 
         if (maybe_parsed_type.has_value())
             type = maybe_parsed_type->serialized();

+ 2 - 2
Userland/Libraries/LibWeb/FileAPI/FileReader.cpp

@@ -86,8 +86,8 @@ WebIDL::ExceptionOr<FileReader::Result> FileReader::blob_package_data(JS::Realm&
             auto maybe_type = MimeSniff::MimeType::parse(mime_type.value());
 
             // 2. If type is not failure, set encoding to the result of getting an encoding from type’s parameters["charset"].
-            if (!maybe_type.is_error() && maybe_type.value().has_value()) {
-                auto type = maybe_type.release_value().value();
+            if (maybe_type.has_value()) {
+                auto const& type = maybe_type.value();
                 auto it = type.parameters().find("charset"sv);
                 if (it != type.parameters().end())
                     encoding = TextCodec::get_standardized_encoding(it->value);

+ 1 - 1
Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp

@@ -235,7 +235,7 @@ FileFilter HTMLInputElement::parse_accept_attribute() const
 
         // A valid MIME type string with no parameters
         //     Indicates that files of the specified type are accepted.
-        else if (auto mime_type = MUST(MimeSniff::MimeType::parse(value)); mime_type.has_value() && mime_type->parameters().is_empty())
+        else if (auto mime_type = MimeSniff::MimeType::parse(value); mime_type.has_value() && mime_type->parameters().is_empty())
             filter.add_filter(FileFilter::MimeType { mime_type->essence() });
 
         // A string whose first character is a U+002E FULL STOP character (.)

+ 1 - 1
Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp

@@ -186,7 +186,7 @@ Bindings::CanPlayTypeResult HTMLMediaElement::can_play_type(StringView type) con
     if (type == "application/octet-stream"sv)
         return Bindings::CanPlayTypeResult::Empty;
 
-    auto mime_type = MUST(MimeSniff::MimeType::parse(type));
+    auto mime_type = MimeSniff::MimeType::parse(type);
 
     if (mime_type.has_value() && mime_type->type() == "video"sv) {
         if (mime_type->subtype() == "webm"sv)

+ 2 - 2
Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp

@@ -246,7 +246,7 @@ void HTMLObjectElement::resource_did_load()
 
         // 2. If the type specified in the resource's Content-Type metadata is "text/plain", and the result of applying the rules for distinguishing if a resource is text or binary to the resource is that the resource is not text/plain, then set binary to true.
         if (content_type == "text/plain"sv) {
-            auto supplied_type = MimeSniff::MimeType::parse(content_type).release_value_but_fixme_should_propagate_errors();
+            auto supplied_type = MimeSniff::MimeType::parse(content_type);
             auto computed_type = MimeSniff::Resource::sniff(resource()->encoded_data(), MimeSniff::SniffingConfiguration {
                                                                                             .sniffing_context = MimeSniff::SniffingContext::TextOrBinary,
                                                                                             .supplied_type = move(supplied_type),
@@ -311,7 +311,7 @@ void HTMLObjectElement::run_object_representation_handler_steps(Optional<ByteStr
         run_object_representation_fallback_steps();
         return;
     }
-    auto mime_type = MimeSniff::MimeType::parse(*resource_type).release_value_but_fixme_should_propagate_errors();
+    auto mime_type = MimeSniff::MimeType::parse(*resource_type);
 
     // * If the resource type is an XML MIME type, or if the resource type does not start with "image/"
     if (mime_type.has_value() && can_load_document_with_type(*mime_type) && (mime_type->is_xml() || !mime_type->is_image())) {

+ 11 - 7
Userland/Libraries/LibWeb/MimeSniff/MimeType.cpp

@@ -23,7 +23,7 @@ bool is_javascript_mime_type_essence_match(StringView string)
 {
     // A string is a JavaScript MIME type essence match if it is an ASCII case-insensitive match for one of the JavaScript MIME type essence strings.
     // NOTE: The mime type parser automatically lowercases the essence.
-    auto type = MimeType::parse(string).release_value_but_fixme_should_propagate_errors();
+    auto type = MimeType::parse(string);
     if (!type.has_value())
         return false;
     return type->is_javascript();
@@ -81,8 +81,12 @@ MimeType MimeType::create(String type, String subtype)
 }
 
 // https://mimesniff.spec.whatwg.org/#parse-a-mime-type
-ErrorOr<Optional<MimeType>> MimeType::parse(StringView string)
+Optional<MimeType> MimeType::parse(StringView string)
 {
+    // Verify that the input string is valid UTF-8 first, so we don't have to think about it anymore.
+    if (!Utf8View(string).validate())
+        return OptionalNone {};
+
     // 1. Remove any leading and trailing HTTP whitespace from input.
     auto trimmed_string = string.trim(Fetch::Infrastructure::HTTP_WHITESPACE, TrimMode::Both);
 
@@ -114,7 +118,7 @@ ErrorOr<Optional<MimeType>> MimeType::parse(StringView string)
         return OptionalNone {};
 
     // 10. Let mimeType be a new MIME type record whose type is type, in ASCII lowercase, and subtype is subtype, in ASCII lowercase.
-    auto mime_type = MimeType::create(TRY(Infra::to_ascii_lowercase(type)), TRY(Infra::to_ascii_lowercase(subtype)));
+    auto mime_type = MimeType::create(MUST(Infra::to_ascii_lowercase(type)), MUST(Infra::to_ascii_lowercase(subtype)));
 
     // 11. While position is not past the end of input:
     while (!lexer.is_eof()) {
@@ -130,7 +134,7 @@ ErrorOr<Optional<MimeType>> MimeType::parse(StringView string)
         });
 
         // 4. Set parameterName to parameterName, in ASCII lowercase.
-        auto parameter_name = TRY(Infra::to_ascii_lowercase(parameter_name_view));
+        auto parameter_name = MUST(Infra::to_ascii_lowercase(parameter_name_view));
 
         // 5. If position is not past the end of input, then:
         if (!lexer.is_eof()) {
@@ -162,10 +166,10 @@ ErrorOr<Optional<MimeType>> MimeType::parse(StringView string)
         // 9. Otherwise:
         else {
             // 1. Set parameterValue to the result of collecting a sequence of code points that are not U+003B (;) from input, given position.
-            parameter_value = TRY(String::from_utf8(lexer.consume_until(';')));
+            parameter_value = String::from_utf8_without_validation(lexer.consume_until(';').bytes());
 
             // 2. Remove any trailing HTTP whitespace from parameterValue.
-            parameter_value = TRY(parameter_value.trim(Fetch::Infrastructure::HTTP_WHITESPACE, TrimMode::Right));
+            parameter_value = MUST(parameter_value.trim(Fetch::Infrastructure::HTTP_WHITESPACE, TrimMode::Right));
 
             // 3. If parameterValue is the empty string, then continue.
             if (parameter_value.is_empty())
@@ -183,7 +187,7 @@ ErrorOr<Optional<MimeType>> MimeType::parse(StringView string)
             // - mimeType’s parameters[parameterName] does not exist
             && !mime_type.m_parameters.contains(parameter_name)) {
             // then set mimeType’s parameters[parameterName] to parameterValue.
-            TRY(mime_type.m_parameters.try_set(move(parameter_name), move(parameter_value)));
+            mime_type.m_parameters.set(move(parameter_name), move(parameter_value));
         }
     }
 

+ 2 - 2
Userland/Libraries/LibWeb/MimeSniff/MimeType.h

@@ -17,8 +17,8 @@ bool is_javascript_mime_type_essence_match(StringView);
 // https://mimesniff.spec.whatwg.org/#mime-type
 class MimeType {
 public:
-    static MimeType create(String type, String subtype);
-    static ErrorOr<Optional<MimeType>> parse(StringView);
+    [[nodiscard]] static MimeType create(String type, String subtype);
+    [[nodiscard]] static Optional<MimeType> parse(StringView);
 
     MimeType(MimeType const&);
     MimeType& operator=(MimeType const&);

+ 2 - 2
Userland/Libraries/LibWeb/MimeSniff/Resource.cpp

@@ -388,7 +388,7 @@ ErrorOr<MimeType> rules_for_identifying_an_unknown_mime_type(Resource const& res
 
             // 2. If patternMatched is true, return the value in the fourth column of row.
             if (pattern_matched) {
-                if (auto maybe_type = TRY(MimeType::parse(row.mime_type)); maybe_type.has_value())
+                if (auto maybe_type = MimeType::parse(row.mime_type); maybe_type.has_value())
                     return maybe_type.release_value();
             }
         }
@@ -419,7 +419,7 @@ ErrorOr<MimeType> rules_for_identifying_an_unknown_mime_type(Resource const& res
 
         // 2. If patternMatched is true, return the value in the fourth column of row.
         if (pattern_matched) {
-            if (auto maybe_type = TRY(MimeType::parse(row.mime_type)); maybe_type.has_value())
+            if (auto maybe_type = MimeType::parse(row.mime_type); maybe_type.has_value())
                 return maybe_type.release_value();
         }
     }

+ 2 - 4
Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp

@@ -594,7 +594,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
             // 1. If body is a Document or a USVString, then:
             if (body->has<JS::Handle<DOM::Document>>() || body->has<String>()) {
                 // 1. Let contentTypeRecord be the result of parsing originalAuthorContentType.
-                auto content_type_record = TRY_OR_THROW_OOM(vm, MimeSniff::MimeType::parse(original_author_content_type.value()));
+                auto content_type_record = MimeSniff::MimeType::parse(original_author_content_type.value());
 
                 // 2. If contentTypeRecord is not failure, contentTypeRecord’s parameters["charset"] exists, and parameters["charset"] is not an ASCII case-insensitive match for "UTF-8", then:
                 if (content_type_record.has_value()) {
@@ -1028,14 +1028,12 @@ WebIDL::ExceptionOr<String> XMLHttpRequest::get_all_response_headers() const
 // https://xhr.spec.whatwg.org/#dom-xmlhttprequest-overridemimetype
 WebIDL::ExceptionOr<void> XMLHttpRequest::override_mime_type(String const& mime)
 {
-    auto& vm = this->vm();
-
     // 1. If this’s state is loading or done, then throw an "InvalidStateError" DOMException.
     if (m_state == State::Loading || m_state == State::Done)
         return WebIDL::InvalidStateError::create(realm(), "Cannot override MIME type when state is Loading or Done."_string);
 
     // 2. Set this’s override MIME type to the result of parsing mime.
-    m_override_mime_type = TRY_OR_THROW_OOM(vm, MimeSniff::MimeType::parse(mime));
+    m_override_mime_type = MimeSniff::MimeType::parse(mime);
 
     // 3. If this’s override MIME type is failure, then set this’s override MIME type to application/octet-stream.
     if (!m_override_mime_type.has_value())