mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 04:09:13 +00:00
LibWeb: Do not store network errors as a StringView
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
Some checks are pending
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
This is very clearly a very dangerous API to have, and was causing a crash on Linux as a result of a stack use-after-free when visiting https://www.index.hr/. Fixes #3901
This commit is contained in:
parent
82a2ae99c8
commit
a5df972055
Notes:
github-actions[bot]
2025-04-02 12:54:16 +00:00
Author: https://github.com/shannonbooth
Commit: a5df972055
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4184
10 changed files with 44 additions and 50 deletions
|
@ -104,7 +104,7 @@ GC::Ref<WebIDL::Promise> fetch(JS::VM& vm, RequestInfo const& input, RequestInit
|
||||||
|
|
||||||
// 3. If response is a network error, then reject p with a TypeError and abort these steps.
|
// 3. If response is a network error, then reject p with a TypeError and abort these steps.
|
||||||
if (response->is_network_error()) {
|
if (response->is_network_error()) {
|
||||||
auto message = response->network_error_message().value_or("Response is a network error"sv);
|
auto message = response->network_error_message().value_or("Response is a network error"_string);
|
||||||
WebIDL::reject_promise(relevant_realm, promise_capability, JS::TypeError::create(relevant_realm, message));
|
WebIDL::reject_promise(relevant_realm, promise_capability, JS::TypeError::create(relevant_realm, message));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -284,7 +284,7 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> main_fetch(JS::Realm& realm, Infra
|
||||||
// 3. If request’s local-URLs-only flag is set and request’s current URL is not local, then set response to a
|
// 3. If request’s local-URLs-only flag is set and request’s current URL is not local, then set response to a
|
||||||
// network error.
|
// network error.
|
||||||
if (request->local_urls_only() && !Infrastructure::is_local_url(request->current_url()))
|
if (request->local_urls_only() && !Infrastructure::is_local_url(request->current_url()))
|
||||||
response = Infrastructure::Response::network_error(vm, "Request with 'local-URLs-only' flag must have a local URL"sv);
|
response = Infrastructure::Response::network_error(vm, "Request with 'local-URLs-only' flag must have a local URL"_string);
|
||||||
|
|
||||||
// 4. Run report Content Security Policy violations for request.
|
// 4. Run report Content Security Policy violations for request.
|
||||||
ContentSecurityPolicy::report_content_security_policy_violations_for_request(realm, request);
|
ContentSecurityPolicy::report_content_security_policy_violations_for_request(realm, request);
|
||||||
|
@ -299,7 +299,7 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> main_fetch(JS::Realm& realm, Infra
|
||||||
if (Infrastructure::block_bad_port(request) == Infrastructure::RequestOrResponseBlocking::Blocked
|
if (Infrastructure::block_bad_port(request) == Infrastructure::RequestOrResponseBlocking::Blocked
|
||||||
|| MixedContent::should_fetching_request_be_blocked_as_mixed_content(request) == Infrastructure::RequestOrResponseBlocking::Blocked
|
|| MixedContent::should_fetching_request_be_blocked_as_mixed_content(request) == Infrastructure::RequestOrResponseBlocking::Blocked
|
||||||
|| ContentSecurityPolicy::should_request_be_blocked_by_content_security_policy(realm, request) == ContentSecurityPolicy::Directives::Directive::Result::Blocked) {
|
|| ContentSecurityPolicy::should_request_be_blocked_by_content_security_policy(realm, request) == ContentSecurityPolicy::Directives::Directive::Result::Blocked) {
|
||||||
response = Infrastructure::Response::network_error(vm, "Request was blocked"sv);
|
response = Infrastructure::Response::network_error(vm, "Request was blocked"_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. If request’s referrer policy is the empty string, then set request’s referrer policy to request’s policy
|
// 8. If request’s referrer policy is the empty string, then set request’s referrer policy to request’s policy
|
||||||
|
@ -374,13 +374,13 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> main_fetch(JS::Realm& realm, Infra
|
||||||
// -> request’s mode is "same-origin"
|
// -> request’s mode is "same-origin"
|
||||||
else if (request->mode() == Infrastructure::Request::Mode::SameOrigin) {
|
else if (request->mode() == Infrastructure::Request::Mode::SameOrigin) {
|
||||||
// Return a network error.
|
// Return a network error.
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'same-origin' mode must have same URL and request origin"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'same-origin' mode must have same URL and request origin"_string));
|
||||||
}
|
}
|
||||||
// -> request’s mode is "no-cors"
|
// -> request’s mode is "no-cors"
|
||||||
else if (request->mode() == Infrastructure::Request::Mode::NoCORS) {
|
else if (request->mode() == Infrastructure::Request::Mode::NoCORS) {
|
||||||
// 1. If request’s redirect mode is not "follow", then return a network error.
|
// 1. If request’s redirect mode is not "follow", then return a network error.
|
||||||
if (request->redirect_mode() != Infrastructure::Request::RedirectMode::Follow)
|
if (request->redirect_mode() != Infrastructure::Request::RedirectMode::Follow)
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'no-cors' mode must have redirect mode set to 'follow'"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'no-cors' mode must have redirect mode set to 'follow'"_string));
|
||||||
|
|
||||||
// 2. Set request’s response tainting to "opaque".
|
// 2. Set request’s response tainting to "opaque".
|
||||||
request->set_response_tainting(Infrastructure::Request::ResponseTainting::Opaque);
|
request->set_response_tainting(Infrastructure::Request::ResponseTainting::Opaque);
|
||||||
|
@ -394,7 +394,7 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> main_fetch(JS::Realm& realm, Infra
|
||||||
VERIFY(request->mode() == Infrastructure::Request::Mode::CORS);
|
VERIFY(request->mode() == Infrastructure::Request::Mode::CORS);
|
||||||
|
|
||||||
// Return a network error.
|
// Return a network error.
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'cors' mode must have URL with HTTP or HTTPS scheme"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'cors' mode must have URL with HTTP or HTTPS scheme"_string));
|
||||||
}
|
}
|
||||||
// -> request’s use-CORS-preflight flag is set
|
// -> request’s use-CORS-preflight flag is set
|
||||||
// -> request’s unsafe-request flag is set and either request’s method is not a CORS-safelisted method or
|
// -> request’s unsafe-request flag is set and either request’s method is not a CORS-safelisted method or
|
||||||
|
@ -563,7 +563,7 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> main_fetch(JS::Realm& realm, Infra
|
||||||
// 1. Let processBodyError be this step: run fetch response handover given fetchParams and a network
|
// 1. Let processBodyError be this step: run fetch response handover given fetchParams and a network
|
||||||
// error.
|
// error.
|
||||||
auto process_body_error = GC::create_function(vm.heap(), [&realm, &vm, &fetch_params](JS::Value) {
|
auto process_body_error = GC::create_function(vm.heap(), [&realm, &vm, &fetch_params](JS::Value) {
|
||||||
fetch_response_handover(realm, fetch_params, Infrastructure::Response::network_error(vm, "Response body could not be processed"sv));
|
fetch_response_handover(realm, fetch_params, Infrastructure::Response::network_error(vm, "Response body could not be processed"_string));
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. If response’s body is null, then run processBodyError and abort these steps.
|
// 2. If response’s body is null, then run processBodyError and abort these steps.
|
||||||
|
@ -842,7 +842,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> scheme_fetch(JS::Realm& realm, Inf
|
||||||
if (request->method() != "GET"sv.bytes() || !blob_url_entry.has_value()) {
|
if (request->method() != "GET"sv.bytes() || !blob_url_entry.has_value()) {
|
||||||
// FIXME: Handle "blobURLEntry’s object is not a Blob object". It could be a MediaSource object, but we
|
// FIXME: Handle "blobURLEntry’s object is not a Blob object". It could be a MediaSource object, but we
|
||||||
// have not yet implemented the Media Source Extensions spec.
|
// have not yet implemented the Media Source Extensions spec.
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has an invalid 'blob:' URL"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has an invalid 'blob:' URL"_string));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Let requestEnvironment be the result of determining the environment given request.
|
// 3. Let requestEnvironment be the result of determining the environment given request.
|
||||||
|
@ -853,7 +853,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> scheme_fetch(JS::Realm& realm, Inf
|
||||||
|
|
||||||
// 5. If isTopLevelNavigation is false and requestEnvironment is null, then return a network error.
|
// 5. If isTopLevelNavigation is false and requestEnvironment is null, then return a network error.
|
||||||
if (!is_top_level_navigation && !request_environment)
|
if (!is_top_level_navigation && !request_environment)
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request is missing fetch client"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request is missing fetch client"_string));
|
||||||
|
|
||||||
// 6. Let navigationOrEnvironment be the string "navigation" if isTopLevelNavigation is true; otherwise, requestEnvironment.
|
// 6. Let navigationOrEnvironment be the string "navigation" if isTopLevelNavigation is true; otherwise, requestEnvironment.
|
||||||
auto navigation_or_environment = [&]() -> Variant<FileAPI::NavigationEnvironment, GC::Ref<HTML::Environment>> {
|
auto navigation_or_environment = [&]() -> Variant<FileAPI::NavigationEnvironment, GC::Ref<HTML::Environment>> {
|
||||||
|
@ -868,7 +868,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> scheme_fetch(JS::Realm& realm, Inf
|
||||||
// 8. If blob is not a Blob object, then return a network error.
|
// 8. If blob is not a Blob object, then return a network error.
|
||||||
// FIXME: This should probably check for a MediaSource object as well, once we implement that.
|
// FIXME: This should probably check for a MediaSource object as well, once we implement that.
|
||||||
if (!blob_object.has_value())
|
if (!blob_object.has_value())
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Failed to obtain a Blob object from 'blob:' URL"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Failed to obtain a Blob object from 'blob:' URL"_string));
|
||||||
auto const blob = FileAPI::Blob::create(realm, blob_object->data, blob_object->type);
|
auto const blob = FileAPI::Blob::create(realm, blob_object->data, blob_object->type);
|
||||||
|
|
||||||
// 9. Let response be a new response.
|
// 9. Let response be a new response.
|
||||||
|
@ -914,7 +914,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> scheme_fetch(JS::Realm& realm, Inf
|
||||||
|
|
||||||
// 4. If rangeValue is failure, then return a network error.
|
// 4. If rangeValue is failure, then return a network error.
|
||||||
if (!maybe_range_value.has_value())
|
if (!maybe_range_value.has_value())
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Failed to parse single range header value"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Failed to parse single range header value"_string));
|
||||||
|
|
||||||
// 5. Let (rangeStart, rangeEnd) be rangeValue.
|
// 5. Let (rangeStart, rangeEnd) be rangeValue.
|
||||||
auto& [range_start, range_end] = maybe_range_value.value();
|
auto& [range_start, range_end] = maybe_range_value.value();
|
||||||
|
@ -933,7 +933,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> scheme_fetch(JS::Realm& realm, Inf
|
||||||
else {
|
else {
|
||||||
// 1. If rangeStart is greater than or equal to fullLength, then return a network error.
|
// 1. If rangeStart is greater than or equal to fullLength, then return a network error.
|
||||||
if (*range_start >= full_length)
|
if (*range_start >= full_length)
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "rangeStart is greater than or equal to fullLength"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "rangeStart is greater than or equal to fullLength"_string));
|
||||||
|
|
||||||
// 2. If rangeEnd is null or rangeEnd is greater than or equal to fullLength, then set rangeEnd to fullLength − 1.
|
// 2. If rangeEnd is null or rangeEnd is greater than or equal to fullLength, then set rangeEnd to fullLength − 1.
|
||||||
if (!range_end.has_value() || *range_end >= full_length)
|
if (!range_end.has_value() || *range_end >= full_length)
|
||||||
|
@ -986,7 +986,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> scheme_fetch(JS::Realm& realm, Inf
|
||||||
|
|
||||||
// 2. If dataURLStruct is failure, then return a network error.
|
// 2. If dataURLStruct is failure, then return a network error.
|
||||||
if (data_url_struct.is_error())
|
if (data_url_struct.is_error())
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Failed to process 'data:' URL"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Failed to process 'data:' URL"_string));
|
||||||
|
|
||||||
// 3. Let mimeType be dataURLStruct’s MIME type, serialized.
|
// 3. Let mimeType be dataURLStruct’s MIME type, serialized.
|
||||||
auto const& mime_type = data_url_struct.value().mime_type.serialized();
|
auto const& mime_type = data_url_struct.value().mime_type.serialized();
|
||||||
|
@ -1010,7 +1010,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> scheme_fetch(JS::Realm& realm, Inf
|
||||||
if (request->origin().has<URL::Origin>() && (request->origin().get<URL::Origin>().is_opaque() || request->origin().get<URL::Origin>().scheme() == "file"sv || request->origin().get<URL::Origin>().scheme() == "resource"sv))
|
if (request->origin().has<URL::Origin>() && (request->origin().get<URL::Origin>().is_opaque() || request->origin().get<URL::Origin>().scheme() == "file"sv || request->origin().get<URL::Origin>().scheme() == "resource"sv))
|
||||||
return TRY(nonstandard_resource_loader_file_or_http_network_fetch(realm, fetch_params));
|
return TRY(nonstandard_resource_loader_file_or_http_network_fetch(realm, fetch_params));
|
||||||
else
|
else
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'file:' or 'resource:' URL blocked"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'file:' or 'resource:' URL blocked"_string));
|
||||||
}
|
}
|
||||||
// -> HTTP(S) scheme
|
// -> HTTP(S) scheme
|
||||||
else if (Infrastructure::is_http_or_https_scheme(request->current_url().scheme())) {
|
else if (Infrastructure::is_http_or_https_scheme(request->current_url().scheme())) {
|
||||||
|
@ -1090,7 +1090,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> http_fetch(JS::Realm& realm, Infra
|
||||||
// - request’s redirect mode is not "follow" and response’s URL list has more than one item.
|
// - request’s redirect mode is not "follow" and response’s URL list has more than one item.
|
||||||
|| (request->redirect_mode() != Infrastructure::Request::RedirectMode::Follow && response->url_list().size() > 1)) {
|
|| (request->redirect_mode() != Infrastructure::Request::RedirectMode::Follow && response->url_list().size() > 1)) {
|
||||||
// then return a network error.
|
// then return a network error.
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Invalid request/response state combination"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Invalid request/response state combination"_string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1269,17 +1269,17 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> http_redirect_fetch(JS::Realm& rea
|
||||||
|
|
||||||
// 5. If locationURL is failure, then return a network error.
|
// 5. If locationURL is failure, then return a network error.
|
||||||
if (location_url_or_error.is_error())
|
if (location_url_or_error.is_error())
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request redirect URL is invalid"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request redirect URL is invalid"_string));
|
||||||
|
|
||||||
auto location_url = location_url_or_error.release_value().release_value();
|
auto location_url = location_url_or_error.release_value().release_value();
|
||||||
|
|
||||||
// 6. If locationURL’s scheme is not an HTTP(S) scheme, then return a network error.
|
// 6. If locationURL’s scheme is not an HTTP(S) scheme, then return a network error.
|
||||||
if (!Infrastructure::is_http_or_https_scheme(location_url.scheme()))
|
if (!Infrastructure::is_http_or_https_scheme(location_url.scheme()))
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request redirect URL must have HTTP or HTTPS scheme"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request redirect URL must have HTTP or HTTPS scheme"_string));
|
||||||
|
|
||||||
// 7. If request’s redirect count is 20, then return a network error.
|
// 7. If request’s redirect count is 20, then return a network error.
|
||||||
if (request->redirect_count() == 20)
|
if (request->redirect_count() == 20)
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has reached maximum redirect count of 20"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has reached maximum redirect count of 20"_string));
|
||||||
|
|
||||||
// 8. Increase request’s redirect count by 1.
|
// 8. Increase request’s redirect count by 1.
|
||||||
request->set_redirect_count(request->redirect_count() + 1);
|
request->set_redirect_count(request->redirect_count() + 1);
|
||||||
|
@ -1290,20 +1290,20 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> http_redirect_fetch(JS::Realm& rea
|
||||||
&& location_url.includes_credentials()
|
&& location_url.includes_credentials()
|
||||||
&& request->origin().has<URL::Origin>()
|
&& request->origin().has<URL::Origin>()
|
||||||
&& !request->origin().get<URL::Origin>().is_same_origin(location_url.origin())) {
|
&& !request->origin().get<URL::Origin>().is_same_origin(location_url.origin())) {
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'cors' mode and different URL and request origin must not include credentials in redirect URL"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'cors' mode and different URL and request origin must not include credentials in redirect URL"_string));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10. If request’s response tainting is "cors" and locationURL includes credentials, then return a network error.
|
// 10. If request’s response tainting is "cors" and locationURL includes credentials, then return a network error.
|
||||||
// NOTE: This catches a cross-origin resource redirecting to a same-origin URL.
|
// NOTE: This catches a cross-origin resource redirecting to a same-origin URL.
|
||||||
if (request->response_tainting() == Infrastructure::Request::ResponseTainting::CORS && location_url.includes_credentials())
|
if (request->response_tainting() == Infrastructure::Request::ResponseTainting::CORS && location_url.includes_credentials())
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'cors' response tainting must not include credentials in redirect URL"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'cors' response tainting must not include credentials in redirect URL"_string));
|
||||||
|
|
||||||
// 11. If internalResponse’s status is not 303, request’s body is non-null, and request’s body’s source is null, then
|
// 11. If internalResponse’s status is not 303, request’s body is non-null, and request’s body’s source is null, then
|
||||||
// return a network error.
|
// return a network error.
|
||||||
if (internal_response->status() != 303
|
if (internal_response->status() != 303
|
||||||
&& !request->body().has<Empty>()
|
&& !request->body().has<Empty>()
|
||||||
&& request->body().get<GC::Ref<Infrastructure::Body>>()->source().has<Empty>()) {
|
&& request->body().get<GC::Ref<Infrastructure::Body>>()->source().has<Empty>()) {
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has body but no body source"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has body but no body source"_string));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12. If one of the following is true
|
// 12. If one of the following is true
|
||||||
|
@ -1811,7 +1811,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> http_network_or_cache_fetch(JS::Re
|
||||||
|
|
||||||
// 5. If the sum of contentLength and inflightKeepaliveBytes is greater than 64 kibibytes, then return a network error.
|
// 5. If the sum of contentLength and inflightKeepaliveBytes is greater than 64 kibibytes, then return a network error.
|
||||||
if ((content_length.value() + inflight_keep_alive_bytes) > keepalive_maximum_size)
|
if ((content_length.value() + inflight_keep_alive_bytes) > keepalive_maximum_size)
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Keepalive request exceeded maximum allowed size of 64 KiB"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Keepalive request exceeded maximum allowed size of 64 KiB"_string));
|
||||||
|
|
||||||
// NOTE: The above limit ensures that requests that are allowed to outlive the environment settings object
|
// NOTE: The above limit ensures that requests that are allowed to outlive the environment settings object
|
||||||
// and contain a body, have a bounded size and are not allowed to stay alive indefinitely.
|
// and contain a body, have a bounded size and are not allowed to stay alive indefinitely.
|
||||||
|
@ -2053,7 +2053,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> http_network_or_cache_fetch(JS::Re
|
||||||
if (!response) {
|
if (!response) {
|
||||||
// 1. If httpRequest’s cache mode is "only-if-cached", then return a network error.
|
// 1. If httpRequest’s cache mode is "only-if-cached", then return a network error.
|
||||||
if (http_request->cache_mode() == Infrastructure::Request::CacheMode::OnlyIfCached)
|
if (http_request->cache_mode() == Infrastructure::Request::CacheMode::OnlyIfCached)
|
||||||
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'only-if-cached' cache mode doesn't have a cached response"sv));
|
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request with 'only-if-cached' cache mode doesn't have a cached response"_string));
|
||||||
|
|
||||||
// 2. Let forwardResponse be the result of running HTTP-network fetch given httpFetchParams, includeCredentials,
|
// 2. Let forwardResponse be the result of running HTTP-network fetch given httpFetchParams, includeCredentials,
|
||||||
// and isNewConnectionFetch.
|
// and isNewConnectionFetch.
|
||||||
|
@ -2598,7 +2598,7 @@ WebIDL::ExceptionOr<GC::Ref<PendingResponse>> cors_preflight_fetch(JS::Realm& re
|
||||||
// is "include" or methods does not contain `*`, then return a network error.
|
// is "include" or methods does not contain `*`, then return a network error.
|
||||||
if (!methods.contains_slow(request.method()) && !Infrastructure::is_cors_safelisted_method(request.method())) {
|
if (!methods.contains_slow(request.method()) && !Infrastructure::is_cors_safelisted_method(request.method())) {
|
||||||
if (request.credentials_mode() == Infrastructure::Request::CredentialsMode::Include) {
|
if (request.credentials_mode() == Infrastructure::Request::CredentialsMode::Include) {
|
||||||
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE(String::formatted("Non-CORS-safelisted method '{}' not found in the CORS-preflight response's Access-Control-Allow-Methods header (the header may be missing). '*' is not allowed as the main request includes credentials."sv, StringView { request.method() }))));
|
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE(String::formatted("Non-CORS-safelisted method '{}' not found in the CORS-preflight response's Access-Control-Allow-Methods header (the header may be missing). '*' is not allowed as the main request includes credentials."_string, StringView { request.method() }))));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,14 +47,14 @@ GC::Ref<Response> Response::create(JS::VM& vm)
|
||||||
|
|
||||||
GC::Ref<Response> Response::aborted_network_error(JS::VM& vm)
|
GC::Ref<Response> Response::aborted_network_error(JS::VM& vm)
|
||||||
{
|
{
|
||||||
auto response = network_error(vm, "Fetch has been aborted"sv);
|
auto response = network_error(vm, "Fetch has been aborted"_string);
|
||||||
response->set_aborted(true);
|
response->set_aborted(true);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
GC::Ref<Response> Response::network_error(JS::VM& vm, Variant<String, StringView> message)
|
GC::Ref<Response> Response::network_error(JS::VM& vm, String message)
|
||||||
{
|
{
|
||||||
dbgln_if(WEB_FETCH_DEBUG, "Fetch: Creating network error response with message: {}", message.visit([](auto const& s) -> StringView { return s; }));
|
dbgln_if(WEB_FETCH_DEBUG, "Fetch: Creating network error response with message: {}", message);
|
||||||
auto response = Response::create(vm);
|
auto response = Response::create(vm);
|
||||||
response->set_status(0);
|
response->set_status(0);
|
||||||
response->set_type(Type::Error);
|
response->set_type(Type::Error);
|
||||||
|
@ -72,7 +72,7 @@ GC::Ref<Response> Response::appropriate_network_error(JS::VM& vm, FetchParams co
|
||||||
// 2. Return an aborted network error if fetchParams is aborted; otherwise return a network error.
|
// 2. Return an aborted network error if fetchParams is aborted; otherwise return a network error.
|
||||||
return fetch_params.is_aborted()
|
return fetch_params.is_aborted()
|
||||||
? aborted_network_error(vm)
|
? aborted_network_error(vm)
|
||||||
: network_error(vm, "Fetch has been terminated"sv);
|
: network_error(vm, "Fetch has been terminated"_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#concept-aborted-network-error
|
// https://fetch.spec.whatwg.org/#concept-aborted-network-error
|
||||||
|
@ -341,12 +341,6 @@ u64 Response::stale_while_revalidate_lifetime() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-standard
|
// Non-standard
|
||||||
Optional<StringView> Response::network_error_message() const
|
|
||||||
{
|
|
||||||
if (!m_network_error_message.has_value())
|
|
||||||
return {};
|
|
||||||
return m_network_error_message->visit([](auto const& s) -> StringView { return s; });
|
|
||||||
}
|
|
||||||
|
|
||||||
FilteredResponse::FilteredResponse(GC::Ref<Response> internal_response, GC::Ref<HeaderList> header_list)
|
FilteredResponse::FilteredResponse(GC::Ref<Response> internal_response, GC::Ref<HeaderList> header_list)
|
||||||
: Response(header_list)
|
: Response(header_list)
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] static GC::Ref<Response> create(JS::VM&);
|
[[nodiscard]] static GC::Ref<Response> create(JS::VM&);
|
||||||
[[nodiscard]] static GC::Ref<Response> aborted_network_error(JS::VM&);
|
[[nodiscard]] static GC::Ref<Response> aborted_network_error(JS::VM&);
|
||||||
[[nodiscard]] static GC::Ref<Response> network_error(JS::VM&, Variant<String, StringView> message);
|
[[nodiscard]] static GC::Ref<Response> network_error(JS::VM&, String message);
|
||||||
[[nodiscard]] static GC::Ref<Response> appropriate_network_error(JS::VM&, FetchParams const&);
|
[[nodiscard]] static GC::Ref<Response> appropriate_network_error(JS::VM&, FetchParams const&);
|
||||||
|
|
||||||
virtual ~Response() = default;
|
virtual ~Response() = default;
|
||||||
|
@ -124,7 +124,7 @@ public:
|
||||||
[[nodiscard]] bool is_stale() const;
|
[[nodiscard]] bool is_stale() const;
|
||||||
|
|
||||||
// Non-standard
|
// Non-standard
|
||||||
[[nodiscard]] Optional<StringView> network_error_message() const;
|
[[nodiscard]] Optional<String> const& network_error_message() const { return m_network_error_message; }
|
||||||
MonotonicTime response_time() const { return m_response_time; }
|
MonotonicTime response_time() const { return m_response_time; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -201,7 +201,7 @@ private:
|
||||||
ByteBuffer m_method;
|
ByteBuffer m_method;
|
||||||
MonotonicTime m_response_time;
|
MonotonicTime m_response_time;
|
||||||
|
|
||||||
Optional<Variant<String, StringView>> m_network_error_message;
|
Optional<String> m_network_error_message;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] ByteBuffer const& method() const { return m_method; }
|
[[nodiscard]] ByteBuffer const& method() const { return m_method; }
|
||||||
|
|
|
@ -173,7 +173,7 @@ GC::Ref<Response> Response::error(JS::VM& vm)
|
||||||
{
|
{
|
||||||
// The static error() method steps are to return the result of creating a Response object, given a new network error, "immutable", and this’s relevant Realm.
|
// The static error() method steps are to return the result of creating a Response object, given a new network error, "immutable", and this’s relevant Realm.
|
||||||
// FIXME: How can we reliably get 'this', i.e. the object the function was called on, in IDL-defined functions?
|
// FIXME: How can we reliably get 'this', i.e. the object the function was called on, in IDL-defined functions?
|
||||||
return Response::create(*vm.current_realm(), Infrastructure::Response::network_error(vm, "Response created via `Response.error()`"sv), Headers::Guard::Immutable);
|
return Response::create(*vm.current_realm(), Infrastructure::Response::network_error(vm, "Response created via `Response.error()`"_string), Headers::Guard::Immutable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#dom-response-redirect
|
// https://fetch.spec.whatwg.org/#dom-response-redirect
|
||||||
|
|
|
@ -1032,8 +1032,8 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::fetch_resource(URL::URL const& url_r
|
||||||
// 4. If the result of verifying response given the current media resource and byteRange is false, then abort these steps.
|
// 4. If the result of verifying response given the current media resource and byteRange is false, then abort these steps.
|
||||||
// NOTE: We do this step before creating the updateMedia task so that we can invoke the failure callback.
|
// NOTE: We do this step before creating the updateMedia task so that we can invoke the failure callback.
|
||||||
if (!verify_response(response, byte_range)) {
|
if (!verify_response(response, byte_range)) {
|
||||||
auto error_message = response->network_error_message().value_or("Failed to fetch media resource"sv);
|
auto error_message = response->network_error_message().value_or("Failed to fetch media resource"_string);
|
||||||
failure_callback(String::from_utf8(error_message).release_value_but_fixme_should_propagate_errors());
|
failure_callback(error_message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -980,7 +980,7 @@ static WebIDL::ExceptionOr<Navigable::NavigationParamsVariant> create_navigation
|
||||||
|
|
||||||
// 3. If the result of should navigation request of type be blocked by Content Security Policy? given request and cspNavigationType is "Blocked", then set response to a network error and break. [CSP]
|
// 3. If the result of should navigation request of type be blocked by Content Security Policy? given request and cspNavigationType is "Blocked", then set response to a network error and break. [CSP]
|
||||||
if (ContentSecurityPolicy::should_navigation_request_of_type_be_blocked_by_content_security_policy(request, csp_navigation_type) == ContentSecurityPolicy::Directives::Directive::Result::Blocked) {
|
if (ContentSecurityPolicy::should_navigation_request_of_type_be_blocked_by_content_security_policy(request, csp_navigation_type) == ContentSecurityPolicy::Directives::Directive::Result::Blocked) {
|
||||||
response_holder->set_response(Fetch::Infrastructure::Response::network_error(vm, "Blocked by Content Security Policy"sv));
|
response_holder->set_response(Fetch::Infrastructure::Response::network_error(vm, "Blocked by Content Security Policy"_string));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,7 +1144,7 @@ static WebIDL::ExceptionOr<Navigable::NavigationParamsVariant> create_navigation
|
||||||
// then return null.
|
// then return null.
|
||||||
if (response_holder->response()->is_network_error()) {
|
if (response_holder->response()->is_network_error()) {
|
||||||
// AD-HOC: We pass the error message if we have one in NullWithError
|
// AD-HOC: We pass the error message if we have one in NullWithError
|
||||||
if (response_holder->response()->network_error_message().has_value() && !response_holder->response()->network_error_message().value().is_null())
|
if (response_holder->response()->network_error_message().has_value())
|
||||||
return response_holder->response()->network_error_message().value();
|
return response_holder->response()->network_error_message().value();
|
||||||
else
|
else
|
||||||
return Navigable::NullOrError {};
|
return Navigable::NullOrError {};
|
||||||
|
@ -1312,7 +1312,7 @@ WebIDL::ExceptionOr<void> Navigable::populate_session_history_entry_document(
|
||||||
},
|
},
|
||||||
[](GC::Ref<NonFetchSchemeNavigationParams>) { return false; })) {
|
[](GC::Ref<NonFetchSchemeNavigationParams>) { return false; })) {
|
||||||
// 1. Set entry's document state's document to the result of creating a document for inline content that doesn't have a DOM, given navigable, null, navTimingType, and userInvolvement. The inline content should indicate to the user the sort of error that occurred.
|
// 1. Set entry's document state's document to the result of creating a document for inline content that doesn't have a DOM, given navigable, null, navTimingType, and userInvolvement. The inline content should indicate to the user the sort of error that occurred.
|
||||||
auto error_message = navigation_params.has<NullOrError>() ? navigation_params.get<NullOrError>().value_or("Unknown error"sv) : "The request was denied."sv;
|
auto error_message = navigation_params.has<NullOrError>() ? navigation_params.get<NullOrError>().value_or("Unknown error"_string) : "The request was denied."_string;
|
||||||
|
|
||||||
auto error_html = load_error_page(entry->url(), error_message).release_value_but_fixme_should_propagate_errors();
|
auto error_html = load_error_page(entry->url(), error_message).release_value_but_fixme_should_propagate_errors();
|
||||||
entry->document_state()->set_document(create_document_for_inline_content(this, navigation_id, user_involvement, [this, error_html](auto& document) {
|
entry->document_state()->set_document(create_document_for_inline_content(this, navigation_id, user_involvement, [this, error_html](auto& document) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ class Navigable : public JS::Cell
|
||||||
public:
|
public:
|
||||||
virtual ~Navigable() override;
|
virtual ~Navigable() override;
|
||||||
|
|
||||||
using NullOrError = Optional<StringView>;
|
using NullOrError = Optional<String>;
|
||||||
using NavigationParamsVariant = Variant<NullOrError, GC::Ref<NavigationParams>, GC::Ref<NonFetchSchemeNavigationParams>>;
|
using NavigationParamsVariant = Variant<NullOrError, GC::Ref<NavigationParams>, GC::Ref<NonFetchSchemeNavigationParams>>;
|
||||||
|
|
||||||
ErrorOr<void> initialize_navigable(GC::Ref<DocumentState> document_state, GC::Ptr<Navigable> parent);
|
ErrorOr<void> initialize_navigable(GC::Ref<DocumentState> document_state, GC::Ptr<Navigable> parent);
|
||||||
|
|
|
@ -63,7 +63,7 @@ WebIDL::ExceptionOr<GC::Ref<XMLHttpRequest>> XMLHttpRequest::construct_impl(JS::
|
||||||
{
|
{
|
||||||
auto upload_object = realm.create<XMLHttpRequestUpload>(realm);
|
auto upload_object = realm.create<XMLHttpRequestUpload>(realm);
|
||||||
auto author_request_headers = Fetch::Infrastructure::HeaderList::create(realm.vm());
|
auto author_request_headers = Fetch::Infrastructure::HeaderList::create(realm.vm());
|
||||||
auto response = Fetch::Infrastructure::Response::network_error(realm.vm(), "Not sent yet"sv);
|
auto response = Fetch::Infrastructure::Response::network_error(realm.vm(), "Not sent yet"_string);
|
||||||
auto fetch_controller = Fetch::Infrastructure::FetchController::create(realm.vm());
|
auto fetch_controller = Fetch::Infrastructure::FetchController::create(realm.vm());
|
||||||
return realm.create<XMLHttpRequest>(realm, *upload_object, *author_request_headers, *response, *fetch_controller);
|
return realm.create<XMLHttpRequest>(realm, *upload_object, *author_request_headers, *response, *fetch_controller);
|
||||||
}
|
}
|
||||||
|
@ -529,7 +529,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::open(String const& method_string, Stri
|
||||||
// Empty this’s author request headers.
|
// Empty this’s author request headers.
|
||||||
m_author_request_headers->clear();
|
m_author_request_headers->clear();
|
||||||
// Set this’s response to a network error.
|
// Set this’s response to a network error.
|
||||||
m_response = Fetch::Infrastructure::Response::network_error(realm().vm(), "Not yet sent"sv);
|
m_response = Fetch::Infrastructure::Response::network_error(realm().vm(), "Not yet sent"_string);
|
||||||
// Set this’s received bytes to the empty byte sequence.
|
// Set this’s received bytes to the empty byte sequence.
|
||||||
m_received_bytes = {};
|
m_received_bytes = {};
|
||||||
// Set this’s response object to null.
|
// Set this’s response object to null.
|
||||||
|
@ -845,7 +845,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
||||||
auto process_body_error = GC::create_function(heap(), [this](JS::Value) {
|
auto process_body_error = GC::create_function(heap(), [this](JS::Value) {
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
// 1. Set this’s response to a network error.
|
// 1. Set this’s response to a network error.
|
||||||
m_response = Fetch::Infrastructure::Response::network_error(vm, "A network error occurred processing body."sv);
|
m_response = Fetch::Infrastructure::Response::network_error(vm, "A network error occurred processing body."_string);
|
||||||
// 2. Run handle errors for this.
|
// 2. Run handle errors for this.
|
||||||
// NOTE: This cannot throw, as `handle_errors` only throws in a synchronous context.
|
// NOTE: This cannot throw, as `handle_errors` only throws in a synchronous context.
|
||||||
// FIXME: However, we can receive allocation failures, but we can't propagate them anywhere currently.
|
// FIXME: However, we can receive allocation failures, but we can't propagate them anywhere currently.
|
||||||
|
@ -1140,7 +1140,7 @@ void XMLHttpRequest::abort()
|
||||||
// Spec Note: No readystatechange event is dispatched.
|
// Spec Note: No readystatechange event is dispatched.
|
||||||
if (m_state == State::Done) {
|
if (m_state == State::Done) {
|
||||||
m_state = State::Unsent;
|
m_state = State::Unsent;
|
||||||
m_response = Fetch::Infrastructure::Response::network_error(vm(), "Not yet sent"sv);
|
m_response = Fetch::Infrastructure::Response::network_error(vm(), "Not yet sent"_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1245,7 +1245,7 @@ JS::ThrowCompletionOr<void> XMLHttpRequest::request_error_steps(FlyString const&
|
||||||
m_send = false;
|
m_send = false;
|
||||||
|
|
||||||
// 3. Set xhr’s response to a network error.
|
// 3. Set xhr’s response to a network error.
|
||||||
m_response = Fetch::Infrastructure::Response::network_error(realm().vm(), "Failed to load"sv);
|
m_response = Fetch::Infrastructure::Response::network_error(realm().vm(), "Failed to load"_string);
|
||||||
|
|
||||||
// 4. If xhr’s synchronous flag is set, then throw exception.
|
// 4. If xhr’s synchronous flag is set, then throw exception.
|
||||||
if (m_synchronous) {
|
if (m_synchronous) {
|
||||||
|
|
|
@ -124,7 +124,7 @@ void DedicatedWorkerHost::run(GC::Ref<Web::Page> page, Web::HTML::TransferDataHo
|
||||||
// 3. If the Run CSP initialization for a global object algorithm returns "Blocked" when executed upon worker
|
// 3. If the Run CSP initialization for a global object algorithm returns "Blocked" when executed upon worker
|
||||||
// global scope, set response to a network error. [CSP]
|
// global scope, set response to a network error. [CSP]
|
||||||
if (worker_global_scope->run_csp_initialization() == Web::ContentSecurityPolicy::Directives::Directive::Result::Blocked) {
|
if (worker_global_scope->run_csp_initialization() == Web::ContentSecurityPolicy::Directives::Directive::Result::Blocked) {
|
||||||
response = Web::Fetch::Infrastructure::Response::network_error(vm, "Blocked by Content Security Policy"sv);
|
response = Web::Fetch::Infrastructure::Response::network_error(vm, "Blocked by Content Security Policy"_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: 4. If worker global scope's embedder policy's value is compatible with cross-origin isolation and is shared is true,
|
// FIXME: 4. If worker global scope's embedder policy's value is compatible with cross-origin isolation and is shared is true,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue