Skip to content

Commit c8020a0

Browse files
Merge pull request #15 from cesarhernandezgt/v.6.0.23.RELEASE-TT.x-patch
Prepare for release 6.0.23.RELEASE-TT.3
2 parents efa28d5 + 29013b3 commit c8020a0

File tree

4 files changed

+163
-70
lines changed

4 files changed

+163
-70
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version=6.0.23.RELEASE-TT.2
1+
version=6.0.23.RELEASE-TT.3
22

33
org.gradle.caching=true
44
org.gradle.jvmargs=-Xmx2048m

spring-context/src/main/java/org/springframework/validation/DataBinder.java

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import java.util.Collections;
2424
import java.util.HashMap;
2525
import java.util.List;
26-
import java.util.Locale;
2726
import java.util.Map;
2827

2928
import org.apache.commons.logging.Log;
@@ -460,15 +459,13 @@ public String[] getAllowedFields() {
460459
* <p>Mark fields as disallowed, for example to avoid unwanted
461460
* modifications by malicious users when binding HTTP request parameters.
462461
* <p>Supports {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
463-
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
464-
* well as direct equality.
465-
* <p>The default implementation of this method stores disallowed field patterns
466-
* in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String) canonical}
467-
* form. As of Spring Framework 5.2.21, the default implementation also transforms
468-
* disallowed field patterns to {@linkplain String#toLowerCase() lowercase} to
469-
* support case-insensitive pattern matching in {@link #isAllowed}. Subclasses
470-
* which override this method must therefore take both of these transformations
471-
* into account.
462+
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts),
463+
* as well as direct equality.
464+
* <p>The default implementation of this method stores disallowed field
465+
* patterns in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String)
466+
* canonical} form, and subsequently pattern matching in {@link #isAllowed}
467+
* is case-insensitive. Subclasses that override this method must therefore
468+
* take this transformation into account.
472469
* <p>More sophisticated matching can be implemented by overriding the
473470
* {@link #isAllowed} method.
474471
* <p>Alternatively, specify a list of <i>allowed</i> field patterns.
@@ -483,8 +480,7 @@ public void setDisallowedFields(@Nullable String... disallowedFields) {
483480
else {
484481
String[] fieldPatterns = new String[disallowedFields.length];
485482
for (int i = 0; i < fieldPatterns.length; i++) {
486-
String field = PropertyAccessorUtils.canonicalPropertyName(disallowedFields[i]);
487-
fieldPatterns[i] = field.toLowerCase(Locale.ROOT);
483+
fieldPatterns[i] = PropertyAccessorUtils.canonicalPropertyName(disallowedFields[i]);
488484
}
489485
this.disallowedFields = fieldPatterns;
490486
}
@@ -808,9 +804,9 @@ protected void checkAllowedFields(MutablePropertyValues mpvs) {
808804
* Determine if the given field is allowed for binding.
809805
* <p>Invoked for each passed-in property value.
810806
* <p>Checks for {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
811-
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
812-
* well as direct equality, in the configured lists of allowed field patterns
813-
* and disallowed field patterns.
807+
* {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts),
808+
* as well as direct equality, in the configured lists of allowed field
809+
* patterns and disallowed field patterns.
814810
* <p>Matching against allowed field patterns is case-sensitive; whereas,
815811
* matching against disallowed field patterns is case-insensitive.
816812
* <p>A field matching a disallowed pattern will not be accepted even if it
@@ -826,8 +822,13 @@ protected void checkAllowedFields(MutablePropertyValues mpvs) {
826822
protected boolean isAllowed(String field) {
827823
String[] allowed = getAllowedFields();
828824
String[] disallowed = getDisallowedFields();
829-
return ((ObjectUtils.isEmpty(allowed) || PatternMatchUtils.simpleMatch(allowed, field)) &&
830-
(ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field.toLowerCase(Locale.ROOT))));
825+
if (!ObjectUtils.isEmpty(allowed) && !PatternMatchUtils.simpleMatch(allowed, field)) {
826+
return false;
827+
}
828+
if (!ObjectUtils.isEmpty(disallowed)) {
829+
return !PatternMatchUtils.simpleMatchIgnoreCase(disallowed, field);
830+
}
831+
return true;
831832
}
832833

833834
/**

spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,24 @@ public abstract class PatternMatchUtils {
3636
* @return whether the String matches the given pattern
3737
*/
3838
public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) {
39+
return simpleMatch(pattern, str, false);
40+
}
41+
42+
/**
43+
* Variant of {@link #simpleMatch(String, String)} that ignores upper/lower case.
44+
*/
45+
public static boolean simpleMatchIgnoreCase(@Nullable String pattern, @Nullable String str) {
46+
return simpleMatch(pattern, str, true);
47+
}
48+
49+
private static boolean simpleMatch(@Nullable String pattern, @Nullable String str, boolean ignoreCase) {
3950
if (pattern == null || str == null) {
4051
return false;
4152
}
4253

4354
int firstIndex = pattern.indexOf('*');
4455
if (firstIndex == -1) {
45-
return pattern.equals(str);
56+
return (ignoreCase ? pattern.equalsIgnoreCase(str) : pattern.equals(str));
4657
}
4758

4859
if (firstIndex == 0) {
@@ -51,25 +62,43 @@ public static boolean simpleMatch(@Nullable String pattern, @Nullable String str
5162
}
5263
int nextIndex = pattern.indexOf('*', 1);
5364
if (nextIndex == -1) {
54-
return str.endsWith(pattern.substring(1));
65+
String part = pattern.substring(1);
66+
return (ignoreCase ? StringUtils.endsWithIgnoreCase(str, part) : str.endsWith(part));
5567
}
5668
String part = pattern.substring(1, nextIndex);
5769
if (part.isEmpty()) {
58-
return simpleMatch(pattern.substring(nextIndex), str);
70+
return simpleMatch(pattern.substring(nextIndex), str, ignoreCase);
5971
}
60-
int partIndex = str.indexOf(part);
72+
int partIndex = indexOf(str, part, 0, ignoreCase);
6173
while (partIndex != -1) {
62-
if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) {
74+
if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()), ignoreCase)) {
6375
return true;
6476
}
65-
partIndex = str.indexOf(part, partIndex + 1);
77+
partIndex = indexOf(str, part, partIndex + 1, ignoreCase);
6678
}
6779
return false;
6880
}
6981

7082
return (str.length() >= firstIndex &&
71-
pattern.startsWith(str.substring(0, firstIndex)) &&
72-
simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex)));
83+
checkStartsWith(pattern, str, firstIndex, ignoreCase) &&
84+
simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex), ignoreCase));
85+
}
86+
87+
private static boolean checkStartsWith(String pattern, String str, int index, boolean ignoreCase) {
88+
String part = str.substring(0, index);
89+
return (ignoreCase ? StringUtils.startsWithIgnoreCase(pattern, part) : pattern.startsWith(part));
90+
}
91+
92+
private static int indexOf(String str, String otherStr, int startIndex, boolean ignoreCase) {
93+
if (!ignoreCase) {
94+
return str.indexOf(otherStr, startIndex);
95+
}
96+
for (int i = startIndex; i <= (str.length() - otherStr.length()); i++) {
97+
if (str.regionMatches(true, i, otherStr, 0, otherStr.length())) {
98+
return i;
99+
}
100+
}
101+
return -1;
73102
}
74103

