1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 14:45:07 +00:00

AK: Decode data URLs to separate class (and parse like every other URL)

Parsing 'data:' URLs took it's own route. It never set standard URL
fields like path, query or fragment (except for scheme) and instead
gave us separate methods called `data_payload()`, `data_mime_type()`,
and `data_payload_is_base64()`.

Because parsing 'data:' didn't use standard fields, running the
following JS code:

    new URL('#a', 'data:text/plain,hello').toString()

not only cleared the path as URLParser doesn't check for data from
data_payload() function (making the result be 'data:#a'), but it also
crashes the program because we forbid having an empty MIME type when we
serialize to string.

With this change, 'data:' URLs will be parsed like every other URLs.
To decode the 'data:' URL contents, one needs to call process_data_url()
on a URL, which will return a struct containing MIME type with already
decoded data! :^)
This commit is contained in:
Karol Kosek 2023-07-06 19:11:58 +02:00 committed by Andreas Kling
parent f27b9b9563
commit eb41f0144b
9 changed files with 172 additions and 165 deletions

View file

@ -5,7 +5,6 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Base64.h>
#include <AK/Debug.h>
#include <AK/JsonObject.h>
#include <LibCore/ElapsedTimer.h>
@ -123,7 +122,7 @@ RefPtr<Resource> ResourceLoader::load_resource(Resource::Type type, LoadRequest&
static DeprecatedString sanitized_url_for_logging(AK::URL const& url)
{
if (url.scheme() == "data"sv)
return DeprecatedString::formatted("[data URL, mime-type={}, size={}]", url.data_mime_type(), url.data_payload().length());
return "[data URL]"sv;
return url.to_deprecated_string();
}
@ -204,30 +203,25 @@ void ResourceLoader::load(LoadRequest& request, Function<void(ReadonlyBytes, Has
}
if (url.scheme() == "data") {
dbgln_if(SPAM_DEBUG, "ResourceLoader loading a data URL with mime-type: '{}', base64={}, payload='{}'",
url.data_mime_type(),
url.data_payload_is_base64(),
url.data_payload());
ByteBuffer data;
if (url.data_payload_is_base64()) {
auto data_maybe = decode_base64(url.data_payload());
if (data_maybe.is_error()) {
auto error_message = data_maybe.error().string_literal();
log_failure(request, error_message);
error_callback(error_message, {});
return;
}
data = data_maybe.value();
} else {
data = url.data_payload().to_byte_buffer();
auto data_url_or_error = url.process_data_url();
if (data_url_or_error.is_error()) {
auto error_message = data_url_or_error.error().string_literal();
log_failure(request, error_message);
error_callback(error_message, {});
return;
}
auto data_url = data_url_or_error.release_value();
dbgln_if(SPAM_DEBUG, "ResourceLoader loading a data URL with mime-type: '{}', payload='{}'",
data_url.mime_type,
StringView(data_url.body.bytes()));
HashMap<DeprecatedString, DeprecatedString, CaseInsensitiveStringTraits> response_headers;
response_headers.set("Content-Type", url.data_mime_type());
response_headers.set("Content-Type", data_url.mime_type.to_deprecated_string());
log_success(request);
Platform::EventLoopPlugin::the().deferred_invoke([data = move(data), response_headers = move(response_headers), success_callback = move(success_callback)] {
Platform::EventLoopPlugin::the().deferred_invoke([data = move(data_url.body), response_headers = move(response_headers), success_callback = move(success_callback)] {
success_callback(data, response_headers, {});
});
return;