001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.cors;
018
019import javax.servlet.http.HttpServletRequest;
020
021import org.springframework.http.HttpHeaders;
022import org.springframework.http.HttpMethod;
023import org.springframework.lang.Nullable;
024import org.springframework.util.ObjectUtils;
025import org.springframework.web.util.UriComponents;
026import org.springframework.web.util.UriComponentsBuilder;
027
028/**
029 * Utility class for CORS request handling based on the
030 * <a href="https://www.w3.org/TR/cors/">CORS W3C recommendation</a>.
031 *
032 * @author Sebastien Deleuze
033 * @since 4.2
034 */
035public abstract class CorsUtils {
036
037        /**
038         * Returns {@code true} if the request is a valid CORS one by checking {@code Origin}
039         * header presence and ensuring that origins are different.
040         */
041        public static boolean isCorsRequest(HttpServletRequest request) {
042                String origin = request.getHeader(HttpHeaders.ORIGIN);
043                if (origin == null) {
044                        return false;
045                }
046                UriComponents originUrl = UriComponentsBuilder.fromOriginHeader(origin).build();
047                String scheme = request.getScheme();
048                String host = request.getServerName();
049                int port = request.getServerPort();
050                return !(ObjectUtils.nullSafeEquals(scheme, originUrl.getScheme()) &&
051                                ObjectUtils.nullSafeEquals(host, originUrl.getHost()) &&
052                                getPort(scheme, port) == getPort(originUrl.getScheme(), originUrl.getPort()));
053
054        }
055
056        private static int getPort(@Nullable String scheme, int port) {
057                if (port == -1) {
058                        if ("http".equals(scheme) || "ws".equals(scheme)) {
059                                port = 80;
060                        }
061                        else if ("https".equals(scheme) || "wss".equals(scheme)) {
062                                port = 443;
063                        }
064                }
065                return port;
066        }
067
068        /**
069         * Returns {@code true} if the request is a valid CORS pre-flight one by checking {code OPTIONS} method with
070         * {@code Origin} and {@code Access-Control-Request-Method} headers presence.
071         */
072        public static boolean isPreFlightRequest(HttpServletRequest request) {
073                return (HttpMethod.OPTIONS.matches(request.getMethod()) &&
074                                request.getHeader(HttpHeaders.ORIGIN) != null &&
075                                request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null);
076        }
077
078}