LibWeb: Remove OOM propagation from Fetch::Infrastructure::Headers

This commit is contained in:
Timothy Flynn 2024-04-26 13:24:20 -04:00 committed by Andreas Kling
commit c79f46fe6f
Notes: sideshowbarker 2024-07-17 09:47:09 +09:00
23 changed files with 212 additions and 225 deletions

View file

@ -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.

View file

@ -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();

View file

@ -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 responses 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 responses 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 responses 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))

View file

@ -174,15 +174,15 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Infrastructure::FetchController>> fetch(JS:
}
// 3. Append (`Accept`, value) to requests 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 requests header list does not contain `Accept-Language`, then user agents should append
// (`Accept-Language, an appropriate header value) to requests 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 requests priority is null, then use requests 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 requests 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 responses 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 requests credentials mode is not "include" and headerNames contains `*`, then set
// responses CORS-exposed header-name list to all unique header names in responses 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 responses 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 responses 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 dataURLStructs 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 requests 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 httpRequests 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 httpRequests cache mode is "default" and httpRequests 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 httpRequests cache mode is "no-store" or "reload", then:
@ -1391,15 +1395,15 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fet
// 1. If httpRequests header list does not contain `Pragma`, then append (`Pragma`, `no-cache`) to
// httpRequests 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 httpRequests header list does not contain `Cache-Control`, then append
// (`Cache-Control`, `no-cache`) to httpRequests 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 httpRequests header list per HTTP. Do not append a given header if httpRequests 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 httpRequests 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
// httpRequests 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 preflights 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`, requests method) to preflights 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 requests 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 responses 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
// responses 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 requests header list, if unsafeName is not a
// byte-case-insensitive match for an item in headerNames and requests 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;

View file

@ -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 thiss 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 thiss header list.
TRY_OR_THROW_OOM(vm, m_header_list->set(move(header)));
m_header_list->set(move(header));
// 5. If thiss 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 thiss 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 idlObjects 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 idlObjects 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 headerss 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 headerss 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 headerss guard is "request-no-cors":
if (m_guard == Guard::RequestNoCORS) {
// 1. Let temporaryValue be the result of getting name from headerss 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 headerss header list.
TRY_OR_THROW_OOM(vm, m_header_list->append(move(header)));
m_header_list->append(move(header));
// 5. If headerss 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 {};

View file

@ -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 thiss 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();

View file

@ -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;

View file

@ -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 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()) {
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 headers value, per the ABNF for headers name, fails, then return failure.
// FIXME: 2. Return one or more values resulting from parsing headers value, per the ABNF for headers 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())

View file

@ -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();

View file

@ -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 requests 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 {};

View file

@ -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 responses 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);

View file

@ -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 responses 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())

View file

@ -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&);
}

View file

@ -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 responses 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 responses 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 requests destination.
auto const& destination = request.destination();

View file

@ -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&);
}

View file

@ -188,7 +188,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Request>> Request::construct_impl(JS::Realm
// A copy of requests 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 thiss 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 thiss 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 thiss headerss header list does not contain `Content-Type`, then append (`Content-Type`, type) to thiss 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.

View file

@ -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 responseObjects responses 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;

View file

@ -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;
}

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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));
});

View file

@ -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 xhrs responses 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 thiss 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 thiss 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 thiss 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 thiss 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 thiss 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 thiss 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 thiss responses 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 thiss responses 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 thiss responses 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 as name is legacy-uppercased-byte less than bs 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 thiss responses 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>())