packages feed

haskell-aliyun-0.1.0.0: Network/Aliyun/Utils.hs

{-# LANGUAGE OverloadedStrings #-}
module Network.Aliyun.Utils where

import qualified Prelude
import BasicPrelude

import qualified Data.ByteString as B
import qualified Data.CaseInsensitive as CI
import qualified Data.ByteString.Char8 as S
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Lazy as L
import Data.HMAC (hmac_sha1)
import qualified Data.Digest.MD5 as MD5

import qualified Network.HTTP.Types as W
import Network.HTTP.Conduit

canonicalizeHeaders :: W.RequestHeaders -> ByteString
canonicalizeHeaders hds =
    let hds' = [hd | hd <- hds, "x-oss-" `S.isPrefixOf` CI.foldedCase (fst hd)]

        -- merge grouped headers.
        merge :: [W.Header] -> W.Header
        merge [] = error "impossible [canonicalizeHeaders]"
        merge xs@((name, _):_) = (name, S.concat . intersperse "," $ map snd xs)

        hds'' = map merge . group . sortBy (comparing fst) $ hds'
    in  S.concat [S.concat [CI.foldedCase k, ":", v, "\n"] | (k,v) <- hds'']

bodyContent :: RequestBody m -> LByteString
bodyContent (RequestBodyLBS s) = s
bodyContent _ = error "unimplemented [bodyContent]"

authorizeRequest :: Request m -> ByteString -> ByteString -> Bool -> Request m
authorizeRequest req identity key needMD5 =
    let date    = fromMaybe "" $ lookup "Date" hds
        ctype   = fromMaybe "" $ lookup "Content-Type" hds
        bodyMD5 = B64.encode . B.pack . MD5.hash . L.unpack . bodyContent . requestBody $ req
        hds'    = requestHeaders req
        hds     = if needMD5 then ("Content-MD5", bodyMD5) : hds' else hds'
        s = S.concat [ method req, "\n"
                     , if needMD5 then bodyMD5 else "", "\n"
                     , ctype, "\n"
                     , date, "\n", canonicalizeHeaders hds
                     , path req
                     ]
        auth = S.concat [ "OSS ", identity, ":"
                        , B64.encode $ B.pack (hmac_sha1 (B.unpack key) (B.unpack s))
                        ]
    in  req { requestHeaders = ("Authorization", auth) : hds }