1
1
/*
2
- * Copyright 2002-2019 the original author or authors.
2
+ * Copyright 2002-2020 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
23
23
import java .util .LinkedHashSet ;
24
24
import java .util .List ;
25
25
import java .util .Set ;
26
+ import java .util .regex .Pattern ;
26
27
import java .util .stream .Collectors ;
27
28
28
29
import org .springframework .http .HttpMethod ;
45
46
* @author Rossen Stoyanchev
46
47
* @author Juergen Hoeller
47
48
* @author Sam Brannen
49
+ * @author Ruslan Akhundov
48
50
* @since 4.2
49
51
* @see <a href="https://www.w3.org/TR/cors/">CORS spec</a>
50
52
*/
51
53
public class CorsConfiguration {
52
54
53
55
/** Wildcard representing <em>all</em> origins, methods, or headers. */
54
56
public static final String ALL = "*" ;
57
+ /** Wildcard representing pattern that matches <em>all</em> origins. */
58
+ public static final String ALL_PATTERN = ".*" ;
55
59
56
60
private static final List <HttpMethod > DEFAULT_METHODS = Collections .unmodifiableList (
57
61
Arrays .asList (HttpMethod .GET , HttpMethod .HEAD ));
@@ -62,10 +66,19 @@ public class CorsConfiguration {
62
66
private static final List <String > DEFAULT_PERMIT_ALL = Collections .unmodifiableList (
63
67
Collections .singletonList (ALL ));
64
68
69
+ private static final List <String > DEFAULT_PERMIT_ALL_PATTERN_STR = Collections .unmodifiableList (
70
+ Collections .singletonList (ALL_PATTERN ));
71
+
72
+ private static final List <Pattern > DEFAULT_PERMIT_ALL_PATTERN = Collections .unmodifiableList (
73
+ Collections .singletonList (Pattern .compile (ALL_PATTERN )));
74
+
65
75
66
76
@ Nullable
67
77
private List <String > allowedOrigins ;
68
78
79
+ @ Nullable
80
+ private List <Pattern > allowedOriginsPatterns ;
81
+
69
82
@ Nullable
70
83
private List <String > allowedMethods ;
71
84
@@ -99,6 +112,7 @@ public CorsConfiguration() {
99
112
*/
100
113
public CorsConfiguration (CorsConfiguration other ) {
101
114
this .allowedOrigins = other .allowedOrigins ;
115
+ this .allowedOriginsPatterns = other .allowedOriginsPatterns ;
102
116
this .allowedMethods = other .allowedMethods ;
103
117
this .resolvedMethods = other .resolvedMethods ;
104
118
this .allowedHeaders = other .allowedHeaders ;
@@ -140,6 +154,54 @@ else if (this.allowedOrigins == DEFAULT_PERMIT_ALL) {
140
154
this .allowedOrigins .add (origin );
141
155
}
142
156
157
+ /**
158
+ * Set the origins patterns to allow, e.g. {@code "*.com"}.
159
+ * <p>By default this is not set.
160
+ */
161
+ public CorsConfiguration setAllowedOriginsPatterns (@ Nullable List <String > allowedOriginsPatterns ) {
162
+ if (allowedOriginsPatterns == null ) {
163
+ this .allowedOriginsPatterns = null ;
164
+ }
165
+ else {
166
+ this .allowedOriginsPatterns = new ArrayList <>(allowedOriginsPatterns .size ());
167
+ for (String pattern : allowedOriginsPatterns ) {
168
+ this .allowedOriginsPatterns .add (Pattern .compile (pattern ));
169
+ }
170
+ }
171
+
172
+ return this ;
173
+ }
174
+
175
+ /**
176
+ * Return the configured origins patterns to allow, or {@code null} if none.
177
+ *
178
+ * @see #addAllowedOriginPattern(String)
179
+ * @see #setAllowedOriginsPatterns(List)
180
+ */
181
+ @ Nullable
182
+ public List <String > getAllowedOriginsPatterns () {
183
+ if (this .allowedOriginsPatterns == null ) {
184
+ return null ;
185
+ }
186
+ if (this .allowedOriginsPatterns == DEFAULT_PERMIT_ALL_PATTERN ) {
187
+ return DEFAULT_PERMIT_ALL_PATTERN_STR ;
188
+ }
189
+ return this .allowedOriginsPatterns .stream ().map (Pattern ::toString ).collect (Collectors .toList ());
190
+ }
191
+
192
+ /**
193
+ * Add an origin pattern to allow.
194
+ */
195
+ public void addAllowedOriginPattern (String originPattern ) {
196
+ if (this .allowedOriginsPatterns == null ) {
197
+ this .allowedOriginsPatterns = new ArrayList <>(4 );
198
+ }
199
+ else if (this .allowedOriginsPatterns == DEFAULT_PERMIT_ALL_PATTERN ) {
200
+ setAllowedOriginsPatterns (DEFAULT_PERMIT_ALL_PATTERN_STR );
201
+ }
202
+ this .allowedOriginsPatterns .add (Pattern .compile (originPattern ));
203
+ }
204
+
143
205
/**
144
206
* Set the HTTP methods to allow, e.g. {@code "GET"}, {@code "POST"},
145
207
* {@code "PUT"}, etc.
@@ -351,7 +413,7 @@ public Long getMaxAge() {
351
413
* </ul>
352
414
*/
353
415
public CorsConfiguration applyPermitDefaultValues () {
354
- if (this .allowedOrigins == null ) {
416
+ if (this .allowedOrigins == null && this . allowedOriginsPatterns == null ) {
355
417
this .allowedOrigins = DEFAULT_PERMIT_ALL ;
356
418
}
357
419
if (this .allowedMethods == null ) {
@@ -392,7 +454,14 @@ public CorsConfiguration combine(@Nullable CorsConfiguration other) {
392
454
return this ;
393
455
}
394
456
CorsConfiguration config = new CorsConfiguration (this );
395
- config .setAllowedOrigins (combine (getAllowedOrigins (), other .getAllowedOrigins ()));
457
+ List <String > combinedOrigins = combine (getAllowedOrigins (), other .getAllowedOrigins ());
458
+ List <String > combinedOriginsPatterns = combine (getAllowedOriginsPatterns (), other .getAllowedOriginsPatterns ());
459
+ if (combinedOrigins == DEFAULT_PERMIT_ALL && combinedOriginsPatterns != DEFAULT_PERMIT_ALL_PATTERN_STR
460
+ && !CollectionUtils .isEmpty (combinedOriginsPatterns )) {
461
+ combinedOrigins = null ;
462
+ }
463
+ config .setAllowedOrigins (combinedOrigins );
464
+ config .setAllowedOriginsPatterns (combinedOriginsPatterns );
396
465
config .setAllowedMethods (combine (getAllowedMethods (), other .getAllowedMethods ()));
397
466
config .setAllowedHeaders (combine (getAllowedHeaders (), other .getAllowedHeaders ()));
398
467
config .setExposedHeaders (combine (getExposedHeaders (), other .getExposedHeaders ()));
@@ -414,15 +483,20 @@ private List<String> combine(@Nullable List<String> source, @Nullable List<Strin
414
483
if (source == null ) {
415
484
return other ;
416
485
}
417
- if (source == DEFAULT_PERMIT_ALL || source == DEFAULT_PERMIT_METHODS ) {
486
+ if (source == DEFAULT_PERMIT_ALL || source == DEFAULT_PERMIT_METHODS
487
+ || source == DEFAULT_PERMIT_ALL_PATTERN_STR ) {
418
488
return other ;
419
489
}
420
- if (other == DEFAULT_PERMIT_ALL || other == DEFAULT_PERMIT_METHODS ) {
490
+ if (other == DEFAULT_PERMIT_ALL || other == DEFAULT_PERMIT_METHODS
491
+ || other == DEFAULT_PERMIT_ALL_PATTERN_STR ) {
421
492
return source ;
422
493
}
423
494
if (source .contains (ALL ) || other .contains (ALL )) {
424
495
return new ArrayList <>(Collections .singletonList (ALL ));
425
496
}
497
+ if ( source .contains (ALL_PATTERN ) || other .contains (ALL_PATTERN )) {
498
+ return new ArrayList <>(Collections .singletonList (ALL_PATTERN ));
499
+ }
426
500
Set <String > combined = new LinkedHashSet <>(source );
427
501
combined .addAll (other );
428
502
return new ArrayList <>(combined );
@@ -439,21 +513,35 @@ public String checkOrigin(@Nullable String requestOrigin) {
439
513
if (!StringUtils .hasText (requestOrigin )) {
440
514
return null ;
441
515
}
442
- if (ObjectUtils .isEmpty (this .allowedOrigins )) {
443
- return null ;
444
- }
445
516
446
- if (this .allowedOrigins .contains (ALL )) {
447
- if (this .allowCredentials != Boolean .TRUE ) {
448
- return ALL ;
517
+ if (!ObjectUtils .isEmpty (this .allowedOrigins )) {
518
+ if (this .allowedOrigins .contains (ALL )) {
519
+ if (this .allowCredentials != Boolean .TRUE ) {
520
+ return ALL ;
521
+ }
522
+ else {
523
+ return requestOrigin ;
524
+ }
449
525
}
450
- else {
451
- return requestOrigin ;
526
+ for (String allowedOrigin : this .allowedOrigins ) {
527
+ if (requestOrigin .equalsIgnoreCase (allowedOrigin )) {
528
+ return requestOrigin ;
529
+ }
452
530
}
453
531
}
454
- for (String allowedOrigin : this .allowedOrigins ) {
455
- if (requestOrigin .equalsIgnoreCase (allowedOrigin )) {
456
- return requestOrigin ;
532
+ if (!ObjectUtils .isEmpty (this .allowedOriginsPatterns )) {
533
+ for (Pattern allowedOriginsPattern : this .allowedOriginsPatterns ) {
534
+ if (allowedOriginsPattern .pattern ().equals (ALL_PATTERN )) {
535
+ if (this .allowCredentials != Boolean .TRUE ) {
536
+ return ALL ;
537
+ }
538
+ else {
539
+ return requestOrigin ;
540
+ }
541
+ }
542
+ else if (allowedOriginsPattern .matcher (requestOrigin ).matches ()) {
543
+ return requestOrigin ;
544
+ }
457
545
}
458
546
}
459
547
0 commit comments