当标头长度超过帧大小时,HttpMessageDecoder将调用下一个处理程序

时间:2013-11-18 11:57:25

标签: httprequest netty

我用netty创建简单的http-server并测试它。 HTTP客户端向服务器发送非法的http请求。 非法的http请求标头太长(超过8192bytes)。

但是当HttpMessageDecoder收到tcp流的最后一帧时,它会使用部分请求调用下一个处理程序。 请求将连接第一帧和最后一帧。

我认为,当HttpMessageDecoder抛出TooLongFrameException时,它应该被称为reset()方法。

我创建了重现此问题的代码。 (我在netty-example中更改了2类HttpHelloWorldServer)

HttpHelloWorldServerPipelineFactory.java

public class HttpHelloWorldServerPipelineFactory implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
    // Create a default pipeline implementation.
    ChannelPipeline pipeline = pipeline();

    // Uncomment the following line if you want HTTPS
    //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
    //engine.setUseClientMode(false);
    //pipeline.addLast("ssl", new SslHandler(engine));

    pipeline.addLast("decoder", new HttpRequestDecoder());
    // Uncomment the following line if you don't want to handle HttpChunks.
    //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
    pipeline.addLast("encoder", new HttpResponseEncoder());
    // Remove the following line if you don't want automatic content compression.
    //pipeline.addLast("deflater", new HttpContentCompressor());
    pipeline.addLast("handler", new HttpHelloWorldServerHandler());
    return pipeline;
}
}

HttpHelloWorldServerHandler.java

public class HttpHelloWorldServerHandler extends SimpleChannelUpstreamHandler {

private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    Object msg = e.getMessage();
    Channel ch = e.getChannel();
    if (msg instanceof HttpRequest) {
        HttpRequest req = (HttpRequest) msg;

        System.out.println("messageReceived:[req=" + req + "]");

        if (is100ContinueExpected(req)) {
            Channels.write(ctx, Channels.future(ch), new DefaultHttpResponse(HTTP_1_1, CONTINUE));
        }

        boolean keepAlive = isKeepAlive(req);
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
        response.setContent(ChannelBuffers.wrappedBuffer(CONTENT));
        response.headers().set(CONTENT_TYPE, "text/plain");
        response.headers().set(CONTENT_LENGTH, response.getContent().readableBytes());

        if (!keepAlive) {
            ChannelFuture f = Channels.future(ch);
            f.addListener(ChannelFutureListener.CLOSE);
            Channels.write(ctx, f, response);
        } else {
            response.headers().set(CONNECTION, Values.KEEP_ALIVE);
            Channels.write(ctx, Channels.future(ch), response);
        }
    }
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
        throws Exception {
    Throwable cause = e.getCause();
    Channel ch = e.getChannel();
    if(cause instanceof TooLongFrameException) {
        ChannelFuture f = ch.write(new DefaultHttpResponse(HTTP_1_1, BAD_REQUEST));
        f.addListener(ChannelFutureListener.CLOSE);
    } else {
        e.getCause().printStackTrace();
        e.getChannel().close();
    }
}
}

并启动HttpHelloWorldServer并使用长标头发送请求(大约8200bytes)。

此服务器输出到stdout,如下所示。

$ java -cp . org.jboss.netty.example.http.helloworld.HttpHelloWorldServer
messageReceived:[req=DefaultHttpRequest(chunked: false)
GET / HTTP/1.1
testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest
testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest
testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest
testtesttesttesttesttesttesttesttesttesttesttesttesttest:
Host: localhost:8080
User-Agent: Apache-HttpClient/4.1.3 (java 1.5)]
java.nio.channels.ClosedChannelException
        at org.jboss.netty.channel.socket.nio.AbstractNioWorker.cleanUpWriteBuff
er(AbstractNioWorker.java:433)
        at org.jboss.netty.channel.socket.nio.AbstractNioWorker.writeFromUserCod
e(AbstractNioWorker.java:128)
        at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.handle
AcceptedSocket(NioServerSocketPipelineSink.java:99)
        at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.eventS
unk(NioServerSocketPipelineSink.java:36)
        at org.jboss.netty.channel.Channels.write(Channels.java:725)
        at org.jboss.netty.handler.codec.oneone.OneToOneEncoder.doEncode(OneToOn
eEncoder.java:71)
        at org.jboss.netty.handler.codec.oneone.OneToOneEncoder.handleDownstream
(OneToOneEncoder.java:59)
        at org.jboss.netty.channel.Channels.write(Channels.java:725)
        at org.jboss.netty.channel.Channels.write(Channels.java:686)
        at org.jboss.netty.example.http.helloworld.HttpHelloWorldServerHandler.m
essageReceived(HttpHelloWorldServerHandler.java:72)
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:29
6)
        at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessage
Received(FrameDecoder.java:459)
        at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(Repl
ayingDecoder.java:536)
        at org.jboss.netty.handler.codec.replay.ReplayingDecoder.cleanup(Replayi
ngDecoder.java:554)
        at org.jboss.netty.handler.codec.frame.FrameDecoder.channelDisconnected(
FrameDecoder.java:365)
        at org.jboss.netty.channel.Channels.fireChannelDisconnected(Channels.jav
a:396)
        at org.jboss.netty.channel.socket.nio.AbstractNioWorker.close(AbstractNi
oWorker.java:360)
        at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.handle
AcceptedSocket(NioServerSocketPipelineSink.java:81)
        at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.eventS
unk(NioServerSocketPipelineSink.java:36)
        at org.jboss.netty.handler.codec.oneone.OneToOneEncoder.handleDownstream
(OneToOneEncoder.java:54)
        at org.jboss.netty.channel.Channels.close(Channels.java:812)
        at org.jboss.netty.channel.AbstractChannel.close(AbstractChannel.java:19
7)
        at org.jboss.netty.channel.ChannelFutureListener$1.operationComplete(Cha
nnelFutureListener.java:41)
        at org.jboss.netty.channel.DefaultChannelFuture.notifyListener(DefaultCh
annelFuture.java:427)
        at org.jboss.netty.channel.DefaultChannelFuture.addListener(DefaultChann
elFuture.java:145)
        at org.jboss.netty.example.http.helloworld.HttpHelloWorldServerHandler.e
xceptionCaught(HttpHelloWorldServerHandler.java:85)
        at org.jboss.netty.handler.codec.frame.FrameDecoder.exceptionCaught(Fram
eDecoder.java:377)
        at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:52
5)
        at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractC
hannelSink.java:48)
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:26
8)
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:25
5)
        at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88)
        at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(Abstract
NioWorker.java:108)
        at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNi
oSelector.java:318)
        at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioW
orker.java:89)
        at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.
java:1110)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:603)
        at java.lang.Thread.run(Thread.java:722)

最好的问候。

1 个答案:

答案 0 :(得分:0)

这听起来像个错误。请通过我们的错误跟踪器[1]打开错误报告。

[1] https://github.com/netty/netty