aws-0.0.4: Aws/S3/Query.hs
{-# LANGUAGE OverloadedStrings, RecordWildCards #-}
module Aws.S3.Query
where
import Aws.Credentials
import Aws.Http
import Aws.Query
import Aws.S3.Info
import Aws.Signature
import Aws.Util
import Data.List
import Data.Maybe
import Data.Monoid
import Data.Time
import qualified Blaze.ByteString.Builder as Blaze
import qualified Blaze.ByteString.Builder.Char8 as Blaze8
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import qualified Network.HTTP.Types as HTTP
data S3Query
= S3Query {
s3QBucket :: Maybe B.ByteString
, s3QSubresources :: HTTP.Query
, s3QQuery :: HTTP.Query
}
deriving (Show)
s3SignQuery :: S3Query -> S3Info -> SignatureData -> SignedQuery
s3SignQuery S3Query{..} S3Info{..} SignatureData{..}
= SignedQuery {
sqMethod = method
, sqProtocol = s3Protocol
, sqHost = B.intercalate "." $ catMaybes host
, sqPort = s3Port
, sqPath = mconcat $ catMaybes path
, sqQuery = sortedSubresources ++ s3QQuery ++ authQuery
, sqDate = Just signatureTime
, sqAuthorization = authorization
, sqContentType = contentType
, sqContentMd5 = contentMd5
, sqBody = L.empty
, sqStringToSign = stringToSign
}
where
method = Get
contentMd5 = Nothing
contentType = Nothing
(host, path) = case s3RequestStyle of
PathStyle -> ([Just s3Endpoint], [Just "/", s3QBucket, Just "/"])
BucketStyle -> ([s3QBucket, Just s3Endpoint], [Just "/"])
VHostStyle -> ([Just $ fromMaybe s3Endpoint s3QBucket], [Just "/"])
sortedSubresources = sort s3QSubresources
canonicalizedResource = Blaze.copyByteString "/" `mappend`
maybe mempty Blaze.copyByteString s3QBucket `mappend`
HTTP.renderQueryBuilder True sortedSubresources `mappend`
Blaze.copyByteString "/"
ti = case (s3UseUri, signatureTimeInfo) of
(False, ti') -> ti'
(True, AbsoluteTimestamp time) -> AbsoluteExpires $ s3DefaultExpiry `addUTCTime` time
(True, AbsoluteExpires time) -> AbsoluteExpires time
sig = signature signatureCredentials HmacSHA1 stringToSign
stringToSign = Blaze.toByteString . mconcat . intersperse (Blaze8.fromChar '\n') . concat $
[[Blaze.copyByteString $ httpMethod method]
, [maybe mempty Blaze.copyByteString contentMd5]
, [maybe mempty Blaze.copyByteString contentType]
, [Blaze.copyByteString $ case ti of
AbsoluteTimestamp time -> fmtRfc822Time time
AbsoluteExpires time -> fmtTimeEpochSeconds time]
, [] -- canonicalized AMZ headers
, [canonicalizedResource]
]
(authorization, authQuery) = case ti of
AbsoluteTimestamp _ -> (Just $ B.concat ["AWS ", accessKeyID signatureCredentials, ":", sig], [])
AbsoluteExpires time -> (Nothing, HTTP.simpleQueryToQuery $ makeAuthQuery time)
makeAuthQuery time
= [("Expires", fmtTimeEpochSeconds time)
, ("AWSAccessKeyId", accessKeyID signatureCredentials)
, ("SignatureMethod", "HmacSHA256")
, ("Signature", sig)]