Configure Jetty to compress responses to requests other than GET

Closes gh-8184
This commit is contained in:
Andy Wilkinson 2017-07-22 10:41:53 +01:00
parent 6df1be3f1a
commit bc4603925e
3 changed files with 36 additions and 49 deletions

View File

@ -32,6 +32,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.server.AbstractConnector; import org.eclipse.jetty.server.AbstractConnector;
@ -229,6 +230,9 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
Compression compression = getCompression(); Compression compression = getCompression();
handler.setMinGzipSize(compression.getMinResponseSize()); handler.setMinGzipSize(compression.getMinResponseSize());
handler.setIncludedMimeTypes(compression.getMimeTypes()); handler.setIncludedMimeTypes(compression.getMimeTypes());
for (HttpMethod httpMethod : HttpMethod.values()) {
handler.addIncludedMethods(httpMethod.name());
}
if (compression.getExcludedUserAgents() != null) { if (compression.getExcludedUserAgents() != null) {
handler.setExcludedAgentPatterns(compression.getExcludedUserAgents()); handler.setExcludedAgentPatterns(compression.getExcludedUserAgents());
} }
@ -581,8 +585,8 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
} }
/** /**
* Returns a mutable collection of Jetty {@link JettyServerCustomizer}s that will be applied * Returns a mutable collection of Jetty {@link JettyServerCustomizer}s that will be
* to the {@link Server} before the it is created. * applied to the {@link Server} before the it is created.
* @return the {@link JettyServerCustomizer}s * @return the {@link JettyServerCustomizer}s
*/ */
public Collection<JettyServerCustomizer> getServerCustomizers() { public Collection<JettyServerCustomizer> getServerCustomizers() {

View File

@ -16,18 +16,12 @@
package org.springframework.boot.web.embedded.jetty; package org.springframework.boot.web.embedded.jetty;
import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.jasper.servlet.JspServlet; import org.apache.jasper.servlet.JspServlet;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
@ -43,13 +37,10 @@ import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.Test; import org.junit.Test;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.springframework.boot.web.server.Compression;
import org.springframework.boot.web.server.PortInUseException; import org.springframework.boot.web.server.PortInUseException;
import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.Ssl;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory; import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory;
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactoryTests; import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactoryTests;
import org.springframework.http.HttpHeaders;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.isA; import static org.hamcrest.CoreMatchers.isA;
@ -296,38 +287,6 @@ public class JettyServletWebServerFactoryTests
factory.getWebServer().start(); factory.getWebServer().start();
} }
@Override
@SuppressWarnings("serial")
// Workaround for Jetty issue - https://bugs.eclipse.org/bugs/show_bug.cgi?id=470646
protected String setUpFactoryForCompression(final int contentSize, String[] mimeTypes,
String[] excludedUserAgents) throws Exception {
char[] chars = new char[contentSize];
Arrays.fill(chars, 'F');
final String testContent = new String(chars);
AbstractServletWebServerFactory factory = getFactory();
Compression compression = new Compression();
compression.setEnabled(true);
if (mimeTypes != null) {
compression.setMimeTypes(mimeTypes);
}
if (excludedUserAgents != null) {
compression.setExcludedUserAgents(excludedUserAgents);
}
factory.setCompression(compression);
this.webServer = factory
.getWebServer(new ServletRegistrationBean<HttpServlet>(new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentLength(contentSize);
resp.setHeader(HttpHeaders.CONTENT_TYPE, "text/plain");
resp.getWriter().print(testContent);
}
}, "/test.txt"));
this.webServer.start();
return testContent;
}
@Override @Override
protected JspServlet getJspServlet() throws Exception { protected JspServlet getJspServlet() throws Exception {
WebAppContext context = (WebAppContext) ((JettyWebServer) this.webServer) WebAppContext context = (WebAppContext) ((JettyWebServer) this.webServer)

View File

@ -58,7 +58,9 @@ import javax.servlet.ServletContext;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
@ -775,10 +777,15 @@ public abstract class AbstractServletWebServerFactoryTests {
} }
@Test @Test
public void compression() throws Exception { public void compressionOfResposeToGetRequest() throws Exception {
assertThat(doTestCompression(10000, null, null)).isTrue(); assertThat(doTestCompression(10000, null, null)).isTrue();
} }
@Test
public void compressionOfResposeToPostRequest() throws Exception {
assertThat(doTestCompression(10000, null, null, HttpMethod.POST)).isTrue();
}
@Test @Test
public void noCompressionForSmallResponse() throws Exception { public void noCompressionForSmallResponse() throws Exception {
assertThat(doTestCompression(100, null, null)).isFalse(); assertThat(doTestCompression(100, null, null)).isFalse();
@ -991,12 +998,18 @@ public abstract class AbstractServletWebServerFactoryTests {
private boolean doTestCompression(int contentSize, String[] mimeTypes, private boolean doTestCompression(int contentSize, String[] mimeTypes,
String[] excludedUserAgents) throws Exception { String[] excludedUserAgents) throws Exception {
return doTestCompression(contentSize, mimeTypes, excludedUserAgents,
HttpMethod.GET);
}
private boolean doTestCompression(int contentSize, String[] mimeTypes,
String[] excludedUserAgents, HttpMethod method) throws Exception {
String testContent = setUpFactoryForCompression(contentSize, mimeTypes, String testContent = setUpFactoryForCompression(contentSize, mimeTypes,
excludedUserAgents); excludedUserAgents);
TestGzipInputStreamFactory inputStreamFactory = new TestGzipInputStreamFactory(); TestGzipInputStreamFactory inputStreamFactory = new TestGzipInputStreamFactory();
Map<String, InputStreamFactory> contentDecoderMap = Collections Map<String, InputStreamFactory> contentDecoderMap = Collections
.singletonMap("gzip", (InputStreamFactory) inputStreamFactory); .singletonMap("gzip", (InputStreamFactory) inputStreamFactory);
String response = getResponse(getLocalUrl("/test.txt"), String response = getResponse(getLocalUrl("/test.txt"), method,
new HttpComponentsClientHttpRequestFactory( new HttpComponentsClientHttpRequestFactory(
HttpClientBuilder.create().setUserAgent("testUserAgent") HttpClientBuilder.create().setUserAgent("testUserAgent")
.setContentDecoderRegistry(contentDecoderMap).build())); .setContentDecoderRegistry(contentDecoderMap).build()));
@ -1004,15 +1017,12 @@ public abstract class AbstractServletWebServerFactoryTests {
return inputStreamFactory.wasCompressionUsed(); return inputStreamFactory.wasCompressionUsed();
} }
protected String setUpFactoryForCompression(int contentSize, String[] mimeTypes, private String setUpFactoryForCompression(int contentSize, String[] mimeTypes,
String[] excludedUserAgents) throws Exception { String[] excludedUserAgents) throws Exception {
char[] chars = new char[contentSize]; char[] chars = new char[contentSize];
Arrays.fill(chars, 'F'); Arrays.fill(chars, 'F');
String testContent = new String(chars); String testContent = new String(chars);
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
FileCopyUtils.copy(testContent,
new FileWriter(this.temporaryFolder.newFile("test.txt")));
factory.setDocumentRoot(this.temporaryFolder.getRoot());
Compression compression = new Compression(); Compression compression = new Compression();
compression.setEnabled(true); compression.setEnabled(true);
if (mimeTypes != null) { if (mimeTypes != null) {
@ -1022,6 +1032,20 @@ public abstract class AbstractServletWebServerFactoryTests {
compression.setExcludedUserAgents(excludedUserAgents); compression.setExcludedUserAgents(excludedUserAgents);
} }
factory.setCompression(compression); factory.setCompression(compression);
factory.addInitializers(
new ServletRegistrationBean<HttpServlet>(new HttpServlet() {
@Override
protected void service(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain");
resp.setContentLength(testContent.length());
resp.getWriter().write(testContent);
resp.getWriter().flush();
}
}, "/test.txt"));
this.webServer = factory.getWebServer(); this.webServer = factory.getWebServer();
this.webServer.start(); this.webServer.start();
return testContent; return testContent;