Proper exception propogation

This commit is contained in:
Michael Snoyman 2010-10-05 11:16:42 +02:00
parent 48f31ed6de
commit 63853a78df
2 changed files with 37 additions and 15 deletions

View File

@ -29,25 +29,28 @@ import Network.HTTP.Enumerator
import qualified Data.ByteString.Lazy.UTF8 as BSLU import qualified Data.ByteString.Lazy.UTF8 as BSLU
import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Char8 as S8
import Control.Arrow (first, (***)) import Control.Arrow (first, (***))
import Control.Applicative ((<$>)) import Control.Monad.IO.Class (MonadIO)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Failure (Failure (failure)) import Control.Failure (Failure (failure))
import Control.Monad (mplus) import Control.Monad (mplus, liftM)
data Discovery = Discovery1 String (Maybe String) data Discovery = Discovery1 String (Maybe String)
| Discovery2 Provider Identifier | Discovery2 Provider Identifier
deriving Show deriving Show
-- | Attempt to resolve an OpenID endpoint, and user identifier. -- | Attempt to resolve an OpenID endpoint, and user identifier.
discover :: (MonadIO m, Failure OpenIdException m) discover :: ( MonadIO m
, Failure OpenIdException m
, Failure HttpException m
, Failure InvalidUrlException m
)
=> Identifier => Identifier
-> m Discovery -> m Discovery
discover ident@(Identifier i) = do discover ident@(Identifier i) = do
res1 <- liftIO $ discoverYADIS ident Nothing res1 <- discoverYADIS ident Nothing
case res1 of case res1 of
Just (x, y) -> return $ Discovery2 x y Just (x, y) -> return $ Discovery2 x y
Nothing -> do Nothing -> do
res2 <- liftIO $ discoverHTML ident res2 <- discoverHTML ident
case res2 of case res2 of
Just x -> return x Just x -> return x
Nothing -> failure $ DiscoveryException i Nothing -> failure $ DiscoveryException i
@ -56,9 +59,13 @@ discover ident@(Identifier i) = do
-- | Attempt a YADIS based discovery, given a valid identifier. The result is -- | Attempt a YADIS based discovery, given a valid identifier. The result is
-- an OpenID endpoint, and the actual identifier for the user. -- an OpenID endpoint, and the actual identifier for the user.
discoverYADIS :: Identifier discoverYADIS :: ( MonadIO m
, Failure HttpException m
, Failure InvalidUrlException m
)
=> Identifier
-> Maybe String -> Maybe String
-> IO (Maybe (Provider,Identifier)) -> m (Maybe (Provider,Identifier))
discoverYADIS ident mb_loc = do discoverYADIS ident mb_loc = do
let uri = fromMaybe (identifier ident) mb_loc let uri = fromMaybe (identifier ident) mb_loc
req <- parseUrl uri req <- parseUrl uri
@ -103,9 +110,14 @@ parseYADIS ident = listToMaybe . mapMaybe isOpenId . concat
-- | Attempt to discover an OpenID endpoint, from an HTML document. The result -- | Attempt to discover an OpenID endpoint, from an HTML document. The result
-- will be an endpoint on success, and the actual identifier of the user. -- will be an endpoint on success, and the actual identifier of the user.
discoverHTML :: Identifier -> IO (Maybe Discovery) discoverHTML :: ( MonadIO m
, Failure HttpException m
, Failure InvalidUrlException m
)
=> Identifier
-> m (Maybe Discovery)
discoverHTML ident'@(Identifier ident) = discoverHTML ident'@(Identifier ident) =
parseHTML ident' . BSLU.toString <$> simpleHttp ident (parseHTML ident' . BSLU.toString) `liftM` simpleHttp ident
-- | Parse out an OpenID endpoint and an actual identifier from an HTML -- | Parse out an OpenID endpoint and an actual identifier from an HTML
-- document. -- document.

View File

@ -17,12 +17,18 @@ import Control.Monad (unless)
import qualified Data.ByteString.UTF8 as BSU import qualified Data.ByteString.UTF8 as BSU
import qualified Data.ByteString.Lazy.UTF8 as BSLU import qualified Data.ByteString.Lazy.UTF8 as BSLU
import Network.HTTP.Enumerator import Network.HTTP.Enumerator
(parseUrl, urlEncodedBody, responseBody, httpLbsRedirect) ( parseUrl, urlEncodedBody, responseBody, httpLbsRedirect
, HttpException, InvalidUrlException
)
import Control.Arrow ((***)) import Control.Arrow ((***))
import Data.List (unfoldr) import Data.List (unfoldr)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
getForwardUrl :: (MonadIO m, Failure OpenIdException m) getForwardUrl :: ( MonadIO m
, Failure OpenIdException m
, Failure HttpException m
, Failure InvalidUrlException m
)
=> String -- ^ The openid the user provided. => String -- ^ The openid the user provided.
-> String -- ^ The URL for this application\'s complete page. -> String -- ^ The URL for this application\'s complete page.
-> m String -- ^ URL to send the user to. -> m String -- ^ URL to send the user to.
@ -44,7 +50,11 @@ getForwardUrl openid' complete = do
, ("openid.return_to", complete) , ("openid.return_to", complete)
] ]
authenticate :: (MonadIO m, Failure OpenIdException m) authenticate :: ( MonadIO m
, Failure OpenIdException m
, Failure InvalidUrlException m
, Failure HttpException m
)
=> [(String, String)] => [(String, String)]
-> m Identifier -> m Identifier
authenticate params = do authenticate params = do
@ -61,9 +71,9 @@ authenticate params = do
let params' = map (BSU.fromString *** BSU.fromString) let params' = map (BSU.fromString *** BSU.fromString)
$ ("openid.mode", "check_authentication") $ ("openid.mode", "check_authentication")
: filter (\(k, _) -> k /= "openid.mode") params : filter (\(k, _) -> k /= "openid.mode") params
req' <- liftIO $ parseUrl endpoint req' <- parseUrl endpoint
let req = urlEncodedBody params' req' let req = urlEncodedBody params' req'
rsp <- liftIO $ httpLbsRedirect req rsp <- httpLbsRedirect req
let rps = parseDirectResponse $ BSLU.toString $ responseBody rsp let rps = parseDirectResponse $ BSLU.toString $ responseBody rsp
case lookup "is_valid" rps of case lookup "is_valid" rps of
Just "true" -> return $ Identifier ident Just "true" -> return $ Identifier ident