我用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)
最好的问候。