Skip to content

Commit 8331809

Browse files
authored
Fix getCharacterEncoding issue with #10563 (#10650)
Do not persist a defaulted charset used in the request. Throw `UnsupportedEncodingException` from `getReader`
1 parent 27865d2 commit 8331809

File tree

5 files changed

+163
-13
lines changed

5 files changed

+163
-13
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.InputStreamReader;
1919
import java.io.UnsupportedEncodingException;
2020
import java.nio.charset.Charset;
21+
import java.nio.charset.IllegalCharsetNameException;
2122
import java.nio.charset.StandardCharsets;
2223
import java.nio.charset.UnsupportedCharsetException;
2324
import java.util.Arrays;
@@ -329,8 +330,13 @@ public MimeTypes(MimeTypes defaults)
329330
* Get the explicit, assumed, or inferred Charset for a mime type
330331
* @param mimeType String form or a mimeType
331332
* @return A {@link Charset} or null;
333+
* @throws IllegalCharsetNameException
334+
* If the given charset name is illegal
335+
* @throws UnsupportedCharsetException
336+
* If no support for the named charset is available
337+
* in this instance of the Java virtual machine
332338
*/
333-
public Charset getCharset(String mimeType)
339+
public Charset getCharset(String mimeType) throws IllegalCharsetNameException, UnsupportedCharsetException
334340
{
335341
if (mimeType == null)
336342
return null;

jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.net.SocketAddress;
2020
import java.nio.ByteBuffer;
2121
import java.nio.charset.Charset;
22+
import java.nio.charset.IllegalCharsetNameException;
23+
import java.nio.charset.UnsupportedCharsetException;
2224
import java.security.Principal;
2325
import java.util.ArrayList;
2426
import java.util.List;
@@ -501,7 +503,14 @@ static InputStream asInputStream(Request request)
501503
return Content.Source.asInputStream(request);
502504
}
503505

504-
static Charset getCharset(Request request)
506+
/**
507+
* Get a {@link Charset} from the request {@link HttpHeader#CONTENT_TYPE}, if any.
508+
* @param request The request.
509+
* @return A {@link Charset} or null
510+
* @throws IllegalCharsetNameException If the charset name is illegal
511+
* @throws UnsupportedCharsetException If no support for the charset is available
512+
*/
513+
static Charset getCharset(Request request) throws IllegalCharsetNameException, UnsupportedCharsetException
505514
{
506515
String contentType = request.getHeaders().get(HttpHeader.CONTENT_TYPE);
507516
return Objects.requireNonNullElse(request.getContext().getMimeTypes(), MimeTypes.DEFAULTS).getCharset(contentType);

jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletApiRequest.java

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import java.io.InputStreamReader;
2020
import java.io.UnsupportedEncodingException;
2121
import java.nio.charset.Charset;
22+
import java.nio.charset.IllegalCharsetNameException;
2223
import java.nio.charset.StandardCharsets;
24+
import java.nio.charset.UnsupportedCharsetException;
2325
import java.security.Principal;
2426
import java.util.AbstractList;
2527
import java.util.Collection;
@@ -717,8 +719,15 @@ public Enumeration<String> getAttributeNames()
717719
@Override
718720
public String getCharacterEncoding()
719721
{
720-
if (_charset == null)
721-
_charset = Request.getCharset(getRequest());
722+
try
723+
{
724+
if (_charset == null)
725+
_charset = Request.getCharset(getRequest());
726+
}
727+
catch (IllegalCharsetNameException | UnsupportedCharsetException e)
728+
{
729+
return MimeTypes.getCharsetFromContentType(getRequest().getHeaders().get(HttpHeader.CONTENT_TYPE));
730+
}
722731

723732
if (_charset == null)
724733
return getServletRequestInfo().getServletContext().getServletContext().getRequestCharacterEncoding();
@@ -1027,18 +1036,38 @@ public BufferedReader getReader() throws IOException
10271036
if (_inputState == ServletContextRequest.INPUT_READER)
10281037
return _reader;
10291038

1030-
if (_charset == null)
1031-
_charset = Request.getCharset(getRequest());
1032-
if (_charset == null)
1033-
_charset = getRequest().getContext().getMimeTypes().getCharset(getServletRequestInfo().getServletContext().getServletContextHandler().getDefaultRequestCharacterEncoding());
1034-
if (_charset == null)
1035-
_charset = StandardCharsets.ISO_8859_1;
1039+
Charset charset = _charset;
1040+
try
1041+
{
1042+
if (charset == null)
1043+
{
1044+
charset = _charset = Request.getCharset(getRequest());
1045+
if (charset == null)
1046+
charset = StandardCharsets.ISO_8859_1;
1047+
}
1048+
1049+
}
1050+
catch (IllegalCharsetNameException | UnsupportedCharsetException e)
1051+
{
1052+
throw new UnsupportedEncodingException(e.getMessage())
1053+
{
1054+
{
1055+
initCause(e);
1056+
}
1057+
1058+
@Override
1059+
public String toString()
1060+
{
1061+
return "%s@%x:%s".formatted(UnsupportedEncodingException.class.getName(), hashCode(), getMessage());
1062+
}
1063+
};
1064+
}
10361065

1037-
if (_reader == null || !_charset.equals(_readerCharset))
1066+
if (_reader == null || !charset.equals(_readerCharset))
10381067
{
10391068
ServletInputStream in = getInputStream();
1040-
_readerCharset = _charset;
1041-
_reader = new BufferedReader(new InputStreamReader(in, _charset))
1069+
_readerCharset = charset;
1070+
_reader = new BufferedReader(new InputStreamReader(in, charset))
10421071
{
10431072
@Override
10441073
public void close() throws IOException

jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/RequestTest.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package org.eclipse.jetty.ee10.servlet;
1515

1616
import java.io.IOException;
17+
import java.io.UnsupportedEncodingException;
1718
import java.util.ArrayList;
1819
import java.util.Arrays;
1920
import java.util.List;
@@ -33,6 +34,7 @@
3334
import org.eclipse.jetty.server.Server;
3435
import org.eclipse.jetty.util.component.LifeCycle;
3536
import org.junit.jupiter.api.AfterEach;
37+
import org.junit.jupiter.api.Assertions;
3638
import org.junit.jupiter.api.Test;
3739

3840
import static org.hamcrest.MatcherAssert.assertThat;
@@ -41,6 +43,7 @@
4143
import static org.hamcrest.Matchers.equalTo;
4244
import static org.hamcrest.Matchers.is;
4345
import static org.hamcrest.Matchers.not;
46+
import static org.hamcrest.Matchers.nullValue;
4447
import static org.hamcrest.Matchers.sameInstance;
4548

4649
public class RequestTest
@@ -282,4 +285,58 @@ protected void service(HttpServletRequest request, HttpServletResponse resp)
282285
assertThat(cookieHistory.get(0), sameInstance(cookieHistory.get(2)));
283286
assertThat(cookieHistory.get(2), not(sameInstance(cookieHistory.get(4))));
284287
}
288+
289+
@Test
290+
public void testGetCharacterEncoding() throws Exception
291+
{
292+
startServer(new HttpServlet()
293+
{
294+
@Override
295+
protected void service(HttpServletRequest request, HttpServletResponse resp) throws IOException
296+
{
297+
// No character encoding specified
298+
request.getReader();
299+
// Try setting after read has been obtained
300+
request.setCharacterEncoding("ISO-8859-2");
301+
assertThat(request.getCharacterEncoding(), nullValue());
302+
}
303+
});
304+
305+
String rawResponse = _connector.getResponse(
306+
"""
307+
GET /test HTTP/1.1\r
308+
Host: host\r
309+
Connection: close\r
310+
\r
311+
""");
312+
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
313+
assertThat(response.getStatus(), is(HttpStatus.OK_200));
314+
}
315+
316+
@Test
317+
public void testUnknownCharacterEncoding() throws Exception
318+
{
319+
startServer(new HttpServlet()
320+
{
321+
@Override
322+
protected void service(HttpServletRequest request, HttpServletResponse resp) throws IOException
323+
{
324+
assertThat(request.getCharacterEncoding(), is("Unknown"));
325+
Assertions.assertThrows(UnsupportedEncodingException.class, request::getReader);
326+
}
327+
});
328+
329+
String rawResponse = _connector.getResponse(
330+
"""
331+
POST /test HTTP/1.1\r
332+
Host: host\r
333+
Content-Type:text/plain; charset=Unknown\r
334+
Content-Length: 10\r
335+
Connection: close\r
336+
\r
337+
1234567890\r
338+
""");
339+
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
340+
assertThat(response.getStatus(), is(HttpStatus.OK_200));
341+
}
285342
}

jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
import org.eclipse.jetty.util.NanoTime;
8989
import org.hamcrest.Matchers;
9090
import org.junit.jupiter.api.AfterEach;
91+
import org.junit.jupiter.api.Assertions;
9192
import org.junit.jupiter.api.BeforeEach;
9293
import org.junit.jupiter.api.Test;
9394
import org.junit.jupiter.api.extension.ExtendWith;
@@ -2493,4 +2494,52 @@ private static void checkCookieResult(String containedCookie, String[] notContai
24932494
}
24942495
}
24952496
}
2497+
2498+
@Test
2499+
public void testGetCharacterEncoding() throws Exception
2500+
{
2501+
_handler._checker = (request, response) ->
2502+
{
2503+
// No character encoding specified
2504+
request.getReader();
2505+
// Try setting after read has been obtained
2506+
request.setCharacterEncoding("ISO-8859-2");
2507+
assertThat(request.getCharacterEncoding(), nullValue());
2508+
return true;
2509+
};
2510+
2511+
String rawResponse = _connector.getResponse(
2512+
"""
2513+
GET /test HTTP/1.1\r
2514+
Host: host\r
2515+
Connection: close\r
2516+
\r
2517+
""");
2518+
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
2519+
assertThat(response.getStatus(), is(HttpStatus.OK_200));
2520+
}
2521+
2522+
@Test
2523+
public void testUnknownCharacterEncoding() throws Exception
2524+
{
2525+
_handler._checker = (request, response) ->
2526+
{
2527+
assertThat(request.getCharacterEncoding(), is("Unknown"));
2528+
Assertions.assertThrows(UnsupportedEncodingException.class, request::getReader);
2529+
return true;
2530+
};
2531+
2532+
String rawResponse = _connector.getResponse(
2533+
"""
2534+
POST /test HTTP/1.1\r
2535+
Host: host\r
2536+
Content-Type:multipart/form-data; charset=Unknown\r
2537+
Content-Length: 10\r
2538+
Connection: close\r
2539+
\r
2540+
1234567890\r
2541+
""");
2542+
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
2543+
assertThat(response.getStatus(), is(HttpStatus.OK_200));
2544+
}
24962545
}

0 commit comments

Comments
 (0)