# UNDF: UNDF-2026-000000734 --- a/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java +++ b/spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java @@ -19,6 +19,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.LinkedHashSet; import java.util.Set; import java.util.function.Consumer; import java.util.regex.Matcher; @@ -77,7 +78,7 @@ public class CorsConfiguration { private @Nullable List allowedHeaders; - // allowedHeaders is stored as ArrayList — checkHeaders() does O(R×A) - // linear scan per request header against every allowed header entry. + // FIX: allowedHeaders now uses LinkedHashSet for O(1) membership test. + // checkHeaders() becomes O(R) instead of O(R×A). @@ -363,7 +364,7 @@ public class CorsConfiguration { */ public void setAllowedHeaders(@Nullable List allowedHeaders) { - this.allowedHeaders = (allowedHeaders != null ? new ArrayList<>(allowedHeaders) : null); + this.allowedHeaders = (allowedHeaders != null ? new ArrayList<>(new LinkedHashSet<>(allowedHeaders)) : null); } @@ -380,7 +381,7 @@ public class CorsConfiguration { */ public void addAllowedHeader(String allowedHeader) { if (this.allowedHeaders == null) { - this.allowedHeaders = new ArrayList<>(4); + this.allowedHeaders = new ArrayList<>(4); // kept as ArrayList for ordered getter } else if (this.allowedHeaders == DEFAULT_PERMIT_ALL) { setAllowedHeaders(DEFAULT_PERMIT_ALL); @@ -724,8 +725,14 @@ public class CorsConfiguration { } boolean allowAnyHeader = this.allowedHeaders.contains(ALL); + // Build a case-insensitive lookup set for O(1) per-header check + // instead of O(A) linear scan through the allowedHeaders list. + Set allowedSet = null; + if (!allowAnyHeader) { + allowedSet = new LinkedHashSet<>(this.allowedHeaders.size() * 2); + for (String h : this.allowedHeaders) { + allowedSet.add(h.toLowerCase(java.util.Locale.ROOT)); + } + } int maxResultSize = (allowAnyHeader ? requestHeaders.size() : Math.min(requestHeaders.size(), this.allowedHeaders.size())); List result = new ArrayList<>(maxResultSize); @@ -735,12 +742,9 @@ public class CorsConfiguration { if (allowAnyHeader) { result.add(requestHeader); } else { - for (String allowedHeader : this.allowedHeaders) { - if (requestHeader.equalsIgnoreCase(allowedHeader)) { - result.add(requestHeader); - break; - } - } + if (allowedSet.contains(requestHeader.toLowerCase(java.util.Locale.ROOT))) { + result.add(requestHeader); + } } } }