diff --git a/bom/pom.xml b/bom/pom.xml index fc5eaa809f..0a827f5b12 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -31,7 +31,7 @@ grizzly-bom pom grizzly-bom - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 Grizzly Bill of Materials (BOM) diff --git a/extras/bundles/grizzly-httpservice-bundle/pom.xml b/extras/bundles/grizzly-httpservice-bundle/pom.xml index 19437313ef..8f56577eb2 100644 --- a/extras/bundles/grizzly-httpservice-bundle/pom.xml +++ b/extras/bundles/grizzly-httpservice-bundle/pom.xml @@ -20,13 +20,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 jar Grizzly OSGi HttpService Bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 org.glassfish.grizzly.osgi grizzly-httpservice-bundle diff --git a/extras/bundles/pom.xml b/extras/bundles/pom.xml index f204356543..05d66f30fe 100644 --- a/extras/bundles/pom.xml +++ b/extras/bundles/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-extra-bundles pom - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-extra-bundles diff --git a/extras/connection-pool/pom.xml b/extras/connection-pool/pom.xml index 2b391b8dc4..b4b3334b8e 100644 --- a/extras/connection-pool/pom.xml +++ b/extras/connection-pool/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 connection-pool bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 connection-pool install diff --git a/extras/grizzly-httpservice/pom.xml b/extras/grizzly-httpservice/pom.xml index 08855da78d..aeb7d32cc4 100644 --- a/extras/grizzly-httpservice/pom.xml +++ b/extras/grizzly-httpservice/pom.xml @@ -20,14 +20,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 jar Grizzly OSGi HttpService - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 org.glassfish.grizzly.osgi grizzly-httpservice diff --git a/extras/http-server-jaxws/pom.xml b/extras/http-server-jaxws/pom.xml index 3f3a3ee99c..343e647304 100644 --- a/extras/http-server-jaxws/pom.xml +++ b/extras/http-server-jaxws/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-http-server-jaxws bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-server-jaxws install diff --git a/extras/http-server-multipart/pom.xml b/extras/http-server-multipart/pom.xml index c5544183d3..1c5479869e 100644 --- a/extras/http-server-multipart/pom.xml +++ b/extras/http-server-multipart/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-http-server-multipart bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-server-multipart install diff --git a/extras/http-servlet-extras/pom.xml b/extras/http-servlet-extras/pom.xml index 6674bbbf0b..fb455cfd0f 100644 --- a/extras/http-servlet-extras/pom.xml +++ b/extras/http-servlet-extras/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-http-servlet-extras bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-servlet-extras install diff --git a/extras/pom.xml b/extras/pom.xml index e85560d12b..68a730b149 100644 --- a/extras/pom.xml +++ b/extras/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../pom.xml 4.0.0 grizzly-extras pom - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-extras diff --git a/extras/tls-sni/pom.xml b/extras/tls-sni/pom.xml index 1d6898dac7..049fe72200 100644 --- a/extras/tls-sni/pom.xml +++ b/extras/tls-sni/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 tls-sni bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 tls-sni install diff --git a/modules/bundles/comet/pom.xml b/modules/bundles/comet/pom.xml index 0a41198a25..275ab7c339 100644 --- a/modules/bundles/comet/pom.xml +++ b/modules/bundles/comet/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 grizzly-comet-server jar - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-comet-server install diff --git a/modules/bundles/core/pom.xml b/modules/bundles/core/pom.xml index b792ca0f1a..7a2591cdc4 100644 --- a/modules/bundles/core/pom.xml +++ b/modules/bundles/core/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 grizzly-core jar - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-core install diff --git a/modules/bundles/http-all/pom.xml b/modules/bundles/http-all/pom.xml index 3369b603c3..c50fe8f9b6 100644 --- a/modules/bundles/http-all/pom.xml +++ b/modules/bundles/http-all/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 grizzly-http-all jar - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-all install diff --git a/modules/bundles/http-servlet/pom.xml b/modules/bundles/http-servlet/pom.xml index 884f08eba1..7db8d0ef2d 100755 --- a/modules/bundles/http-servlet/pom.xml +++ b/modules/bundles/http-servlet/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 grizzly-http-servlet-server jar - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-servlet-server install diff --git a/modules/bundles/http/pom.xml b/modules/bundles/http/pom.xml index aaa51da586..5544e1e6e1 100755 --- a/modules/bundles/http/pom.xml +++ b/modules/bundles/http/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 grizzly-http-server-core jar - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-server-core install @@ -171,7 +171,7 @@ org.glassfish.grizzly grizzly-npn-api - ${grizzly.alpn.version} + ${grizzly.npn.api.version} org.glassfish.grizzly diff --git a/modules/bundles/pom.xml b/modules/bundles/pom.xml index 3fb5bddcc3..789f323b80 100644 --- a/modules/bundles/pom.xml +++ b/modules/bundles/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-bundles pom - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-bundles diff --git a/modules/bundles/websockets/pom.xml b/modules/bundles/websockets/pom.xml index 4a58056a59..f7f550532c 100644 --- a/modules/bundles/websockets/pom.xml +++ b/modules/bundles/websockets/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 grizzly-websockets-server jar - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-websockets-server install diff --git a/modules/comet/pom.xml b/modules/comet/pom.xml index 39c67ff779..91aad8fefa 100644 --- a/modules/comet/pom.xml +++ b/modules/comet/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-comet bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-comet install diff --git a/modules/grizzly/pom.xml b/modules/grizzly/pom.xml index aba3318396..bda79af58d 100644 --- a/modules/grizzly/pom.xml +++ b/modules/grizzly/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-framework bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-framework install diff --git a/modules/grizzly/src/main/java/org/glassfish/grizzly/filterchain/DefaultFilterChain.java b/modules/grizzly/src/main/java/org/glassfish/grizzly/filterchain/DefaultFilterChain.java index 82cb59ae1f..53828ec39c 100644 --- a/modules/grizzly/src/main/java/org/glassfish/grizzly/filterchain/DefaultFilterChain.java +++ b/modules/grizzly/src/main/java/org/glassfish/grizzly/filterchain/DefaultFilterChain.java @@ -253,14 +253,14 @@ protected NextAction executeFilter(final FilterExecutor executor, NextAction nextNextAction; do { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINE, "Execute filter. filter={0} context={1}", + LOGGER.log(Level.FINE, "before filter execution. filter={0} context={1}", new Object[]{currentFilter, ctx}); } // execute the task nextNextAction = executor.execute(currentFilter, ctx); if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINE, "after execute filter. filter={0} context={1} nextAction={2}", + LOGGER.log(Level.FINE, "after filter execution. filter={0} context={1} nextAction={2}", new Object[]{currentFilter, ctx, nextNextAction}); } } while (nextNextAction.type() == RerunFilterAction.TYPE); diff --git a/modules/grizzly/src/main/java/org/glassfish/grizzly/ssl/HandshakeListener.java b/modules/grizzly/src/main/java/org/glassfish/grizzly/ssl/HandshakeListener.java deleted file mode 100644 index e9d296d26c..0000000000 --- a/modules/grizzly/src/main/java/org/glassfish/grizzly/ssl/HandshakeListener.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.glassfish.grizzly.ssl; - -import javax.net.ssl.SSLEngine; - -import org.glassfish.grizzly.Connection; - -public interface HandshakeListener { - void onInit(Connection connection, SSLEngine sslEngine); - void onStart(Connection connection); - void onComplete(Connection connection); - void onFailure(Connection connection, Throwable t); -} \ No newline at end of file diff --git a/modules/grizzly/src/main/java/org/glassfish/grizzly/ssl/SSLBaseFilter.java b/modules/grizzly/src/main/java/org/glassfish/grizzly/ssl/SSLBaseFilter.java index 0267b9e14b..04752020a8 100644 --- a/modules/grizzly/src/main/java/org/glassfish/grizzly/ssl/SSLBaseFilter.java +++ b/modules/grizzly/src/main/java/org/glassfish/grizzly/ssl/SSLBaseFilter.java @@ -365,11 +365,9 @@ public NextAction handleWrite(final FilterChainContext ctx) throws IOException { //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized(connection) { - final Buffer output = - wrapAll(ctx, obtainSslConnectionContext(connection)); + final Buffer output = wrapAll(ctx, obtainSslConnectionContext(connection)); - final TransportContext transportContext = - ctx.getTransportContext(); + final TransportContext transportContext = ctx.getTransportContext(); ctx.write(null, output, transportContext.getCompletionHandler(), @@ -909,20 +907,18 @@ public void run() { } } - protected SSLConnectionContext obtainSslConnectionContext( - final Connection connection) { + protected SSLConnectionContext obtainSslConnectionContext( final Connection connection) { SSLConnectionContext sslCtx = SSL_CTX_ATTR.get(connection); if (sslCtx == null) { sslCtx = createSslConnectionContext(connection); SSL_CTX_ATTR.set(connection, sslCtx); } - + return sslCtx; } - + @SuppressWarnings("MethodMayBeStatic") - protected SSLConnectionContext createSslConnectionContext( - final Connection connection) { + protected SSLConnectionContext createSslConnectionContext( final Connection connection) { return new SSLConnectionContext(connection); } @@ -981,9 +977,7 @@ private static Certificate[] getPeerCertificates(final SSLConnectionContext sslC try { return sslCtx.getSslEngine().getSession().getPeerCertificates(); } catch( Throwable t ) { - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE,"Error getting client certs", t); - } + LOGGER.log(Level.FINE,"Error getting client certs", t); return null; } } @@ -1208,4 +1202,15 @@ public Buffer clone(final Connection connection, return originalMessage; } } + + + // don't move to own file, Tyrus has a dependency on this interface + public interface HandshakeListener { + default void onInit(Connection connection, SSLEngine sslEngine) { + // nothing + } + void onStart(Connection connection); + void onComplete(Connection connection); + void onFailure(Connection connection, Throwable t); + } } diff --git a/modules/http-ajp/pom.xml b/modules/http-ajp/pom.xml index 2c6181a05c..0d10cf462c 100755 --- a/modules/http-ajp/pom.xml +++ b/modules/http-ajp/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-http-ajp bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-ajp https://projects.eclipse.org/projects/ee4j.grizzly diff --git a/modules/http-server/pom.xml b/modules/http-server/pom.xml index fd288498e6..56ad30a217 100644 --- a/modules/http-server/pom.xml +++ b/modules/http-server/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-http-server bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-server install diff --git a/modules/http-servlet/pom.xml b/modules/http-servlet/pom.xml index 64e7c545a9..adb85e5df0 100755 --- a/modules/http-servlet/pom.xml +++ b/modules/http-servlet/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-http-servlet bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-servlet install diff --git a/modules/http/pom.xml b/modules/http/pom.xml index 01afd55627..9f443f2d87 100644 --- a/modules/http/pom.xml +++ b/modules/http/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-http bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http install diff --git a/modules/http/src/main/java/org/glassfish/grizzly/http/HttpContent.java b/modules/http/src/main/java/org/glassfish/grizzly/http/HttpContent.java index dab209a6ea..5e930df3dd 100644 --- a/modules/http/src/main/java/org/glassfish/grizzly/http/HttpContent.java +++ b/modules/http/src/main/java/org/glassfish/grizzly/http/HttpContent.java @@ -36,7 +36,7 @@ */ public class HttpContent extends HttpPacket implements org.glassfish.grizzly.Appendable { - + private static final ThreadCache.CachedTypeIndex CACHE_IDX = ThreadCache.obtainIndex(HttpContent.class, 16); @@ -72,27 +72,25 @@ public static HttpContent create(final HttpHeader httpHeader, final boolean isLast) { return create(httpHeader, isLast, Buffers.EMPTY_BUFFER); } - + public static HttpContent create(final HttpHeader httpHeader, final boolean isLast, Buffer content) { content = content != null ? content : Buffers.EMPTY_BUFFER; - - final HttpContent httpContent = - ThreadCache.takeFromCache(CACHE_IDX); + final HttpContent httpContent = ThreadCache.takeFromCache(CACHE_IDX); if (httpContent != null) { httpContent.httpHeader = httpHeader; httpContent.isLast = isLast; httpContent.content = content; - + return httpContent; } return new HttpContent(httpHeader, isLast, content); } - + /** * Returns {@link HttpContent} builder. - * + * * @param httpHeader related HTTP message header * @return {@link Builder}. */ @@ -101,7 +99,7 @@ public static Builder builder(final HttpHeader httpHeader) { } protected boolean isLast; - + protected Buffer content = Buffers.EMPTY_BUFFER; protected HttpHeader httpHeader; @@ -120,7 +118,7 @@ protected HttpContent(final HttpHeader httpHeader, final boolean isLast, this.isLast = isLast; this.content = content; } - + /** * Get the HTTP message content {@link Buffer}. * @@ -147,7 +145,7 @@ public final HttpHeader getHttpHeader() { /** * Return true, if the current content chunk is last, * or false, if there are content chunks to follow. - * + * * @return true, if the current content chunk is last, * or false, if there are content chunks to follow. */ @@ -176,7 +174,7 @@ public HttpContent append(final HttpContent element) { if (isBroken(element)) { return element; } - + final Buffer content2 = element.getContent(); if (content2 != null && content2.hasRemaining()) { content = Buffers.appendBuffers(null, content, content2); @@ -244,7 +242,7 @@ public final T last(boolean last) { this.last = last; return (T) this; } - + /** * Set the HttpContent chunk content {@link Buffer}. * diff --git a/modules/http/src/main/java/org/glassfish/grizzly/http/HttpTrailer.java b/modules/http/src/main/java/org/glassfish/grizzly/http/HttpTrailer.java index cdcc089ccf..5cec0f863d 100644 --- a/modules/http/src/main/java/org/glassfish/grizzly/http/HttpTrailer.java +++ b/modules/http/src/main/java/org/glassfish/grizzly/http/HttpTrailer.java @@ -36,7 +36,7 @@ public class HttpTrailer extends HttpContent implements MimeHeadersPacket { * @return true if passed {@link HttpContent} is a HttpTrailder. */ public static boolean isTrailer(HttpContent httpContent) { - return HttpTrailer.class.isAssignableFrom(httpContent.getClass()); + return httpContent != null && HttpTrailer.class.isAssignableFrom(httpContent.getClass()); } public static HttpTrailer create() { diff --git a/modules/http2/pom.xml b/modules/http2/pom.xml index d27ec0ec89..39ee242750 100644 --- a/modules/http2/pom.xml +++ b/modules/http2/pom.xml @@ -21,14 +21,16 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-http2 - 2.4.4.payara-p4-SNAPSHOT grizzly-http2 + + + install @@ -83,9 +85,7 @@ maven-surefire-plugin - - -XX:+HeapDumpOnOutOfMemoryError -Xbootclasspath/p:${settings.localRepository}/org/glassfish/grizzly/grizzly-npn-bootstrap/1.8/grizzly-npn-bootstrap-1.8.jar - + -XX:+HeapDumpOnOutOfMemoryError ${bootClasspath} @@ -118,7 +118,7 @@ org.glassfish.grizzly grizzly-npn-api - ${grizzly.alpn.version} + ${grizzly.npn.api.version} provided @@ -128,6 +128,36 @@ 2.18.3 test - + + + + openjsse + + -Xbootclasspath/p:${settings.localRepository}/org/openjsse/openjsse/${openjsse.version}/openjsse-${openjsse.version}.jar + + + + org.openjsse + openjsse + ${openjsse.version} + provided + + + + + npn + + -Xbootclasspath/p:${settings.localRepository}/org/glassfish/grizzly/grizzly-npn-bootstrap/${grizzly.npn.bootstrap.version}/grizzly-npn-bootstrap-${grizzly.npn.bootstrap.version}.jar + + + + org.glassfish.grizzly + grizzly-npn-bootstrap + ${grizzly.npn.bootstrap.version} + provided + + + + diff --git a/modules/http2/src/main/java/org/glassfish/grizzly/http2/AlpnSupport.java b/modules/http2/src/main/java/org/glassfish/grizzly/http2/AlpnSupport.java index 36862b4986..2752e62bdf 100644 --- a/modules/http2/src/main/java/org/glassfish/grizzly/http2/AlpnSupport.java +++ b/modules/http2/src/main/java/org/glassfish/grizzly/http2/AlpnSupport.java @@ -22,7 +22,6 @@ import java.util.WeakHashMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.BiFunction; import java.util.logging.Level; import java.util.logging.Logger; @@ -37,43 +36,24 @@ import org.glassfish.grizzly.npn.AlpnClientNegotiator; import org.glassfish.grizzly.npn.AlpnServerNegotiator; import org.glassfish.grizzly.npn.NegotiationSupport; -import org.glassfish.grizzly.ssl.HandshakeListener; import org.glassfish.grizzly.ssl.SSLBaseFilter; +import org.glassfish.grizzly.ssl.SSLBaseFilter.HandshakeListener; import org.glassfish.grizzly.ssl.SSLUtils; /** * Grizzly TLS Next Protocol Negotiation support class. - * */ public class AlpnSupport { - private final static Logger LOGGER = Grizzly.logger(AlpnSupport.class); + private static final Logger LOGGER = Grizzly.logger(AlpnSupport.class); - private final static Map> SSL_TO_CONNECTION_MAP = - new WeakHashMap<>(); - + private static final Map> SSL_TO_CONNECTION_MAP = new WeakHashMap<>(); private static final AlpnSupport INSTANCE; - private static final Method nativeHandshakeMethod; - - static { - boolean isExtensionFound = false; - Method setHandshakeAlpnSelector = null; - - try { - setHandshakeAlpnSelector = SSLEngine.class.getMethod("setHandshakeApplicationProtocolSelector", BiFunction.class); - } catch (Exception e) { - try { - ClassLoader.getSystemClassLoader().loadClass("sun.security.ssl.GrizzlyNPN"); - isExtensionFound = true; - } catch (Exception e2) { - LOGGER.log(Level.FINE, "Native ALPN is not found:", e); - LOGGER.log(Level.FINE, "TLS ALPN extension is not found:", e2); - } - } + private static final AplnExtensionCompatibility COMPATIBILITY; - nativeHandshakeMethod = setHandshakeAlpnSelector; - INSTANCE = isExtensionFound - || nativeHandshakeMethod != null - ? new AlpnSupport() : null; + static { + COMPATIBILITY = AplnExtensionCompatibility.getInstance(); + LOGGER.config(() -> "Detected ALPN compatibility info: " + COMPATIBILITY); + INSTANCE = COMPATIBILITY.isAlpnExtensionAvailable() ? new AlpnSupport() : null; } public static boolean isEnabled() { @@ -84,7 +64,6 @@ public static AlpnSupport getInstance() { if (!isEnabled()) { throw new IllegalStateException("TLS ALPN is disabled"); } - return INSTANCE; } @@ -93,39 +72,42 @@ public static Connection getConnection(final SSLEngine engine) { return SSL_TO_CONNECTION_MAP.get(engine); } } - - private static void setConnection(final SSLEngine engine, - final Connection connection) { + + private static void setConnection(final SSLEngine engine, final Connection connection) { synchronized (SSL_TO_CONNECTION_MAP) { SSL_TO_CONNECTION_MAP.put(engine, connection); } } - private final Map serverSideNegotiators = - new WeakHashMap<>(); + private final Map serverSideNegotiators = new WeakHashMap<>(); private final ReadWriteLock serverSideLock = new ReentrantReadWriteLock(); - - private final Map clientSideNegotiators = - new WeakHashMap<>(); + + private final Map clientSideNegotiators = new WeakHashMap<>(); private final ReadWriteLock clientSideLock = new ReentrantReadWriteLock(); - private final HandshakeListener handshakeListener = - new HandshakeListener() { + private final HandshakeListener handshakeListener = new HandshakeListener() { @Override public void onInit(final Connection connection, final SSLEngine sslEngine) { assert sslEngine != null; - - AlpnServerNegotiator negotiator = getServerNegotiator(connection); - - if (negotiator != null && nativeHandshakeMethod != null) { - // Code only works for JDK9+ - // sslEngine.setHandshakeApplicationProtocolSelector(negotiator); - try { - nativeHandshakeMethod.invoke(sslEngine, negotiator); - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Couldn't execute sslEngine.setHandshakeApplicationProtocolSelector", ex); - } + if (sslEngine.getUseClientMode()) { + // makes sense only for the server + return; + } + if (!COMPATIBILITY.isProtocolSelectorSetterInImpl()) { + // even when the api implements it, impl doesn't + return; + } + final AlpnServerNegotiator negotiator = getServerNegotiator(connection); + if (negotiator == null) { + return; + } + // Older JDK8 versions are missing this method in API, that's why we do this. + final Method setter = COMPATIBILITY.getProtocolSelectorSetter(sslEngine); + try { + setter.invoke(sslEngine, negotiator); + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Couldn't execute " + setter, ex); } } @@ -133,10 +115,9 @@ public void onInit(final Connection connection, final SSLEngine sslEngine) { public void onStart(final Connection connection) { final SSLEngine sslEngine = SSLUtils.getSSLEngine(connection); assert sslEngine != null; - + if (sslEngine.getUseClientMode()) { AlpnClientNegotiator negotiator = getClientNegotiator(connection); - if (negotiator != null) { // add a CloseListener to ensure we remove the // negotiator associated with this SSLEngine @@ -152,9 +133,7 @@ public void onClosed(Closeable closeable, CloseType type) throws IOException { } } else { AlpnServerNegotiator negotiator = getServerNegotiator(connection); - if (negotiator != null) { - // add a CloseListener to ensure we remove the // negotiator associated with this SSLEngine connection.addCloseListener(new CloseListener() { @@ -168,7 +147,7 @@ public void onClosed(Closeable closeable, CloseType type) throws IOException { NegotiationSupport.addNegotiator(sslEngine, negotiator); } } - + } @Override @@ -179,39 +158,33 @@ public void onComplete(final Connection connection) { public void onFailure(Connection connection, Throwable t) { } }; - + private AlpnSupport() { - } - + } + public void configure(final SSLBaseFilter sslFilter) { sslFilter.addHandshakeListener(handshakeListener); } - - public void setServerSideNegotiator(final Transport transport, - final AlpnServerNegotiator negotiator) { + + public void setServerSideNegotiator(final Transport transport, final AlpnServerNegotiator negotiator) { putServerSideNegotiator(transport, negotiator); } - - public void setServerSideNegotiator(final Connection connection, - final AlpnServerNegotiator negotiator) { + + public void setServerSideNegotiator(final Connection connection, final AlpnServerNegotiator negotiator) { putServerSideNegotiator(connection, negotiator); } - - public void setClientSideNegotiator(final Transport transport, - final AlpnClientNegotiator negotiator) { + + public void setClientSideNegotiator(final Transport transport, final AlpnClientNegotiator negotiator) { putClientSideNegotiator(transport, negotiator); } - public void setClientSideNegotiator(final Connection connection, - final AlpnClientNegotiator negotiator) { + public void setClientSideNegotiator(final Connection connection, final AlpnClientNegotiator negotiator) { putClientSideNegotiator(connection, negotiator); } - private void putServerSideNegotiator(final Object object, - final AlpnServerNegotiator negotiator) { + private void putServerSideNegotiator(final Object object, final AlpnServerNegotiator negotiator) { serverSideLock.writeLock().lock(); - try { serverSideNegotiators.put(object, negotiator); } finally { @@ -219,8 +192,7 @@ private void putServerSideNegotiator(final Object object, } } - private void putClientSideNegotiator(final Object object, - final AlpnClientNegotiator negotiator) { + private void putClientSideNegotiator(final Object object, final AlpnClientNegotiator negotiator) { clientSideLock.writeLock().lock(); try { @@ -229,12 +201,11 @@ private void putClientSideNegotiator(final Object object, clientSideLock.writeLock().unlock(); } } - + private AlpnClientNegotiator getClientNegotiator(Connection connection) { AlpnClientNegotiator negotiator; clientSideLock.readLock().lock(); - try { negotiator = clientSideNegotiators.get(connection); if (negotiator == null) { @@ -250,7 +221,6 @@ private AlpnClientNegotiator getClientNegotiator(Connection connection) { private AlpnServerNegotiator getServerNegotiator(Connection connection) { AlpnServerNegotiator negotiator; serverSideLock.readLock().lock(); - try { negotiator = serverSideNegotiators.get(connection); if (negotiator == null) { diff --git a/modules/http2/src/main/java/org/glassfish/grizzly/http2/AplnExtensionCompatibility.java b/modules/http2/src/main/java/org/glassfish/grizzly/http2/AplnExtensionCompatibility.java new file mode 100644 index 0000000000..8becb07696 --- /dev/null +++ b/modules/http2/src/main/java/org/glassfish/grizzly/http2/AplnExtensionCompatibility.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2012, 2017 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.grizzly.http2; + +import java.lang.reflect.Method; +import java.util.Objects; +import java.util.function.BiFunction; +import java.util.logging.Logger; + +import javax.net.ssl.SSLEngine; + +class AplnExtensionCompatibility { + private static final Logger LOG = Logger.getLogger(AplnExtensionCompatibility.class.getName()); + + private static final String IMPL_CLASS_NAME = "sun.security.ssl.SSLEngineImpl"; + private static final String METHOD_NAME = "setHandshakeApplicationProtocolSelector"; + + private static AplnExtensionCompatibility INSTANCE; + + private final boolean alpnExtensionGrizzly; + private final boolean protocolSelectorSetterInApi; + private final boolean protocolSelectorSetterInImpl; + + public static synchronized AplnExtensionCompatibility getInstance() { + if (INSTANCE == null) { + INSTANCE = new AplnExtensionCompatibility(); + } + return INSTANCE; + } + + + public boolean isAlpnExtensionAvailable() { + return isAlpnExtensionGrizzly() || isProtocolSelectorSetterInApi() || isProtocolSelectorSetterInImpl(); + } + + + public boolean isAlpnExtensionGrizzly() { + return alpnExtensionGrizzly; + } + + + public boolean isProtocolSelectorSetterInApi() { + return protocolSelectorSetterInApi; + } + + + public boolean isProtocolSelectorSetterInImpl() { + return protocolSelectorSetterInImpl; + } + + + public Method getProtocolSelectorSetter(final SSLEngine engine) { + Objects.requireNonNull(engine, "engine"); + try { + // newer JSSE versions implement this method. + // some JDK8 versions (Zulu 8u265) don't see the method as public on impl + final Class engineClass; + if (isHandshakeSetterInApi()) { + engineClass = SSLEngine.class; + } else { + engineClass = engine.getClass(); + } + return engineClass.getMethod(METHOD_NAME, BiFunction.class); + } catch (final NoSuchMethodException e) { + throw new IllegalArgumentException("The method public void setHandshakeApplicationProtocolSelector(" + + "BiFunction, String> selector) is not declared by" + + " the " + engine.getClass().getName() + ".", e); + } + } + + + private AplnExtensionCompatibility() { + this.alpnExtensionGrizzly = isClassAvailableOnBootstrapClasspath("sun.security.ssl.GrizzlyNPN"); + this.protocolSelectorSetterInApi = isHandshakeSetterInApi(); + this.protocolSelectorSetterInImpl = isHandshakeSetterInImpl(); + } + + + private static boolean isClassAvailableOnBootstrapClasspath(final String className) { + try { + ClassLoader.getSystemClassLoader().loadClass(className); + return true; + } catch (final ClassNotFoundException e) { + LOG.config("The class with the name '" + className + "' is not available on the bootstrap classpath."); + return false; + } + } + + + private static boolean isHandshakeSetterInImpl() { + try { + Class.forName(IMPL_CLASS_NAME).getMethod(METHOD_NAME, BiFunction.class); + return true; + } catch (final IllegalAccessError e) { + LOG.config(() -> "The class " + IMPL_CLASS_NAME + " is not accessible."); + return false; + } catch (final ClassNotFoundException | NoClassDefFoundError e) { + LOG.config(() -> "The class " + IMPL_CLASS_NAME + " cloud not be found."); + return false; + } catch (final NoSuchMethodException e) { + LOG.config(() -> "The method public void setHandshakeApplicationProtocolSelector(" + + "BiFunction, String> selector) is not declared by" + + " the " + IMPL_CLASS_NAME + " class."); + return false; + } + } + + + private static boolean isHandshakeSetterInApi() { + try { + // new grizzly bootstrap versions implement this method. + SSLEngine.class.getMethod(METHOD_NAME, BiFunction.class); + return true; + } catch (final NoSuchMethodException e) { + LOG.config("The method public void setHandshakeApplicationProtocolSelector(" + + "BiFunction, String> selector) is not declared by" + + " the " + SSLEngine.class.getName() + "."); + return false; + } + } + + + @Override + public String toString() { + return super.toString() + "ALPN available: " + isAlpnExtensionAvailable() + + ", ALPN is Grizzly: " + isAlpnExtensionGrizzly() + + ", setHandshakeApplicationProtocolSelector in API: " + isProtocolSelectorSetterInApi() + + ", setHandshakeApplicationProtocolSelector in impl: " + isProtocolSelectorSetterInImpl(); + } +} diff --git a/modules/http2/src/main/java/org/glassfish/grizzly/http2/DefaultOutputSink.java b/modules/http2/src/main/java/org/glassfish/grizzly/http2/DefaultOutputSink.java index 7fe34e9a80..cbae273551 100644 --- a/modules/http2/src/main/java/org/glassfish/grizzly/http2/DefaultOutputSink.java +++ b/modules/http2/src/main/java/org/glassfish/grizzly/http2/DefaultOutputSink.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Logger; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.CompletionHandler; @@ -54,24 +53,24 @@ /** * Default implementation of an output sink, which is associated * with specific {@link Http2Stream}. - * + * * The implementation is aligned with HTTP/2 requirements with regards to message * flow control. - * + * * @author Alexey Stashok */ class DefaultOutputSink implements StreamOutputSink { - private static final Logger LOGGER = Grizzly.logger(StreamOutputSink.class); + private static final Logger LOGGER = Grizzly.logger(DefaultOutputSink.class); private static final int MAX_OUTPUT_QUEUE_SIZE = 65536; private static final int ZERO_QUEUE_RECORD_SIZE = 1; - + private static final OutputQueueRecord TERMINATING_QUEUE_RECORD = new OutputQueueRecord(null, null, true, true); - + // async output queue - final TaskQueue outputQueue = + private final TaskQueue outputQueue = TaskQueue.createTaskQueue(new TaskQueue.MutableMaxQueueSize() { @Override @@ -79,7 +78,7 @@ public int getMaxQueueSize() { return MAX_OUTPUT_QUEUE_SIZE; } }); - + // the space (in bytes) in flow control window, that still could be used. // in other words the number of bytes, which could be sent to the peer private final AtomicInteger availStreamWindowSize; @@ -88,7 +87,7 @@ public int getMaxQueueSize() { private volatile boolean isLastFrameQueued; // not null if last output frame has been sent or forcibly terminated private Termination terminationFlag; - + // associated HTTP/2 session private final Http2Session http2Session; // associated HTTP/2 stream @@ -100,7 +99,7 @@ public int getMaxQueueSize() { private final Object flushHandlersSync = new Object(); // flush handlers queue private BundleQueue> flushHandlersQueue; - + DefaultOutputSink(final Http2Stream stream) { this.stream = stream; http2Session = stream.getHttp2Session(); @@ -131,7 +130,7 @@ private void assertReady() throws IOException { /** * The method is called by HTTP2 Filter once WINDOW_UPDATE message comes * for this {@link Http2Stream}. - * + * * @param delta the delta. * @throws Http2StreamException if an error occurs processing the window update. */ @@ -150,7 +149,7 @@ public void onPeerWindowUpdate(final int delta) throws Http2StreamException { // try to write until window limit allows while ((isWantToWrite() && !outputQueue.isEmpty()) || (outputQueue.peek() != null && outputQueue.peek().trailer != null)) { - + // pick up the first output record in the queue OutputQueueRecord outputQueueRecord = outputQueue.poll(); @@ -158,7 +157,7 @@ public void onPeerWindowUpdate(final int delta) throws Http2StreamException { if (outputQueueRecord == null) { return; } - + // if it's terminating record - processFin if (outputQueueRecord == TERMINATING_QUEUE_RECORD) { // if it's TERMINATING_QUEUE_RECORD - don't forget to release ATOMIC_QUEUE_RECORD_SIZE @@ -166,38 +165,31 @@ public void onPeerWindowUpdate(final int delta) throws Http2StreamException { writeEmptyFin(); return; } - - final FlushCompletionHandler completionHandler = - outputQueueRecord.chunkedCompletionHandler; + + final FlushCompletionHandler completionHandler = outputQueueRecord.chunkedCompletionHandler; boolean isLast = outputQueueRecord.isLast; final boolean isZeroSizeData = outputQueueRecord.isZeroSizeData; final Source resource = outputQueueRecord.resource; final HttpTrailer currentTrailer = outputQueueRecord.trailer; - final MessageCloner messageCloner = outputQueueRecord.cloner; - if (currentTrailer != null) { - try { - outputQueueRecord = null; - sendTrailers(completionHandler, messageCloner, currentTrailer); - } catch (IOException ex) { - LOGGER.log(WARNING, "Error sending trailers.", ex); - } + outputQueueRecord = null; + sendTrailers(completionHandler, currentTrailer); return; } - + // check if output record's buffer is fitting into window size // if not - split it into 2 parts: part to send, part to keep in the queue final int bytesToSend = checkOutputWindow(resource.remaining()); final Buffer dataChunkToSend = resource.read(bytesToSend); final boolean hasRemaining = resource.hasRemaining(); - + // if there is a chunk to store if (hasRemaining) { // Create output record for the chunk to be stored outputQueueRecord.reset(resource, completionHandler, isLast); outputQueueRecord.incChunksCounter(); - + // reset isLast for the current chunk isLast = false; } else { @@ -206,26 +198,23 @@ public void onPeerWindowUpdate(final int delta) throws Http2StreamException { } // if there is a chunk to sent - if (dataChunkToSend != null && - (dataChunkToSend.hasRemaining() || isLast)) { + if (dataChunkToSend != null && (dataChunkToSend.hasRemaining() || isLast)) { final int dataChunkToSendSize = dataChunkToSend.remaining(); - + // send a http2 data frame - flushToConnectionOutputSink(null, dataChunkToSend, completionHandler, - null, isLast); - + flushToConnectionOutputSink(dataChunkToSend, completionHandler, isLast); + // update the available window size bytes counter availStreamWindowSize.addAndGet(-dataChunkToSendSize); - releaseWriteQueueSpace(dataChunkToSendSize, - isZeroSizeData, outputQueueRecord == null); - + releaseWriteQueueSpace(dataChunkToSendSize, isZeroSizeData, outputQueueRecord == null); + outputQueue.doNotify(); } else if (isZeroSizeData && outputQueueRecord == null) { // if it's atomic and no remainder left - don't forget to release ATOMIC_QUEUE_RECORD_SIZE releaseWriteQueueSpace(0, true, true); outputQueue.doNotify(); } - + if (outputQueueRecord != null) { // if there is a chunk to be stored - store it and return outputQueue.setCurrentElement(outputQueueRecord); @@ -233,12 +222,11 @@ public void onPeerWindowUpdate(final int delta) throws Http2StreamException { } } } - /** * Send an {@link HttpPacket} to the {@link Http2Stream}. - * + * * The writeDownStream(...) methods have to be synchronized with shutdown(). - * + * * @param httpPacket {@link HttpPacket} to send * @param completionHandler the {@link CompletionHandler}, * which will be notified about write progress. @@ -247,40 +235,49 @@ public void onPeerWindowUpdate(final int delta) throws Http2StreamException { * current thread. * @throws IOException if an error occurs with the write operation. */ - @SuppressWarnings("ConstantConditions") @Override public synchronized void writeDownStream(final HttpPacket httpPacket, - final FilterChainContext ctx, - final CompletionHandler completionHandler, - final MessageCloner messageCloner) - throws IOException { - assert ctx != null; + final FilterChainContext ctx, + final CompletionHandler completionHandler, + final MessageCloner messageCloner) throws IOException { + assert ctx != null; assertReady(); - + final OutputQueueRecord next = writeDownStream0(httpPacket, ctx, completionHandler, messageCloner); + if (next != null) { + addOutputQueueRecord(next); + } + } + + + private OutputQueueRecord writeDownStream0(final HttpPacket httpPacket, + final FilterChainContext ctx, + final CompletionHandler completionHandler, + final MessageCloner messageCloner) + throws IOException { + final HttpHeader httpHeader = stream.getOutputHttpHeader(); final HttpContent httpContent = HttpContent.isContent(httpPacket) ? (HttpContent) httpPacket : null; - List headerFrames = null; - OutputQueueRecord outputQueueRecord = null; - - final ReentrantLock deflatorLock = http2Session.getDeflaterLock(); + boolean sendTrailers = false; + boolean lockedByMe = false; + try { + // try-finally block to release deflater lock if needed + boolean isLast = httpContent != null && httpContent.isLast(); + final boolean isTrailer = HttpTrailer.isTrailer(httpContent); - try { // try-finally block to release deflater lock if needed - // If HTTP header hasn't been committed - commit it if (!httpHeader.isCommitted()) { - // do we expect any HTTP payload? - final boolean isNoPayload = !httpHeader.isExpectContent() || - (httpContent != null && httpContent.isLast() && - !httpContent.getContent().hasRemaining()); - - // !!!!! LOCK the deflater - deflatorLock.lock(); + final boolean dontSendPayload = !httpHeader.isExpectContent() + || (httpContent != null && httpContent.isLast() && !httpContent.getContent().hasRemaining()); + LOGGER.finest(() -> "Header not committed yet; dontSendPayload=" + dontSendPayload); + + http2Session.getDeflaterLock().lock(); + lockedByMe = true; final boolean logging = NetLogger.isActive(); final Map capture = ((logging) ? new HashMap<>() : null); headerFrames = http2Session.encodeHttpHeaderAsHeaderFrames( - ctx, httpHeader, stream.getId(), isNoPayload, null, capture); + ctx, httpHeader, stream.getId(), dontSendPayload, null, capture); if (logging) { for (Http2Frame http2Frame : headerFrames) { if (http2Frame.getType() == PushPromiseFrame.TYPE) { @@ -289,7 +286,7 @@ public synchronized void writeDownStream(final HttpPacket httpPacket, } } } - stream.onSndHeaders(isNoPayload); + stream.onSndHeaders(dontSendPayload); // 100-Continue block if (!httpHeader.isRequest()) { @@ -298,84 +295,62 @@ public synchronized void writeDownStream(final HttpPacket httpPacket, response.acknowledged(); response.getHeaders().clear(); unflushedWritesCounter.incrementAndGet(); - flushToConnectionOutputSink(headerFrames, null, - new FlushCompletionHandler(completionHandler), - messageCloner, false); - return; + flushToConnectionOutputSink(headerFrames, completionHandler, messageCloner, false); + LOGGER.finest("Acknowledgement has been sent."); + return null; } } - + httpHeader.setCommitted(true); - if (isNoPayload || httpContent == null) { - // if we don't expect any HTTP payload, mark this frame as - // last and return + if (dontSendPayload || httpContent == null) { + // if we don't expect any HTTP payload, mark this frame as last and return unflushedWritesCounter.incrementAndGet(); - flushToConnectionOutputSink(headerFrames, null, - new FlushCompletionHandler(completionHandler), - messageCloner, isNoPayload); - return; + flushToConnectionOutputSink(headerFrames, completionHandler, messageCloner, dontSendPayload); + sendTrailers = false; // isLast && isTrailer; // FIXME: this causes data corruption! + LOGGER.finest(() -> "Nothing to send; dontSendPayload=" + dontSendPayload); + return null; } } - // if there is nothing to write - return if (httpContent == null) { - return; + sendTrailers = false; // isLast && isTrailer; // FIXME: this causes data corruption! + LOGGER.finest("Nothing to send, httpContent is null."); + return null; } - + http2Session.handlerFilter.onHttpContentEncoded(httpContent, ctx); - Buffer dataToSend = null; - boolean isLast = httpContent.isLast(); - final boolean isTrailer = HttpTrailer.isTrailer(httpContent); Buffer data = httpContent.getContent(); final int dataSize = data.remaining(); - unflushedWritesCounter.incrementAndGet(); - final FlushCompletionHandler flushCompletionHandler = - new FlushCompletionHandler(completionHandler); - - boolean isDataCloned = false; - + final FlushCompletionHandler flushCompletionHandler = new FlushCompletionHandler(completionHandler); final boolean isZeroSizeData = (dataSize == 0); final int spaceToReserve = isZeroSizeData ? ZERO_QUEUE_RECORD_SIZE : dataSize; + boolean isDataCloned = false; // Check if output queue is not empty - add new element - if (reserveWriteQueueSpace(spaceToReserve) > spaceToReserve) { + final int spaceReserved = reserveWriteQueueSpace(spaceToReserve); + LOGGER.finest(() -> "Bytes reserved: " + spaceReserved + ", was requested: " + spaceToReserve); + if (spaceReserved > spaceToReserve) { // if the queue is not empty - the headers should have been sent assert headerFrames == null; - if (messageCloner != null) { - data = messageCloner.clone( - http2Session.getConnection(), data); + data = messageCloner.clone(http2Session.getConnection(), data); isDataCloned = true; } - if (isTrailer) { - outputQueueRecord = new OutputQueueRecord( - Source.factory(stream) - .createBufferSource(data), - flushCompletionHandler, - (HttpTrailer) httpContent, - false); - } else { - outputQueueRecord = new OutputQueueRecord( - Source.factory(stream) - .createBufferSource(data), - flushCompletionHandler, isLast, isZeroSizeData); - } - - outputQueue.offer(outputQueueRecord); + final OutputQueueRecord record = createOutputQueueRecord(data, httpContent, flushCompletionHandler, + isLast, isZeroSizeData); + outputQueue.offer(record); // check if our element wasn't forgotten (async) - if (outputQueue.size() != spaceToReserve || - !outputQueue.remove(outputQueueRecord)) { - // if not - return - return; + if (outputQueue.size() != spaceToReserve || !outputQueue.remove(record)) { + sendTrailers = false; // isLast && isTrailer; // FIXME: this causes data corruption! + LOGGER.finest("Weird condition. FIXME... why are we removing what we added in previous if/else?"); + return null; } - - outputQueueRecord = null; } // our element is first in the output queue @@ -384,77 +359,78 @@ public synchronized void writeDownStream(final HttpPacket httpPacket, // check if output record's buffer is fitting into window size // if not - split it into 2 parts: part to send, part to keep in the queue final int fitWindowLen = checkOutputWindow(remaining); + LOGGER.finest(() -> "Remaining: " + remaining + ", fitWindowLen: " + fitWindowLen); - // if there is a chunk to store - if (fitWindowLen < remaining) { + final OutputQueueRecord outputQueueRecord; + if (fitWindowLen >= remaining) { + outputQueueRecord = null; + } else { + // if there is a chunk to store if (!isDataCloned && messageCloner != null) { - data = messageCloner.clone( - http2Session.getConnection(), data); + data = messageCloner.clone(http2Session.getConnection(), data); isDataCloned = true; } - final Buffer dataChunkToStore = splitOutputBufferIfNeeded( - data, fitWindowLen); + final Buffer dataChunkToStore = splitOutputBufferIfNeeded(data, fitWindowLen); // Create output record for the chunk to be stored - outputQueueRecord = new OutputQueueRecord( - Source.factory(stream) - .createBufferSource(dataChunkToStore), - flushCompletionHandler, - isLast, isZeroSizeData); + outputQueueRecord = createOutputQueueRecord(dataChunkToStore, null, flushCompletionHandler, isLast, + isZeroSizeData); // reset completion handler and isLast for the current chunk isLast = false; } - // if there is a chunk to send - if (data != null && - (data.hasRemaining() || isLast)) { - - final int dataChunkToSendSize = data.remaining(); - - // update the available window size bytes counter - availStreamWindowSize.addAndGet(-dataChunkToSendSize); - releaseWriteQueueSpace(dataChunkToSendSize, - isZeroSizeData, outputQueueRecord == null); - - dataToSend = data; - } - // if there's anything to send - send it + final Buffer dataToSend = prepareDataToSend(outputQueueRecord == null, isLast, data, isZeroSizeData); if (headerFrames != null || dataToSend != null) { - // if another part of data is stored in the queue - - // we have to increase CompletionHandler counter to avoid - // premature notification + // we have to increase CompletionHandler counter to avoid premature notification if (outputQueueRecord != null) { outputQueueRecord.incChunksCounter(); } - flushToConnectionOutputSink(headerFrames, dataToSend, flushCompletionHandler, - isDataCloned ? null : messageCloner, - isLast && !isTrailer); + isDataCloned ? null : messageCloner, isLast && !isTrailer); } - if (isLast) { - if (isTrailer) { - // !!!!! LOCK the deflater - sendTrailers(completionHandler, messageCloner, (HttpTrailer) httpContent); - } - return; - } - + LOGGER.finest("isLast=" + isLast + "; isTrailer=" + isTrailer); + sendTrailers = isLast && isTrailer; + return isLast ? null : outputQueueRecord; } finally { - if (deflatorLock.isHeldByCurrentThread()) { - deflatorLock.unlock(); + LOGGER.finest("sendTrailers=" + sendTrailers); + if (sendTrailers) { + sendTrailers(completionHandler, (HttpTrailer) httpContent); } + if (lockedByMe) { + http2Session.getDeflaterLock().unlock(); + } + } + } + + + private OutputQueueRecord createOutputQueueRecord(final Buffer data, final HttpContent httpContent, + final FlushCompletionHandler flushCompletionHandler, boolean isLast, final boolean isZeroSizeData) { + final Source bufferSource = Source.factory(stream).createBufferSource(data); + if (httpContent instanceof HttpTrailer) { + return new OutputQueueRecord(bufferSource, flushCompletionHandler, (HttpTrailer) httpContent, false); + } + return new OutputQueueRecord(bufferSource, flushCompletionHandler, isLast, isZeroSizeData); + } + + + private Buffer prepareDataToSend(final boolean isRecordNull, final boolean isLast, final Buffer data, + final boolean isZeroSizeData) { + if (data == null) { + return null; } - - if (outputQueueRecord == null) { - return; + if (data.hasRemaining() || isLast) { + final int dataChunkToSendSize = data.remaining(); + // update the available window size bytes counter + availStreamWindowSize.addAndGet(-dataChunkToSendSize); + releaseWriteQueueSpace(dataChunkToSendSize, isZeroSizeData, isRecordNull); + return data; } - - addOutputQueueRecord(outputQueueRecord); + return null; } @@ -462,13 +438,12 @@ public synchronized void writeDownStream(final HttpPacket httpPacket, /** * Flush {@link Http2Stream} output and notify {@link CompletionHandler} once * all output data has been flushed. - * + * * @param completionHandler {@link CompletionHandler} to be notified */ @Override - public void flush( - final CompletionHandler completionHandler) { - + public void flush(final CompletionHandler completionHandler) { + // check if there are pending unflushed data if (unflushedWritesCounter.get() > 0) { // if yes - synchronize do disallow decrease counter from other thread (increasing is ok) @@ -482,24 +457,24 @@ public void flush( flushHandlersQueue = new BundleQueue<>(); } - + // add the handler to the queue flushHandlersQueue.add(counterNow, completionHandler); - + return; } } } - + // if there are no pending flushes - notify the handler completionHandler.completed(stream); } - + /** * The method is responsible for checking the current output window size. * The returned integer value is the size of the data, which could be * sent now. - * + * * @param size check the provided size against the window size limit. * * @return the amount of data that may be written. @@ -520,17 +495,32 @@ private Buffer splitOutputBufferIfNeeded(final Buffer buffer, return buffer.split(buffer.position() + length); } + private void flushToConnectionOutputSink(final List headerFrames, + final CompletionHandler completionHandler, + final MessageCloner messageCloner, + final boolean sendFIN) { + final FlushCompletionHandler flushCompletionHandler = new FlushCompletionHandler(completionHandler); + flushToConnectionOutputSink(headerFrames, null, flushCompletionHandler, messageCloner, sendFIN); + } + + private void flushToConnectionOutputSink( + final Buffer data, + final FlushCompletionHandler flushCompletionHandler, + final boolean sendFIN) { + flushToConnectionOutputSink(null, data, flushCompletionHandler, null, sendFIN); + } + private void flushToConnectionOutputSink( final List headerFrames, final Buffer data, final CompletionHandler completionHandler, final MessageCloner messageCloner, - final boolean isLast) { - - http2Session.getOutputSink().writeDataDownStream(stream, headerFrames, - data, completionHandler, messageCloner, isLast); - - if (isLast) { + final boolean sendFIN) { + + http2Session.getOutputSink().writeDataDownStream( + stream, headerFrames, data, completionHandler, messageCloner, sendFIN); + + if (sendFIN) { terminate(OUT_FIN_TERMINATION); } } @@ -543,17 +533,16 @@ private void flushToConnectionOutputSink( public synchronized void close() { if (!isClosed()) { isLastFrameQueued = true; - + if (outputQueue.isEmpty()) { writeEmptyFin(); return; } - + outputQueue.reserveSpace(ZERO_QUEUE_RECORD_SIZE); outputQueue.offer(TERMINATING_QUEUE_RECORD); - - if (outputQueue.size() == ZERO_QUEUE_RECORD_SIZE && - outputQueue.remove(TERMINATING_QUEUE_RECORD)) { + + if (outputQueue.size() == ZERO_QUEUE_RECORD_SIZE && outputQueue.remove(TERMINATING_QUEUE_RECORD)) { writeEmptyFin(); } } @@ -572,12 +561,12 @@ public synchronized void terminate(final Termination terminationFlag) { stream.onOutputClosed(); } } - + @Override public boolean isClosed() { return isLastFrameQueued || isTerminated(); } - + /** * @return the number of writes (not bytes), that haven't reached network layer */ @@ -585,16 +574,15 @@ public boolean isClosed() { public int getUnflushedWritesCount() { return unflushedWritesCounter.get(); } - + private boolean isTerminated() { return terminationFlag != null; } - + private void writeEmptyFin() { if (!isTerminated()) { unflushedWritesCounter.incrementAndGet(); - flushToConnectionOutputSink(null, Buffers.EMPTY_BUFFER, - new FlushCompletionHandler(null), null, true); + flushToConnectionOutputSink(Buffers.EMPTY_BUFFER, new FlushCompletionHandler(null), true); } } @@ -610,85 +598,66 @@ private boolean isWantToWrite() { private void addOutputQueueRecord(OutputQueueRecord outputQueueRecord) throws Http2StreamException { - - do { // Make sure current outputQueueRecord is not forgotten - // set the outputQueueRecord as the current + do { outputQueue.setCurrentElement(outputQueueRecord); // check if situation hasn't changed and we can't send the data chunk now - if (isWantToWrite() && - outputQueue.compareAndSetCurrentElement(outputQueueRecord, null)) { - - // if we can send the output record now - do that - final FlushCompletionHandler chunkedCompletionHandler = - outputQueueRecord.chunkedCompletionHandler; - - final HttpTrailer currentTrailer = outputQueueRecord.trailer; - final MessageCloner messageCloner = outputQueueRecord.cloner; - if (currentTrailer != null) { - try { - sendTrailers(chunkedCompletionHandler, messageCloner, currentTrailer); - } catch (IOException ex) { - LOGGER.log(WARNING, "Error sending trailers.", ex); - } - return; - } + if (!isWantToWrite() || !outputQueue.compareAndSetCurrentElement(outputQueueRecord, null)) { + break; // will be (or already) written asynchronously + } - boolean isLast = outputQueueRecord.isLast; - final boolean isZeroSizeData = outputQueueRecord.isZeroSizeData; - - final Source currentResource = outputQueueRecord.resource; - - final int fitWindowLen = checkOutputWindow(currentResource.remaining()); - final Buffer dataChunkToSend = currentResource.read(fitWindowLen); - - // if there is a chunk to store - if (currentResource.hasRemaining()) { - // Create output record for the chunk to be stored - outputQueueRecord.reset(currentResource, - chunkedCompletionHandler, - isLast); - outputQueueRecord.incChunksCounter(); - - // reset isLast for the current chunk - isLast = false; - } else { - outputQueueRecord.release(); - outputQueueRecord = null; - } + // if we can send the output record now - do that + final FlushCompletionHandler chunkedCompletionHandler = outputQueueRecord.chunkedCompletionHandler; + final HttpTrailer currentTrailer = outputQueueRecord.trailer; + if (currentTrailer != null) { + sendTrailers(chunkedCompletionHandler, currentTrailer); + return; + } - // if there is a chunk to send - if (dataChunkToSend != null && - (dataChunkToSend.hasRemaining() || isLast)) { - final int dataChunkToSendSize = dataChunkToSend.remaining(); - - flushToConnectionOutputSink(null, dataChunkToSend, - chunkedCompletionHandler, null, isLast); - - // update the available window size bytes counter - availStreamWindowSize.addAndGet(-dataChunkToSendSize); - releaseWriteQueueSpace(dataChunkToSendSize, isZeroSizeData, - outputQueueRecord == null); - - } else if (isZeroSizeData && outputQueueRecord == null) { - // if it's atomic and no remainder left - don't forget to release ATOMIC_QUEUE_RECORD_SIZE - releaseWriteQueueSpace(0, true, true); - } else if (dataChunkToSend != null && !dataChunkToSend.hasRemaining()) { - // current window won't allow the data to be sent. Will be written once the - // window changes. - if (outputQueueRecord != null) { - reserveWriteQueueSpace(outputQueueRecord.resource.remaining()); - outputQueue.offer(outputQueueRecord); - } - break; - } + boolean isLast = outputQueueRecord.isLast; + final boolean isZeroSizeData = outputQueueRecord.isZeroSizeData; + final Source currentResource = outputQueueRecord.resource; + + final int fitWindowLen = checkOutputWindow(currentResource.remaining()); + final Buffer dataChunkToSend = currentResource.read(fitWindowLen); + + // if there is a chunk to store + if (currentResource.hasRemaining()) { + // Create output record for the chunk to be stored + outputQueueRecord.reset(currentResource, chunkedCompletionHandler, isLast); + outputQueueRecord.incChunksCounter(); + + // reset isLast for the current chunk + isLast = false; } else { - break; // will be (or already) written asynchronously + outputQueueRecord.release(); + outputQueueRecord = null; + } + + // if there is a chunk to send + if (dataChunkToSend != null && (dataChunkToSend.hasRemaining() || isLast)) { + final int dataChunkToSendSize = dataChunkToSend.remaining(); + flushToConnectionOutputSink(dataChunkToSend, chunkedCompletionHandler, isLast); + + // update the available window size bytes counter + availStreamWindowSize.addAndGet(-dataChunkToSendSize); + releaseWriteQueueSpace(dataChunkToSendSize, isZeroSizeData, outputQueueRecord == null); + } else if (isZeroSizeData && outputQueueRecord == null) { + // if it's atomic and no remainder left - don't forget to release ATOMIC_QUEUE_RECORD_SIZE + releaseWriteQueueSpace(0, true, true); + } else if (dataChunkToSend != null && !dataChunkToSend.hasRemaining()) { + // current window won't allow the data to be sent. Will be written once the + // window changes. + if (outputQueueRecord != null) { + reserveWriteQueueSpace(outputQueueRecord.resource.remaining()); + outputQueue.offer(outputQueueRecord); + } + break; } } while (outputQueueRecord != null); } - + private int reserveWriteQueueSpace(final int spaceToReserve) { return outputQueue.reserveSpace(spaceToReserve); } @@ -702,58 +671,60 @@ private void releaseWriteQueueSpace(final int justSentBytes, final boolean isAto } } - private void sendTrailers(final CompletionHandler completionHandler, - final MessageCloner messageCloner, - final HttpTrailer httpContent) - throws IOException { - final boolean logging = NetLogger.isActive(); - final Map capture = ((logging) ? new HashMap<>() : null); - List trailerFrames = - http2Session.encodeTrailersAsHeaderFrames(stream.getId(), - new ArrayList<>(4), - httpContent.getHeaders(), capture); - if (logging) { - for (Http2Frame http2Frame : trailerFrames) { - if (http2Frame.getType() == PushPromiseFrame.TYPE) { - NetLogger.log(NetLogger.Context.TX, http2Session, (HeadersFrame) http2Frame, capture); - break; + private void sendTrailers(final CompletionHandler completionHandler, final HttpTrailer httpContent) { + http2Session.getDeflaterLock().lock(); + try { + final boolean logging = NetLogger.isActive(); + final Map capture = logging ? new HashMap<>() : null; + final List trailerFrames = + http2Session.encodeTrailersAsHeaderFrames(stream.getId(), + new ArrayList<>(4), + httpContent.getHeaders(), capture); + if (logging) { + for (Http2Frame http2Frame : trailerFrames) { + if (http2Frame.getType() == PushPromiseFrame.TYPE) { + NetLogger.log(NetLogger.Context.TX, http2Session, (HeadersFrame) http2Frame, capture); + break; + } } } + flushToConnectionOutputSink(trailerFrames, completionHandler, null, true); + unflushedWritesCounter.incrementAndGet(); + } catch (IOException ex) { + LOGGER.log(WARNING, "Error sending trailers.", ex); + } finally { + close(); + LOGGER.finest("Sending trailers finished, unlocking the deflater lock ..."); + http2Session.getDeflaterLock().unlock(); } - unflushedWritesCounter.incrementAndGet(); - flushToConnectionOutputSink(trailerFrames, null, - new FlushCompletionHandler(completionHandler), - messageCloner, true); - close(); } private static class OutputQueueRecord extends AsyncQueueRecord { + private final HttpTrailer trailer; + private final boolean isZeroSizeData; + private Source resource; private FlushCompletionHandler chunkedCompletionHandler; - - private HttpTrailer trailer; - private MessageCloner cloner; - private boolean isLast; - - private final boolean isZeroSizeData; - + + public OutputQueueRecord(final Source resource, final FlushCompletionHandler completionHandler, final boolean isLast, final boolean isZeroSizeData) { super(null, null, null); - + this.resource = resource; this.chunkedCompletionHandler = completionHandler; this.isLast = isLast; + this.trailer = null; this.isZeroSizeData = isZeroSizeData; } - + public OutputQueueRecord(final Source resource, final FlushCompletionHandler completionHandler, final HttpTrailer trailer, final boolean isZeroDataSize) { super(null, null, null); - + this.resource = resource; this.chunkedCompletionHandler = completionHandler; this.isLast = true; @@ -774,7 +745,7 @@ private void reset(final Source resource, this.chunkedCompletionHandler = completionHandler; this.isLast = last; } - + public void release() { if (resource != null) { resource.release(); @@ -794,7 +765,7 @@ public void notifyFailure(final Throwable e) { release(); } } - + @Override public void recycle() { } @@ -804,40 +775,43 @@ public WriteResult getCurrentResult() { return null; } } - + /** * Flush {@link CompletionHandler}, which will be passed on each * {@link Http2Stream} write to make sure the data reached the wires. - * + * * Usually FlushCompletionHandler is also used as a wrapper for * custom {@link CompletionHandler} provided by users. + * + * The parent class has an internal state, so be careful with reuses of the same instance! */ private final class FlushCompletionHandler extends ChunkedCompletionHandler { - public FlushCompletionHandler( - final CompletionHandler parentCompletionHandler) { + public FlushCompletionHandler(final CompletionHandler parentCompletionHandler) { super(parentCompletionHandler); } + /** + * Notifies all flush handlers about the completition. + */ @Override protected void done0() { synchronized (flushHandlersSync) { // synchronize with flush() unflushedWritesCounter.decrementAndGet(); - if (flushHandlersQueue == null || - !flushHandlersQueue.nextBundle()) { + if (flushHandlersQueue == null || !flushHandlersQueue.nextBundle()) { return; } } - + boolean hasNext; CompletionHandler handler; - + do { synchronized (flushHandlersSync) { handler = flushHandlersQueue.next(); hasNext = flushHandlersQueue.hasNext(); } - + try { handler.completed(stream); } catch (Exception ignored) { diff --git a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2AddOn.java b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2AddOn.java index bba94e1ec7..aadb948fcf 100644 --- a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2AddOn.java +++ b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2AddOn.java @@ -41,14 +41,13 @@ public class Http2AddOn implements AddOn { private static final Logger LOGGER = Grizzly.logger(Http2AddOn.class); - + private final Http2Configuration http2Configuration; // ----------------------------------------------------------- Constructors - @SuppressWarnings("unused") public Http2AddOn() { this(Http2Configuration.builder().build()); } @@ -64,15 +63,17 @@ public Http2AddOn(final Http2Configuration http2Configuration) { @Override public void setup(NetworkListener networkListener, FilterChainBuilder builder) { + LOGGER.config(() -> String.format("setup(networkListener=%s, builder=%s)", networkListener, builder)); final TCPNIOTransport transport = networkListener.getTransport(); - + if (networkListener.isSecure() && !AlpnSupport.isEnabled()) { - LOGGER.warning("TLS ALPN (Application-Layer Protocol Negotiation) support is not available. HTTP/2 support will not be enabled."); + LOGGER.warning("TLS ALPN (Application-Layer Protocol Negotiation) support is not available." + + " HTTP/2 support will not be enabled."); return; } - + final Http2ServerFilter http2Filter = updateFilterChain(builder); - + if (networkListener.isSecure()) { configureAlpn(transport, http2Filter, builder); } @@ -95,30 +96,26 @@ public Http2Configuration getConfiguration() { private Http2ServerFilter updateFilterChain(final FilterChainBuilder builder) { - - final int codecFilterIdx = builder.indexOfType( - org.glassfish.grizzly.http.HttpServerFilter.class); - - final Http2ServerFilter http2HandlerFilter = - new Http2ServerFilter(http2Configuration); - + final int codecFilterIdx = builder.indexOfType(org.glassfish.grizzly.http.HttpServerFilter.class); + final Http2ServerFilter http2HandlerFilter = new Http2ServerFilter(http2Configuration); http2HandlerFilter.setLocalMaxFramePayloadSize(http2Configuration.getMaxFramePayloadSize()); builder.add(codecFilterIdx + 1, http2HandlerFilter); - return http2HandlerFilter; } - + private static void configureAlpn(final Transport transport, final Http2ServerFilter http2Filter, final FilterChainBuilder builder) { - - final int idx = builder.indexOfType(SSLBaseFilter.class); - if (idx != -1) { - final SSLBaseFilter sslFilter = (SSLBaseFilter) builder.get(idx); + LOGGER.finest(() -> String.format("configureAlpn(transport=%s, http2Filter=%s, builder=%s)", + transport, http2Filter, builder)); - AlpnSupport.getInstance().configure(sslFilter); - AlpnSupport.getInstance().setServerSideNegotiator(transport, - new AlpnServerNegotiatorImpl(http2Filter)); + final int idx = builder.indexOfType(SSLBaseFilter.class); + if (idx == -1) { + LOGGER.warning("No usable SSLBaseFilter found!"); + return; } + final SSLBaseFilter sslFilter = (SSLBaseFilter) builder.get(idx); + AlpnSupport.getInstance().configure(sslFilter); + AlpnSupport.getInstance().setServerSideNegotiator(transport, new AlpnServerNegotiatorImpl(http2Filter)); } } diff --git a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2ClientFilter.java b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2ClientFilter.java index 15de5f0269..821d020d12 100644 --- a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2ClientFilter.java +++ b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2ClientFilter.java @@ -21,6 +21,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Logger; + import javax.net.ssl.SSLEngine; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.Connection; @@ -69,27 +71,25 @@ * @author oleksiys */ public class Http2ClientFilter extends Http2BaseFilter { + + private static final Logger LOGGER = Logger.getLogger(Http2ClientFilter.class.getName()); private final AlpnClientNegotiatorImpl defaultClientAlpnNegotiator; - + private boolean isNeverForceUpgrade; private boolean sendPushRequestUpstream; private final HeaderValue defaultHttp2Upgrade; private final HeaderValue connectionUpgradeHeaderValue; - + public Http2ClientFilter(final Http2Configuration configuration) { super(configuration); - defaultClientAlpnNegotiator = - new AlpnClientNegotiatorImpl(this); - + defaultClientAlpnNegotiator = new AlpnClientNegotiatorImpl(this); defaultHttp2Upgrade = HeaderValue.newHeaderValue(HTTP2_CLEAR); - connectionUpgradeHeaderValue = - HeaderValue.newHeaderValue("Upgrade, HTTP2-Settings"); + connectionUpgradeHeaderValue = HeaderValue.newHeaderValue("Upgrade, HTTP2-Settings"); } /** * @return true if an upgrade to HTTP/2 will not be performed, otherwise false */ - @SuppressWarnings("unused") public boolean isNeverForceUpgrade() { return isNeverForceUpgrade; } @@ -99,7 +99,6 @@ public boolean isNeverForceUpgrade() { * * @param neverForceUpgrade true to disable upgrade attempts, otherwise false */ - @SuppressWarnings("unused") public void setNeverForceUpgrade(boolean neverForceUpgrade) { this.isNeverForceUpgrade = neverForceUpgrade; } @@ -108,7 +107,6 @@ public void setNeverForceUpgrade(boolean neverForceUpgrade) { * @return true if the push request has to be sent upstream, so * a user have a chance to process it, or false otherwise */ - @SuppressWarnings("unused") public boolean isSendPushRequestUpstream() { return sendPushRequestUpstream; } @@ -118,23 +116,22 @@ public boolean isSendPushRequestUpstream() { * be sent upstream, so a user have a chance to process it, * or false otherwise */ - @SuppressWarnings("unused") public void setSendPushRequestUpstream(boolean sendPushRequestUpstream) { this.sendPushRequestUpstream = sendPushRequestUpstream; } - + @Override public NextAction handleConnect(final FilterChainContext ctx) throws IOException { + LOGGER.finest(() -> String.format("handleConnect(ctx=%s)", ctx)); final Connection connection = ctx.getConnection(); - final FilterChain filterChain = (FilterChain) connection.getProcessor(); final int idx = filterChain.indexOfType(SSLFilter.class); - + if (idx != -1) { // use TLS ALPN final SSLFilter sslFilter = (SSLFilter) filterChain.get(idx); + LOGGER.finest(() -> String.format("Using AlpnSupport for filter: %s", sslFilter)); AlpnSupport.getInstance().configure(sslFilter); - AlpnSupport.getInstance().setClientSideNegotiator( - connection, getClientAlpnNegotiator()); + AlpnSupport.getInstance().setClientSideNegotiator(connection, getClientAlpnNegotiator()); final NextAction suspendAction = ctx.getSuspendAction(); ctx.suspend(); @@ -156,6 +153,7 @@ public void failed(Throwable throwable) { connection.enableIOEvent(IOEvent.READ); return suspendAction; } else if (getConfiguration().isPriorKnowledge()) { + LOGGER.finest(() -> String.format("Using HTTP 1.1 upgrade mechanism for connection: %s", connection)); final Http2Session http2Session = createClientHttp2Session(connection); final Http2State state = http2Session.getHttp2State(); state.setDirectUpgradePhase(); @@ -173,71 +171,72 @@ public void ready(Http2Session http2Session) { connection.enableIOEvent(IOEvent.READ); return suspendAction; } - + return ctx.getInvokeAction(); } - - @SuppressWarnings("unchecked") + @Override public NextAction handleRead(final FilterChainContext ctx) throws IOException { - + LOGGER.finest(() -> String.format("handleRead(ctx=%s)", ctx)); // if it's a stream chain (the stream is already assigned) - just // bypass the parsing part if (checkIfHttp2StreamChain(ctx)) { + LOGGER.finest("Already registered HTTP2 stream chain, invoking action."); return ctx.getInvokeAction(); } - + final Connection connection = ctx.getConnection(); Http2State http2State = Http2State.get(connection); - + if (http2State == null || http2State.isNeverHttp2()) { + LOGGER.finest("Not a HTTP2 connection, invoking action."); // NOT HTTP2 connection and never will be return ctx.getInvokeAction(); } - + final HttpContent httpContent = ctx.getMessage(); final HttpHeader httpHeader = httpContent.getHttpHeader(); - + if (http2State.isHttpUpgradePhase()) { // Not HTTP/2 (yet?) assert !httpHeader.isRequest(); - + final HttpResponsePacket httpResponse = (HttpResponsePacket) httpHeader; final HttpRequestPacket httpRequest = httpResponse.getRequest(); - + if (!tryHttpUpgrade(ctx, http2State, httpRequest, httpResponse)) { - // upgrade didn't work out + LOGGER.finest("Upgrade to HTTP2 didn't work out. Invoking action."); http2State.setNeverHttp2(); return ctx.getInvokeAction(); } } - - final Http2Session http2Session = - obtainHttp2Session(http2State, ctx, true); - + + final Http2Session http2Session = obtainHttp2Session(http2State, ctx, true); + final Buffer framePayload = httpContent.getContent(); httpContent.recycle(); - + final List framesList = frameCodec.parse(http2Session, http2State.getFrameParsingState(), framePayload); - + if (!processFrames(ctx, http2Session, framesList)) { return ctx.getSuspendAction(); } - + return ctx.getStopAction(); } @Override public NextAction handleWrite(final FilterChainContext ctx) throws IOException { - + LOGGER.finest(() -> String.format("handleWrite(ctx=%s)", ctx)); + final Connection connection = ctx.getConnection(); Http2State http2State = Http2State.get(connection); - + if (http2State != null && http2State.isNeverHttp2()) { return ctx.getInvokeAction(); } @@ -245,59 +244,58 @@ public NextAction handleWrite(final FilterChainContext ctx) if (http2State == null) { http2State = Http2State.create(connection); final Object msg = ctx.getMessage(); - + if (!tryInsertHttpUpgradeHeaders(connection, msg)) { http2State.setNeverHttp2(); } - + assert HttpPacket.isHttp(ctx.getMessage()); - + checkIfLastHttp11Chunk(ctx, http2State, msg); - return ctx.getInvokeAction(); - } else { - if (http2State.isHttpUpgradePhase()) { - // We still don't have the server response regarding HTTP2 upgrade offer - final Object msg = ctx.getMessage(); - if (HttpPacket.isHttp(msg)) { - if (!((HttpPacket) msg).getHttpHeader().isCommitted()) { - throw new IllegalStateException("Can't pipeline HTTP requests because it's still not clear if HTTP/1.x or HTTP/2 will be used"); - } - - checkIfLastHttp11Chunk(ctx, http2State, msg); + } + + if (http2State.isHttpUpgradePhase()) { + // We still don't have the server response regarding HTTP2 upgrade offer + final Object msg = ctx.getMessage(); + if (HttpPacket.isHttp(msg)) { + if (!((HttpPacket) msg).getHttpHeader().isCommitted()) { + throw new IllegalStateException("Can't pipeline HTTP requests because it's still not clear if HTTP/1.x or HTTP/2 will be used"); } - - return ctx.getInvokeAction(); + + checkIfLastHttp11Chunk(ctx, http2State, msg); } + + return ctx.getInvokeAction(); } - + return super.handleWrite(ctx); } @Override - @SuppressWarnings("unchecked") public NextAction handleEvent(final FilterChainContext ctx, final FilterChainEvent event) throws IOException { + LOGGER.finest(() -> String.format("handleEvent(ctx=%s, event=%s)", ctx, event)); if (!Http2State.isHttp2(ctx.getConnection())) { return ctx.getInvokeAction(); } - + final Object type = event.type(); - + if (type == OutgoingHttpUpgradeEvent.TYPE) { assert event instanceof OutgoingHttpUpgradeEvent; - + final OutgoingHttpUpgradeEvent outUpgradeEvent = (OutgoingHttpUpgradeEvent) event; // If it's HTTP2 outgoing upgrade message - we have to re-enable content modifiers control outUpgradeEvent.getHttpHeader().setIgnoreContentModifiers(false); - + return ctx.getStopAction(); } - + return ctx.getInvokeAction(); } - + /** * Process the provided outbound header/packet. * @@ -318,15 +316,15 @@ protected void processOutgoingHttpHeader(final FilterChainContext ctx, // HTTP2 output is not enabled yet return; } - + final HttpRequestPacket request = (HttpRequestPacket) httpHeader; - + if (!request.isCommitted()) { prepareOutgoingRequest(request); } final Http2Stream stream = Http2Stream.getStreamFor(request); - + if (stream == null) { processOutgoingRequestForNewStream(ctx, http2Session, request, entireHttpPacket); @@ -339,17 +337,17 @@ protected void processOutgoingHttpHeader(final FilterChainContext ctx, transportContext.getMessageCloner()); } } - + @SuppressWarnings("unchecked") private void processOutgoingRequestForNewStream(final FilterChainContext ctx, final Http2Session http2Session, final HttpRequestPacket request, final HttpPacket entireHttpPacket) throws IOException { - + final ReentrantLock newStreamLock = http2Session.getNewClientStreamLock(); newStreamLock.lock(); - + try { final Http2Stream stream = http2Session.openStream( request, @@ -359,10 +357,10 @@ private void processOutgoingRequestForNewStream(final FilterChainContext ctx, if (stream == null) { throw new IOException("Http2Session is closed"); } - + // Make sure request contains the association with the HTTP2 stream request.setAttribute(Http2Stream.HTTP2_STREAM_ATTRIBUTE, stream); - + final TransportContext transportContext = ctx.getTransportContext(); stream.getOutputSink().writeDownStream(entireHttpPacket, @@ -374,15 +372,15 @@ private void processOutgoingRequestForNewStream(final FilterChainContext ctx, newStreamLock.unlock(); } } - + /** * Creates client-side {@link Http2Session} with pre-configured * initial-windows-size and max-concurrent-streams. - * + * * Note: Should be called with disabled OP_READ (or during OP_READ processing), * because peer frames must not be processed at the time this method * is running. - * + * * @param connection the TCP connection * @return {@link Http2Session} */ @@ -390,15 +388,15 @@ protected Http2Session createClientHttp2Session(final Connection connection) { return createHttp2Session(connection, false); } - + protected AlpnClientNegotiator getClientAlpnNegotiator() { return defaultClientAlpnNegotiator; - } + } /** * The method is called once a client receives an HTTP response to its initial * propose to establish HTTP/2.0 connection. - * + * * @param ctx the current {@link FilterChainContext} * @param http2State the HTTP2 connection state * @param httpRequest the HTTP request @@ -422,26 +420,26 @@ private boolean tryHttpUpgrade(final FilterChainContext ctx, if (!checkRequestHeadersOnUpgrade(httpRequest)) { return false; } - + // check the server's response, if it accepts HTTP/2.0 upgrade if (!checkResponseHeadersOnUpgrade(httpResponse)) { return false; } final Connection connection = ctx.getConnection(); - + // Create HTTP/2.0 connection for the given Grizzly Connection http2State.setDirectUpgradePhase(); // expecting preface (settings frame) - + final Http2Session http2Session = createClientHttp2Session(connection); - + if (http2State.tryLockClientPreface()) { http2Session.sendPreface(); } - + http2Session.setupFilterChains(ctx, true); - + // reset the response object httpResponse.setStatus(HttpStatus.OK_200); httpResponse.getHeaders().clear(); @@ -449,7 +447,7 @@ private boolean tryHttpUpgrade(final FilterChainContext ctx, httpResponse.setProtocol(Protocol.HTTP_2_0); httpResponse.getUpgradeDC().recycle(); httpResponse.getProcessingState().setKeepAlive(true); - + // create a virtual stream for this request if (http2Session.isGoingAway()) { @@ -458,36 +456,36 @@ private boolean tryHttpUpgrade(final FilterChainContext ctx, final Http2Stream stream = http2Session.openUpgradeStream( httpRequest, 0); - + final HttpContext oldHttpContext = httpResponse.getProcessingState().getHttpContext(); - + // replace the HttpContext final HttpContext httpContext = HttpContext.newInstance(stream, stream, stream, httpRequest); httpRequest.getProcessingState().setHttpContext(httpContext); httpContext.attach(ctx); - + final HttpRequestPacket dummyRequestPacket = HttpRequestPacket.builder() .method(Method.PRI) .uri("/dummy_pri") .protocol(Protocol.HTTP_2_0) .build(); - + final HttpResponsePacket dummyResponsePacket = HttpResponsePacket.builder(dummyRequestPacket) .status(200) .reasonPhrase("OK") .protocol(Protocol.HTTP_2_0) .build(); - + dummyResponsePacket.getProcessingState().setHttpContext(oldHttpContext); dummyResponsePacket.setIgnoreContentModifiers(true); - + // change the HttpClientFilter's HttpResponsePacket associated with the Connection ctx.notifyDownstream( HttpEvents.createChangePacketInProgressEvent(dummyResponsePacket)); - + return true; } @@ -498,7 +496,7 @@ private boolean tryInsertHttpUpgradeHeaders(final Connection connection, // we aren't allowed to insert HTTP2 Upgrade headers return false; } - + if (!HttpPacket.isHttp(msg)) { return false; } @@ -521,7 +519,7 @@ private boolean tryInsertHttpUpgradeHeaders(final Connection connection, httpHeader.addHeader(Header.HTTP2Settings, prepareSettings(Http2Session.get(connection)).build().toBase64Uri()); - + // pass the updated request downstream return true; } @@ -556,14 +554,14 @@ private void processInResponse(final Http2Session http2Session, if (stream == null) { // Stream doesn't exist return; } - + final HttpRequestPacket request = stream.getRequest(); - + HttpResponsePacket response = request.getResponse(); if (response == null) { response = Http2Response.create(); } - + final boolean isEOS = headersFrame.isEndStream(); bind(request, response); @@ -632,7 +630,7 @@ private void processInPushPromise(final Http2Session http2Session, onHttpHeadersParsed(request, context); prepareIncomingRequest(stream, request); - + stream.outputSink.terminate(OUT_FIN_TERMINATION); stream.onReceivePushPromise(); // send the push request upstream only in case, when user explicitly wants it @@ -645,11 +643,11 @@ private void processInPushPromise(final Http2Session http2Session, protected SettingsFrame.SettingsFrameBuilder prepareSettings( final Http2Session http2Session) { - + SettingsFrame.SettingsFrameBuilder builder = SettingsFrame.builder(); final int maxConcStreams = getConfiguration().getMaxConcurrentStreams(); - + if (maxConcStreams != -1 && maxConcStreams != http2Session.getDefaultMaxConcurrentStreams()) { builder.setting(SETTINGS_MAX_CONCURRENT_STREAMS, maxConcStreams); @@ -663,9 +661,9 @@ protected SettingsFrame.SettingsFrameBuilder prepareSettings( } builder.setting(SETTINGS_ENABLE_PUSH, ((getConfiguration().isPushEnabled()) ? 1 : 0)); - + return builder; - } + } private void checkIfLastHttp11Chunk(final FilterChainContext ctx, final Http2State http2State, final Object msg) { diff --git a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2ServerFilter.java b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2ServerFilter.java index d233b9a6e7..ed35e9242b 100644 --- a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2ServerFilter.java +++ b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2ServerFilter.java @@ -360,7 +360,7 @@ public class Http2ServerFilter extends Http2BaseFilter { static { Arrays.sort(CIPHER_SUITE_BLACK_LIST); } - + // flag, which enables/disables payload support for HTTP methods, // for which HTTP spec doesn't clearly state whether they support payload. // Known "undefined" methods are: GET, HEAD, DELETE @@ -369,8 +369,8 @@ public class Http2ServerFilter extends Http2BaseFilter { private final Attribute CIPHER_CHECKED = AttributeBuilder.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("BLACK_LIST_CIPHER_SUITE_CHEKCED"); - private Collection activeConnections = new HashSet<>(1024); - private AtomicBoolean shuttingDown = new AtomicBoolean(); + private final Collection activeConnections = new HashSet<>(1024); + private final AtomicBoolean shuttingDown = new AtomicBoolean(); /** * Create a new {@link Http2ServerFilter} using the specified {@link Http2Configuration}. @@ -385,10 +385,9 @@ public Http2ServerFilter(final Http2Configuration configuration) { * The flag, which enables/disables payload support for HTTP methods, * for which HTTP spec doesn't clearly state whether they support payload. * Known "undefined" methods are: GET, HEAD, DELETE. - * + * * @return true if "undefined" methods support payload, or false otherwise */ - @SuppressWarnings("unused") public boolean isAllowPayloadForUndefinedHttpMethods() { return allowPayloadForUndefinedHttpMethods; } @@ -397,10 +396,9 @@ public boolean isAllowPayloadForUndefinedHttpMethods() { * The flag, which enables/disables payload support for HTTP methods, * for which HTTP spec doesn't clearly state whether they support payload. * Known "undefined" methods are: GET, HEAD, DELETE. - * + * * @param allowPayloadForUndefinedHttpMethods true if "undefined" methods support payload, or false otherwise */ - @SuppressWarnings("unused") public void setAllowPayloadForUndefinedHttpMethods(boolean allowPayloadForUndefinedHttpMethods) { this.allowPayloadForUndefinedHttpMethods = allowPayloadForUndefinedHttpMethods; } @@ -421,28 +419,28 @@ public NextAction handleClose(final FilterChainContext ctx) throws IOException { return ctx.getInvokeAction(); } - @SuppressWarnings("unchecked") @Override public NextAction handleRead(final FilterChainContext ctx) throws IOException { - + LOGGER.finest(() -> String.format("handleRead(ctx=%s)", ctx)); // if it's a stream chain (the stream is already assigned) - just // bypass the parsing part if (checkIfHttp2StreamChain(ctx)) { + LOGGER.finest("Already registered HTTP2 stream chain, invoking action."); return ctx.getInvokeAction(); } - + final Connection connection = ctx.getConnection(); Http2State http2State = Http2State.get(connection); - + if (http2State != null && http2State.isNeverHttp2()) { - // NOT HTTP2 connection and never will be + LOGGER.finest("Not a HTTP2 connection, invoking action."); return ctx.getInvokeAction(); } - + final HttpContent httpContent = ctx.getMessage(); final HttpHeader httpHeader = httpContent.getHttpHeader(); - + if (http2State == null) { // Not HTTP/2 (yet?) assert httpHeader.isRequest(); @@ -450,29 +448,27 @@ public NextAction handleRead(final FilterChainContext ctx) // ALPN should've set the Http2State, but in our case it's null. // It means ALPN was bypassed - SSL without ALPN shouldn't work. // Don't try HTTP/2 in this case. + LOGGER.finest("Secure connection, but http2State was null, ALPN was bypassed. Invoking action."); Http2State.create(connection).setNeverHttp2(); return ctx.getInvokeAction(); } - - final HttpRequestPacket httpRequest = - (HttpRequestPacket) httpHeader; - - if (!Method.PRI.equals(httpRequest.getMethod())) { + + final HttpRequestPacket httpRequest = (HttpRequestPacket) httpHeader; + + if (Method.PRI.equals(httpRequest.getMethod())) { + // PRI method + // DIRECT HTTP/2.0 request + http2State = doDirectUpgrade(ctx); + } else { final boolean isLast = httpContent.isLast(); if (tryHttpUpgrade(ctx, httpRequest, isLast) && isLast) { enableOpReadNow(ctx); } - return ctx.getInvokeAction(); } - - // PRI method - // DIRECT HTTP/2.0 request - http2State = doDirectUpgrade(ctx); } - - final Http2Session http2Session = - obtainHttp2Session(http2State, ctx, true); + + final Http2Session http2Session = obtainHttp2Session(http2State, ctx, true); if (httpHeader.isSecure() && !getConfiguration().isDisableCipherCheck() && !CIPHER_CHECKED.isSet(connection)) { CIPHER_CHECKED.set(connection, connection); @@ -484,22 +480,22 @@ public NextAction handleRead(final FilterChainContext ctx) } } } - + final Buffer framePayload; if (!http2Session.isHttp2InputEnabled()) { // Preface is not received yet - + if (http2State.isHttpUpgradePhase()) { // It's plain HTTP/1.1 data coming with upgrade request if (httpContent.isLast()) { http2State.setDirectUpgradePhase(); // expecting preface enableOpReadNow(ctx); } - + return ctx.getInvokeAction(); } - + final HttpRequestPacket httpRequest = (HttpRequestPacket) httpHeader; - + // PRI message hasn't been checked try { if (!checkPRI(httpRequest, httpContent)) { @@ -523,7 +519,7 @@ public NextAction handleRead(final FilterChainContext ctx) } else { framePayload = httpContent.getContent(); } - + httpContent.recycle(); // Prime the initial value of push. Will be overridden if the settings contain a @@ -531,7 +527,7 @@ public NextAction handleRead(final FilterChainContext ctx) if (connection.getAttributes().getAttribute(HTTP2_PUSH_ENABLED) == null) { connection.getAttributes().setAttribute(HTTP2_PUSH_ENABLED, Boolean.TRUE); } - + final List framesList = frameCodec.parse(http2Session, http2State.getFrameParsingState(), @@ -540,14 +536,15 @@ public NextAction handleRead(final FilterChainContext ctx) if (!processFrames(ctx, http2Session, framesList)) { return ctx.getSuspendAction(); } - + return ctx.getStopAction(); } @Override public NextAction handleEvent(final FilterChainContext ctx, final FilterChainEvent event) throws IOException { - + + LOGGER.finest(() -> String.format("handleEvent(ctx=%s, event=%s)", ctx, event)); final Object type = event.type(); if (type == ShutdownEvent.TYPE) { @@ -575,7 +572,7 @@ public Filter call() throws Exception { }); } } - + if (type == HttpEvents.IncomingHttpUpgradeEvent.TYPE) { final HttpHeader header = ((HttpEvents.IncomingHttpUpgradeEvent) event).getHttpHeader(); @@ -585,16 +582,16 @@ public Filter call() throws Exception { // for the HTTP/2 upgrade request we want to obey HTTP/1.1 // content modifiers (transfer and content encodings) header.setIgnoreContentModifiers(false); - + return ctx.getStopAction(); } } - + return ctx.getInvokeAction(); } final Http2State state = Http2State.get(ctx.getConnection()); - + if (state == null || state.isNeverHttp2()) { return ctx.getInvokeAction(); } @@ -603,22 +600,22 @@ public Filter call() throws Exception { doPush(ctx, (PushEvent) event); return ctx.getSuspendAction(); } - + if (type == HttpEvents.ResponseCompleteEvent.TYPE) { final HttpContext httpContext = HttpContext.get(ctx); final Http2Stream stream = (Http2Stream) httpContext.getContextStorage(); stream.onProcessingComplete(); - + final Http2Session http2Session = stream.getHttp2Session(); - + if (!http2Session.isHttp2InputEnabled()) { // it's the first HTTP/1.1 -> HTTP/2.0 upgrade request. // We have to notify regular HTTP codec filter as well state.finishHttpUpgradePhase(); // mark HTTP upgrade as finished (in case it's still on) - + return ctx.getInvokeAction(); } - + // it's pure HTTP/2.0 request processing return ctx.getStopAction(); } @@ -632,10 +629,11 @@ protected void onPrefaceReceived(Http2Session http2Session) { // from a client http2Session.sendPreface(); } - + private Http2State doDirectUpgrade(final FilterChainContext ctx) { + LOGGER.finest(() -> String.format("doDirectUpgrade(ctx=%s)", ctx)); final Connection connection = ctx.getConnection(); - + final Http2Session http2Session = new Http2Session(connection, true, this); @@ -644,10 +642,10 @@ private Http2State doDirectUpgrade(final FilterChainContext ctx) { http2State.setHttp2Session(http2Session); http2State.setDirectUpgradePhase(); http2Session.setupFilterChains(ctx, true); - + // server preface http2Session.sendPreface(); - + return http2State; } @@ -659,17 +657,17 @@ Collection shuttingDown() { private boolean tryHttpUpgrade(final FilterChainContext ctx, final HttpRequestPacket httpRequest, final boolean isLast) throws Http2StreamException { - + if (!checkHttpMethodOnUpgrade(httpRequest)) { return false; } - + if (!checkRequestHeadersOnUpgrade(httpRequest)) { return false; } - + final boolean http2Upgrade = isHttp2UpgradingVersion(httpRequest); - + if (!http2Upgrade) { // Not HTTP/2.0 HTTP packet return false; @@ -677,21 +675,21 @@ private boolean tryHttpUpgrade(final FilterChainContext ctx, final SettingsFrame settingsFrame = getHttp2UpgradeSettings(httpRequest); - + if (settingsFrame == null) { // Not HTTP/2.0 HTTP packet return false; } - + final Connection connection = ctx.getConnection(); - + final Http2Session http2Session = new Http2Session(connection, true, this); // Create HTTP/2.0 connection for the given Grizzly Connection final Http2State http2State = Http2State.create(connection); http2State.setHttp2Session(http2Session); http2Session.setupFilterChains(ctx, true); - + if (isLast) { http2State.setDirectUpgradePhase(); // expecting preface } @@ -702,21 +700,21 @@ private boolean tryHttpUpgrade(final FilterChainContext ctx, Http2State.remove(connection); return false; } - + // Send 101 Switch Protocols back to the client final HttpResponsePacket httpResponse = httpRequest.getResponse(); httpResponse.setStatus(HttpStatus.SWITCHING_PROTOCOLS_101); httpResponse.setHeader(Header.Connection, "Upgrade"); httpResponse.setHeader(Header.Upgrade, HTTP2_CLEAR); httpResponse.setIgnoreContentModifiers(true); - + ctx.write(httpResponse); // un-commit the response httpResponse.setCommitted(false); - - + + // server preface http2Session.sendPreface(); @@ -736,7 +734,7 @@ private boolean tryHttpUpgrade(final FilterChainContext ctx, // create a virtual stream for this request final Http2Stream stream = http2Session.acceptUpgradeStream( httpRequest, 0, !httpRequest.isExpectContent()); - + // replace the HttpContext final HttpContext httpContext = HttpContext.newInstance(stream, stream, stream, httpRequest); @@ -744,16 +742,16 @@ private boolean tryHttpUpgrade(final FilterChainContext ctx, // add read-only HTTP2Stream attribute httpRequest.setAttribute(Http2Stream.HTTP2_STREAM_ATTRIBUTE, stream); httpContext.attach(ctx); - + return true; } - + private boolean checkHttpMethodOnUpgrade( final HttpRequestPacket httpRequest) { - + return httpRequest.getMethod() != Method.CONNECT; } - + private boolean checkPRI(final HttpRequestPacket httpRequest, final HttpContent httpContent) { if (!Method.PRI.equals(httpRequest.getMethod())) { @@ -774,7 +772,7 @@ private boolean checkPRI(final HttpRequestPacket httpRequest, throw new HttpBrokenContentException(); } } - + return true; } @@ -788,7 +786,7 @@ protected void processCompleteHeader( processInRequest(http2Session, context, (HeadersFrame) firstHeaderFrame); } } - + private void processInRequest(final Http2Session http2Session, final FilterChainContext context, final HeadersFrame headersFrame) throws IOException { @@ -874,10 +872,10 @@ private void processInRequest(final Http2Session http2Session, request.getHeaders().mark(); prepareIncomingRequest(stream, request); - + final boolean isEOS = headersFrame.isEndStream(); stream.onRcvHeaders(isEOS); - + // stream HEADERS frame will be transformed to HTTP request packet if (isEOS) { request.setExpectContent(false); @@ -974,6 +972,7 @@ protected void processOutgoingHttpHeader(final FilterChainContext ctx, } private void doPush(final FilterChainContext ctx, final PushEvent pushEvent) { + LOGGER.finest(() -> String.format("doPush(ctx=%s, pushEvent=%s)", ctx, pushEvent)); final Http2Session http2Session = Http2Session.get(ctx.getConnection()); if (http2Session == null) { throw new IllegalStateException("Unable to find valid Http2Session"); diff --git a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2Session.java b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2Session.java index 79ebad95e0..c6e6fac68e 100644 --- a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2Session.java +++ b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2Session.java @@ -13,7 +13,7 @@ * https://www.gnu.org/software/classpath/license.html. * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 - * + * * Contributors: * Payara Services - Prevent push when globally disabled */ @@ -892,8 +892,6 @@ protected List encodeHttpRequestAsPushPromiseFrames( final Map capture) throws IOException { - final boolean logging = NetLogger.isActive(); - final List headerFrames = bufferToPushPromiseFrames( streamId, @@ -965,7 +963,7 @@ private List completeHeadersProviderFrameSerialization( final Buffer compressedHeaders, List toList) { // we assume deflaterLock is acquired and held by this thread - assert deflaterLock.isHeldByCurrentThread(); + assert getDeflaterLock().isHeldByCurrentThread(); if (toList == null) { toList = tmpHeaderFramesList; diff --git a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2SessionOutputSink.java b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2SessionOutputSink.java index 4190870717..20afca0e2d 100644 --- a/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2SessionOutputSink.java +++ b/modules/http2/src/main/java/org/glassfish/grizzly/http2/Http2SessionOutputSink.java @@ -29,18 +29,16 @@ import org.glassfish.grizzly.Grizzly; import org.glassfish.grizzly.WriteHandler; import org.glassfish.grizzly.WriteResult; -import org.glassfish.grizzly.asyncqueue.AsyncQueueRecord; import org.glassfish.grizzly.asyncqueue.MessageCloner; import org.glassfish.grizzly.asyncqueue.TaskQueue; import org.glassfish.grizzly.http2.frames.DataFrame; import org.glassfish.grizzly.http2.frames.ErrorCode; import org.glassfish.grizzly.http2.frames.Http2Frame; -import org.glassfish.grizzly.http2.utils.ChunkedCompletionHandler; /** * Class represents an output sink associated with specific {@link Http2Session} * and is responsible for session (connection) level flow control. - * + * * @author Alexey Stashok */ public class Http2SessionOutputSink { @@ -74,9 +72,9 @@ public Http2SessionOutputSink(Http2Session session) { protected Http2FrameCodec frameCodec() { return http2Session.handlerFilter.frameCodec; } - + protected void writeDownStream(final Http2Frame frame) { - + http2Session.getHttp2SessionChain().write( http2Session.getConnection(), null, frameCodec().serializeAndRecycle(http2Session, frame), @@ -84,18 +82,18 @@ protected void writeDownStream(final Http2Frame frame) { } protected void writeDownStream(final List frames) { - + http2Session.getHttp2SessionChain().write( http2Session.getConnection(), null, frameCodec().serializeAndRecycle(http2Session, frames), null, (MessageCloner) null); } - + @SuppressWarnings("unchecked") protected void writeDownStream(final K anyMessage, final CompletionHandler completionHandler, final MessageCloner messageCloner) { - + // Encode Http2Frame -> Buffer final Object msg; if (anyMessage instanceof List) { @@ -107,9 +105,9 @@ protected void writeDownStream(final K anyMessage, } else { msg = anyMessage; } - + http2Session.getHttp2SessionChain().write(http2Session.getConnection(), - null, msg, completionHandler, messageCloner); + null, msg, completionHandler, messageCloner); } protected int getAvailablePeerConnectionWindowSize() { @@ -168,7 +166,6 @@ protected void writeDataDownStream(final Http2Stream stream, } writeDownStream(msg, completionHandler, messageCloner); - return; } else if (headerFrames != null && !headerFrames.isEmpty()) { // flush the headers now in this thread, diff --git a/modules/http2/src/main/java/org/glassfish/grizzly/http2/utils/ChunkedCompletionHandler.java b/modules/http2/src/main/java/org/glassfish/grizzly/http2/utils/ChunkedCompletionHandler.java index be616ca8c9..a511ea93c0 100644 --- a/modules/http2/src/main/java/org/glassfish/grizzly/http2/utils/ChunkedCompletionHandler.java +++ b/modules/http2/src/main/java/org/glassfish/grizzly/http2/utils/ChunkedCompletionHandler.java @@ -16,6 +16,8 @@ package org.glassfish.grizzly.http2.utils; +import java.util.logging.Logger; + import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.WriteResult; @@ -24,23 +26,27 @@ * @author oleksiys */ public class ChunkedCompletionHandler implements CompletionHandler { + private static final Logger LOG = Logger.getLogger(ChunkedCompletionHandler.class.getName()); private final CompletionHandler parentCompletionHandler; private boolean isDone; - protected int chunksCounter = 1; + private int chunksCounter = 1; private long writtenSize; - public ChunkedCompletionHandler( - final CompletionHandler parentCompletionHandler) { + /** + * @param parentCompletionHandler - can be null + */ + public ChunkedCompletionHandler(final CompletionHandler parentCompletionHandler) { this.parentCompletionHandler = parentCompletionHandler; } public void incChunks() { chunksCounter++; } - + @Override public void cancelled() { + LOG.finest("cancelled()"); if (done()) { if (parentCompletionHandler != null) { parentCompletionHandler.cancelled(); @@ -50,6 +56,8 @@ public void cancelled() { @Override public void failed(Throwable throwable) { + // we don't need a stacktrace here, but we want to see why we are here. + LOG.finest(() -> String.format("failed(throwable=%s)", throwable)); if (done()) { if (parentCompletionHandler != null) { parentCompletionHandler.failed(throwable); @@ -59,6 +67,7 @@ public void failed(Throwable throwable) { @Override public void completed(final WriteResult result) { + LOG.finest(() -> String.format("completed(result=%s)", result)); if (isDone) { return; } @@ -85,9 +94,9 @@ public void completed(final WriteResult result) { @Override public void updated(final WriteResult result) { + LOG.finest(() -> String.format("updated(result=%s)", result)); if (parentCompletionHandler != null) { final long initialWrittenSize = result.getWrittenSize(); - try { result.setWrittenSize(writtenSize + initialWrittenSize); parentCompletionHandler.updated(result); @@ -103,11 +112,16 @@ private boolean done() { } isDone = true; - + done0(); return true; } - + + + /** + * This method does nothing but can be overriden to implement some action executed before + * the parent completition handler is executed. + */ protected void done0() { } } diff --git a/modules/http2/src/test/java/org/glassfish/grizzly/http2/AbstractHttp2Test.java b/modules/http2/src/test/java/org/glassfish/grizzly/http2/AbstractHttp2Test.java index 84a0af8895..6dcd1a5095 100644 --- a/modules/http2/src/test/java/org/glassfish/grizzly/http2/AbstractHttp2Test.java +++ b/modules/http2/src/test/java/org/glassfish/grizzly/http2/AbstractHttp2Test.java @@ -16,11 +16,12 @@ package org.glassfish.grizzly.http2; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.Arrays; import java.util.Collection; -import java.util.LinkedList; +import java.util.logging.LogManager; import java.util.logging.Logger; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.Grizzly; @@ -45,14 +46,23 @@ /** * General HTTP2 client/server init code. - * + * * @author Alexey Stashok */ public abstract class AbstractHttp2Test { + static { + try { + LogManager.getLogManager().readConfiguration(AbstractHttp2Test.class.getResourceAsStream("/logging.properties")); + } catch (SecurityException | IOException e) { + e.printStackTrace(); + } + } + + protected static final Logger LOGGER = Grizzly.logger(AbstractHttp2Test.class); - + private volatile static SSLEngineConfigurator clientSSLEngineConfigurator; - private volatile static SSLEngineConfigurator serverSSLEngineConfigurator; + private volatile static SSLEngineConfigurator serverSSLEngineConfigurator; public static Collection configure() { return Arrays.asList(new Object[][]{ @@ -62,17 +72,17 @@ public static Collection configure() { //{ (AlpnSupport.isEnabled() && !Boolean.valueOf(System.getProperty("grizzly.skip.http2tls", "false"))), Boolean.FALSE }, // secure }); } - + protected Http2AddOn http2Addon; - + protected HttpServer createServer(final String docRoot, final int port, final boolean isSecure, final HttpHandlerRegistration... registrations) { - + return createServer(docRoot, port, isSecure, false, registrations); } - + protected HttpServer createServer(final String docRoot, final int port, final boolean isSecure, final boolean isFileCacheEnabled, @@ -80,7 +90,7 @@ protected HttpServer createServer(final String docRoot, final int port, HttpServer server = HttpServer.createSimpleServer(docRoot, port); NetworkListener listener = server.getListener("grizzly"); listener.setSendFileEnabled(false); - + listener.getFileCache().setEnabled(isFileCacheEnabled); if (isSecure) { @@ -90,21 +100,21 @@ protected HttpServer createServer(final String docRoot, final int port, http2Addon = new Http2AddOn(Http2Configuration.builder().disableCipherCheck(true).build()); listener.registerAddOn(http2Addon); - + ServerConfiguration sconfig = server.getServerConfiguration(); - + for (HttpHandlerRegistration registration : registrations) { sconfig.addHttpHandler(registration.httpHandler, registration.mappings); } - + return server; } - + protected static FilterChain createClientFilterChain( final boolean isSecure, final Filter... clientFilters) { - + return createClientFilterChainAsBuilder(isSecure, false, clientFilters).build(); } @@ -114,23 +124,23 @@ protected static FilterChainBuilder createClientFilterChainAsBuilder( final Filter... clientFilters) { return createClientFilterChainAsBuilder(isSecure, false, clientFilters); } - + protected static FilterChainBuilder createClientFilterChainAsBuilder( final boolean isSecure, final boolean priorKnowledge, final Filter... clientFilters) { - + final FilterChainBuilder builder = FilterChainBuilder.stateless() .add(new TransportFilter()); if (isSecure) { builder.add(new SSLFilter(null, getClientSSLEngineConfigurator())); } - - + + builder.add(new HttpClientFilter()); builder.add(new Http2ClientFilter(Http2Configuration.builder().priorKnowledge(priorKnowledge).build())); - + if (clientFilters != null) { for (Filter clientFilter : clientFilters) { if (clientFilter != null) { @@ -138,15 +148,15 @@ protected static FilterChainBuilder createClientFilterChainAsBuilder( } } } - + return builder; } - + protected static SSLEngineConfigurator getClientSSLEngineConfigurator() { checkSSLEngineConfigurators(); return clientSSLEngineConfigurator; } - + protected static SSLEngineConfigurator getServerSSLEngineConfigurator() { checkSSLEngineConfigurators(); return serverSSLEngineConfigurator; @@ -172,7 +182,7 @@ private static void checkSSLEngineConfigurators() { } } } - + protected static SSLContextConfigurator createSSLContextConfigurator() { SSLContextConfigurator sslContextConfigurator = new SSLContextConfigurator(); @@ -193,7 +203,7 @@ protected static SSLContextConfigurator createSSLContextConfigurator() { return sslContextConfigurator; } - + @SuppressWarnings({"unchecked"}) protected HttpPacket createRequest(final int port, final String method, @@ -221,13 +231,13 @@ protected HttpPacket createRequest(final int port, } request.setContentLength(contentBuffer.remaining()); - + if (encoding != null) { request.setCharacterEncoding(encoding); } - + request.setContentType("text/plain"); - + cb.content(contentBuffer); cb.last(true); return cb.build(); @@ -236,7 +246,7 @@ protected HttpPacket createRequest(final int port, return request; } - + protected static class HttpHandlerRegistration { private final HttpHandler httpHandler; private final String[] mappings; @@ -245,7 +255,7 @@ private HttpHandlerRegistration(HttpHandler httpHandler, String[] mappings) { this.httpHandler = httpHandler; this.mappings = mappings; } - + public static HttpHandlerRegistration of(final HttpHandler httpHandler, final String... mappings) { return new HttpHandlerRegistration(httpHandler, mappings); diff --git a/modules/http2/src/test/java/org/glassfish/grizzly/http2/TrailersTest.java b/modules/http2/src/test/java/org/glassfish/grizzly/http2/TrailersTest.java index 40ce24f6ef..5a064659a3 100644 --- a/modules/http2/src/test/java/org/glassfish/grizzly/http2/TrailersTest.java +++ b/modules/http2/src/test/java/org/glassfish/grizzly/http2/TrailersTest.java @@ -138,7 +138,7 @@ public NextAction handleRead(FilterChainContext ctx) throws IOException { return ctx.getStopAction(); } }; - final Connection c = getConnection("localhost", PORT, filter); + final Connection c = getConnection("localhost", PORT, filter); HttpRequestPacket.Builder builder = HttpRequestPacket.builder(); HttpRequestPacket request = builder.method(Method.POST) .uri("/echo") @@ -204,7 +204,7 @@ public NextAction handleRead(FilterChainContext ctx) throws IOException { return ctx.getStopAction(); } }; - final Connection c = getConnection("localhost", PORT, filter); + final Connection c = getConnection("localhost", PORT, filter); HttpRequestPacket.Builder builder = HttpRequestPacket.builder(); HttpRequestPacket request = builder.method(Method.POST) .uri("/echo") diff --git a/modules/http2/src/test/resources/logging.properties b/modules/http2/src/test/resources/logging.properties new file mode 100644 index 0000000000..fe3fc59da8 --- /dev/null +++ b/modules/http2/src/test/resources/logging.properties @@ -0,0 +1,17 @@ +handlers=java.util.logging.ConsoleHandler + +java.util.logging.ConsoleHandler.encoding=UTF-8 +java.util.logging.ConsoleHandler.level=ALL +java.util.logging.ConsoleHandler.formatter=org.glassfish.grizzly.utils.LoggingFormatter + +# Note: NIOOutputSinksTest fails with too verbose logging + +.level=INFO +org.glassfish.grizzly.filterchain.DefaultFilterChain.level=INFO +org.glassfish.grizzly.http.server.Request.level=INFO +org.glassfish.grizzly.http2.level=INFO +org.glassfish.grizzly.http2.AlpnSupport.level=CONFIG +org.glassfish.grizzly.http2.DefaultInputBuffer.level=INFO +org.glassfish.grizzly.http2.DefaultOutputSink.level=INFO +org.glassfish.grizzly.http2.Http2Stream.level=INFO +org.glassfish.grizzly.http2.NetLogger.level=INFO diff --git a/modules/monitoring/grizzly/pom.xml b/modules/monitoring/grizzly/pom.xml index c96f16c4e8..abf4e933bb 100644 --- a/modules/monitoring/grizzly/pom.xml +++ b/modules/monitoring/grizzly/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 grizzly-framework-monitoring bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-framework-monitoring install diff --git a/modules/monitoring/http-server/pom.xml b/modules/monitoring/http-server/pom.xml index 770d40756f..11d0614c81 100644 --- a/modules/monitoring/http-server/pom.xml +++ b/modules/monitoring/http-server/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 grizzly-http-server-monitoring bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-server-monitoring install diff --git a/modules/monitoring/http/pom.xml b/modules/monitoring/http/pom.xml index 902fbbbffb..42a22b7eb6 100644 --- a/modules/monitoring/http/pom.xml +++ b/modules/monitoring/http/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../../pom.xml 4.0.0 grizzly-http-monitoring bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-monitoring install diff --git a/modules/monitoring/pom.xml b/modules/monitoring/pom.xml index 464bcf1d8b..a48d09d5f5 100644 --- a/modules/monitoring/pom.xml +++ b/modules/monitoring/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-monitoring pom - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-monitoring grizzly diff --git a/modules/pom.xml b/modules/pom.xml index 5117082cd6..a247988f16 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../pom.xml 4.0.0 grizzly-modules pom - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-modules diff --git a/modules/portunif/pom.xml b/modules/portunif/pom.xml index d3eab14a1a..fffd1c4e6c 100644 --- a/modules/portunif/pom.xml +++ b/modules/portunif/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-portunif bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-portunif install diff --git a/modules/websockets/pom.xml b/modules/websockets/pom.xml index 7d34d87b4c..d4ec76a3fd 100644 --- a/modules/websockets/pom.xml +++ b/modules/websockets/pom.xml @@ -21,13 +21,13 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 grizzly-websockets bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-websockets install diff --git a/pom.xml b/pom.xml index 49a532fd49..4521519ff0 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ org.glassfish.grizzly grizzly-bom - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 bom/pom.xml @@ -28,7 +28,7 @@ grizzly-project pom grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 http://grizzly.java.net GitHub @@ -441,6 +441,8 @@ false exclude-common.xml 1.8 - 1.9.payara-p1 + 1.9.payara-p1 + 1.9.payara-p1 + 1.1.4 diff --git a/samples/connection-pool-samples/pom.xml b/samples/connection-pool-samples/pom.xml index 714ceda89c..7d28b22adc 100755 --- a/samples/connection-pool-samples/pom.xml +++ b/samples/connection-pool-samples/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 org.glassfish.grizzly.samples connection-pool-samples bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 connection-pool-samples install diff --git a/samples/framework-samples/pom.xml b/samples/framework-samples/pom.xml index 724c49e0df..2d863d983e 100755 --- a/samples/framework-samples/pom.xml +++ b/samples/framework-samples/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 org.glassfish.grizzly.samples grizzly-framework-samples bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-framework-samples install diff --git a/samples/http-ajp-samples/pom.xml b/samples/http-ajp-samples/pom.xml index 4401848bda..aee7e9f4ef 100644 --- a/samples/http-ajp-samples/pom.xml +++ b/samples/http-ajp-samples/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 org.glassfish.grizzly.samples grizzly-http-ajp-samples bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-ajp-samples install diff --git a/samples/http-jaxws-samples/pom.xml b/samples/http-jaxws-samples/pom.xml index 000b8f99b3..2849c15927 100644 --- a/samples/http-jaxws-samples/pom.xml +++ b/samples/http-jaxws-samples/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 org.glassfish.grizzly.samples grizzly-http-jaxws-samples bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-jaxws-samples install diff --git a/samples/http-multipart-samples/pom.xml b/samples/http-multipart-samples/pom.xml index ae9677b6fd..41cb677a56 100644 --- a/samples/http-multipart-samples/pom.xml +++ b/samples/http-multipart-samples/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 org.glassfish.grizzly.samples grizzly-http-multipart-samples bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-multipart-samples install diff --git a/samples/http-samples/pom.xml b/samples/http-samples/pom.xml index 59a8118869..d9fb9dff57 100755 --- a/samples/http-samples/pom.xml +++ b/samples/http-samples/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 org.glassfish.grizzly.samples grizzly-http-samples bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-samples install diff --git a/samples/http-server-samples/pom.xml b/samples/http-server-samples/pom.xml index 32c1c96963..035e5f7a35 100644 --- a/samples/http-server-samples/pom.xml +++ b/samples/http-server-samples/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 org.glassfish.grizzly.samples grizzly-http-server-samples bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-http-server-samples install diff --git a/samples/pom.xml b/samples/pom.xml index f5533898e4..52eb262bbd 100755 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../pom.xml 4.0.0 org.glassfish.grizzly.samples grizzly-samples pom - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-samples framework-samples diff --git a/samples/portunif/pom.xml b/samples/portunif/pom.xml index 7ecff252b4..a1159b0a5c 100644 --- a/samples/portunif/pom.xml +++ b/samples/portunif/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 org.glassfish.grizzly.samples grizzly-portunif-samples bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-portunif-samples install diff --git a/samples/tls-sni-samples/pom.xml b/samples/tls-sni-samples/pom.xml index 6a7c91fada..6a065e3ff9 100644 --- a/samples/tls-sni-samples/pom.xml +++ b/samples/tls-sni-samples/pom.xml @@ -15,14 +15,14 @@ org.glassfish.grizzly grizzly-project - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 ../../pom.xml 4.0.0 org.glassfish.grizzly.samples grizzly-tls-sni-samples bundle - 2.4.4.payara-p4-SNAPSHOT + 2.4.4.payara-p4 grizzly-tls-sni-samples install