    {-# LANGUAGE CPP #-}

    module Aws.S3.Commands.GetObject
    where

    import           Aws.Core
    import           Aws.S3.Core
    import           Control.Applicative
    import           Control.Monad.Trans.Resource (ResourceT)
    import           Data.ByteString.Char8 ({- IsString -})
    import qualified Data.ByteString.Char8 as B8
    import qualified Data.ByteString.Lazy  as L
    import qualified Data.Conduit          as C
    import           Data.Conduit ((.|))
    import qualified Data.Conduit.List     as CL
    import           Data.Maybe
    import qualified Data.Text             as T
    import qualified Data.Text.Encoding    as T
    import           Prelude
    import qualified Network.HTTP.Conduit  as HTTP
    import qualified Network.HTTP.Types    as HTTP

    data GetObject
        = GetObject {
            GetObject -> Bucket
    goBucket :: Bucket
          , GetObject -> Bucket
    goObjectName :: Object
          , GetObject -> Maybe Bucket
    goVersionId :: Maybe T.Text
          , GetObject -> Maybe Bucket
    goResponseContentType :: Maybe T.Text
          , GetObject -> Maybe Bucket
    goResponseContentLanguage :: Maybe T.Text
          , GetObject -> Maybe Bucket
    goResponseExpires :: Maybe T.Text
          , GetObject -> Maybe Bucket
    goResponseCacheControl :: Maybe T.Text
          , GetObject -> Maybe Bucket
    goResponseContentDisposition :: Maybe T.Text
          , GetObject -> Maybe Bucket
    goResponseContentEncoding :: Maybe T.Text
          , GetObject -> Maybe (Int, Int)
    goResponseContentRange :: Maybe (Int,Int)
          , GetObject -> Maybe Bucket
    goIfMatch :: Maybe T.Text
          -- ^ Return the object only if its entity tag (ETag, which is an md5sum of the content) is the same as the one specified; otherwise, catch a 'StatusCodeException' with a status of 412 precondition failed.
          , GetObject -> Maybe Bucket
    goIfNoneMatch :: Maybe T.Text
          -- ^ Return the object only if its entity tag (ETag, which is an md5sum of the content) is different from the one specified; otherwise, catch a 'StatusCodeException' with a status of 304 not modified.
          }
      deriving (Int -> GetObject -> ShowS
    [GetObject] -> ShowS
    GetObject -> String
    (Int -> GetObject -> ShowS)
    -> (GetObject -> String)
    -> ([GetObject] -> ShowS)
    -> Show GetObject
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> GetObject -> ShowS
    showsPrec :: Int -> GetObject -> ShowS
    $cshow :: GetObject -> String
    show :: GetObject -> String
    $cshowList :: [GetObject] -> ShowS
    showList :: [GetObject] -> ShowS
    Show)

    getObject :: Bucket -> T.Text -> GetObject
    getObject :: Bucket -> Bucket -> GetObject
    getObject Bucket
    b Bucket
    o = Bucket
    -> Bucket
    -> Maybe Bucket
    -> Maybe Bucket
    -> Maybe Bucket
    -> Maybe Bucket
    -> Maybe Bucket
    -> Maybe Bucket
    -> Maybe Bucket
    -> Maybe (Int, Int)
    -> Maybe Bucket
    -> Maybe Bucket
    -> GetObject
    GetObject Bucket
    b Bucket
    o Maybe Bucket
    forall a. Maybe a
    Nothing Maybe Bucket
    forall a. Maybe a
    Nothing Maybe Bucket
    forall a. Maybe a
    Nothing Maybe Bucket
    forall a. Maybe a
    Nothing Maybe Bucket
    forall a. Maybe a
    Nothing Maybe Bucket
    forall a. Maybe a
    Nothing Maybe Bucket
    forall a. Maybe a
    Nothing Maybe (Int, Int)
    forall a. Maybe a
    Nothing Maybe Bucket
    forall a. Maybe a
    Nothing Maybe Bucket
    forall a. Maybe a
    Nothing

    data GetObjectResponse
        = GetObjectResponse {
            GetObjectResponse -> ObjectMetadata
    gorMetadata :: ObjectMetadata,
            GetObjectResponse
    -> Response (ConduitM () ByteString (ResourceT IO) ())
    gorResponse :: HTTP.Response (C.ConduitM () B8.ByteString (ResourceT IO) ())
          }

    data GetObjectMemoryResponse
        = GetObjectMemoryResponse ObjectMetadata (HTTP.Response L.ByteString)
        deriving (Int -> GetObjectMemoryResponse -> ShowS
    [GetObjectMemoryResponse] -> ShowS
    GetObjectMemoryResponse -> String
    (Int -> GetObjectMemoryResponse -> ShowS)
    -> (GetObjectMemoryResponse -> String)
    -> ([GetObjectMemoryResponse] -> ShowS)
    -> Show GetObjectMemoryResponse
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> GetObjectMemoryResponse -> ShowS
    showsPrec :: Int -> GetObjectMemoryResponse -> ShowS
    $cshow :: GetObjectMemoryResponse -> String
    show :: GetObjectMemoryResponse -> String
    $cshowList :: [GetObjectMemoryResponse] -> ShowS
    showList :: [GetObjectMemoryResponse] -> ShowS
    Show)

    -- | ServiceConfiguration: 'S3Configuration'
    instance SignQuery GetObject where
        type ServiceConfiguration GetObject = S3Configuration
        signQuery :: forall queryType.
    GetObject
    -> ServiceConfiguration GetObject queryType
    -> SignatureData
    -> SignedQuery
    signQuery GetObject {Maybe (Int, Int)
    Maybe Bucket
    Bucket
    goBucket :: GetObject -> Bucket
    goObjectName :: GetObject -> Bucket
    goVersionId :: GetObject -> Maybe Bucket
    goResponseContentType :: GetObject -> Maybe Bucket
    goResponseContentLanguage :: GetObject -> Maybe Bucket
    goResponseExpires :: GetObject -> Maybe Bucket
    goResponseCacheControl :: GetObject -> Maybe Bucket
    goResponseContentDisposition :: GetObject -> Maybe Bucket
    goResponseContentEncoding :: GetObject -> Maybe Bucket
    goResponseContentRange :: GetObject -> Maybe (Int, Int)
    goIfMatch :: GetObject -> Maybe Bucket
    goIfNoneMatch :: GetObject -> Maybe Bucket
    goBucket :: Bucket
    goObjectName :: Bucket
    goVersionId :: Maybe Bucket
    goResponseContentType :: Maybe Bucket
    goResponseContentLanguage :: Maybe Bucket
    goResponseExpires :: Maybe Bucket
    goResponseCacheControl :: Maybe Bucket
    goResponseContentDisposition :: Maybe Bucket
    goResponseContentEncoding :: Maybe Bucket
    goResponseContentRange :: Maybe (Int, Int)
    goIfMatch :: Maybe Bucket
    goIfNoneMatch :: Maybe Bucket
    ..} = S3Query
    -> S3Configuration queryType -> SignatureData -> SignedQuery
    forall qt.
    S3Query -> S3Configuration qt -> SignatureData -> SignedQuery
    s3SignQuery S3Query {
                                       s3QMethod :: Method
    s3QMethod = Method
    Get
                                     , s3QBucket :: Maybe ByteString
    s3QBucket = ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
    forall a b. (a -> b) -> a -> b
    $ Bucket -> ByteString
    T.encodeUtf8 Bucket
    goBucket
                                     , s3QObject :: Maybe ByteString
    s3QObject = ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
    forall a b. (a -> b) -> a -> b
    $ Bucket -> ByteString
    T.encodeUtf8 Bucket
    goObjectName
                                     , s3QSubresources :: Query
    s3QSubresources = [Maybe (ByteString, Bucket)] -> Query
    forall a. QueryLike a => a -> Query
    HTTP.toQuery [
                                                           (ByteString
    "versionId" :: B8.ByteString,) (Bucket -> (ByteString, Bucket))
    -> Maybe Bucket -> Maybe (ByteString, Bucket)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Bucket
    goVersionId
                                                         , (ByteString
    "response-content-type" :: B8.ByteString,) (Bucket -> (ByteString, Bucket))
    -> Maybe Bucket -> Maybe (ByteString, Bucket)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Bucket
    goResponseContentType
                                                         , (ByteString
    "response-content-language",) (Bucket -> (ByteString, Bucket))
    -> Maybe Bucket -> Maybe (ByteString, Bucket)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Bucket
    goResponseContentLanguage
                                                         , (ByteString
    "response-expires",) (Bucket -> (ByteString, Bucket))
    -> Maybe Bucket -> Maybe (ByteString, Bucket)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Bucket
    goResponseExpires
                                                         , (ByteString
    "response-cache-control",) (Bucket -> (ByteString, Bucket))
    -> Maybe Bucket -> Maybe (ByteString, Bucket)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Bucket
    goResponseCacheControl
                                                         , (ByteString
    "response-content-disposition",) (Bucket -> (ByteString, Bucket))
    -> Maybe Bucket -> Maybe (ByteString, Bucket)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Bucket
    goResponseContentDisposition
                                                         , (ByteString
    "response-content-encoding",) (Bucket -> (ByteString, Bucket))
    -> Maybe Bucket -> Maybe (ByteString, Bucket)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Bucket
    goResponseContentEncoding
                                                         ]
                                     , s3QQuery :: Query
    s3QQuery = []
                                     , s3QContentType :: Maybe ByteString
    s3QContentType = Maybe ByteString
    forall a. Maybe a
    Nothing
                                     , s3QContentMd5 :: Maybe (Digest MD5)
    s3QContentMd5 = Maybe (Digest MD5)
    forall a. Maybe a
    Nothing
                                     , s3QAmzHeaders :: RequestHeaders
    s3QAmzHeaders = []
                                     , s3QOtherHeaders :: RequestHeaders
    s3QOtherHeaders = [Maybe Header] -> RequestHeaders
    forall a. [Maybe a] -> [a]
    catMaybes [
                                                           (Int, Int) -> Header
    forall {a} {a} {a}.
    (IsString a, Show a, Show a) =>
    (a, a) -> (a, ByteString)
    decodeRange ((Int, Int) -> Header) -> Maybe (Int, Int) -> Maybe Header
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe (Int, Int)
    goResponseContentRange
                                                         , (HeaderName
    "if-match",) (ByteString -> Header)
    -> (Bucket -> ByteString) -> Bucket -> Header
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Bucket -> ByteString
    T.encodeUtf8 (Bucket -> Header) -> Maybe Bucket -> Maybe Header
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Bucket
    goIfMatch
                                                         , (HeaderName
    "if-none-match",) (ByteString -> Header)
    -> (Bucket -> ByteString) -> Bucket -> Header
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Bucket -> ByteString
    T.encodeUtf8 (Bucket -> Header) -> Maybe Bucket -> Maybe Header
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Bucket
    goIfNoneMatch
                                                         ]
                                     , s3QRequestBody :: Maybe RequestBody
    s3QRequestBody = Maybe RequestBody
    forall a. Maybe a
    Nothing
                                     }
          where decodeRange :: (a, a) -> (a, ByteString)
    decodeRange (a
    pos,a
    len) = (a
    "range",[ByteString] -> ByteString
    B8.concat ([ByteString] -> ByteString) -> [ByteString] -> ByteString
    forall a b. (a -> b) -> a -> b
    $ [ByteString
    "bytes=", String -> ByteString
    B8.pack (a -> String
    forall a. Show a => a -> String
    show a
    pos), ByteString
    "-", String -> ByteString
    B8.pack (a -> String
    forall a. Show a => a -> String
    show a
    len)])

    instance ResponseConsumer GetObject GetObjectResponse where
        type ResponseMetadata GetObjectResponse = S3Metadata
        responseConsumer :: Request
    -> GetObject
    -> IORef (ResponseMetadata GetObjectResponse)
    -> HTTPResponseConsumer GetObjectResponse
    responseConsumer Request
    httpReq GetObject{} IORef (ResponseMetadata GetObjectResponse)
    metadata Response (ConduitM () ByteString (ResourceT IO) ())
    resp
            | Status
    status Status -> Status -> Bool
    forall a. Eq a => a -> a -> Bool
    == Status
    HTTP.status200 = do
                rsp <- HTTPResponseConsumer
      (Response (ConduitM () ByteString (ResourceT IO) ()))
    -> IORef S3Metadata
    -> HTTPResponseConsumer
         (Response (ConduitM () ByteString (ResourceT IO) ()))
    forall a.
    HTTPResponseConsumer a
    -> IORef S3Metadata -> HTTPResponseConsumer a
    s3BinaryResponseConsumer HTTPResponseConsumer
      (Response (ConduitM () ByteString (ResourceT IO) ()))
    forall a. a -> ResourceT IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return IORef (ResponseMetadata GetObjectResponse)
    IORef S3Metadata
    metadata Response (ConduitM () ByteString (ResourceT IO) ())
    resp
                om <- parseObjectMetadata (HTTP.responseHeaders resp)
                return $ GetObjectResponse om rsp
            | Bool
    otherwise = Request -> HTTPResponseConsumer GetObjectResponse
    forall (m :: * -> *) a.
    MonadThrow m =>
    Request -> Response (ConduitM () ByteString m ()) -> m a
    throwStatusCodeException Request
    httpReq Response (ConduitM () ByteString (ResourceT IO) ())
    resp
          where
            status :: Status
    status  = Response (ConduitM () ByteString (ResourceT IO) ()) -> Status
    forall body. Response body -> Status
    HTTP.responseStatus    Response (ConduitM () ByteString (ResourceT IO) ())
    resp

    instance Transaction GetObject GetObjectResponse

    instance AsMemoryResponse GetObjectResponse where
        type MemoryResponse GetObjectResponse = GetObjectMemoryResponse
        loadToMemory :: GetObjectResponse
    -> ResourceT IO (MemoryResponse GetObjectResponse)
    loadToMemory (GetObjectResponse ObjectMetadata
    om Response (ConduitM () ByteString (ResourceT IO) ())
    x) = do
            bss <- ConduitT () Void (ResourceT IO) [ByteString]
    -> ResourceT IO [ByteString]
    forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
    C.runConduit (ConduitT () Void (ResourceT IO) [ByteString]
     -> ResourceT IO [ByteString])
    -> ConduitT () Void (ResourceT IO) [ByteString]
    -> ResourceT IO [ByteString]
    forall a b. (a -> b) -> a -> b
    $ Response (ConduitM () ByteString (ResourceT IO) ())
    -> ConduitM () ByteString (ResourceT IO) ()
    forall body. Response body -> body
    HTTP.responseBody Response (ConduitM () ByteString (ResourceT IO) ())
    x ConduitM () ByteString (ResourceT IO) ()
    -> ConduitT ByteString Void (ResourceT IO) [ByteString]
    -> ConduitT () Void (ResourceT IO) [ByteString]
    forall (m :: * -> *) a b c r.
    Monad m =>
    ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
    .| ConduitT ByteString Void (ResourceT IO) [ByteString]
    forall (m :: * -> *) a o. Monad m => ConduitT a o m [a]
    CL.consume
            return $ GetObjectMemoryResponse om x
                { HTTP.responseBody = L.fromChunks bss
                }