Issue #7567 - don't compare params when checking MIME type for GzipHandler

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2022-02-14 12:13:14 +11:00
parent ce0d3c7b8d
commit 0aa307db64
3 changed files with 83 additions and 9 deletions

View File

@ -694,7 +694,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
String mimeType = context == null ? MimeTypes.getDefaultMimeByExtension(path) : context.getMimeType(path); String mimeType = context == null ? MimeTypes.getDefaultMimeByExtension(path) : context.getMimeType(path);
if (mimeType != null) if (mimeType != null)
{ {
mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType); mimeType = HttpField.valueParameters(mimeType, null);
if (!isMimeTypeGzipable(mimeType)) if (!isMimeTypeGzipable(mimeType))
{ {
LOG.debug("{} excluded by path suffix mime type {}", this, request); LOG.debug("{} excluded by path suffix mime type {}", this, request);

View File

@ -23,7 +23,6 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpOutput; import org.eclipse.jetty.server.HttpOutput;
@ -160,8 +159,8 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
String ct = response.getContentType(); String ct = response.getContentType();
if (ct != null) if (ct != null)
{ {
ct = MimeTypes.getContentTypeWithoutCharset(ct); String baseType = HttpField.valueParameters(ct, null);
if (!_factory.isMimeTypeGzipable(StringUtil.asciiToLowerCase(ct))) if (!_factory.isMimeTypeGzipable(StringUtil.asciiToLowerCase(baseType)))
{ {
LOG.debug("{} exclude by mimeType {}", this, ct); LOG.debug("{} exclude by mimeType {}", this, ct);
noCompression(); noCompression();

View File

@ -14,9 +14,14 @@
package org.eclipse.jetty.servlet; package org.eclipse.jetty.servlet;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
import javax.servlet.MultipartConfigElement; import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
@ -26,8 +31,13 @@ import javax.servlet.http.Part;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.util.BytesRequestContent; import org.eclipse.jetty.client.util.BytesRequestContent;
import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.client.util.MultiPartRequestContent; import org.eclipse.jetty.client.util.MultiPartRequestContent;
import org.eclipse.jetty.client.util.StringRequestContent;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.MimeTypes;
@ -36,6 +46,7 @@ import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.MultiPartFormInputStream; import org.eclipse.jetty.server.MultiPartFormInputStream;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -44,7 +55,9 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class MultiPartServletTest public class MultiPartServletTest
{ {
@ -77,29 +90,53 @@ public class MultiPartServletTest
} }
} }
public static class MultiPartEchoServlet extends HttpServlet
{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
if (!req.getContentType().contains(MimeTypes.Type.MULTIPART_FORM_DATA.asString()))
{
resp.sendError(400);
return;
}
resp.setContentType(req.getContentType());
IO.copy(req.getInputStream(), resp.getOutputStream());
}
}
@BeforeEach @BeforeEach
public void start() throws Exception public void start() throws Exception
{ {
tmpDir = Files.createTempDirectory(MultiPartServletTest.class.getSimpleName()); tmpDir = Files.createTempDirectory(MultiPartServletTest.class.getSimpleName());
assertNotNull(tmpDir);
server = new Server(); server = new Server();
connector = new ServerConnector(server); connector = new ServerConnector(server);
server.addConnector(connector); server.addConnector(connector);
MultipartConfigElement config = new MultipartConfigElement(tmpDir.toAbsolutePath().toString(),
MAX_FILE_SIZE, -1, 1);
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
contextHandler.setContextPath("/"); contextHandler.setContextPath("/");
ServletHolder servletHolder = contextHandler.addServlet(MultiPartServlet.class, "/"); ServletHolder servletHolder = contextHandler.addServlet(MultiPartServlet.class, "/");
servletHolder.getRegistration().setMultipartConfig(config);
MultipartConfigElement config = new MultipartConfigElement(tmpDir.toAbsolutePath().toString(), servletHolder = contextHandler.addServlet(MultiPartEchoServlet.class, "/echo");
MAX_FILE_SIZE, -1, 1);
servletHolder.getRegistration().setMultipartConfig(config); servletHolder.getRegistration().setMultipartConfig(config);
server.setHandler(contextHandler); GzipHandler gzipHandler = new GzipHandler();
gzipHandler.addIncludedMimeTypes("multipart/form-data");
gzipHandler.setMinGzipSize(32);
gzipHandler.setHandler(contextHandler);
server.setHandler(gzipHandler);
server.start(); server.start();
client = new HttpClient(); client = new HttpClient();
client.start(); client.start();
client.getContentDecoderFactories().clear();
} }
@AfterEach @AfterEach
@ -135,6 +172,44 @@ public class MultiPartServletTest
containsString("Multipart Mime part largePart exceeds max filesize")); containsString("Multipart Mime part largePart exceeds max filesize"));
} }
assertThat(tmpDir.toFile().list().length, is(0)); String[] fileList = tmpDir.toFile().list();
assertNotNull(fileList);
assertThat(fileList.length, is(0));
}
@Test
public void testMultiPartGzip() throws Exception
{
String contentString = "the quick brown fox jumps over the lazy dog, " +
"the quick brown fox jumps over the lazy dog";
StringRequestContent content = new StringRequestContent(contentString);
MultiPartRequestContent multiPart = new MultiPartRequestContent();
multiPart.addFieldPart("largePart", content, null);
multiPart.close();
try (StacklessLogging ignored = new StacklessLogging(HttpChannel.class, MultiPartFormInputStream.class))
{
InputStreamResponseListener responseStream = new InputStreamResponseListener();
client.newRequest("localhost", connector.getLocalPort())
.path("/echo")
.scheme(HttpScheme.HTTP.asString())
.method(HttpMethod.POST)
.headers(h -> h.add(HttpHeader.ACCEPT_ENCODING, "gzip"))
.body(multiPart)
.send(responseStream);
Response response = responseStream.get(5, TimeUnit.SECONDS);
HttpFields headers = response.getHeaders();
assertThat(headers.get(HttpHeader.CONTENT_TYPE), startsWith("multipart/form-data"));
assertThat(headers.get(HttpHeader.CONTENT_ENCODING), is("gzip"));
InputStream inputStream = new GZIPInputStream(responseStream.getInputStream());
String contentType = headers.get(HttpHeader.CONTENT_TYPE);
MultiPartFormInputStream mpis = new MultiPartFormInputStream(inputStream, contentType, null, null);
List<Part> parts = new ArrayList<>(mpis.getParts());
assertThat(parts.size(), is(1));
assertThat(IO.toString(parts.get(0).getInputStream()), is(contentString));
}
} }
} }