Not add ChannelHandler to ChannelPipeline once the pipeline was destroyed.
Motivation: ChannelPipeline will happily add a handler to a closed Channel's pipeline and will call handlerAdded(...) but will not call handlerRemoved(...). Modifications: Check if pipeline was destroyed and if so not add the handler at all but propergate an exception. Result: Fixes [#6768]
This commit is contained in:
parent
eee0ec3902
commit
4aa8002596
@ -67,6 +67,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
private Map<EventExecutorGroup, EventExecutor> childExecutors;
|
private Map<EventExecutorGroup, EventExecutor> childExecutors;
|
||||||
private MessageSizeEstimator.Handle estimatorHandle;
|
private MessageSizeEstimator.Handle estimatorHandle;
|
||||||
private boolean firstRegistration = true;
|
private boolean firstRegistration = true;
|
||||||
|
private boolean destroyed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the head of a linked list that is processed by {@link #callHandlerAddedForAllHandlers()} and so process
|
* This is the head of a linked list that is processed by {@link #callHandlerAddedForAllHandlers()} and so process
|
||||||
@ -138,6 +139,12 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkDestroyed(ChannelHandler handler) {
|
||||||
|
if (destroyed) {
|
||||||
|
throw new ChannelPipelineException("Channel already closed, can not add handler " + handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ChannelPipeline addFirst(String name, ChannelHandler handler) {
|
public final ChannelPipeline addFirst(String name, ChannelHandler handler) {
|
||||||
return addFirst(null, name, handler);
|
return addFirst(null, name, handler);
|
||||||
@ -147,6 +154,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
public final ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler) {
|
public final ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler) {
|
||||||
final AbstractChannelHandlerContext newCtx;
|
final AbstractChannelHandlerContext newCtx;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
checkDestroyed(handler);
|
||||||
checkMultiplicity(handler);
|
checkMultiplicity(handler);
|
||||||
name = filterName(name, handler);
|
name = filterName(name, handler);
|
||||||
|
|
||||||
@ -196,6 +204,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
|
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
|
||||||
final AbstractChannelHandlerContext newCtx;
|
final AbstractChannelHandlerContext newCtx;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
checkDestroyed(handler);
|
||||||
checkMultiplicity(handler);
|
checkMultiplicity(handler);
|
||||||
|
|
||||||
newCtx = newContext(group, filterName(name, handler), handler);
|
newCtx = newContext(group, filterName(name, handler), handler);
|
||||||
@ -246,6 +255,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
final AbstractChannelHandlerContext newCtx;
|
final AbstractChannelHandlerContext newCtx;
|
||||||
final AbstractChannelHandlerContext ctx;
|
final AbstractChannelHandlerContext ctx;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
checkDestroyed(handler);
|
||||||
checkMultiplicity(handler);
|
checkMultiplicity(handler);
|
||||||
name = filterName(name, handler);
|
name = filterName(name, handler);
|
||||||
ctx = getContextOrDie(baseName);
|
ctx = getContextOrDie(baseName);
|
||||||
@ -306,6 +316,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
final AbstractChannelHandlerContext ctx;
|
final AbstractChannelHandlerContext ctx;
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
checkDestroyed(handler);
|
||||||
checkMultiplicity(handler);
|
checkMultiplicity(handler);
|
||||||
name = filterName(name, handler);
|
name = filterName(name, handler);
|
||||||
ctx = getContextOrDie(baseName);
|
ctx = getContextOrDie(baseName);
|
||||||
@ -516,6 +527,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
|
|
||||||
final AbstractChannelHandlerContext newCtx;
|
final AbstractChannelHandlerContext newCtx;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
checkDestroyed(newHandler);
|
||||||
checkMultiplicity(newHandler);
|
checkMultiplicity(newHandler);
|
||||||
if (newName == null) {
|
if (newName == null) {
|
||||||
newName = generateName(newHandler);
|
newName = generateName(newHandler);
|
||||||
@ -838,6 +850,7 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
* See: https://github.com/netty/netty/issues/3156
|
* See: https://github.com/netty/netty/issues/3156
|
||||||
*/
|
*/
|
||||||
private synchronized void destroy() {
|
private synchronized void destroy() {
|
||||||
|
destroyed = true;
|
||||||
destroyUp(head.next, false);
|
destroyUp(head.next, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1073,6 +1073,38 @@ public class DefaultChannelPipelineTest {
|
|||||||
group.shutdownGracefully(0, 0, TimeUnit.SECONDS);
|
group.shutdownGracefully(0, 0, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandlerAfterClose() throws Exception {
|
||||||
|
EmbeddedChannel channel = new EmbeddedChannel();
|
||||||
|
channel.close().syncUninterruptibly();
|
||||||
|
|
||||||
|
assertFalse(channel.isActive());
|
||||||
|
|
||||||
|
final AtomicBoolean addedHandler = new AtomicBoolean();
|
||||||
|
final AtomicBoolean removedHandler = new AtomicBoolean();
|
||||||
|
|
||||||
|
ChannelPipeline pipeline = channel.pipeline();
|
||||||
|
try {
|
||||||
|
pipeline.addLast(new ChannelHandlerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
addedHandler.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
removedHandler.set(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fail();
|
||||||
|
} catch (ChannelPipelineException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(addedHandler.get());
|
||||||
|
assertFalse(removedHandler.get());
|
||||||
|
}
|
||||||
|
|
||||||
@Test(timeout = 3000)
|
@Test(timeout = 3000)
|
||||||
public void testVoidPromiseNotify() throws Throwable {
|
public void testVoidPromiseNotify() throws Throwable {
|
||||||
ChannelPipeline pipeline1 = new LocalChannel().pipeline();
|
ChannelPipeline pipeline1 = new LocalChannel().pipeline();
|
||||||
|
Loading…
Reference in New Issue
Block a user