Reputation: 875
This is based on the suggestion from my earlier question here:
go bs = do
r <- try $ parseRequest reader bs secure
case r of
Left ex -> do
putStrLn "got exception"
exceptionHandler writer ex
go empty
Right (request, bs') -> do
sendResponse writer =<< app request
go bs'
When there is no exception, the Right part runs no problem. However when an exception is thrown, the exception bubbles all the way to the top and Left isn't run. It doesn't seem to mater what kind of exception it is.
Here are the exceptions that is it supposed to catch (though it also won't catch error
):
data ParseError
= Unexpected
| MalformedRequestLine ByteString
| MalformedHeader ByteString
| MissingHeader ByteString Headers
| UnknownSIPVersion ByteString
deriving (Typeable, Show, Eq)
instance Exception ParseError
Here is the type of exceptionHandler:
exceptionHandler :: (ByteString -> IO ())
-> ParseError
-> IO ()
Also this is version 7.4.1 of ghc.
Any ideas why?
Upvotes: 0
Views: 162
Reputation: 139890
I suspect the problem is that you're using a throw
which doesn't get evaluated within the scope of the try
. In that case, you will get the exception after the try
instead, when you try to use the result. If you can, use throwIO
instead to ensure that the exception gets thrown at the correct time.
Notice the difference:
> :set -XDeriveDataTypeable
> :m + Control.Exception Data.Typeable
> data Boom = Boom deriving (Show, Typeable)
> instance Exception Boom
> try $ return (throw Boom) :: IO (Either Boom Int)
Right *** Exception: Boom
> try $ throwIO Boom :: IO (Either Boom Int)
Left Boom
Upvotes: 7
Reputation: 64740
Your question pains me because if you use the correct try
it should work, but you have failed to provide a minimum example. Instead, I will provide a functional example and leave it to you to determine what is different in your code.
{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-}
I only needed ScopedTypeVariables
because I didn't use an explicitly typed function.
import Control.Exception as X
import Data.ByteString as B
import Data.Typeable
import Data.Data
Notice I am using the Control.Exception
module, and the try
function from there. I suspect your try
comes from elsewhere.
data ParseError
= Unexpected
| MalformedRequestLine ByteString
| MalformedHeader ByteString
| MissingHeader ByteString ()
| UnknownSIPVersion ByteString
deriving (Typeable, Show, Eq)
instance Exception ParseError
parseRequest :: IO Int
parseRequest = throw Unexpected
For testing, my parseResult
just throws something.
exceptionHandler :: (ByteString -> IO ())
-> ParseError
-> IO ()
exceptionHandler f p = print p
main = do
r <- X.try parseRequest
case r of
Right i -> print i
Left (e :: ParseError) -> print ("Caught",e)
And the main routine is pretty boring - just a summary of the important parts of your routine. It runs fine:
$ ghc so.hs
[1 of 1] Compiling Main ( so.hs, so.o )
Linking so ...
$ ./so
("Caught",Unexpected)
If you modify the exception to a different type you'll see the exception is not caught:
parseRequest :: IO Int
parseRequest = error "This is a different type, and won't be caught by 'ParseError' handlers."
With a result of:
$ ./so
so: This is a different type, thus not caught by 'ParseError' handlers.
If you wish to catch ALL exceptions then you need a type that suffices for that task.
Upvotes: 1