Consider this server: it attempts to return a string with status 200,
however the string's value is `undefined`.
import Control.Monad.Catch (SomeException, handle)
main :: IO ()
main = do
let sendResponse = ok $ toResponse (fromJust Nothing :: String)
simpleHTTP nullConf (handle errorPage sendResponse)
where
errorPage :: SomeException -> ServerPart Response
errorPage _ = (internalServerError $ toResponse "Custom error page!")
On each request, this server replies with "200 OK" with no
content (even though philosophically there was a clear internal server
error, and furthermore there is an error handler present). At least
it outputs "HTTP request failed with: Maybe.fromJust: Nothing" to
stderr.
This patch makes it possible to deeply strictly evaluate Response
objects before sending the HTTP response. Then errors like these can
be caught and an error page shown. The application can be changed to
something like this:
import Control.DeepSeq (deepseq)
import Control.Monad.Catch (SomeException, handle)
handleServerPartError :: ServerPart Response -> ServerPart Response
handleServerPartError s = handle errorPage $ do
res <- s
deepseq res (return res)
where
errorPage :: SomeException -> ServerPart Response
errorPage _ = (internalServerError $ toResponse "Custom error page!")
main :: IO ()
main = do
let sendResponse = ok $ toResponse (fromJust Nothing :: String)
simpleHTTP nullConf (handleServerPartError sendResponse)
Which deeply, strictly evaluates the Response, revealing the
`undefined` that is present and displaying the custom error page.
Not all requests (streaming videos, for example) can or should be
deeply strictly evaluated before being sent to the client. However,
for requests like those, the client often knows not to fully trust the
200 status code of the response, and likely has some error handling
built in if the response data does not stream in in the expected
format. For most HTTP requests, the status code can be trusted, and
client applications should not need to have any special handling.