yeenow123
yeenow123

Reputation: 836

Netty - Skip the rest of the handlers in the pipeline

I'm currently using Netty 4.0 if that matters but anyways..

I have a handler written like so that I want to filter out requests depending on the URI:

public class URIFilterHandler extends SimpleChannelInboundHandler<HttpRequest> {

public void channelRead0(ChannelHandlerContext ctx, HttpRequest req) {
    String uri = req.uri();

    if (uri.contains("abcde")) {
        HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NO_CONTENT);
        ctx.writeAndFlush(response);
        // HERE IS WHERE I WANT TO SKIP REST OF THE HANDLERS

    } else {
        ctx.fireChannelRead(req);
    }
}
}

And then here is my pipeline

public class ServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    public void initChannel(SocketChannel ch) {
        ChannelPipeline p = ch.pipeline();

        p.addLast(new HttpRequestDecoder());
        p.addLast(new HttpResponseEncoder());
        p.addLast(new URIFilterHandler());
        p.addLast(new HttpObjectAggregator(1048576));
        p.addLast(new RequestHandler());

    }
}

I tried the following, but it seemed to permanently remove these handlers from the pipeline and not just for the one request.

       ctx.pipeline().remove(HttpObjectAggregator.class);
       ctx.pipeline().remove(RequestHandler.class;)

I tried using ctx.channel().close() and ctx.fireChannelInactive() to no avail. It seems to still pass the request onto the next handler (HttpObjectAggregator in this case). I think it's possibly being due to the close() and fireChannelInactive() being asynchronous?

EDIT: It seems the issue I was having was I was sending back a DefaultHttpResponse. When I sent back a DefaultFullHttpResponse, the request never hangs.

Upvotes: 2

Views: 3616

Answers (2)

Prim
Prim

Reputation: 2978

To skip the rest of the handlers, just do nothing. To continue to handle data with the next handler, with the initial object or with one another, call ctx.fireChannelRead( object )

Take care of reference counted objects. SimpleChannelInboundHandler release by default the input (depending on constructor parameters). If you decide to fire it to the next handler, you must call ReferenceCountUtil.retain(Object). See documentation here: http://netty.io/wiki/reference-counted-objects.html

Moreover, I think you should put the HttpObjectAggregator handler before your own handler on pipeline, and make your handler catching FullHttpRequest. HttpObjectAggregator handles all http chuncks for you and puts on pipeline a FullHttpRequest. In your case, it may be interessing because if you ignore one chunck, what do you do with others chuncks already aggregated on pipeline ? I guess you may have a DecoderException thrown if you do nothing.

Upvotes: 5

forty-two
forty-two

Reputation: 12817

If you don't call ctx.fireChannelRead() in channelRead0, then the message will not be propagated to the following handlers. This can be demonstrated with the following code snippet, where the first handler filters out all odd numbers:

    EmbeddedChannel channel = new EmbeddedChannel(
            new SimpleChannelInboundHandler<Integer>() {
                @Override
                protected void channelRead0(ChannelHandlerContext ctx,
                        Integer msg) throws Exception {
                    if (msg % 2 == 0)
                        ctx.fireChannelRead(msg);
                }
            },
            new ChannelInboundHandlerAdapter() {
                @Override
                public void channelRead(ChannelHandlerContext ctx, 
                       Object msg) throws Exception {
                    System.out.println(msg);
                }
            });

    channel.writeInbound(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Upvotes: 2

Related Questions