mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-30 12:49:19 +00:00
LibWeb: Remove OOM propagation from Fetch::Infrastructure::Headers
This commit is contained in:
parent
2925fcd4bc
commit
c79f46fe6f
Notes:
sideshowbarker
2024-07-17 09:47:09 +09:00
Author: https://github.com/trflynn89
Commit: c79f46fe6f
Pull-request: https://github.com/SerenityOS/serenity/pull/24124
23 changed files with 212 additions and 225 deletions
|
@ -301,7 +301,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Document>> Document::create_and_initialize(
|
|||
document->m_window = window;
|
||||
|
||||
// NOTE: Non-standard: Pull out the Last-Modified header for use in the lastModified property.
|
||||
if (auto maybe_last_modified = MUST(navigation_params.response->header_list()->get("Last-Modified"sv.bytes())); maybe_last_modified.has_value())
|
||||
if (auto maybe_last_modified = navigation_params.response->header_list()->get("Last-Modified"sv.bytes()); maybe_last_modified.has_value())
|
||||
document->m_last_modified = Core::DateTime::parse("%a, %d %b %Y %H:%M:%S %Z"sv, maybe_last_modified.value());
|
||||
|
||||
// 11. Set window's associated Document to document.
|
||||
|
|
|
@ -469,7 +469,7 @@ JS::GCPtr<DOM::Document> load_document(HTML::NavigationParams const& navigation_
|
|||
// and origin initiatorOrigin, perform the following steps. They return a Document or null.
|
||||
|
||||
// 1. Let type be the computed type of navigationParams's response.
|
||||
auto extracted_mime_type = navigation_params.response->header_list()->extract_mime_type().release_value_but_fixme_should_propagate_errors();
|
||||
auto extracted_mime_type = navigation_params.response->header_list()->extract_mime_type();
|
||||
if (!extracted_mime_type.has_value())
|
||||
return nullptr;
|
||||
auto type = extracted_mime_type.release_value();
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Web::Fetch::Fetching {
|
|||
ErrorOr<bool> cors_check(Infrastructure::Request const& request, Infrastructure::Response const& response)
|
||||
{
|
||||
// 1. Let origin be the result of getting `Access-Control-Allow-Origin` from response’s header list.
|
||||
auto origin = TRY(response.header_list()->get("Access-Control-Allow-Origin"sv.bytes()));
|
||||
auto origin = response.header_list()->get("Access-Control-Allow-Origin"sv.bytes());
|
||||
|
||||
// 2. If origin is null, then return failure.
|
||||
// NOTE: Null is not `null`.
|
||||
|
@ -35,7 +35,7 @@ ErrorOr<bool> cors_check(Infrastructure::Request const& request, Infrastructure:
|
|||
return true;
|
||||
|
||||
// 6. Let credentials be the result of getting `Access-Control-Allow-Credentials` from response’s header list.
|
||||
auto credentials = TRY(response.header_list()->get("Access-Control-Allow-Credentials"sv.bytes()));
|
||||
auto credentials = response.header_list()->get("Access-Control-Allow-Credentials"sv.bytes());
|
||||
|
||||
// 7. If credentials is `true`, then return success.
|
||||
if (credentials.has_value() && credentials->span() == "true"sv.bytes())
|
||||
|
@ -53,7 +53,7 @@ ErrorOr<bool> tao_check(Infrastructure::Request const& request, Infrastructure::
|
|||
return false;
|
||||
|
||||
// 2. Let values be the result of getting, decoding, and splitting `Timing-Allow-Origin` from response’s header list.
|
||||
auto values = TRY(response.header_list()->get_decode_and_split("Timing-Allow-Origin"sv.bytes()));
|
||||
auto values = response.header_list()->get_decode_and_split("Timing-Allow-Origin"sv.bytes());
|
||||
|
||||
// 3. If values contains "*", then return success.
|
||||
if (values.has_value() && values->contains_slow("*"sv))
|
||||
|
|
|
@ -174,15 +174,15 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Infrastructure::FetchController>> fetch(JS:
|
|||
}
|
||||
|
||||
// 3. Append (`Accept`, value) to request’s header list.
|
||||
auto header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Accept"sv, value.bytes()));
|
||||
TRY_OR_THROW_OOM(vm, request.header_list()->append(move(header)));
|
||||
auto header = Infrastructure::Header::from_string_pair("Accept"sv, value.bytes());
|
||||
request.header_list()->append(move(header));
|
||||
}
|
||||
|
||||
// 14. If request’s header list does not contain `Accept-Language`, then user agents should append
|
||||
// (`Accept-Language, an appropriate header value) to request’s header list.
|
||||
if (!request.header_list()->contains("Accept-Language"sv.bytes())) {
|
||||
auto header = MUST(Infrastructure::Header::from_string_pair("Accept-Language"sv, "*"sv));
|
||||
TRY_OR_THROW_OOM(vm, request.header_list()->append(move(header)));
|
||||
auto header = Infrastructure::Header::from_string_pair("Accept-Language"sv, "*"sv);
|
||||
request.header_list()->append(move(header));
|
||||
}
|
||||
|
||||
// 15. If request’s priority is null, then use request’s initiator, destination, and render-blocking appropriately
|
||||
|
@ -335,7 +335,7 @@ WebIDL::ExceptionOr<JS::GCPtr<PendingResponse>> main_fetch(JS::Realm& realm, Inf
|
|||
request->use_cors_preflight()
|
||||
|| (request->unsafe_request()
|
||||
&& (!Infrastructure::is_cors_safelisted_method(request->method())
|
||||
|| !TRY_OR_THROW_OOM(vm, Infrastructure::get_cors_unsafe_header_names(request->header_list())).is_empty()))) {
|
||||
|| !Infrastructure::get_cors_unsafe_header_names(request->header_list()).is_empty()))) {
|
||||
// 1. Set request’s response tainting to "cors".
|
||||
request->set_response_tainting(Infrastructure::Request::ResponseTainting::CORS);
|
||||
|
||||
|
@ -398,14 +398,14 @@ WebIDL::ExceptionOr<JS::GCPtr<PendingResponse>> main_fetch(JS::Realm& realm, Inf
|
|||
if (request->response_tainting() == Infrastructure::Request::ResponseTainting::CORS) {
|
||||
// 1. Let headerNames be the result of extracting header list values given
|
||||
// `Access-Control-Expose-Headers` and response’s header list.
|
||||
auto header_names_or_failure = TRY_OR_IGNORE(Infrastructure::extract_header_list_values("Access-Control-Expose-Headers"sv.bytes(), response->header_list()));
|
||||
auto header_names_or_failure = Infrastructure::extract_header_list_values("Access-Control-Expose-Headers"sv.bytes(), response->header_list());
|
||||
auto header_names = header_names_or_failure.has<Vector<ByteBuffer>>() ? header_names_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
|
||||
|
||||
// 2. If request’s credentials mode is not "include" and headerNames contains `*`, then set
|
||||
// response’s CORS-exposed header-name list to all unique header names in response’s header
|
||||
// list.
|
||||
if (request->credentials_mode() != Infrastructure::Request::CredentialsMode::Include && header_names.contains_slow("*"sv.bytes())) {
|
||||
auto unique_header_names = TRY_OR_IGNORE(response->header_list()->unique_names());
|
||||
auto unique_header_names = response->header_list()->unique_names();
|
||||
response->set_cors_exposed_header_name_list(move(unique_header_names));
|
||||
}
|
||||
// 3. Otherwise, if headerNames is not null or failure, then set response’s CORS-exposed
|
||||
|
@ -463,9 +463,9 @@ WebIDL::ExceptionOr<JS::GCPtr<PendingResponse>> main_fetch(JS::Realm& realm, Inf
|
|||
// FIXME: - should internalResponse to request be blocked by Content Security Policy
|
||||
|| false
|
||||
// - should internalResponse to request be blocked due to its MIME type
|
||||
|| TRY_OR_IGNORE(Infrastructure::should_response_to_request_be_blocked_due_to_its_mime_type(internal_response, request)) == Infrastructure::RequestOrResponseBlocking::Blocked
|
||||
|| Infrastructure::should_response_to_request_be_blocked_due_to_its_mime_type(internal_response, request) == Infrastructure::RequestOrResponseBlocking::Blocked
|
||||
// - 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)) {
|
||||
|| 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.
|
||||
response = internal_response = Infrastructure::Response::network_error(vm, "Response was blocked"_string);
|
||||
}
|
||||
|
@ -548,7 +548,7 @@ WebIDL::ExceptionOr<void> fetch_response_handover(JS::Realm& realm, Infrastructu
|
|||
// The user agent may decide to expose `Server-Timing` headers to non-secure contexts requests as well.
|
||||
auto client = fetch_params.request()->client();
|
||||
if (!response.is_network_error() && client != nullptr && HTML::is_secure_context(*client)) {
|
||||
auto server_timing_headers = TRY_OR_THROW_OOM(vm, response.header_list()->get_decode_and_split("Server-Timing"sv.bytes()));
|
||||
auto server_timing_headers = response.header_list()->get_decode_and_split("Server-Timing"sv.bytes());
|
||||
if (server_timing_headers.has_value())
|
||||
timing_info->set_server_timing_headers(server_timing_headers.release_value());
|
||||
}
|
||||
|
@ -713,8 +713,10 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
|
|||
if (request->current_url().serialize_path() == "blank"sv) {
|
||||
auto response = Infrastructure::Response::create(vm);
|
||||
response->set_status_message(MUST(ByteBuffer::copy("OK"sv.bytes())));
|
||||
auto header = MUST(Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html;charset=utf-8"sv));
|
||||
TRY_OR_THROW_OOM(vm, response->header_list()->append(move(header)));
|
||||
|
||||
auto header = Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html;charset=utf-8"sv);
|
||||
response->header_list()->append(move(header));
|
||||
|
||||
response->set_body(MUST(Infrastructure::byte_sequence_as_body(realm, ""sv.bytes())));
|
||||
return PendingResponse::create(vm, request, response);
|
||||
}
|
||||
|
@ -764,11 +766,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
|
|||
response->set_body(move(body_with_type.body));
|
||||
|
||||
// 4. Set response’s header list to « (`Content-Length`, serializedFullLength), (`Content-Type`, type) ».
|
||||
auto content_length_header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Content-Length"sv, serialized_full_length));
|
||||
TRY_OR_THROW_OOM(vm, response->header_list()->append(move(content_length_header)));
|
||||
auto content_length_header = Infrastructure::Header::from_string_pair("Content-Length"sv, serialized_full_length);
|
||||
response->header_list()->append(move(content_length_header));
|
||||
|
||||
auto content_type_header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Content-Type"sv, type));
|
||||
TRY_OR_THROW_OOM(vm, response->header_list()->append(move(content_type_header)));
|
||||
auto content_type_header = Infrastructure::Header::from_string_pair("Content-Type"sv, type);
|
||||
response->header_list()->append(move(content_type_header));
|
||||
}
|
||||
// FIXME: 9. Otherwise:
|
||||
else {
|
||||
|
@ -819,8 +821,10 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm& r
|
|||
// body is dataURLStruct’s body as a body.
|
||||
auto response = Infrastructure::Response::create(vm);
|
||||
response->set_status_message(MUST(ByteBuffer::copy("OK"sv.bytes())));
|
||||
auto header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Content-Type"sv, mime_type));
|
||||
TRY_OR_THROW_OOM(vm, response->header_list()->append(move(header)));
|
||||
|
||||
auto header = Infrastructure::Header::from_string_pair("Content-Type"sv, mime_type);
|
||||
response->header_list()->append(move(header));
|
||||
|
||||
response->set_body(TRY(Infrastructure::byte_sequence_as_body(realm, data_url_struct.value().body)));
|
||||
return PendingResponse::create(vm, request, response);
|
||||
}
|
||||
|
@ -939,7 +943,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_fetch(JS::Realm& rea
|
|||
// - There is at least one item in the CORS-unsafe request-header names with request’s header list for
|
||||
// which there is no header-name cache entry match using request.
|
||||
// FIXME: We currently have no cache, so there will always be no header-name cache entry.
|
||||
|| !TRY_OR_THROW_OOM(vm, Infrastructure::get_cors_unsafe_header_names(request->header_list())).is_empty())) {
|
||||
|| !Infrastructure::get_cors_unsafe_header_names(request->header_list()).is_empty())) {
|
||||
// 1. Let preflightResponse be the result of running CORS-preflight fetch given request.
|
||||
pending_preflight_response = TRY(cors_preflight_fetch(realm, request));
|
||||
|
||||
|
@ -1324,7 +1328,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
|||
.name = MUST(ByteBuffer::copy("Content-Length"sv.bytes())),
|
||||
.value = content_length_header_value.release_value(),
|
||||
};
|
||||
TRY_OR_THROW_OOM(vm, http_request->header_list()->append(move(header)));
|
||||
http_request->header_list()->append(move(header));
|
||||
}
|
||||
|
||||
// FIXME: 10. If contentLength is non-null and httpRequest’s keepalive is true, then:
|
||||
|
@ -1345,7 +1349,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
|||
.name = MUST(ByteBuffer::copy("Referer"sv.bytes())),
|
||||
.value = move(referrer_value),
|
||||
};
|
||||
TRY_OR_THROW_OOM(vm, http_request->header_list()->append(move(header)));
|
||||
http_request->header_list()->append(move(header));
|
||||
}
|
||||
|
||||
// 12. Append a request `Origin` header for httpRequest.
|
||||
|
@ -1360,7 +1364,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
|||
.name = MUST(ByteBuffer::copy("User-Agent"sv.bytes())),
|
||||
.value = Infrastructure::default_user_agent_value(),
|
||||
};
|
||||
TRY_OR_THROW_OOM(vm, http_request->header_list()->append(move(header)));
|
||||
http_request->header_list()->append(move(header));
|
||||
}
|
||||
|
||||
// 15. If httpRequest’s cache mode is "default" and httpRequest’s header list contains `If-Modified-Since`,
|
||||
|
@ -1381,8 +1385,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
|||
if (http_request->cache_mode() == Infrastructure::Request::CacheMode::NoCache
|
||||
&& !http_request->prevent_no_cache_cache_control_header_modification()
|
||||
&& !http_request->header_list()->contains("Cache-Control"sv.bytes())) {
|
||||
auto header = MUST(Infrastructure::Header::from_string_pair("Cache-Control"sv, "max-age=0"sv));
|
||||
TRY_OR_THROW_OOM(vm, http_request->header_list()->append(move(header)));
|
||||
auto header = Infrastructure::Header::from_string_pair("Cache-Control"sv, "max-age=0"sv);
|
||||
http_request->header_list()->append(move(header));
|
||||
}
|
||||
|
||||
// 17. If httpRequest’s cache mode is "no-store" or "reload", then:
|
||||
|
@ -1391,15 +1395,15 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
|||
// 1. If httpRequest’s header list does not contain `Pragma`, then append (`Pragma`, `no-cache`) to
|
||||
// httpRequest’s header list.
|
||||
if (!http_request->header_list()->contains("Pragma"sv.bytes())) {
|
||||
auto header = MUST(Infrastructure::Header::from_string_pair("Pragma"sv, "no-cache"sv));
|
||||
TRY_OR_THROW_OOM(vm, http_request->header_list()->append(move(header)));
|
||||
auto header = Infrastructure::Header::from_string_pair("Pragma"sv, "no-cache"sv);
|
||||
http_request->header_list()->append(move(header));
|
||||
}
|
||||
|
||||
// 2. If httpRequest’s header list does not contain `Cache-Control`, then append
|
||||
// (`Cache-Control`, `no-cache`) to httpRequest’s header list.
|
||||
if (!http_request->header_list()->contains("Cache-Control"sv.bytes())) {
|
||||
auto header = MUST(Infrastructure::Header::from_string_pair("Cache-Control"sv, "no-cache"sv));
|
||||
TRY_OR_THROW_OOM(vm, http_request->header_list()->append(move(header)));
|
||||
auto header = Infrastructure::Header::from_string_pair("Cache-Control"sv, "no-cache"sv);
|
||||
http_request->header_list()->append(move(header));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1408,8 +1412,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
|||
// NOTE: This avoids a failure when handling content codings with a part of an encoded response.
|
||||
// Additionally, many servers mistakenly ignore `Range` headers if a non-identity encoding is accepted.
|
||||
if (http_request->header_list()->contains("Range"sv.bytes())) {
|
||||
auto header = MUST(Infrastructure::Header::from_string_pair("Accept-Encoding"sv, "identity"sv));
|
||||
TRY_OR_THROW_OOM(vm, http_request->header_list()->append(move(header)));
|
||||
auto header = Infrastructure::Header::from_string_pair("Accept-Encoding"sv, "identity"sv);
|
||||
http_request->header_list()->append(move(header));
|
||||
}
|
||||
|
||||
// 19. Modify httpRequest’s header list per HTTP. Do not append a given header if httpRequest’s header list
|
||||
|
@ -1438,8 +1442,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
|||
|
||||
// 2. If cookies is not the empty string, then append (`Cookie`, cookies) to httpRequest’s header list.
|
||||
if (!cookies.is_empty()) {
|
||||
auto header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Cookie"sv, cookies));
|
||||
TRY_OR_THROW_OOM(vm, http_request->header_list()->append(move(header)));
|
||||
auto header = Infrastructure::Header::from_string_pair("Cookie"sv, cookies);
|
||||
http_request->header_list()->append(move(header));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1466,8 +1470,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
|
|||
// 4. If authorizationValue is non-null, then append (`Authorization`, authorizationValue) to
|
||||
// httpRequest’s header list.
|
||||
if (authorization_value.has_value()) {
|
||||
auto header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Authorization"sv, *authorization_value));
|
||||
TRY_OR_THROW_OOM(vm, http_request->header_list()->append(move(header)));
|
||||
auto header = Infrastructure::Header::from_string_pair("Authorization"sv, *authorization_value);
|
||||
http_request->header_list()->append(move(header));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1772,8 +1776,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load
|
|||
response->set_status(status_code.value_or(200));
|
||||
response->set_body(move(body));
|
||||
for (auto const& [name, value] : response_headers) {
|
||||
auto header = TRY_OR_IGNORE(Infrastructure::Header::from_string_pair(name, value));
|
||||
TRY_OR_IGNORE(response->header_list()->append(header));
|
||||
auto header = Infrastructure::Header::from_string_pair(name, value);
|
||||
response->header_list()->append(move(header));
|
||||
}
|
||||
// FIXME: Set response status message
|
||||
pending_response->resolve(response);
|
||||
|
@ -1792,8 +1796,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load
|
|||
auto [body, _] = TRY_OR_IGNORE(extract_body(realm, data));
|
||||
response->set_body(move(body));
|
||||
for (auto const& [name, value] : response_headers) {
|
||||
auto header = TRY_OR_IGNORE(Infrastructure::Header::from_string_pair(name, value));
|
||||
TRY_OR_IGNORE(response->header_list()->append(header));
|
||||
auto header = Infrastructure::Header::from_string_pair(name, value);
|
||||
response->header_list()->append(move(header));
|
||||
}
|
||||
// FIXME: Set response status message
|
||||
}
|
||||
|
@ -1825,15 +1829,15 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> cors_preflight_fetch(JS::
|
|||
preflight->set_response_tainting(Infrastructure::Request::ResponseTainting::CORS);
|
||||
|
||||
// 2. Append (`Accept`, `*/*`) to preflight’s header list.
|
||||
auto temp_header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Accept"sv, "*/*"sv));
|
||||
TRY_OR_THROW_OOM(vm, preflight->header_list()->append(move(temp_header)));
|
||||
auto temp_header = Infrastructure::Header::from_string_pair("Accept"sv, "*/*"sv);
|
||||
preflight->header_list()->append(move(temp_header));
|
||||
|
||||
// 3. Append (`Access-Control-Request-Method`, request’s method) to preflight’s header list.
|
||||
temp_header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Access-Control-Request-Method"sv, request.method()));
|
||||
TRY_OR_THROW_OOM(vm, preflight->header_list()->append(move(temp_header)));
|
||||
temp_header = Infrastructure::Header::from_string_pair("Access-Control-Request-Method"sv, request.method());
|
||||
preflight->header_list()->append(move(temp_header));
|
||||
|
||||
// 4. Let headers be the CORS-unsafe request-header names with request’s header list.
|
||||
auto headers = TRY_OR_THROW_OOM(vm, Infrastructure::get_cors_unsafe_header_names(request.header_list()));
|
||||
auto headers = Infrastructure::get_cors_unsafe_header_names(request.header_list());
|
||||
|
||||
// 5. If headers is not empty, then:
|
||||
if (!headers.is_empty()) {
|
||||
|
@ -1855,7 +1859,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> cors_preflight_fetch(JS::
|
|||
.name = TRY_OR_THROW_OOM(vm, ByteBuffer::copy("Access-Control-Request-Headers"sv.bytes())),
|
||||
.value = move(value),
|
||||
};
|
||||
TRY_OR_THROW_OOM(vm, preflight->header_list()->append(move(temp_header)));
|
||||
preflight->header_list()->append(move(temp_header));
|
||||
}
|
||||
|
||||
// 6. Let response be the result of running HTTP-network-or-cache fetch given a new fetch params whose request is preflight.
|
||||
|
@ -1874,11 +1878,11 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> cors_preflight_fetch(JS::
|
|||
// NOTE: The CORS check is done on request rather than preflight to ensure the correct credentials mode is used.
|
||||
if (TRY_OR_IGNORE(cors_check(request, response)) && Infrastructure::is_ok_status(response->status())) {
|
||||
// 1. Let methods be the result of extracting header list values given `Access-Control-Allow-Methods` and response’s header list.
|
||||
auto methods_or_failure = TRY_OR_IGNORE(Infrastructure::extract_header_list_values("Access-Control-Allow-Methods"sv.bytes(), response->header_list()));
|
||||
auto methods_or_failure = Infrastructure::extract_header_list_values("Access-Control-Allow-Methods"sv.bytes(), response->header_list());
|
||||
|
||||
// 2. Let headerNames be the result of extracting header list values given `Access-Control-Allow-Headers` and
|
||||
// response’s header list.
|
||||
auto header_names_or_failure = TRY_OR_IGNORE(Infrastructure::extract_header_list_values("Access-Control-Allow-Headers"sv.bytes(), response->header_list()));
|
||||
auto header_names_or_failure = Infrastructure::extract_header_list_values("Access-Control-Allow-Headers"sv.bytes(), response->header_list());
|
||||
|
||||
// 3. If either methods or headerNames is failure, return a network error.
|
||||
if (methods_or_failure.has<Infrastructure::ExtractHeaderParseFailure>()) {
|
||||
|
@ -1939,7 +1943,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> cors_preflight_fetch(JS::
|
|||
// 7. For each unsafeName of the CORS-unsafe request-header names with request’s header list, if unsafeName is not a
|
||||
// byte-case-insensitive match for an item in headerNames and request’s credentials mode is "include" or headerNames
|
||||
// does not contain `*`, return a network error.
|
||||
auto unsafe_names = TRY_OR_IGNORE(Infrastructure::get_cors_unsafe_header_names(request.header_list()));
|
||||
auto unsafe_names = Infrastructure::get_cors_unsafe_header_names(request.header_list());
|
||||
for (auto const& unsafe_name : unsafe_names) {
|
||||
bool is_in_header_names = false;
|
||||
|
||||
|
|
|
@ -69,12 +69,11 @@ WebIDL::ExceptionOr<void> Headers::append(String const& name_string, String cons
|
|||
WebIDL::ExceptionOr<void> Headers::delete_(String const& name_string)
|
||||
{
|
||||
// The delete(name) method steps are:
|
||||
auto& vm = this->vm();
|
||||
auto name = name_string.bytes();
|
||||
|
||||
// 1. If validating (name, ``) for headers returns false, then return.
|
||||
// NOTE: Passing a dummy header value ought not to have any negative repercussions.
|
||||
auto header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair(name, ""sv));
|
||||
auto header = Infrastructure::Header::from_string_pair(name, ""sv);
|
||||
if (!TRY(validate(header)))
|
||||
return {};
|
||||
|
||||
|
@ -108,7 +107,7 @@ WebIDL::ExceptionOr<Optional<String>> Headers::get(String const& name_string)
|
|||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid header name"sv };
|
||||
|
||||
// 2. Return the result of getting name from this’s header list.
|
||||
auto byte_buffer = TRY_OR_THROW_OOM(vm, m_header_list->get(name));
|
||||
auto byte_buffer = m_header_list->get(name);
|
||||
return byte_buffer.has_value() ? TRY_OR_THROW_OOM(vm, String::from_utf8(*byte_buffer)) : Optional<String> {};
|
||||
}
|
||||
|
||||
|
@ -157,7 +156,7 @@ WebIDL::ExceptionOr<void> Headers::set(String const& name_string, String const&
|
|||
auto value = value_string.bytes();
|
||||
|
||||
// 1. Normalize value.
|
||||
auto normalized_value = TRY_OR_THROW_OOM(vm, Infrastructure::normalize_header_value(value));
|
||||
auto normalized_value = Infrastructure::normalize_header_value(value);
|
||||
|
||||
auto header = Infrastructure::Header {
|
||||
.name = TRY_OR_THROW_OOM(vm, ByteBuffer::copy(name)),
|
||||
|
@ -173,7 +172,7 @@ WebIDL::ExceptionOr<void> Headers::set(String const& name_string, String const&
|
|||
return {};
|
||||
|
||||
// 4. Set (name, value) in this’s header list.
|
||||
TRY_OR_THROW_OOM(vm, m_header_list->set(move(header)));
|
||||
m_header_list->set(move(header));
|
||||
|
||||
// 5. If this’s guard is "request-no-cors", then remove privileged no-CORS request-headers from this.
|
||||
if (m_guard == Guard::RequestNoCORS)
|
||||
|
@ -188,14 +187,14 @@ JS::ThrowCompletionOr<void> Headers::for_each(ForEachCallback callback)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// The value pairs to iterate over are the return value of running sort and combine with this’s header list.
|
||||
auto value_pairs_to_iterate_over = [&]() -> JS::ThrowCompletionOr<Vector<Fetch::Infrastructure::Header>> {
|
||||
return TRY_OR_THROW_OOM(vm, m_header_list->sort_and_combine());
|
||||
auto value_pairs_to_iterate_over = [&]() {
|
||||
return m_header_list->sort_and_combine();
|
||||
};
|
||||
|
||||
// 1-5. Are done in the generated wrapper code.
|
||||
|
||||
// 6. Let pairs be idlObject’s list of value pairs to iterate over.
|
||||
auto pairs = TRY(value_pairs_to_iterate_over());
|
||||
auto pairs = value_pairs_to_iterate_over();
|
||||
|
||||
// 7. Let i be 0.
|
||||
size_t i = 0;
|
||||
|
@ -209,7 +208,7 @@ JS::ThrowCompletionOr<void> Headers::for_each(ForEachCallback callback)
|
|||
TRY(callback(TRY_OR_THROW_OOM(vm, String::from_utf8(pair.name)), TRY_OR_THROW_OOM(vm, String::from_utf8(pair.value))));
|
||||
|
||||
// 3. Set pairs to idlObject’s current list of value pairs to iterate over. (It might have changed.)
|
||||
pairs = TRY(value_pairs_to_iterate_over());
|
||||
pairs = value_pairs_to_iterate_over();
|
||||
|
||||
// 4. Set i to i + 1.
|
||||
++i;
|
||||
|
@ -221,8 +220,6 @@ JS::ThrowCompletionOr<void> Headers::for_each(ForEachCallback callback)
|
|||
// https://fetch.spec.whatwg.org/#headers-validate
|
||||
WebIDL::ExceptionOr<bool> Headers::validate(Infrastructure::Header const& header) const
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// To validate a header (name, value) for a Headers object headers:
|
||||
auto const& [name, value] = header;
|
||||
|
||||
|
@ -237,7 +234,7 @@ WebIDL::ExceptionOr<bool> Headers::validate(Infrastructure::Header const& header
|
|||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Headers object is immutable"sv };
|
||||
|
||||
// 3. If headers’s guard is "request" and (name, value) is a forbidden request-header, then return false.
|
||||
if (m_guard == Guard::Request && TRY_OR_THROW_OOM(realm.vm(), Infrastructure::is_forbidden_request_header(header)))
|
||||
if (m_guard == Guard::Request && Infrastructure::is_forbidden_request_header(header))
|
||||
return false;
|
||||
|
||||
// 4. If headers’s guard is "response" and name is a forbidden response-header name, then return false.
|
||||
|
@ -258,7 +255,7 @@ WebIDL::ExceptionOr<void> Headers::append(Infrastructure::Header header)
|
|||
auto& [name, value] = header;
|
||||
|
||||
// 1. Normalize value.
|
||||
value = TRY_OR_THROW_OOM(vm, Infrastructure::normalize_header_value(value));
|
||||
value = Infrastructure::normalize_header_value(value);
|
||||
|
||||
// 2. If validating (name, value) for headers returns false, then return.
|
||||
if (!TRY(validate(header)))
|
||||
|
@ -267,7 +264,7 @@ WebIDL::ExceptionOr<void> Headers::append(Infrastructure::Header header)
|
|||
// 3. If headers’s guard is "request-no-cors":
|
||||
if (m_guard == Guard::RequestNoCORS) {
|
||||
// 1. Let temporaryValue be the result of getting name from headers’s header list.
|
||||
auto temporary_value = TRY_OR_THROW_OOM(vm, m_header_list->get(name));
|
||||
auto temporary_value = m_header_list->get(name);
|
||||
|
||||
// 2. If temporaryValue is null, then set temporaryValue to value.
|
||||
if (!temporary_value.has_value()) {
|
||||
|
@ -291,7 +288,7 @@ WebIDL::ExceptionOr<void> Headers::append(Infrastructure::Header header)
|
|||
}
|
||||
|
||||
// 4. Append (name, value) to headers’s header list.
|
||||
TRY_OR_THROW_OOM(vm, m_header_list->append(move(header)));
|
||||
m_header_list->append(move(header));
|
||||
|
||||
// 5. If headers’s guard is "request-no-cors", then remove privileged no-CORS request-headers from headers.
|
||||
if (m_guard == Guard::RequestNoCORS)
|
||||
|
@ -303,8 +300,6 @@ WebIDL::ExceptionOr<void> Headers::append(Infrastructure::Header header)
|
|||
// https://fetch.spec.whatwg.org/#concept-headers-fill
|
||||
WebIDL::ExceptionOr<void> Headers::fill(HeadersInit const& object)
|
||||
{
|
||||
auto& vm = realm().vm();
|
||||
|
||||
// To fill a Headers object headers with a given object object, run these steps:
|
||||
return object.visit(
|
||||
// 1. If object is a sequence, then for each header of object:
|
||||
|
@ -315,7 +310,7 @@ WebIDL::ExceptionOr<void> Headers::fill(HeadersInit const& object)
|
|||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Array must contain header key/value pair"sv };
|
||||
|
||||
// 2. Append (header[0], header[1]) to headers.
|
||||
auto header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair(entry[0], entry[1]));
|
||||
auto header = Infrastructure::Header::from_string_pair(entry[0], entry[1]);
|
||||
TRY(append(move(header)));
|
||||
}
|
||||
return {};
|
||||
|
@ -323,7 +318,7 @@ WebIDL::ExceptionOr<void> Headers::fill(HeadersInit const& object)
|
|||
// 2. Otherwise, object is a record, then for each key → value of object, append (key, value) to headers.
|
||||
[&](OrderedHashMap<String, String> const& object) -> WebIDL::ExceptionOr<void> {
|
||||
for (auto const& entry : object) {
|
||||
auto header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair(entry.key, entry.value));
|
||||
auto header = Infrastructure::Header::from_string_pair(entry.key, entry.value);
|
||||
TRY(append(move(header)));
|
||||
}
|
||||
return {};
|
||||
|
|
|
@ -52,20 +52,17 @@ void HeadersIterator::visit_edges(JS::Cell::Visitor& visitor)
|
|||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#es-iterable, Step 2
|
||||
JS::ThrowCompletionOr<JS::Object*> HeadersIterator::next()
|
||||
JS::NonnullGCPtr<JS::Object> HeadersIterator::next()
|
||||
{
|
||||
// The value pairs to iterate over are the return value of running sort and combine with this’s header list.
|
||||
auto value_pairs_to_iterate_over = [&]() -> JS::ThrowCompletionOr<Vector<Fetch::Infrastructure::Header>> {
|
||||
auto headers_or_error = m_headers->m_header_list->sort_and_combine();
|
||||
if (headers_or_error.is_error())
|
||||
return vm().throw_completion<JS::InternalError>(JS::ErrorType::NotEnoughMemoryToAllocate);
|
||||
return headers_or_error.release_value();
|
||||
auto value_pairs_to_iterate_over = [&]() {
|
||||
return m_headers->m_header_list->sort_and_combine();
|
||||
};
|
||||
|
||||
auto pairs = TRY(value_pairs_to_iterate_over());
|
||||
auto pairs = value_pairs_to_iterate_over();
|
||||
|
||||
if (m_index >= pairs.size())
|
||||
return create_iterator_result_object(vm(), JS::js_undefined(), true).ptr();
|
||||
return create_iterator_result_object(vm(), JS::js_undefined(), true);
|
||||
|
||||
auto const& pair = pairs[m_index++];
|
||||
StringView pair_name { pair.name };
|
||||
|
@ -73,12 +70,12 @@ JS::ThrowCompletionOr<JS::Object*> HeadersIterator::next()
|
|||
|
||||
switch (m_iteration_kind) {
|
||||
case JS::Object::PropertyKind::Key:
|
||||
return create_iterator_result_object(vm(), JS::PrimitiveString::create(vm(), pair_name), false).ptr();
|
||||
return create_iterator_result_object(vm(), JS::PrimitiveString::create(vm(), pair_name), false);
|
||||
case JS::Object::PropertyKind::Value:
|
||||
return create_iterator_result_object(vm(), JS::PrimitiveString::create(vm(), pair_value), false).ptr();
|
||||
return create_iterator_result_object(vm(), JS::PrimitiveString::create(vm(), pair_value), false);
|
||||
case JS::Object::PropertyKind::KeyAndValue: {
|
||||
auto array = JS::Array::create_from(realm(), { JS::PrimitiveString::create(vm(), pair_name), JS::PrimitiveString::create(vm(), pair_value) });
|
||||
return create_iterator_result_object(vm(), array, false).ptr();
|
||||
return create_iterator_result_object(vm(), array, false);
|
||||
}
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
|
||||
virtual ~HeadersIterator() override;
|
||||
|
||||
JS::ThrowCompletionOr<JS::Object*> next();
|
||||
JS::NonnullGCPtr<JS::Object> next();
|
||||
|
||||
private:
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
|
|
@ -42,11 +42,11 @@ requires(IsSameIgnoringCV<T, u8>) struct CaseInsensitiveBytesTraits : public Tra
|
|||
}
|
||||
};
|
||||
|
||||
ErrorOr<Header> Header::from_string_pair(StringView name, StringView value)
|
||||
Header Header::from_string_pair(StringView name, StringView value)
|
||||
{
|
||||
return Header {
|
||||
.name = TRY(ByteBuffer::copy(name.bytes())),
|
||||
.value = TRY(ByteBuffer::copy(value.bytes())),
|
||||
.name = MUST(ByteBuffer::copy(name.bytes())),
|
||||
.value = MUST(ByteBuffer::copy(value.bytes())),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ JS::NonnullGCPtr<HeaderList> HeaderList::create(JS::VM& vm)
|
|||
}
|
||||
|
||||
// Non-standard
|
||||
ErrorOr<Vector<ByteBuffer>> HeaderList::unique_names() const
|
||||
Vector<ByteBuffer> HeaderList::unique_names() const
|
||||
{
|
||||
Vector<ByteBuffer> header_names_set;
|
||||
HashTable<ReadonlyBytes, CaseInsensitiveBytesTraits<u8 const>> header_names_seen;
|
||||
|
@ -64,9 +64,8 @@ ErrorOr<Vector<ByteBuffer>> HeaderList::unique_names() const
|
|||
for (auto const& header : *this) {
|
||||
if (header_names_seen.contains(header.name))
|
||||
continue;
|
||||
auto bytes = TRY(ByteBuffer::copy(header.name));
|
||||
TRY(header_names_seen.try_set(header.name));
|
||||
TRY(header_names_set.try_append(move(bytes)));
|
||||
header_names_seen.set(header.name);
|
||||
header_names_set.append(MUST(ByteBuffer::copy(header.name)));
|
||||
}
|
||||
|
||||
return header_names_set;
|
||||
|
@ -82,13 +81,13 @@ bool HeaderList::contains(ReadonlyBytes name) const
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list-get
|
||||
ErrorOr<Optional<ByteBuffer>> HeaderList::get(ReadonlyBytes name) const
|
||||
Optional<ByteBuffer> HeaderList::get(ReadonlyBytes name) const
|
||||
{
|
||||
// To get a header name name from a header list list, run these steps:
|
||||
|
||||
// 1. If list does not contain name, then return null.
|
||||
if (!contains(name))
|
||||
return Optional<ByteBuffer> {};
|
||||
return {};
|
||||
|
||||
// 2. Return the values of all headers in list whose name is a byte-case-insensitive match for name, separated from each other by 0x2C 0x20, in order.
|
||||
ByteBuffer buffer;
|
||||
|
@ -99,32 +98,32 @@ ErrorOr<Optional<ByteBuffer>> HeaderList::get(ReadonlyBytes name) const
|
|||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
TRY(buffer.try_append(0x2c));
|
||||
TRY(buffer.try_append(0x20));
|
||||
buffer.append(0x2c);
|
||||
buffer.append(0x20);
|
||||
}
|
||||
TRY(buffer.try_append(header.value));
|
||||
buffer.append(header.value);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list-get-decode-split
|
||||
ErrorOr<Optional<Vector<String>>> HeaderList::get_decode_and_split(ReadonlyBytes name) const
|
||||
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:
|
||||
|
||||
// 1. Let value be the result of getting name from list.
|
||||
auto value = TRY(get(name));
|
||||
auto value = get(name);
|
||||
|
||||
// 2. If value is null, then return null.
|
||||
if (!value.has_value())
|
||||
return Optional<Vector<String>> {};
|
||||
return {};
|
||||
|
||||
// 3. Return the result of getting, decoding, and splitting value.
|
||||
return get_decode_and_split_header_value(*value);
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#header-value-get-decode-and-split
|
||||
ErrorOr<Optional<Vector<String>>> get_decode_and_split_header_value(ReadonlyBytes value)
|
||||
Optional<Vector<String>> get_decode_and_split_header_value(ReadonlyBytes value)
|
||||
{
|
||||
// To get, decode, and split a header value value, run these steps:
|
||||
|
||||
|
@ -144,14 +143,14 @@ ErrorOr<Optional<Vector<String>>> get_decode_and_split_header_value(ReadonlyByte
|
|||
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.
|
||||
// NOTE: The result might be the empty string.
|
||||
TRY(temporary_value_builder.try_append(lexer.consume_until(is_any_of("\","sv))));
|
||||
temporary_value_builder.append(lexer.consume_until(is_any_of("\","sv)));
|
||||
|
||||
// 2. If position is not past the end of input, then:
|
||||
if (!lexer.is_eof()) {
|
||||
// 1. If the code point at position within input is U+0022 ("), then:
|
||||
if (lexer.peek() == '"') {
|
||||
// 1. Append the result of collecting an HTTP quoted string from input, given position, to temporaryValue.
|
||||
TRY(temporary_value_builder.try_append(TRY(collect_an_http_quoted_string(lexer))));
|
||||
temporary_value_builder.append(MUST(collect_an_http_quoted_string(lexer)));
|
||||
|
||||
// 2. If position is not past the end of input, then continue.
|
||||
if (!lexer.is_eof())
|
||||
|
@ -168,10 +167,10 @@ ErrorOr<Optional<Vector<String>>> get_decode_and_split_header_value(ReadonlyByte
|
|||
}
|
||||
|
||||
// 3. Remove all HTTP tab or space from the start and end of temporaryValue.
|
||||
auto temporary_value = TRY(String::from_utf8(temporary_value_builder.string_view().trim(HTTP_TAB_OR_SPACE, TrimMode::Both)));
|
||||
auto temporary_value = MUST(String::from_utf8(temporary_value_builder.string_view().trim(HTTP_TAB_OR_SPACE, TrimMode::Both)));
|
||||
|
||||
// 4. Append temporaryValue to values.
|
||||
TRY(values.try_append(move(temporary_value)));
|
||||
values.append(move(temporary_value));
|
||||
|
||||
// 5. Set temporaryValue to the empty string.
|
||||
temporary_value_builder.clear();
|
||||
|
@ -182,7 +181,7 @@ ErrorOr<Optional<Vector<String>>> get_decode_and_split_header_value(ReadonlyByte
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list-append
|
||||
ErrorOr<void> HeaderList::append(Header header)
|
||||
void HeaderList::append(Header header)
|
||||
{
|
||||
// To append a header (name, value) to a header list list, run these steps:
|
||||
// NOTE: Can't use structured bindings captured in the lambda due to https://github.com/llvm/llvm-project/issues/48582
|
||||
|
@ -198,9 +197,7 @@ ErrorOr<void> HeaderList::append(Header header)
|
|||
}
|
||||
|
||||
// 2. Append (name, value) to list.
|
||||
TRY(Vector<Header>::try_append(move(header)));
|
||||
|
||||
return {};
|
||||
Vector<Header>::append(move(header));
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list-delete
|
||||
|
@ -213,7 +210,7 @@ void HeaderList::delete_(ReadonlyBytes name)
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list-set
|
||||
ErrorOr<void> HeaderList::set(Header header)
|
||||
void HeaderList::set(Header header)
|
||||
{
|
||||
// To set a header (name, value) in a header list list, run these steps:
|
||||
// NOTE: Can't use structured bindings captured in the lambda due to https://github.com/llvm/llvm-project/issues/48582
|
||||
|
@ -226,7 +223,7 @@ ErrorOr<void> HeaderList::set(Header header)
|
|||
return StringView { existing_header.name }.equals_ignoring_ascii_case(name);
|
||||
}).index();
|
||||
auto& matching_header = at(matching_index);
|
||||
matching_header.value = TRY(ByteBuffer::copy(value));
|
||||
matching_header.value = MUST(ByteBuffer::copy(value));
|
||||
size_t i = 0;
|
||||
remove_all_matching([&](auto const& existing_header) {
|
||||
ScopeGuard increment_i = [&]() { i++; };
|
||||
|
@ -237,14 +234,12 @@ ErrorOr<void> HeaderList::set(Header header)
|
|||
}
|
||||
// 2. Otherwise, append header (name, value) to list.
|
||||
else {
|
||||
TRY(try_append(move(header)));
|
||||
append(move(header));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list-combine
|
||||
ErrorOr<void> HeaderList::combine(Header header)
|
||||
void HeaderList::combine(Header header)
|
||||
{
|
||||
// To combine a header (name, value) in a header list list, run these steps:
|
||||
// NOTE: Can't use structured bindings captured in the lambda due to https://github.com/llvm/llvm-project/issues/48582
|
||||
|
@ -256,20 +251,18 @@ ErrorOr<void> HeaderList::combine(Header header)
|
|||
auto matching_header = first_matching([&](auto const& existing_header) {
|
||||
return StringView { existing_header.name }.equals_ignoring_ascii_case(name);
|
||||
});
|
||||
TRY(matching_header->value.try_append(0x2c));
|
||||
TRY(matching_header->value.try_append(0x20));
|
||||
TRY(matching_header->value.try_append(value));
|
||||
matching_header->value.append(0x2c);
|
||||
matching_header->value.append(0x20);
|
||||
matching_header->value.append(value);
|
||||
}
|
||||
// 2. Otherwise, append (name, value) to list.
|
||||
else {
|
||||
TRY(try_append(move(header)));
|
||||
append(move(header));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
|
||||
ErrorOr<Vector<Header>> HeaderList::sort_and_combine() const
|
||||
Vector<Header> HeaderList::sort_and_combine() const
|
||||
{
|
||||
// To sort and combine a header list list, run these steps:
|
||||
|
||||
|
@ -278,10 +271,10 @@ ErrorOr<Vector<Header>> HeaderList::sort_and_combine() const
|
|||
|
||||
// 2. Let names be the result of convert header names to a sorted-lowercase set with all the names of the headers in list.
|
||||
Vector<ReadonlyBytes> names_list;
|
||||
TRY(names_list.try_ensure_capacity(size()));
|
||||
names_list.ensure_capacity(size());
|
||||
for (auto const& header : *this)
|
||||
names_list.unchecked_append(header.name);
|
||||
auto names = TRY(convert_header_names_to_a_sorted_lowercase_set(names_list));
|
||||
auto names = convert_header_names_to_a_sorted_lowercase_set(names_list);
|
||||
|
||||
// 3. For each name of names:
|
||||
for (auto& name : names) {
|
||||
|
@ -292,15 +285,15 @@ ErrorOr<Vector<Header>> HeaderList::sort_and_combine() const
|
|||
for (auto const& [header_name, value] : *this) {
|
||||
if (StringView { header_name }.equals_ignoring_ascii_case(name)) {
|
||||
// 1. Append (name, value) to headers.
|
||||
auto header = TRY(Header::from_string_pair(name, value));
|
||||
TRY(headers.try_append(move(header)));
|
||||
auto header = Header::from_string_pair(name, value);
|
||||
headers.append(move(header));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. Otherwise:
|
||||
else {
|
||||
// 1. Let value be the result of getting name from list.
|
||||
auto value = TRY(get(name));
|
||||
auto value = get(name);
|
||||
|
||||
// 2. Assert: value is not null.
|
||||
VERIFY(value.has_value());
|
||||
|
@ -310,7 +303,7 @@ ErrorOr<Vector<Header>> HeaderList::sort_and_combine() const
|
|||
.name = move(name),
|
||||
.value = value.release_value(),
|
||||
};
|
||||
TRY(headers.try_append(move(header)));
|
||||
headers.append(move(header));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,10 +312,10 @@ ErrorOr<Vector<Header>> HeaderList::sort_and_combine() const
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#header-list-extract-a-length
|
||||
ErrorOr<HeaderList::ExtractLengthResult> HeaderList::extract_length() const
|
||||
HeaderList::ExtractLengthResult HeaderList::extract_length() const
|
||||
{
|
||||
// 1. Let values be the result of getting, decoding, and splitting `Content-Length` from headers.
|
||||
auto values = TRY(get_decode_and_split("Content-Length"sv.bytes()));
|
||||
auto values = get_decode_and_split("Content-Length"sv.bytes());
|
||||
|
||||
// 2. If values is null, then return null.
|
||||
if (!values.has_value())
|
||||
|
@ -355,7 +348,7 @@ ErrorOr<HeaderList::ExtractLengthResult> HeaderList::extract_length() const
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-extract-mime-type
|
||||
ErrorOr<Optional<MimeSniff::MimeType>> HeaderList::extract_mime_type() const
|
||||
Optional<MimeSniff::MimeType> HeaderList::extract_mime_type() const
|
||||
{
|
||||
// 1. Let charset be null.
|
||||
Optional<String> charset;
|
||||
|
@ -367,19 +360,16 @@ ErrorOr<Optional<MimeSniff::MimeType>> HeaderList::extract_mime_type() const
|
|||
Optional<MimeSniff::MimeType> mime_type;
|
||||
|
||||
// 4. Let values be the result of getting, decoding, and splitting `Content-Type` from headers.
|
||||
auto values_or_error = get_decode_and_split("Content-Type"sv.bytes());
|
||||
if (values_or_error.is_error())
|
||||
return OptionalNone {};
|
||||
auto values = values_or_error.release_value();
|
||||
auto values = get_decode_and_split("Content-Type"sv.bytes());
|
||||
|
||||
// 5. If values is null, then return failure.
|
||||
if (!values.has_value())
|
||||
return OptionalNone {};
|
||||
return {};
|
||||
|
||||
// 6. For each value of values:
|
||||
for (auto const& value : *values) {
|
||||
// 1. Let temporaryMimeType be the result of parsing value.
|
||||
auto temporary_mime_type = TRY(MimeSniff::MimeType::parse(value));
|
||||
auto temporary_mime_type = MUST(MimeSniff::MimeType::parse(value));
|
||||
|
||||
// 2. If temporaryMimeType is failure or its essence is "*/*", then continue.
|
||||
if (!temporary_mime_type.has_value() || temporary_mime_type->essence() == "*/*"sv)
|
||||
|
@ -403,7 +393,7 @@ ErrorOr<Optional<MimeSniff::MimeType>> HeaderList::extract_mime_type() const
|
|||
}
|
||||
// 5. Otherwise, if mimeType’s parameters["charset"] does not exist, and charset is non-null, set mimeType’s parameters["charset"] to charset.
|
||||
else if (!mime_type->parameters().contains("charset"sv) && charset.has_value()) {
|
||||
TRY(mime_type->set_parameter("charset"_string, charset.release_value()));
|
||||
MUST(mime_type->set_parameter("charset"_string, charset.release_value()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -436,7 +426,7 @@ StringView legacy_extract_an_encoding(Optional<MimeSniff::MimeType> const& mime_
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#convert-header-names-to-a-sorted-lowercase-set
|
||||
ErrorOr<OrderedHashTable<ByteBuffer>> convert_header_names_to_a_sorted_lowercase_set(Span<ReadonlyBytes> header_names)
|
||||
OrderedHashTable<ByteBuffer> convert_header_names_to_a_sorted_lowercase_set(Span<ReadonlyBytes> header_names)
|
||||
{
|
||||
// To convert header names to a sorted-lowercase set, given a list of names headerNames, run these steps:
|
||||
|
||||
|
@ -448,7 +438,7 @@ ErrorOr<OrderedHashTable<ByteBuffer>> convert_header_names_to_a_sorted_lowercase
|
|||
for (auto name : header_names) {
|
||||
if (header_names_seen.contains(name))
|
||||
continue;
|
||||
auto bytes = TRY(ByteBuffer::copy(name));
|
||||
auto bytes = MUST(ByteBuffer::copy(name));
|
||||
Infra::byte_lowercase(bytes);
|
||||
header_names_seen.set(name);
|
||||
header_names_set.append(move(bytes));
|
||||
|
@ -492,13 +482,13 @@ bool is_header_value(ReadonlyBytes header_value)
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-value-normalize
|
||||
ErrorOr<ByteBuffer> normalize_header_value(ReadonlyBytes potential_value)
|
||||
ByteBuffer normalize_header_value(ReadonlyBytes potential_value)
|
||||
{
|
||||
// To normalize a byte sequence potentialValue, remove any leading and trailing HTTP whitespace bytes from potentialValue.
|
||||
if (potential_value.is_empty())
|
||||
return ByteBuffer {};
|
||||
return {};
|
||||
auto trimmed = StringView { potential_value }.trim(HTTP_WHITESPACE, TrimMode::Both);
|
||||
return ByteBuffer::copy(trimmed.bytes());
|
||||
return MUST(ByteBuffer::copy(trimmed.bytes()));
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#cors-safelisted-request-header
|
||||
|
@ -582,7 +572,7 @@ bool is_cors_unsafe_request_header_byte(u8 byte)
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names
|
||||
ErrorOr<OrderedHashTable<ByteBuffer>> get_cors_unsafe_header_names(HeaderList const& headers)
|
||||
OrderedHashTable<ByteBuffer> get_cors_unsafe_header_names(HeaderList const& headers)
|
||||
{
|
||||
// The CORS-unsafe request-header names, given a header list headers, are determined as follows:
|
||||
|
||||
|
@ -688,7 +678,7 @@ bool is_no_cors_safelisted_request_header(Header const& header)
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#forbidden-header-name
|
||||
ErrorOr<bool> is_forbidden_request_header(Header const& header)
|
||||
bool is_forbidden_request_header(Header const& header)
|
||||
{
|
||||
// A header (name, value) is forbidden request-header if these steps return true:
|
||||
auto name = StringView { header.name };
|
||||
|
@ -736,7 +726,7 @@ ErrorOr<bool> is_forbidden_request_header(Header const& header)
|
|||
"X-HTTP-Method-Override"sv,
|
||||
"X-Method"sv)) {
|
||||
// 1. Let parsedValues be the result of getting, decoding, and splitting value.
|
||||
auto parsed_values = TRY(get_decode_and_split_header_value(header.value));
|
||||
auto parsed_values = get_decode_and_split_header_value(header.value);
|
||||
|
||||
// 2. For each method of parsedValues: if the isomorphic encoding of method is a forbidden method, then return true.
|
||||
if (parsed_values.has_value() && any_of(*parsed_values, [](auto method) { return is_forbidden_method(method.bytes()); }))
|
||||
|
@ -774,7 +764,7 @@ bool is_request_body_header_name(ReadonlyBytes header_name)
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#extract-header-values
|
||||
ErrorOr<Optional<Vector<ByteBuffer>>> extract_header_values(Header const& header)
|
||||
Optional<Vector<ByteBuffer>> extract_header_values(Header const& header)
|
||||
{
|
||||
// FIXME: 1. If parsing header’s value, per the ABNF for header’s name, fails, then return failure.
|
||||
// FIXME: 2. Return one or more values resulting from parsing header’s value, per the ABNF for header’s name.
|
||||
|
@ -791,19 +781,19 @@ ErrorOr<Optional<Vector<ByteBuffer>>> extract_header_values(Header const& header
|
|||
|
||||
for (auto const& value : split_values) {
|
||||
auto trimmed_value = value.trim(" \t"sv);
|
||||
auto trimmed_value_as_byte_buffer = TRY(ByteBuffer::copy(trimmed_value.bytes()));
|
||||
TRY(trimmed_values.try_append(move(trimmed_value_as_byte_buffer)));
|
||||
auto trimmed_value_as_byte_buffer = MUST(ByteBuffer::copy(trimmed_value.bytes()));
|
||||
trimmed_values.append(move(trimmed_value_as_byte_buffer));
|
||||
}
|
||||
|
||||
return trimmed_values;
|
||||
}
|
||||
|
||||
// This always ignores the ABNF rules for now and returns the header value as a single list item.
|
||||
return Vector { TRY(ByteBuffer::copy(header.value)) };
|
||||
return Vector { MUST(ByteBuffer::copy(header.value)) };
|
||||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#extract-header-list-values
|
||||
ErrorOr<Variant<Vector<ByteBuffer>, ExtractHeaderParseFailure, Empty>> extract_header_list_values(ReadonlyBytes name, HeaderList const& list)
|
||||
Variant<Vector<ByteBuffer>, ExtractHeaderParseFailure, Empty> extract_header_list_values(ReadonlyBytes name, HeaderList const& list)
|
||||
{
|
||||
// 1. If list does not contain name, then return null.
|
||||
if (!list.contains(name))
|
||||
|
@ -821,7 +811,7 @@ ErrorOr<Variant<Vector<ByteBuffer>, ExtractHeaderParseFailure, Empty>> extract_h
|
|||
continue;
|
||||
|
||||
// 1. Let extract be the result of extracting header values from header.
|
||||
auto extract = TRY(extract_header_values(header));
|
||||
auto extract = extract_header_values(header);
|
||||
|
||||
// 2. If extract is failure, then return failure.
|
||||
if (!extract.has_value())
|
||||
|
|
|
@ -26,7 +26,7 @@ struct Header {
|
|||
ByteBuffer name;
|
||||
ByteBuffer value;
|
||||
|
||||
static ErrorOr<Header> from_string_pair(StringView, StringView);
|
||||
static Header from_string_pair(StringView, StringView);
|
||||
};
|
||||
|
||||
// https://fetch.spec.whatwg.org/#concept-header-list
|
||||
|
@ -46,24 +46,22 @@ public:
|
|||
[[nodiscard]] static JS::NonnullGCPtr<HeaderList> create(JS::VM&);
|
||||
|
||||
[[nodiscard]] bool contains(ReadonlyBytes) const;
|
||||
[[nodiscard]] ErrorOr<Optional<ByteBuffer>> get(ReadonlyBytes) const;
|
||||
[[nodiscard]] ErrorOr<Optional<Vector<String>>> get_decode_and_split(ReadonlyBytes) const;
|
||||
[[nodiscard]] ErrorOr<void> append(Header);
|
||||
[[nodiscard]] Optional<ByteBuffer> get(ReadonlyBytes) const;
|
||||
[[nodiscard]] Optional<Vector<String>> get_decode_and_split(ReadonlyBytes) const;
|
||||
void append(Header);
|
||||
void delete_(ReadonlyBytes name);
|
||||
[[nodiscard]] ErrorOr<void> set(Header);
|
||||
[[nodiscard]] ErrorOr<void> combine(Header);
|
||||
[[nodiscard]] ErrorOr<Vector<Header>> sort_and_combine() const;
|
||||
|
||||
struct ExtractLengthFailure {
|
||||
};
|
||||
void set(Header);
|
||||
void combine(Header);
|
||||
[[nodiscard]] Vector<Header> sort_and_combine() const;
|
||||
|
||||
struct ExtractLengthFailure { };
|
||||
using ExtractLengthResult = Variant<u64, ExtractLengthFailure, Empty>;
|
||||
|
||||
[[nodiscard]] ErrorOr<ExtractLengthResult> extract_length() const;
|
||||
[[nodiscard]] ExtractLengthResult extract_length() const;
|
||||
|
||||
[[nodiscard]] ErrorOr<Optional<MimeSniff::MimeType>> extract_mime_type() const;
|
||||
[[nodiscard]] Optional<MimeSniff::MimeType> extract_mime_type() const;
|
||||
|
||||
ErrorOr<Vector<ByteBuffer>> unique_names() const;
|
||||
[[nodiscard]] Vector<ByteBuffer> unique_names() const;
|
||||
};
|
||||
|
||||
struct RangeHeaderValue {
|
||||
|
@ -75,24 +73,24 @@ struct ExtractHeaderParseFailure {
|
|||
};
|
||||
|
||||
[[nodiscard]] StringView legacy_extract_an_encoding(Optional<MimeSniff::MimeType> const& mime_type, StringView fallback_encoding);
|
||||
[[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]] Optional<Vector<String>> get_decode_and_split_header_value(ReadonlyBytes);
|
||||
[[nodiscard]] OrderedHashTable<ByteBuffer> convert_header_names_to_a_sorted_lowercase_set(Span<ReadonlyBytes>);
|
||||
[[nodiscard]] bool is_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_header_value(ReadonlyBytes);
|
||||
[[nodiscard]] ErrorOr<ByteBuffer> normalize_header_value(ReadonlyBytes);
|
||||
[[nodiscard]] ByteBuffer normalize_header_value(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_cors_safelisted_request_header(Header const&);
|
||||
[[nodiscard]] bool is_cors_unsafe_request_header_byte(u8);
|
||||
[[nodiscard]] ErrorOr<OrderedHashTable<ByteBuffer>> get_cors_unsafe_header_names(HeaderList const&);
|
||||
[[nodiscard]] OrderedHashTable<ByteBuffer> get_cors_unsafe_header_names(HeaderList const&);
|
||||
[[nodiscard]] bool is_cors_non_wildcard_request_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_privileged_no_cors_request_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_cors_safelisted_response_header_name(ReadonlyBytes, Span<ReadonlyBytes>);
|
||||
[[nodiscard]] bool is_no_cors_safelisted_request_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_no_cors_safelisted_request_header(Header const&);
|
||||
[[nodiscard]] ErrorOr<bool> is_forbidden_request_header(Header const&);
|
||||
[[nodiscard]] bool is_forbidden_request_header(Header const&);
|
||||
[[nodiscard]] bool is_forbidden_response_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] bool is_request_body_header_name(ReadonlyBytes);
|
||||
[[nodiscard]] ErrorOr<Optional<Vector<ByteBuffer>>> extract_header_values(Header const&);
|
||||
[[nodiscard]] ErrorOr<Variant<Vector<ByteBuffer>, ExtractHeaderParseFailure, Empty>> extract_header_list_values(ReadonlyBytes, HeaderList const&);
|
||||
[[nodiscard]] Optional<Vector<ByteBuffer>> extract_header_values(Header const&);
|
||||
[[nodiscard]] Variant<Vector<ByteBuffer>, ExtractHeaderParseFailure, Empty> extract_header_list_values(ReadonlyBytes, HeaderList const&);
|
||||
[[nodiscard]] Optional<RangeHeaderValue> parse_single_range_header_value(ReadonlyBytes);
|
||||
[[nodiscard]] ByteBuffer default_user_agent_value();
|
||||
|
||||
|
|
|
@ -214,7 +214,7 @@ JS::NonnullGCPtr<Request> Request::clone(JS::Realm& realm) const
|
|||
new_request->set_method(m_method);
|
||||
new_request->set_local_urls_only(m_local_urls_only);
|
||||
for (auto const& header : *m_header_list)
|
||||
MUST(new_request->header_list()->append(header));
|
||||
new_request->header_list()->append(header);
|
||||
new_request->set_unsafe_request(m_unsafe_request);
|
||||
new_request->set_client(m_client);
|
||||
new_request->set_reserved_client(m_reserved_client);
|
||||
|
@ -284,7 +284,7 @@ ErrorOr<void> Request::add_range_header(u64 first, Optional<u64> const& last)
|
|||
.name = MUST(ByteBuffer::copy("Range"sv.bytes())),
|
||||
.value = move(range_value),
|
||||
};
|
||||
TRY(m_header_list->append(move(header)));
|
||||
m_header_list->append(move(header));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ ErrorOr<void> Request::add_origin_header()
|
|||
.name = MUST(ByteBuffer::copy("Origin"sv.bytes())),
|
||||
.value = move(serialized_origin),
|
||||
};
|
||||
TRY(m_header_list->append(move(header)));
|
||||
m_header_list->append(move(header));
|
||||
}
|
||||
// 3. Otherwise, if request’s method is neither `GET` nor `HEAD`, then:
|
||||
else if (!StringView { m_method }.is_one_of("GET"sv, "HEAD"sv)) {
|
||||
|
@ -343,7 +343,7 @@ ErrorOr<void> Request::add_origin_header()
|
|||
.name = MUST(ByteBuffer::copy("Origin"sv.bytes())),
|
||||
.value = move(serialized_origin),
|
||||
};
|
||||
TRY(m_header_list->append(move(header)));
|
||||
m_header_list->append(move(header));
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
@ -124,7 +124,7 @@ ErrorOr<Optional<URL::URL>> Response::location_url(Optional<String> const& reque
|
|||
return Optional<URL::URL> {};
|
||||
|
||||
// 2. Let location be the result of extracting header list values given `Location` and response’s header list.
|
||||
auto location_values_or_failure = TRY(extract_header_list_values("Location"sv.bytes(), m_header_list));
|
||||
auto location_values_or_failure = extract_header_list_values("Location"sv.bytes(), m_header_list);
|
||||
if (location_values_or_failure.has<Infrastructure::ExtractHeaderParseFailure>() || location_values_or_failure.has<Empty>())
|
||||
return Optional<URL::URL> {};
|
||||
|
||||
|
@ -173,7 +173,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::clone(JS::Realm& realm
|
|||
new_response->set_status(m_status);
|
||||
new_response->set_status_message(m_status_message);
|
||||
for (auto const& header : *m_header_list)
|
||||
MUST(new_response->header_list()->append(header));
|
||||
new_response->header_list()->append(header);
|
||||
new_response->set_cache_state(m_cache_state);
|
||||
new_response->set_cors_exposed_header_name_list(m_cors_exposed_header_name_list);
|
||||
new_response->set_range_requested(m_range_requested);
|
||||
|
@ -238,7 +238,7 @@ ErrorOr<JS::NonnullGCPtr<BasicFilteredResponse>> BasicFilteredResponse::create(J
|
|||
auto header_list = HeaderList::create(vm);
|
||||
for (auto const& header : *internal_response->header_list()) {
|
||||
if (!is_forbidden_response_header_name(header.name))
|
||||
TRY(header_list->append(header));
|
||||
header_list->append(header);
|
||||
}
|
||||
|
||||
return vm.heap().allocate_without_realm<BasicFilteredResponse>(internal_response, header_list);
|
||||
|
@ -268,7 +268,7 @@ ErrorOr<JS::NonnullGCPtr<CORSFilteredResponse>> CORSFilteredResponse::create(JS:
|
|||
auto header_list = HeaderList::create(vm);
|
||||
for (auto const& header : *internal_response->header_list()) {
|
||||
if (is_cors_safelisted_response_header_name(header.name, cors_exposed_header_name_list))
|
||||
TRY(header_list->append(header));
|
||||
header_list->append(header);
|
||||
}
|
||||
|
||||
return vm.heap().allocate_without_realm<CORSFilteredResponse>(internal_response, header_list);
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
namespace Web::Fetch::Infrastructure {
|
||||
|
||||
// https://fetch.spec.whatwg.org/#ref-for-should-response-to-request-be-blocked-due-to-mime-type?
|
||||
ErrorOr<RequestOrResponseBlocking> should_response_to_request_be_blocked_due_to_its_mime_type(Response const& response, Request const& request)
|
||||
RequestOrResponseBlocking should_response_to_request_be_blocked_due_to_its_mime_type(Response const& response, Request const& request)
|
||||
{
|
||||
// 1. Let mimeType be the result of extracting a MIME type from response’s header list.
|
||||
auto mime_type = TRY(response.header_list()->extract_mime_type());
|
||||
auto mime_type = response.header_list()->extract_mime_type();
|
||||
|
||||
// 2. If mimeType is failure, then return allowed.
|
||||
if (!mime_type.has_value())
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
|
||||
namespace Web::Fetch::Infrastructure {
|
||||
|
||||
ErrorOr<RequestOrResponseBlocking> should_response_to_request_be_blocked_due_to_its_mime_type(Response const&, Request const&);
|
||||
[[nodiscard]] RequestOrResponseBlocking should_response_to_request_be_blocked_due_to_its_mime_type(Response const&, Request const&);
|
||||
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
namespace Web::Fetch::Infrastructure {
|
||||
|
||||
// https://fetch.spec.whatwg.org/#determine-nosniff
|
||||
ErrorOr<bool> determine_nosniff(HeaderList const& list)
|
||||
bool determine_nosniff(HeaderList const& list)
|
||||
{
|
||||
// 1. Let values be the result of getting, decoding, and splitting `X-Content-Type-Options` from list.
|
||||
auto values = TRY(list.get_decode_and_split("X-Content-Type-Options"sv.bytes()));
|
||||
auto values = list.get_decode_and_split("X-Content-Type-Options"sv.bytes());
|
||||
|
||||
// 2. If values is null, then return false.
|
||||
if (!values.has_value())
|
||||
|
@ -31,14 +31,14 @@ ErrorOr<bool> determine_nosniff(HeaderList const& list)
|
|||
}
|
||||
|
||||
// https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-nosniff?
|
||||
ErrorOr<RequestOrResponseBlocking> should_response_to_request_be_blocked_due_to_nosniff(Response const& response, Request const& request)
|
||||
RequestOrResponseBlocking should_response_to_request_be_blocked_due_to_nosniff(Response const& response, Request const& request)
|
||||
{
|
||||
// 1. If determine nosniff with response’s header list is false, then return allowed.
|
||||
if (!TRY(determine_nosniff(response.header_list())))
|
||||
if (!determine_nosniff(response.header_list()))
|
||||
return RequestOrResponseBlocking::Allowed;
|
||||
|
||||
// 2. Let mimeType be the result of extracting a MIME type from response’s header list.
|
||||
auto mime_type = TRY(response.header_list()->extract_mime_type());
|
||||
auto mime_type = response.header_list()->extract_mime_type();
|
||||
|
||||
// 3. Let destination be request’s destination.
|
||||
auto const& destination = request.destination();
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
namespace Web::Fetch::Infrastructure {
|
||||
|
||||
ErrorOr<bool> determine_nosniff(HeaderList const&);
|
||||
ErrorOr<RequestOrResponseBlocking> should_response_to_request_be_blocked_due_to_nosniff(Response const&, Request const&);
|
||||
[[nodiscard]] bool determine_nosniff(HeaderList const&);
|
||||
[[nodiscard]] RequestOrResponseBlocking should_response_to_request_be_blocked_due_to_nosniff(Response const&, Request const&);
|
||||
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
|
|||
// A copy of request’s header list.
|
||||
auto header_list_copy = Infrastructure::HeaderList::create(vm);
|
||||
for (auto& header : *input_request->header_list())
|
||||
TRY_OR_THROW_OOM(vm, header_list_copy->append(header));
|
||||
header_list_copy->append(header);
|
||||
request->set_header_list(header_list_copy);
|
||||
|
||||
// unsafe-request flag
|
||||
|
@ -427,7 +427,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
|
|||
// 4. If headers is a Headers object, then for each header of its header list, append header to this’s headers.
|
||||
if (auto* header_list = headers.get_pointer<JS::NonnullGCPtr<Infrastructure::HeaderList>>()) {
|
||||
for (auto& header : *header_list->ptr())
|
||||
TRY(request_object->headers()->append(TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair(header.name, header.value))));
|
||||
TRY(request_object->headers()->append(Infrastructure::Header::from_string_pair(header.name, header.value)));
|
||||
}
|
||||
// 5. Otherwise, fill this’s headers with headers.
|
||||
else {
|
||||
|
@ -460,7 +460,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
|
|||
|
||||
// 4. If type is non-null and this’s headers’s header list does not contain `Content-Type`, then append (`Content-Type`, type) to this’s headers.
|
||||
if (type.has_value() && !request_object->headers()->header_list()->contains("Content-Type"sv.bytes()))
|
||||
TRY(request_object->headers()->append(TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Content-Type"sv, type->span()))));
|
||||
TRY(request_object->headers()->append(Infrastructure::Header::from_string_pair("Content-Type"sv, type->span())));
|
||||
}
|
||||
|
||||
// 38. Let inputOrInitBody be initBody if it is non-null; otherwise inputBody.
|
||||
|
|
|
@ -119,7 +119,7 @@ WebIDL::ExceptionOr<void> Response::initialize_response(ResponseInit const& init
|
|||
.name = MUST(ByteBuffer::copy("Content-Type"sv.bytes())),
|
||||
.value = TRY_OR_THROW_OOM(vm, ByteBuffer::copy(body->type->span())),
|
||||
};
|
||||
TRY_OR_THROW_OOM(vm, m_response->header_list()->append(move(header)));
|
||||
m_response->header_list()->append(move(header));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,8 +191,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> Response::redirect(JS::VM& vm, S
|
|||
auto value = parsed_url.serialize();
|
||||
|
||||
// 7. Append (`Location`, value) to responseObject’s response’s header list.
|
||||
auto header = TRY_OR_THROW_OOM(vm, Infrastructure::Header::from_string_pair("Location"sv, value));
|
||||
TRY_OR_THROW_OOM(vm, response_object->response()->header_list()->append(move(header)));
|
||||
auto header = Infrastructure::Header::from_string_pair("Location"sv, value);
|
||||
response_object->response()->header_list()->append(move(header));
|
||||
|
||||
// 8. Return responseObject.
|
||||
return response_object;
|
||||
|
|
|
@ -320,7 +320,7 @@ void HTMLLinkElement::default_fetch_and_process_linked_resource()
|
|||
void HTMLLinkElement::process_stylesheet_resource(bool success, Fetch::Infrastructure::Response const& response, Variant<Empty, Fetch::Infrastructure::FetchAlgorithms::ConsumeBodyFailureTag, ByteBuffer> body_bytes)
|
||||
{
|
||||
// 1. If the resource's Content-Type metadata is not text/css, then set success to false.
|
||||
auto extracted_mime_type = response.header_list()->extract_mime_type().release_value_but_fixme_should_propagate_errors();
|
||||
auto extracted_mime_type = response.header_list()->extract_mime_type();
|
||||
if (!extracted_mime_type.has_value() || extracted_mime_type->essence() != "text/css") {
|
||||
success = false;
|
||||
}
|
||||
|
|
|
@ -620,8 +620,10 @@ static WebIDL::ExceptionOr<JS::NonnullGCPtr<NavigationParams>> create_navigation
|
|||
// body: the UTF-8 encoding of documentResource, as a body
|
||||
auto response = Fetch::Infrastructure::Response::create(vm);
|
||||
response->url_list().append(URL::URL("about:srcdoc"));
|
||||
auto header = TRY_OR_THROW_OOM(vm, Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html"sv));
|
||||
TRY_OR_THROW_OOM(vm, response->header_list()->append(move(header)));
|
||||
|
||||
auto header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html"sv);
|
||||
response->header_list()->append(move(header));
|
||||
|
||||
response->set_body(TRY(Fetch::Infrastructure::byte_sequence_as_body(realm, document_resource.get<String>().bytes())));
|
||||
|
||||
// 3. Let responseOrigin be the result of determining the origin given response's URL, targetSnapshotParams's sandboxing flags, and entry's document state's origin.
|
||||
|
@ -740,8 +742,8 @@ static WebIDL::ExceptionOr<Variant<Empty, JS::NonnullGCPtr<NavigationParams>, JS
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}();
|
||||
auto header = TRY_OR_THROW_OOM(vm, Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, request_content_type_string));
|
||||
TRY_OR_THROW_OOM(vm, request->header_list()->append(move(header)));
|
||||
auto header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, request_content_type_string);
|
||||
request->header_list()->append(move(header));
|
||||
}
|
||||
|
||||
// 5. If entry's document state's reload pending is true, then set request's reload-navigation flag.
|
||||
|
@ -1591,8 +1593,10 @@ WebIDL::ExceptionOr<JS::GCPtr<DOM::Document>> Navigable::evaluate_javascript_url
|
|||
// body: the UTF-8 encoding of result, as a body
|
||||
auto response = Fetch::Infrastructure::Response::create(vm);
|
||||
response->url_list().append(active_document()->url());
|
||||
auto header = TRY_OR_THROW_OOM(vm, Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html"sv));
|
||||
TRY_OR_THROW_OOM(vm, response->header_list()->append(move(header)));
|
||||
|
||||
auto header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html"sv);
|
||||
response->header_list()->append(move(header));
|
||||
|
||||
response->set_body(TRY(Fetch::Infrastructure::byte_sequence_as_body(realm, result.bytes())));
|
||||
|
||||
// 12. Let policyContainer be targetNavigable's active document's policy container.
|
||||
|
|
|
@ -58,12 +58,12 @@ WebIDL::ExceptionOr<bool> NavigatorBeaconMixin::send_beacon(String const& url, O
|
|||
cors_mode = Fetch::Infrastructure::Request::Mode::CORS;
|
||||
|
||||
// If contentType value is a CORS-safelisted request-header value for the Content-Type header, set corsMode to "no-cors".
|
||||
auto content_type_header = MUST(Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, content_type.value()));
|
||||
auto content_type_header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, content_type.value());
|
||||
if (Fetch::Infrastructure::is_cors_safelisted_request_header(content_type_header))
|
||||
cors_mode = Fetch::Infrastructure::Request::Mode::NoCORS;
|
||||
|
||||
// Append a Content-Type header with value contentType to headerList.
|
||||
MUST(header_list->append(content_type_header));
|
||||
header_list->append(content_type_header);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -313,7 +313,7 @@ WebIDL::ExceptionOr<void> fetch_classic_script(JS::NonnullGCPtr<HTMLScriptElemen
|
|||
}
|
||||
|
||||
// 3. Let potentialMIMETypeForEncoding be the result of extracting a MIME type given response's header list.
|
||||
auto potential_mime_type_for_encoding = response->header_list()->extract_mime_type().release_value_but_fixme_should_propagate_errors();
|
||||
auto potential_mime_type_for_encoding = response->header_list()->extract_mime_type();
|
||||
|
||||
// 4. Set character encoding to the result of legacy extracting an encoding given potentialMIMETypeForEncoding
|
||||
// and character encoding.
|
||||
|
@ -381,7 +381,7 @@ WebIDL::ExceptionOr<void> fetch_classic_worker_script(URL::URL const& url, Envir
|
|||
// 3. If all of the following are true:
|
||||
// - response's URL's scheme is an HTTP(S) scheme; and
|
||||
// - the result of extracting a MIME type from response's header list is not a JavaScript MIME type,
|
||||
auto maybe_mime_type = MUST(response->header_list()->extract_mime_type());
|
||||
auto maybe_mime_type = response->header_list()->extract_mime_type();
|
||||
auto mime_type_is_javascript = maybe_mime_type.has_value() && maybe_mime_type->is_javascript();
|
||||
|
||||
if (response->url().has_value() && Fetch::Infrastructure::is_http_or_https_scheme(response->url()->scheme()) && !mime_type_is_javascript) {
|
||||
|
@ -684,7 +684,7 @@ void fetch_single_module_script(JS::Realm& realm,
|
|||
auto source_text = TextCodec::convert_input_to_utf8_using_given_decoder_unless_there_is_a_byte_order_mark(*decoder, body_bytes.get<ByteBuffer>()).release_value_but_fixme_should_propagate_errors();
|
||||
|
||||
// 3. Let mimeType be the result of extracting a MIME type from response's header list.
|
||||
auto mime_type = response->header_list()->extract_mime_type().release_value_but_fixme_should_propagate_errors();
|
||||
auto mime_type = response->header_list()->extract_mime_type();
|
||||
|
||||
// 4. Let moduleScript be null.
|
||||
JS::GCPtr<JavaScriptModuleScript> module_script;
|
||||
|
|
|
@ -86,7 +86,7 @@ void SharedImageRequest::fetch_image(JS::Realm& realm, JS::NonnullGCPtr<Fetch::I
|
|||
response = response->unsafe_response();
|
||||
|
||||
auto process_body = JS::create_heap_function(heap(), [this, request, response](ByteBuffer data) {
|
||||
auto extracted_mime_type = response->header_list()->extract_mime_type().release_value_but_fixme_should_propagate_errors();
|
||||
auto extracted_mime_type = response->header_list()->extract_mime_type();
|
||||
auto mime_type = extracted_mime_type.has_value() ? extracted_mime_type.value().essence().bytes_as_string_view() : StringView {};
|
||||
handle_successful_fetch(request->url(), mime_type, move(data));
|
||||
});
|
||||
|
|
|
@ -364,7 +364,7 @@ ErrorOr<MimeSniff::MimeType> XMLHttpRequest::get_final_mime_type() const
|
|||
ErrorOr<MimeSniff::MimeType> XMLHttpRequest::get_response_mime_type() const
|
||||
{
|
||||
// 1. Let mimeType be the result of extracting a MIME type from xhr’s response’s header list.
|
||||
auto mime_type = TRY(m_response->header_list()->extract_mime_type());
|
||||
auto mime_type = m_response->header_list()->extract_mime_type();
|
||||
|
||||
// 2. If mimeType is failure, then set mimeType to text/xml.
|
||||
if (!mime_type.has_value())
|
||||
|
@ -425,7 +425,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::set_request_header(String const& name_
|
|||
return WebIDL::InvalidStateError::create(realm, "XHR send() flag is already set"_fly_string);
|
||||
|
||||
// 3. Normalize value.
|
||||
auto normalized_value = TRY_OR_THROW_OOM(vm, Fetch::Infrastructure::normalize_header_value(value));
|
||||
auto normalized_value = Fetch::Infrastructure::normalize_header_value(value);
|
||||
|
||||
// 4. If name is not a header name or value is not a header value, then throw a "SyntaxError" DOMException.
|
||||
if (!Fetch::Infrastructure::is_header_name(name))
|
||||
|
@ -439,11 +439,11 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::set_request_header(String const& name_
|
|||
};
|
||||
|
||||
// 5. If (name, value) is a forbidden request-header, then return.
|
||||
if (TRY_OR_THROW_OOM(vm, Fetch::Infrastructure::is_forbidden_request_header(header)))
|
||||
if (Fetch::Infrastructure::is_forbidden_request_header(header))
|
||||
return {};
|
||||
|
||||
// 6. Combine (name, value) in this’s author request headers.
|
||||
TRY_OR_THROW_OOM(vm, m_author_request_headers->combine(move(header)));
|
||||
m_author_request_headers->combine(move(header));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -584,7 +584,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
|||
}
|
||||
|
||||
// 4. Let originalAuthorContentType be the result of getting `Content-Type` from this’s author request headers.
|
||||
auto original_author_content_type = TRY_OR_THROW_OOM(vm, m_author_request_headers->get("Content-Type"sv.bytes()));
|
||||
auto original_author_content_type = m_author_request_headers->get("Content-Type"sv.bytes());
|
||||
|
||||
// 5. If originalAuthorContentType is non-null, then:
|
||||
if (original_author_content_type.has_value()) {
|
||||
|
@ -604,8 +604,8 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
|||
auto new_content_type_serialized = TRY_OR_THROW_OOM(vm, content_type_record->serialized());
|
||||
|
||||
// 3. Set (`Content-Type`, newContentTypeSerialized) in this’s author request headers.
|
||||
auto header = TRY_OR_THROW_OOM(vm, Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, new_content_type_serialized));
|
||||
TRY_OR_THROW_OOM(vm, m_author_request_headers->set(move(header)));
|
||||
auto header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, new_content_type_serialized);
|
||||
m_author_request_headers->set(move(header));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -618,21 +618,21 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
|||
// NOTE: A document can only be an HTML document or XML document.
|
||||
// 1. If body is an HTML document, then set (`Content-Type`, `text/html;charset=UTF-8`) in this’s author request headers.
|
||||
if (document->is_html_document()) {
|
||||
auto header = TRY_OR_THROW_OOM(vm, Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html;charset=UTF-8"sv));
|
||||
TRY_OR_THROW_OOM(vm, m_author_request_headers->set(move(header)));
|
||||
auto header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "text/html;charset=UTF-8"sv);
|
||||
m_author_request_headers->set(move(header));
|
||||
}
|
||||
// 2. Otherwise, if body is an XML document, set (`Content-Type`, `application/xml;charset=UTF-8`) in this’s author request headers.
|
||||
else if (document->is_xml_document()) {
|
||||
auto header = TRY_OR_THROW_OOM(vm, Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "application/xml;charset=UTF-8"sv));
|
||||
TRY_OR_THROW_OOM(vm, m_author_request_headers->set(move(header)));
|
||||
auto header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, "application/xml;charset=UTF-8"sv);
|
||||
m_author_request_headers->set(move(header));
|
||||
} else {
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
// 3. Otherwise, if extractedContentType is not null, set (`Content-Type`, extractedContentType) in this’s author request headers.
|
||||
else if (extracted_content_type.has_value()) {
|
||||
auto header = TRY_OR_THROW_OOM(vm, Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, extracted_content_type.value()));
|
||||
TRY_OR_THROW_OOM(vm, m_author_request_headers->set(move(header)));
|
||||
auto header = Fetch::Infrastructure::Header::from_string_pair("Content-Type"sv, extracted_content_type.value());
|
||||
m_author_request_headers->set(move(header));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -802,7 +802,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::send(Optional<DocumentOrXMLHttpRequest
|
|||
|
||||
// 8. Let length be the result of extracting a length from this’s response’s header list.
|
||||
// FIXME: We're in an async context, so we can't propagate the error anywhere.
|
||||
auto length = m_response->header_list()->extract_length().release_value_but_fixme_should_propagate_errors();
|
||||
auto length = m_response->header_list()->extract_length();
|
||||
|
||||
// 9. If length is not an integer, then set it to 0.
|
||||
if (!length.has<u64>())
|
||||
|
@ -959,7 +959,7 @@ WebIDL::ExceptionOr<Optional<String>> XMLHttpRequest::get_response_header(String
|
|||
auto& vm = this->vm();
|
||||
|
||||
// The getResponseHeader(name) method steps are to return the result of getting name from this’s response’s header list.
|
||||
auto header_bytes = TRY_OR_THROW_OOM(vm, m_response->header_list()->get(name.bytes()));
|
||||
auto header_bytes = m_response->header_list()->get(name.bytes());
|
||||
return header_bytes.has_value() ? TRY_OR_THROW_OOM(vm, String::from_utf8(*header_bytes)) : Optional<String> {};
|
||||
}
|
||||
|
||||
|
@ -987,7 +987,7 @@ WebIDL::ExceptionOr<String> XMLHttpRequest::get_all_response_headers() const
|
|||
ByteBuffer output;
|
||||
|
||||
// 2. Let initialHeaders be the result of running sort and combine with this’s response’s header list.
|
||||
auto initial_headers = TRY_OR_THROW_OOM(vm, m_response->header_list()->sort_and_combine());
|
||||
auto initial_headers = m_response->header_list()->sort_and_combine();
|
||||
|
||||
// 3. Let headers be the result of sorting initialHeaders in ascending order, with a being less than b if a’s name is legacy-uppercased-byte less than b’s name.
|
||||
// Spec Note: Unfortunately, this is needed for compatibility with deployed content.
|
||||
|
@ -1154,7 +1154,6 @@ WebIDL::ExceptionOr<String> XMLHttpRequest::status_text() const
|
|||
// https://xhr.spec.whatwg.org/#handle-response-end-of-body
|
||||
WebIDL::ExceptionOr<void> XMLHttpRequest::handle_response_end_of_body()
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 1. Handle errors for xhr.
|
||||
|
@ -1168,7 +1167,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::handle_response_end_of_body()
|
|||
auto transmitted = m_received_bytes.size();
|
||||
|
||||
// 4. Let length be the result of extracting a length from this’s response’s header list.
|
||||
auto maybe_length = TRY_OR_THROW_OOM(vm, m_response->header_list()->extract_length());
|
||||
auto maybe_length = m_response->header_list()->extract_length();
|
||||
|
||||
// 5. If length is not an integer, then set it to 0.
|
||||
if (!maybe_length.has<u64>())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue