Skip to content

Commit

Permalink
Merge branch 'decompression_support' of git://github.com/clonyara/ver…
Browse files Browse the repository at this point in the history
…t.x into clonyara-decompression_support
  • Loading branch information
vietj committed Nov 6, 2016
2 parents 17ecf4c + a31d8da commit 52c51a1
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/main/asciidoc/dataobjects.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,10 @@ Add a CRL path
+++
Add a CRL value
+++
|[[decompressionSupported]]`decompressionSupported`|`Boolean`|
+++
Set whether the server supports decompression
+++
|[[enabledCipherSuites]]`enabledCipherSuites`|`Array of String`|
+++
Add an enabled cipher suite, appended to the ordered suites.
Expand Down
1 change: 1 addition & 0 deletions src/main/asciidoc/java/cli-for-java.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

The described `link:../../apidocs/io/vertx/core/cli/Option.html[Option]` and `link:../../apidocs/io/vertx/core/cli/Argument.html[Argument]` classes are _untyped_,
meaning that the only get String values.

`link:../../apidocs/io/vertx/core/cli/TypedOption.html[TypedOption]` and `link:../../apidocs/io/vertx/core/cli/TypedArgument.html[TypedArgument]` let you specify a _type_, so the
(String) raw value is converted to the specified type.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public static void fromJson(JsonObject json, HttpServerOptions obj) {
if (json.getValue("compressionSupported") instanceof Boolean) {
obj.setCompressionSupported((Boolean)json.getValue("compressionSupported"));
}
if (json.getValue("decompressionSupported") instanceof Boolean) {
obj.setDecompressionSupported((Boolean)json.getValue("decompressionSupported"));
}
if (json.getValue("handle100ContinueAutomatically") instanceof Boolean) {
obj.setHandle100ContinueAutomatically((Boolean)json.getValue("handle100ContinueAutomatically"));
}
Expand Down Expand Up @@ -73,6 +76,7 @@ public static void toJson(HttpServerOptions obj, JsonObject json) {
collect(java.util.stream.Collectors.toList())));
}
json.put("compressionSupported", obj.isCompressionSupported());
json.put("decompressionSupported", obj.isDecompressionSupported());
json.put("handle100ContinueAutomatically", obj.isHandle100ContinueAutomatically());
json.put("http2ConnectionWindowSize", obj.getHttp2ConnectionWindowSize());
if (obj.getInitialSettings() != null) {
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/io/vertx/core/http/HttpServerOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ public class HttpServerOptions extends NetServerOptions {
*/
public static final int DEFAULT_HTTP2_CONNECTION_WINDOW_SIZE = -1;

/**
* Default value of whether decompression is supported = false
*/
public static final boolean DEFAULT_DECOMPRESSION_SUPPORTED = false;

private boolean compressionSupported;
private int maxWebsocketFrameSize;
private String websocketSubProtocols;
Expand All @@ -94,6 +99,7 @@ public class HttpServerOptions extends NetServerOptions {
private Http2Settings initialSettings;
private List<HttpVersion> alpnVersions;
private int http2ConnectionWindowSize;
private boolean decompressionSupported;

/**
* Default constructor
Expand Down Expand Up @@ -121,6 +127,7 @@ public HttpServerOptions(HttpServerOptions other) {
this.initialSettings = other.initialSettings != null ? new Http2Settings(other.initialSettings) : null;
this.alpnVersions = other.alpnVersions != null ? new ArrayList<>(other.alpnVersions) : null;
this.http2ConnectionWindowSize = other.http2ConnectionWindowSize;
this.decompressionSupported = other.isDecompressionSupported();
}

/**
Expand All @@ -145,6 +152,7 @@ private void init() {
initialSettings = new Http2Settings().setMaxConcurrentStreams(DEFAULT_INITIAL_SETTINGS_MAX_CONCURRENT_STREAMS);
alpnVersions = new ArrayList<>(DEFAULT_ALPN_VERSIONS);
http2ConnectionWindowSize = DEFAULT_HTTP2_CONNECTION_WINDOW_SIZE;
decompressionSupported = DEFAULT_DECOMPRESSION_SUPPORTED;
}

@Override
Expand Down Expand Up @@ -514,6 +522,24 @@ public HttpServerOptions setLogActivity(boolean logEnabled) {
return (HttpServerOptions) super.setLogActivity(logEnabled);
}

/**
* @return true if the server supports decompression
*/
public boolean isDecompressionSupported() {
return decompressionSupported;
}

/**
* Set whether the server supports decompression
*
* @param decompressionSupported true if decompression supported
* @return a reference to this, so the API can be used fluently
*/
public HttpServerOptions setDecompressionSupported(boolean decompressionSupported) {
this.decompressionSupported = decompressionSupported;
return this;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -531,6 +557,7 @@ public boolean equals(Object o) {
if (initialSettings == null ? that.initialSettings != null : !initialSettings.equals(that.initialSettings)) return false;
if (alpnVersions == null ? that.alpnVersions != null : !alpnVersions.equals(that.alpnVersions)) return false;
if (http2ConnectionWindowSize != that.http2ConnectionWindowSize) return false;
if (decompressionSupported != that.decompressionSupported) return false;
return !(websocketSubProtocols != null ? !websocketSubProtocols.equals(that.websocketSubProtocols) : that.websocketSubProtocols != null);
}

Expand All @@ -547,6 +574,7 @@ public int hashCode() {
result = 31 * result + maxHeaderSize;
result = 31 * result + (alpnVersions != null ? alpnVersions.hashCode() : 0);
result = 31 * result + http2ConnectionWindowSize;
result = 31 * result + (decompressionSupported ? 1 : 0);
return result;
}
}
5 changes: 5 additions & 0 deletions src/main/java/io/vertx/core/http/impl/HttpServerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpContentDecompressor;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpHeaders;
Expand Down Expand Up @@ -355,6 +356,7 @@ private VertxHttp2ConnectionHandler<Http2ServerConnection> createHttp2Handler(Ha
.connectionMap(connectionMap2)
.server(true)
.useCompression(options.isCompressionSupported())
.useDecompression(options.isDecompressionSupported())
.initialSettings(options.getInitialSettings())
.connectionFactory(connHandler -> new Http2ServerConnection(ch, holder.context, serverOrigin, connHandler, options, holder.handler.requesthHandler, metrics))
.logEnabled(logEnabled)
Expand All @@ -371,6 +373,9 @@ private void configureHttp1(ChannelPipeline pipeline) {
pipeline.addLast("httpDecoder", new HttpRequestDecoder(options.getMaxInitialLineLength()
, options.getMaxHeaderSize(), options.getMaxChunkSize(), false));
pipeline.addLast("httpEncoder", new VertxHttpResponseEncoder());
if (options.isDecompressionSupported()) {
pipeline.addLast("inflater", new HttpContentDecompressor(true));
}
if (options.isCompressionSupported()) {
pipeline.addLast("deflater", new HttpChunkContentCompressor());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class VertxHttp2ConnectionHandlerBuilder<C extends Http2ConnectionBase> extends

private Map<Channel, ? super C> connectionMap;
private boolean useCompression;
private boolean useDecompression;
private io.vertx.core.http.Http2Settings initialSettings;
private Function<VertxHttp2ConnectionHandler<C>, C> connectionFactory;
private boolean logEnabled;
Expand All @@ -64,6 +65,11 @@ VertxHttp2ConnectionHandlerBuilder<C> useCompression(boolean useCompression) {
return this;
}

VertxHttp2ConnectionHandlerBuilder<C> useDecompression(boolean useDecompression) {
this.useDecompression = useDecompression;
return this;
}

VertxHttp2ConnectionHandlerBuilder<C> connectionFactory(Function<VertxHttp2ConnectionHandler<C>, C> connectionFactory) {
this.connectionFactory = connectionFactory;
return this;
Expand Down Expand Up @@ -92,7 +98,11 @@ protected VertxHttp2ConnectionHandler<C> build(Http2ConnectionDecoder decoder, H
encoder = new CompressorHttp2ConnectionEncoder(encoder);
}
VertxHttp2ConnectionHandler<C> handler = new VertxHttp2ConnectionHandler<>(connectionMap, decoder, encoder, initialSettings, connectionFactory);
frameListener(handler.connection);
if (useDecompression) {
frameListener(new DelegatingDecompressorFrameListener(decoder.connection(), handler.connection));
} else {
frameListener(handler.connection);
}
return handler;
} else {
VertxHttp2ConnectionHandler<C> handler = new VertxHttp2ConnectionHandler<>(connectionMap, decoder, encoder, initialSettings, connectionFactory);
Expand Down
37 changes: 36 additions & 1 deletion src/test/java/io/vertx/test/core/Http1xTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,10 @@ public void testServerOptions() {
assertEquals(rand, options.getHttp2ConnectionWindowSize());
assertEquals(options, options.setHttp2ConnectionWindowSize(-1));
assertEquals(-1, options.getHttp2ConnectionWindowSize());

assertFalse(options.isDecompressionSupported());
assertEquals(options, options.setDecompressionSupported(true));
assertTrue(options.isDecompressionSupported());
}

@Test
Expand Down Expand Up @@ -717,6 +721,7 @@ public void testCopyServerOptions() {
boolean openSslSessionCacheEnabled = rand.nextBoolean();
SSLEngineOptions sslEngine = TestUtils.randomBoolean() ? new JdkSSLEngineOptions() : new OpenSSLEngineOptions();
List<HttpVersion> alpnVersions = Collections.singletonList(HttpVersion.values()[TestUtils.randomPositiveInt() % 3]);
boolean decompressionSupported = rand.nextBoolean();
options.setSendBufferSize(sendBufferSize);
options.setReceiveBufferSize(receiverBufferSize);
options.setReuseAddress(reuseAddress);
Expand Down Expand Up @@ -745,6 +750,7 @@ public void testCopyServerOptions() {
options.setSslEngineOptions(sslEngine);
options.setInitialSettings(initialSettings);
options.setAlpnVersions(alpnVersions);
options.setDecompressionSupported(decompressionSupported);
HttpServerOptions copy = new HttpServerOptions(options);
assertEquals(sendBufferSize, copy.getSendBufferSize());
assertEquals(receiverBufferSize, copy.getReceiveBufferSize());
Expand Down Expand Up @@ -779,6 +785,7 @@ public void testCopyServerOptions() {
assertEquals(http2ConnectionWindowSize, copy.getHttp2ConnectionWindowSize());
assertEquals(sslEngine, copy.getSslEngineOptions());
assertEquals(alpnVersions, copy.getAlpnVersions());
assertEquals(decompressionSupported, copy.isDecompressionSupported());
}

@Test
Expand Down Expand Up @@ -808,6 +815,7 @@ public void testDefaultServerOptionsJson() {
assertEquals(def.getSslEngineOptions(), json.getSslEngineOptions());
assertEquals(def.getAlpnVersions(), json.getAlpnVersions());
assertEquals(def.getHttp2ConnectionWindowSize(), json.getHttp2ConnectionWindowSize());
assertEquals(def.isDecompressionSupported(), json.isDecompressionSupported());
}

@Test
Expand Down Expand Up @@ -852,6 +860,7 @@ public void testServerOptionsJson() {
String sslEngine = TestUtils.randomBoolean() ? "jdkSslEngineOptions" : "openSslEngineOptions";
List<HttpVersion> alpnVersions = Collections.singletonList(HttpVersion.values()[TestUtils.randomPositiveInt() % 3]);
boolean openSslSessionCacheEnabled = TestUtils.randomBoolean();
boolean decompressionSupported = TestUtils.randomBoolean();

JsonObject json = new JsonObject();
json.put("sendBufferSize", sendBufferSize)
Expand Down Expand Up @@ -890,7 +899,8 @@ public void testServerOptionsJson() {
.put("http2ConnectionWindowSize", http2ConnectionWindowSize)
.put(sslEngine, new JsonObject())
.put("alpnVersions", new JsonArray().add(alpnVersions.get(0).name()))
.put("openSslSessionCacheEnabled", openSslSessionCacheEnabled);
.put("openSslSessionCacheEnabled", openSslSessionCacheEnabled)
.put("decompressionSupported", decompressionSupported);

HttpServerOptions options = new HttpServerOptions(json);
assertEquals(sendBufferSize, options.getSendBufferSize());
Expand Down Expand Up @@ -938,6 +948,7 @@ public void testServerOptionsJson() {
break;
}
assertEquals(alpnVersions, options.getAlpnVersions());
assertEquals(decompressionSupported, options.isDecompressionSupported());

// Test other keystore/truststore types
json.remove("keyStoreOptions");
Expand Down Expand Up @@ -2586,6 +2597,30 @@ public void testRandomPorts() throws Exception {
await();
}

@Test
public void testContentDecompression() throws Exception {
server.close();
server = vertx.createHttpServer(new HttpServerOptions().setPort(DEFAULT_HTTP_PORT).setDecompressionSupported(true));
String expected = TestUtils.randomAlphaString(1000);
byte[] dataGzipped = TestUtils.compressGzip(expected);
server.requestHandler(req -> {
assertEquals("localhost:" + DEFAULT_HTTP_PORT, req.headers().get("host"));
req.bodyHandler(buffer -> {
assertEquals(expected, buffer.toString());
req.response().end();
});
});

server.listen(onSuccess(server -> {
client
.request(HttpMethod.POST, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "some-uri", resp -> testComplete())
.putHeader("Content-Encoding", "gzip")
.end(Buffer.buffer(dataGzipped));
}));

await();
}

@Test
public void testResetClientRequestNotYetSent() throws Exception {
testResetClientRequestNotYetSent(false, false);
Expand Down
29 changes: 29 additions & 0 deletions src/test/java/io/vertx/test/core/Http2ServerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2089,6 +2089,35 @@ public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int
fut.sync();
await();
}

@Test
public void testRequestCompressionEnabled() throws Exception {
String expected = TestUtils.randomAlphaString(1000);
byte[] expectedGzipped = TestUtils.compressGzip(expected);
server.close();
server = vertx.createHttpServer(serverOptions.setDecompressionSupported(true));
server.requestHandler(req -> {
StringBuilder postContent = new StringBuilder();
req.handler(buff -> {
postContent.append(buff.toString());
});
req.endHandler(v -> {
req.response().putHeader("content-type", "text/plain").end("");
assertEquals(expected, postContent.toString());
testComplete();
});
});
startServer();
TestClient client = new TestClient();
ChannelFuture fut = client.connect(DEFAULT_HTTPS_PORT, DEFAULT_HTTPS_HOST, request -> {
int id = request.nextStreamId();
request.encoder.writeHeaders(request.context, id, POST("/").add("content-encoding", "gzip"), 0, false, request.context.newPromise());
request.encoder.writeData(request.context, id, Buffer.buffer(expectedGzipped).getByteBuf(), 0, true, request.context.newPromise());
request.context.flush();
});
fut.sync();
await();
}

@Test
public void test100ContinueHandledManually() throws Exception {
Expand Down
15 changes: 15 additions & 0 deletions src/test/java/io/vertx/test/core/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.Http2Settings;

import java.io.ByteArrayOutputStream;
import java.util.EnumSet;
import java.util.Random;
import java.util.Set;
import java.util.zip.GZIPOutputStream;

import static org.junit.Assert.fail;

Expand Down Expand Up @@ -305,4 +307,17 @@ public static void assertIndexOutOfBoundsException(Runnable runnable) {
// OK
}
}

/**
* @param source
* @return gzipped data
* @throws Exception
*/
public static byte[] compressGzip(String source) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gos = new GZIPOutputStream(baos);
gos.write(source.getBytes());
gos.close();
return baos.toByteArray();
}
}

0 comments on commit 52c51a1

Please sign in to comment.