
io.muserver.rest.CORSConfig Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mu-server Show documentation
Show all versions of mu-server Show documentation
A simple but powerful web server framework
The newest version!
package io.muserver.rest;
import io.muserver.*;
import java.util.*;
import java.util.regex.Pattern;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toSet;
/**
* CORS configuration for REST resources. Create this using {@link CORSConfigBuilder#corsConfig()}
*/
public class CORSConfig {
private final boolean allowCredentials;
private final Collection allowedOrigins;
private final List allowedOriginRegex;
private final Collection exposedHeaders;
private final long maxAge;
private final Collection allowedHeaders;
private final String exposedHeadersCSV;
private final String allowedHeadersCSV;
CORSConfig(boolean allowCredentials, Collection allowedOrigins, List allowedOriginRegex, Collection allowedHeaders, Collection exposedHeaders, long maxAge) {
Mutils.notNull("allowedOriginRegex", allowedOriginRegex);
this.allowCredentials = allowCredentials;
this.allowedOrigins = allowedOrigins == null ? null : Collections.unmodifiableCollection(allowedOrigins);
this.allowedOriginRegex = allowedOriginRegex;
this.maxAge = maxAge;
this.allowedHeaders = allowedHeaders;
this.allowedHeadersCSV = String.join(", ", allowedHeaders);
this.exposedHeaders = Collections.unmodifiableCollection(exposedHeaders);
this.exposedHeadersCSV = String.join(", ", exposedHeaders);
}
/**
* Adds CORS headers to the response, if needed.
*
* @param request The request
* @param response The response to add headers to
* @param allowedMethods The methods
* @return Returns true if any Access Control headers were added; otherwise false. (Note: the Vary: origin
header is always added.
*/
public boolean writeHeaders(MuRequest request, MuResponse response, Set allowedMethods) {
boolean written = writeHeadersInternal(request, response, null);
if (written) {
response.headers().set(HeaderNames.ACCESS_CONTROL_ALLOW_METHODS, getAllowedString(allowedMethods));
}
return written;
}
boolean writeHeadersInternal(MuRequest request, MuResponse response, Set matchedMethodsForPath) {
Headers respHeaders = response.headers();
if (!respHeaders.containsValue(HeaderNames.VARY, HeaderNames.ORIGIN, true)) {
respHeaders.add(HeaderNames.VARY, HeaderNames.ORIGIN);
}
String origin = request.headers().get(HeaderNames.ORIGIN);
if (Mutils.nullOrEmpty(origin)) {
return false;
}
if (allowCors(origin)) {
respHeaders.set(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN, origin);
if (matchedMethodsForPath != null) {
String allowed = getAllowedMethods(matchedMethodsForPath);
respHeaders.set(HeaderNames.ACCESS_CONTROL_ALLOW_METHODS, allowed);
}
if (request.method() == Method.OPTIONS) {
respHeaders.set(HeaderNames.ACCESS_CONTROL_MAX_AGE, maxAge);
if (!allowedHeaders.isEmpty()) {
respHeaders.set(HeaderNames.ACCESS_CONTROL_ALLOW_HEADERS, allowedHeadersCSV);
}
}
if (!exposedHeaders.isEmpty()) {
respHeaders.set(HeaderNames.ACCESS_CONTROL_EXPOSE_HEADERS, exposedHeadersCSV);
}
if (allowCredentials) {
respHeaders.set(HeaderNames.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
}
return true;
} else {
respHeaders.remove(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN);
return false;
}
}
static String getAllowedMethods(Set matchedMethodsForPath) {
Set methods = matchedMethodsForPath.stream().map(m -> m.resourceMethod.httpMethod).collect(toSet());
return getAllowedString(methods);
}
static String getAllowedString(Set allowed) {
if (allowed.contains(Method.GET)) {
allowed.add(Method.HEAD);
}
allowed.add(Method.OPTIONS);
return allowed.stream().map(Enum::name).sorted().collect(joining(", "));
}
boolean allowCors(String origin) {
if (allowedOrigins == null || allowedOrigins.contains(origin)) {
return true;
}
for (Pattern pattern : allowedOriginRegex) {
if (pattern.matcher(origin).matches()) {
return true;
}
}
return false;
}
/**
* @return the value described by {@link CORSConfigBuilder#withAllowCredentials}
*/
public boolean allowCredentials() {
return allowCredentials;
}
/**
@return the value described by {@link CORSConfigBuilder#withAllowedOrigins}
*/
public Collection allowedOrigins() {
return allowedOrigins;
}
/**
@return the value described by {@link CORSConfigBuilder#withAllowedOriginRegex}
*/
public List allowedOriginRegex() {
return allowedOriginRegex;
}
/**
@return the value described by {@link CORSConfigBuilder#withExposedHeaders}
*/
public Collection exposedHeaders() {
return exposedHeaders;
}
/**
@return the value described by {@link CORSConfigBuilder#withMaxAge}
*/
public long maxAge() {
return maxAge;
}
/**
@return the value described by {@link CORSConfigBuilder#withAllowedHeaders}
*/
public Collection allowedHeaders() {
return allowedHeaders;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CORSConfig that = (CORSConfig) o;
return allowCredentials == that.allowCredentials && maxAge == that.maxAge && Objects.equals(allowedOrigins, that.allowedOrigins) && Objects.equals(allowedOriginRegex, that.allowedOriginRegex) && Objects.equals(exposedHeaders, that.exposedHeaders) && Objects.equals(allowedHeaders, that.allowedHeaders) && Objects.equals(exposedHeadersCSV, that.exposedHeadersCSV) && Objects.equals(allowedHeadersCSV, that.allowedHeadersCSV);
}
@Override
public int hashCode() {
return Objects.hash(allowCredentials, allowedOrigins, allowedOriginRegex, exposedHeaders, maxAge, allowedHeaders, exposedHeadersCSV, allowedHeadersCSV);
}
@Override
public String toString() {
return "CORSConfig{" +
"allowCredentials=" + allowCredentials +
", allowedOrigins=" + allowedOrigins +
", allowedOriginRegex=" + allowedOriginRegex +
", exposedHeaders=" + exposedHeaders +
", maxAge=" + maxAge +
", allowedHeaders=" + allowedHeaders +
", exposedHeadersCSV='" + exposedHeadersCSV + '\'' +
", allowedHeadersCSV='" + allowedHeadersCSV + '\'' +
'}';
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy