{-# LANGUAGE DeriveDataTypeable #-}
module Database.Bloodhound.Auth.Amazonka.Internal where
import Control.Applicative as A
import Control.Exception
import Data.Time.Clock
import Data.Typeable
import Network.AWS.Data.Body
import Network.AWS.Data.ByteString
import Network.AWS.Data.Path
import Network.AWS.Data.Query
import qualified Network.AWS.Data.Query as A
import Network.AWS.ElasticSearch (elasticSearch)
import Network.AWS.Types (AuthEnv, Region, sgRequest,
sgSign)
import qualified Network.AWS.Types as A
import Network.HTTP.Client
import Network.HTTP.Types.Method (Method, parseMethod)
import URI.ByteString
amazonkaAuthHook :: AuthEnv -> Region -> Request -> IO (Either EsAmazonkaAuthError Request)
amazonkaAuthHook ae reg req = amazonkaAuthHook' ae reg req A.<$> getCurrentTime
amazonkaAuthHook' :: AuthEnv -> Region -> Request -> UTCTime -> Either EsAmazonkaAuthError Request
amazonkaAuthHook' ae reg req now = toReq <$> toAwsRequest req reg
where algo = sgSign (A._svcSigner elasticSearch)
toReq req' = restoreTimeout (decodePath (sgRequest (algo req' ae reg now)))
decodePath x = x { path = urlDecode True (path x)}
restoreTimeout x = x { responseTimeout = responseTimeout req }
toAwsRequest :: Request -> Region -> Either EsAmazonkaAuthError (A.Request a)
toAwsRequest r reg = do
meth <- either (const (Left badMethod)) Right (parseMethod bsMeth)
rqb <- toRQBody (requestBody r)
q <- toQS (queryString r)
return (A.Request { A._rqService = svc
, A._rqMethod = meth
, A._rqPath = rawPath (path r)
, A._rqQuery = q
, A._rqHeaders = requestHeaders r
, A._rqBody = rqb})
where bsMeth = method r
badMethod = InvalidStdMethod bsMeth
svc = elasticSearch { A._svcEndpoint = const endpoint}
endpoint = requestEndpoint r reg
toQS :: ByteString -> Either EsAmazonkaAuthError A.QueryString
toQS bs = case parseRelativeRef laxURIParserOptions bs of
Right rr -> Right (go (rrQuery rr))
Left _ -> Left MalformedQueryString
where go q = QList [ QPair k (QValue (Just v)) | (k, v) <- queryPairs q]
requestEndpoint :: Request -> Region -> A.Endpoint
requestEndpoint r reg = A.Endpoint { A._endpointHost = host r
, A._endpointSecure = secure r
, A._endpointPort = port r
, A._endpointScope = toBS reg}
data EsAmazonkaAuthError = InvalidStdMethod Method
| StreamingBodyNotSupported
| MalformedQueryString deriving (Show, Eq, Typeable)
instance Exception EsAmazonkaAuthError
toRQBody :: RequestBody -> Either EsAmazonkaAuthError RqBody
toRQBody (RequestBodyLBS b) = Right (toBody b)
toRQBody (RequestBodyBS b) = Right (toBody b)
toRQBody _ = Left StreamingBodyNotSupported