mtrudel/bandit

Do not write 500 if an exception is already handled

Closed this issue · 4 comments

Today, Bandit sends a 500 response when an exception is rescued. However, when using a plug such as Plug.ErrorHandler, where an exception is handled and then re-raised, Bandit ends up sending a response after a response has already been written by the error handling function.

Perhaps this isn't too problematic, but I have found that some HTTP clients, such as Go's, will complain about an unexpected response being written to the open socket, with an error such as:

2024/01/11 11:59:51 Unsolicited response received on idle HTTP channel starting with HTTP/1.1 500 Internal Server Error
date: Thu, 11 Jan 2024 16:59:51 GMT
content-length: 0
vary: accept-encoding

I couldn't track down where the exception handling happens in Plug.Cowboy, but note that when using it, this issue doesn't appear to occur.

Yep, we should be doing a better job here. The relevant fix will be to check the process mailbox to see if we've sent ourselves a {:plug_conn, :sent} message, and to quell sending if so.

The scope of this is only HTTP/1. HTTP/2 does the right thing already since we use a multi-process model by necessity, and error trapping & reporting is an intrinsic part of the HTTP/2 model.

Cowboy gets a pass on this because their process model lets them keep state about whether a response has already been sent in the connection process, separate from the handler process. Their HTTP/1 process model is less efficient, but more robust to cases like this.

I'll get a fix up for this in the next few days. Thanks for the report!

Fix is up at #289 if you want to take a peek

Fix published in 1.1.3

Perfect, thank you @mtrudel!