diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandler.java index 74cb910fbd..c4c4a4f28a 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientProtocolHandler.java @@ -81,7 +81,8 @@ public class WebSocketClientProtocolHandler extends WebSocketProtocolHandler { * Client protocol configuration. */ public WebSocketClientProtocolHandler(WebSocketClientProtocolConfig clientConfig) { - super(Objects.requireNonNull(clientConfig, "clientConfig").dropPongFrames()); + super(Objects.requireNonNull(clientConfig, "clientConfig").dropPongFrames(), + clientConfig.sendCloseFrame(), clientConfig.forceCloseTimeoutMillis()); this.handshaker = WebSocketClientHandshakerFactory.newHandshaker( clientConfig.webSocketUri(), clientConfig.version(), @@ -381,9 +382,5 @@ public class WebSocketClientProtocolHandler extends WebSocketProtocolHandler { ctx.pipeline().addBefore(ctx.name(), Utf8FrameValidator.class.getName(), new Utf8FrameValidator()); } - if (clientConfig.sendCloseFrame() != null) { - cp.addBefore(ctx.name(), WebSocketCloseFrameHandler.class.getName(), - new WebSocketCloseFrameHandler(clientConfig.sendCloseFrame(), clientConfig.forceCloseTimeoutMillis())); - } } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketCloseFrameHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketCloseFrameHandler.java deleted file mode 100644 index 5ec10f48a4..0000000000 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketCloseFrameHandler.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2019 The Netty Project - * - * The Netty Project licenses this file to you 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 io.netty.handler.codec.http.websocketx; - -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import io.netty.util.ReferenceCountUtil; -import io.netty.util.concurrent.ScheduledFuture; - -import java.nio.channels.ClosedChannelException; -import java.util.Objects; -import java.util.concurrent.TimeUnit; - -/** - * Send {@link CloseWebSocketFrame} message on channel close, if close frame was not sent before. - */ -final class WebSocketCloseFrameHandler implements ChannelHandler { - private final WebSocketCloseStatus closeStatus; - private final long forceCloseTimeoutMillis; - private ChannelPromise closeSent; - - WebSocketCloseFrameHandler(WebSocketCloseStatus closeStatus, long forceCloseTimeoutMillis) { - this.closeStatus = Objects.requireNonNull(closeStatus, "closeStatus"); - this.forceCloseTimeoutMillis = forceCloseTimeoutMillis; - } - - @Override - public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception { - if (!ctx.channel().isActive()) { - ctx.close(promise); - return; - } - if (closeSent == null) { - write(ctx, new CloseWebSocketFrame(closeStatus), ctx.newPromise()); - } - flush(ctx); - applyCloseSentTimeout(ctx); - closeSent.addListener((ChannelFutureListener) future -> ctx.close(promise)); - } - - @Override - public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - if (closeSent != null) { - ReferenceCountUtil.release(msg); - promise.setFailure(new ClosedChannelException()); - return; - } - if (msg instanceof CloseWebSocketFrame) { - promise = promise.unvoid(); - closeSent = promise; - } - ctx.write(msg, promise); - } - - private void applyCloseSentTimeout(ChannelHandlerContext ctx) { - if (closeSent.isDone() || forceCloseTimeoutMillis < 0) { - return; - } - - final ScheduledFuture timeoutTask = ctx.executor().schedule(() -> { - if (!closeSent.isDone()) { - closeSent.tryFailure(new WebSocketHandshakeException("send close frame timed out")); - } - }, forceCloseTimeoutMillis, TimeUnit.MILLISECONDS); - - closeSent.addListener((ChannelFutureListener) future -> timeoutTask.cancel(false)); - } -} diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java index bfbb719c48..17bba48df9 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java @@ -17,13 +17,20 @@ package io.netty.handler.codec.http.websocketx; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; import io.netty.handler.codec.MessageToMessageDecoder; +import io.netty.util.ReferenceCountUtil; +import io.netty.util.concurrent.ScheduledFuture; -import java.util.List; +import java.nio.channels.ClosedChannelException; +import java.util.concurrent.TimeUnit; abstract class WebSocketProtocolHandler extends MessageToMessageDecoder { private final boolean dropPongFrames; + private final WebSocketCloseStatus closeStatus; + private final long forceCloseTimeoutMillis; + private ChannelPromise closeSent; /** * Creates a new {@link WebSocketProtocolHandler} that will drop {@link PongWebSocketFrame}s. @@ -40,7 +47,15 @@ abstract class WebSocketProtocolHandler extends MessageToMessageDecoder ctx.close(promise)); + } + } + + @Override + public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + if (closeSent != null) { + ReferenceCountUtil.release(msg); + promise.setFailure(new ClosedChannelException()); + return; + } + if (msg instanceof CloseWebSocketFrame) { + promise = promise.unvoid(); + closeSent = promise; + } + ctx.write(msg, promise); + } + + private void applyCloseSentTimeout(ChannelHandlerContext ctx) { + if (closeSent.isDone() || forceCloseTimeoutMillis < 0) { + return; + } + + final ScheduledFuture timeoutTask = ctx.executor().schedule(() -> { + if (!closeSent.isDone()) { + closeSent.tryFailure(new WebSocketHandshakeException("send close frame timed out")); + } + }, forceCloseTimeoutMillis, TimeUnit.MILLISECONDS); + + closeSent.addListener(future -> timeoutTask.cancel(false)); + } + @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.fireExceptionCaught(cause); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java index 138bbec9c5..8c5fa7b4ce 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java @@ -109,7 +109,10 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler { * Server protocol configuration. */ public WebSocketServerProtocolHandler(WebSocketServerProtocolConfig serverConfig) { - super(Objects.requireNonNull(serverConfig, "serverConfig").dropPongFrames()); + super(Objects.requireNonNull(serverConfig, "serverConfig").dropPongFrames(), + serverConfig.sendCloseFrame(), + serverConfig.forceCloseTimeoutMillis() + ); this.serverConfig = serverConfig; } @@ -225,10 +228,6 @@ public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler { cp.addBefore(ctx.name(), Utf8FrameValidator.class.getName(), new Utf8FrameValidator()); } - if (serverConfig.sendCloseFrame() != null) { - cp.addBefore(ctx.name(), WebSocketCloseFrameHandler.class.getName(), - new WebSocketCloseFrameHandler(serverConfig.sendCloseFrame(), serverConfig.forceCloseTimeoutMillis())); - } } @Override