Skip to content

Commit

Permalink
Polish CORS global configuration
Browse files Browse the repository at this point in the history
This commit introduces the following changes:
 - configureCors(CorsConfigurer configurer) is renamed to
   addCorsMappings(CorsRegistry registry)
 - enableCors(String... pathPatterns) is renamed to
   addMapping(String pathPattern)
 - <cors /> element must have at least one <mapping /> child
   element in order to be consistent with XML based configuration
   and have more explicit configuration

Issues: SPR-12933, SPR-13046
  • Loading branch information
sdeleuze committed Jun 5, 2015
1 parent e8441ed commit 0c3b34f
Show file tree
Hide file tree
Showing 11 changed files with 48 additions and 61 deletions.
Expand Up @@ -34,12 +34,12 @@
*/
public class CorsRegistration {

private final String[] pathPatterns;
private final String pathPattern;

private final CorsConfiguration config;

public CorsRegistration(String... pathPatterns) {
this.pathPatterns = (pathPatterns.length == 0 ? new String[]{ "/**" } : pathPatterns);
public CorsRegistration(String pathPattern) {
this.pathPattern = pathPattern;
// Same default values than @CrossOrigin annotation + allows simple methods
this.config = new CorsConfiguration();
this.config.addAllowedOrigin("*");
Expand Down Expand Up @@ -81,8 +81,8 @@ public CorsRegistration allowCredentials(boolean allowCredentials) {
return this;
}

protected String[] getPathPatterns() {
return this.pathPatterns;
protected String getPathPattern() {
return this.pathPattern;
}

protected CorsConfiguration getCorsConfiguration() {
Expand Down
Expand Up @@ -24,35 +24,35 @@
import org.springframework.web.cors.CorsConfiguration;

/**
* Assist with the registration of {@link CorsConfiguration} mapped to one or more path patterns.
* Assist with the registration of {@link CorsConfiguration} mapped on a path pattern.
* @author Sebastien Deleuze
*
* @since 4.2
* @see CorsRegistration
*/
public class CorsConfigurer {
public class CorsRegistry {

private final List<CorsRegistration> registrations = new ArrayList<CorsRegistration>();


/**
* Enable cross origin requests on the specified path patterns. If no path pattern is specified,
* cross-origin request handling is mapped on "/**" .
* Enable cross origin requests processing on the specified path pattern.
* Exact path mapping URIs (such as "/admin") are supported as well as Ant-stype path
* patterns (such as /admin/**).
*
* <p>By default, all origins, all headers and credentials are allowed. Max age is set to 30 minutes.</p>
* <p>By default, all origins, all headers, credentials and GET, HEAD, POST methods are allowed.
* Max age is set to 30 minutes.</p>
*/
public CorsRegistration enableCors(String... pathPatterns) {
CorsRegistration registration = new CorsRegistration(pathPatterns);
public CorsRegistration addMapping(String pathPattern) {
CorsRegistration registration = new CorsRegistration(pathPattern);
this.registrations.add(registration);
return registration;
}

protected Map<String, CorsConfiguration> getCorsConfigurations() {
Map<String, CorsConfiguration> configs = new LinkedHashMap<String, CorsConfiguration>(this.registrations.size());
for (CorsRegistration registration : this.registrations) {
for (String pathPattern : registration.getPathPatterns()) {
configs.put(pathPattern, registration.getCorsConfiguration());
}
configs.put(registration.getPathPattern(), registration.getCorsConfiguration());
}
return configs;
}
Expand Down
Expand Up @@ -133,8 +133,8 @@ protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver>
}

@Override
protected void configureCors(CorsConfigurer configurer) {
this.configurers.configureCors(configurer);
protected void addCorsMappings(CorsRegistry registry) {
this.configurers.addCorsMappings(registry);
}

}
Expand Up @@ -875,19 +875,19 @@ protected void configureViewResolvers(ViewResolverRegistry registry) {
*/
protected final Map<String, CorsConfiguration> getCorsConfigurations() {
if (this.corsConfigurations == null) {
CorsConfigurer registry = new CorsConfigurer();
configureCors(registry);
CorsRegistry registry = new CorsRegistry();
addCorsMappings(registry);
this.corsConfigurations = registry.getCorsConfigurations();
}
return this.corsConfigurations;
}

/**
* Override this method to configure cross-origin requests handling.
* Override this method to configure cross origin requests processing.
* @since 4.2
* @see CorsConfigurer
* @see CorsRegistry
*/
protected void configureCors(CorsConfigurer configurer) {
protected void addCorsMappings(CorsRegistry registry) {
}


Expand Down
Expand Up @@ -183,9 +183,9 @@ public interface WebMvcConfigurer {
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);

/**
* Configure cross-origin requests handling.
* Configure cross origin requests processing.
* @since 4.2
*/
void configureCors(CorsConfigurer configurer);
void addCorsMappings(CorsRegistry registry);

}
Expand Up @@ -170,7 +170,7 @@ public void configureDefaultServletHandling(DefaultServletHandlerConfigurer conf
* <p>This implementation is empty.
*/
@Override
public void configureCors(CorsConfigurer configurer) {
public void addCorsMappings(CorsRegistry registry) {
}

}
Expand Up @@ -154,9 +154,9 @@ public Validator getValidator() {
}

@Override
public void configureCors(CorsConfigurer configurer) {
public void addCorsMappings(CorsRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.configureCors(configurer);
delegate.addCorsMappings(registry);
}
}

Expand Down
Expand Up @@ -1237,17 +1237,15 @@
<xsd:element name="cors">
<xsd:annotation>
<xsd:documentation><![CDATA[
Configure cross origin requests handling.
By default, all origins, GET HEAD POST methods, all headers and credentials
are allowed and max age is set to 30 minutes.
Configure cross origin requests processing.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="mapping" minOccurs="0" maxOccurs="unbounded">
<xsd:element name="mapping" minOccurs="1" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation><![CDATA[
Enable cross origin requests handling on the specified path patterns.
Enable cross origin requests processing on the specified path pattern.
By default, all origins, GET HEAD POST methods, all headers and credentials
are allowed and max age is set to 30 minutes.
]]></xsd:documentation>
Expand Down
Expand Up @@ -27,50 +27,37 @@
import org.springframework.web.cors.CorsConfiguration;

/**
* Test fixture with a {@link CorsConfigurer}.
* Test fixture with a {@link CorsRegistry}.
*
* @author Sebastien Deleuze
*/
public class CorsConfigurerTests {
public class CorsRegistryTests {

private CorsConfigurer configurer;
private CorsRegistry registry;

@Before
public void setUp() {
this.configurer = new CorsConfigurer();
this.registry = new CorsRegistry();
}

@Test
public void noCorsConfigured() {
assertTrue(this.configurer.getCorsConfigurations().isEmpty());
public void noMapping() {
assertTrue(this.registry.getCorsConfigurations().isEmpty());
}

@Test
public void multipleCorsConfigured() {
this.configurer.enableCors("/foo");
this.configurer.enableCors("/bar");
assertEquals(2, this.configurer.getCorsConfigurations().size());
public void multipleMappings() {
this.registry.addMapping("/foo");
this.registry.addMapping("/bar");
assertEquals(2, this.registry.getCorsConfigurations().size());
}

@Test
public void defaultCorsRegistration() {
this.configurer.enableCors();
Map<String, CorsConfiguration> configs = this.configurer.getCorsConfigurations();
assertEquals(1, configs.size());
CorsConfiguration config = configs.get("/**");
assertEquals(Arrays.asList("*"), config.getAllowedOrigins());
assertEquals(Arrays.asList("GET", "HEAD", "POST"), config.getAllowedMethods());
assertEquals(Arrays.asList("*"), config.getAllowedHeaders());
assertEquals(true, config.getAllowCredentials());
assertEquals(Long.valueOf(1800), config.getMaxAge());
}

@Test
public void customizedCorsRegistration() {
this.configurer.enableCors("/foo").allowedOrigins("http://domain2.com", "http://domain2.com")
public void customizedMapping() {
this.registry.addMapping("/foo").allowedOrigins("http://domain2.com", "http://domain2.com")
.allowedMethods("DELETE").allowCredentials(false).allowedHeaders("header1", "header2")
.exposedHeaders("header3", "header4").maxAge(3600);
Map<String, CorsConfiguration> configs = this.configurer.getCorsConfigurations();
Map<String, CorsConfiguration> configs = this.registry.getCorsConfigurations();
assertEquals(1, configs.size());
CorsConfiguration config = configs.get("/foo");
assertEquals(Arrays.asList("http://domain2.com", "http://domain2.com"), config.getAllowedOrigins());
Expand Down
Expand Up @@ -404,8 +404,8 @@ public void configureDefaultServletHandling(DefaultServletHandlerConfigurer conf
}

@Override
public void configureCors(CorsConfigurer registry) {
registry.enableCors("/resources/**");
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/resources/**");
}

}
Expand Down
Expand Up @@ -6,7 +6,9 @@
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!-- <mvc:cors /> element before <mvc:annotation-driven /> one -->
<mvc:cors />
<mvc:cors>
<mvc:mapping path="/**" />
</mvc:cors>

<mvc:annotation-driven />

Expand Down

0 comments on commit 0c3b34f

Please sign in to comment.