Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delegate compression to servlet container #390

Merged
merged 3 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ To run locally exploded web archive:
"^.*_anon_.*$"
--controlPort = set the shutdown/control port. -1 to disable, Default disabled

--compression = set the compression scheme (gzip or none to disable compression). Default is gzip.
--sessionTimeout = set the http session timeout value in minutes. Default to what webapp specifies, and then to 60 minutes
--sessionEviction = set the session eviction timeout for idle sessions in seconds. Default value is 180. -1 never evict, 0 evict on exit
--mimeTypes=ARG = define additional MIME type mappings. ARG would be EXT=MIMETYPE:EXT=MIMETYPE:...
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/winstone/HostConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
import winstone.cmdline.CompressionScheme;
import winstone.cmdline.Option;

/**
Expand Down Expand Up @@ -103,7 +105,20 @@
}
}

server.setHandler(handler);
CompressionScheme compressionScheme = Option.COMPRESSION.get(this.args);
switch (compressionScheme) {

Check warning on line 109 in src/main/java/winstone/HostConfiguration.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 109 is only partially covered, one branch is missing
case GZIP:
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setHandler(handler);
server.setHandler(gzipHandler);
break;
case NONE:
server.setHandler(handler);
break;
default:
throw new IllegalArgumentException("Unexpected compression scheme: " + compressionScheme);

Check warning on line 119 in src/main/java/winstone/HostConfiguration.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 119 is not covered by tests
}

Logger.log(
Level.FINER,
Launcher.RESOURCES,
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/winstone/cmdline/CompressionScheme.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package winstone.cmdline;

/**
* The compression schemes supported by the server. In the future, this list may be expanded as support for additional
* compression schemes is added to Jetty upstream.
*/
public enum CompressionScheme {
GZIP,
NONE,
}
26 changes: 26 additions & 0 deletions src/main/java/winstone/cmdline/Option.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
public static final OInt JETTY_ACCEPTORS = integer("jettyAcceptorsCount", -1);
public static final OInt JETTY_SELECTORS = integer("jettySelectorsCount", 0);

public static final OCompression COMPRESSION = new OCompression("compression", CompressionScheme.GZIP);
public static final OString MIME_TYPES = string("mimeTypes");
public static final OInt MAX_PARAM_COUNT = integer("maxParamCount", -1);
public static final OBoolean USAGE = bool("usage", false);
Expand Down Expand Up @@ -308,6 +309,31 @@
}
}

public static class OCompression extends Option<CompressionScheme> {
public OCompression(String name, CompressionScheme defaultValue) {
super(name, CompressionScheme.class, defaultValue);
}

public CompressionScheme get(Map<String, String> args) {
return get(args, defaultValue);
}

public CompressionScheme get(Map<String, String> args, CompressionScheme defaultValue) {
String v = args.get(name);
CompressionScheme compressionScheme;
if (v == null) {
compressionScheme = defaultValue;
} else if (v.equalsIgnoreCase("gzip")) {
compressionScheme = CompressionScheme.GZIP;
} else if (v.equalsIgnoreCase("none")) {

Check warning on line 328 in src/main/java/winstone/cmdline/Option.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 328 is only partially covered, one branch is missing
compressionScheme = CompressionScheme.NONE;
} else {
throw new IllegalArgumentException("Unexpected compression scheme: " + v);

Check warning on line 331 in src/main/java/winstone/cmdline/Option.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 331 is not covered by tests
}
return compressionScheme;
}
}

// static {
// String[] protocols = {"http","https"};
// for (int i=0; i<protocols.length; i++) {
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/winstone/LocalStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Launcher.UsageInstructions.Options=\
\ "^.*_NULL_.*$", \n\
\ "^.*_anon_.*$" \n\
\ --controlPort = set the shutdown/control port. -1 to disable, Default disabled\n\n\
\ --compression = set the compression scheme (gzip or none to disable compression). Default is gzip.\n\
\ --sessionTimeout = set the http session timeout value in minutes. Default to what webapp specifies, and then to 60 minutes\n\
\ --sessionEviction = set the session eviction timeout for idle sessions in seconds. Default value is 180. -1 never evict, 0 evict on exit\n\
\ --mimeTypes=ARG = define additional MIME type mappings. ARG would be EXT=MIMETYPE:EXT=MIMETYPE:...\n\
Expand Down
63 changes: 63 additions & 0 deletions src/test/java/winstone/LauncherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,89 @@

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Filter;
import java.util.logging.LogRecord;
import java.util.zip.GZIPInputStream;
import org.eclipse.jetty.server.ServerConnector;
import org.junit.Test;

