cc.shacocloud.mirage.web.util.CorsUtils Maven / Gradle / Ivy
package cc.shacocloud.mirage.web.util;
import cc.shacocloud.mirage.web.HttpRequest;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod;
import org.jetbrains.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* CORS请求处理的工具类 W3C CORS 标准.
*/
public abstract class CorsUtils {
private static final String SCHEME_PATTERN = "([^:/?#]+):";
private static final String USERINFO_PATTERN = "([^@\\[/?#]*)";
private static final String HOST_IPV4_PATTERN = "[^\\[/?#:]*";
private static final String HOST_IPV6_PATTERN = "\\[[\\p{XDigit}:.]*[%\\p{Alnum}]*]";
private static final String HOST_PATTERN = "(" + HOST_IPV6_PATTERN + "|" + HOST_IPV4_PATTERN + ")";
private static final String PORT_PATTERN = "(\\d*(?:\\{[^/]+?})?)";
private static final String PATH_PATTERN = "([^?#]*)";
private static final String QUERY_PATTERN = "([^#]*)";
private static final String LAST_PATTERN = "(.*)";
// 匹配uri的正则表达式模式 见 RFC 3986, 附录 B
private static final Pattern URI_PATTERN = Pattern.compile(
"^(" + SCHEME_PATTERN + ")?" + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN +
")?" + ")?" + PATH_PATTERN + "(\\?" + QUERY_PATTERN + ")?" + "(#" + LAST_PATTERN + ")?");
/**
* 如果请求是有效的CORS,通过检查源头是否存在并确保源是不同的,返回{@code true}
*/
public static boolean isCorsRequest(HttpRequest request) {
String origin = request.headers().get(HttpHeaders.ORIGIN);
if (origin == null) return false;
Matcher matcher = URI_PATTERN.matcher(origin);
Assert.isTrue(matcher.matches(), "[" + origin + "] 不是有效的 \"Origin\" 请求头");
String originScheme = matcher.group(2);
String originHost = matcher.group(6);
String originPortStr = matcher.group(8);
// 端口解析判断
int originPort;
if (originPortStr == null) {
originPort = -1;
} else if (originPortStr.contains("{")) {
throw new IllegalStateException("该端口包含一个URI变量,但尚未展开: " + originPortStr);
} else {
originPort = Integer.parseInt(originPortStr);
}
String scheme = request.getScheme();
String host = request.getServerName();
int port = request.getServerPort();
return !(ObjectUtils.nullSafeEquals(scheme, originScheme) &&
ObjectUtils.nullSafeEquals(host, originHost) &&
getPort(scheme, port) == getPort(originScheme, originPort));
}
private static int getPort(@Nullable String scheme, int port) {
if (port == -1) {
if ("http".equals(scheme) || "ws".equals(scheme)) {
port = 80;
} else if ("https".equals(scheme) || "wss".equals(scheme)) {
port = 443;
}
}
return port;
}
/**
* 如果请求是一个有效的CORS 执行前检查{code OPTIONS}方法的起源和访问-控制-请求-方法头存在。
*/
public static boolean isPreFlightRequest(HttpRequest request) {
return HttpMethod.OPTIONS == request.method() &&
request.headers().get(HttpHeaders.ORIGIN) != null &&
request.headers().get(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy