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 // 2. For each token returned by extracting header list values given Content-Security-Policy and responses header
// list: // list:
auto enforce_policy_tokens_or_failure = response->header_list()->extract_header_list_values("Content-Security-Policy"sv.bytes()); 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 (auto const* enforce_policy_tokens = enforce_policy_tokens_or_failure.get_pointer<Vector<ByteBuffer>>()) {
if (!policy->m_directives.is_empty()) { for (auto const& enforce_policy_token : *enforce_policy_tokens) {
policies.append(policy); // 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 // 3. For each token returned by extracting header list values given Content-Security-Policy-Report-Only and
// responses header list: // 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_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 (auto const* report_policy_tokens = enforce_policy_tokens_or_failure.get_pointer<Vector<ByteBuffer>>()) {
if (!policy->m_directives.is_empty()) { for (auto const& report_policy_token : *report_policy_tokens) {
policies.append(policy); // 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 // 1. Let headerNames be the result of extracting header list values given
// `Access-Control-Expose-Headers` and responses header list. // `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_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 if (auto* header_names = header_names_or_failure.get_pointer<Vector<ByteBuffer>>()) {
// responses CORS-exposed header-name list to all unique header names in responses header // 2. If requests credentials mode is not "include" and headerNames contains `*`, then set
// list. // responses CORS-exposed header-name list to all unique header names in responses header
if (request->credentials_mode() != Infrastructure::Request::CredentialsMode::Include && header_names.contains_slow("*"sv.bytes())) { // list.
auto unique_header_names = response->header_list()->unique_names(); if (request->credentials_mode() != Infrastructure::Request::CredentialsMode::Include && header_names->contains_slow("*"sv.bytes())) {
response->set_cors_exposed_header_name_list(move(unique_header_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 }
// header-name list to headerNames. // 3. Otherwise, if headerNames is not null or failure, then set responses CORS-exposed
else if (!header_names.is_empty()) { // header-name list to headerNames.
response->set_cors_exposed_header_name_list(move(header_names)); 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. // 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. // 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. // 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. // 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. // 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()); 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>()) auto const* location_values = location_values_or_failure.get_pointer<Vector<ByteBuffer>>();
return Optional<URL::URL> {};
auto const& location_values = location_values_or_failure.get<Vector<ByteBuffer>>(); if (!location_values || location_values->size() != 1)
if (location_values.size() != 1) return OptionalNone {};
return Optional<URL::URL> {};
// 3. If location is a header value, then set location to the result of parsing location with responses URL. // 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()) if (!location.has_value())
return Error::from_string_literal("Invalid 'Location' header URL"); 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. // 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_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. // 2. Let policy be the empty string.
auto policy = ReferrerPolicy::EmptyString; 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. // 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) { if (auto const* policy_tokens = policy_tokens_or_failure.get_pointer<Vector<ByteBuffer>>()) {
auto referrer_policy = from_string(token); for (auto const& token : *policy_tokens) {
if (referrer_policy.has_value() && referrer_policy.value() != ReferrerPolicy::EmptyString) auto referrer_policy = from_string(token);
policy = referrer_policy.release_value(); if (referrer_policy.has_value() && referrer_policy.value() != ReferrerPolicy::EmptyString)
policy = referrer_policy.release_value();
}
} }
// 4. Return policy. // 4. Return policy.