diff --git a/bom/application/pom.xml b/bom/application/pom.xml index fadad60a12689..b2afc0d2087e8 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -114,7 +114,7 @@ 1.15.4.Final 1.8.7.Final 3.2.0.Final - 4.1.0.Beta1 + 4.1.0.CR1 4.5.13 4.4.14 4.1.4 @@ -137,7 +137,7 @@ 12.1.1.Final 4.4.0.Final 2.9.1 - 4.1.60.Final + 4.1.65.Final 1.0.3 3.4.1.Final 0.17.0 diff --git a/extensions/netty/runtime/pom.xml b/extensions/netty/runtime/pom.xml index 880977accf3a0..78bcd224ba879 100644 --- a/extensions/netty/runtime/pom.xml +++ b/extensions/netty/runtime/pom.xml @@ -22,6 +22,14 @@ io.netty netty-codec + + io.netty + netty-codec-http + + + io.netty + netty-codec-http2 + io.quarkus quarkus-arc diff --git a/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java b/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java index 2580740d1b690..19b5ed2e83dd2 100644 --- a/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java +++ b/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java @@ -1,5 +1,10 @@ package io.quarkus.netty.runtime.graal; +import static io.netty.handler.codec.http.HttpHeaderValues.DEFLATE; +import static io.netty.handler.codec.http.HttpHeaderValues.GZIP; +import static io.netty.handler.codec.http.HttpHeaderValues.X_DEFLATE; +import static io.netty.handler.codec.http.HttpHeaderValues.X_GZIP; + import java.nio.ByteBuffer; import java.security.PrivateKey; import java.security.Provider; @@ -17,6 +22,7 @@ import javax.net.ssl.TrustManagerFactory; import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; import com.oracle.svm.core.annotate.Substitute; @@ -29,7 +35,14 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; import io.netty.channel.DefaultChannelPromise; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.handler.codec.compression.ZlibCodecFactory; +import io.netty.handler.codec.compression.ZlibWrapper; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http2.Http2Exception; import io.netty.handler.ssl.ApplicationProtocolConfig; import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; import io.netty.handler.ssl.CipherSuiteFilter; @@ -83,7 +96,9 @@ static boolean isAlpnSupported() { } } -/** Hardcode io.netty.handler.ssl.OpenSsl as non-available */ +/** + * Hardcode io.netty.handler.ssl.OpenSsl as non-available + */ @TargetClass(className = "io.netty.handler.ssl.OpenSsl") final class Target_io_netty_handler_ssl_OpenSsl { @@ -186,7 +201,8 @@ final class Target_io_netty_handler_ssl_JdkAlpnApplicationProtocolNegotiator_Alp @Substitute public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc, JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) { - return (SSLEngine) (Object) new Target_io_netty_handler_ssl_JdkAlpnSslEngine(engine, applicationNegotiator, isServer); + return (SSLEngine) (Object) new Target_io_netty_handler_ssl_JdkAlpnSslEngine(engine, applicationNegotiator, + isServer); } } @@ -242,7 +258,8 @@ final class Target_io_netty_handler_ssl_SslContext { @Substitute static SslContext newServerContextInternal(SslProvider provider, Provider sslContextProvider, - X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, + X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, + X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp, String keyStoreType, @@ -257,10 +274,12 @@ static SslContext newServerContextInternal(SslProvider provider, Provider sslCon } @Substitute - static SslContext newClientContextInternal(SslProvider provider, Provider sslContextProvider, X509Certificate[] trustCert, + static SslContext newClientContextInternal(SslProvider provider, Provider sslContextProvider, + X509Certificate[] trustCert, TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, - ApplicationProtocolConfig apn, String[] protocols, long sessionCacheSize, long sessionTimeout, boolean enableOcsp, + ApplicationProtocolConfig apn, String[] protocols, long sessionCacheSize, long sessionTimeout, + boolean enableOcsp, String keyStoreType, Map.Entry, Object>... options) throws SSLException { if (enableOcsp) { throw new IllegalArgumentException("OCSP is not supported with this SslProvider: " + provider); @@ -305,11 +324,11 @@ static JdkApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig c // .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); // } SelectorFailureBehavior behavior = config.selectorFailureBehavior(); - if (behavior == SelectorFailureBehavior.FATAL_ALERT) + if (behavior == SelectorFailureBehavior.FATAL_ALERT) { return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); - else if (behavior == SelectorFailureBehavior.NO_ADVERTISE) + } else if (behavior == SelectorFailureBehavior.NO_ADVERTISE) { return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols()); - else { + } else { throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") .append(config.selectorFailureBehavior()).append(" failure behavior").toString()); } @@ -321,12 +340,14 @@ else if (behavior == SelectorFailureBehavior.NO_ADVERTISE) return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols()); default: throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ") - .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString()); + .append(config.selectedListenerFailureBehavior()).append(" failure behavior") + .toString()); } } default: throw new UnsupportedOperationException( - new StringBuilder("JDK provider does not support ").append(config.protocol()).append(" protocol") + new StringBuilder("JDK provider does not support ").append(config.protocol()) + .append(" protocol") .toString()); } } @@ -515,6 +536,67 @@ public long memoryAddress() { } +@TargetClass(className = "io.netty.handler.codec.compression.BrotliDecoder") +@Delete +final class Target_BrotliDecoder { + +} + +@TargetClass(className = "io.netty.handler.codec.http.HttpContentDecompressor") +final class Target_io_netty_handler_codec_http_HttpContentDecompressor { + + @Alias + private boolean strict; + + @Alias + protected ChannelHandlerContext ctx; + + @Substitute + protected EmbeddedChannel newContentDecoder(String contentEncoding) throws Exception { + if (GZIP.contentEqualsIgnoreCase(contentEncoding) || + X_GZIP.contentEqualsIgnoreCase(contentEncoding)) { + return new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), + ctx.channel().config(), ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP)); + } + if (DEFLATE.contentEqualsIgnoreCase(contentEncoding) || + X_DEFLATE.contentEqualsIgnoreCase(contentEncoding)) { + final ZlibWrapper wrapper = strict ? ZlibWrapper.ZLIB : ZlibWrapper.ZLIB_OR_NONE; + // To be strict, 'deflate' means ZLIB, but some servers were not implemented correctly. + return new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), + ctx.channel().config(), ZlibCodecFactory.newZlibDecoder(wrapper)); + } + + // 'identity' or unsupported + return null; + } +} + +@TargetClass(className = "io.netty.handler.codec.http2.DelegatingDecompressorFrameListener") +final class Target_io_netty_handler_codec_http2_DelegatingDecompressorFrameListener { + + @Alias + boolean strict; + + @Substitute + protected EmbeddedChannel newContentDecompressor(ChannelHandlerContext ctx, CharSequence contentEncoding) + throws Http2Exception { + if (!HttpHeaderValues.GZIP.contentEqualsIgnoreCase(contentEncoding) + && !HttpHeaderValues.X_GZIP.contentEqualsIgnoreCase(contentEncoding)) { + if (!HttpHeaderValues.DEFLATE.contentEqualsIgnoreCase(contentEncoding) + && !HttpHeaderValues.X_DEFLATE.contentEqualsIgnoreCase(contentEncoding)) { + return null; + } else { + ZlibWrapper wrapper = this.strict ? ZlibWrapper.ZLIB : ZlibWrapper.ZLIB_OR_NONE; + return new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), ctx.channel().config(), + new ChannelHandler[] { ZlibCodecFactory.newZlibDecoder(wrapper) }); + } + } else { + return new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), ctx.channel().config(), + new ChannelHandler[] { ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP) }); + } + } +} + class NettySubstitutions { } diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/CompressionTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/CompressionTest.java index 4384a442e9986..29ab204a67472 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/CompressionTest.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/CompressionTest.java @@ -1,5 +1,8 @@ package io.quarkus.vertx.http; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; @@ -45,7 +48,7 @@ public void test() throws Exception { .body(Matchers.equalTo(longString)); RestAssured.given().get("/nocompress").then().statusCode(200) - .header("content-encoding", "identity") + .header("content-encoding", is(nullValue())) .header("content-length", Matchers.equalTo(Integer.toString(longString.length()))) .body(Matchers.equalTo(longString)); } diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/hotreload/VertxInjectionTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/hotreload/VertxInjectionTest.java index 993b549643bdf..194dbb538884c 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/hotreload/VertxInjectionTest.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/hotreload/VertxInjectionTest.java @@ -23,9 +23,7 @@ public void testEditingBeanUsingVertx() { .statusCode(200) .body(containsString("hello")); - System.out.println("Modification"); TEST.modifySourceFile("VertxEventBusConsumer.java", s -> s.replace("hello", "bonjour")); - System.out.println("After"); RestAssured.get("/").then() .statusCode(200) .body(containsString("bonjour")); diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/filters/QuarkusRequestWrapper.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/filters/QuarkusRequestWrapper.java index ab9210d6cdbdc..15efa520877ec 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/filters/QuarkusRequestWrapper.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/filters/QuarkusRequestWrapper.java @@ -204,6 +204,11 @@ public Cookie setMaxAge(long maxAge) { return null; } + @Override + public long getMaxAge() { + return Long.MIN_VALUE; + } + @Override public Cookie setSecure(boolean secure) { return null;