mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:47:47 +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:
parent
f27b9b9563
commit
eb41f0144b
9 changed files with 172 additions and 165 deletions
|
@ -714,17 +714,15 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
|
|||
// -> "data"
|
||||
else if (request->current_url().scheme() == "data"sv) {
|
||||
// 1. Let dataURLStruct be the result of running the data: URL processor on request’s current URL.
|
||||
auto const& url = request->current_url();
|
||||
auto data_or_error = url.data_payload_is_base64()
|
||||
? decode_base64(url.data_payload())
|
||||
: TRY_OR_THROW_OOM(vm, ByteBuffer::copy(url.data_payload().bytes()));
|
||||
auto data_url_struct = request->current_url().process_data_url();
|
||||
|
||||
// 2. If dataURLStruct is failure, then return a network error.
|
||||
if (data_or_error.is_error())
|
||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has invalid base64 'data:' URL"sv));
|
||||
if (data_url_struct.is_error())
|
||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Failed to process 'data:' URL"sv));
|
||||
|
||||
// 3. Let mimeType be dataURLStruct’s MIME type, serialized.
|
||||
auto const& mime_type = url.data_mime_type();
|
||||
// FIXME: Serialize MIME type.
|
||||
auto const& mime_type = data_url_struct.value().mime_type;
|
||||
|
||||
// 4. Return a new response whose status message is `OK`, header list is « (`Content-Type`, mimeType) », and
|
||||
// body is dataURLStruct’s body as a body.
|
||||
|
@ -732,7 +730,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
|
|||
response->set_status_message(MUST(ByteBuffer::copy("OK"sv.bytes())));
|
||||
auto header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Content-Type"sv, mime_type));
|
||||
TRY_OR_THROW_OOM(vm, response->header_list()->append(move(header)));
|
||||
response->set_body(TRY(Infrastructure::byte_sequence_as_body(realm, data_or_error.value().span())));
|
||||
response->set_body(TRY(Infrastructure::byte_sequence_as_body(realm, data_url_struct.value().body)));
|
||||
return PendingResponse::create(vm, request, response);
|
||||
}
|
||||
// -> "file"
|
||||
|
|
|
@ -195,7 +195,7 @@ DeprecatedString HTMLCanvasElement::to_data_url(DeprecatedString const& type, [[
|
|||
// FIXME: propagate error
|
||||
return {};
|
||||
}
|
||||
return AK::URL::create_with_data(type, base64_encoded_or_error.release_value().to_deprecated_string(), true).to_deprecated_string();
|
||||
return AK::URL::create_with_data(type, base64_encoded_or_error.release_value(), true).to_deprecated_string();
|
||||
}
|
||||
|
||||
void HTMLCanvasElement::present()
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue