1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 23:17:45 +00:00

LibWeb/Fetch: Port infrastructure to new String

This commit is contained in:
Linus Groh 2023-03-02 23:26:35 +00:00
parent 7f9ddcf420
commit 11023a3c53
20 changed files with 144 additions and 142 deletions

View file

@ -158,7 +158,7 @@ JS::NonnullGCPtr<JS::Promise> consume_body(JS::Realm& realm, BodyMixin const& ob
// 3. If objects body is non-null, then set promise to the result of fully reading body as promise given objects body. // 3. If objects body is non-null, then set promise to the result of fully reading body as promise given objects body.
auto const& body = object.body_impl(); auto const& body = object.body_impl();
if (body.has_value()) if (body.has_value())
promise = body->fully_read_as_promise(); promise = body->fully_read_as_promise().release_value_but_fixme_should_propagate_errors();
// 4. Let steps be to return the result of package data with the first argument given, type, and objects MIME type. // 4. Let steps be to return the result of package data with the first argument given, type, and objects MIME type.
auto steps = [&vm, &realm, &object, type](JS::Value value) -> WebIDL::ExceptionOr<JS::Value> { auto steps = [&vm, &realm, &object, type](JS::Value value) -> WebIDL::ExceptionOr<JS::Value> {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -99,8 +99,8 @@ JS::NonnullGCPtr<JS::Promise> fetch_impl(JS::VM& vm, RequestInfo const& input, R
// 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.release_value_but_fixme_should_propagate_errors());
WebIDL::reject_promise(vm, promise_capability, JS::TypeError::create(relevant_realm, message).release_allocated_value_but_fixme_should_propagate_errors()); WebIDL::reject_promise(vm, promise_capability, JS::TypeError::create(relevant_realm, move(message)));
return; return;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -56,11 +56,11 @@ ErrorOr<bool> tao_check(Infrastructure::Request const& request, Infrastructure::
auto values = TRY(response.header_list()->get_decode_and_split("Timing-Allow-Origin"sv.bytes())); auto values = TRY(response.header_list()->get_decode_and_split("Timing-Allow-Origin"sv.bytes()));
// 3. If values contains "*", then return success. // 3. If values contains "*", then return success.
if (values.has_value() && values->contains_slow("*"sv)) if (values.has_value() && values->contains_slow("*"_short_string))
return true; return true;
// 4. If values contains the result of serializing a request origin with request, then return success. // 4. If values contains the result of serializing a request origin with request, then return success.
if (values.has_value() && values->contains_slow(request.serialize_origin())) if (values.has_value() && values->contains_slow(TRY(request.serialize_origin())))
return true; return true;
// 5. If requests mode is "navigate" and requests current URLs origin is not same origin with requests origin, then return failure. // 5. If requests mode is "navigate" and requests current URLs origin is not same origin with requests origin, then return failure.

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
@ -214,7 +214,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
// 3. If requests local-URLs-only flag is set and requests current URL is not local, then set response to a // 3. If requests local-URLs-only flag is set and requests 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, TRY_OR_THROW_OOM(vm, "Request with 'local-URLs-only' flag must have a local URL"_string));
// FIXME: 4. Run report Content Security Policy violations for request. // FIXME: 4. Run report Content Security Policy violations for request.
// FIXME: 5. Upgrade request to a potentially trustworthy URL, if appropriate. // FIXME: 5. Upgrade request to a potentially trustworthy URL, if appropriate.
@ -225,7 +225,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
|| false // FIXME: "should fetching request be blocked as mixed content" || false // FIXME: "should fetching request be blocked as mixed content"
|| false // FIXME: "should request be blocked by Content Security Policy returns blocked" || false // FIXME: "should request be blocked by Content Security Policy returns blocked"
) { ) {
response = Infrastructure::Response::network_error(vm, "Request was blocked"sv); response = Infrastructure::Response::network_error(vm, TRY_OR_THROW_OOM(vm, "Request was blocked"_string));
} }
// 7. If requests referrer policy is the empty string, then set requests referrer policy to requests policy // 7. If requests referrer policy is the empty string, then set requests referrer policy to requests policy
@ -300,13 +300,13 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
// -> requests mode is "same-origin" // -> requests 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, TRY_OR_THROW_OOM(vm, "Request with 'same-origin' mode must have same URL and request origin"_string)));
} }
// -> requests mode is "no-cors" // -> requests mode is "no-cors"
else if (request->mode() == Infrastructure::Request::Mode::NoCORS) { else if (request->mode() == Infrastructure::Request::Mode::NoCORS) {
// 1. If requests redirect mode is not "follow", then return a network error. // 1. If requests 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, TRY_OR_THROW_OOM(vm, "Request with 'no-cors' mode must have redirect mode set to 'follow'"_string)));
// 2. Set requests response tainting to "opaque". // 2. Set requests response tainting to "opaque".
request->set_response_tainting(Infrastructure::Request::ResponseTainting::Opaque); request->set_response_tainting(Infrastructure::Request::ResponseTainting::Opaque);
@ -320,7 +320,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
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, TRY_OR_THROW_OOM(vm, "Request with 'cors' mode must have URL with HTTP or HTTPS scheme"_string)));
} }
// -> requests use-CORS-preflight flag is set // -> requests use-CORS-preflight flag is set
// -> requests unsafe-request flag is set and either requests method is not a CORS-safelisted method or // -> requests unsafe-request flag is set and either requests method is not a CORS-safelisted method or
@ -451,7 +451,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
// - should internalResponse to request be blocked due to nosniff // - should internalResponse to request be blocked due to nosniff
|| TRY_OR_IGNORE(Infrastructure::should_response_to_request_be_blocked_due_to_nosniff(internal_response, request)) == Infrastructure::RequestOrResponseBlocking::Blocked)) { || TRY_OR_IGNORE(Infrastructure::should_response_to_request_be_blocked_due_to_nosniff(internal_response, request)) == Infrastructure::RequestOrResponseBlocking::Blocked)) {
// then set response and internalResponse to a network error. // then set response and internalResponse to a network error.
response = internal_response = Infrastructure::Response::network_error(vm, "Response was blocked"sv); response = internal_response = Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("Response was blocked"_string));
} }
// 19. If responses type is "opaque", internalResponses status is 206, internalResponses range-requested // 19. If responses type is "opaque", internalResponses status is 206, internalResponses range-requested
@ -464,7 +464,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
&& internal_response->status() == 206 && internal_response->status() == 206
&& internal_response->range_requested() && internal_response->range_requested()
&& !request->header_list()->contains("Range"sv.bytes())) { && !request->header_list()->contains("Range"sv.bytes())) {
response = internal_response = Infrastructure::Response::network_error(vm, "Response has status 206 and 'range-requested' flag set, but request has no 'Range' header"sv); response = internal_response = Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("Response has status 206 and 'range-requested' flag set, but request has no 'Range' header"_string));
} }
// 20. If response is not a network error and either requests method is `HEAD` or `CONNECT`, or // 20. If response is not a network error and either requests method is `HEAD` or `CONNECT`, or
@ -478,8 +478,8 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
if (!request->integrity_metadata().is_empty()) { if (!request->integrity_metadata().is_empty()) {
// 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 = [&] { auto process_body_error = [&]() -> WebIDL::ExceptionOr<void> {
return fetch_response_handover(realm, fetch_params, Infrastructure::Response::network_error(vm, "Response body could not be processed"sv)); return fetch_response_handover(realm, fetch_params, Infrastructure::Response::network_error(vm, TRY_OR_THROW_OOM(vm, "Response body could not be processed"_string)));
}; };
// 2. If responses body is null, then run processBodyError and abort these steps. // 2. If responses body is null, then run processBodyError and abort these steps.
@ -668,7 +668,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
// 1. If fetchParams is canceled, then return the appropriate network error for fetchParams. // 1. If fetchParams is canceled, then return the appropriate network error for fetchParams.
if (fetch_params.is_canceled()) if (fetch_params.is_canceled())
return PendingResponse::create(vm, fetch_params.request(), Infrastructure::Response::appropriate_network_error(vm, fetch_params)); return PendingResponse::create(vm, fetch_params.request(), TRY_OR_THROW_OOM(vm, Infrastructure::Response::appropriate_network_error(vm, fetch_params)));
// 2. Let request be fetchParamss request. // 2. Let request be fetchParamss request.
auto request = fetch_params.request(); auto request = fetch_params.request();
@ -693,7 +693,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
// -> "blob" // -> "blob"
else if (request->current_url().scheme() == "blob"sv) { else if (request->current_url().scheme() == "blob"sv) {
// FIXME: Support 'blob://' URLs // FIXME: Support 'blob://' URLs
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has 'blob:' URL which is currently unsupported"sv)); return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, TRY_OR_THROW_OOM(vm, "Request has 'blob:' URL which is currently unsupported"_string)));
} }
// -> "data" // -> "data"
else if (request->current_url().scheme() == "data"sv) { else if (request->current_url().scheme() == "data"sv) {
@ -705,7 +705,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
// 2. If dataURLStruct is failure, then return a network error. // 2. If dataURLStruct is failure, then return a network error.
if (data_or_error.is_error()) if (data_or_error.is_error())
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has invalid base64 'data:' URL"sv)); return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, TRY_OR_THROW_OOM(vm, "Request has invalid base64 'data:' URL"_string)));
// 3. Let mimeType be dataURLStructs MIME type, serialized. // 3. Let mimeType be dataURLStructs MIME type, serialized.
auto const& mime_type = url.data_mime_type(); auto const& mime_type = url.data_mime_type();
@ -724,7 +724,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
// For now, unfortunate as it is, file: URLs are left as an exercise for the reader. // For now, unfortunate as it is, file: URLs are left as an exercise for the reader.
// When in doubt, return a network error. // When in doubt, return a network error.
// FIXME: Support 'file://' URLs // FIXME: Support 'file://' URLs
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, "Request has 'file:' URL which is currently unsupported"sv)); return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, TRY_OR_THROW_OOM(vm, "Request has 'file:' URL which is currently unsupported"_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())) {
@ -734,9 +734,9 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
// 4. Return a network error. // 4. Return a network error.
auto message = request->current_url().scheme() == "about"sv auto message = request->current_url().scheme() == "about"sv
? "Request has invalid 'about:' URL, only 'about:blank' can be fetched"sv ? TRY_OR_THROW_OOM(vm, "Request has invalid 'about:' URL, only 'about:blank' can be fetched"_string)
: "Request URL has invalid scheme, must be one of 'about', 'blob', 'data', 'file', 'http', or 'https'"sv; : TRY_OR_THROW_OOM(vm, "Request URL has invalid scheme, must be one of 'about', 'blob', 'data', 'file', 'http', or 'https'"_string);
return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, message)); return PendingResponse::create(vm, request, Infrastructure::Response::network_error(vm, move(message)));
} }
// https://fetch.spec.whatwg.org/#concept-http-fetch // https://fetch.spec.whatwg.org/#concept-http-fetch
@ -806,7 +806,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_fetch(JS::Realm& rea
// - requests redirect mode is not "follow" and responses URL list has more than one item. // - requests redirect mode is not "follow" and responses 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, TRY_OR_THROW_OOM(vm, "Invalid request/response state combination"_string)));
} }
} }
} }
@ -883,7 +883,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_fetch(JS::Realm& rea
// a service worker for that matter, it is applied here. // a service worker for that matter, it is applied here.
if (request->response_tainting() == Infrastructure::Request::ResponseTainting::CORS if (request->response_tainting() == Infrastructure::Request::ResponseTainting::CORS
&& !TRY_OR_IGNORE(cors_check(request, *response))) { && !TRY_OR_IGNORE(cors_check(request, *response))) {
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, "Request with 'cors' response tainting failed CORS check"sv)); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("Request with 'cors' response tainting failed CORS check"_string)));
return; return;
} }
@ -901,7 +901,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_fetch(JS::Realm& rea
if ((request->response_tainting() == Infrastructure::Request::ResponseTainting::Opaque || response->type() == Infrastructure::Response::Type::Opaque) if ((request->response_tainting() == Infrastructure::Request::ResponseTainting::Opaque || response->type() == Infrastructure::Response::Type::Opaque)
&& false // FIXME: "and the cross-origin resource policy check with requests origin, requests client, requests destination, and actualResponse returns blocked" && false // FIXME: "and the cross-origin resource policy check with requests origin, requests client, requests destination, and actualResponse returns blocked"
) { ) {
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, "Response was blocked by cross-origin resource policy check"sv)); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("Response was blocked by cross-origin resource policy check"_string)));
return; return;
} }
@ -918,7 +918,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_fetch(JS::Realm& rea
// -> "error" // -> "error"
case Infrastructure::Request::RedirectMode::Error: case Infrastructure::Request::RedirectMode::Error:
// Set response to a network error. // Set response to a network error.
response = Infrastructure::Response::network_error(vm, "Request with 'error' redirect mode received redirect response"sv); response = Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("Request with 'error' redirect mode received redirect response"_string));
break; break;
// -> "manual" // -> "manual"
case Infrastructure::Request::RedirectMode::Manual: case Infrastructure::Request::RedirectMode::Manual:
@ -974,7 +974,9 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_redirect_fetch(JS::R
: static_cast<Infrastructure::FilteredResponse const&>(response).internal_response(); : static_cast<Infrastructure::FilteredResponse const&>(response).internal_response();
// 3. Let locationURL be actualResponses location URL given requests current URLs fragment. // 3. Let locationURL be actualResponses location URL given requests current URLs fragment.
auto location_url_or_error = actual_response->location_url(request->current_url().fragment()); auto const& fragment = request->current_url().fragment();
auto fragment_string = fragment.is_null() ? Optional<String> {} : TRY_OR_THROW_OOM(vm, String::from_deprecated_string(fragment));
auto location_url_or_error = actual_response->location_url(fragment_string);
// 4. If locationURL is null, then return response. // 4. If locationURL is null, then return response.
if (!location_url_or_error.is_error() && !location_url_or_error.value().has_value()) if (!location_url_or_error.is_error() && !location_url_or_error.value().has_value())
@ -982,17 +984,17 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_redirect_fetch(JS::R
// 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, TRY_OR_THROW_OOM(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 locationURLs scheme is not an HTTP(S) scheme, then return a network error. // 6. If locationURLs 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, TRY_OR_THROW_OOM(vm, "Request redirect URL must have HTTP or HTTPS scheme"_string)));
// 7. If requests redirect count is 20, then return a network error. // 7. If requests 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, TRY_OR_THROW_OOM(vm, "Request has reached maximum redirect count of 20"_string)));
// 8. Increase requests redirect count by 1. // 8. Increase requests redirect count by 1.
request->set_redirect_count(request->redirect_count() + 1); request->set_redirect_count(request->redirect_count() + 1);
@ -1003,20 +1005,20 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_redirect_fetch(JS::R
&& location_url.includes_credentials() && location_url.includes_credentials()
&& request->origin().has<HTML::Origin>() && request->origin().has<HTML::Origin>()
&& !request->origin().get<HTML::Origin>().is_same_origin(URL::url_origin(location_url))) { && !request->origin().get<HTML::Origin>().is_same_origin(URL::url_origin(location_url))) {
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, TRY_OR_THROW_OOM(vm, "Request with 'cors' mode and different URL and request origin must not include credentials in redirect URL"_string)));
} }
// 10. If requests response tainting is "cors" and locationURL includes credentials, then return a network error. // 10. If requests 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, TRY_OR_THROW_OOM(vm, "Request with 'cors' response tainting must not include credentials in redirect URL"_string)));
// 11. If actualResponses status is not 303, requests body is non-null, and requests bodys source is null, then // 11. If actualResponses status is not 303, requests body is non-null, and requests bodys source is null, then
// return a network error. // return a network error.
if (actual_response->status() != 303 if (actual_response->status() != 303
&& !request->body().has<Empty>() && !request->body().has<Empty>()
&& request->body().get<Infrastructure::Body>().source().has<Empty>()) { && request->body().get<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, TRY_OR_THROW_OOM(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
@ -1191,7 +1193,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
// 8. If contentLength is non-null, then set contentLengthHeaderValue to contentLength, serialized and // 8. If contentLength is non-null, then set contentLengthHeaderValue to contentLength, serialized and
// isomorphic encoded. // isomorphic encoded.
if (content_length.has_value()) if (content_length.has_value())
content_length_header_value = MUST(ByteBuffer::copy(DeprecatedString::number(*content_length).bytes())); content_length_header_value = MUST(ByteBuffer::copy(TRY_OR_THROW_OOM(vm, String::number(*content_length)).bytes()));
// 9. If contentLengthHeaderValue is non-null, then append (`Content-Length`, contentLengthHeaderValue) to // 9. If contentLengthHeaderValue is non-null, then append (`Content-Length`, contentLengthHeaderValue) to
// httpRequests header list. // httpRequests header list.
@ -1324,7 +1326,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
// 2. If httpRequests header list does not contain `Authorization`, then: // 2. If httpRequests header list does not contain `Authorization`, then:
if (!http_request->header_list()->contains("Authorization"sv.bytes())) { if (!http_request->header_list()->contains("Authorization"sv.bytes())) {
// 1. Let authorizationValue be null. // 1. Let authorizationValue be null.
auto authorization_value = Optional<DeprecatedString> {}; auto authorization_value = Optional<String> {};
// 2. If theres an authentication entry for httpRequest and either httpRequests use-URL-credentials // 2. If theres an authentication entry for httpRequest and either httpRequests use-URL-credentials
// flag is unset or httpRequests current URL does not include credentials, then set // flag is unset or httpRequests current URL does not include credentials, then set
@ -1337,8 +1339,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
// true, set authorizationValue to httpRequests current URL, converted to an `Authorization` value. // true, set authorizationValue to httpRequests current URL, converted to an `Authorization` value.
else if (http_request->current_url().includes_credentials() && is_authentication_fetch == IsAuthenticationFetch::Yes) { else if (http_request->current_url().includes_credentials() && is_authentication_fetch == IsAuthenticationFetch::Yes) {
auto const& url = http_request->current_url(); auto const& url = http_request->current_url();
auto payload = DeprecatedString::formatted("{}:{}", url.username(), url.password()); auto payload = TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", url.username(), url.password()));
authorization_value = TRY_OR_THROW_OOM(vm, encode_base64(payload.bytes())).to_deprecated_string(); authorization_value = TRY_OR_THROW_OOM(vm, encode_base64(payload.bytes()));
} }
// 4. If authorizationValue is non-null, then append (`Authorization`, authorizationValue) to // 4. If authorizationValue is non-null, then append (`Authorization`, authorizationValue) to
@ -1378,7 +1380,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
// 9. If aborted, then return the appropriate network error for fetchParams. // 9. If aborted, then return the appropriate network error for fetchParams.
if (aborted) if (aborted)
return PendingResponse::create(vm, request, Infrastructure::Response::appropriate_network_error(vm, fetch_params)); return PendingResponse::create(vm, request, TRY_OR_THROW_OOM(vm, Infrastructure::Response::appropriate_network_error(vm, fetch_params)));
JS::GCPtr<PendingResponse> pending_forward_response; JS::GCPtr<PendingResponse> pending_forward_response;
@ -1386,7 +1388,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
if (!response) { if (!response) {
// 1. If httpRequests cache mode is "only-if-cached", then return a network error. // 1. If httpRequests 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, TRY_OR_THROW_OOM(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.
@ -1465,7 +1467,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
if (!request->body().has<Empty>()) { if (!request->body().has<Empty>()) {
// 1. If requests bodys source is null, then return a network error. // 1. If requests bodys source is null, then return a network error.
if (request->body().get<Infrastructure::Body>().source().has<Empty>()) { if (request->body().get<Infrastructure::Body>().source().has<Empty>()) {
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, "Request has body but no body source"sv)); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("Request has body but no body source"_string)));
return; return;
} }
@ -1483,7 +1485,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
if (!request->use_url_credentials() || is_authentication_fetch == IsAuthenticationFetch::Yes) { if (!request->use_url_credentials() || is_authentication_fetch == IsAuthenticationFetch::Yes) {
// 1. If fetchParams is canceled, then return the appropriate network error for fetchParams. // 1. If fetchParams is canceled, then return the appropriate network error for fetchParams.
if (fetch_params.is_canceled()) { if (fetch_params.is_canceled()) {
returned_pending_response->resolve(Infrastructure::Response::appropriate_network_error(vm, fetch_params)); returned_pending_response->resolve(TRY_OR_IGNORE(Infrastructure::Response::appropriate_network_error(vm, fetch_params)));
return; return;
} }
@ -1511,7 +1513,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
// 1. If requests window is "no-window", then return a network error. // 1. If requests window is "no-window", then return a network error.
if (request->window().has<Infrastructure::Request::Window>() if (request->window().has<Infrastructure::Request::Window>()
&& request->window().get<Infrastructure::Request::Window>() == Infrastructure::Request::Window::NoWindow) { && request->window().get<Infrastructure::Request::Window>() == Infrastructure::Request::Window::NoWindow) {
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, "Request requires proxy authentication but has 'no-window' set"sv)); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("Request requires proxy authentication but has 'no-window' set"_string)));
return; return;
} }
@ -1520,7 +1522,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
// 3. If fetchParams is canceled, then return the appropriate network error for fetchParams. // 3. If fetchParams is canceled, then return the appropriate network error for fetchParams.
if (fetch_params.is_canceled()) { if (fetch_params.is_canceled()) {
returned_pending_response->resolve(Infrastructure::Response::appropriate_network_error(vm, fetch_params)); returned_pending_response->resolve(TRY_OR_IGNORE(Infrastructure::Response::appropriate_network_error(vm, fetch_params)));
return; return;
} }
@ -1546,7 +1548,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
) { ) {
// 1. If fetchParams is canceled, then return the appropriate network error for fetchParams. // 1. If fetchParams is canceled, then return the appropriate network error for fetchParams.
if (fetch_params.is_canceled()) { if (fetch_params.is_canceled()) {
returned_pending_response->resolve(Infrastructure::Response::appropriate_network_error(vm, fetch_params)); returned_pending_response->resolve(TRY_OR_IGNORE(Infrastructure::Response::appropriate_network_error(vm, fetch_params)));
return; return;
} }
// 2. Set response to the result of running HTTP-network-or-cache fetch given fetchParams, // 2. Set response to the result of running HTTP-network-or-cache fetch given fetchParams,
@ -1648,13 +1650,13 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load
dbgln_if(WEB_FETCH_DEBUG, "Fetch: ResourceLoader load for '{}' complete", request->url()); dbgln_if(WEB_FETCH_DEBUG, "Fetch: ResourceLoader load for '{}' complete", request->url());
if constexpr (WEB_FETCH_DEBUG) if constexpr (WEB_FETCH_DEBUG)
log_response(status_code, response_headers, data); log_response(status_code, response_headers, data);
auto [body, _] = MUST(extract_body(realm, data)); auto [body, _] = TRY_OR_IGNORE(extract_body(realm, data));
auto response = Infrastructure::Response::create(vm); auto response = Infrastructure::Response::create(vm);
response->set_status(status_code.value_or(200)); response->set_status(status_code.value_or(200));
response->set_body(move(body)); response->set_body(move(body));
for (auto const& [name, value] : response_headers) { for (auto const& [name, value] : response_headers) {
auto header = Infrastructure::Header::from_string_pair(name, value).release_value_but_fixme_should_propagate_errors(); auto header = TRY_OR_IGNORE(Infrastructure::Header::from_string_pair(name, value));
response->header_list()->append(header).release_value_but_fixme_should_propagate_errors(); TRY_OR_IGNORE(response->header_list()->append(header));
} }
// FIXME: Set response status message // FIXME: Set response status message
pending_response->resolve(response); pending_response->resolve(response);
@ -1664,7 +1666,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load
auto response = Infrastructure::Response::create(vm); auto response = Infrastructure::Response::create(vm);
// FIXME: This is ugly, ResourceLoader should tell us. // FIXME: This is ugly, ResourceLoader should tell us.
if (status_code.value_or(0) == 0) { if (status_code.value_or(0) == 0) {
response = Infrastructure::Response::network_error(vm, "HTTP request failed"sv); response = Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("HTTP request failed"_string));
} else { } else {
response->set_status(status_code.value_or(200)); response->set_status(status_code.value_or(200));
// FIXME: Set response status message and body // FIXME: Set response status message and body
@ -1754,12 +1756,12 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> cors_preflight_fetch(JS::
// 3. If either methods or headerNames is failure, return a network error. // 3. If either methods or headerNames is failure, return a network error.
if (methods_or_failure.has<Infrastructure::ExtractHeaderParseFailure>()) { if (methods_or_failure.has<Infrastructure::ExtractHeaderParseFailure>()) {
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, "The Access-Control-Allow-Methods in the CORS-preflight response is syntactically invalid"sv)); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("The Access-Control-Allow-Methods in the CORS-preflight response is syntactically invalid"_string)));
return; return;
} }
if (header_names_or_failure.has<Infrastructure::ExtractHeaderParseFailure>()) { if (header_names_or_failure.has<Infrastructure::ExtractHeaderParseFailure>()) {
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, "The Access-Control-Allow-Headers in the CORS-preflight response is syntactically invalid"sv)); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("The Access-Control-Allow-Headers in the CORS-preflight response is syntactically invalid"_string)));
return; return;
} }
@ -1810,12 +1812,12 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> cors_preflight_fetch(JS::
// 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, DeprecatedString::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."sv, StringView { request.method() }))));
return; return;
} }
if (!methods.contains_slow("*"sv.bytes())) { if (!methods.contains_slow("*"sv.bytes())) {
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, DeprecatedString::formatted("Non-CORS-safelisted method '{}' not found in the CORS-preflight response's Access-Control-Allow-Methods header and there was no '*' entry. The header may be missing."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 and there was no '*' entry. The header may be missing."sv, StringView { request.method() }))));
return; return;
} }
} }
@ -1834,7 +1836,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> cors_preflight_fetch(JS::
} }
if (!is_in_header_names) { if (!is_in_header_names) {
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, DeprecatedString::formatted("Main request contains the header '{}' that is not specified in the CORS-preflight response's Access-Control-Allow-Headers header (the header may be missing). '*' does not capture this header."sv, StringView { header.name }))); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE(String::formatted("Main request contains the header '{}' that is not specified in the CORS-preflight response's Access-Control-Allow-Headers header (the header may be missing). '*' does not capture this header."sv, StringView { header.name }))));
return; return;
} }
} }
@ -1856,12 +1858,12 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> cors_preflight_fetch(JS::
if (!is_in_header_names) { if (!is_in_header_names) {
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, DeprecatedString::formatted("CORS-unsafe request-header '{}' not found in the CORS-preflight response's Access-Control-Allow-Headers header (the header may be missing). '*' is not allowed as the main request includes credentials."sv, StringView { unsafe_name }))); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE(String::formatted("CORS-unsafe request-header '{}' not found in the CORS-preflight response's Access-Control-Allow-Headers header (the header may be missing). '*' is not allowed as the main request includes credentials."sv, StringView { unsafe_name }))));
return; return;
} }
if (!header_names.contains_slow("*"sv.bytes())) { if (!header_names.contains_slow("*"sv.bytes())) {
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, DeprecatedString::formatted("CORS-unsafe request-header '{}' not found in the CORS-preflight response's Access-Control-Allow-Headers header and there was no '*' entry. The header may be missing."sv, StringView { unsafe_name }))); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE(String::formatted("CORS-unsafe request-header '{}' not found in the CORS-preflight response's Access-Control-Allow-Headers header and there was no '*' entry. The header may be missing."sv, StringView { unsafe_name }))));
return; return;
} }
} }
@ -1888,7 +1890,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> cors_preflight_fetch(JS::
} }
// 8. Otherwise, return a network error. // 8. Otherwise, return a network error.
returned_pending_response->resolve(Infrastructure::Response::network_error(vm, "CORS-preflight check failed")); returned_pending_response->resolve(Infrastructure::Response::network_error(vm, TRY_OR_IGNORE("CORS-preflight check failed"_string)));
}); });
return returned_pending_response; return returned_pending_response;

View file

@ -1,12 +1,12 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#pragma once #pragma once
#include <AK/DeprecatedString.h> #include <AK/String.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibJS/Forward.h> #include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h> #include <LibJS/Heap/Cell.h>
@ -50,9 +50,9 @@ public:
[[nodiscard]] JS::GCPtr<ConnectionTimingInfo> final_connection_timing_info() const { return m_final_connection_timing_info; } [[nodiscard]] JS::GCPtr<ConnectionTimingInfo> final_connection_timing_info() const { return m_final_connection_timing_info; }
void set_final_connection_timing_info(JS::GCPtr<ConnectionTimingInfo> final_connection_timing_info) { m_final_connection_timing_info = final_connection_timing_info; } void set_final_connection_timing_info(JS::GCPtr<ConnectionTimingInfo> final_connection_timing_info) { m_final_connection_timing_info = final_connection_timing_info; }
[[nodiscard]] Vector<DeprecatedString>& server_timing_headers() { return m_server_timing_headers; } [[nodiscard]] Vector<String>& server_timing_headers() { return m_server_timing_headers; }
[[nodiscard]] Vector<DeprecatedString> const& server_timing_headers() const { return m_server_timing_headers; } [[nodiscard]] Vector<String> const& server_timing_headers() const { return m_server_timing_headers; }
void set_server_timing_headers(Vector<DeprecatedString> server_timing_headers) { m_server_timing_headers = move(server_timing_headers); } void set_server_timing_headers(Vector<String> server_timing_headers) { m_server_timing_headers = move(server_timing_headers); }
[[nodiscard]] bool render_blocking() const { return m_render_blocking; } [[nodiscard]] bool render_blocking() const { return m_render_blocking; }
void set_render_blocking(bool render_blocking) { m_render_blocking = render_blocking; } void set_render_blocking(bool render_blocking) { m_render_blocking = render_blocking; }
@ -110,7 +110,7 @@ private:
// https://fetch.spec.whatwg.org/#fetch-timing-info-server-timing-headers // https://fetch.spec.whatwg.org/#fetch-timing-info-server-timing-headers
// server-timing headers (default « ») // server-timing headers (default « »)
// A list of strings. // A list of strings.
Vector<DeprecatedString> m_server_timing_headers; Vector<String> m_server_timing_headers;
// https://fetch.spec.whatwg.org/#fetch-timing-info-render-blocking // https://fetch.spec.whatwg.org/#fetch-timing-info-render-blocking
// render-blocking (default false) // render-blocking (default false)

