Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a better way to handle decoder failures #441

Closed
naude-r opened this issue Jul 6, 2012 · 16 comments
Closed

Provide a better way to handle decoder failures #441

naude-r opened this issue Jul 6, 2012 · 16 comments
Assignees
Labels
Milestone

Comments

@naude-r
Copy link
Contributor

naude-r commented Jul 6, 2012

hi,

Have run into a problem when issuing a malformed HTTP request, e.g. GET /blah.

Netty generates an exception:
java.lang.IllegalArgumentException: empty text

This is correct, but one is not allowed to return an error message. Generating a BAD_REQUEST response results in another exception:
java.lang.IllegalStateException: cannot send more responses than requests

I guess this is due to a request never been generated? Additionally one cannot log an access record as the http request information is not available when receiving the exception in exceptionCaught.

What would be the best way to resolve this?

@jpinner
Copy link

jpinner commented Jul 6, 2012

I usually resolve this by catching the exception and passing a
"BAD_REQUEST" upstream. See:

https://github.com/twitter/finagle/blob/master/finagle-http/src/main/scala/com/twitter/finagle/http/Codec.scala

Hope this helps.

On Fri, Jul 6, 2012 at 2:53 AM, naude-r
reply@reply.github.com
wrote:

hi,

Have run into a problem when issuing a malformed HTTP request, e.g. GET /blah.

Netty generates an exception:
java.lang.IllegalArgumentException: empty text

This is correct, but one is not allowed to return an error message. Generating a BAD_REQUEST response results in another exception:
java.lang.IllegalStateException: cannot send more responses than requests

I guess this is due to a request never been generated? Additionally one cannot log an access record as the http request information is not available when receiving the exception in exceptionCaught.

What would be the best way to resolve this?


Reply to this email directly or view it on GitHub:
#441

@normanmaurer
Copy link
Member

@jpinner, @trustin I wonder if we should somehow make this "easier"

@ghost ghost assigned normanmaurer Jul 8, 2012
@normanmaurer
Copy link
Member

@naude-r btw could you please post the stacktraces here.. thanks!

@naude-r
Copy link
Contributor Author

naude-r commented Jul 9, 2012

The issue can triggered with the HttpStaticFileServer example:
telnet localhost 8080
GET /somefile
Host: localhost

java.lang.IllegalArgumentException: empty text
        at org.jboss.netty.handler.codec.http.HttpVersion.<init>(HttpVersion.java:97) ~[netty-3.5.2.Final.jar:na]
        at org.jboss.netty.handler.codec.http.HttpVersion.valueOf(HttpVersion.java:62) ~[netty-3.5.2.Final.jar:na]
        at org.jboss.netty.handler.codec.http.HttpRequestDecoder.createMessage(HttpRequestDecoder.java:76) ~[netty-3.5.2.Final.jar:na]
        at org.jboss.netty.handler.codec.http.HttpMessageDecoder.decode(HttpMessageDecoder.java:189) ~[netty-3.5.2.Final.jar:na]
        at org.jboss.netty.handler.codec.http.HttpMessageDecoder.decode(HttpMessageDecoder.java:101) ~[netty-3.5.2.Final.jar:na]
        at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:502) ~[netty-3.5.2.Final.jar:na]
        at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:437) ~[netty-3.5.2.Final.jar:na]
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268) ~[netty-3.5.2.Final.jar:na]
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255) ~[netty-3.5.2.Final.jar:na]
        at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:91) ~[netty-3.5.2.Final.jar:na]

@naude-r
Copy link
Contributor Author

naude-r commented Jul 9, 2012

@jpinner thank you. the work-around works just fine.

@jpinner
Copy link

jpinner commented Jul 11, 2012

@trustin, @normanmaurer would it be preferable to generate a "bad request" object in the request decoder and pass the object upstream (letting the user determine the error response, perform logging, etc.) or to catch the exception in the server codec and return an appropriate error response ourselves (400, 413, 414, etc.)

@trustin
Copy link
Member

trustin commented Jul 13, 2012

@jpinner I prefer to geretate a 'bad request' object in the request decoder.

@normanmaurer
Copy link
Member

@trustin @jpinner me too.. But I'm a bit worried about such a change in 3.5.x as it may break existing applications. What about to target it for 3.6.x ?

@trustin
Copy link
Member

trustin commented Aug 22, 2012

What about 4?

@normanmaurer
Copy link
Member

@trustin also ok :)

@ghost ghost assigned trustin Sep 23, 2012
@trustin
Copy link
Member

trustin commented Sep 23, 2012

Working on this. The idea is, when decoding fails, a bad http message is generated so that an inbound handler can handle it. Any subsequent inbound traffic should be discarded by the decoder. Sometimes, the handler might be expecting HttpChunk rather than HttpRequest/HttpResponse, so I think we should introduce a new supertype for HttpMessage and HttpChunk. The resulting type hierarchy could be:

interface HttpObject
interface HttpMessage extends HttpObject
interface HttpChunk extends HttpObject
interface BadHttpObject extends HttpObject
interface BadHttpMessage extends BadHttpObject
interface BadHttpChunk extends BadHttpObject

What do you think? BadHttpObject could provide the cause of the decode failure. A user might want to determine if the decode failed while decoding a chunk or not.

@jpinner
Copy link

jpinner commented Sep 25, 2012

In SPDY we indicate failure with a field in the object itself (see isInvalid method in SpdyHeaderBlock). I think we should do something similar here because of the following:

When we encounter an error we may want to pass / collect / generate / parse / etc. as much data as possible so that upstream handlers can log the cause of the error (maybe for statistics on bad clients or debug errors in the decoder). If we have already generated the request object and started decoding, we don't want to have to necessarily generate a new object and copy the data into it just to satisfy the class hierarchy. Consider the case of adding headers to a request object until exceeding the maximum header size and then deciding to declare the request as "bad." We may want to log the headers already received or the URI of the request and otherwise we would have to generate a new "bad" request object and copy the data or save the original request as a field within it. There is less wasted work by being able to simply "mark" the object as bad and perhaps given a reason (a response code for instance that can be used to indicate the type of error).

trustin added a commit that referenced this issue Sep 28, 2012
* Add DecodeResult that represents the result of decoding a message
* Add HttpObject which HttpMessage and HttpChunk extend.
** HttpObject has a property 'decodeResult'
trustin added a commit that referenced this issue Sep 28, 2012
* 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.
trustin added a commit that referenced this issue Sep 28, 2012
* Make HttpChunkAggregator handle DecoderResult properly
trustin added a commit that referenced this issue Sep 28, 2012
* Rename isPartial() to isPartialFailure()
* Add isCompleteFailure() and isFailure()
@trustin
Copy link
Member

trustin commented Sep 28, 2012

Check out the updated examples: 045b621

@slandelle
Copy link
Contributor

Hi,

I have the feeling that this issue also happens in 3.6: AsyncHttpClient/async-http-client#93
If so, any chance of having the fix backported?

Cheers,

Stéphane

@ThE-MaRaC
Copy link

Hi,

with the correction, output of the toString() method has been changed, content is not returned any more, what was the reason for this change?

Thx.

Regards,
ThE-MaRaC

@trustin
Copy link
Member

trustin commented Nov 15, 2013

@ThE-MaRaC Whose toString()?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants