Fix getCharacterEncoding issue with #10563 (#10650)

Do not persist a defaulted charset used in the request.
Throw `UnsupportedEncodingException` from `getReader`
This commit is contained in:
Greg Wilkins 2023-10-03 03:45:40 +02:00 committed by GitHub
parent 27865d29b4
commit 8331809c40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 163 additions and 13 deletions

View File

@ -18,6 +18,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Arrays;
@ -329,8 +330,13 @@ public class MimeTypes
* Get the explicit, assumed, or inferred Charset for a mime type
* @param mimeType String form or a mimeType
* @return A {@link Charset} or null;
* @throws IllegalCharsetNameException
* If the given charset name is illegal
* @throws UnsupportedCharsetException
* If no support for the named charset is available
* in this instance of the Java virtual machine
*/
public Charset getCharset(String mimeType)
public Charset getCharset(String mimeType) throws IllegalCharsetNameException, UnsupportedCharsetException
{
if (mimeType == null)
return null;

View File

@ -19,6 +19,8 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
@ -501,7 +503,14 @@ public interface Request extends Attributes, Content.Source
return Content.Source.asInputStream(request);
}
static Charset getCharset(Request request)
/**
* Get a {@link Charset} from the request {@link HttpHeader#CONTENT_TYPE}, if any.
* @param request The request.
* @return A {@link Charset} or null
* @throws IllegalCharsetNameException If the charset name is illegal
* @throws UnsupportedCharsetException If no support for the charset is available
*/
static Charset getCharset(Request request) throws IllegalCharsetNameException, UnsupportedCharsetException
{
String contentType = request.getHeaders().get(HttpHeader.CONTENT_TYPE);
return Objects.requireNonNullElse(request.getContext().getMimeTypes(), MimeTypes.DEFAULTS).getCharset(contentType);

View File

@ -19,7 +19,9 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.security.Principal;
import java.util.AbstractList;
import java.util.Collection;
@ -717,8 +719,15 @@ public class ServletApiRequest implements HttpServletRequest
@Override
public String getCharacterEncoding()
{
if (_charset == null)
_charset = Request.getCharset(getRequest());
try
{
if (_charset == null)
_charset = Request.getCharset(getRequest());
}
catch (IllegalCharsetNameException | UnsupportedCharsetException e)
{
return MimeTypes.getCharsetFromContentType(getRequest().getHeaders().get(HttpHeader.CONTENT_TYPE));
}
if (_charset == null)
return getServletRequestInfo().getServletContext().getServletContext().getRequestCharacterEncoding();
@ -1027,18 +1036,38 @@ public class ServletApiRequest implements HttpServletRequest
if (_inputState == ServletContextRequest.INPUT_READER)
return _reader;
if (_charset == null)
_charset = Request.getCharset(getRequest());
if (_charset == null)
_charset = getRequest().getContext().getMimeTypes().getCharset(getServletRequestInfo().getServletContext().getServletContextHandler().getDefaultRequestCharacterEncoding());
if (_charset == null)
_charset = StandardCharsets.ISO_8859_1;
Charset charset = _charset;
try
{
if (charset == null)
{
charset = _charset = Request.getCharset(getRequest());
if (charset == null)
charset = StandardCharsets.ISO_8859_1;
}
if (_reader == null || !_charset.equals(_readerCharset))
}
catch (IllegalCharsetNameException | UnsupportedCharsetException e)
{
throw new UnsupportedEncodingException(e.getMessage())
{
{
initCause(e);
}
@Override
public String toString()
{
return "%s@%x:%s".formatted(UnsupportedEncodingException.class.getName(), hashCode(), getMessage());
}
};
}
if (_reader == null || !charset.equals(_readerCharset))
{
ServletInputStream in = getInputStream();
_readerCharset = _charset;
_reader = new BufferedReader(new InputStreamReader(in, _charset))
_readerCharset = charset;
_reader = new BufferedReader(new InputStreamReader(in, charset))
{
@Override
public void close() throws IOException

View File

@ -14,6 +14,7 @@
package org.eclipse.jetty.ee10.servlet;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -33,6 +34,7 @@ import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.component.LifeCycle;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -41,6 +43,7 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
public class RequestTest
@ -282,4 +285,58 @@ public class RequestTest
assertThat(cookieHistory.get(0), sameInstance(cookieHistory.get(2)));
assertThat(cookieHistory.get(2), not(sameInstance(cookieHistory.get(4))));
}
@Test
public void testGetCharacterEncoding() throws Exception
{
startServer(new HttpServlet()
{
@Override
protected void service(HttpServletRequest request, HttpServletResponse resp) throws IOException
{
// No character encoding specified
request.getReader();
// Try setting after read has been obtained
request.setCharacterEncoding("ISO-8859-2");
assertThat(request.getCharacterEncoding(), nullValue());
}
});
String rawResponse = _connector.getResponse(
"""
GET /test HTTP/1.1\r
Host: host\r
Connection: close\r
\r
""");
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
assertThat(response.getStatus(), is(HttpStatus.OK_200));
}
@Test
public void testUnknownCharacterEncoding() throws Exception
{
startServer(new HttpServlet()
{
@Override
protected void service(HttpServletRequest request, HttpServletResponse resp) throws IOException
{
assertThat(request.getCharacterEncoding(), is("Unknown"));
Assertions.assertThrows(UnsupportedEncodingException.class, request::getReader);
}
});
String rawResponse = _connector.getResponse(
"""
POST /test HTTP/1.1\r
Host: host\r
Content-Type:text/plain; charset=Unknown\r
Content-Length: 10\r
Connection: close\r
\r
1234567890\r
""");
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
assertThat(response.getStatus(), is(HttpStatus.OK_200));
}
}

View File

@ -88,6 +88,7 @@ import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.NanoTime;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -2493,4 +2494,52 @@ public class RequestTest
}
}
}
@Test
public void testGetCharacterEncoding() throws Exception
{
_handler._checker = (request, response) ->
{
// No character encoding specified
request.getReader();
// Try setting after read has been obtained
request.setCharacterEncoding("ISO-8859-2");
assertThat(request.getCharacterEncoding(), nullValue());
return true;
};
String rawResponse = _connector.getResponse(
"""
GET /test HTTP/1.1\r
Host: host\r
Connection: close\r
\r
""");
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
assertThat(response.getStatus(), is(HttpStatus.OK_200));
}
@Test
public void testUnknownCharacterEncoding() throws Exception
{
_handler._checker = (request, response) ->
{
assertThat(request.getCharacterEncoding(), is("Unknown"));
Assertions.assertThrows(UnsupportedEncodingException.class, request::getReader);
return true;
};
String rawResponse = _connector.getResponse(
"""
POST /test HTTP/1.1\r
Host: host\r
Content-Type:multipart/form-data; charset=Unknown\r
Content-Length: 10\r
Connection: close\r
\r
1234567890\r
""");
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
assertThat(response.getStatus(), is(HttpStatus.OK_200));
}
}