WIP: Trap postgres errors in middleware

Fixes #39
This commit is contained in:
Joe Nelson
2014-10-08 14:58:38 -07:00
parent 68d0a38806
commit 527d51670c
5 changed files with 97 additions and 71 deletions
+1
View File
@@ -36,6 +36,7 @@ executable dbapi
, PgStructure
, PgQuery
, RangeQuery
, Middleware
hs-source-dirs: src
Test-Suite spec
+3 -11
View File
@@ -5,7 +5,6 @@ module Dbapi where
import Types (SqlRow, getRow)
import Control.Exception (try)
import Control.Monad (join)
import Control.Exception.Base (bracket_)
import Control.Arrow ((***))
@@ -35,7 +34,6 @@ import Data.String.Conversions (cs)
import qualified Data.CaseInsensitive as CI
import Database.HDBC.PostgreSQL (Connection)
import Database.HDBC.Types (SqlError, seErrorMsg)
import PgStructure (printTables, printColumns, primaryKeyColumns,
columns, Column(colName))
@@ -94,7 +92,7 @@ app conn anonymous req respond = do
MalformedAuth ->
respond $ responseLBS status400 [] "Malformed basic auth header"
LoginFailed ->
respond $ responseLBS status403 [] "Invalid username or password"
respond $ responseLBS status401 [] "Invalid username or password"
LoginSuccess role ->
bracket_ (pgSetRole conn role) (pgResetRole conn) $ appWithRole conn req respond
NoCredentials ->
@@ -102,9 +100,8 @@ app conn anonymous req respond = do
appWithRole :: Connection -> Application
appWithRole conn req respond = do
r <- try $
case (path, verb) of
appWithRole conn req respond =
respond =<< case (path, verb) of
([], _) ->
responseLBS status200 [jsonContentType] <$> printTables ver conn
@@ -168,8 +165,6 @@ appWithRole conn req respond = do
(_, _) ->
return $ responseLBS status404 [] ""
respond $ either sqlErrorHandler id r
where
path = pathInfo req
verb = requestMethod req
@@ -232,9 +227,6 @@ requestedVersion hdrs =
accept = cs <$> lookup hAccept hdrs :: Maybe String
verStr = (=~ verRegex) <$> accept :: Maybe [[String]]
sqlErrorHandler :: SqlError -> Response
sqlErrorHandler e =
responseLBS status400 [] $ cs (seErrorMsg e)
addHeaders :: ResponseHeaders -> Response -> Response
addHeaders hdrs (ResponseFile s headers fp m) =
+2 -1
View File
@@ -4,6 +4,7 @@
module Main where
import Dbapi
import Middleware (reportPgErrors)
import Network.Wai.Handler.Warp hiding (Connection)
import Database.HDBC.PostgreSQL (connectPostgreSQL')
import Data.String.Conversions (cs)
@@ -40,7 +41,7 @@ main = do
Prelude.putStrLn $ "Listening on port " ++ (show $ configPort conf :: String)
conn <- connectPostgreSQL' dburi
runTLS tls settings $ gzip def $ cors corsPolicy $ app conn (cs $ configAnonRole conf)
runTLS tls settings $ gzip def $ cors corsPolicy $ reportPgErrors $ app conn (cs $ configAnonRole conf)
where
describe = progDesc "create a REST API to an existing Postgres database"
+33
View File
@@ -0,0 +1,33 @@
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Middleware where
import Data.Aeson
import Network.HTTP.Types.Header (hContentType)
import Network.HTTP.Types.Status (status400)
import Database.HDBC.Types (SqlError(..))
import Control.Exception (catchJust)
import Network.Wai
instance ToJSON SqlError where
toJSON t = object [
"error" .= object [
"code" .= seNativeError t
, "message" .= seErrorMsg t
, "state" .= seState t
]
]
reportPgErrors :: Middleware
reportPgErrors app req respond =
catchJust isPgException (app req respond) (
respond . responseLBS status400 [(hContentType, "application/json")]
. encode
)
where
isPgException :: SqlError -> Maybe SqlError
isPgException = Just
+2 -3
View File
@@ -13,12 +13,11 @@ spec :: Spec
spec = around appWithFixture $
describe "authorization" $ do
it "hides tables that anonymous does not own" $
-- TODO: should be 404
get "/authors_only" `shouldRespondWith` 400
get "/authors_only" `shouldRespondWith` 400 -- TODO: should be 404
it "indicates login failure" $ do
let auth = authHeader "dbapi_test_author_a" "fakefake"
request methodGet "/authors_only" [auth] ""
`shouldRespondWith` 403
`shouldRespondWith` 401
it "allows users with permissions to see their tables" $ do
let auth = authHeader "dbapi_test_author_a" ""
request methodGet "/authors_only" [auth] ""