IllegalStateExceptions not setting content-length for non-chunked encoding

1,589 views
Skip to first unread message

Alan Quinton

unread,
Dec 1, 2015, 12:19:30 PM12/1/15
to vert.x
Hi,
   In our Vert.x (3.1.0) server application we are seeing a profusion of these exceptions which apparently are destabilizing the application . Although it's clear our clients *should* be setting the Content-Length parameter in their requests, our concern is that we don't control all of these requests and would like to bullet-proof the server so that these are not generated. Another real concern is that a malicious client could destabilize the application by generating lots of these requests. The exception stack is provided below. 

Is there any hook which will allow us to pre-process these? 

Nov 18, 2015 9:14:07 AM io.vertx.core.impl.ContextImpl

SEVERE: Unhandled exception

java.lang.IllegalStateException: You must set the Content-Length header to be the total size of the message body BEFORE sending any data if you are not using HTTP chunked encoding.

               at io.vertx.core.http.impl.HttpServerResponseImpl.write(HttpServerResponseImpl.java:576)

               at io.vertx.core.http.impl.HttpServerResponseImpl.write(HttpServerResponseImpl.java:270)

               at io.vertx.core.http.impl.HttpServerResponseImpl.write(HttpServerResponseImpl.java:52)

               at io.vertx.core.streams.impl.PumpImpl.lambda$new$207(PumpImpl.java:64)

               at io.vertx.core.http.impl.HttpClientResponseImpl.handleChunk(HttpClientResponseImpl.java:205)

               at io.vertx.core.http.impl.ClientConnection.handleResponseChunk(ClientConnection.java:279)

               at io.vertx.core.http.impl.HttpClientImpl$ClientHandler.doMessageReceived(HttpClientImpl.java:861)

               at io.vertx.core.http.impl.HttpClientImpl$ClientHandler.doMessageReceived(HttpClientImpl.java:832)

               at io.vertx.core.http.impl.VertxHttpHandler.lambda$channelRead$18(VertxHttpHandler.java:80)

               at io.vertx.core.impl.ContextImpl.lambda$wrapTask$16(ContextImpl.java:333)

               at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:225)

               at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:80)

               at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:124)

               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

               at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)

               at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)

               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

               at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)

               at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:244)

               at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:147)

               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

               at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)

               at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1107)

               at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:965)

               at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:327)

               at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:230)

               at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)

               at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)

               at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)

               at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)

               at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)

               at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)

               at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)

               at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)

               at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)

               at java.lang.Thread.run(Thread.java:745)


Thanks for any advice,

Alan

 

Nat

unread,
Dec 1, 2015, 1:08:31 PM12/1/15
to vert.x
you should change your code instead by either 
1. If the header "Content-Length" is not provided, you should call HttpServerResponse.setChunked(true)
2. Buffer the response from http client and then write the response in one go as you know the content length by then.

Alexander Lehmann

unread,
Dec 2, 2015, 8:39:33 AM12/2/15
to vert.x
Actually this is has kind of bothered me before, but I didn't get around to further investigating this.

A response without Content-Length is legal without chunked encoding, but this is not implemented by vert.x.

Rob Worsnop

unread,
Jan 1, 2016, 9:57:56 PM1/1/16
to vert.x
The root of this seems to be a misunderstanding on Tim's part about what the HTTP 1.1 spec says about Content-Length and Transfer-Encoding:chunked.


Especially when a client isn't using persistent connections, we really ought to be able to send responses without either of these headers.

Tim Fox

unread,
Jan 2, 2016, 4:45:04 AM1/2/16
to ve...@googlegroups.com
On 02/12/15 13:39, Alexander Lehmann wrote:
Actually this is has kind of bothered me before, but I didn't get around to further investigating this.

A response without Content-Length is legal without chunked encoding, but this is not implemented by vert.x.

It's only legal in the case that the server terminates the connection immediately afterwards - in general I wouldn't recommend this as it will prevent keep-alive.

I can't remember why this is not implemented in Vert.x, I have a vague recollection of Netty not supporting it at the time but that was a long time ago.

--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
Visit this group at http://groups.google.com/group/vertx.
To view this discussion on the web, visit https://groups.google.com/d/msgid/vertx/a9d52532-0af5-4f6f-abd3-e966d702e868%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alexander Lehmann

unread,
Jan 2, 2016, 10:48:48 AM1/2/16
to vert.x
My reasoning would be the client can determine (and has to) if the connection can use keep-alive or not by the response headers (i.e. no content-length and no chunked) and switch to non keep-alive for this connection, the same will happen with any other server that is not vertx, e.g. when accessing apache with a regular cgi script

Tim Fox

unread,
Jan 2, 2016, 12:18:19 PM1/2/16
to ve...@googlegroups.com
My point was more about good server side application design.

While we should support not setting content-length for responses that are closed immediately I wouldn't recommend always closing connections after writing a response as it will probably make your app scale poorly.
Reply all
Reply to author
Forward
0 new messages