75104
/**
@@ -80,7 +109,7 @@ public static boolean simpleMatch(@Nullable String pattern, @Nullable String str
80109
* @param str the String to match
81110
* @return whether the String matches any of the given patterns
82111
*/
83-
public static boolean simpleMatch(@Nullable String[] patterns, String str) {
112+
public static boolean simpleMatch(@Nullable String[] patterns, @Nullable String str) {
84113
if (patterns != null) {
85114
for (String pattern : patterns) {
86115
if (simpleMatch(pattern, str)) {
@@ -91,4 +120,18 @@ public static boolean simpleMatch(@Nullable String[] patterns, String str) {
91120
return false;
92121
}
93122

123+
/**
124+
* Variant of {@link #simpleMatch(String[], String)} that ignores upper/lower case.
125+
*/
126+
public static boolean simpleMatchIgnoreCase(@Nullable String[] patterns, @Nullable String str) {
127+
if (patterns != null) {
128+
for (String pattern : patterns) {
129+
if (simpleMatch(pattern, str, true)) {
130+
return true;
131+
}
132+
}
133+
}
134+
return false;
135+
}
136+
94137
}

spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java

Lines changed: 92 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,81 +26,130 @@
2626
*/
2727
class PatternMatchUtilsTests {
2828

29+
@Test
30+
void nullAndEmptyValues() {
31+
assertDoesNotMatch((String) null, null);
32+
assertDoesNotMatch((String) null, "");
33+
assertDoesNotMatch("123", null);
34+
35+
assertDoesNotMatch((String[]) null, null);
36+
assertDoesNotMatch((String[]) null, "");
37+
assertDoesNotMatch(new String[] {}, null);
38+
}
39+
2940
@Test
3041
void trivial() {
31-
assertThat(PatternMatchUtils.simpleMatch((String) null, "")).isFalse();
32-
assertThat(PatternMatchUtils.simpleMatch("1", null)).isFalse();
33-
doTest("*", "123", true);
34-
doTest("123", "123", true);
42+
assertMatches("", "");
43+
assertMatches("123", "123");
44+
assertMatches("*", "123");
45+
46+
assertMatches(new String[] { "" }, "");
47+
assertMatches(new String[] { "123" }, "123");
48+
assertMatches(new String[] { "*" }, "123");
49+
50+
assertMatches(new String[] { null, "" }, "");
51+
assertMatches(new String[] { null, "123" }, "123");
52+
assertMatches(new String[] { null, "*" }, "123");
53+
54+
testMixedCaseMatch("abC", "Abc");
3555
}
3656

3757
@Test
3858
void startsWith() {
39-
doTest("get*", "getMe", true);
40-
doTest("get*", "setMe", false);
59+
assertMatches("get*", "getMe");
60+
assertDoesNotMatch("get*", "setMe");
61+
testMixedCaseMatch("geT*", "GetMe");
4162
}
4263

4364
@Test
4465
void endsWith() {
45-
doTest("*Test", "getMeTest", true);
46-
doTest("*Test", "setMe", false);
66+
assertMatches("*Test", "getMeTest");
67+
assertDoesNotMatch("*Test", "setMe");
68+
testMixedCaseMatch("*TeSt", "getMeTesT");
4769
}
4870

4971
@Test
5072
void between() {
51-
doTest("*stuff*", "getMeTest", false);
52-
doTest("*stuff*", "getstuffTest", true);
53-
doTest("*stuff*", "stuffTest", true);
54-
doTest("*stuff*", "getstuff", true);
55-
doTest("*stuff*", "stuff", true);
73+
assertDoesNotMatch("*stuff*", "getMeTest");
74+
assertMatches("*stuff*", "getstuffTest");
75+
assertMatches("*stuff*", "stuffTest");
76+
assertMatches("*stuff*", "getstuff");
77+
assertMatches("*stuff*", "stuff");
78+
testMixedCaseMatch("*stuff*", "getStuffTest");
79+
testMixedCaseMatch("*stuff*", "StuffTest");
80+
testMixedCaseMatch("*stuff*", "getStuff");
81+
testMixedCaseMatch("*stuff*", "Stuff");
5682
}
5783

5884
@Test
5985
void startsEnds() {
60-
doTest("on*Event", "onMyEvent", true);
61-
doTest("on*Event", "onEvent", true);
62-
doTest("3*3", "3", false);
63-
doTest("3*3", "33", true);
86+
assertMatches("on*Event", "onMyEvent");
87+
assertMatches("on*Event", "onEvent");
88+
assertDoesNotMatch("3*3", "3");
89+
assertMatches("3*3", "33");
90+
testMixedCaseMatch("on*Event", "OnMyEvenT");
91+
testMixedCaseMatch("on*Event", "OnEvenT");
6492
}
6593

6694
@Test
6795
void startsEndsBetween() {
68-
doTest("12*45*78", "12345678", true);
69-
doTest("12*45*78", "123456789", false);
70-
doTest("12*45*78", "012345678", false);
71-
doTest("12*45*78", "124578", true);
72-
doTest("12*45*78", "1245457878", true);
73-
doTest("3*3*3", "33", false);
74-
doTest("3*3*3", "333", true);
96+
assertMatches("12*45*78", "12345678");
97+
assertDoesNotMatch("12*45*78", "123456789");
98+
assertDoesNotMatch("12*45*78", "012345678");
99+
assertMatches("12*45*78", "124578");
100+
assertMatches("12*45*78", "1245457878");
101+
assertDoesNotMatch("3*3*3", "33");
102+
assertMatches("3*3*3", "333");
75103
}
76104

77105
@Test
78106
void ridiculous() {
79-
doTest("*1*2*3*", "0011002001010030020201030", true);
80-
doTest("1*2*3*4", "10300204", false);
81-
doTest("1*2*3*3", "10300203", false);
82-
doTest("*1*2*3*", "123", true);
83-
doTest("*1*2*3*", "132", false);
107+
assertMatches("*1*2*3*", "0011002001010030020201030");
108+
assertDoesNotMatch("1*2*3*4", "10300204");
109+
assertDoesNotMatch("1*2*3*3", "10300203");
110+
assertMatches("*1*2*3*", "123");
111+
assertDoesNotMatch("*1*2*3*", "132");
84112
}
85113

86114
@Test
87115
void patternVariants() {
88-
doTest("*a", "*", false);
89-
doTest("*a", "a", true);
90-
doTest("*a", "b", false);
91-
doTest("*a", "aa", true);
92-
doTest("*a", "ba", true);
93-
doTest("*a", "ab", false);
94-
doTest("**a", "*", false);
95-
doTest("**a", "a", true);
96-
doTest("**a", "b", false);
97-
doTest("**a", "aa", true);
98-
doTest("**a", "ba", true);
99-
doTest("**a", "ab", false);
116+
assertDoesNotMatch("*a", "*");
117+
assertMatches("*a", "a");
118+
assertDoesNotMatch("*a", "b");
119+
assertMatches("*a", "aa");
120+
assertMatches("*a", "ba");
121+
assertDoesNotMatch("*a", "ab");
122+
assertDoesNotMatch("**a", "*");
123+
assertMatches("**a", "a");
124+
assertDoesNotMatch("**a", "b");
125+
assertMatches("**a", "aa");
126+
assertMatches("**a", "ba");
127+
assertDoesNotMatch("**a", "ab");
128+
}
129+
130+
private void assertMatches(String pattern, String str) {
131+
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isTrue();
132+
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isTrue();
133+
}
134+
135+
private void assertDoesNotMatch(String pattern, String str) {
136+
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse();
137+
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isFalse();
138+
}
139+
140+
private void testMixedCaseMatch(String pattern, String str) {
141+
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse();
142+
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isTrue();
143+
}
144+
145+
private void assertMatches(String[] patterns, String str) {
146+
assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isTrue();
147+
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(patterns, str)).isTrue();
100148
}
101149

102-
private void doTest(String pattern, String str, boolean shouldMatch) {
103-
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isEqualTo(shouldMatch);
150+
private void assertDoesNotMatch(String[] patterns, String str) {
151+
assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isFalse();
152+
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(patterns, str)).isFalse();
104153
}
105154

106155
}

0 commit comments

Comments
 (0)