Support coma-delimited format for origin values
Closes gh-27606
This commit is contained in:
@@ -21,11 +21,10 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -120,9 +119,16 @@ public class CorsConfiguration {
|
||||
|
||||
|
||||
/**
|
||||
* A list of origins for which cross-origin requests are allowed. Values may
|
||||
* be a specific domain, e.g. {@code "https://domain1.com"}, or the CORS
|
||||
* defined special value {@code "*"} for all origins.
|
||||
* A list of origins for which cross-origin requests are allowed where each
|
||||
* value may be one of the following:
|
||||
* <ul>
|
||||
* <li>a specific domain, e.g. {@code "https://domain1.com"}
|
||||
* <li>coma-delimited list of specific domains, e.g.
|
||||
* {@code "https://a1.com,https://a2.com"}; this is convenient when a value
|
||||
* is resolved through a property placeholder, e.g. {@code "${origin}"};
|
||||
* note that such placeholders must be resolved externally.
|
||||
* <li>the CORS defined special value {@code "*"} for all origins
|
||||
* </ul>
|
||||
* <p>For matched pre-flight and actual requests the
|
||||
* {@code Access-Control-Allow-Origin} response header is set either to the
|
||||
* matched domain value or to {@code "*"}. Keep in mind however that the
|
||||
@@ -135,8 +141,15 @@ public class CorsConfiguration {
|
||||
* {@code @CrossOrigin}, via {@link #applyPermitDefaultValues()}.
|
||||
*/
|
||||
public void setAllowedOrigins(@Nullable List<String> origins) {
|
||||
this.allowedOrigins = (origins == null ? null :
|
||||
origins.stream().filter(Objects::nonNull).map(this::trimTrailingSlash).collect(Collectors.toList()));
|
||||
if (origins == null) {
|
||||
this.allowedOrigins = null;
|
||||
}
|
||||
else {
|
||||
this.allowedOrigins = new ArrayList<>(origins.size());
|
||||
for (String origin : origins) {
|
||||
addAllowedOrigin(origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String trimTrailingSlash(String origin) {
|
||||
@@ -164,8 +177,10 @@ public class CorsConfiguration {
|
||||
else if (this.allowedOrigins == DEFAULT_PERMIT_ALL && CollectionUtils.isEmpty(this.allowedOriginPatterns)) {
|
||||
setAllowedOrigins(DEFAULT_PERMIT_ALL);
|
||||
}
|
||||
origin = trimTrailingSlash(origin);
|
||||
this.allowedOrigins.add(origin);
|
||||
parseComaDelimitedOrigin(origin, value -> {
|
||||
value = trimTrailingSlash(value);
|
||||
this.allowedOrigins.add(value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,12 +193,16 @@ public class CorsConfiguration {
|
||||
* domain1.com on port 8080 or port 8081
|
||||
* <li>{@literal https://*.domain1.com:[*]} -- domains ending with
|
||||
* domain1.com on any port, including the default port
|
||||
* <li>coma-delimited list of patters, e.g.
|
||||
* {@code "https://*.a1.com,https://*.a2.com"}; this is convenient when a
|
||||
* value is resolved through a property placeholder, e.g. {@code "${origin}"};
|
||||
* note that such placeholders must be resolved externally.
|
||||
* </ul>
|
||||
* <p>In contrast to {@link #setAllowedOrigins(List) allowedOrigins} which
|
||||
* only supports "*" and cannot be used with {@code allowCredentials}, when
|
||||
* an allowedOriginPattern is matched, the {@code Access-Control-Allow-Origin}
|
||||
* response header is set to the matched origin and not to {@code "*"} nor
|
||||
* to the pattern. Therefore allowedOriginPatterns can be used in combination
|
||||
* to the pattern. Therefore, allowedOriginPatterns can be used in combination
|
||||
* with {@link #setAllowCredentials} set to {@code true}.
|
||||
* <p>By default this is not set.
|
||||
* @since 5.3
|
||||
@@ -226,10 +245,40 @@ public class CorsConfiguration {
|
||||
if (this.allowedOriginPatterns == null) {
|
||||
this.allowedOriginPatterns = new ArrayList<>(4);
|
||||
}
|
||||
originPattern = trimTrailingSlash(originPattern);
|
||||
this.allowedOriginPatterns.add(new OriginPattern(originPattern));
|
||||
if (this.allowedOrigins == DEFAULT_PERMIT_ALL) {
|
||||
this.allowedOrigins = null;
|
||||
parseComaDelimitedOrigin(originPattern, value -> {
|
||||
value = trimTrailingSlash(value);
|
||||
this.allowedOriginPatterns.add(new OriginPattern(value));
|
||||
if (this.allowedOrigins == DEFAULT_PERMIT_ALL) {
|
||||
this.allowedOrigins = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void parseComaDelimitedOrigin(String rawValue, Consumer<String> valueConsumer) {
|
||||
if (rawValue.indexOf(',') == -1) {
|
||||
valueConsumer.accept(rawValue);
|
||||
return;
|
||||
}
|
||||
int start = 0;
|
||||
boolean withinPortRange = false;
|
||||
for (int current = 0; current < rawValue.length(); current++) {
|
||||
switch (rawValue.charAt(current)) {
|
||||
case '[':
|
||||
withinPortRange = true;
|
||||
break;
|
||||
case ']':
|
||||
withinPortRange = false;
|
||||
break;
|
||||
case ',':
|
||||
if (!withinPortRange) {
|
||||
valueConsumer.accept(rawValue.substring(start, current).trim());
|
||||
start = current + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start < rawValue.length()) {
|
||||
valueConsumer.accept(rawValue.substring(start));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user