Skip to content

Commit 03c4b6b

Browse files
committed
Fix for issue with #10563
Do not persist a defaulted charset used in the request. Throw UnsupportedEncodingException from getReader Improve performance with asciiEqualsIgnoreCase HttpMethod is case-insensitive
1 parent f55fb7e commit 03c4b6b

File tree

7 files changed

+137
-57
lines changed

7 files changed

+137
-57
lines changed

jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ protected void initializeContextPath(ContextHandler context, Path path)
470470
contextPath = "/";
471471
}
472472
// handle root with virtual host form
473-
else if (StringUtil.startsWithIgnoreCase(contextPath, "root-"))
473+
else if (StringUtil.asciiStartsWithIgnoreCase(contextPath, "root-"))
474474
{
475475
int dash = contextPath.indexOf('-');
476476
String virtual = contextPath.substring(dash + 1);

jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public enum Violation implements ComplianceViolation
4646
/**
4747
* The HTTP RFC(s) require that field names are case-insensitive, so for example the fields "{@code Content-Type: text/xml}"
4848
* and "{@code content-type: text/xml}" are considered equivalent. Jetty has been optimized to take advantage of this by
49-
* looking up field names in a case insensitive cache and will by default provide the standard capitalisation of a field
49+
* looking up field names in a case-insensitive cache and will by default provide the standard capitalisation of a field
5050
* name rather than create a new string with the actual capitalisation received. However, some applications have been
5151
* written to expect a specific capitalisation of field, so deployments of such applications must include this violation
5252
* in their {@link HttpCompliance} mode to prevent Jetty altering the case of the fields received. Jetty itself will still
@@ -56,8 +56,8 @@ public enum Violation implements ComplianceViolation
5656
CASE_SENSITIVE_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2", "Field name is case-insensitive"),
5757

5858
/**
59-
* The HTTP RFC(s) require that method names are case sensitive, so that "{@code Get}" and "{@code GET}" are considered
60-
* different methods. Jetty releases prior to 9.4 used a case insensitive cache to match method names, thus this requirement
59+
* The HTTP RFC(s) require that method names are case-sensitive, so that "{@code Get}" and "{@code GET}" are considered
60+
* different methods. Jetty releases prior to 9.4 used a case-insensitive cache to match method names, thus this requirement
6161
* was violated. Deployments which wish to retain this legacy violation can include this violation in the
6262
* {@link HttpCompliance} mode.
6363
*/

jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public byte[] getBytesColonSpace()
194194

195195
public boolean is(String s)
196196
{
197-
return _string.equalsIgnoreCase(s);
197+
return StringUtil.asciiEqualsIgnoreCase(_string, s);
198198
}
199199

200200
/**

jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public byte[] getBytes()
9595

9696
public boolean is(String s)
9797
{
98-
return toString().equalsIgnoreCase(s);
98+
return toString().equals(s);
9999
}
100100

101101
/**

jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -653,21 +653,19 @@ private boolean parseLine(ByteBuffer buffer)
653653
_length = _string.length();
654654
_methodString = takeString();
655655

656-
if (Violation.CASE_INSENSITIVE_METHOD.isAllowedBy(_complianceMode))
656+
HttpMethod method = HttpMethod.CACHE.get(_methodString);
657+
if (method != null)
657658
{
658-
HttpMethod method = HttpMethod.INSENSITIVE_CACHE.get(_methodString);
659-
if (method != null)
660-
{
661-
if (!method.asString().equals(_methodString))
662-
reportComplianceViolation(Violation.CASE_INSENSITIVE_METHOD, _methodString);
663-
_methodString = method.asString();
664-
}
659+
_methodString = method.asString();
665660
}
666-
else
661+
else if (Violation.CASE_INSENSITIVE_METHOD.isAllowedBy(_complianceMode))
667662
{
668-
HttpMethod method = HttpMethod.CACHE.get(_methodString);
663+
method = HttpMethod.INSENSITIVE_CACHE.get(_methodString);
669664
if (method != null)
665+
{
670666
_methodString = method.asString();
667+
reportComplianceViolation(Violation.CASE_INSENSITIVE_METHOD, _methodString);
668+
}
671669
}
672670

673671
setState(State.SPACE1);

jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -225,18 +225,71 @@ public static String sanitizeFileSystemName(String str)
225225
return String.valueOf(chars);
226226
}
227227

228-
public static boolean startsWithIgnoreCase(String s, String w)
228+
/**
229+
* Check for string equality, ignoring {@link StandardCharsets#US_ASCII} case differences.
230+
* @param string The string to check
231+
* @param other The other string to check
232+
* @return true if the strings are equal, ignoring {@link StandardCharsets#US_ASCII} case differences.
233+
*/
234+
public static boolean asciiEqualsIgnoreCase(String string, String other)
235+
{
236+
if (string == null)
237+
return other == null;
238+
239+
if (other == null)
240+
return false;
241+
242+
if (string.length() != other.length())
243+
return false;
244+
245+
for (int i = 0; i < string.length(); i++)
246+
{
247+
char c1 = string.charAt(i);
248+
char c2 = other.charAt(i);
249+
if (c1 != c2)
250+
{
251+
if (c1 <= 127)
252+
c1 = LOWERCASES[c1];
253+
if (c2 <= 127)
254+
c2 = LOWERCASES[c2];
255+
if (c1 != c2)
256+
return false;
257+
}
258+
}
259+
return true;
260+
}
261+
262+
/**
263+
* Check for a string prefix, ignoring {@link StandardCharsets#US_ASCII} case differences.
264+
* @param string The string to check
265+
* @param prefix The sub string to look for as a prefix
266+
* @return true if the string ends with the substring, ignoring {@link StandardCharsets#US_ASCII} case differences.
267+
* @deprecated Use {@link #asciiEndsWithIgnoreCase(String, String)}
268+
*/
269+
@Deprecated
270+
public static boolean startsWithIgnoreCase(String string, String prefix)
271+
{
272+
return asciiStartsWithIgnoreCase(string, prefix);
273+
}
274+
275+
/**
276+
* Check for a string prefix, ignoring {@link StandardCharsets#US_ASCII} case differences.
277+
* @param string The string to check
278+
* @param prefix The sub string to look for as a prefix
279+
* @return true if the string ends with the substring, ignoring {@link StandardCharsets#US_ASCII} case differences.
280+
*/
281+
public static boolean asciiStartsWithIgnoreCase(String string, String prefix)
229282
{
230-
if (w == null)
283+
if (prefix == null)
231284
return true;
232285

233-
if (s == null || s.length() < w.length())
286+
if (string == null || string.length() < prefix.length())
234287
return false;
235288

236-
for (int i = 0; i < w.length(); i++)
289+
for (int i = 0; i < prefix.length(); i++)
237290
{
238-
char c1 = s.charAt(i);
239-
char c2 = w.charAt(i);
291+
char c1 = string.charAt(i);
292+
char c2 = prefix.charAt(i);
240293
if (c1 != c2)
241294
{
242295
if (c1 <= 127)
@@ -250,23 +303,42 @@ public static boolean startsWithIgnoreCase(String s, String w)
250303
return true;
251304
}
252305

253-
public static boolean endsWithIgnoreCase(String s, String w)
306+
/**
307+
* Check for a string suffix, ignoring {@link StandardCharsets#US_ASCII} case differences.
308+
* @param string The string to check
309+
* @param suffix The sub string to look for as a suffix
310+
* @return true if the string ends with the substring, ignoring {@link StandardCharsets#US_ASCII} case differences.
311+
* @deprecated Use {@link #asciiEndsWithIgnoreCase(String, String)}
312+
*/
313+
@Deprecated
314+
public static boolean endsWithIgnoreCase(String string, String suffix)
254315
{
255-
if (w == null)
316+
return asciiEndsWithIgnoreCase(string, suffix);
317+
}
318+
319+
/**
320+
* Check for a string suffix, ignoring {@link StandardCharsets#US_ASCII} case differences.
321+
* @param string The string to check
322+
* @param suffix The sub string to look for as a suffix
323+
* @return true if the string ends with the substring, ignoring {@link StandardCharsets#US_ASCII} case differences.
324+
*/
325+
public static boolean asciiEndsWithIgnoreCase(String string, String suffix)
326+
{
327+
if (suffix == null)
256328
return true;
257-
if (s == null)
329+
if (string == null)
258330
return false;
259331

260-
int sl = s.length();
261-
int wl = w.length();
332+
int sl = string.length();
333+
int wl = suffix.length();
262334

263335
if (sl < wl)
264336
return false;
265337

266338
for (int i = wl; i-- > 0; )
267339
{
268-
char c1 = s.charAt(--sl);
269-
char c2 = w.charAt(i);
340+
char c1 = string.charAt(--sl);
341+
char c2 = suffix.charAt(i);
270342
if (c1 != c2)
271343
{
272344
if (c1 <= 127)

jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,55 +29,65 @@
2929
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
3030
import static org.junit.jupiter.api.Assertions.assertEquals;
3131
import static org.junit.jupiter.api.Assertions.assertFalse;
32+
import static org.junit.jupiter.api.Assertions.assertSame;
3233
import static org.junit.jupiter.api.Assertions.assertThrows;
3334
import static org.junit.jupiter.api.Assertions.assertTrue;
3435

3536
// @checkstyle-disable-check : AvoidEscapedUnicodeCharactersCheck
3637
public class StringUtilTest
3738
{
38-
3939
@Test
4040
@SuppressWarnings("ReferenceEquality")
4141
public void testAsciiToLowerCase()
4242
{
4343
String lc = "\u0690bc def 1\u06903";
4444
assertEquals(StringUtil.asciiToLowerCase("\u0690Bc DeF 1\u06903"), lc);
45-
assertTrue(StringUtil.asciiToLowerCase(lc) == lc);
45+
assertSame(StringUtil.asciiToLowerCase(lc), lc);
4646
}
4747

4848
@Test
49-
public void testStartsWithIgnoreCase()
49+
public void testAsciiEqualsIgnoreCase()
5050
{
51+
assertTrue(StringUtil.asciiEqualsIgnoreCase(null, null));
52+
assertTrue(StringUtil.asciiEqualsIgnoreCase("", ""));
53+
assertTrue(StringUtil.asciiEqualsIgnoreCase("AbC", "aBc"));
54+
55+
assertFalse(StringUtil.asciiEqualsIgnoreCase("AbC", "aBcd"));
56+
assertFalse(StringUtil.asciiEqualsIgnoreCase("AbCd", "aBc"));
57+
}
5158

52-
assertTrue(StringUtil.startsWithIgnoreCase("\u0690b\u0690defg", "\u0690b\u0690"));
53-
assertTrue(StringUtil.startsWithIgnoreCase("\u0690bcdefg", "\u0690bc"));
54-
assertTrue(StringUtil.startsWithIgnoreCase("\u0690bcdefg", "\u0690Bc"));
55-
assertTrue(StringUtil.startsWithIgnoreCase("\u0690Bcdefg", "\u0690bc"));
56-
assertTrue(StringUtil.startsWithIgnoreCase("\u0690Bcdefg", "\u0690Bc"));
57-
assertTrue(StringUtil.startsWithIgnoreCase("\u0690bcdefg", ""));
58-
assertTrue(StringUtil.startsWithIgnoreCase("\u0690bcdefg", null));
59-
assertTrue(StringUtil.startsWithIgnoreCase("\u0690bcdefg", "\u0690bcdefg"));
60-
61-
assertFalse(StringUtil.startsWithIgnoreCase(null, "xyz"));
62-
assertFalse(StringUtil.startsWithIgnoreCase("\u0690bcdefg", "xyz"));
63-
assertFalse(StringUtil.startsWithIgnoreCase("\u0690", "xyz"));
59+
@Test
60+
public void testAsciiStartsWithIgnoreCase()
61+
{
62+
assertTrue(StringUtil.asciiStartsWithIgnoreCase("\u0690b\u0690defg", "\u0690b\u0690"));
63+
assertTrue(StringUtil.asciiStartsWithIgnoreCase("\u0690bcdefg", "\u0690bc"));
64+
assertTrue(StringUtil.asciiStartsWithIgnoreCase("\u0690bcdefg", "\u0690Bc"));
65+
assertTrue(StringUtil.asciiStartsWithIgnoreCase("\u0690Bcdefg", "\u0690bc"));
66+
assertTrue(StringUtil.asciiStartsWithIgnoreCase("\u0690Bcdefg", "\u0690Bc"));
67+
assertTrue(StringUtil.asciiStartsWithIgnoreCase("\u0690bcdefg", ""));
68+
assertTrue(StringUtil.asciiStartsWithIgnoreCase("\u0690bcdefg", null));
69+
assertTrue(StringUtil.asciiStartsWithIgnoreCase("\u0690bcdefg", "\u0690bcdefg"));
70+
71+
assertFalse(StringUtil.asciiStartsWithIgnoreCase(null, "xyz"));
72+
assertFalse(StringUtil.asciiStartsWithIgnoreCase("\u0690bcdefg", "xyz"));
73+
assertFalse(StringUtil.asciiStartsWithIgnoreCase("\u0690", "xyz"));
6474
}
6575

6676
@Test
67-
public void testEndsWithIgnoreCase()
77+
public void testAsciiEndsWithIgnoreCase()
6878
{
69-
assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcd\u0690f\u0690", "\u0690f\u0690"));
70-
assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcdefg", "efg"));
71-
assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcdefg", "eFg"));
72-
assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcdeFg", "efg"));
73-
assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcdeFg", "eFg"));
74-
assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcdefg", ""));
75-
assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcdefg", null));
76-
assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcdefg", "\u0690bcdefg"));
77-
78-
assertFalse(StringUtil.endsWithIgnoreCase(null, "xyz"));
79-
assertFalse(StringUtil.endsWithIgnoreCase("\u0690bcdefg", "xyz"));
80-
assertFalse(StringUtil.endsWithIgnoreCase("\u0690", "xyz"));
79+
assertTrue(StringUtil.asciiEndsWithIgnoreCase("\u0690bcd\u0690f\u0690", "\u0690f\u0690"));
80+
assertTrue(StringUtil.asciiEndsWithIgnoreCase("\u0690bcdefg", "efg"));
81+
assertTrue(StringUtil.asciiEndsWithIgnoreCase("\u0690bcdefg", "eFg"));
82+
assertTrue(StringUtil.asciiEndsWithIgnoreCase("\u0690bcdeFg", "efg"));
83+
assertTrue(StringUtil.asciiEndsWithIgnoreCase("\u0690bcdeFg", "eFg"));
84+
assertTrue(StringUtil.asciiEndsWithIgnoreCase("\u0690bcdefg", ""));
85+
assertTrue(StringUtil.asciiEndsWithIgnoreCase("\u0690bcdefg", null));
86+
assertTrue(StringUtil.asciiEndsWithIgnoreCase("\u0690bcdefg", "\u0690bcdefg"));
87+
88+
assertFalse(StringUtil.asciiEndsWithIgnoreCase(null, "xyz"));
89+
assertFalse(StringUtil.asciiEndsWithIgnoreCase("\u0690bcdefg", "xyz"));
90+
assertFalse(StringUtil.asciiEndsWithIgnoreCase("\u0690", "xyz"));
8191
}
8292

8393
@Test

0 commit comments

Comments
 (0)