From b4352785f32bce91fdc15cd5422a3c1f50ea2f61 Mon Sep 17 00:00:00 2001 From: Maksym Ostroverkhov Date: Thu, 17 Sep 2020 20:48:10 +0300 Subject: [PATCH 1/6] next development iteration --- README.md | 4 ++-- gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7b4f9a0..d5d1195 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ interface Http2WebSocketAcceptor { Http2WebSocketClientHandshaker handShaker = Http2WebSocketClientHandshaker.create(channel); Http2Headers headers = - new DefaultHttp2Headers().set("user-agent", "jauntsdn-websocket-http2-client/0.0.3"); + new DefaultHttp2Headers().set("user-agent", "jauntsdn-websocket-http2-client/0.1.0"); ChannelFuture handshakeFuture = /*http1 websocket handler*/ handShaker.handshake("/echo", headers, new EchoWebSocketHandler()); @@ -207,7 +207,7 @@ repositories { } dependencies { - implementation 'com.jauntsdn.netty:netty-websocket-http2:0.0.3' + implementation 'com.jauntsdn.netty:netty-websocket-http2:0.1.0' } ``` diff --git a/gradle.properties b/gradle.properties index b7d2aad..efdf423 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group=com.jauntsdn.netty -version=0.1.0 +version=0.1.1 googleJavaFormatPluginVersion=0.9 dependencyManagementPluginVersion=1.0.10.RELEASE From f016dd84832941fd10c8afd99d4bd4f6b35dfea6 Mon Sep 17 00:00:00 2001 From: Maksym Ostroverkhov Date: Fri, 18 Sep 2020 14:56:31 +0300 Subject: [PATCH 2/6] Make sure :protocol pseudoheader is added last, otherwise some implementations (e.g. libwebsockets based server) force close connection (#11) add libwebsockets.org/testserver/ client example --- lws_client.sh | 3 + netty-websocket-http2-example/build.gradle | 5 + .../websocketx/example/lwsclient/Main.java | 168 ++++++++++++++++++ .../Http2WebSocketClientHandshaker.java | 19 +- .../websocketx/Http2WebSocketProtocol.java | 5 +- .../websocketx/ProtocolHandshakeTest.java | 8 +- 6 files changed, 192 insertions(+), 16 deletions(-) create mode 100755 lws_client.sh create mode 100644 netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/lwsclient/Main.java diff --git a/lws_client.sh b/lws_client.sh new file mode 100755 index 0000000..309ec35 --- /dev/null +++ b/lws_client.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +./gradlew netty-websocket-http2-example:runLwsClient \ No newline at end of file diff --git a/netty-websocket-http2-example/build.gradle b/netty-websocket-http2-example/build.gradle index e0af2d6..b9a2243 100644 --- a/netty-websocket-http2-example/build.gradle +++ b/netty-websocket-http2-example/build.gradle @@ -36,3 +36,8 @@ task runChannelClient(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath main = "com.jauntsdn.netty.handler.codec.http2.websocketx.example.channelclient.Main" } + +task runLwsClient(type: JavaExec) { + classpath = sourceSets.main.runtimeClasspath + main = "com.jauntsdn.netty.handler.codec.http2.websocketx.example.lwsclient.Main" +} diff --git a/netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/lwsclient/Main.java b/netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/lwsclient/Main.java new file mode 100644 index 0000000..c6030a8 --- /dev/null +++ b/netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/lwsclient/Main.java @@ -0,0 +1,168 @@ +/* + * Copyright 2020 - present Maksym Ostroverkhov. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.jauntsdn.netty.handler.codec.http2.websocketx.example.lwsclient; + +import static io.netty.channel.ChannelHandler.Sharable; + +import com.jauntsdn.netty.handler.codec.http2.websocketx.Http2WebSocketClientHandler; +import com.jauntsdn.netty.handler.codec.http2.websocketx.Http2WebSocketClientHandshaker; +import com.jauntsdn.netty.handler.codec.http2.websocketx.example.Security; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketDecoderConfig; +import io.netty.handler.codec.http2.DefaultHttp2Headers; +import io.netty.handler.codec.http2.Http2FrameCodec; +import io.netty.handler.codec.http2.Http2FrameCodecBuilder; +import io.netty.handler.codec.http2.Http2Headers; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslHandler; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import io.netty.util.concurrent.ScheduledFuture; +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Main { + private static final Logger logger = LoggerFactory.getLogger(Main.class); + + public static void main(String[] args) throws Exception { + String host = System.getProperty("HOST", "libwebsockets.org"); + int port = Integer.parseInt(System.getProperty("PORT", "443")); + InetSocketAddress address = new InetSocketAddress(host, port); + + logger.info("\n==> libwebsockets.org websocket-over-http2 client\n"); + logger.info("\n==> Remote address: {}:{}", host, port); + logger.info("\n==> Dumb increment demo of https://libwebsockets.org/testserver/"); + + final SslContext sslContext = Security.clientSslContext(); + Channel channel = + new Bootstrap() + .group(new NioEventLoopGroup()) + .channel(NioSocketChannel.class) + .handler( + new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + SslHandler sslHandler = sslContext.newHandler(ch.alloc()); + Http2FrameCodecBuilder http2FrameCodecBuilder = + Http2FrameCodecBuilder.forClient(); + http2FrameCodecBuilder.initialSettings().initialWindowSize(1_000); + Http2FrameCodec http2FrameCodec = http2FrameCodecBuilder.build(); + Http2WebSocketClientHandler http2WebSocketClientHandler = + Http2WebSocketClientHandler.builder() + .decoderConfig( + WebSocketDecoderConfig.newBuilder() + .allowExtensions(true) + .allowMaskMismatch(true) + .build()) + .handshakeTimeoutMillis(15_000) + .compression(true) + .build(); + + ch.pipeline().addLast(sslHandler, http2FrameCodec, http2WebSocketClientHandler); + } + }) + .connect(address) + .sync() + .channel(); + + Http2WebSocketClientHandshaker handShaker = Http2WebSocketClientHandshaker.create(channel); + + Http2Headers headers = + new DefaultHttp2Headers().set("user-agent", "jauntsdn-websocket-http2-client/0.1.0"); + ChannelFuture handshake = + handShaker.handshake( + "/", "dumb-increment-protocol", headers, new WebSocketDumbIncrementHandler()); + + handshake.addListener(new WebSocketFutureListener()); + + Channel echoWebSocketChannel = handshake.channel(); + + EventLoopGroup eventLoop = echoWebSocketChannel.eventLoop(); + + echoWebSocketChannel.closeFuture().sync(); + logger.info("==> Websocket closed. Terminating client..."); + eventLoop.shutdownGracefully(); + logger.info("==> Client terminated"); + } + + @Sharable + private static class WebSocketDumbIncrementHandler + extends SimpleChannelInboundHandler { + private ScheduledFuture sendResetFuture; + private ScheduledFuture receiveReportFuture; + private int receiveCounter; + private int receiveValue; + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + sendResetFuture = + ctx.executor() + .scheduleAtFixedRate( + () -> { + ctx.writeAndFlush(new TextWebSocketFrame("reset\n")); + logger.info("==> Sent reset counter websocket frame"); + }, + 5_000, + 5_000, + TimeUnit.MILLISECONDS); + + receiveReportFuture = + ctx.executor() + .scheduleAtFixedRate( + () -> + logger.info( + "==> Received {} frames, latest value: {}", receiveCounter, receiveValue), + 1_000, + 1_000, + TimeUnit.MILLISECONDS); + + super.channelActive(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + sendResetFuture.cancel(true); + receiveReportFuture.cancel(true); + super.channelInactive(ctx); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame webSocketFrame) { + receiveValue = Integer.parseInt(webSocketFrame.text()); + receiveCounter++; + } + } + + private static class WebSocketFutureListener + implements GenericFutureListener> { + @Override + public void operationComplete(Future future) { + if (future.isSuccess()) { + logger.info("==> Websocket channel future success"); + } else { + logger.info("==> Websocket channel future error: {}", future.cause().toString()); + } + } + } +} diff --git a/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketClientHandshaker.java b/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketClientHandshaker.java index fd3c701..39c35e4 100644 --- a/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketClientHandshaker.java +++ b/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketClientHandshaker.java @@ -382,17 +382,18 @@ private void handshakeImmediate(Handshake handshake, boolean supportsWebSocket) int streamId = streamIdFactory.incrementAndGetNextStreamId(); webSocketsParent.register(streamId, webSocketChannel.setStreamId(streamId)); - String path = webSocketChannel.path(); String authority = authority(); + String path = webSocketChannel.path(); Http2Headers headers = - Http2WebSocketProtocol.extendedConnect() - .scheme(scheme) - .authority(authority) - .path(path) - /* sec-websocket-version=13 only */ - .set( - Http2WebSocketProtocol.HEADER_WEBSOCKET_VERSION_NAME, - Http2WebSocketProtocol.HEADER_WEBSOCKET_VERSION_VALUE); + Http2WebSocketProtocol.extendedConnect( + new DefaultHttp2Headers() + .scheme(scheme) + .authority(authority) + .path(path) + /* sec-websocket-version=13 only */ + .set( + Http2WebSocketProtocol.HEADER_WEBSOCKET_VERSION_NAME, + Http2WebSocketProtocol.HEADER_WEBSOCKET_VERSION_VALUE)); /*compression*/ PerMessageDeflateClientExtensionHandshaker handshaker = compressionHandshaker; diff --git a/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketProtocol.java b/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketProtocol.java index 52a4c42..a9c1ddd 100644 --- a/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketProtocol.java +++ b/netty-websocket-http2/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/Http2WebSocketProtocol.java @@ -16,7 +16,6 @@ package com.jauntsdn.netty.handler.codec.http2.websocketx; -import io.netty.handler.codec.http2.DefaultHttp2Headers; import io.netty.handler.codec.http2.Http2Headers; import io.netty.util.AsciiString; @@ -38,8 +37,8 @@ final class Http2WebSocketProtocol { static final AsciiString HEADER_PROTOCOL_NAME_HANDSHAKED = AsciiString.of("x-protocol"); static final AsciiString HEADER_METHOD_CONNECT_HANDSHAKED = AsciiString.of("POST"); - static Http2Headers extendedConnect() { - return new DefaultHttp2Headers() + static Http2Headers extendedConnect(Http2Headers headers) { + return headers .method(Http2WebSocketProtocol.HEADER_METHOD_CONNECT) .set( Http2WebSocketProtocol.HEADER_PROTOCOL_NAME, diff --git a/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ProtocolHandshakeTest.java b/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ProtocolHandshakeTest.java index 3aad579..e7bd426 100644 --- a/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ProtocolHandshakeTest.java +++ b/netty-websocket-http2/src/test/java/com/jauntsdn/netty/handler/codec/http2/websocketx/ProtocolHandshakeTest.java @@ -196,7 +196,7 @@ void invalidWebSocketRequestRejected(Http2Headers invalidHttp2RequestHeaders) th static Stream invalidWebSocketRequests() { Http2Headers emptyPath = - Http2WebSocketProtocol.extendedConnect() + Http2WebSocketProtocol.extendedConnect(new DefaultHttp2Headers()) .scheme("https") .authority("localhost") .path("") @@ -206,7 +206,7 @@ static Stream invalidWebSocketRequests() { Http2WebSocketProtocol.HEADER_WEBSOCKET_VERSION_VALUE); Http2Headers emptyAuthority = - Http2WebSocketProtocol.extendedConnect() + Http2WebSocketProtocol.extendedConnect(new DefaultHttp2Headers()) .scheme("https") .authority("") .path("path") @@ -216,7 +216,7 @@ static Stream invalidWebSocketRequests() { Http2WebSocketProtocol.HEADER_WEBSOCKET_VERSION_VALUE); Http2Headers emptyScheme = - Http2WebSocketProtocol.extendedConnect() + Http2WebSocketProtocol.extendedConnect(new DefaultHttp2Headers()) .scheme("") .authority("localhost") .path("path") @@ -226,7 +226,7 @@ static Stream invalidWebSocketRequests() { Http2WebSocketProtocol.HEADER_WEBSOCKET_VERSION_VALUE); Http2Headers nonHttpScheme = - Http2WebSocketProtocol.extendedConnect() + Http2WebSocketProtocol.extendedConnect(new DefaultHttp2Headers()) .scheme("ftp") .authority("localhost") .path("path") From 7ffdc69597b6d2fe2edcb4b87375a14214119dfa Mon Sep 17 00:00:00 2001 From: Maksym Ostroverkhov Date: Fri, 18 Sep 2020 15:00:20 +0300 Subject: [PATCH 3/6] libwebsockets example: increment initial window size --- .../handler/codec/http2/websocketx/example/lwsclient/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/lwsclient/Main.java b/netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/lwsclient/Main.java index c6030a8..2d31ffc 100644 --- a/netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/lwsclient/Main.java +++ b/netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/lwsclient/Main.java @@ -66,7 +66,7 @@ protected void initChannel(SocketChannel ch) { SslHandler sslHandler = sslContext.newHandler(ch.alloc()); Http2FrameCodecBuilder http2FrameCodecBuilder = Http2FrameCodecBuilder.forClient(); - http2FrameCodecBuilder.initialSettings().initialWindowSize(1_000); + http2FrameCodecBuilder.initialSettings().initialWindowSize(10_000); Http2FrameCodec http2FrameCodec = http2FrameCodecBuilder.build(); Http2WebSocketClientHandler http2WebSocketClientHandler = Http2WebSocketClientHandler.builder() From efe9243333aa6dd398043b8236964c5894c45340 Mon Sep 17 00:00:00 2001 From: Maksym Ostroverkhov Date: Sun, 20 Sep 2020 16:54:19 +0300 Subject: [PATCH 4/6] [skip ci] readme --- README.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d5d1195..c749c04 100644 --- a/README.md +++ b/README.md @@ -103,8 +103,6 @@ Only verifies whether http2 stream is valid websocket, then passes it down the p Works with both callbacks-style `Http2ConnectionHandler` and frames based `Http2FrameCodec`. -Websocket requests rejected due to protocol violation are reported to `RejectedWebSocketListener` - ``` Http2WebSocketServerHandler.builder().handshakeOnly(rejectedWebSocketListener); ``` @@ -113,6 +111,24 @@ Runnable demo is available in `netty-websocket-http2-example` module - [handshakeserver](https://github.com/jauntsdn/netty-websocket-http2/blob/develop/netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/handshakeserver/Main.java), [channelclient](https://github.com/jauntsdn/netty-websocket-http2/blob/develop/netty-websocket-http2-example/src/main/java/com/jauntsdn/netty/handler/codec/http2/websocketx/example/channelclient/Main.java). +### configuration +Initial settings of server http2 codecs (`Http2ConnectionHandler` or `Http2FrameCodec`) should contain [SETTINGS_ENABLE_CONNECT_PROTOCOL=1](https://tools.ietf.org/html/rfc8441#section-9.1) +parameter to advertise websocket-over-http2 support. + +Also server http2 codecs must disable built-in headers validation because It is not compatible +with rfc8441 due to newly introduced `:protocol` pseudo-header. All websocket handlers provided by this library +do headers validation on their own - both for websocket and non-websocket requests. + +Above configuration may be done with utility methods of `Http2WebSocketServerBuilder` + +``` +public static Http2FrameCodecBuilder configureHttp2Server( + Http2FrameCodecBuilder http2Builder); + +public static Http2ConnectionHandlerBuilder configureHttp2Server( + Http2ConnectionHandlerBuilder http2Builder) +``` + ### compression & subprotocols Client and server `permessage-deflate` compression configuration is shared by all streams ```groovy @@ -135,7 +151,7 @@ ChannelFuture handshake = ```groovy Http2WebSocketServerHandler.builder() .handler("/echo", "subprotocol", http1WebSocketHandler) - .handler("/echo", "wamp", http1WebSocketWampHandler) + .handler("/echo", "wamp", http1WebSocketWampHandler); ``` ### lifecycle @@ -189,7 +205,8 @@ Currently blocked by [netty bug](https://github.com/netty/netty/issues/10416). with this library/browser as clients. * `channelserver, channelclient` packages for websocket subchannel API demos. * `handshakeserver, channelclient` packages for handshake only API demo. - +* `lwsclient` package for client demo that runs against [https://libwebsockets.org/testserver/](https://libwebsockets.org/testserver/) which hosts websocket-over-http2 +server implemented with [libwebsockets](https://github.com/warmcat/libwebsockets) - popular C-based networking library. ### browser example Both example servers have web page at `https://localhost:8099` that sends pings to `/echo` endpoint. From 390489b9bc5582d30ac54138159432fb3df0956c Mon Sep 17 00:00:00 2001 From: Maksym Ostroverkhov Date: Sun, 20 Sep 2020 17:11:06 +0300 Subject: [PATCH 5/6] update dependencies --- build.gradle | 2 +- gradle/publishing.gradle | 2 +- netty-websocket-http2-perftest/build.gradle | 2 +- .../dependency-locks/compileClasspath.lockfile | 2 +- settings.gradle | 14 +++++++------- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index c48e271..4efefc3 100644 --- a/build.gradle +++ b/build.gradle @@ -130,4 +130,4 @@ def projectVersion(project) { return project.version + versionSuffix } -defaultTasks 'clean', 'build' \ No newline at end of file +defaultTasks "clean", "build" \ No newline at end of file diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index 42d912b..c9a0098 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -76,7 +76,7 @@ subprojects { name = "sonatype" def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" - url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + url = version.endsWith("SNAPSHOT") ? snapshotsRepoUrl : releasesRepoUrl credentials { username = project.property("ossrhUsername") password = project.property("ossrhPassword") diff --git a/netty-websocket-http2-perftest/build.gradle b/netty-websocket-http2-perftest/build.gradle index 19e632d..b956125 100644 --- a/netty-websocket-http2-perftest/build.gradle +++ b/netty-websocket-http2-perftest/build.gradle @@ -16,7 +16,7 @@ description = "Netty based implementation of rfc8441 - bootstrapping websockets with http/2. Performance test project" -def nettyNativeTransportVersion = "4.1.51.Final" +def nettyNativeTransportVersion = "4.1.52.Final" dependencies { implementation project(":netty-websocket-http2") diff --git a/netty-websocket-http2-perftest/gradle/dependency-locks/compileClasspath.lockfile b/netty-websocket-http2-perftest/gradle/dependency-locks/compileClasspath.lockfile index 8bb410d..7ac95ed 100644 --- a/netty-websocket-http2-perftest/gradle/dependency-locks/compileClasspath.lockfile +++ b/netty-websocket-http2-perftest/gradle/dependency-locks/compileClasspath.lockfile @@ -11,7 +11,7 @@ io.netty:netty-common:4.1.52.Final io.netty:netty-handler:4.1.52.Final io.netty:netty-resolver:4.1.52.Final io.netty:netty-tcnative-boringssl-static:2.0.34.Final -io.netty:netty-transport-native-epoll:4.1.51.Final +io.netty:netty-transport-native-epoll:4.1.52.Final io.netty:netty-transport-native-unix-common:4.1.52.Final io.netty:netty-transport:4.1.52.Final org.hdrhistogram:HdrHistogram:2.1.12 diff --git a/settings.gradle b/settings.gradle index 400bee0..640ffe3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,15 +16,15 @@ pluginManagement { plugins { - id 'com.github.sherter.google-java-format' version "${googleJavaFormatPluginVersion}" - id 'io.spring.dependency-management' version "${dependencyManagementPluginVersion}" + id "com.github.sherter.google-java-format" version "${googleJavaFormatPluginVersion}" + id "io.spring.dependency-management" version "${dependencyManagementPluginVersion}" id "com.palantir.git-version" version "${gitPluginVersion}" - id 'com.google.osdetector' version "${osDetectorPluginVersion}" + id "com.google.osdetector" version "${osDetectorPluginVersion}" } } -rootProject.name = 'netty-websocket-http2-parent' -include 'netty-websocket-http2' -include 'netty-websocket-http2-example' -include 'netty-websocket-http2-perftest' +rootProject.name = "netty-websocket-http2-parent" +include "netty-websocket-http2" +include "netty-websocket-http2-example" +include "netty-websocket-http2-perftest" From 0b56492e702c9f33eb949e38328f46dea57f258b Mon Sep 17 00:00:00 2001 From: Maksym Ostroverkhov Date: Sun, 20 Sep 2020 17:40:06 +0300 Subject: [PATCH 6/6] prepare for 1.0.0 release --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index efdf423..35ab8d1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group=com.jauntsdn.netty -version=0.1.1 +version=1.0.0 googleJavaFormatPluginVersion=0.9 dependencyManagementPluginVersion=1.0.10.RELEASE