/**
* @author Kohsuke Kawaguchi
*/
public class LauncherTest extends AbstractWinstoneTest {
@Test
public void implicitGzip() throws Exception {
Map<String, String> args = new HashMap<>();
args.put("warfile", "target/test-classes/test.war");
args.put("prefix", "/");
args.put("httpPort", "0");
winstone = new Launcher(args);
verifyGzip(true);
}

@Test
public void explicitGzip() throws Exception {
Map<String, String> args = new HashMap<>();
args.put("warfile", "target/test-classes/test.war");
args.put("prefix", "/");
args.put("httpPort", "0");
args.put("compression", "gzip");
winstone = new Launcher(args);
verifyGzip(true);
}

@Test
public void noCompression() throws Exception {
Map<String, String> args = new HashMap<>();
args.put("warfile", "target/test-classes/test.war");
args.put("prefix", "/");
args.put("httpPort", "0");
args.put("compression", "none");
winstone = new Launcher(args);
verifyGzip(false);
}

private void verifyGzip(boolean gzip) throws Exception {
int port = ((ServerConnector) winstone.server.getConnectors()[0]).getLocalPort();
HttpRequest request = HttpRequest.newBuilder(new URI("http://127.0.0.2:" + port + "/lipsum.txt"))
.GET()
.header("Accept-Encoding", "gzip")
.build();
HttpResponse<InputStream> response =
HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofInputStream());
assertEquals(HttpURLConnection.HTTP_OK, response.statusCode());
assertEquals("text/plain", response.headers().firstValue("Content-Type").orElseThrow());
InputStream is;
if (gzip) {
assertEquals(
"gzip", response.headers().firstValue("Content-Encoding").orElseThrow());
is = new GZIPInputStream(response.body());
} else {
assertFalse(response.headers().firstValue("Content-Encoding").isPresent());
is = response.body();
}
try {
assertThat(new String(is.readAllBytes(), StandardCharsets.UTF_8), startsWith("Lorem ipsum dolor sit amet"));
} finally {
is.close();
}
}

@Test
public void mimeType() throws Exception {
Map<String, String> args = new HashMap<>();
Expand Down
9 changes: 9 additions & 0 deletions src/testwebapp/lipsum.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tristique vehicula bibendum. Aenean ut ligula vel risus suscipit hendrerit. Ut eu nibh quis purus bibendum semper nec non nibh. Mauris a sapien vel arcu lobortis interdum. Proin eget elit accumsan, aliquet lacus pharetra, pulvinar massa. Nullam mauris urna, venenatis at dolor at, vulputate consequat turpis. Aenean tempus dignissim pretium. Pellentesque lobortis tortor ut tristique sagittis. Suspendisse porttitor facilisis leo ac maximus. Sed dapibus metus pulvinar, aliquam leo ut, finibus odio.

Nunc tristique ligula ac porttitor bibendum. Maecenas molestie sagittis dui ac molestie. Nullam et est ex. Nullam et nunc interdum, congue risus quis, viverra neque. In efficitur, mauris ac porta congue, tellus lacus mattis massa, eu pulvinar magna ex non lacus. Proin odio libero, placerat eget neque ut, tristique dignissim eros. Sed elementum feugiat efficitur. Nulla sit amet porta nibh. Vivamus placerat bibendum risus sit amet blandit. Aliquam erat volutpat. Cras orci tellus, posuere eget nunc non, elementum consectetur lacus. Nullam at hendrerit neque.

Pellentesque non interdum est, vitae volutpat arcu. Mauris imperdiet elit sed sodales egestas. Curabitur viverra quis ante in convallis. In feugiat, est eget suscipit mollis, ante ipsum scelerisque ante, ac blandit urna augue non ex. Nam vel elit vel ante gravida dignissim. Duis quis viverra urna. Phasellus ultrices, nulla nec mollis dictum, nulla tortor gravida lorem, id maximus lorem nunc eget nisl. Nulla condimentum ligula massa, id ultrices enim ultrices in. Aliquam rutrum scelerisque lacus non accumsan. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam erat volutpat. In nec congue elit, vel mollis diam. Donec sed erat a massa elementum interdum aliquet at risus. Nulla non euismod eros, porta imperdiet ante.

Aenean lectus est, maximus sed lectus nec, vehicula tincidunt velit. Donec vel ligula eget mi aliquam cursus. Proin laoreet dui eu sapien feugiat facilisis. Praesent nec est id diam pulvinar efficitur. Duis nec facilisis nisl, nec cursus nulla. Nulla lacinia felis ut euismod porta. Curabitur porta sem nec dui posuere, eget vestibulum enim euismod. Duis at ultrices nulla, ullamcorper scelerisque libero. Mauris vel auctor justo, imperdiet fermentum nunc. Integer nec eleifend ex.

Aliquam consectetur tincidunt scelerisque. Nullam fermentum blandit lacus. Quisque aliquam venenatis fringilla. Sed at ultricies lectus. Donec arcu mi, dictum eu sem et, mattis malesuada ligula. Donec facilisis est non est porttitor, id ultrices turpis sollicitudin. In eleifend urna sed justo lobortis tincidunt. Phasellus feugiat venenatis elit vel varius. Aenean lorem erat, iaculis sit amet tincidunt ac, volutpat at ipsum. Donec eleifend ipsum dignissim orci iaculis, nec condimentum nisl lacinia. Donec nec felis in erat finibus consequat.