From a15213d751bf386678570d66f00812919ffcaf07 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Fri, 21 Sep 2012 22:08:12 +0200 Subject: [PATCH 01/29] Cleanup imports and add javadocs --- .../main/java/io/netty/channel/socket/SctpData.java | 3 ++- .../io/netty/channel/socket/SctpNotification.java | 11 +++++++++-- .../netty/channel/socket/SctpNotificationHandler.java | 1 - .../io/netty/channel/socket/oio/OioSctpChannel.java | 2 +- .../channel/socket/oio/OioSctpServerChannel.java | 2 -- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/transport/src/main/java/io/netty/channel/socket/SctpData.java b/transport/src/main/java/io/netty/channel/socket/SctpData.java index 25804872c0..123de98f9e 100644 --- a/transport/src/main/java/io/netty/channel/socket/SctpData.java +++ b/transport/src/main/java/io/netty/channel/socket/SctpData.java @@ -29,7 +29,7 @@ public final class SctpData implements SctpMessage { private final ByteBuf payloadBuffer; - private MessageInfo msgInfo; + private final MessageInfo msgInfo; /** * Essential data that is being carried within SCTP Data Chunk @@ -41,6 +41,7 @@ public final class SctpData implements SctpMessage { this.protocolIdentifier = protocolIdentifier; this.streamIdentifier = streamIdentifier; this.payloadBuffer = payloadBuffer; + this.msgInfo = null; } public SctpData(MessageInfo msgInfo, ByteBuf payloadBuffer) { diff --git a/transport/src/main/java/io/netty/channel/socket/SctpNotification.java b/transport/src/main/java/io/netty/channel/socket/SctpNotification.java index a02e4bac73..95fa304249 100644 --- a/transport/src/main/java/io/netty/channel/socket/SctpNotification.java +++ b/transport/src/main/java/io/netty/channel/socket/SctpNotification.java @@ -18,8 +18,8 @@ package io.netty.channel.socket; import com.sun.nio.sctp.Notification; public final class SctpNotification implements SctpMessage { - private Notification notification; - private Object attachment; + private final Notification notification; + private final Object attachment; public SctpNotification(Notification notification, Object attachment) { @@ -27,10 +27,17 @@ public final class SctpNotification implements SctpMessage { this.attachment = attachment; } + /** + * Return the {@link Notification} + */ public Notification notification() { return notification; } + /** + * Return the attachment of this {@link SctpNotification}, or + * null if no attachment was provided + */ public Object attachment() { return attachment; } diff --git a/transport/src/main/java/io/netty/channel/socket/SctpNotificationHandler.java b/transport/src/main/java/io/netty/channel/socket/SctpNotificationHandler.java index b409a027d5..103a317e60 100644 --- a/transport/src/main/java/io/netty/channel/socket/SctpNotificationHandler.java +++ b/transport/src/main/java/io/netty/channel/socket/SctpNotificationHandler.java @@ -22,7 +22,6 @@ import com.sun.nio.sctp.Notification; import com.sun.nio.sctp.PeerAddressChangeNotification; import com.sun.nio.sctp.SendFailedNotification; import com.sun.nio.sctp.ShutdownNotification; -import io.netty.channel.ChannelPipeline; public class SctpNotificationHandler extends AbstractNotificationHandler { diff --git a/transport/src/main/java/io/netty/channel/socket/oio/OioSctpChannel.java b/transport/src/main/java/io/netty/channel/socket/oio/OioSctpChannel.java index 7219ff2f1d..d9525696bf 100755 --- a/transport/src/main/java/io/netty/channel/socket/oio/OioSctpChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioSctpChannel.java @@ -52,7 +52,7 @@ public class OioSctpChannel extends AbstractOioMessageChannel private final SctpChannel ch; private final SctpChannelConfig config; - private final NotificationHandler notificationHandler; + private final NotificationHandler notificationHandler; private static SctpChannel openChannel() { try { diff --git a/transport/src/main/java/io/netty/channel/socket/oio/OioSctpServerChannel.java b/transport/src/main/java/io/netty/channel/socket/oio/OioSctpServerChannel.java index 5f31c9a507..11d0ebe30d 100755 --- a/transport/src/main/java/io/netty/channel/socket/oio/OioSctpServerChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioSctpServerChannel.java @@ -21,9 +21,7 @@ import io.netty.buffer.ChannelBufType; import io.netty.buffer.MessageBuf; import io.netty.channel.ChannelException; import io.netty.channel.ChannelMetadata; -import io.netty.channel.socket.DefaultSctpChannelConfig; import io.netty.channel.socket.DefaultSctpServerChannelConfig; -import io.netty.channel.socket.SctpNotificationHandler; import io.netty.channel.socket.SctpServerChannelConfig; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; From 93b34e385624afb786e008bf34c969226ac5e8ee Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Fri, 21 Sep 2012 22:33:11 +0200 Subject: [PATCH 02/29] Some more cleanup --- .../src/main/java/io/netty/channel/ChannelInitializer.java | 1 + .../src/main/java/io/netty/channel/DefaultChannelConfig.java | 2 ++ .../src/main/java/io/netty/channel/DefaultChannelPipeline.java | 2 ++ .../io/netty/channel/socket/DefaultDatagramChannelConfig.java | 3 +-- .../java/io/netty/channel/socket/DefaultSctpChannelConfig.java | 1 + .../netty/channel/socket/DefaultSctpServerChannelConfig.java | 2 +- .../netty/channel/socket/DefaultServerSocketChannelConfig.java | 1 + .../io/netty/channel/socket/DefaultSocketChannelConfig.java | 1 + .../netty/channel/socket/aio/AioServerSocketChannelConfig.java | 1 + .../io/netty/channel/socket/aio/AioSocketChannelConfig.java | 1 + 10 files changed, 12 insertions(+), 3 deletions(-) diff --git a/transport/src/main/java/io/netty/channel/ChannelInitializer.java b/transport/src/main/java/io/netty/channel/ChannelInitializer.java index 0ec4da0a17..a347e75eda 100644 --- a/transport/src/main/java/io/netty/channel/ChannelInitializer.java +++ b/transport/src/main/java/io/netty/channel/ChannelInitializer.java @@ -26,6 +26,7 @@ public abstract class ChannelInitializer extends ChannelState public abstract void initChannel(C ch) throws Exception; + @SuppressWarnings("unchecked") @Override public final void channelRegistered(ChannelHandlerContext ctx) throws Exception { diff --git a/transport/src/main/java/io/netty/channel/DefaultChannelConfig.java b/transport/src/main/java/io/netty/channel/DefaultChannelConfig.java index 9bb9b6f690..b7fd02ed60 100644 --- a/transport/src/main/java/io/netty/channel/DefaultChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/DefaultChannelConfig.java @@ -48,6 +48,7 @@ public class DefaultChannelConfig implements ChannelConfig { return result; } + @SuppressWarnings("unchecked") @Override public boolean setOptions(Map, ?> options) { if (options == null) { @@ -64,6 +65,7 @@ public class DefaultChannelConfig implements ChannelConfig { return setAllOptions; } + @SuppressWarnings("unchecked") @Override public T getOption(ChannelOption option) { if (option == null) { diff --git a/transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java b/transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java index bf6d4aea66..6231ac7796 100755 --- a/transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java +++ b/transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java @@ -388,6 +388,7 @@ public class DefaultChannelPipeline implements ChannelPipeline { return remove(getContextOrDie(name)).handler(); } + @SuppressWarnings("unchecked") @Override public T remove(Class handlerType) { return (T) remove(getContextOrDie(handlerType)).handler(); @@ -784,6 +785,7 @@ public class DefaultChannelPipeline implements ChannelPipeline { } } + @SuppressWarnings("unchecked") @Override public T get(Class handlerType) { ChannelHandlerContext ctx = context(handlerType); diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java index 665196a1b4..f1f9a1c2b5 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java @@ -61,6 +61,7 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement IP_MULTICAST_ADDR, IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_TOS, UDP_RECEIVE_PACKET_SIZE); } + @SuppressWarnings("unchecked") @Override public T getOption(ChannelOption option) { if (option == SO_BROADCAST) { @@ -82,12 +83,10 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement return (T) Boolean.valueOf(isLoopbackModeDisabled()); } if (option == IP_MULTICAST_ADDR) { - @SuppressWarnings("unchecked") T i = (T) getInterface(); return i; } if (option == IP_MULTICAST_IF) { - @SuppressWarnings("unchecked") T i = (T) getNetworkInterface(); return i; } diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultSctpChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultSctpChannelConfig.java index 03ab6d9ad0..fa0dbae987 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultSctpChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultSctpChannelConfig.java @@ -48,6 +48,7 @@ public class DefaultSctpChannelConfig extends DefaultChannelConfig implements Sc } + @SuppressWarnings("unchecked") @Override public T getOption(ChannelOption option) { if (option == SO_RCVBUF) { diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultSctpServerChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultSctpServerChannelConfig.java index c5d2c44bb5..fb7a87568a 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultSctpServerChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultSctpServerChannelConfig.java @@ -28,7 +28,6 @@ import java.util.Map; import static com.sun.nio.sctp.SctpStandardSocketOptions.SCTP_INIT_MAXSTREAMS; import static com.sun.nio.sctp.SctpStandardSocketOptions.SO_RCVBUF; import static com.sun.nio.sctp.SctpStandardSocketOptions.SO_SNDBUF; -import static io.netty.channel.ChannelOption.SCTP_NODELAY; /** * The default {@link SctpServerChannelConfig} implementation for SCTP. @@ -56,6 +55,7 @@ public class DefaultSctpServerChannelConfig extends DefaultChannelConfig impleme } + @SuppressWarnings("unchecked") @Override public T getOption(ChannelOption option) { if (option == ChannelOption.SO_RCVBUF) { diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultServerSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultServerSocketChannelConfig.java index 71ada68669..2d75c4fcf0 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultServerSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultServerSocketChannelConfig.java @@ -49,6 +49,7 @@ public class DefaultServerSocketChannelConfig extends DefaultChannelConfig return getOptions(super.getOptions(), SO_RCVBUF, SO_REUSEADDR, SO_BACKLOG); } + @SuppressWarnings("unchecked") @Override public T getOption(ChannelOption option) { if (option == SO_RCVBUF) { diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java index e900b68fee..9c1521e4a2 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultSocketChannelConfig.java @@ -51,6 +51,7 @@ public class DefaultSocketChannelConfig extends DefaultChannelConfig ALLOW_HALF_CLOSURE); } + @SuppressWarnings("unchecked") @Override public T getOption(ChannelOption option) { if (option == SO_RCVBUF) { diff --git a/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannelConfig.java index 990e8172b5..d23dae7241 100644 --- a/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/aio/AioServerSocketChannelConfig.java @@ -45,6 +45,7 @@ final class AioServerSocketChannelConfig extends DefaultChannelConfig return getOptions(super.getOptions(), SO_RCVBUF, SO_REUSEADDR, SO_BACKLOG); } + @SuppressWarnings("unchecked") @Override public T getOption(ChannelOption option) { if (option == SO_RCVBUF) { diff --git a/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannelConfig.java index 3be37ea7a2..a03acb25d4 100644 --- a/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/aio/AioSocketChannelConfig.java @@ -57,6 +57,7 @@ final class AioSocketChannelConfig extends DefaultChannelConfig AIO_READ_TIMEOUT, AIO_WRITE_TIMEOUT, ALLOW_HALF_CLOSURE); } + @SuppressWarnings("unchecked") @Override public T getOption(ChannelOption option) { if (option == SO_RCVBUF) { From 256f55b2e9155caf2104e5dd3118e0d7277187a3 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sat, 22 Sep 2012 11:22:02 +0900 Subject: [PATCH 03/29] [#608] Channel MessageBridge concurrency issues Fixed ArrayIndexOutOfBoundsException caused by a race condition that the peer's inbound buffer is accessed concurrently. --- .../io/netty/channel/local/LocalChannel.java | 29 ++-- .../local/LocalTransportThreadModelTest2.java | 153 ++++++++++++++++++ 2 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest2.java diff --git a/transport/src/main/java/io/netty/channel/local/LocalChannel.java b/transport/src/main/java/io/netty/channel/local/LocalChannel.java index c36db6b588..576a708ceb 100755 --- a/transport/src/main/java/io/netty/channel/local/LocalChannel.java +++ b/transport/src/main/java/io/netty/channel/local/LocalChannel.java @@ -23,6 +23,7 @@ import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; +import io.netty.channel.ChannelPipeline; import io.netty.channel.DefaultChannelConfig; import io.netty.channel.EventLoop; import io.netty.channel.SingleThreadEventExecutor; @@ -215,16 +216,26 @@ public class LocalChannel extends AbstractChannel { } final LocalChannel peer = this.peer; - assert peer != null; + final ChannelPipeline peerPipeline = peer.pipeline(); + final EventLoop peerLoop = peer.eventLoop(); - buf.drainTo(peer.pipeline().inboundMessageBuffer()); - - peer.eventLoop().execute(new Runnable() { - @Override - public void run() { - peer.pipeline().fireInboundBufferUpdated(); - } - }); + if (peerLoop == eventLoop()) { + buf.drainTo(peerPipeline.inboundMessageBuffer()); + peerPipeline.fireInboundBufferUpdated(); + } else { + final Object msgs[] = buf.toArray(); + buf.clear(); + peerLoop.execute(new Runnable() { + @Override + public void run() { + MessageBuf buf = peerPipeline.inboundMessageBuffer(); + for (Object m: msgs) { + buf.add(m); + } + peerPipeline.fireInboundBufferUpdated(); + } + }); + } } @Override diff --git a/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest2.java b/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest2.java new file mode 100644 index 0000000000..87fdfe41ac --- /dev/null +++ b/transport/src/test/java/io/netty/channel/local/LocalTransportThreadModelTest2.java @@ -0,0 +1,153 @@ +/* + * Copyright 2012 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.channel.local; + +import static org.junit.Assert.*; +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.MessageBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundMessageHandlerAdapter; + +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +public class LocalTransportThreadModelTest2 { + + private static final String LOCAL_CHANNEL = LocalTransportThreadModelTest2.class.getName(); + + static final int messageCountPerRun = 4; + + @Test(timeout = 15000) + public void testSocketReuse() throws InterruptedException { + ServerBootstrap serverBootstrap = new ServerBootstrap(); + LocalHander serverHandler = new LocalHander("SERVER"); + serverBootstrap + .group(new LocalEventLoopGroup(), new LocalEventLoopGroup()) + .channel(LocalServerChannel.class) + .localAddress(new LocalAddress(LOCAL_CHANNEL)) + .childHandler(serverHandler); + + Bootstrap clientBootstrap = new Bootstrap(); + LocalHander clientHandler = new LocalHander("CLIENT"); + clientBootstrap + .group(new LocalEventLoopGroup()) + .channel(LocalChannel.class) + .remoteAddress(new LocalAddress(LOCAL_CHANNEL)).handler(clientHandler); + + serverBootstrap.bind().sync(); + + int count = 100; + for (int i = 1; i < count + 1; i ++) { + Channel ch = clientBootstrap.connect().sync().channel(); + + // SPIN until we get what we are looking for. + int target = i * messageCountPerRun; + while (serverHandler.count.get() != target || clientHandler.count.get() != target) { + Thread.sleep(50); + } + close(ch, clientHandler); + } + + assertEquals(count * 2 * messageCountPerRun, serverHandler.count.get() + + clientHandler.count.get()); + } + + public void close(final Channel localChannel, final LocalHander localRegistrationHandler) { + // we want to make sure we actually shutdown IN the event loop + if (localChannel.eventLoop().inEventLoop()) { + MessageBuf outboundMessageBuffer = + localChannel.pipeline().outboundMessageBuffer(); + if (!outboundMessageBuffer.isEmpty()) { + System.err.println("NOT EMPTY TO SEND!"); + } + + // Wait until all messages are flushed before closing the channel. + if (localRegistrationHandler.lastWriteFuture != null) { + localRegistrationHandler.lastWriteFuture.awaitUninterruptibly(); + } + + MessageBuf inboundMessageBuffer = + localChannel.pipeline().inboundMessageBuffer(); + if (!inboundMessageBuffer.isEmpty()) { + // sometimes we close the pipeline before everything on it has been notified/received. + // we want these messages, since they are in our queue. + Iterator iterator = inboundMessageBuffer.iterator(); + while (iterator.hasNext()) { + Object next = iterator.next(); + System.err.println("DEFERRED on close: " + next); + iterator.remove(); + } + } + + localChannel.close(); + return; + } else { + localChannel.eventLoop().execute(new Runnable() { + @Override + public void run() { + close(localChannel, localRegistrationHandler); + } + }); + } + + // Wait until the connection is closed or the connection attempt fails. + localChannel.closeFuture().awaitUninterruptibly(); + + MessageBuf inboundMessageBuffer = localChannel.pipeline().inboundMessageBuffer(); + if (!inboundMessageBuffer.isEmpty()) { + // sometimes we close the pipeline before everything on it has been notified/received. + // we want these messages, since they are in our queue. + Iterator iterator = inboundMessageBuffer.iterator(); + while (iterator.hasNext()) { + Object next = iterator.next(); + System.err.println("DEFERRED on close: " + next); + iterator.remove(); + } + } + } + + @Sharable + class LocalHander extends ChannelInboundMessageHandlerAdapter { + private final String name; + + public volatile ChannelFuture lastWriteFuture = null; + + public AtomicInteger count = new AtomicInteger(0); + + public LocalHander(String name) { + this.name = name; + + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + for (int i = 0; i < messageCountPerRun; i ++) { + lastWriteFuture = ctx.channel().write(name + " " + i); + } + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { + count.incrementAndGet(); + } + } +} \ No newline at end of file From 0b71afb81c59036c9a345f67de4f902a4e7492c3 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sat, 22 Sep 2012 12:05:00 +0900 Subject: [PATCH 04/29] Improve the stability of ServerSocketSuspendTest --- .../transport/socket/ServerSocketSuspendTest.java | 4 ++++ .../main/java/io/netty/bootstrap/ServerBootstrap.java | 10 +++++----- .../main/java/io/netty/channel/AbstractChannel.java | 9 +++++++++ transport/src/main/java/io/netty/channel/Channel.java | 6 ++++++ .../io/netty/channel/socket/oio/OioEventLoopGroup.java | 2 +- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java index cfcd8db9d6..32557291cf 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java @@ -72,15 +72,19 @@ public class ServerSocketSuspendTest extends AbstractServerSocketTest { } } + Thread.sleep(TIMEOUT / 1000000); + try { long startTime = System.nanoTime(); for (int i = 0; i < NUM_CHANNELS; i ++) { + System.err.println(i + ": " + System.currentTimeMillis()); Socket s = new Socket(); s.connect(addr, 10000); sockets.add(s); } long endTime = System.nanoTime(); + System.err.println(endTime - startTime); Assert.assertTrue(endTime - startTime < TIMEOUT); } finally { for (Socket s: sockets) { diff --git a/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java b/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java index c57b4b2afc..c7fce485bc 100644 --- a/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java +++ b/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java @@ -17,17 +17,16 @@ package io.netty.bootstrap; import io.netty.buffer.MessageBuf; import io.netty.buffer.Unpooled; - import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelInboundMessageHandler; import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInboundMessageHandler; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.ServerChannel; import io.netty.channel.socket.SocketChannel; @@ -232,6 +231,7 @@ public class ServerBootstrap extends AbstractBootstrap { try { childGroup.register(child); } catch (Throwable t) { + child.unsafe().closeForcibly(); logger.warn("Failed to register an accepted channel: " + child, t); } } diff --git a/transport/src/main/java/io/netty/channel/AbstractChannel.java b/transport/src/main/java/io/netty/channel/AbstractChannel.java index 46096f882d..49d854f82c 100644 --- a/transport/src/main/java/io/netty/channel/AbstractChannel.java +++ b/transport/src/main/java/io/netty/channel/AbstractChannel.java @@ -547,6 +547,15 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha } } + @Override + public final void closeForcibly() { + try { + doClose(); + } catch (Exception e) { + logger.warn("Failed to close a channel.", e); + } + } + @Override public final void deregister(final ChannelFuture future) { if (eventLoop().inEventLoop()) { diff --git a/transport/src/main/java/io/netty/channel/Channel.java b/transport/src/main/java/io/netty/channel/Channel.java index 788daedce8..ea0d3e6969 100755 --- a/transport/src/main/java/io/netty/channel/Channel.java +++ b/transport/src/main/java/io/netty/channel/Channel.java @@ -248,6 +248,12 @@ public interface Channel extends AttributeMap, ChannelOutboundInvoker, ChannelFu */ void close(ChannelFuture future); + /** + * Closes the {@link Channel} immediately without firing any events. Probably only useful + * when registration attempt failed. + */ + void closeForcibly(); + /** * Deregister the {@link Channel} of the {@link ChannelFuture} from {@link EventLoop} and notify the * {@link ChannelFuture} once the operation was complete. diff --git a/transport/src/main/java/io/netty/channel/socket/oio/OioEventLoopGroup.java b/transport/src/main/java/io/netty/channel/socket/oio/OioEventLoopGroup.java index d2232cadfe..75e65d8056 100644 --- a/transport/src/main/java/io/netty/channel/socket/oio/OioEventLoopGroup.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioEventLoopGroup.java @@ -19,9 +19,9 @@ package io.netty.channel.socket.oio; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelTaskScheduler; import io.netty.channel.EventLoop; import io.netty.channel.EventLoopGroup; -import io.netty.channel.ChannelTaskScheduler; import java.util.Collections; import java.util.Queue; From 7c75dfb456823e510fe49b32f1ca89d26f701ea1 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sat, 22 Sep 2012 12:08:58 +0900 Subject: [PATCH 05/29] Remove System.err.printlns --- .../testsuite/transport/socket/ServerSocketSuspendTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java index 32557291cf..41124a5e1c 100644 --- a/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/ServerSocketSuspendTest.java @@ -77,14 +77,12 @@ public class ServerSocketSuspendTest extends AbstractServerSocketTest { try { long startTime = System.nanoTime(); for (int i = 0; i < NUM_CHANNELS; i ++) { - System.err.println(i + ": " + System.currentTimeMillis()); Socket s = new Socket(); s.connect(addr, 10000); sockets.add(s); } long endTime = System.nanoTime(); - System.err.println(endTime - startTime); Assert.assertTrue(endTime - startTime < TIMEOUT); } finally { for (Socket s: sockets) { From cf7a55106ca824fdc31ab6fc6f22a7909a93508f Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sat, 22 Sep 2012 12:09:45 +0900 Subject: [PATCH 06/29] Fix checkstyle violation --- .../src/main/java/io/netty/channel/local/LocalChannel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transport/src/main/java/io/netty/channel/local/LocalChannel.java b/transport/src/main/java/io/netty/channel/local/LocalChannel.java index 576a708ceb..9b86ca75e1 100755 --- a/transport/src/main/java/io/netty/channel/local/LocalChannel.java +++ b/transport/src/main/java/io/netty/channel/local/LocalChannel.java @@ -223,7 +223,7 @@ public class LocalChannel extends AbstractChannel { buf.drainTo(peerPipeline.inboundMessageBuffer()); peerPipeline.fireInboundBufferUpdated(); } else { - final Object msgs[] = buf.toArray(); + final Object[] msgs = buf.toArray(); buf.clear(); peerLoop.execute(new Runnable() { @Override From b8ae8be96a24dc5c40ae01b184638a9d6f9a3fb9 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Sat, 22 Sep 2012 21:23:58 +0200 Subject: [PATCH 07/29] Fix IndexOutOfBoundException when using CompositeChannelBuffer and the readerIndex is at the last position and an empty array is passed to read to. See #474 --- .../netty/buffer/DefaultCompositeByteBuf.java | 47 ++++++++++++++----- .../AbstractCompositeChannelBufferTest.java | 7 +++ 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java b/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java index 96c8036c55..860925f506 100644 --- a/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java @@ -578,14 +578,19 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit @Override public void getBytes(int index, byte[] dst, int dstIndex, int length) { - int componentId = toComponentIndex(index); if (index > capacity() - length || dstIndex > dst.length - length) { throw new IndexOutOfBoundsException("Too many bytes to read - Needs " + (index + length) + ", maximum is " + capacity() + " or " + dst.length); } + if (index < 0) { + throw new IndexOutOfBoundsException("index must be >= 0"); + } + if (length == 0) { + return; + } + int i = toComponentIndex(index); - int i = componentId; while (length > 0) { Component c = components.get(i); ByteBuf s = c.buf; @@ -601,15 +606,20 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit @Override public void getBytes(int index, ByteBuffer dst) { - int componentId = toComponentIndex(index); int limit = dst.limit(); int length = dst.remaining(); + if (index > capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to be read - Needs " + (index + length) + ", maximum is " + capacity()); } - - int i = componentId; + if (index < 0) { + throw new IndexOutOfBoundsException("index must be >= 0"); + } + if (length == 0) { + return; + } + int i = toComponentIndex(index); try { while (length > 0) { Component c = components.get(i); @@ -629,14 +639,18 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit @Override public void getBytes(int index, ByteBuf dst, int dstIndex, int length) { - int componentId = toComponentIndex(index); if (index > capacity() - length || dstIndex > dst.capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to be read - Needs " + (index + length) + " or " + (dstIndex + length) + ", maximum is " + capacity() + " or " + dst.capacity()); } - - int i = componentId; + if (index < 0) { + throw new IndexOutOfBoundsException("index must be >= 0"); + } + if (length == 0) { + return; + } + int i = toComponentIndex(index); while (length > 0) { Component c = components.get(i); ByteBuf s = c.buf; @@ -670,13 +684,18 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit @Override public void getBytes(int index, OutputStream out, int length) throws IOException { - int componentId = toComponentIndex(index); if (index > capacity() - length) { throw new IndexOutOfBoundsException("Too many bytes to be read - needs " + (index + length) + ", maximum of " + capacity()); } + if (index < 0) { + throw new IndexOutOfBoundsException("index must be >= 0"); + } + if (length == 0) { + return; + } - int i = componentId; + int i = toComponentIndex(index); while (length > 0) { Component c = components.get(i); ByteBuf s = c.buf; @@ -1031,11 +1050,17 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit @Override public ByteBuffer[] nioBuffers(int index, int length) { - int componentId = toComponentIndex(index); if (index + length > capacity()) { throw new IndexOutOfBoundsException("Too many bytes to convert - Needs" + (index + length) + ", maximum is " + capacity()); } + if (index < 0) { + throw new IndexOutOfBoundsException("index must be >= 0"); + } + if (length == 0) { + return new ByteBuffer[0]; + } + int componentId = toComponentIndex(index); List buffers = new ArrayList(components.size()); diff --git a/buffer/src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java index 2900336c25..b73513e358 100644 --- a/buffer/src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java +++ b/buffer/src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java @@ -410,4 +410,11 @@ public abstract class AbstractCompositeChannelBufferTest extends wrappedBuffer(new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5).order(order)); assertFalse(ByteBufUtil.equals(a, b)); } + + @Test + public void testEmptyBuffer() { + ByteBuf b = wrappedBuffer(new byte[] {1, 2}, new byte[] {3, 4}); + b.readBytes(new byte[4]); + b.readBytes(new byte[0]); + } } From 0f0479547df4d1da6ab5085fcee56600e4826847 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sun, 23 Sep 2012 15:40:37 +0900 Subject: [PATCH 08/29] Upgrade to netty-build 10 --- all/pom.xml | 7 +++++++ pom.xml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/all/pom.xml b/all/pom.xml index a85be0c8d4..f9c3d23ae9 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -259,6 +259,13 @@ Netty Source Xref (${project.version}) Netty Source Xref (${project.version}) + + + ${project.groupId} + netty-build + 10 + + maven-javadoc-plugin diff --git a/pom.xml b/pom.xml index 20cbf96dc6..e60b40d424 100644 --- a/pom.xml +++ b/pom.xml @@ -318,7 +318,7 @@ ${project.groupId} netty-build - 9 + 10 From a156f67804f5a55cc1673ed298cec4f8defd534c Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sun, 23 Sep 2012 17:01:31 +0900 Subject: [PATCH 09/29] [#624] Add varargs constructor to MessageToByteEncoder, MessageToMessage(Encoder|Decoder|Codec) to implement default isEncodable/isDecodable() .. and modify all their subtypes to take advantage of this improvement. --- .../codec/http/HttpChunkAggregator.java | 7 +--- .../codec/http/HttpContentDecoder.java | 6 +-- .../codec/http/HttpContentEncoder.java | 13 ++----- .../codec/http/HttpMessageEncoder.java | 6 +-- .../websocketx/WebSocket00FrameEncoder.java | 5 +-- .../websocketx/WebSocket08FrameEncoder.java | 9 ++--- .../handler/codec/spdy/SpdyFrameEncoder.java | 7 +--- .../handler/codec/spdy/SpdyHttpDecoder.java | 2 + .../handler/codec/spdy/SpdyHttpEncoder.java | 9 +---- .../codec/spdy/SpdySessionHandler.java | 14 +------ .../io/netty/handler/codec/CodecUtil.java | 37 +++++++++++++++++++ .../handler/codec/LengthFieldPrepender.java | 7 +--- .../handler/codec/MessageToByteEncoder.java | 8 +++- .../handler/codec/MessageToMessageCodec.java | 17 ++++++++- .../codec/MessageToMessageDecoder.java | 8 +++- .../codec/MessageToMessageEncoder.java | 8 +++- .../handler/codec/base64/Base64Decoder.java | 7 +--- .../handler/codec/base64/Base64Encoder.java | 7 +--- .../handler/codec/bytes/ByteArrayDecoder.java | 5 +-- .../handler/codec/bytes/ByteArrayEncoder.java | 9 ++--- .../codec/protobuf/ProtobufDecoder.java | 7 +--- .../codec/protobuf/ProtobufEncoder.java | 5 +-- .../ProtobufVarint32LengthFieldPrepender.java | 6 +-- .../CompatibleObjectEncoder.java | 7 +--- .../codec/serialization/ObjectEncoder.java | 5 +-- .../handler/codec/string/StringDecoder.java | 7 +--- .../handler/codec/string/StringEncoder.java | 11 ++---- .../example/factorial/NumberEncoder.java | 4 ++ 28 files changed, 123 insertions(+), 120 deletions(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java index e175ffcdb9..c61bcd2ebb 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java @@ -66,6 +66,8 @@ public class HttpChunkAggregator extends MessageToMessageDecoder[] { HttpMessage.class }, + new Class[] { HttpMessage.class, HttpChunk.class }); } @Override @@ -74,11 +72,6 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec { * Creates a new instance. */ protected HttpMessageEncoder() { - } - - @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof HttpMessage || msg instanceof HttpChunk; + super(HttpMessage.class, HttpChunk.class); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java index 81d5cd1686..431d40c372 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java @@ -32,9 +32,8 @@ import io.netty.handler.codec.MessageToByteEncoder; @Sharable public class WebSocket00FrameEncoder extends MessageToByteEncoder { - @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof WebSocketFrame; + public WebSocket00FrameEncoder() { + super(WebSocketFrame.class); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameEncoder.java index 1d77385229..937035b447 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameEncoder.java @@ -90,17 +90,14 @@ public class WebSocket08FrameEncoder extends MessageToByteEncoder { * Creates a new instance with the specified parameters. */ public SpdyFrameEncoder(int version, int compressionLevel, int windowBits, int memLevel) { + super(SpdyDataFrame.class, SpdyControlFrame.class); + if (version < SpdyConstants.SPDY_MIN_VERSION || version > SpdyConstants.SPDY_MAX_VERSION) { throw new IllegalArgumentException( "unknown version: " + version); @@ -74,11 +76,6 @@ public class SpdyFrameEncoder extends MessageToByteEncoder { }); } - @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof SpdyDataFrame || msg instanceof SpdyControlFrame; - } - @Override public void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { if (msg instanceof SpdyDataFrame) { diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpDecoder.java index be61fc7ee1..d72aaf6cce 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpDecoder.java @@ -52,6 +52,8 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder SpdyConstants.SPDY_MAX_VERSION) { throw new IllegalArgumentException( "unsupported version: " + version); diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java index c413c09cbf..5ea2067883 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java @@ -129,6 +129,8 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder { * @param version the protocol version */ public SpdyHttpEncoder(int version) { + super(HttpMessage.class, HttpChunk.class); + if (version < SpdyConstants.SPDY_MIN_VERSION || version > SpdyConstants.SPDY_MAX_VERSION) { throw new IllegalArgumentException( "unsupported version: " + version); @@ -136,13 +138,6 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder { spdyVersion = version; } - @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof HttpRequest || - msg instanceof HttpResponse || - msg instanceof HttpChunk; - } - @Override public Object encode(ChannelHandlerContext ctx, Object msg) throws Exception { diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java index 145c987601..57d8d969f2 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java @@ -103,19 +103,7 @@ public class SpdySessionHandler break; } - if (msg instanceof SpdyDataFrame || - msg instanceof SpdySynStreamFrame || - msg instanceof SpdySynReplyFrame || - msg instanceof SpdyRstStreamFrame || - msg instanceof SpdySettingsFrame || - msg instanceof SpdyPingFrame || - msg instanceof SpdyGoAwayFrame || - msg instanceof SpdyHeadersFrame || - msg instanceof SpdyWindowUpdateFrame) { - handleInboundMessage(ctx, msg); - } else { - ctx.nextInboundMessageBuffer().add(msg); - } + handleInboundMessage(ctx, msg); } ctx.fireInboundBufferUpdated(); } diff --git a/codec/src/main/java/io/netty/handler/codec/CodecUtil.java b/codec/src/main/java/io/netty/handler/codec/CodecUtil.java index 43d8c76723..de26a0e266 100644 --- a/codec/src/main/java/io/netty/handler/codec/CodecUtil.java +++ b/codec/src/main/java/io/netty/handler/codec/CodecUtil.java @@ -82,6 +82,43 @@ final class CodecUtil { msg.getClass().getSimpleName())); } + private static final Class[] EMPTY_TYPES = new Class[0]; + + static Class[] acceptedMessageTypes(Class[] acceptedMsgTypes) { + if (acceptedMsgTypes == null) { + return EMPTY_TYPES; + } + + int numElem = 0; + for (Class c: acceptedMsgTypes) { + if (c == null) { + break; + } + numElem ++; + } + + Class[] newAllowedMsgTypes = new Class[numElem]; + for (int i = 0; i < numElem; i ++) { + newAllowedMsgTypes[i] = acceptedMsgTypes[i]; + } + + return newAllowedMsgTypes; + } + + static boolean acceptMessage(Class[] acceptedMsgTypes, Object msg) { + if (acceptedMsgTypes.length == 0) { + return true; + } + + for (Class c: acceptedMsgTypes) { + if (c.isInstance(msg)) { + return true; + } + } + + return false; + } + private CodecUtil() { // Unused } diff --git a/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java b/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java index 46763ea5f4..83cceab485 100644 --- a/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java +++ b/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java @@ -83,6 +83,8 @@ public class LengthFieldPrepender extends MessageToByteEncoder { */ public LengthFieldPrepender( int lengthFieldLength, boolean lengthIncludesLengthFieldLength) { + super(ByteBuf.class); + if (lengthFieldLength != 1 && lengthFieldLength != 2 && lengthFieldLength != 3 && lengthFieldLength != 4 && lengthFieldLength != 8) { @@ -95,11 +97,6 @@ public class LengthFieldPrepender extends MessageToByteEncoder { this.lengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength; } - @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof ByteBuf; - } - @Override public void encode( ChannelHandlerContext ctx, diff --git a/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java b/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java index 567ac9f0b7..92b0536485 100644 --- a/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/MessageToByteEncoder.java @@ -23,6 +23,12 @@ import io.netty.channel.ChannelOutboundMessageHandlerAdapter; public abstract class MessageToByteEncoder extends ChannelOutboundMessageHandlerAdapter { + private final Class[] acceptedMsgTypes; + + protected MessageToByteEncoder(Class... acceptedMsgTypes) { + this.acceptedMsgTypes = CodecUtil.acceptedMessageTypes(acceptedMsgTypes); + } + @Override public void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception { MessageBuf in = ctx.outboundMessageBuffer(); @@ -61,7 +67,7 @@ public abstract class MessageToByteEncoder extends ChannelOutboundMessageHand * @param msg the message */ public boolean isEncodable(Object msg) throws Exception { - return true; + return CodecUtil.acceptMessage(acceptedMsgTypes, msg); } public abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception; diff --git a/codec/src/main/java/io/netty/handler/codec/MessageToMessageCodec.java b/codec/src/main/java/io/netty/handler/codec/MessageToMessageCodec.java index 8ff57491bb..d86e6c5cfe 100644 --- a/codec/src/main/java/io/netty/handler/codec/MessageToMessageCodec.java +++ b/codec/src/main/java/io/netty/handler/codec/MessageToMessageCodec.java @@ -53,6 +53,19 @@ public abstract class MessageToMessageCodec[] acceptedInboundMsgTypes; + private final Class[] acceptedOutboundMsgTypes; + + protected MessageToMessageCodec() { + this(null, null); + } + + protected MessageToMessageCodec( + Class[] acceptedInboundMsgTypes, Class[] acceptedOutboundMsgTypes) { + this.acceptedInboundMsgTypes = CodecUtil.acceptedMessageTypes(acceptedInboundMsgTypes); + this.acceptedOutboundMsgTypes = CodecUtil.acceptedMessageTypes(acceptedOutboundMsgTypes); + } + @Override public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { return decoder.newInboundBuffer(ctx); @@ -80,7 +93,7 @@ public abstract class MessageToMessageCodec extends ChannelInboundHandlerAdapter implements ChannelInboundMessageHandler { + private final Class[] acceptedMsgTypes; + + protected MessageToMessageDecoder(Class... acceptedMsgTypes) { + this.acceptedMsgTypes = CodecUtil.acceptedMessageTypes(acceptedMsgTypes); + } + @Override public MessageBuf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { return Unpooled.messageBuffer(); @@ -77,7 +83,7 @@ public abstract class MessageToMessageDecoder * @param msg the message */ public boolean isDecodable(Object msg) throws Exception { - return true; + return CodecUtil.acceptMessage(acceptedMsgTypes, msg); } public abstract O decode(ChannelHandlerContext ctx, I msg) throws Exception; diff --git a/codec/src/main/java/io/netty/handler/codec/MessageToMessageEncoder.java b/codec/src/main/java/io/netty/handler/codec/MessageToMessageEncoder.java index 3b22fc6c3d..cbc0be41ee 100644 --- a/codec/src/main/java/io/netty/handler/codec/MessageToMessageEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/MessageToMessageEncoder.java @@ -22,6 +22,12 @@ import io.netty.channel.ChannelOutboundMessageHandlerAdapter; public abstract class MessageToMessageEncoder extends ChannelOutboundMessageHandlerAdapter { + private final Class[] acceptedMsgTypes; + + protected MessageToMessageEncoder(Class... acceptedMsgTypes) { + this.acceptedMsgTypes = CodecUtil.acceptedMessageTypes(acceptedMsgTypes); + } + @Override public void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception { MessageBuf in = ctx.outboundMessageBuffer(); @@ -65,7 +71,7 @@ public abstract class MessageToMessageEncoder extends ChannelOutboundMessa * @param msg the message */ public boolean isEncodable(Object msg) throws Exception { - return true; + return CodecUtil.acceptMessage(acceptedMsgTypes, msg); } public abstract O encode(ChannelHandlerContext ctx, I msg) throws Exception; diff --git a/codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java b/codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java index 985bcfdc12..e820483a4d 100644 --- a/codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java +++ b/codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java @@ -53,17 +53,14 @@ public class Base64Decoder extends MessageToMessageDecoder { } public Base64Decoder(Base64Dialect dialect) { + super(ByteBuf.class); + if (dialect == null) { throw new NullPointerException("dialect"); } this.dialect = dialect; } - @Override - public boolean isDecodable(Object msg) throws Exception { - return msg instanceof ByteBuf; - } - @Override public ByteBuf decode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { return Base64.decode(msg, msg.readerIndex(), msg.readableBytes(), dialect); diff --git a/codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java b/codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java index c90790f745..8d95fc9fba 100644 --- a/codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java +++ b/codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java @@ -54,6 +54,8 @@ public class Base64Encoder extends MessageToMessageEncoder { } public Base64Encoder(boolean breakLines, Base64Dialect dialect) { + super(ByteBuf.class); + if (dialect == null) { throw new NullPointerException("dialect"); } @@ -62,11 +64,6 @@ public class Base64Encoder extends MessageToMessageEncoder { this.dialect = dialect; } - @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof ByteBuf; - } - @Override public ByteBuf encode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { diff --git a/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java index 50f00a99b2..300dabe263 100644 --- a/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java @@ -49,9 +49,8 @@ import io.netty.handler.codec.MessageToMessageDecoder; */ public class ByteArrayDecoder extends MessageToMessageDecoder { - @Override - public boolean isDecodable(Object msg) throws Exception { - return msg instanceof ByteBuf; + public ByteArrayDecoder() { + super(ByteBuf.class); } @Override diff --git a/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java index 93e91567ec..87eb79112a 100644 --- a/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java @@ -51,14 +51,13 @@ import io.netty.handler.codec.MessageToMessageEncoder; */ public class ByteArrayEncoder extends MessageToMessageEncoder { - @Override - public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { - return Unpooled.messageBuffer(); + public ByteArrayEncoder() { + super(byte[].class); } @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof byte[]; + public MessageBuf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { + return Unpooled.messageBuffer(); } @Override diff --git a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java index 77b940e992..3320fc432e 100644 --- a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java @@ -74,6 +74,8 @@ public class ProtobufDecoder extends MessageToMessageDecoder { - @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof MessageLite || msg instanceof MessageLite.Builder; + public ProtobufEncoder() { + super(MessageLite.class, MessageLite.Builder.class); } @Override diff --git a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrepender.java b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrepender.java index 98ecb47113..0a5c89f120 100644 --- a/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrepender.java +++ b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrepender.java @@ -44,11 +44,7 @@ public class ProtobufVarint32LengthFieldPrepender extends MessageToByteEncoder { * the long term. */ public CompatibleObjectEncoder(int resetInterval) { + super(Serializable.class); + if (resetInterval < 0) { throw new IllegalArgumentException( "resetInterval: " + resetInterval); @@ -75,11 +77,6 @@ public class CompatibleObjectEncoder extends MessageToByteEncoder { return new ObjectOutputStream(out); } - @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof Serializable; - } - @Override public void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { Attribute oosAttr = ctx.attr(OOS); diff --git a/codec/src/main/java/io/netty/handler/codec/serialization/ObjectEncoder.java b/codec/src/main/java/io/netty/handler/codec/serialization/ObjectEncoder.java index 9205635990..96e620d622 100644 --- a/codec/src/main/java/io/netty/handler/codec/serialization/ObjectEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/serialization/ObjectEncoder.java @@ -39,9 +39,8 @@ import java.io.Serializable; public class ObjectEncoder extends MessageToByteEncoder { private static final byte[] LENGTH_PLACEHOLDER = new byte[4]; - @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof Serializable; + public ObjectEncoder() { + super(Serializable.class); } @Override diff --git a/codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java b/codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java index f8528cdac5..6e955f3e12 100644 --- a/codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java @@ -68,17 +68,14 @@ public class StringDecoder extends MessageToMessageDecoder { * Creates a new instance with the specified character set. */ public StringDecoder(Charset charset) { + super(ByteBuf.class); + if (charset == null) { throw new NullPointerException("charset"); } this.charset = charset; } - @Override - public boolean isDecodable(Object msg) throws Exception { - return msg instanceof ByteBuf; - } - @Override public String decode(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { return msg.toString(charset); diff --git a/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java b/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java index 795c6b46b4..91faa5c029 100644 --- a/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java @@ -50,7 +50,7 @@ import java.nio.charset.Charset; * @apiviz.landmark */ @Sharable -public class StringEncoder extends MessageToMessageEncoder { +public class StringEncoder extends MessageToMessageEncoder { // TODO Use CharsetEncoder instead. private final Charset charset; @@ -66,6 +66,8 @@ public class StringEncoder extends MessageToMessageEncoder { * Creates a new instance with the specified character set. */ public StringEncoder(Charset charset) { + super(CharSequence.class); + if (charset == null) { throw new NullPointerException("charset"); } @@ -73,12 +75,7 @@ public class StringEncoder extends MessageToMessageEncoder { } @Override - public boolean isEncodable(Object msg) throws Exception { - return msg instanceof String; - } - - @Override - public ByteBuf encode(ChannelHandlerContext ctx, String msg) throws Exception { + public ByteBuf encode(ChannelHandlerContext ctx, CharSequence msg) throws Exception { return Unpooled.copiedBuffer(msg, charset); } } diff --git a/example/src/main/java/io/netty/example/factorial/NumberEncoder.java b/example/src/main/java/io/netty/example/factorial/NumberEncoder.java index 4fcd80adbc..ebe79f3e9e 100644 --- a/example/src/main/java/io/netty/example/factorial/NumberEncoder.java +++ b/example/src/main/java/io/netty/example/factorial/NumberEncoder.java @@ -28,6 +28,10 @@ import java.math.BigInteger; */ public class NumberEncoder extends MessageToByteEncoder { + public NumberEncoder() { + super(Number.class); + } + @Override public void encode( ChannelHandlerContext ctx, Number msg, ByteBuf out) throws Exception { From d49d02ffe490f956126db37a1abf6f82858aeff5 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sun, 23 Sep 2012 17:25:24 +0900 Subject: [PATCH 10/29] [#610] alpha4: DefaultSctpServerChannelConfig options in current java 7 Fix a wrong signature in com.sun.nio.sctp.SctpServerChannel.setOption() --- .../src/main/java/com/sun/nio/sctp/SctpServerChannel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transport/src/main/java/com/sun/nio/sctp/SctpServerChannel.java b/transport/src/main/java/com/sun/nio/sctp/SctpServerChannel.java index eaf617e5f7..2b47d1daf3 100644 --- a/transport/src/main/java/com/sun/nio/sctp/SctpServerChannel.java +++ b/transport/src/main/java/com/sun/nio/sctp/SctpServerChannel.java @@ -30,13 +30,13 @@ public abstract class SctpServerChannel extends AbstractSelectableChannel { public static SctpServerChannel open() throws IOException { return null; } - + protected SctpServerChannel(SelectorProvider provider) { super(provider); } public abstract T getOption(SctpSocketOption name) throws IOException; - public abstract SctpChannel setOption(SctpSocketOption name, T value) throws IOException; + public abstract SctpServerChannel setOption(SctpSocketOption name, T value) throws IOException; public abstract Set getAllLocalAddresses() throws IOException; From a6bd91dce5da6eb8ae3ae2d1dd124f00aad042dc Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Sun, 23 Sep 2012 17:28:52 +0900 Subject: [PATCH 11/29] Sync the default select timeout with 3.x --- .../src/main/java/io/netty/channel/socket/nio/SelectorUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transport/src/main/java/io/netty/channel/socket/nio/SelectorUtil.java b/transport/src/main/java/io/netty/channel/socket/nio/SelectorUtil.java index 459fa06a8b..e47802ac62 100644 --- a/transport/src/main/java/io/netty/channel/socket/nio/SelectorUtil.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/SelectorUtil.java @@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit; final class SelectorUtil { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SelectorUtil.class); - static final long DEFAULT_SELECT_TIMEOUT = 10; + static final long DEFAULT_SELECT_TIMEOUT = 500; static final long SELECT_TIMEOUT = SystemPropertyUtil.getLong("io.netty.selectTimeout", DEFAULT_SELECT_TIMEOUT); static final long SELECT_TIMEOUT_NANOS = TimeUnit.MILLISECONDS.toNanos(SELECT_TIMEOUT); From bd8ee64366ca657e5282e87865efa7c753e10ae9 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Thu, 27 Sep 2012 19:04:35 +0900 Subject: [PATCH 12/29] Pull #625 from @CruzBishop selectively --- .../io/netty/handler/codec/CodecUtil.java | 4 +--- .../http/snoop/HttpSnoopServerHandler.java | 22 ++++++++++++------- .../io/netty/channel/local/LocalChannel.java | 5 ++--- .../socket/aio/AbstractAioChannel.java | 2 +- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/codec/src/main/java/io/netty/handler/codec/CodecUtil.java b/codec/src/main/java/io/netty/handler/codec/CodecUtil.java index de26a0e266..30966c1643 100644 --- a/codec/src/main/java/io/netty/handler/codec/CodecUtil.java +++ b/codec/src/main/java/io/netty/handler/codec/CodecUtil.java @@ -98,9 +98,7 @@ final class CodecUtil { } Class[] newAllowedMsgTypes = new Class[numElem]; - for (int i = 0; i < numElem; i ++) { - newAllowedMsgTypes[i] = acceptedMsgTypes[i]; - } + System.arraycopy(acceptedMsgTypes, 0, newAllowedMsgTypes, 0, numElem); return newAllowedMsgTypes; } diff --git a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java index 1adad5709d..ddea7dafc0 100644 --- a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java @@ -62,12 +62,14 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< buf.append("WELCOME TO THE WILD WILD WEB SERVER\r\n"); buf.append("===================================\r\n"); - buf.append("VERSION: " + request.getProtocolVersion() + "\r\n"); - buf.append("HOSTNAME: " + getHost(request, "unknown") + "\r\n"); - buf.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n"); + buf.append("VERSION: ").append(request.getProtocolVersion()).append("\r\n"); + buf.append("HOSTNAME: ").append(getHost(request, "unknown")).append("\r\n"); + buf.append("REQUEST_URI: ").append(request.getUri()).append("\r\n\r\n"); for (Map.Entry h: request.getHeaders()) { - buf.append("HEADER: " + h.getKey() + " = " + h.getValue() + "\r\n"); + String key = h.getKey(); + String value = h.getValue(); + buf.append("HEADER: ").append(key).append(" = ").append(value).append("\r\n"); } buf.append("\r\n"); @@ -78,7 +80,7 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< String key = p.getKey(); List vals = p.getValue(); for (String val : vals) { - buf.append("PARAM: " + key + " = " + val + "\r\n"); + buf.append("PARAM: ").append(key).append(" = ").append(val).append("\r\n"); } } buf.append("\r\n"); @@ -89,7 +91,9 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< } else { ByteBuf content = request.getContent(); if (content.readable()) { - buf.append("CONTENT: " + content.toString(CharsetUtil.UTF_8) + "\r\n"); + buf.append("CONTENT: "); + buf.append(content.toString(CharsetUtil.UTF_8)); + buf.append("\r\n"); } writeResponse(ctx); } @@ -104,7 +108,8 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< buf.append("\r\n"); for (String name: trailer.getHeaderNames()) { for (String value: trailer.getHeaders(name)) { - buf.append("TRAILING HEADER: " + name + " = " + value + "\r\n"); + buf.append("TRAILING HEADER: "); + buf.append(name).append(" = ").append(value).append("\r\n"); } } buf.append("\r\n"); @@ -112,7 +117,8 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< writeResponse(ctx); } else { - buf.append("CHUNK: " + chunk.getContent().toString(CharsetUtil.UTF_8) + "\r\n"); + buf.append("CHUNK: "); + buf.append(chunk.getContent().toString(CharsetUtil.UTF_8)).append("\r\n"); } } } diff --git a/transport/src/main/java/io/netty/channel/local/LocalChannel.java b/transport/src/main/java/io/netty/channel/local/LocalChannel.java index 9b86ca75e1..0b02e1290f 100755 --- a/transport/src/main/java/io/netty/channel/local/LocalChannel.java +++ b/transport/src/main/java/io/netty/channel/local/LocalChannel.java @@ -34,6 +34,7 @@ import java.nio.channels.AlreadyConnectedException; import java.nio.channels.ClosedChannelException; import java.nio.channels.ConnectionPendingException; import java.nio.channels.NotYetConnectedException; +import java.util.Collections; /** * A {@link Channel} for the local transport. @@ -229,9 +230,7 @@ public class LocalChannel extends AbstractChannel { @Override public void run() { MessageBuf buf = peerPipeline.inboundMessageBuffer(); - for (Object m: msgs) { - buf.add(m); - } + Collections.addAll(buf, msgs); peerPipeline.fireInboundBufferUpdated(); } }); diff --git a/transport/src/main/java/io/netty/channel/socket/aio/AbstractAioChannel.java b/transport/src/main/java/io/netty/channel/socket/aio/AbstractAioChannel.java index ac31001d50..7b7dc8e136 100755 --- a/transport/src/main/java/io/netty/channel/socket/aio/AbstractAioChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/aio/AbstractAioChannel.java @@ -68,7 +68,7 @@ abstract class AbstractAioChannel extends AbstractChannel { @Override protected Runnable doRegister() throws Exception { - if (((AioEventLoop) eventLoop()).parent() != group) { + if (eventLoop().parent() != group) { throw new ChannelException( getClass().getSimpleName() + " must be registered to the " + AioEventLoopGroup.class.getSimpleName() + " which was specified in the constructor."); From 2ecf26c8ebcfcd78fdfa13c6c78ba7f6f96c75b5 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Thu, 27 Sep 2012 19:16:02 +0900 Subject: [PATCH 13/29] Fix #525 Add CORS preflight headers to HttpHeaders.Names --- .../netty/handler/codec/http/HttpHeaders.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaders.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaders.java index a29d87199a..7ee60973f2 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaders.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaders.java @@ -62,6 +62,34 @@ public class HttpHeaders { * {@code "Accept-Patch"} */ public static final String ACCEPT_PATCH = "Accept-Patch"; + /** + * {@code "Access-Control-Allow-Credentials"} + */ + public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; + /** + * {@code "Access-Control-Allow-Headers"} + */ + public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; + /** + * {@code "Access-Control-Allow-Methods"} + */ + public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; + /** + * {@code "Access-Control-Allow-Origin"} + */ + public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; + /** + * {@code "Access-Control-Max-Age"} + */ + public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age"; + /** + * {@code "Access-Control-Request-Headers"} + */ + public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers"; + /** + * {@code "Access-Control-Request-Method"} + */ + public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method"; /** * {@code "Age"} */ From 817309c7c880ac4ffeaf9e30cf9b5de7005e3608 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Thu, 27 Sep 2012 19:28:41 +0900 Subject: [PATCH 14/29] Remove magic numbers from SslHandler --- .../java/io/netty/handler/ssl/SslHandler.java | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java index 67aa3b1675..e2ed8c3201 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java @@ -170,6 +170,9 @@ public class SslHandler private final Queue handshakeFutures = new ArrayDeque(); private final SSLEngineInboundCloseFuture sslCloseFuture = new SSLEngineInboundCloseFuture(); + private volatile long handshakeTimeoutMillis = 10000; + private volatile long closeNotifyTimeoutMillis = 3000; + /** * Creates a new instance. * @@ -227,6 +230,46 @@ public class SslHandler this.startTls = startTls; } + public long getHandshakeTimeoutMillis() { + return handshakeTimeoutMillis; + } + + public void setHandshakeTimeout(long handshakeTimeout, TimeUnit unit) { + if (unit == null) { + throw new NullPointerException("unit"); + } + + setHandshakeTimeoutMillis(unit.toMillis(handshakeTimeout)); + } + + public void setHandshakeTimeoutMillis(long handshakeTimeoutMillis) { + if (handshakeTimeoutMillis < 0) { + throw new IllegalArgumentException( + "handshakeTimeoutMillis: " + handshakeTimeoutMillis + " (expected: >= 0)"); + } + this.handshakeTimeoutMillis = handshakeTimeoutMillis; + } + + public long getCloseNotifyTimeoutMillis() { + return handshakeTimeoutMillis; + } + + public void setCloseNotifyTimeout(long closeNotifyTimeout, TimeUnit unit) { + if (unit == null) { + throw new NullPointerException("unit"); + } + + setCloseNotifyTimeoutMillis(unit.toMillis(closeNotifyTimeout)); + } + + public void setCloseNotifyTimeoutMillis(long closeNotifyTimeoutMillis) { + if (closeNotifyTimeoutMillis < 0) { + throw new IllegalArgumentException( + "closeNotifyTimeoutMillis: " + closeNotifyTimeoutMillis + " (expected: >= 0)"); + } + this.closeNotifyTimeoutMillis = closeNotifyTimeoutMillis; + } + /** * Returns the {@link SSLEngine} which is used by this handler. */ @@ -259,7 +302,7 @@ public class SslHandler ctx.fireExceptionCaught(e); ctx.close(); } - }, 10, TimeUnit.SECONDS); // FIXME: Magic value + }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS); ctx.executor().execute(new Runnable() { @Override public void run() { @@ -861,7 +904,7 @@ public class SslHandler } } - private static void safeClose( + private void safeClose( final ChannelHandlerContext ctx, ChannelFuture flushFuture, final ChannelFuture closeFuture) { if (!ctx.channel().isActive()) { @@ -878,7 +921,7 @@ public class SslHandler " Force-closing the connection."); ctx.close(closeFuture); } - }, 3, TimeUnit.SECONDS); // FIXME: Magic value + }, closeNotifyTimeoutMillis, TimeUnit.MILLISECONDS); // Close the connection if close_notify is sent in time. flushFuture.addListener(new ChannelFutureListener() { From adebda156041d8edb88d322fd5d0557e64b99720 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 13:48:17 +0900 Subject: [PATCH 15/29] [#441] Provide a better way to handle decoder failures * Add DecodeResult that represents the result of decoding a message * Add HttpObject which HttpMessage and HttpChunk extend. ** HttpObject has a property 'decodeResult' --- .../handler/codec/http/DefaultHttpChunk.java | 2 +- .../codec/http/DefaultHttpChunkTrailer.java | 2 +- .../codec/http/DefaultHttpMessage.java | 2 +- .../handler/codec/http/DefaultHttpObject.java | 40 ++++++++++ .../netty/handler/codec/http/HttpChunk.java | 13 +++- .../netty/handler/codec/http/HttpMessage.java | 2 +- .../netty/handler/codec/http/HttpObject.java | 23 ++++++ .../io/netty/handler/codec/DecodeResult.java | 77 +++++++++++++++++++ 8 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java create mode 100644 codec-http/src/main/java/io/netty/handler/codec/http/HttpObject.java create mode 100644 codec/src/main/java/io/netty/handler/codec/DecodeResult.java diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java index 96705bf4ac..f78c018d4d 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java @@ -20,7 +20,7 @@ import io.netty.buffer.ByteBuf; /** * The default {@link HttpChunk} implementation. */ -public class DefaultHttpChunk implements HttpChunk { +public class DefaultHttpChunk extends DefaultHttpObject implements HttpChunk { private ByteBuf content; private boolean last; diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java index 6cb31aa0bb..65235d4b86 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java @@ -25,7 +25,7 @@ import java.util.Set; /** * The default {@link HttpChunkTrailer} implementation. */ -public class DefaultHttpChunkTrailer implements HttpChunkTrailer { +public class DefaultHttpChunkTrailer extends DefaultHttpObject implements HttpChunkTrailer { private final HttpHeaders headers = new HttpHeaders() { @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java index a0697aa12f..09d79e0a3a 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java @@ -26,7 +26,7 @@ import java.util.Set; /** * The default {@link HttpMessage} implementation. */ -public class DefaultHttpMessage implements HttpMessage { +public class DefaultHttpMessage extends DefaultHttpObject implements HttpMessage { private final HttpHeaders headers = new HttpHeaders(); private HttpVersion version; diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java new file mode 100644 index 0000000000..3f24c7375a --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012 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; + +import io.netty.handler.codec.DecodeResult; + +public class DefaultHttpObject implements HttpObject { + + private DecodeResult decodeResult = DecodeResult.SUCCESS; + + protected DefaultHttpObject() { + // Disallow direct instantiation + } + + @Override + public DecodeResult getDecodeResult() { + return decodeResult; + } + + @Override + public void setDecodeResult(DecodeResult result) { + if (result == null) { + throw new NullPointerException("result"); + } + decodeResult = result; + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java index 4157fc91ec..8a2c1fd067 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java @@ -18,6 +18,7 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelPipeline; +import io.netty.handler.codec.DecodeResult; import java.util.Collections; import java.util.List; @@ -33,7 +34,7 @@ import java.util.Set; * {@link ChannelPipeline}. * @apiviz.landmark */ -public interface HttpChunk { +public interface HttpChunk extends HttpObject { /** * The 'end of content' marker in chunked encoding. @@ -103,6 +104,16 @@ public interface HttpChunk { public void setHeader(String name, Iterable values) { throw new IllegalStateException("read-only"); } + + @Override + public DecodeResult getDecodeResult() { + return DecodeResult.SUCCESS; + } + + @Override + public void setDecodeResult(DecodeResult result) { + throw new IllegalStateException("read-only"); + } }; /** diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessage.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessage.java index 317d673264..33389d6ccf 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessage.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessage.java @@ -34,7 +34,7 @@ import java.util.Set; * @apiviz.landmark * @apiviz.has io.netty.handler.codec.http.HttpChunk oneway - - is followed by */ -public interface HttpMessage { +public interface HttpMessage extends HttpObject { /** * Returns the value of a header with the specified name. If there are diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpObject.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObject.java new file mode 100644 index 0000000000..095c266edb --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpObject.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012 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; + +import io.netty.handler.codec.DecodeResult; + +public interface HttpObject { + DecodeResult getDecodeResult(); + void setDecodeResult(DecodeResult result); +} diff --git a/codec/src/main/java/io/netty/handler/codec/DecodeResult.java b/codec/src/main/java/io/netty/handler/codec/DecodeResult.java new file mode 100644 index 0000000000..9463119f43 --- /dev/null +++ b/codec/src/main/java/io/netty/handler/codec/DecodeResult.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012 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; + +public class DecodeResult { + + public static final DecodeResult SUCCESS = new DecodeResult(false, null); + + public static DecodeResult failure(Throwable cause) { + if (cause == null) { + throw new NullPointerException("cause"); + } + return new DecodeResult(false, cause); + } + + public static DecodeResult partialFailure(Throwable cause) { + if (cause == null) { + throw new NullPointerException("cause"); + } + return new DecodeResult(true, cause); + } + + private final boolean partial; + private final Throwable cause; + + protected DecodeResult(boolean partial, Throwable cause) { + if (partial && cause == null) { + throw new IllegalArgumentException("successful result cannot be partial."); + } + + this.partial = partial; + this.cause = cause; + } + + public boolean isSuccess() { + return cause == null; + } + + public boolean isPartial() { + return partial; + } + + public Throwable cause() { + return cause; + } + + @Override + public String toString() { + if (isSuccess()) { + return "success"; + } + + String cause = cause().toString(); + StringBuilder buf = new StringBuilder(cause.length() + 17); + if (isPartial()) { + buf.append("partial_"); + } + buf.append("failure("); + buf.append(cause); + buf.append(')'); + + return buf.toString(); + } +} From 7514a82c3550690fb965e8c767519fec423b108d Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 13:52:05 +0900 Subject: [PATCH 16/29] Disable timeouts if they are set to 0 --- .../java/io/netty/handler/ssl/SslHandler.java | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java index e2ed8c3201..80277ebb85 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java @@ -290,23 +290,32 @@ public class SslHandler public ChannelFuture handshake(final ChannelFuture future) { final ChannelHandlerContext ctx = this.ctx; - ctx.executor().schedule(new Runnable() { - @Override - public void run() { - if (future.isDone()) { - return; - } + final ScheduledFuture timeoutFuture; + if (handshakeTimeoutMillis > 0) { + timeoutFuture = ctx.executor().schedule(new Runnable() { + @Override + public void run() { + if (future.isDone()) { + return; + } + + SSLException e = new SSLException("handshake timed out"); + future.setFailure(e); + ctx.fireExceptionCaught(e); + ctx.close(); + } + }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS); + } else { + timeoutFuture = null; + } - SSLException e = new SSLException("handshake timed out"); - future.setFailure(e); - ctx.fireExceptionCaught(e); - ctx.close(); - } - }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS); ctx.executor().execute(new Runnable() { @Override public void run() { try { + if (timeoutFuture != null) { + timeoutFuture.cancel(false); + } engine.beginHandshake(); handshakeFutures.add(future); flush(ctx, ctx.newFuture()); @@ -912,23 +921,31 @@ public class SslHandler return; } - // Force-close the connection if close_notify is not fully sent in time. - final ScheduledFuture timeoutFuture = ctx.executor().schedule(new Runnable() { - @Override - public void run() { - logger.warn( - ctx.channel() + " last lssssswrite attempt timed out." + - " Force-closing the connection."); - ctx.close(closeFuture); - } - }, closeNotifyTimeoutMillis, TimeUnit.MILLISECONDS); + final ScheduledFuture timeoutFuture; + if (closeNotifyTimeoutMillis > 0) { + // Force-close the connection if close_notify is not fully sent in time. + timeoutFuture = ctx.executor().schedule(new Runnable() { + @Override + public void run() { + logger.warn( + ctx.channel() + " last lssssswrite attempt timed out." + + " Force-closing the connection."); + ctx.close(closeFuture); + } + }, closeNotifyTimeoutMillis, TimeUnit.MILLISECONDS); + } else { + timeoutFuture = null; + } + // Close the connection if close_notify is sent in time. flushFuture.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) throws Exception { - timeoutFuture.cancel(false); + if (timeoutFuture != null) { + timeoutFuture.cancel(false); + } if (ctx.channel().isActive()) { ctx.close(closeFuture); } From b923d0c51f586558eaf9df7cb8f35333367f9de0 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 14:00:07 +0900 Subject: [PATCH 17/29] Use supertype HttpObject instead of HttpMessage + HttpChunk where possible --- .../io/netty/handler/codec/http/HttpChunkAggregator.java | 6 +++--- .../io/netty/handler/codec/http/HttpContentDecoder.java | 2 +- .../io/netty/handler/codec/http/HttpContentEncoder.java | 2 +- .../io/netty/handler/codec/http/HttpMessageEncoder.java | 2 +- .../java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java | 3 ++- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java index c61bcd2ebb..d9097a0feb 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java @@ -46,7 +46,7 @@ import java.util.Map.Entry; * @apiviz.landmark * @apiviz.has io.netty.handler.codec.http.HttpChunk oneway - - filters out */ -public class HttpChunkAggregator extends MessageToMessageDecoder { +public class HttpChunkAggregator extends MessageToMessageDecoder { public static final int DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS = 1024; private static final ByteBuf CONTINUE = Unpooled.copiedBuffer( "HTTP/1.1 100 Continue\r\n\r\n", CharsetUtil.US_ASCII); @@ -66,7 +66,7 @@ public class HttpChunkAggregator extends MessageToMessageDecoder[] { HttpMessage.class }, - new Class[] { HttpMessage.class, HttpChunk.class }); + new Class[] { HttpObject.class }); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java index b984120fbe..7410998356 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java @@ -50,7 +50,7 @@ public abstract class HttpMessageEncoder extends MessageToByteEncoder { * Creates a new instance. */ protected HttpMessageEncoder() { - super(HttpMessage.class, HttpChunk.class); + super(HttpObject.class); } @Override diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java index 5ea2067883..afa4cf1c1c 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHttpEncoder.java @@ -22,6 +22,7 @@ import io.netty.handler.codec.http.HttpChunk; import io.netty.handler.codec.http.HttpChunkTrailer; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMessage; +import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; @@ -129,7 +130,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder { * @param version the protocol version */ public SpdyHttpEncoder(int version) { - super(HttpMessage.class, HttpChunk.class); + super(HttpObject.class); if (version < SpdyConstants.SPDY_MIN_VERSION || version > SpdyConstants.SPDY_MAX_VERSION) { throw new IllegalArgumentException( From 41e0ef2e9ac5b19744e75392543632b21da498c6 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 15:16:29 +0900 Subject: [PATCH 18/29] [#441] Provide a better way to handle decoder failures * Update toString() of all HttpObject implementations * HttpMessageDecoder does not raise an exception but sets decoderResult property of the decoded message. * HttpMessageDecoder discards inbound traffic once decoding fails, by adding a new state called BAD_MESSAGE. * Add a test case that tests this behavior. --- .../handler/codec/http/DefaultHttpChunk.java | 20 +++ .../codec/http/DefaultHttpChunkTrailer.java | 34 +++++ .../codec/http/DefaultHttpRequest.java | 2 + .../codec/http/DefaultHttpResponse.java | 2 + .../codec/http/HttpMessageDecoder.java | 51 ++++++-- .../codec/http/HttpRequestDecoder.java | 5 + .../codec/http/HttpResponseDecoder.java | 7 ++ .../codec/rtsp/RtspRequestDecoder.java | 5 + .../codec/rtsp/RtspResponseDecoder.java | 7 ++ .../codec/http/HttpInvalidMessageTest.java | 117 ++++++++++++++++++ 10 files changed, 243 insertions(+), 7 deletions(-) create mode 100644 codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java index f78c018d4d..9cf64e8711 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java @@ -51,4 +51,24 @@ public class DefaultHttpChunk extends DefaultHttpObject implements HttpChunk { public boolean isLast() { return last; } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + + final boolean last = isLast(); + buf.append("(last: "); + buf.append(last); + if (!last) { + buf.append(", size: "); + buf.append(getContent().readableBytes()); + } + + buf.append(", decodeResult: "); + buf.append(getDecodeResult()); + buf.append(')'); + + return buf.toString(); + } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java index 65235d4b86..2f3c6bc591 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java @@ -17,6 +17,7 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.util.internal.StringUtil; import java.util.List; import java.util.Map; @@ -104,4 +105,37 @@ public class DefaultHttpChunkTrailer extends DefaultHttpObject implements HttpCh public void setContent(ByteBuf content) { throw new IllegalStateException("read-only"); } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + + final boolean last = isLast(); + buf.append("(last: "); + buf.append(last); + if (!last) { + buf.append(", size: "); + buf.append(getContent().readableBytes()); + } + + buf.append(", decodeResult: "); + buf.append(getDecodeResult()); + buf.append(')'); + buf.append(StringUtil.NEWLINE); + appendHeaders(buf); + + // Remove the last newline. + buf.setLength(buf.length() - StringUtil.NEWLINE.length()); + return buf.toString(); + } + + private void appendHeaders(StringBuilder buf) { + for (Map.Entry e: getHeaders()) { + buf.append(e.getKey()); + buf.append(": "); + buf.append(e.getValue()); + buf.append(StringUtil.NEWLINE); + } + } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java index afadec21bd..2729b9e9d4 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java @@ -70,6 +70,8 @@ public class DefaultHttpRequest extends DefaultHttpMessage implements HttpReques buf.append(getClass().getSimpleName()); buf.append("(transferEncoding: "); buf.append(getTransferEncoding()); + buf.append(", decodeResult: "); + buf.append(getDecodeResult()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append(getMethod().toString()); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java index 440b34fed0..c872e940e4 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java @@ -54,6 +54,8 @@ public class DefaultHttpResponse extends DefaultHttpMessage implements HttpRespo buf.append(getClass().getSimpleName()); buf.append("(transferEncoding: "); buf.append(getTransferEncoding()); + buf.append(", decodeResult: "); + buf.append(getDecodeResult()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append(getProtocolVersion().getText()); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java index 13ff6ad8f8..82a49f6ea0 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.handler.codec.DecodeResult; import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.TooLongFrameException; @@ -125,7 +126,8 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder Date: Fri, 28 Sep 2012 15:19:08 +0900 Subject: [PATCH 19/29] Rename DecodeResult to DecoderResult --- .../handler/codec/http/DefaultHttpObject.java | 8 ++++---- .../io/netty/handler/codec/http/HttpChunk.java | 8 ++++---- .../handler/codec/http/HttpMessageDecoder.java | 8 ++++---- .../io/netty/handler/codec/http/HttpObject.java | 6 +++--- .../handler/codec/http/HttpInvalidMessageTest.java | 12 ++++++------ .../{DecodeResult.java => DecoderResult.java} | 14 +++++++------- 6 files changed, 28 insertions(+), 28 deletions(-) rename codec/src/main/java/io/netty/handler/codec/{DecodeResult.java => DecoderResult.java} (81%) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java index 3f24c7375a..22cdb9294a 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java @@ -15,23 +15,23 @@ */ package io.netty.handler.codec.http; -import io.netty.handler.codec.DecodeResult; +import io.netty.handler.codec.DecoderResult; public class DefaultHttpObject implements HttpObject { - private DecodeResult decodeResult = DecodeResult.SUCCESS; + private DecoderResult decodeResult = DecoderResult.SUCCESS; protected DefaultHttpObject() { // Disallow direct instantiation } @Override - public DecodeResult getDecodeResult() { + public DecoderResult getDecodeResult() { return decodeResult; } @Override - public void setDecodeResult(DecodeResult result) { + public void setDecodeResult(DecoderResult result) { if (result == null) { throw new NullPointerException("result"); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java index 8a2c1fd067..216d4a09ba 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java @@ -18,7 +18,7 @@ package io.netty.handler.codec.http; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.DecodeResult; +import io.netty.handler.codec.DecoderResult; import java.util.Collections; import java.util.List; @@ -106,12 +106,12 @@ public interface HttpChunk extends HttpObject { } @Override - public DecodeResult getDecodeResult() { - return DecodeResult.SUCCESS; + public DecoderResult getDecodeResult() { + return DecoderResult.SUCCESS; } @Override - public void setDecodeResult(DecodeResult result) { + public void setDecodeResult(DecoderResult result) { throw new IllegalStateException("read-only"); } }; diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java index 82a49f6ea0..cddb3071d5 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java @@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.DecodeResult; +import io.netty.handler.codec.DecoderResult; import io.netty.handler.codec.ReplayingDecoder; import io.netty.handler.codec.TooLongFrameException; @@ -459,10 +459,10 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder Date: Fri, 28 Sep 2012 15:20:02 +0900 Subject: [PATCH 20/29] Rename get/setDecodeResult() to get/setDecoderResult() --- .../netty/handler/codec/http/DefaultHttpChunk.java | 2 +- .../handler/codec/http/DefaultHttpChunkTrailer.java | 2 +- .../netty/handler/codec/http/DefaultHttpObject.java | 4 ++-- .../netty/handler/codec/http/DefaultHttpRequest.java | 2 +- .../handler/codec/http/DefaultHttpResponse.java | 2 +- .../java/io/netty/handler/codec/http/HttpChunk.java | 4 ++-- .../netty/handler/codec/http/HttpMessageDecoder.java | 6 +++--- .../java/io/netty/handler/codec/http/HttpObject.java | 4 ++-- .../handler/codec/http/HttpInvalidMessageTest.java | 12 ++++++------ 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java index 9cf64e8711..329c203211 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java @@ -66,7 +66,7 @@ public class DefaultHttpChunk extends DefaultHttpObject implements HttpChunk { } buf.append(", decodeResult: "); - buf.append(getDecodeResult()); + buf.append(getDecoderResult()); buf.append(')'); return buf.toString(); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java index 2f3c6bc591..29b4cdfced 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java @@ -120,7 +120,7 @@ public class DefaultHttpChunkTrailer extends DefaultHttpObject implements HttpCh } buf.append(", decodeResult: "); - buf.append(getDecodeResult()); + buf.append(getDecoderResult()); buf.append(')'); buf.append(StringUtil.NEWLINE); appendHeaders(buf); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java index 22cdb9294a..232eeecea1 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpObject.java @@ -26,12 +26,12 @@ public class DefaultHttpObject implements HttpObject { } @Override - public DecoderResult getDecodeResult() { + public DecoderResult getDecoderResult() { return decodeResult; } @Override - public void setDecodeResult(DecoderResult result) { + public void setDecoderResult(DecoderResult result) { if (result == null) { throw new NullPointerException("result"); } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java index 2729b9e9d4..134be89901 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java @@ -71,7 +71,7 @@ public class DefaultHttpRequest extends DefaultHttpMessage implements HttpReques buf.append("(transferEncoding: "); buf.append(getTransferEncoding()); buf.append(", decodeResult: "); - buf.append(getDecodeResult()); + buf.append(getDecoderResult()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append(getMethod().toString()); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java index c872e940e4..9872868ae1 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java @@ -55,7 +55,7 @@ public class DefaultHttpResponse extends DefaultHttpMessage implements HttpRespo buf.append("(transferEncoding: "); buf.append(getTransferEncoding()); buf.append(", decodeResult: "); - buf.append(getDecodeResult()); + buf.append(getDecoderResult()); buf.append(')'); buf.append(StringUtil.NEWLINE); buf.append(getProtocolVersion().getText()); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java index 216d4a09ba..dbf5e3917b 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java @@ -106,12 +106,12 @@ public interface HttpChunk extends HttpObject { } @Override - public DecoderResult getDecodeResult() { + public DecoderResult getDecoderResult() { return DecoderResult.SUCCESS; } @Override - public void setDecodeResult(DecoderResult result) { + public void setDecoderResult(DecoderResult result) { throw new IllegalStateException("read-only"); } }; diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java index cddb3071d5..7ed31212c3 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java @@ -459,10 +459,10 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder Date: Fri, 28 Sep 2012 15:26:38 +0900 Subject: [PATCH 21/29] [#441] Provide a better way to handle decoder failures * Make HttpChunkAggregator handle DecoderResult properly --- .../codec/http/HttpChunkAggregator.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java index d9097a0feb..f32963f308 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java @@ -22,6 +22,7 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; +import io.netty.handler.codec.DecoderResult; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.TooLongFrameException; import io.netty.util.CharsetUtil; @@ -124,6 +125,12 @@ public class HttpChunkAggregator extends MessageToMessageDecoder Date: Fri, 28 Sep 2012 15:42:38 +0900 Subject: [PATCH 22/29] [#441] Update HTTP examples so that they understand DecoderResult --- .../file/HttpStaticFileServerHandler.java | 14 +++--- .../http/snoop/HttpSnoopServerHandler.java | 43 +++++++++++++++---- .../autobahn/AutobahnServerHandler.java | 6 +++ .../server/WebSocketServerHandler.java | 6 +++ .../sslserver/WebSocketSslServerHandler.java | 6 +++ 5 files changed, 58 insertions(+), 17 deletions(-) diff --git a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java index 22ab5a6756..4f641bbacd 100644 --- a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java +++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java @@ -25,7 +25,6 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundMessageHandlerAdapter; -import io.netty.handler.codec.TooLongFrameException; import io.netty.handler.codec.http.DefaultHttpResponse; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpRequest; @@ -104,6 +103,11 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda public void messageReceived( ChannelHandlerContext ctx, HttpRequest request) throws Exception { + if (!request.getDecoderResult().isSuccess()) { + sendError(ctx, BAD_REQUEST); + return; + } + if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; @@ -172,13 +176,7 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda } @Override - public void exceptionCaught( - ChannelHandlerContext ctx, Throwable cause) throws Exception { - if (cause instanceof TooLongFrameException) { - sendError(ctx, BAD_REQUEST); - return; - } - + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); if (ctx.channel().isActive()) { sendError(ctx, INTERNAL_SERVER_ERROR); diff --git a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java index ddea7dafc0..7d5793b48f 100644 --- a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java @@ -25,12 +25,14 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.handler.codec.DecoderResult; import io.netty.handler.codec.http.Cookie; import io.netty.handler.codec.http.CookieDecoder; import io.netty.handler.codec.http.DefaultHttpResponse; import io.netty.handler.codec.http.HttpChunk; import io.netty.handler.codec.http.HttpChunkTrailer; import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.QueryStringDecoder; @@ -66,12 +68,15 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< buf.append("HOSTNAME: ").append(getHost(request, "unknown")).append("\r\n"); buf.append("REQUEST_URI: ").append(request.getUri()).append("\r\n\r\n"); - for (Map.Entry h: request.getHeaders()) { - String key = h.getKey(); - String value = h.getValue(); - buf.append("HEADER: ").append(key).append(" = ").append(value).append("\r\n"); + List> headers = request.getHeaders(); + if (!headers.isEmpty()) { + for (Map.Entry h: request.getHeaders()) { + String key = h.getKey(); + String value = h.getValue(); + buf.append("HEADER: ").append(key).append(" = ").append(value).append("\r\n"); + } + buf.append("\r\n"); } - buf.append("\r\n"); QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri()); Map> params = queryStringDecoder.getParameters(); @@ -95,7 +100,8 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< buf.append(content.toString(CharsetUtil.UTF_8)); buf.append("\r\n"); } - writeResponse(ctx); + appendDecoderResult(buf, request); + writeResponse(ctx, request); } } else { HttpChunk chunk = (HttpChunk) msg; @@ -115,20 +121,39 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< buf.append("\r\n"); } - writeResponse(ctx); + appendDecoderResult(buf, chunk); + writeResponse(ctx, chunk); } else { buf.append("CHUNK: "); buf.append(chunk.getContent().toString(CharsetUtil.UTF_8)).append("\r\n"); + appendDecoderResult(buf, chunk); } } } - private void writeResponse(ChannelHandlerContext ctx) { + private static void appendDecoderResult(StringBuilder buf, HttpObject o) { + DecoderResult result = o.getDecoderResult(); + if (result.isSuccess()) { + return; + } + + buf.append(".. WITH A "); + if (result.isPartial()) { + buf.append("PARTIAL "); + } + buf.append("DECODER FAILURE: "); + buf.append(result.cause()); + buf.append("\r\n"); + } + + private void writeResponse(ChannelHandlerContext ctx, HttpObject currentObj) { // Decide whether to close the connection or not. boolean keepAlive = isKeepAlive(request); // Build the response object. - HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); + HttpResponse response = new DefaultHttpResponse( + HTTP_1_1, currentObj.getDecoderResult().isSuccess()? OK : BAD_REQUEST); + response.setContent(Unpooled.copiedBuffer(buf.toString(), CharsetUtil.UTF_8)); response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8"); diff --git a/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java index da6eb9e2a0..ea7e1768e2 100644 --- a/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java +++ b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java @@ -59,6 +59,12 @@ public class AutobahnServerHandler extends ChannelInboundMessageHandlerAdapter Date: Fri, 28 Sep 2012 15:46:17 +0900 Subject: [PATCH 23/29] [#441] Provide a better way to handle decoder failures * Rename isPartial() to isPartialFailure() * Add isCompleteFailure() and isFailure() --- .../handler/codec/http/HttpInvalidMessageTest.java | 10 +++++----- .../java/io/netty/handler/codec/DecoderResult.java | 12 ++++++++++-- .../example/http/snoop/HttpSnoopServerHandler.java | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java index 77a27f1307..3d67783227 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpInvalidMessageTest.java @@ -37,7 +37,7 @@ public class HttpInvalidMessageTest { HttpRequest req = (HttpRequest) ch.readInbound(); DecoderResult dr = req.getDecoderResult(); Assert.assertFalse(dr.isSuccess()); - Assert.assertFalse(dr.isPartial()); + Assert.assertFalse(dr.isPartialFailure()); ensureInboundTrafficDiscarded(ch); } @@ -51,7 +51,7 @@ public class HttpInvalidMessageTest { HttpRequest req = (HttpRequest) ch.readInbound(); DecoderResult dr = req.getDecoderResult(); Assert.assertFalse(dr.isSuccess()); - Assert.assertTrue(dr.isPartial()); + Assert.assertTrue(dr.isPartialFailure()); Assert.assertEquals("Good Value", req.getHeader("Good_Name")); Assert.assertEquals("/maybe-something", req.getUri()); ensureInboundTrafficDiscarded(ch); @@ -64,7 +64,7 @@ public class HttpInvalidMessageTest { HttpResponse res = (HttpResponse) ch.readInbound(); DecoderResult dr = res.getDecoderResult(); Assert.assertFalse(dr.isSuccess()); - Assert.assertFalse(dr.isPartial()); + Assert.assertFalse(dr.isPartialFailure()); ensureInboundTrafficDiscarded(ch); } @@ -78,7 +78,7 @@ public class HttpInvalidMessageTest { HttpResponse res = (HttpResponse) ch.readInbound(); DecoderResult dr = res.getDecoderResult(); Assert.assertFalse(dr.isSuccess()); - Assert.assertTrue(dr.isPartial()); + Assert.assertTrue(dr.isPartialFailure()); Assert.assertEquals("Maybe OK", res.getStatus().getReasonPhrase()); Assert.assertEquals("Good Value", res.getHeader("Good_Name")); ensureInboundTrafficDiscarded(ch); @@ -97,7 +97,7 @@ public class HttpInvalidMessageTest { HttpChunk chunk = (HttpChunk) ch.readInbound(); DecoderResult dr = chunk.getDecoderResult(); Assert.assertFalse(dr.isSuccess()); - Assert.assertFalse(dr.isPartial()); + Assert.assertFalse(dr.isPartialFailure()); ensureInboundTrafficDiscarded(ch); } diff --git a/codec/src/main/java/io/netty/handler/codec/DecoderResult.java b/codec/src/main/java/io/netty/handler/codec/DecoderResult.java index 9c12a3c6e1..e621d8baf1 100644 --- a/codec/src/main/java/io/netty/handler/codec/DecoderResult.java +++ b/codec/src/main/java/io/netty/handler/codec/DecoderResult.java @@ -49,7 +49,15 @@ public class DecoderResult { return cause == null; } - public boolean isPartial() { + public boolean isFailure() { + return cause != null; + } + + public boolean isCompleteFailure() { + return cause != null && !partial; + } + + public boolean isPartialFailure() { return partial; } @@ -65,7 +73,7 @@ public class DecoderResult { String cause = cause().toString(); StringBuilder buf = new StringBuilder(cause.length() + 17); - if (isPartial()) { + if (isPartialFailure()) { buf.append("partial_"); } buf.append("failure("); diff --git a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java index 7d5793b48f..5ba3073733 100644 --- a/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java @@ -138,7 +138,7 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter< } buf.append(".. WITH A "); - if (result.isPartial()) { + if (result.isPartialFailure()) { buf.append("PARTIAL "); } buf.append("DECODER FAILURE: "); From 1bb5ac110f45d4992d3588f3b75ef4ddb52707bf Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 16:27:23 +0900 Subject: [PATCH 24/29] [#600] mvn clean package on OSX throws Exception * Choose port randomly * Ensure SO_REUSEADDR is not set at any case * Ensure the port works for both wildcard and localhost --- .../io/netty/testsuite/util/TestUtils.java | 54 +++++++++++++++---- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/testsuite/src/test/java/io/netty/testsuite/util/TestUtils.java b/testsuite/src/test/java/io/netty/testsuite/util/TestUtils.java index 33c8242c01..38e2f8ac78 100644 --- a/testsuite/src/test/java/io/netty/testsuite/util/TestUtils.java +++ b/testsuite/src/test/java/io/netty/testsuite/util/TestUtils.java @@ -15,13 +15,38 @@ */ package io.netty.testsuite.util; +import io.netty.util.NetworkConstants; + import java.io.IOException; +import java.net.InetSocketAddress; import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; public class TestUtils { - private static int START_PORT = 20000; - private static int END_PORT = 30000; + private static final int START_PORT = 32768; + private static final int END_PORT = 65536; + private static final int NUM_CANDIDATES = END_PORT - START_PORT; + + private static final List PORTS = new ArrayList(); + private static Iterator PORTS_ITERATOR; + + static { + for (int i = START_PORT; i < END_PORT; i ++) { + PORTS.add(i); + } + Collections.shuffle(PORTS); + } + + private static int nextCandidatePort() { + if (PORTS_ITERATOR == null || !PORTS_ITERATOR.hasNext()) { + PORTS_ITERATOR = PORTS.iterator(); + } + return PORTS_ITERATOR.next(); + } /** * Return a free port which can be used to bind to @@ -29,19 +54,28 @@ public class TestUtils { * @return port */ public static int getFreePort() { - for(int start = START_PORT; start <= END_PORT; start++) { + for (int i = 0; i < NUM_CANDIDATES; i ++) { + int port = nextCandidatePort(); try { - ServerSocket socket = new ServerSocket(start); - socket.setReuseAddress(true); - socket.close(); - START_PORT = start + 1; - return start; + // Ensure it is possible to bind on both wildcard and loopback. + ServerSocket ss; + ss = new ServerSocket(); + ss.setReuseAddress(false); + ss.bind(new InetSocketAddress(port)); + ss.close(); + + ss = new ServerSocket(); + ss.setReuseAddress(false); + ss.bind(new InetSocketAddress(NetworkConstants.LOCALHOST, port)); + ss.close(); + + return port; } catch (IOException e) { // ignore } - } - throw new RuntimeException("Unable to find a free port...."); + + throw new RuntimeException("unable to find a free port"); } private TestUtils() { } From eae7b2d6624782086d6911b02dff50eb1f24763a Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 16:58:26 +0900 Subject: [PATCH 25/29] [#532] HttpStaticFileServer should generate an index page * Add index page listing and directory redirection --- .../file/HttpStaticFileServerHandler.java | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java index 4f641bbacd..eeaa3d65d5 100644 --- a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java +++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java @@ -113,7 +113,8 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda return; } - final String path = sanitizeUri(request.getUri()); + final String uri = request.getUri(); + final String path = sanitizeUri(uri); if (path == null) { sendError(ctx, FORBIDDEN); return; @@ -124,6 +125,16 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda sendError(ctx, NOT_FOUND); return; } + + if (file.isDirectory()) { + if (uri.endsWith("/")) { + sendListing(ctx, file); + } else { + sendRedirect(ctx, uri + '/'); + } + return; + } + if (!file.isFile()) { sendError(ctx, FORBIDDEN); return; @@ -195,6 +206,10 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda } } + if (!uri.startsWith("/")) { + return null; + } + // Convert file separators. uri = uri.replace('/', File.separatorChar); @@ -210,6 +225,58 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda return System.getProperty("user.dir") + File.separator + uri; } + private static void sendListing(ChannelHandlerContext ctx, File dir) { + HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.OK); + response.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8"); + + StringBuilder buf = new StringBuilder(); + + buf.append("\r\n"); + buf.append(""); + buf.append("Listing of: "); + buf.append(dir.getPath()); + buf.append("\r\n"); + + buf.append("

Listing of: "); + buf.append(dir.getPath()); + buf.append("

\r\n"); + + buf.append("
    "); + buf.append("
  • ..
  • \r\n"); + + for (File f: dir.listFiles()) { + if (f.isHidden()) { + continue; + } + if (!f.canRead()) { + continue; + } + + String name = f.getName(); + + buf.append("
  • "); + buf.append(name); + buf.append("
  • \r\n"); + } + + buf.append("
\r\n"); + + response.setContent(Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8)); + + // Close the connection as soon as the error message is sent. + ctx.write(response).addListener(ChannelFutureListener.CLOSE); + } + + private static void sendRedirect(ChannelHandlerContext ctx, String newUri) { + HttpResponse response = new DefaultHttpResponse(HTTP_1_1, FOUND); + response.setHeader(LOCATION, newUri); + + // Close the connection as soon as the error message is sent. + ctx.write(response).addListener(ChannelFutureListener.CLOSE); + } + private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status); response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8"); From 9f6505192c4a243f4c4930d4b51f8b023bf81a2e Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 16:59:51 +0900 Subject: [PATCH 26/29] Simplify if --- .../netty/example/http/file/HttpStaticFileServerHandler.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java index eeaa3d65d5..75365fd74f 100644 --- a/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java +++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java @@ -245,10 +245,7 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda buf.append("
  • ..
  • \r\n"); for (File f: dir.listFiles()) { - if (f.isHidden()) { - continue; - } - if (!f.canRead()) { + if (f.isHidden() || !f.canRead()) { continue; } From b3d568c4d2e3b89f00d63017edb71ab51cba988b Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 17:45:40 +0900 Subject: [PATCH 27/29] de-duplicate plugin versions --- all/pom.xml | 5 ----- pom.xml | 34 ++++++++++++++++++++++++++++++++-- tarball/pom.xml | 6 ------ testsuite/pom.xml | 1 - 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index f9c3d23ae9..0bd51186ca 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -117,7 +117,6 @@ maven-clean-plugin - 2.5 clean-first @@ -130,7 +129,6 @@ maven-dependency-plugin - 2.4 unpack-sources @@ -162,7 +160,6 @@ org.codehaus.mojo build-helper-maven-plugin - 1.7 add-source @@ -203,7 +200,6 @@ maven-resources-plugin - 2.5 default-resources @@ -239,7 +235,6 @@ maven-jxr-plugin - 2.2 generate-xref diff --git a/pom.xml b/pom.xml index e60b40d424..75e49d950a 100644 --- a/pom.xml +++ b/pom.xml @@ -378,10 +378,40 @@ - + + maven-clean-plugin + 2.5 + + + maven-resources-plugin + 2.5 + + + maven-jar-plugin + 2.4 + + + maven-dependency-plugin + 2.4 + + + maven-assembly-plugin + 2.3 + + + maven-jxr-plugin + 2.2 + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + org.eclipse.m2e lifecycle-mapping diff --git a/tarball/pom.xml b/tarball/pom.xml index 880371f9aa..1ac13459f3 100644 --- a/tarball/pom.xml +++ b/tarball/pom.xml @@ -51,7 +51,6 @@ maven-clean-plugin - 2.5 clean-first @@ -87,7 +86,6 @@ maven-deploy-plugin - 2.7 true @@ -102,7 +100,6 @@ maven-dependency-plugin - 2.4 copy-jars @@ -158,7 +155,6 @@ maven-assembly-plugin - 2.3 build-tarball @@ -177,11 +173,9 @@ - - diff --git a/testsuite/pom.xml b/testsuite/pom.xml index bd7b5e5c23..05301c6342 100644 --- a/testsuite/pom.xml +++ b/testsuite/pom.xml @@ -45,7 +45,6 @@ maven-deploy-plugin - 2.7 true From 595e1067c7caf059d889181a5ada11d750d7c0c7 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 17:57:04 +0900 Subject: [PATCH 28/29] [maven-release-plugin] prepare release netty-4.0.0.Alpha5 --- all/pom.xml | 2 +- buffer/pom.xml | 2 +- codec-http/pom.xml | 2 +- codec/pom.xml | 2 +- common/pom.xml | 2 +- example/pom.xml | 2 +- handler/pom.xml | 2 +- pom.xml | 4 ++-- tarball/pom.xml | 2 +- testsuite/pom.xml | 2 +- transport/pom.xml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index 0bd51186ca..de72194906 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty diff --git a/buffer/pom.xml b/buffer/pom.xml index 17574e422b..a8b0b902b3 100644 --- a/buffer/pom.xml +++ b/buffer/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty-buffer diff --git a/codec-http/pom.xml b/codec-http/pom.xml index 7c369d4d0d..b40b5f5a7f 100644 --- a/codec-http/pom.xml +++ b/codec-http/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty-codec-http diff --git a/codec/pom.xml b/codec/pom.xml index e795254a0a..4dd040f308 100644 --- a/codec/pom.xml +++ b/codec/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty-codec diff --git a/common/pom.xml b/common/pom.xml index 6e641f43ef..9997c7df1f 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty-common diff --git a/example/pom.xml b/example/pom.xml index aeae757e55..75df527b59 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty-example diff --git a/handler/pom.xml b/handler/pom.xml index b1f902e878..30b7500f82 100644 --- a/handler/pom.xml +++ b/handler/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty-handler diff --git a/pom.xml b/pom.xml index 75e49d950a..91f6b68e09 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ io.netty netty-parent pom - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 Netty http://netty.io/ @@ -53,7 +53,7 @@ https://github.com/netty/netty scm:git:git://github.com/netty/netty.git scm:git:ssh://git@github.com/netty/netty.git - HEAD + netty-4.0.0.Alpha5 diff --git a/tarball/pom.xml b/tarball/pom.xml index 1ac13459f3..74a631258c 100644 --- a/tarball/pom.xml +++ b/tarball/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty-tarball diff --git a/testsuite/pom.xml b/testsuite/pom.xml index 05301c6342..f696dbd3b4 100644 --- a/testsuite/pom.xml +++ b/testsuite/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty-testsuite diff --git a/transport/pom.xml b/transport/pom.xml index e04bb88f74..b198db2dfa 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5-SNAPSHOT + 4.0.0.Alpha5 netty-transport From 820af50b636b2ae1176f24fc5a8dab38269b985e Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 28 Sep 2012 17:57:40 +0900 Subject: [PATCH 29/29] [maven-release-plugin] prepare for next development iteration --- all/pom.xml | 2 +- buffer/pom.xml | 2 +- codec-http/pom.xml | 2 +- codec/pom.xml | 2 +- common/pom.xml | 2 +- example/pom.xml | 2 +- handler/pom.xml | 2 +- pom.xml | 4 ++-- tarball/pom.xml | 2 +- testsuite/pom.xml | 2 +- transport/pom.xml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/all/pom.xml b/all/pom.xml index de72194906..1f553f0372 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty diff --git a/buffer/pom.xml b/buffer/pom.xml index a8b0b902b3..f661965a66 100644 --- a/buffer/pom.xml +++ b/buffer/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty-buffer diff --git a/codec-http/pom.xml b/codec-http/pom.xml index b40b5f5a7f..8e9d245872 100644 --- a/codec-http/pom.xml +++ b/codec-http/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty-codec-http diff --git a/codec/pom.xml b/codec/pom.xml index 4dd040f308..a9e9074fea 100644 --- a/codec/pom.xml +++ b/codec/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty-codec diff --git a/common/pom.xml b/common/pom.xml index 9997c7df1f..09e8aef32f 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty-common diff --git a/example/pom.xml b/example/pom.xml index 75df527b59..db66842354 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty-example diff --git a/handler/pom.xml b/handler/pom.xml index 30b7500f82..d0324ff43c 100644 --- a/handler/pom.xml +++ b/handler/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty-handler diff --git a/pom.xml b/pom.xml index 91f6b68e09..fc90c06f27 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ io.netty netty-parent pom - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT Netty http://netty.io/ @@ -53,7 +53,7 @@ https://github.com/netty/netty scm:git:git://github.com/netty/netty.git scm:git:ssh://git@github.com/netty/netty.git - netty-4.0.0.Alpha5 + HEAD diff --git a/tarball/pom.xml b/tarball/pom.xml index 74a631258c..a6bf2c7ee3 100644 --- a/tarball/pom.xml +++ b/tarball/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty-tarball diff --git a/testsuite/pom.xml b/testsuite/pom.xml index f696dbd3b4..76a92ed472 100644 --- a/testsuite/pom.xml +++ b/testsuite/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty-testsuite diff --git a/transport/pom.xml b/transport/pom.xml index b198db2dfa..e5733faf00 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ io.netty netty-parent - 4.0.0.Alpha5 + 4.0.0.Alpha6-SNAPSHOT netty-transport