LibWeb: Do not copy the result of HeaderList::extract_header_list_values

There's no need to copy the Vector out of this result every time we call
it. We can move it out or access it directly.
This commit is contained in:
Timothy Flynn 2025-11-25 11:09:28 -05:00 committed by Tim Flynn
parent 44fbf6451e
commit ed27eea091
Notes: github-actions[bot] 2025-11-26 14:16:24 +00:00
4 changed files with 45 additions and 39 deletions

View file

@ -102,28 +102,30 @@ GC::Ref<PolicyList> Policy::parse_a_responses_content_security_policies(GC::Heap
// 2. For each token returned by extracting header list values given Content-Security-Policy and responses header
// list:
auto enforce_policy_tokens_or_failure = response->header_list()->extract_header_list_values("Content-Security-Policy"sv.bytes());
auto enforce_policy_tokens = enforce_policy_tokens_or_failure.has<Vector<ByteBuffer>>() ? enforce_policy_tokens_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
for (auto const& enforce_policy_token : enforce_policy_tokens) {
// 1. Let policy be the result of parsing token, with a source of "header", and a disposition of "enforce".
auto policy = parse_a_serialized_csp(heap, enforce_policy_token, Policy::Source::Header, Policy::Disposition::Enforce);
// 2. If policys directive set is not empty, append policy to policies.
if (!policy->m_directives.is_empty()) {
policies.append(policy);
if (auto const* enforce_policy_tokens = enforce_policy_tokens_or_failure.get_pointer<Vector<ByteBuffer>>()) {
for (auto const& enforce_policy_token : *enforce_policy_tokens) {
// 1. Let policy be the result of parsing token, with a source of "header", and a disposition of "enforce".
auto policy = parse_a_serialized_csp(heap, enforce_policy_token, Policy::Source::Header, Policy::Disposition::Enforce);
// 2. If policys directive set is not empty, append policy to policies.
if (!policy->m_directives.is_empty())
policies.append(policy);
}
}
// 3. For each token returned by extracting header list values given Content-Security-Policy-Report-Only and
// responses header list:
auto report_policy_tokens_or_failure = response->header_list()->extract_header_list_values("Content-Security-Policy-Report-Only"sv.bytes());
auto report_policy_tokens = report_policy_tokens_or_failure.has<Vector<ByteBuffer>>() ? report_policy_tokens_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
for (auto const& report_policy_token : report_policy_tokens) {
// 1. Let policy be the result of parsing token, with a source of "header", and a disposition of "report".
auto policy = parse_a_serialized_csp(heap, report_policy_token, Policy::Source::Header, Policy::Disposition::Report);
// 2. If policys directive set is not empty, append policy to policies.
if (!policy->m_directives.is_empty()) {
policies.append(policy);
if (auto const* report_policy_tokens = enforce_policy_tokens_or_failure.get_pointer<Vector<ByteBuffer>>()) {
for (auto const& report_policy_token : *report_policy_tokens) {
// 1. Let policy be the result of parsing token, with a source of "header", and a disposition of "report".
auto policy = parse_a_serialized_csp(heap, report_policy_token, Policy::Source::Header, Policy::Disposition::Report);
// 2. If policys directive set is not empty, append policy to policies.
if (!policy->m_directives.is_empty())
policies.append(policy);
}
}

View file

@ -496,19 +496,20 @@ GC::Ptr<PendingResponse> main_fetch(JS::Realm& realm, Infrastructure::FetchParam
// 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 = response->header_list()->extract_header_list_values("Access-Control-Expose-Headers"sv.bytes());
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 = 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
// header-name list to headerNames.
else if (!header_names.is_empty()) {
response->set_cors_exposed_header_name_list(move(header_names));
if (auto* header_names = header_names_or_failure.get_pointer<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 = 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
// header-name list to headerNames.
else if (!header_names->is_empty()) {
response->set_cors_exposed_header_name_list(move(*header_names));
}
}
}
@ -2531,10 +2532,14 @@ GC::Ref<PendingResponse> cors_preflight_fetch(JS::Realm& realm, Infrastructure::
}
// NOTE: We treat "methods_or_failure" being `Empty` as empty Vector here.
auto methods = methods_or_failure.has<Vector<ByteBuffer>>() ? methods_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
auto methods = methods_or_failure.visit(
[](Vector<ByteBuffer>& methods) { return move(methods); },
[](auto) -> Vector<ByteBuffer> { return {}; });
// NOTE: We treat "header_names_or_failure" being `Empty` as empty Vector here.
auto header_names = header_names_or_failure.has<Vector<ByteBuffer>>() ? header_names_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
auto header_names = header_names_or_failure.visit(
[](Vector<ByteBuffer>& header_names) { return move(header_names); },
[](auto) -> Vector<ByteBuffer> { return {}; });
// 4. If methods is null and requests use-CORS-preflight flag is set, then set methods to a new list containing requests method.
// NOTE: This ensures that a CORS-preflight fetch that happened due to requests use-CORS-preflight flag being set is cached.

View file

@ -126,15 +126,13 @@ ErrorOr<Optional<URL::URL>> Response::location_url(Optional<String> const& reque
// 2. Let location be the result of extracting header list values given `Location` and responses header list.
auto location_values_or_failure = m_header_list->extract_header_list_values("Location"sv.bytes());
if (location_values_or_failure.has<Infrastructure::HeaderList::ExtractHeaderParseFailure>() || location_values_or_failure.has<Empty>())
return Optional<URL::URL> {};
auto const* location_values = location_values_or_failure.get_pointer<Vector<ByteBuffer>>();
auto const& location_values = location_values_or_failure.get<Vector<ByteBuffer>>();
if (location_values.size() != 1)
return Optional<URL::URL> {};
if (!location_values || location_values->size() != 1)
return OptionalNone {};
// 3. If location is a header value, then set location to the result of parsing location with responses URL.
auto location = DOMURL::parse(location_values.first(), url());
auto location = DOMURL::parse(location_values->first(), url());
if (!location.has_value())
return Error::from_string_literal("Invalid 'Location' header URL");

View file

@ -23,16 +23,17 @@ ReferrerPolicy parse_a_referrer_policy_from_a_referrer_policy_header(Fetch::Infr
{
// 1. Let policy-tokens be the result of extracting header list values given `Referrer-Policy` and responses header list.
auto policy_tokens_or_failure = response.header_list()->extract_header_list_values("Referrer-Policy"sv.bytes());
auto policy_tokens = policy_tokens_or_failure.has<Vector<ByteBuffer>>() ? policy_tokens_or_failure.get<Vector<ByteBuffer>>() : Vector<ByteBuffer> {};
// 2. Let policy be the empty string.
auto policy = ReferrerPolicy::EmptyString;
// 3. For each token in policy-tokens, if token is a referrer policy and token is not the empty string, then set policy to token.
for (auto token : policy_tokens) {
auto referrer_policy = from_string(token);
if (referrer_policy.has_value() && referrer_policy.value() != ReferrerPolicy::EmptyString)
policy = referrer_policy.release_value();
if (auto const* policy_tokens = policy_tokens_or_failure.get_pointer<Vector<ByteBuffer>>()) {
for (auto const& token : *policy_tokens) {
auto referrer_policy = from_string(token);
if (referrer_policy.has_value() && referrer_policy.value() != ReferrerPolicy::EmptyString)
policy = referrer_policy.release_value();
}
}
// 4. Return policy.