View file

@ -4,15 +4,15 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/DeprecatedString.h>
#include <AK/GenericLexer.h> #include <AK/GenericLexer.h>
#include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibWeb/Fetch/Infrastructure/HTTP.h> #include <LibWeb/Fetch/Infrastructure/HTTP.h>
namespace Web::Fetch::Infrastructure { namespace Web::Fetch::Infrastructure {
// https://fetch.spec.whatwg.org/#collect-an-http-quoted-string // https://fetch.spec.whatwg.org/#collect-an-http-quoted-string
DeprecatedString collect_an_http_quoted_string(GenericLexer& lexer, HttpQuotedStringExtractValue extract_value) ErrorOr<String> collect_an_http_quoted_string(GenericLexer& lexer, HttpQuotedStringExtractValue extract_value)
{ {
// To collect an HTTP quoted string from a string input, given a position variable position and optionally an extract-value flag, run these steps: // To collect an HTTP quoted string from a string input, given a position variable position and optionally an extract-value flag, run these steps:
// 1. Let positionStart be position. // 1. Let positionStart be position.
@ -69,13 +69,13 @@ DeprecatedString collect_an_http_quoted_string(GenericLexer& lexer, HttpQuotedSt
// 6. If the extract-value flag is set, then return value. // 6. If the extract-value flag is set, then return value.
if (extract_value == HttpQuotedStringExtractValue::Yes) if (extract_value == HttpQuotedStringExtractValue::Yes)
return value.to_deprecated_string(); return value.to_string();
// 7. Return the code points from positionStart to position, inclusive, within input. // 7. Return the code points from positionStart to position, inclusive, within input.
auto position = lexer.tell(); auto position = lexer.tell();
auto number_of_characters_to_consume = position - position_start + 1; auto number_of_characters_to_consume = position - position_start + 1;
lexer.retreat(number_of_characters_to_consume); lexer.retreat(number_of_characters_to_consume);
return lexer.consume(number_of_characters_to_consume); return String::from_utf8(lexer.consume(number_of_characters_to_consume));
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, Luke Wilde <lukew@serenityos.org> * Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
@ -37,6 +37,6 @@ enum class HttpQuotedStringExtractValue {
Yes, Yes,
}; };
[[nodiscard]] DeprecatedString collect_an_http_quoted_string(GenericLexer& lexer, HttpQuotedStringExtractValue extract_value = HttpQuotedStringExtractValue::No); ErrorOr<String> collect_an_http_quoted_string(GenericLexer& lexer, HttpQuotedStringExtractValue extract_value = HttpQuotedStringExtractValue::No);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -41,14 +41,15 @@ WebIDL::ExceptionOr<Body> Body::clone() const
} }
// https://fetch.spec.whatwg.org/#fully-reading-body-as-promise // https://fetch.spec.whatwg.org/#fully-reading-body-as-promise
JS::NonnullGCPtr<WebIDL::Promise> Body::fully_read_as_promise() const WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> Body::fully_read_as_promise() const
{ {
auto& vm = Bindings::main_thread_vm(); auto& vm = Bindings::main_thread_vm();
auto& realm = *vm.current_realm(); auto& realm = *vm.current_realm();
// FIXME: Implement the streams spec - this is completely made up for now :^) // FIXME: Implement the streams spec - this is completely made up for now :^)
if (auto const* byte_buffer = m_source.get_pointer<ByteBuffer>()) { if (auto const* byte_buffer = m_source.get_pointer<ByteBuffer>()) {
auto result = DeprecatedString::copy(*byte_buffer); // FIXME: The buffer may or may not be valid UTF-8.
auto result = TRY_OR_THROW_OOM(vm, String::from_utf8(*byte_buffer));
return WebIDL::create_resolved_promise(realm, JS::PrimitiveString::create(vm, move(result))); return WebIDL::create_resolved_promise(realm, JS::PrimitiveString::create(vm, move(result)));
} }
// Empty, Blob, FormData // Empty, Blob, FormData

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -31,9 +31,9 @@ public:
[[nodiscard]] SourceType const& source() const { return m_source; } [[nodiscard]] SourceType const& source() const { return m_source; }
[[nodiscard]] Optional<u64> const& length() const { return m_length; } [[nodiscard]] Optional<u64> const& length() const { return m_length; }
[[nodiscard]] WebIDL::ExceptionOr<Body> clone() const; WebIDL::ExceptionOr<Body> clone() const;
[[nodiscard]] JS::NonnullGCPtr<WebIDL::Promise> fully_read_as_promise() const; WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> fully_read_as_promise() const;
private: private:
// https://fetch.spec.whatwg.org/#concept-body-stream // https://fetch.spec.whatwg.org/#concept-body-stream

View file

@ -87,7 +87,7 @@ ErrorOr<Optional<ByteBuffer>> HeaderList::get(ReadonlyBytes name) const
} }
// https://fetch.spec.whatwg.org/#concept-header-list-get-decode-split // https://fetch.spec.whatwg.org/#concept-header-list-get-decode-split
ErrorOr<Optional<Vector<DeprecatedString>>> HeaderList::get_decode_and_split(ReadonlyBytes name) const ErrorOr<Optional<Vector<String>>> HeaderList::get_decode_and_split(ReadonlyBytes name) const
{ {
// To get, decode, and split a header name name from header list list, run these steps: // To get, decode, and split a header name name from header list list, run these steps:
@ -96,14 +96,14 @@ ErrorOr<Optional<Vector<DeprecatedString>>> HeaderList::get_decode_and_split(Rea
// 2. If value is null, then return null. // 2. If value is null, then return null.
if (!value.has_value()) if (!value.has_value())
return Optional<Vector<DeprecatedString>> {}; return Optional<Vector<String>> {};
// 3. Return the result of getting, decoding, and splitting value. // 3. Return the result of getting, decoding, and splitting value.
return get_decode_and_split_header_value(*value); return get_decode_and_split_header_value(*value);
} }
// https://fetch.spec.whatwg.org/#header-value-get-decode-and-split // https://fetch.spec.whatwg.org/#header-value-get-decode-and-split
ErrorOr<Optional<Vector<DeprecatedString>>> get_decode_and_split_header_value(ReadonlyBytes value) ErrorOr<Optional<Vector<String>>> get_decode_and_split_header_value(ReadonlyBytes value)
{ {
// To get, decode, and split a header value value, run these steps: // To get, decode, and split a header value value, run these steps:
@ -114,7 +114,7 @@ ErrorOr<Optional<Vector<DeprecatedString>>> get_decode_and_split_header_value(Re
auto lexer = GenericLexer { input }; auto lexer = GenericLexer { input };
// 3. Let values be a list of strings, initially empty. // 3. Let values be a list of strings, initially empty.
Vector<DeprecatedString> values; Vector<String> values;
// 4. Let temporaryValue be the empty string. // 4. Let temporaryValue be the empty string.
StringBuilder temporary_value_builder; StringBuilder temporary_value_builder;
@ -123,14 +123,14 @@ ErrorOr<Optional<Vector<DeprecatedString>>> get_decode_and_split_header_value(Re
while (!lexer.is_eof()) { while (!lexer.is_eof()) {
// 1. Append the result of collecting a sequence of code points that are not U+0022 (") or U+002C (,) from input, given position, to temporaryValue. // 1. Append the result of collecting a sequence of code points that are not U+0022 (") or U+002C (,) from input, given position, to temporaryValue.
// NOTE: The result might be the empty string. // NOTE: The result might be the empty string.
temporary_value_builder.append(lexer.consume_until(is_any_of("\","sv))); TRY(temporary_value_builder.try_append(lexer.consume_until(is_any_of("\","sv))));
// 2. If position is not past the end of input, then: // 2. If position is not past the end of input, then:
if (!lexer.is_eof()) { if (!lexer.is_eof()) {
// 1. If the code point at position within input is U+0022 ("), then: // 1. If the code point at position within input is U+0022 ("), then:
if (lexer.peek() == '"') { if (lexer.peek() == '"') {
// 1. Append the result of collecting an HTTP quoted string from input, given position, to temporaryValue. // 1. Append the result of collecting an HTTP quoted string from input, given position, to temporaryValue.
temporary_value_builder.append(collect_an_http_quoted_string(lexer)); TRY(temporary_value_builder.try_append(TRY(collect_an_http_quoted_string(lexer))));
// 2. If position is not past the end of input, then continue. // 2. If position is not past the end of input, then continue.
if (!lexer.is_eof()) if (!lexer.is_eof())
@ -147,10 +147,10 @@ ErrorOr<Optional<Vector<DeprecatedString>>> get_decode_and_split_header_value(Re
} }
// 3. Remove all HTTP tab or space from the start and end of temporaryValue. // 3. Remove all HTTP tab or space from the start and end of temporaryValue.
auto temporary_value = temporary_value_builder.to_deprecated_string().trim(HTTP_TAB_OR_SPACE, TrimMode::Both); auto temporary_value = TRY(String::from_utf8(temporary_value_builder.string_view().trim(HTTP_TAB_OR_SPACE, TrimMode::Both)));
// 4. Append temporaryValue to values. // 4. Append temporaryValue to values.
values.append(move(temporary_value)); TRY(values.try_append(move(temporary_value)));
// 5. Set temporaryValue to the empty string. // 5. Set temporaryValue to the empty string.
temporary_value_builder.clear(); temporary_value_builder.clear();
@ -301,10 +301,10 @@ ErrorOr<Vector<Header>> HeaderList::sort_and_combine() const
Optional<MimeSniff::MimeType> HeaderList::extract_mime_type() const Optional<MimeSniff::MimeType> HeaderList::extract_mime_type() const
{ {
// 1. Let charset be null. // 1. Let charset be null.
Optional<DeprecatedString> charset; Optional<String> charset;
// 2. Let essence be null. // 2. Let essence be null.
Optional<DeprecatedString> essence; Optional<String> essence;
// 3. Let mimeType be null. // 3. Let mimeType be null.
Optional<MimeSniff::MimeType> mime_type; Optional<MimeSniff::MimeType> mime_type;
@ -332,21 +332,21 @@ Optional<MimeSniff::MimeType> HeaderList::extract_mime_type() const
mime_type = temporary_mime_type; mime_type = temporary_mime_type;
// 4. If mimeTypes essence is not essence, then: // 4. If mimeTypes essence is not essence, then:
if (mime_type->essence() != essence) { if (!essence.has_value() || (mime_type->essence() != essence->bytes_as_string_view())) {
// 1. Set charset to null. // 1. Set charset to null.
charset = {}; charset = {};
// 2. If mimeTypes parameters["charset"] exists, then set charset to mimeTypes parameters["charset"]. // 2. If mimeTypes parameters["charset"] exists, then set charset to mimeTypes parameters["charset"].
auto charset_it = mime_type->parameters().find("charset"sv); auto it = mime_type->parameters().find("charset"sv);
if (charset_it != mime_type->parameters().end()) if (it != mime_type->parameters().end())
charset = charset_it->value; charset = String::from_deprecated_string(it->value).release_value_but_fixme_should_propagate_errors();
// 3. Set essence to mimeTypes essence. // 3. Set essence to mimeTypes essence.
essence = mime_type->essence(); essence = String::from_deprecated_string(mime_type->essence()).release_value_but_fixme_should_propagate_errors();
} }
// 5. Otherwise, if mimeTypes parameters["charset"] does not exist, and charset is non-null, set mimeTypes parameters["charset"] to charset. // 5. Otherwise, if mimeTypes parameters["charset"] does not exist, and charset is non-null, set mimeTypes parameters["charset"] to charset.
else if (!mime_type->parameters().contains("charset"sv) && charset.has_value()) { else if (!mime_type->parameters().contains("charset"sv) && charset.has_value()) {
mime_type->set_parameter("charset"sv, charset.value()); mime_type->set_parameter("charset"sv, charset->to_deprecated_string());
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -7,11 +7,11 @@
#pragma once #pragma once
#include <AK/ByteBuffer.h> #include <AK/ByteBuffer.h>
#include <AK/DeprecatedString.h>
#include <AK/Error.h> #include <AK/Error.h>
#include <AK/Forward.h> #include <AK/Forward.h>
#include <AK/HashTable.h> #include <AK/HashTable.h>
#include <AK/Optional.h> #include <AK/Optional.h>
#include <AK/String.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibJS/Forward.h> #include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h> #include <LibJS/Heap/Cell.h>
@ -45,7 +45,7 @@ public:
[[nodiscard]] bool contains(ReadonlyBytes) const; [[nodiscard]] bool contains(ReadonlyBytes) const;
[[nodiscard]] ErrorOr<Optional<ByteBuffer>> get(ReadonlyBytes) const; [[nodiscard]] ErrorOr<Optional<ByteBuffer>> get(ReadonlyBytes) const;
[[nodiscard]] ErrorOr<Optional<Vector<DeprecatedString>>> get_decode_and_split(ReadonlyBytes) const; [[nodiscard]] ErrorOr<Optional<Vector<String>>> get_decode_and_split(ReadonlyBytes) const;
[[nodiscard]] ErrorOr<void> append(Header); [[nodiscard]] ErrorOr<void> append(Header);
void delete_(ReadonlyBytes name); void delete_(ReadonlyBytes name);
[[nodiscard]] ErrorOr<void> set(Header); [[nodiscard]] ErrorOr<void> set(Header);
@ -62,7 +62,7 @@ struct RangeHeaderValue {
struct ExtractHeaderParseFailure { struct ExtractHeaderParseFailure {
}; };
[[nodiscard]] ErrorOr<Optional<Vector<DeprecatedString>>> get_decode_and_split_header_value(ReadonlyBytes); [[nodiscard]] ErrorOr<Optional<Vector<String>>> get_decode_and_split_header_value(ReadonlyBytes);
[[nodiscard]] ErrorOr<OrderedHashTable<ByteBuffer>> convert_header_names_to_a_sorted_lowercase_set(Span<ReadonlyBytes>); [[nodiscard]] ErrorOr<OrderedHashTable<ByteBuffer>> convert_header_names_to_a_sorted_lowercase_set(Span<ReadonlyBytes>);
[[nodiscard]] bool is_header_name(ReadonlyBytes); [[nodiscard]] bool is_header_name(ReadonlyBytes);
[[nodiscard]] bool is_header_value(ReadonlyBytes); [[nodiscard]] bool is_header_value(ReadonlyBytes);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -177,21 +177,21 @@ bool Request::has_redirect_tainted_origin() const
} }
// https://fetch.spec.whatwg.org/#serializing-a-request-origin // https://fetch.spec.whatwg.org/#serializing-a-request-origin
DeprecatedString Request::serialize_origin() const ErrorOr<String> Request::serialize_origin() const
{ {
// 1. If request has a redirect-tainted origin, then return "null". // 1. If request has a redirect-tainted origin, then return "null".
if (has_redirect_tainted_origin()) if (has_redirect_tainted_origin())
return "null"sv; return "null"_string;
// 2. Return requests origin, serialized. // 2. Return requests origin, serialized.
return m_origin.get<HTML::Origin>().serialize(); return String::from_deprecated_string(m_origin.get<HTML::Origin>().serialize());
} }
// https://fetch.spec.whatwg.org/#byte-serializing-a-request-origin // https://fetch.spec.whatwg.org/#byte-serializing-a-request-origin
ErrorOr<ByteBuffer> Request::byte_serialize_origin() const ErrorOr<ByteBuffer> Request::byte_serialize_origin() const
{ {
// Byte-serializing a request origin, given a request request, is to return the result of serializing a request origin with request, isomorphic encoded. // Byte-serializing a request origin, given a request request, is to return the result of serializing a request origin with request, isomorphic encoded.
return ByteBuffer::copy(serialize_origin().bytes()); return ByteBuffer::copy(TRY(serialize_origin()).bytes());
} }
// https://fetch.spec.whatwg.org/#concept-request-clone // https://fetch.spec.whatwg.org/#concept-request-clone
@ -260,14 +260,14 @@ ErrorOr<void> Request::add_range_header(u64 first, Optional<u64> const& last)
auto range_value = MUST(ByteBuffer::copy("bytes"sv.bytes())); auto range_value = MUST(ByteBuffer::copy("bytes"sv.bytes()));
// 3. Serialize and isomorphic encode first, and append the result to rangeValue. // 3. Serialize and isomorphic encode first, and append the result to rangeValue.
TRY(range_value.try_append(DeprecatedString::number(first).bytes())); TRY(range_value.try_append(TRY(String::number(first)).bytes()));
// 4. Append 0x2D (-) to rangeValue. // 4. Append 0x2D (-) to rangeValue.
TRY(range_value.try_append('-')); TRY(range_value.try_append('-'));
// 5. If last is given, then serialize and isomorphic encode it, and append the result to rangeValue. // 5. If last is given, then serialize and isomorphic encode it, and append the result to rangeValue.
if (last.has_value()) if (last.has_value())
TRY(range_value.try_append(DeprecatedString::number(*last).bytes())); TRY(range_value.try_append(TRY(String::number(*last)).bytes()));
// 6. Append (`Range`, rangeValue) to requests header list. // 6. Append (`Range`, rangeValue) to requests header list.
auto header = Header { auto header = Header {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -7,10 +7,10 @@
#pragma once #pragma once
#include <AK/ByteBuffer.h> #include <AK/ByteBuffer.h>
#include <AK/DeprecatedString.h>
#include <AK/Error.h> #include <AK/Error.h>
#include <AK/Forward.h> #include <AK/Forward.h>
#include <AK/Optional.h> #include <AK/Optional.h>
#include <AK/String.h>
#include <AK/URL.h> #include <AK/URL.h>
#include <AK/Variant.h> #include <AK/Variant.h>
#include <AK/Vector.h> #include <AK/Vector.h>
@ -186,8 +186,8 @@ public:
[[nodiscard]] ReservedClientType& reserved_client() { return m_reserved_client; } [[nodiscard]] ReservedClientType& reserved_client() { return m_reserved_client; }
void set_reserved_client(ReservedClientType reserved_client) { m_reserved_client = move(reserved_client); } void set_reserved_client(ReservedClientType reserved_client) { m_reserved_client = move(reserved_client); }
[[nodiscard]] DeprecatedString const& replaces_client_id() const { return m_replaces_client_id; } [[nodiscard]] String const& replaces_client_id() const { return m_replaces_client_id; }
void set_replaces_client_id(DeprecatedString replaces_client_id) { m_replaces_client_id = move(replaces_client_id); } void set_replaces_client_id(String replaces_client_id) { m_replaces_client_id = move(replaces_client_id); }
[[nodiscard]] WindowType const& window() const { return m_window; } [[nodiscard]] WindowType const& window() const { return m_window; }
void set_window(WindowType window) { m_window = move(window); } void set_window(WindowType window) { m_window = move(window); }
@ -234,11 +234,11 @@ public:
[[nodiscard]] RedirectMode redirect_mode() const { return m_redirect_mode; } [[nodiscard]] RedirectMode redirect_mode() const { return m_redirect_mode; }
void set_redirect_mode(RedirectMode redirect_mode) { m_redirect_mode = redirect_mode; } void set_redirect_mode(RedirectMode redirect_mode) { m_redirect_mode = redirect_mode; }
[[nodiscard]] DeprecatedString const& integrity_metadata() const { return m_integrity_metadata; } [[nodiscard]] String const& integrity_metadata() const { return m_integrity_metadata; }
void set_integrity_metadata(DeprecatedString integrity_metadata) { m_integrity_metadata = move(integrity_metadata); } void set_integrity_metadata(String integrity_metadata) { m_integrity_metadata = move(integrity_metadata); }
[[nodiscard]] DeprecatedString const& cryptographic_nonce_metadata() const { return m_cryptographic_nonce_metadata; } [[nodiscard]] String const& cryptographic_nonce_metadata() const { return m_cryptographic_nonce_metadata; }
void set_cryptographic_nonce_metadata(DeprecatedString cryptographic_nonce_metadata) { m_cryptographic_nonce_metadata = move(cryptographic_nonce_metadata); } void set_cryptographic_nonce_metadata(String cryptographic_nonce_metadata) { m_cryptographic_nonce_metadata = move(cryptographic_nonce_metadata); }
[[nodiscard]] Optional<ParserMetadata> const& parser_metadata() const { return m_parser_metadata; } [[nodiscard]] Optional<ParserMetadata> const& parser_metadata() const { return m_parser_metadata; }
void set_parser_metadata(Optional<ParserMetadata> parser_metadata) { m_parser_metadata = move(parser_metadata); } void set_parser_metadata(Optional<ParserMetadata> parser_metadata) { m_parser_metadata = move(parser_metadata); }
@ -294,7 +294,7 @@ public:
[[nodiscard]] bool has_redirect_tainted_origin() const; [[nodiscard]] bool has_redirect_tainted_origin() const;
[[nodiscard]] DeprecatedString serialize_origin() const; [[nodiscard]] ErrorOr<String> serialize_origin() const;
[[nodiscard]] ErrorOr<ByteBuffer> byte_serialize_origin() const; [[nodiscard]] ErrorOr<ByteBuffer> byte_serialize_origin() const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> clone(JS::VM&) const; [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> clone(JS::VM&) const;
@ -352,7 +352,7 @@ private:
// https://fetch.spec.whatwg.org/#concept-request-replaces-client-id // https://fetch.spec.whatwg.org/#concept-request-replaces-client-id
// A request has an associated replaces client id (a string). Unless stated otherwise it is the empty string. // A request has an associated replaces client id (a string). Unless stated otherwise it is the empty string.
DeprecatedString m_replaces_client_id { DeprecatedString::empty() }; String m_replaces_client_id;
// https://fetch.spec.whatwg.org/#concept-request-window // https://fetch.spec.whatwg.org/#concept-request-window
// A request has an associated window ("no-window", "client", or an environment settings object whose global object // A request has an associated window ("no-window", "client", or an environment settings object whose global object
@ -444,12 +444,12 @@ private:
// https://fetch.spec.whatwg.org/#concept-request-integrity-metadata // https://fetch.spec.whatwg.org/#concept-request-integrity-metadata
// A request has associated integrity metadata (a string). Unless stated otherwise, it is the empty string. // A request has associated integrity metadata (a string). Unless stated otherwise, it is the empty string.
DeprecatedString m_integrity_metadata { DeprecatedString::empty() }; String m_integrity_metadata;
// https://fetch.spec.whatwg.org/#concept-request-nonce-metadata // https://fetch.spec.whatwg.org/#concept-request-nonce-metadata
// A request has associated cryptographic nonce metadata (a string). Unless stated otherwise, it is the empty // A request has associated cryptographic nonce metadata (a string). Unless stated otherwise, it is the empty
// string. // string.
DeprecatedString m_cryptographic_nonce_metadata { DeprecatedString::empty() }; String m_cryptographic_nonce_metadata;
// https://fetch.spec.whatwg.org/#concept-request-parser-metadata // https://fetch.spec.whatwg.org/#concept-request-parser-metadata
// A request has associated parser metadata which is the empty string, "parser-inserted", or // A request has associated parser metadata which is the empty string, "parser-inserted", or

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -37,14 +37,14 @@ JS::NonnullGCPtr<Response> Response::create(JS::VM& vm)
// A network error is a response whose status is always 0, status message is always // A network error is a response whose status is always 0, status message is always
// the empty byte sequence, header list is always empty, and body is always null. // the empty byte sequence, header list is always empty, and body is always null.
JS::NonnullGCPtr<Response> Response::aborted_network_error(JS::VM& vm) ErrorOr<JS::NonnullGCPtr<Response>> Response::aborted_network_error(JS::VM& vm)
{ {
auto response = network_error(vm, "Fetch has been aborted"sv); auto response = network_error(vm, TRY("Fetch has been aborted"_string));
response->set_aborted(true); response->set_aborted(true);
return response; return response;
} }
JS::NonnullGCPtr<Response> Response::network_error(JS::VM& vm, DeprecatedString message) JS::NonnullGCPtr<Response> Response::network_error(JS::VM& vm, String message)
{ {
dbgln_if(WEB_FETCH_DEBUG, "Fetch: Creating network error response with message: {}", message); dbgln_if(WEB_FETCH_DEBUG, "Fetch: Creating network error response with message: {}", message);
auto response = Response::create(vm); auto response = Response::create(vm);
@ -56,15 +56,15 @@ JS::NonnullGCPtr<Response> Response::network_error(JS::VM& vm, DeprecatedString
} }
// https://fetch.spec.whatwg.org/#appropriate-network-error // https://fetch.spec.whatwg.org/#appropriate-network-error
JS::NonnullGCPtr<Response> Response::appropriate_network_error(JS::VM& vm, FetchParams const& fetch_params) ErrorOr<JS::NonnullGCPtr<Response>> Response::appropriate_network_error(JS::VM& vm, FetchParams const& fetch_params)
{ {
// 1. Assert: fetchParams is canceled. // 1. Assert: fetchParams is canceled.
VERIFY(fetch_params.is_canceled()); VERIFY(fetch_params.is_canceled());
// 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) ? TRY(aborted_network_error(vm))
: network_error(vm, "Fetch has been terminated"sv); : network_error(vm, TRY("Fetch has been terminated"_string));
} }
// https://fetch.spec.whatwg.org/#concept-aborted-network-error // https://fetch.spec.whatwg.org/#concept-aborted-network-error
@ -94,7 +94,7 @@ Optional<AK::URL const&> Response::url() const
} }
// https://fetch.spec.whatwg.org/#concept-response-location-url // https://fetch.spec.whatwg.org/#concept-response-location-url
ErrorOr<Optional<AK::URL>> Response::location_url(Optional<DeprecatedString> const& request_fragment) const ErrorOr<Optional<AK::URL>> Response::location_url(Optional<String> const& request_fragment) const
{ {
// The location URL of a response response, given null or an ASCII string requestFragment, is the value returned by the following steps. They return null, failure, or a URL. // The location URL of a response response, given null or an ASCII string requestFragment, is the value returned by the following steps. They return null, failure, or a URL.
@ -120,7 +120,7 @@ ErrorOr<Optional<AK::URL>> Response::location_url(Optional<DeprecatedString> con
// 4. If location is a URL whose fragment is null, then set locations fragment to requestFragment. // 4. If location is a URL whose fragment is null, then set locations fragment to requestFragment.
if (location.fragment().is_null()) if (location.fragment().is_null())
location.set_fragment(request_fragment.value_or({})); location.set_fragment(request_fragment.has_value() ? request_fragment->to_deprecated_string() : DeprecatedString {});
// 5. Return location. // 5. Return location.
return location; return location;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -50,9 +50,9 @@ public:
}; };
[[nodiscard]] static JS::NonnullGCPtr<Response> create(JS::VM&); [[nodiscard]] static JS::NonnullGCPtr<Response> create(JS::VM&);
[[nodiscard]] static JS::NonnullGCPtr<Response> aborted_network_error(JS::VM&); static ErrorOr<JS::NonnullGCPtr<Response>> aborted_network_error(JS::VM&);
[[nodiscard]] static JS::NonnullGCPtr<Response> network_error(JS::VM&, DeprecatedString message); [[nodiscard]] static JS::NonnullGCPtr<Response> network_error(JS::VM&, String message);
[[nodiscard]] static JS::NonnullGCPtr<Response> appropriate_network_error(JS::VM&, FetchParams const&); static ErrorOr<JS::NonnullGCPtr<Response>> appropriate_network_error(JS::VM&, FetchParams const&);
virtual ~Response() = default; virtual ~Response() = default;
@ -104,12 +104,12 @@ public:
[[nodiscard]] bool is_network_error() const; [[nodiscard]] bool is_network_error() const;
[[nodiscard]] Optional<AK::URL const&> url() const; [[nodiscard]] Optional<AK::URL const&> url() const;
[[nodiscard]] ErrorOr<Optional<AK::URL>> location_url(Optional<DeprecatedString> const& request_fragment) const; [[nodiscard]] ErrorOr<Optional<AK::URL>> location_url(Optional<String> const& request_fragment) const;
[[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> clone(JS::VM&) const; [[nodiscard]] WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> clone(JS::VM&) const;
// Non-standard // Non-standard
Optional<DeprecatedString> const& network_error_message() const { return m_network_error_message; } Optional<String> const& network_error_message() const { return m_network_error_message; }
protected: protected:
explicit Response(JS::NonnullGCPtr<HeaderList>); explicit Response(JS::NonnullGCPtr<HeaderList>);
@ -177,7 +177,7 @@ private:
bool m_has_cross_origin_redirects { false }; bool m_has_cross_origin_redirects { false };
// Non-standard // Non-standard
Optional<DeprecatedString> m_network_error_message; Optional<String> m_network_error_message;
}; };
// https://fetch.spec.whatwg.org/#concept-filtered-response // https://fetch.spec.whatwg.org/#concept-filtered-response

View file

@ -355,7 +355,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
// 23. If init["integrity"] exists, then set requests integrity metadata to it. // 23. If init["integrity"] exists, then set requests integrity metadata to it.
if (init.integrity.has_value()) if (init.integrity.has_value())
request->set_integrity_metadata(init.integrity->to_deprecated_string()); request->set_integrity_metadata(*init.integrity);
// 24. If init["keepalive"] exists, then set requests keepalive to it. // 24. If init["keepalive"] exists, then set requests keepalive to it.
if (init.keepalive.has_value()) if (init.keepalive.has_value())
@ -590,12 +590,10 @@ Bindings::RequestRedirect Request::redirect() const
} }
// https://fetch.spec.whatwg.org/#dom-request-integrity // https://fetch.spec.whatwg.org/#dom-request-integrity
WebIDL::ExceptionOr<String> Request::integrity() const String Request::integrity() const
{ {
auto& vm = this->vm();
// The integrity getter steps are to return thiss requests integrity metadata. // The integrity getter steps are to return thiss requests integrity metadata.
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(m_request->integrity_metadata())); return m_request->integrity_metadata();
} }
// https://fetch.spec.whatwg.org/#dom-request-keepalive // https://fetch.spec.whatwg.org/#dom-request-keepalive

View file

@ -88,7 +88,7 @@ public:
[[nodiscard]] Bindings::RequestCredentials credentials() const; [[nodiscard]] Bindings::RequestCredentials credentials() const;
[[nodiscard]] Bindings::RequestCache cache() const; [[nodiscard]] Bindings::RequestCache cache() const;
[[nodiscard]] Bindings::RequestRedirect redirect() const; [[nodiscard]] Bindings::RequestRedirect redirect() const;
[[nodiscard]] WebIDL::ExceptionOr<String> integrity() const; [[nodiscard]] String integrity() const;
[[nodiscard]] bool keepalive() const; [[nodiscard]] bool keepalive() const;
[[nodiscard]] bool is_reload_navigation() const; [[nodiscard]] bool is_reload_navigation() const;
[[nodiscard]] bool is_history_navigation() const; [[nodiscard]] bool is_history_navigation() const;

View file

@ -160,11 +160,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::construct_impl(JS::Rea
} }
// https://fetch.spec.whatwg.org/#dom-response-error // https://fetch.spec.whatwg.org/#dom-response-error
JS::NonnullGCPtr<Response> Response::error(JS::VM& vm) WebIDL::ExceptionOr<JS::NonnullGCPtr<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 thiss relevant Realm. // The static error() method steps are to return the result of creating a Response object, given a new network error, "immutable", and thiss 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).release_value_but_fixme_should_propagate_errors(); return Response::create(*vm.current_realm(), Infrastructure::Response::network_error(vm, TRY_OR_THROW_OOM(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

View file

@ -45,7 +45,7 @@ public:
[[nodiscard]] JS::NonnullGCPtr<Infrastructure::Response> response() const { return m_response; } [[nodiscard]] JS::NonnullGCPtr<Infrastructure::Response> response() const { return m_response; }
// JS API functions // JS API functions
[[nodiscard]] static JS::NonnullGCPtr<Response> error(JS::VM&); static WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> error(JS::VM&);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> redirect(JS::VM&, String const& url, u16 status); static WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> redirect(JS::VM&, String const& url, u16 status);
static WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> json(JS::VM&, JS::Value data, ResponseInit const& init = {}); static WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> json(JS::VM&, JS::Value data, ResponseInit const& init = {});
[[nodiscard]] Bindings::ResponseType type() const; [[nodiscard]] Bindings::ResponseType type() const;

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2022, Luke Wilde <lukew@serenityos.org> * Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org> * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022, networkException <networkexception@serenityos.org> * Copyright (c) 2022, networkException <networkexception@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
@ -8,6 +8,7 @@
#include <AK/CharacterTypes.h> #include <AK/CharacterTypes.h>
#include <AK/GenericLexer.h> #include <AK/GenericLexer.h>
#include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibWeb/Fetch/Infrastructure/HTTP.h> #include <LibWeb/Fetch/Infrastructure/HTTP.h>
#include <LibWeb/MimeSniff/MimeType.h> #include <LibWeb/MimeSniff/MimeType.h>
@ -136,7 +137,7 @@ Optional<MimeType> MimeType::from_string(StringView string)
// 8. If the code point at position within input is U+0022 ("), then: // 8. If the code point at position within input is U+0022 ("), then:
if (lexer.peek() == '"') { if (lexer.peek() == '"') {
// 1. Set parameterValue to the result of collecting an HTTP quoted string from input, given position and the extract-value flag. // 1. Set parameterValue to the result of collecting an HTTP quoted string from input, given position and the extract-value flag.
parameter_value = Fetch::Infrastructure::collect_an_http_quoted_string(lexer, Fetch::Infrastructure::HttpQuotedStringExtractValue::Yes); parameter_value = Fetch::Infrastructure::collect_an_http_quoted_string(lexer, Fetch::Infrastructure::HttpQuotedStringExtractValue::Yes).release_value_but_fixme_should_propagate_errors().to_deprecated_string();
// 2. Collect a sequence of code points that are not U+003B (;) from input, given position. // 2. Collect a sequence of code points that are not U+003B (;) from input, given position.
lexer.ignore_until(';'); lexer.ignore_until(';');