Happstack’s “Helpful” Exception Handler

Lately I’ve been messing around with web development in Haskell using Happstack. I believe that web development is something that a pure functional language excels in. Web apps are inherently stateless, so it stands to reason that a stateless programming language would be a good fit.

Happstack provides many of the nice features one would expect of a web framework. Among these things is a top-level exception handler to prevent exceptions from bringing down the server. Suppose you try to call head on an empty list:

willThrow :: ServerPart Response willThrow = ok $ head []

This will of course throw an exception. Happstack “helpfully” catches it and produces this output:

bad_throw_1

Why the air quotes? Notice how Happstack prints the exception message? While this might seem somewhat benign with a simple empty list exception (maybe even helpful if you’re troubleshooting), imagine you’re doing something a little less contrived:

maliciousThrow :: ServerPart Response maliciousThrow = do dirs <- liftIO $ getDirectoryContents "/bar" ok $ toResponse $ show $ dirs

Once again Happstack airs out your dirty laundry.

bad_throw_2

In this case, it prints the fact that /bar doesn’t exist for the whole world to see. Great

I spent some time searching around for the proper way to deal with exceptions in Happstack. There doesn’t seem to be much other than “handle them”. Personally, I feel that if an unhandled exception is thrown, Happstack should treat it as mzero.

This can be accomplished pretty simply:

noThrow :: ServerPart Response noThrow = do dirs <- liftIO $ tryGDC "/bar" case (dirs) of Right d -> ok $ toResponse $ show $ d Left _ -> mzero where tryGDC :: String -> IO (Either SomeException [FilePath]) tryGDC a = try $ getDirectoryContents a

This function is similar to the previous maliciousThrow, except for the tryGDC function. This function uses the try function found within Control.Exception. Try attempts to perform some IO action, and returns Either an exception or a result, wrapped within an IO.

It is necessary to give tryGDC a function signature. Since functions can throw multiple exception types, the type checker cannot infer which is correct. In this case I’ve used the top-level exception class SomeException.

After trying, I check the result. On Right I return a ServerPart Response, on Left, I return mzero. Now when I attempt to access the page using this new version of maliciousThrow, I get this:

no_throw

As it should be. It’s nobody’s business what went wrong.

Best Practices

It should be noted that the function noThrow is equivalent in quality to the following snippet of Java:

public static ThingDoer newThingDoer () { try { return ThingDoerFactory.constructThingDoer(); } catch (Exception ex) { return null; } }

If you wrote that in a real application, you would be a Bad Person. Similarly, noThrow discards all info about what went wrong. You really should do something with it. Don’t show it to the user, but log it somewhere.

Update: I’ve posted a follow-up to this article, which can be found here!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: