All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.web.cors.UrlBasedCorsConfigurationSource Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.cors;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import jakarta.servlet.http.HttpServletRequest;

import org.springframework.http.server.PathContainer;
import org.springframework.lang.Nullable;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;
import org.springframework.web.util.ServletRequestPathUtils;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;

/**
 * {@code CorsConfigurationSource} that uses URL path patterns to select the
 * {@code CorsConfiguration} for a request.
 *
 * 

Pattern matching can be done with a {@link PathMatcher} or with pre-parsed * {@link PathPattern}s. The syntax is largely the same with the latter being more * tailored for web usage and more efficient. The choice depends on the presence of a * {@link UrlPathHelper#resolveAndCacheLookupPath resolved} String lookupPath or a * {@link ServletRequestPathUtils#parseAndCache parsed} {@code RequestPath} * with a fallback on {@link PathMatcher} but the fallback can be disabled. * For more details, please see {@link #setAllowInitLookupPath(boolean)}. * * @author Sebastien Deleuze * @author Rossen Stoyanchev * @since 4.2 * @see PathPattern * @see AntPathMatcher */ public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource { private static final PathMatcher defaultPathMatcher = new AntPathMatcher(); private final PathPatternParser patternParser; private UrlPathHelper urlPathHelper = UrlPathHelper.defaultInstance; private PathMatcher pathMatcher = defaultPathMatcher; @Nullable private String lookupPathAttributeName; private boolean allowInitLookupPath = true; private final Map corsConfigurations = new LinkedHashMap<>(); /** * Default constructor with {@link PathPatternParser#defaultInstance}. */ public UrlBasedCorsConfigurationSource() { this(PathPatternParser.defaultInstance); } /** * Constructor with a {@link PathPatternParser} to parse patterns with. * @param parser the parser to use * @since 5.3 */ public UrlBasedCorsConfigurationSource(PathPatternParser parser) { Assert.notNull(parser, "PathPatternParser must not be null"); this.patternParser = parser; } /** * Shortcut to the * {@link org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath * same property} on the configured {@code UrlPathHelper}. * @deprecated as of 5.3 in favor of using * {@link #setUrlPathHelper(UrlPathHelper)}, if at all. For further details, * please see {@link #setAllowInitLookupPath(boolean)}. */ @Deprecated public void setAlwaysUseFullPath(boolean alwaysUseFullPath) { initUrlPathHelper(); this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath); } /** * Shortcut to the * {@link org.springframework.web.util.UrlPathHelper#setUrlDecode same property} * on the configured {@code UrlPathHelper}. * @deprecated as of 5.3 in favor of using * {@link #setUrlPathHelper(UrlPathHelper)}, if at all. For further details, * please see {@link #setAllowInitLookupPath(boolean)}. */ @Deprecated public void setUrlDecode(boolean urlDecode) { initUrlPathHelper(); this.urlPathHelper.setUrlDecode(urlDecode); } /** * Shortcut to the * {@link org.springframework.web.util.UrlPathHelper#setRemoveSemicolonContent * same property} on the configured {@code UrlPathHelper}. * @deprecated as of 5.3 in favor of using * {@link #setUrlPathHelper(UrlPathHelper)}, if at all. For further details, * please see {@link #setAllowInitLookupPath(boolean)}. */ @Deprecated public void setRemoveSemicolonContent(boolean removeSemicolonContent) { initUrlPathHelper(); this.urlPathHelper.setRemoveSemicolonContent(removeSemicolonContent); } private void initUrlPathHelper() { if (this.urlPathHelper == UrlPathHelper.defaultInstance) { this.urlPathHelper = new UrlPathHelper(); } } /** * Configure the {@code UrlPathHelper} to resolve the lookupPath. This may * not be necessary if the lookupPath is expected to be pre-resolved or if * parsed {@code PathPatterns} are used instead. * For further details on that, see {@link #setAllowInitLookupPath(boolean)}. *

By default this is {@link UrlPathHelper#defaultInstance}. */ public void setUrlPathHelper(UrlPathHelper urlPathHelper) { Assert.notNull(urlPathHelper, "UrlPathHelper must not be null"); this.urlPathHelper = urlPathHelper; } /** * When enabled, if there is neither a * {@link UrlPathHelper#resolveAndCacheLookupPath esolved} String lookupPath nor a * {@link ServletRequestPathUtils#parseAndCache parsed} {@code RequestPath} * then use the {@link #setUrlPathHelper configured} {@code UrlPathHelper} * to resolve a String lookupPath. This in turn determines use of URL * pattern matching with {@link PathMatcher} or with parsed {@link PathPattern}s. *

In Spring MVC, either a resolved String lookupPath or a parsed * {@code RequestPath} is always available within {@code DispatcherServlet} * processing. However, in a Servlet {@code Filter} such as {@code CorsFilter} * that may or may not be the case. *

By default this is set to {@code true} in which case lazy lookupPath * initialization is allowed. Set this to {@code false} when an * application is using parsed {@code PathPatterns} in which case the * {@code RequestPath} can be parsed earlier via * {@link org.springframework.web.filter.ServletRequestPathFilter * ServletRequestPathFilter}. * @param allowInitLookupPath whether to disable lazy initialization * and fail if not already resolved * @since 5.3 */ public void setAllowInitLookupPath(boolean allowInitLookupPath) { this.allowInitLookupPath = allowInitLookupPath; } /** * Configure the name of the attribute that holds the lookupPath extracted * via {@link UrlPathHelper#getLookupPathForRequest(HttpServletRequest)}. *

By default this is {@link UrlPathHelper#PATH_ATTRIBUTE}. * @param name the request attribute to check * @since 5.2 * @deprecated as of 5.3 in favor of {@link UrlPathHelper#PATH_ATTRIBUTE}. */ @Deprecated public void setLookupPathAttributeName(String name) { this.lookupPathAttributeName = name; } /** * Configure a {@code PathMatcher} to use for pattern matching. *

This is an advanced property that should be used only when a * customized {@link AntPathMatcher} or a custom PathMatcher is required. *

By default this is {@link AntPathMatcher}. *

Note: Setting {@code PathMatcher} enforces use of * String pattern matching even when a * {@link ServletRequestPathUtils#parseAndCache parsed} {@code RequestPath} * is available. */ public void setPathMatcher(PathMatcher pathMatcher) { this.pathMatcher = pathMatcher; } /** * Set the CORS configuration mappings. *

For pattern syntax see {@link AntPathMatcher} and {@link PathPattern} * as well as class-level Javadoc for details on which one may in use. * Generally the syntax is largely the same with {@link PathPattern} more * tailored for web usage. * @param corsConfigurations the mappings to use * @see PathPattern * @see AntPathMatcher */ public void setCorsConfigurations(@Nullable Map corsConfigurations) { this.corsConfigurations.clear(); if (corsConfigurations != null) { corsConfigurations.forEach(this::registerCorsConfiguration); } } /** * Variant of {@link #setCorsConfigurations(Map)} to register one mapping at a time. * @param pattern the mapping pattern * @param config the CORS configuration to use for the pattern * @see PathPattern * @see AntPathMatcher */ public void registerCorsConfiguration(String pattern, CorsConfiguration config) { this.corsConfigurations.put(this.patternParser.parse(pattern), config); } /** * Return all configured CORS mappings. */ public Map getCorsConfigurations() { Map result = CollectionUtils.newHashMap(this.corsConfigurations.size()); this.corsConfigurations.forEach((pattern, config) -> result.put(pattern.getPatternString(), config)); return Collections.unmodifiableMap(result); } @Override @Nullable public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { Object path = resolvePath(request); boolean isPathContainer = (path instanceof PathContainer); for (Map.Entry entry : this.corsConfigurations.entrySet()) { if (match(path, isPathContainer, entry.getKey())) { return entry.getValue(); } } return null; } @SuppressWarnings("deprecation") private Object resolvePath(HttpServletRequest request) { if (this.allowInitLookupPath && !ServletRequestPathUtils.hasCachedPath(request)) { return (this.lookupPathAttributeName != null ? this.urlPathHelper.getLookupPathForRequest(request, this.lookupPathAttributeName) : this.urlPathHelper.getLookupPathForRequest(request)); } Object lookupPath = ServletRequestPathUtils.getCachedPath(request); if (this.pathMatcher != defaultPathMatcher) { lookupPath = lookupPath.toString(); } return lookupPath; } private boolean match(Object path, boolean isPathContainer, PathPattern pattern) { return (isPathContainer ? pattern.matches((PathContainer) path) : this.pathMatcher.match(pattern.getPatternString(), (String) path)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy