packages feed

minio-hs 1.4.0 → 1.5.0

raw patch · 29 files changed

+417/−289 lines, 29 filesdep −containersPVP ok

version bump matches the API change (PVP)

Dependencies removed: containers

API changes (from Hackage documentation)

+ Network.Minio: data GetObjectResponse
+ Network.Minio: gorObjectInfo :: GetObjectResponse -> ObjectInfo
+ Network.Minio: gorObjectStream :: GetObjectResponse -> ConduitM () ByteString Minio ()
+ Network.Minio: oiUserMetadata :: ObjectInfo -> HashMap Text Text
- Network.Minio: getObject :: Bucket -> Object -> GetObjectOptions -> Minio (ConduitM () ByteString Minio ())
+ Network.Minio: getObject :: Bucket -> Object -> GetObjectOptions -> Minio GetObjectResponse
- Network.Minio: oiMetadata :: ObjectInfo -> Map Text Text
+ Network.Minio: oiMetadata :: ObjectInfo -> HashMap Text Text
- Network.Minio: presignedPostPolicy :: PostPolicy -> Minio (ByteString, Map Text ByteString)
+ Network.Minio: presignedPostPolicy :: PostPolicy -> Minio (ByteString, HashMap Text ByteString)
- Network.Minio.S3API: getObject' :: Bucket -> Object -> Query -> [Header] -> Minio ([Header], ConduitM () ByteString Minio ())
+ Network.Minio.S3API: getObject' :: Bucket -> Object -> Query -> [Header] -> Minio GetObjectResponse
- Network.Minio.S3API: presignedPostPolicy :: PostPolicy -> Minio (ByteString, Map Text ByteString)
+ Network.Minio.S3API: presignedPostPolicy :: PostPolicy -> Minio (ByteString, HashMap Text ByteString)

Files

CHANGELOG.md view
@@ -1,6 +1,17 @@ Changelog ========== +## Version 1.5.0++* Switch to faster map data type - all previous usage of+  Data.Map.Strict and Data.Set is replaced with Data.HashMap.Strict+  and Data.HashSet.+* Add `oiUserMetadata` to parse and return user metadata stored with+  an object.+* Add `GetObjectResponse` data type for the value returned by+  `getObject`. It now contains parsed ObjectInfo along with the+  conduit of object bytes.+ ## Version 1.4.0  * Expose runMinioRes and runMinioResWith (#129)
README.md view
@@ -25,7 +25,7 @@ ```  A section of the tests use the remote MinIO Play server at-`https://play.min.io:9000` by default. For library development,+`https://play.min.io` by default. For library development, using this remote server maybe slow. To run the tests against a locally running MinIO live server at `http://localhost:9000`, just set the environment `MINIO_LOCAL` to any value (and unset it to switch@@ -47,7 +47,7 @@ -- stack --resolver lts-11.1 runghc --package minio-hs --package optparse-applicative --package filepath  ----- MinIO Haskell SDK, (C) 2017, 2018 MinIO, Inc.+-- MinIO Haskell SDK, (C) 2017-2019 MinIO, Inc. -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License.@@ -76,7 +76,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
docs/API.md view
@@ -20,15 +20,15 @@  ``` -|Bucket operations|Object Operations|Presigned Operations|-|:---|:---|:---|-|[`listBuckets`](#listBuckets) |[`getObject`](#getObject)|[`presignedGetObjectUrl`](#presignedGetObjectUrl)|-|[`makeBucket`](#makeBucket)|[`putObject`](#putObject)|[`presignedPutObjectUrl`](#presignedPutObjectUrl)|-|[`removeBucket`](#removeBucket)|[`fGetObject`](#fGetObject)|[`presignedPostPolicy`](#presignedPostPolicy)|-|[`listObjects`](#listObjects)|[`fPutObject`](#fPutObject)||-|[`listObjectsV1`](#listObjectsV1)|[`copyObject`](#copyObject)||-|[`listIncompleteUploads`](#listIncompleteUploads)|[`removeObject`](#removeObject)||-|[`bucketExists`](#bucketExists)|[`selectObjectContent`](#selectObjectContent)||+| Bucket operations                                 | Object Operations                             | Presigned Operations                              |+|:--------------------------------------------------|:----------------------------------------------|:--------------------------------------------------|+| [`listBuckets`](#listBuckets)                     | [`getObject`](#getObject)                     | [`presignedGetObjectUrl`](#presignedGetObjectUrl) |+| [`makeBucket`](#makeBucket)                       | [`putObject`](#putObject)                     | [`presignedPutObjectUrl`](#presignedPutObjectUrl) |+| [`removeBucket`](#removeBucket)                   | [`fGetObject`](#fGetObject)                   | [`presignedPostPolicy`](#presignedPostPolicy)     |+| [`listObjects`](#listObjects)                     | [`fPutObject`](#fPutObject)                   |                                                   |+| [`listObjectsV1`](#listObjectsV1)                 | [`copyObject`](#copyObject)                   |                                                   |+| [`listIncompleteUploads`](#listIncompleteUploads) | [`removeObject`](#removeObject)               |                                                   |+| [`bucketExists`](#bucketExists)                   | [`selectObjectContent`](#selectObjectContent) |                                                   |  ## 1. Connecting and running operations on the storage service @@ -69,16 +69,16 @@  The parameters in the expression `awsWithRegion region autoDiscover` are: -|Parameter|Type|Description|-|:---|:---|:---|-| `region` | _Region_ (alias for `Text`) | The region to connect to by default for all requests. |-| `autoDiscover` | _Bool_ | If `True`, region discovery will be enabled. If `False`, discovery is disabled, and all requests go the given region only.|+| Parameter      | Type                        | Description                                                                                                                |+|:---------------|:----------------------------|:---------------------------------------------------------------------------------------------------------------------------|+| `region`       | _Region_ (alias for `Text`) | The region to connect to by default for all requests.                                                                      |+| `autoDiscover` | _Bool_                      | If `True`, region discovery will be enabled. If `False`, discovery is disabled, and all requests go the given region only. |  #### minioPlayCI :: ConnectInfo  This constructor provides connection and authentication information to connect to the public MinIO Play server at-`https://play.min.io:9000/`.+`https://play.min.io/`.  #### minioCI :: Text -> Int -> Bool -> ConnectInfo @@ -86,25 +86,25 @@  The parameters in the expression `minioCI host port isSecure` are: -|Parameter|Type|Description|-|:---|:---|:---|-| `host` | _Text_ | Hostname of the MinIO or other S3-API compatible server |-| `port` | _Int_ | Port number to connect to|-| `isSecure` | _Bool_ | Does the server use HTTPS? |+| Parameter  | Type   | Description                                             |+|:-----------|:-------|:--------------------------------------------------------|+| `host`     | _Text_ | Hostname of the MinIO or other S3-API compatible server |+| `port`     | _Int_  | Port number to connect to                               |+| `isSecure` | _Bool_ | Does the server use HTTPS?                              |  #### The ConnectInfo fields and Default instance  The following table shows the fields in the `ConnectInfo` record-type: -| Field | Type | Description |-|:---|:---|:---|-| `connectHost` | _Text_ | Host name of the server. Defaults to `localhost`. |-| `connectPort` | _Int_ | Port number on which the server listens. Defaults to `9000`. |-| `connectAccessKey` | _Text_ | Access key to use in authentication. Defaults to `minio`. |-| `connectSecretkey` | _Text_ | Secret key to use in authentication. Defaults to `minio123`. |-| `connectIsSecure` | _Bool_ | Specifies if the server used TLS. Defaults to `False` |-| `connectRegion` | _Region_ (alias for `Text`) | Specifies the region to use. Defaults to 'us-east-1' |-| `connectAutoDiscoverRegion` | _Bool_ | Specifies if the library should automatically discover the region of a bucket. Defaults to `True`|+| Field                       | Type                        | Description                                                                                       |+|:----------------------------|:----------------------------|:--------------------------------------------------------------------------------------------------|+| `connectHost`               | _Text_                      | Host name of the server. Defaults to `localhost`.                                                 |+| `connectPort`               | _Int_                       | Port number on which the server listens. Defaults to `9000`.                                      |+| `connectAccessKey`          | _Text_                      | Access key to use in authentication. Defaults to `minio`.                                         |+| `connectSecretkey`          | _Text_                      | Secret key to use in authentication. Defaults to `minio123`.                                      |+| `connectIsSecure`           | _Bool_                      | Specifies if the server used TLS. Defaults to `False`                                             |+| `connectRegion`             | _Region_ (alias for `Text`) | Specifies the region to use. Defaults to 'us-east-1'                                              |+| `connectAutoDiscoverRegion` | _Bool_                      | Specifies if the library should automatically discover the region of a bucket. Defaults to `True` |  The `def` value of type `ConnectInfo` has all the above default values.@@ -148,17 +148,17 @@  __Return Value__ -|Return type   |Description   |-|:---|:---|-| _Minio [BucketInfo]_| List of buckets |+| Return type          | Description     |+|:---------------------|:----------------|+| _Minio [BucketInfo]_ | List of buckets |   __BucketInfo record type__ -|Field   |Type   |Description   |-|:---|:---| :---|-| `biName` | _Bucket_ (alias of `Text`) | Name of the bucket |-| `biCreationDate` | _UTCTime_ | Creation time of the bucket |+| Field            | Type                       | Description                 |+|:-----------------|:---------------------------|:----------------------------|+| `biName`         | _Bucket_ (alias of `Text`) | Name of the bucket          |+| `biCreationDate` | _UTCTime_                  | Creation time of the bucket |   <a name="makeBucket"></a>@@ -171,10 +171,10 @@  In the expression `makeBucket bucketName region` the arguments are: -| Param  | Type  | Description  |-|---|---|---|-|`bucketName`  | _Bucket_ (alias for `Text`) | Name of the bucket |-| `region`  |  _Maybe Region_ | Region where the bucket is to be created. If not specified, default to the region in `ConnectInfo`.|+| Param        | Type                        | Description                                                                                         |+|--------------|-----------------------------|-----------------------------------------------------------------------------------------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket                                                                                  |+| `region`     | _Maybe Region_              | Region where the bucket is to be created. If not specified, default to the region in `ConnectInfo`. |  __Example__ @@ -200,9 +200,9 @@  In the expression `removeBucket bucketName` the arguments are: -| Param  | Type  | Description  |-|---|---|---|-|`bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |+| Param        | Type                        | Description        |+|--------------|-----------------------------|--------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket |   __Example__@@ -233,26 +233,27 @@ In the expression `listObjects bucketName prefix recursive` the arguments are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `prefix` | _Maybe Text_  | Optional prefix that listed objects should have |-| `recursive`  | _Bool_  |`True` indicates recursive style listing and `False` indicates directory style listing delimited by '/'.  |+| Param        | Type                        | Description                                                                                              |+|:-------------|:----------------------------|:---------------------------------------------------------------------------------------------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket                                                                                       |+| `prefix`     | _Maybe Text_                | Optional prefix that listed objects should have                                                          |+| `recursive`  | _Bool_                      | `True` indicates recursive style listing and `False` indicates directory style listing delimited by '/'. |  __Return Value__ -|Return type   |Description   |-|:---|:---|-| _C.ConduitM () ObjectInfo Minio ()_  | A Conduit Producer of `ObjectInfo` values corresponding to each object. |+| Return type                         | Description                                                             |+|:------------------------------------|:------------------------------------------------------------------------|+| _C.ConduitM () ObjectInfo Minio ()_ | A Conduit Producer of `ObjectInfo` values corresponding to each object. |  __ObjectInfo record type__ -|Field   |Type   |Description   |-|:---|:---| :---|-|`oiObject`  | _Object_ (alias for `Text`) | Name of object |-|`oiModTime` | _UTCTime_ | Last modified time of the object |-|`oiETag` | _ETag_ (alias for `Text`) | ETag of the object |-|`oiSize` | _Int64_ | Size of the object in bytes  |+| Field        | Type                        | Description                          |+|:-------------|:----------------------------|:-------------------------------------|+| `oiObject`   | _Object_ (alias for `Text`) | Name of object                       |+| `oiModTime`  | _UTCTime_                   | Last modified time of the object     |+| `oiETag`     | _ETag_ (alias for `Text`)   | ETag of the object                   |+| `oiSize`     | _Int64_                     | Size of the object in bytes          |+| `oiMetadata` | _HashMap Text Text_         | Map of key-value user-metadata pairs |  __Example__ @@ -265,7 +266,7 @@   -- | The following example uses MinIO play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo@@ -294,26 +295,26 @@ In the expression `listObjectsV1 bucketName prefix recursive` the arguments are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `prefix` | _Maybe Text_  | Optional prefix that listed objects should have |-| `recursive`  | _Bool_  |`True` indicates recursive style listing and `False` indicates directory style listing delimited by '/'.  |+| Param        | Type                        | Description                                                                                              |+|:-------------|:----------------------------|:---------------------------------------------------------------------------------------------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket                                                                                       |+| `prefix`     | _Maybe Text_                | Optional prefix that listed objects should have                                                          |+| `recursive`  | _Bool_                      | `True` indicates recursive style listing and `False` indicates directory style listing delimited by '/'. |  __Return Value__ -|Return type   |Description   |-|:---|:---|-| _C.ConduitM () ObjectInfo Minio ()_  | A Conduit Producer of `ObjectInfo` values corresponding to each object. |+| Return type                         | Description                                                             |+|:------------------------------------|:------------------------------------------------------------------------|+| _C.ConduitM () ObjectInfo Minio ()_ | A Conduit Producer of `ObjectInfo` values corresponding to each object. |  __ObjectInfo record type__ -|Field   |Type   |Description   |-|:---|:---| :---|-|`oiObject`  | _Object_ (alias for `Text`) | Name of object |-|`oiModTime` | _UTCTime_ | Last modified time of the object |-|`oiETag` | _ETag_ (alias for `Text`) | ETag of the object |-|`oiSize` | _Int64_ | Size of the object in bytes  |+| Field       | Type                        | Description                      |+|:------------|:----------------------------|:---------------------------------|+| `oiObject`  | _Object_ (alias for `Text`) | Name of object                   |+| `oiModTime` | _UTCTime_                   | Last modified time of the object |+| `oiETag`    | _ETag_ (alias for `Text`)   | ETag of the object               |+| `oiSize`    | _Int64_                     | Size of the object in bytes      |  __Example__ @@ -326,7 +327,7 @@   -- | The following example uses MinIO play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo@@ -354,11 +355,11 @@ In the expression `listIncompleteUploads bucketName prefix recursive` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `prefix` | _Maybe Text_  | Optional prefix that listed objects should have. |-| `recursive`  | _Bool_  |`True` indicates recursive style listing and `Talse` indicates directory style listing delimited by '/'.  |+| Param        | Type                        | Description                                                                                              |+|:-------------|:----------------------------|:---------------------------------------------------------------------------------------------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket                                                                                       |+| `prefix`     | _Maybe Text_                | Optional prefix that listed objects should have.                                                         |+| `recursive`  | _Bool_                      | `True` indicates recursive style listing and `Talse` indicates directory style listing delimited by '/'. |  __Return Value__ @@ -368,11 +369,11 @@  __UploadInfo record type__ -|Field   |Type   |Description   |-|:---|:---| :---|-|`uiKey`  | _Object_  |Name of incompletely uploaded object |-|`uiUploadId` | _String_ |Upload ID of incompletely uploaded object |-|`uiSize` | _Int64_ |Size of incompletely uploaded object |+| Field        | Type     | Description                               |+|:-------------|:---------|:------------------------------------------|+| `uiKey`      | _Object_ | Name of incompletely uploaded object      |+| `uiUploadId` | _String_ | Upload ID of incompletely uploaded object |+| `uiSize`     | _Int64_  | Size of incompletely uploaded object      |  __Example__ @@ -384,7 +385,7 @@ import           Prelude  -- | The following example uses MinIO play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo@@ -415,29 +416,29 @@ In the expression `getObject bucketName objectName opts` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `objectName` | _Object_ (alias for `Text`)  | Name of the object |-| `opts`   | _GetObjectOptions_ | Options for GET requests specifying additional options like If-Match, Range |+| Param        | Type                        | Description                                                                 |+|:-------------|:----------------------------|:----------------------------------------------------------------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket                                                          |+| `objectName` | _Object_ (alias for `Text`) | Name of the object                                                          |+| `opts`       | _GetObjectOptions_          | Options for GET requests specifying additional options like If-Match, Range |  __GetObjectOptions record type__ -|Field   |Type   |Description   |-|:---|:---| :---|-| `gooRange` | `Maybe ByteRanges` | Represents the byte range of object. E.g ByteRangeFromTo 0 9 represents first ten bytes of the object|-| `gooIfMatch` | `Maybe ETag` (alias for `Text`) | (Optional) ETag of object should match |-| `gooIfNoneMatch` | `Maybe ETag` (alias for `Text`) | (Optional) ETag of object shouldn't match |-| `gooIfUnmodifiedSince` | `Maybe UTCTime` | (Optional) Time since object wasn't modified |-| `gooIfModifiedSince` | `Maybe UTCTime` | (Optional) Time since object was modified |+| Field                  | Type                            | Description                                                                                           |+|:-----------------------|:--------------------------------|:------------------------------------------------------------------------------------------------------|+| `gooRange`             | `Maybe ByteRanges`              | Represents the byte range of object. E.g ByteRangeFromTo 0 9 represents first ten bytes of the object |+| `gooIfMatch`           | `Maybe ETag` (alias for `Text`) | (Optional) ETag of object should match                                                                |+| `gooIfNoneMatch`       | `Maybe ETag` (alias for `Text`) | (Optional) ETag of object shouldn't match                                                             |+| `gooIfUnmodifiedSince` | `Maybe UTCTime`                 | (Optional) Time since object wasn't modified                                                          |+| `gooIfModifiedSince`   | `Maybe UTCTime`                 | (Optional) Time since object was modified                                                             |  __Return Value__  The return value can be incrementally read to process the contents of the object.-|Return type   |Description   |-|:---|:---|-| _Minio (C.ConduitM () ByteString Minio ())_  | A Conduit source of `ByteString` values. |+| Return type                                 | Description                              |+|:--------------------------------------------|:-----------------------------------------|+| _Minio (C.ConduitM () ByteString Minio ())_ | A Conduit source of `ByteString` values. |  __Example__ @@ -451,7 +452,7 @@ import           Prelude  -- | The following example uses MinIO play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo@@ -482,13 +483,13 @@ In the expression `putObject bucketName objectName inputSrc` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `objectName` | _Object_ (alias for `Text`)  | Name of the object |-| `inputSrc` | _C.ConduitM () ByteString Minio ()_ | A Conduit producer of `ByteString` values |-| `size` | _Int64_ | Provide stream size (optional) |-| `opts` | _PutObjectOptions_ | Optional parameters to provide additional metadata for the object |+| Param        | Type                                | Description                                                       |+|:-------------|:------------------------------------|:------------------------------------------------------------------|+| `bucketName` | _Bucket_ (alias for `Text`)         | Name of the bucket                                                |+| `objectName` | _Object_ (alias for `Text`)         | Name of the object                                                |+| `inputSrc`   | _C.ConduitM () ByteString Minio ()_ | A Conduit producer of `ByteString` values                         |+| `size`       | _Int64_                             | Provide stream size (optional)                                    |+| `opts`       | _PutObjectOptions_                  | Optional parameters to provide additional metadata for the object |  __Example__ @@ -501,7 +502,7 @@ import           Prelude  -- | The following example uses MinIO play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo@@ -533,23 +534,23 @@ In the expression `fGetObject bucketName objectName inputFile` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `objectName` | _Object_ (alias for `Text`)  | Name of the object |-| `inputFile` | _FilePath_ | Path to the file to be uploaded |-| `opts`      | _GetObjectOptions_ | Options for GET requests specifying additional options like If-Match, Range |+| Param        | Type                        | Description                                                                 |+|:-------------|:----------------------------|:----------------------------------------------------------------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket                                                          |+| `objectName` | _Object_ (alias for `Text`) | Name of the object                                                          |+| `inputFile`  | _FilePath_                  | Path to the file to be uploaded                                             |+| `opts`       | _GetObjectOptions_          | Options for GET requests specifying additional options like If-Match, Range |   __GetObjectOptions record type__ -|Field   |Type   |Description   |-|:---|:---| :---|-| `gooRange` | `Maybe ByteRanges` | Represents the byte range of object. E.g ByteRangeFromTo 0 9 represents first ten bytes of the object|-| `gooIfMatch` | `Maybe ETag` (alias for `Text`) | (Optional) ETag of object should match |-| `gooIfNoneMatch` | `Maybe ETag` (alias for `Text`) | (Optional) ETag of object shouldn't match |-| `gooIfUnmodifiedSince` | `Maybe UTCTime` | (Optional) Time since object wasn't modified |-| `gooIfModifiedSince` | `Maybe UTCTime` | (Optional) Time since object was modified |+| Field                  | Type                            | Description                                                                                           |+|:-----------------------|:--------------------------------|:------------------------------------------------------------------------------------------------------|+| `gooRange`             | `Maybe ByteRanges`              | Represents the byte range of object. E.g ByteRangeFromTo 0 9 represents first ten bytes of the object |+| `gooIfMatch`           | `Maybe ETag` (alias for `Text`) | (Optional) ETag of object should match                                                                |+| `gooIfNoneMatch`       | `Maybe ETag` (alias for `Text`) | (Optional) ETag of object shouldn't match                                                             |+| `gooIfUnmodifiedSince` | `Maybe UTCTime`                 | (Optional) Time since object wasn't modified                                                          |+| `gooIfModifiedSince`   | `Maybe UTCTime`                 | (Optional) Time since object was modified                                                             |  ``` haskell @@ -561,7 +562,7 @@ import Prelude  -- | The following example uses MinIO play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo@@ -592,11 +593,11 @@ In the expression `fPutObject bucketName objectName inputFile` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `objectName` | _Object_ (alias for `Text`)  | Name of the object |-| `inputFile` | _FilePath_ | Path to the file to be uploaded |+| Param        | Type                        | Description                     |+|:-------------|:----------------------------|:--------------------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket              |+| `objectName` | _Object_ (alias for `Text`) | Name of the object              |+| `inputFile`  | _FilePath_                  | Path to the file to be uploaded |  __Example__ @@ -629,28 +630,28 @@ In the expression `copyObject dstInfo srcInfo` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|+| Param     | Type              | Description                                               |+|:----------|:------------------|:----------------------------------------------------------| | `dstInfo` | _DestinationInfo_ | A value representing properties of the destination object |-| `srcInfo` | _SourceInfo_ | A value representing properties of the source object |+| `srcInfo` | _SourceInfo_      | A value representing properties of the source object      |   __SourceInfo record type__ -|Field   |Type   |Description   |-|:---|:---| :---|-| `srcBucket` | `Bucket` | Name of source bucket |-| `srcObject` | `Object` | Name of source object |-| `srcRange` | `Maybe (Int64, Int64)` | (Optional) Represents the byte range of source object. (0, 9) represents first ten bytes of source object|-| `srcIfMatch` | `Maybe Text` | (Optional) ETag source object should match |-| `srcIfNoneMatch` | `Maybe Text` | (Optional) ETag source object shouldn't match |-| `srcIfUnmodifiedSince` | `Maybe UTCTime` | (Optional) Time since source object wasn't modified |-| `srcIfModifiedSince` | `Maybe UTCTime` | (Optional) Time since source object was modified |+| Field                  | Type                   | Description                                                                                               |+|:-----------------------|:-----------------------|:----------------------------------------------------------------------------------------------------------|+| `srcBucket`            | `Bucket`               | Name of source bucket                                                                                     |+| `srcObject`            | `Object`               | Name of source object                                                                                     |+| `srcRange`             | `Maybe (Int64, Int64)` | (Optional) Represents the byte range of source object. (0, 9) represents first ten bytes of source object |+| `srcIfMatch`           | `Maybe Text`           | (Optional) ETag source object should match                                                                |+| `srcIfNoneMatch`       | `Maybe Text`           | (Optional) ETag source object shouldn't match                                                             |+| `srcIfUnmodifiedSince` | `Maybe UTCTime`        | (Optional) Time since source object wasn't modified                                                       |+| `srcIfModifiedSince`   | `Maybe UTCTime`        | (Optional) Time since source object was modified                                                          |  __Destination record type__ -|Field   |Type   |Description   |-|:---|:---| :---|+| Field       | Type     | Description                                          |+|:------------|:---------|:-----------------------------------------------------| | `dstBucket` | `Bucket` | Name of destination bucket in server-side copyObject | | `dstObject` | `Object` | Name of destination object in server-side copyObject | @@ -684,10 +685,10 @@ In the expression `removeObject bucketName objectName` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `objectName` | _Object_ (alias for `Text`)  | Name of the object |+| Param        | Type                        | Description        |+|:-------------|:----------------------------|:-------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket |+| `objectName` | _Object_ (alias for `Text`) | Name of the object |  __Example__ @@ -718,10 +719,10 @@ In the expression `removeIncompleteUpload bucketName objectName` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `objectName` | _Object_ (alias for `Text`)  | Name of the object |+| Param        | Type                        | Description        |+|:-------------|:----------------------------|:-------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket |+| `objectName` | _Object_ (alias for `Text`) | Name of the object |  __Example__ @@ -752,11 +753,11 @@ In the expression `selectObjectContent bucketName objectName selReq` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `objectName` | _Object_ (alias for `Text`)  | Name of the object |-| `selReq` | _SelectRequest_   | Select request parameters  |+| Param        | Type                        | Description               |+|:-------------|:----------------------------|:--------------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket        |+| `objectName` | _Object_ (alias for `Text`) | Name of the object        |+| `selReq`     | _SelectRequest_             | Select request parameters |  __SelectRequest record__ @@ -804,9 +805,9 @@  In the expression `bucketExists bucketName` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |+| Param        | Type                        | Description        |+|:-------------|:----------------------------|:-------------------|+| `bucketName` | _Bucket_ (alias for `Text`) | Name of the bucket |   ## 4. Presigned operations@@ -828,22 +829,22 @@ In the expression `presignedGetObjectUrl bucketName objectName expiry queryParams headers` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `objectName` | _Object_ (alias for `Text`)  | Name of the object |-| `expiry` | _UrlExpiry_ (alias for `Int`) | Url expiry time in seconds |-| `queryParams` | _Query_ (from package `http-types:Network.HTTP.Types`) | Query parameters to add to the URL |-| `headers` | _RequestHeaders_ (from package `http-types:Network.HTTP.Types` | Request headers that would be used with the URL |+| Param         | Type                                                           | Description                                     |+|:--------------|:---------------------------------------------------------------|:------------------------------------------------|+| `bucketName`  | _Bucket_ (alias for `Text`)                                    | Name of the bucket                              |+| `objectName`  | _Object_ (alias for `Text`)                                    | Name of the object                              |+| `expiry`      | _UrlExpiry_ (alias for `Int`)                                  | Url expiry time in seconds                      |+| `queryParams` | _Query_ (from package `http-types:Network.HTTP.Types`)         | Query parameters to add to the URL              |+| `headers`     | _RequestHeaders_ (from package `http-types:Network.HTTP.Types` | Request headers that would be used with the URL |  __Return Value__  Returns the generated URL - it will include authentication information. -|Return type   |Description   |-|:---|:---|-| _ByteString_  | Generated presigned URL |+| Return type  | Description             |+|:-------------|:------------------------|+| _ByteString_ | Generated presigned URL |  __Example__ @@ -886,21 +887,21 @@ In the expression `presignedPutObjectUrl bucketName objectName expiry headers` the parameters are: -|Param   |Type   |Description   |-|:---|:---| :---|-| `bucketName`  | _Bucket_ (alias for `Text`)  | Name of the bucket |-| `objectName` | _Object_ (alias for `Text`)  | Name of the object |-| `expiry` | _UrlExpiry_ (alias for `Int`) | Url expiry time in seconds |-| `headers` | _RequestHeaders_ (from package `http-types:Network.HTTP.Types` | Request headers that would be used with the URL |+| Param        | Type                                                           | Description                                     |+|:-------------|:---------------------------------------------------------------|:------------------------------------------------|+| `bucketName` | _Bucket_ (alias for `Text`)                                    | Name of the bucket                              |+| `objectName` | _Object_ (alias for `Text`)                                    | Name of the object                              |+| `expiry`     | _UrlExpiry_ (alias for `Int`)                                  | Url expiry time in seconds                      |+| `headers`    | _RequestHeaders_ (from package `http-types:Network.HTTP.Types` | Request headers that would be used with the URL |  __Return Value__  Returns the generated URL - it will include authentication information. -|Return type   |Description   |-|:---|:---|-| _ByteString_  | Generated presigned URL |+| Return type  | Description             |+|:-------------|:------------------------|+| _ByteString_ | Generated presigned URL |  __Example__ @@ -928,7 +929,7 @@ ```  <a name="presignedPostPolicy"></a>-### presignedPostPolicy :: PostPolicy -> Minio (ByteString, Map.Map Text ByteString)+### presignedPostPolicy :: PostPolicy -> Minio (ByteString, HashMap Text ByteString)  Generate a presigned URL and POST policy to upload files via a POST request. This is intended for browser uploads and generates form data@@ -940,10 +941,10 @@  In the expression `newPostPolicy expirationTime conditions` the parameters are: -|Param | Type| Description |-|:---|:---|:---|-| `expirationTime` | _UTCTime_ (from package `time:Data.Time.UTCTime`) | The expiration time for the policy |-| `conditions` | _[PostPolicyConditions]_ | List of conditions to be added to the policy |+| Param            | Type                                              | Description                                  |+|:-----------------|:--------------------------------------------------|:---------------------------------------------|+| `expirationTime` | _UTCTime_ (from package `time:Data.Time.UTCTime`) | The expiration time for the policy           |+| `conditions`     | _[PostPolicyConditions]_                          | List of conditions to be added to the policy |  The policy conditions are created using various helper functions - please refer to the Haddocks for details.@@ -965,7 +966,7 @@  import qualified Data.ByteString       as B import qualified Data.ByteString.Char8 as Char8-import qualified Data.Map.Strict       as Map+import qualified Data.HashMap.Strict   as H import qualified Data.Text.Encoding    as Enc import qualified Data.Time             as Time @@ -1005,7 +1006,7 @@         let           formFn (k, v) = B.concat ["-F ", Enc.encodeUtf8 k, "=",                                     "'", v, "'"]-          formOptions = B.intercalate " " $ map formFn $ Map.toList formData+          formOptions = B.intercalate " " $ map formFn $ H.toList formData           return $ B.intercalate " " $
examples/BucketExists.hs view
@@ -24,7 +24,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/CopyObject.hs view
@@ -24,7 +24,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/FileUploader.hs view
@@ -31,7 +31,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/GetObject.hs view
@@ -26,7 +26,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/HeadObject.hs view
@@ -24,7 +24,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/ListBuckets.hs view
@@ -24,7 +24,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/ListIncompleteUploads.hs view
@@ -24,7 +24,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/ListObjects.hs view
@@ -25,7 +25,7 @@   -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/MakeBucket.hs view
@@ -24,7 +24,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/PresignedGetObject.hs view
@@ -27,7 +27,7 @@ import qualified Data.Text.Encoding       as E  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/PresignedPostPolicy.hs view
@@ -22,12 +22,12 @@  import qualified Data.ByteString       as B import qualified Data.ByteString.Char8 as Char8-import qualified Data.Map.Strict       as Map+import qualified Data.HashMap.Strict   as H import qualified Data.Text.Encoding    as Enc import qualified Data.Time             as Time  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo@@ -69,7 +69,7 @@         let           formFn (k, v) = B.concat ["-F ", Enc.encodeUtf8 k, "=",                                     "'", v, "'"]-          formOptions = B.intercalate " " $ map formFn $ Map.toList formData+          formOptions = B.intercalate " " $ map formFn $ H.toList formData           return $ B.intercalate " " $
examples/PresignedPutObject.hs view
@@ -24,7 +24,7 @@ import           Data.CaseInsensitive  (original)  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/PutObject.hs view
@@ -25,7 +25,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/RemoveBucket.hs view
@@ -24,7 +24,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
examples/RemoveIncompleteUpload.hs view
@@ -23,7 +23,7 @@ import           Prelude  -- | The following example uses minio's play server at--- https://play.min.io:9000.  The endpoint and associated+-- https://play.min.io.  The endpoint and associated -- credentials are provided via the libary constant, -- -- > minioPlayCI :: ConnectInfo
minio-hs.cabal view
@@ -1,5 +1,5 @@ name:                minio-hs-version:             1.4.0+version:             1.5.0 synopsis:            A MinIO Haskell Library for Amazon S3 compatible cloud                      storage. description:         The MinIO Haskell client library provides simple APIs to@@ -57,7 +57,6 @@                      , conduit >= 1.3                      , conduit-extra >= 1.3                      , connection-                     , containers >= 0.5                      , cryptonite >= 0.25                      , cryptonite-conduit >= 0.2                      , digest >= 0.0.1@@ -153,7 +152,6 @@                      , conduit                      , conduit-extra                      , connection-                     , containers                      , cryptonite                      , cryptonite-conduit                      , digest@@ -200,7 +198,6 @@                      , conduit                      , conduit-extra                      , connection-                     , containers                      , cryptonite                      , cryptonite-conduit                      , digest
src/Network/Minio.hs view
@@ -90,6 +90,7 @@   , oiModTime   , oiETag   , oiSize+  , oiUserMetadata   , oiMetadata    -- ** Listing incomplete uploads@@ -146,6 +147,9 @@   , gooIfModifiedSince   , gooIfUnmodifiedSince   , gooSSECKey+  , GetObjectResponse+  , gorObjectInfo+  , gorObjectStream    -- ** Server-side object copying   , copyObject@@ -241,7 +245,7 @@ fGetObject :: Bucket -> Object -> FilePath -> GetObjectOptions -> Minio () fGetObject bucket object fp opts = do   src <- getObject bucket object opts-  C.connect src $ CB.sinkFileCautious fp+  C.connect (gorObjectStream src) $ CB.sinkFileCautious fp  -- | Upload the given file to the given object. fPutObject :: Bucket -> Object -> FilePath@@ -271,11 +275,11 @@ removeObject :: Bucket -> Object -> Minio () removeObject = deleteObject --- | Get an object from the object store as a resumable source (conduit).+-- | Get an object from the object store. getObject :: Bucket -> Object -> GetObjectOptions-          -> Minio (C.ConduitM () ByteString Minio ())-getObject bucket object opts = snd <$> getObject' bucket object []-                               (gooToHeaders opts)+          -> Minio GetObjectResponse+getObject bucket object opts =+    getObject' bucket object [] $ gooToHeaders opts  -- | Get an object's metadata from the object store. It accepts the -- same options as GetObject.
src/Network/Minio/API.hs view
@@ -34,7 +34,7 @@ import qualified Data.ByteString           as B import qualified Data.Char                 as C import qualified Data.Conduit              as C-import qualified Data.Map                  as Map+import qualified Data.HashMap.Strict       as H import qualified Data.Text                 as T import qualified Data.Time.Clock           as Time import           Network.HTTP.Conduit      (Response)@@ -95,7 +95,7 @@      if "amazonaws.com" `T.isSuffixOf` connectHost ci     then maybe (throwIO $ MErrVRegionNotSupported r)-         return (Map.lookup r awsRegionMap)+         return (H.lookup r awsRegionMap)     else return $ connectHost ci  buildRequest :: S3ReqInfo -> Minio NC.Request
src/Network/Minio/Data.hs view
@@ -32,7 +32,6 @@ import           Data.CaseInsensitive         (mk) import qualified Data.HashMap.Strict          as H import qualified Data.Ini                     as Ini-import qualified Data.Map                     as Map import           Data.String                  (IsString (..)) import qualified Data.Text                    as T import qualified Data.Text.Encoding           as TE@@ -74,8 +73,8 @@ -- type should have a IsString instance to infer the appropriate -- constant. -- | awsRegionMap - library constant-awsRegionMap :: Map.Map Text Text-awsRegionMap = Map.fromList [+awsRegionMap :: H.HashMap Text Text+awsRegionMap = H.fromList [       ("us-east-1", "s3.amazonaws.com")     , ("us-east-2", "s3-us-east-2.amazonaws.com")     , ("us-west-1", "s3-us-west-1.amazonaws.com")@@ -96,7 +95,7 @@ -- enable the @OverloadedStrings@ language extension and use the -- `IsString` instance to provide a URL, for example: ----- > let c :: ConnectInfo = "https://play.min.io:9000"+-- > let c :: ConnectInfo = "https://play.min.io" data ConnectInfo =     ConnectInfo { connectHost                     :: Text                 , connectPort                     :: Int@@ -231,13 +230,13 @@ awsCI = "https://s3.amazonaws.com"  --- | <https://play.min.io:9000 MinIO Play Server>+-- | <https://play.min.io MinIO Play Server> -- ConnectInfo. Credentials are already filled in. minioPlayCI :: ConnectInfo minioPlayCI = let playCreds = Credentials "Q3AM3UQ867SPQQA43P2F" "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"               in setCreds playCreds                  $ setRegion "us-east-1"-                 "https://play.min.io:9000"+                 "https://play.min.io"  -- | -- Represents a bucket in the object store@@ -336,14 +335,22 @@ defaultPutObjectOptions :: PutObjectOptions defaultPutObjectOptions = PutObjectOptions Nothing Nothing Nothing Nothing Nothing Nothing [] Nothing Nothing +-- | If the given header name has the @X-Amz-Meta-@ prefix, it is+-- stripped and a Just is returned.+userMetadataHeaderNameMaybe :: Text -> Maybe Text+userMetadataHeaderNameMaybe k =+    let prefix = T.toCaseFold "X-Amz-Meta-"+        n = T.length prefix+    in if T.toCaseFold (T.take n k) == prefix+       then Just (T.drop n k)+       else Nothing+ addXAmzMetaPrefix :: Text -> Text-addXAmzMetaPrefix s = do-  if (T.isPrefixOf "x-amz-meta-" s)-    then s-    else T.concat ["x-amz-meta-", s]+addXAmzMetaPrefix s | isJust (userMetadataHeaderNameMaybe s) = s+                    | otherwise = "X-Amz-Meta-" <> s  mkHeaderFromMetadata :: [(Text, Text)] -> [HT.Header]-mkHeaderFromMetadata = map (\(x, y) -> (mk $ encodeUtf8 $ addXAmzMetaPrefix $ T.toLower x, encodeUtf8 y))+mkHeaderFromMetadata = map (\(x, y) -> (mk $ encodeUtf8 $ addXAmzMetaPrefix $ x, encodeUtf8 y))  pooToHeaders :: PutObjectOptions -> [HT.Header] pooToHeaders poo = userMetadata@@ -436,12 +443,19 @@  -- | Represents information about an object. data ObjectInfo = ObjectInfo-  { oiObject   :: Object -- ^ Object key-  , oiModTime  :: UTCTime -- ^ Mdification time of the object-  , oiETag     :: ETag -- ^ ETag of the object-  , oiSize     :: Int64 -- ^ Size of the object in bytes-  , oiMetadata :: Map.Map Text Text -- ^ A map of the metadata-                                    -- key-value pairs+  { oiObject       :: Object -- ^ Object key+  , oiModTime      :: UTCTime -- ^ Modification time of the object+  , oiETag         :: ETag -- ^ ETag of the object+  , oiSize         :: Int64 -- ^ Size of the object in bytes+  , oiUserMetadata :: H.HashMap Text Text -- ^ A map of user-metadata+                                          -- pairs stored with an+                                          -- object (keys will not+                                          -- have the @X-Amz-Meta-@+                                          -- prefix).+  , oiMetadata     :: H.HashMap Text Text -- ^ A map of metadata+                                          -- key-value pairs (not+                                          -- including the+                                          -- user-metadata pairs)   } deriving (Show, Eq)  -- | Represents source object in server-side copy object@@ -523,6 +537,14 @@     rangeHdr = maybe [] (\a -> [(hRange, HT.renderByteRanges [a])])                $ gooRange goo +-- | Data type returned by 'getObject' representing the object being+-- retrieved. Use the @gor*@ functions to access its contents.+data GetObjectResponse = GetObjectResponse {+      -- | ObjectInfo of the object being retrieved.+      gorObjectInfo   :: ObjectInfo+      -- | A conduit of the bytes of the object.+    , gorObjectStream :: C.ConduitM () ByteString Minio ()+    }  -- | A data-type for events that can occur in the object storage -- server. Reference:@@ -928,7 +950,7 @@ -- seconds. The maximum duration that can be specified is 7 days. type UrlExpiry = Int -type RegionMap = Map.Map Bucket Region+type RegionMap = H.HashMap Bucket Region  -- | The Minio Monad - all computations accessing object storage -- happens in it.@@ -991,7 +1013,7 @@ -- `MinioConn`. mkMinioConn :: ConnectInfo -> NC.Manager -> IO MinioConn mkMinioConn ci mgr = do-    rMapMVar <- M.newMVar Map.empty+    rMapMVar <- M.newMVar H.empty     return $ MinioConn ci mgr rMapMVar  -- | Run the Minio action and return the result or an error.
src/Network/Minio/PresignedOperations.hs view
@@ -39,7 +39,7 @@ import           Data.Aeson                ((.=)) import qualified Data.Aeson                as Json import           Data.ByteString.Builder   (byteString, toLazyByteString)-import qualified Data.Map.Strict           as Map+import qualified Data.HashMap.Strict       as H import qualified Data.Text                 as T import qualified Data.Time                 as Time import qualified Network.HTTP.Conduit      as NC@@ -252,7 +252,7 @@ -- browser. On success, this function returns a URL and POST -- form-data. presignedPostPolicy :: PostPolicy-                    -> Minio (ByteString, Map.Map Text ByteString)+                    -> Minio (ByteString, H.HashMap Text ByteString) presignedPostPolicy p = do   ci <- asks mcConnInfo   signTime <- liftIO $ Time.getCurrentTime@@ -277,12 +277,12 @@     mkPair (PPCStartsWith k v) = Just (k, v)     mkPair (PPCEquals k v)     = Just (k, v)     mkPair _                   = Nothing-    formFromPolicy = Map.map toS $ Map.fromList $ catMaybes $+    formFromPolicy = H.map toS $ H.fromList $ catMaybes $                      mkPair <$> conditions ppWithCreds-    formData = formFromPolicy `Map.union` signData+    formData = formFromPolicy `H.union` signData      -- compute POST upload URL-    bucket = Map.findWithDefault "" "bucket" formData+    bucket = H.lookupDefault "" "bucket" formData     scheme = byteString $ bool "http://" "https://" $ connectIsSecure ci     region = connectRegion ci 
src/Network/Minio/S3API.hs view
@@ -91,7 +91,6 @@   , removeAllBucketNotification   ) where -import qualified Conduit                           as C import qualified Data.ByteString                   as BS import qualified Data.Text                         as T import qualified Network.HTTP.Conduit              as NC@@ -118,19 +117,37 @@     }   parseListBuckets $ NC.responseBody resp --- | GET an object from the service and return the response headers--- and a conduit source for the object content+-- Parse headers from getObject and headObject calls.+parseGetObjectHeaders :: Object -> [HT.Header] -> Maybe ObjectInfo+parseGetObjectHeaders object headers =+    let metadataPairs = getMetadata headers+        userMetadata = getUserMetadataMap metadataPairs+        metadata = getNonUserMetadataMap metadataPairs+    in ObjectInfo <$> Just object+                  <*> getLastModifiedHeader headers+                  <*> getETagHeader headers+                  <*> getContentLength headers+                  <*> Just userMetadata+                  <*> Just metadata++-- | GET an object from the service and return parsed ObjectInfo and a+-- conduit source for the object content getObject' :: Bucket -> Object -> HT.Query -> [HT.Header]-           -> Minio ([HT.Header], C.ConduitM () ByteString Minio ())+           -> Minio GetObjectResponse getObject' bucket object queryParams headers = do-  resp <- mkStreamRequest reqInfo-  return (NC.responseHeaders resp, NC.responseBody resp)+    resp <- mkStreamRequest reqInfo+    let objInfoMaybe = parseGetObjectHeaders object $ NC.responseHeaders resp+    objInfo <- maybe (throwIO MErrVInvalidObjectInfoResponse) return+               objInfoMaybe+    return $ GetObjectResponse { gorObjectInfo = objInfo+                               , gorObjectStream = NC.responseBody resp+                               }   where     reqInfo = defaultS3ReqInfo { riBucket = Just bucket-                  , riObject = Just object-                  , riQueryParams = queryParams-                  , riHeaders = headers-                  }+                               , riObject = Just object+                               , riQueryParams = queryParams+                               , riHeaders = headers+                               }  -- | Creates a bucket via a PUT bucket call. putBucket :: Bucket -> Region -> Minio ()@@ -412,20 +429,13 @@ headObject :: Bucket -> Object -> [HT.Header] -> Minio ObjectInfo headObject bucket object reqHeaders = do   resp <- executeRequest $ defaultS3ReqInfo { riMethod = HT.methodHead-                               , riBucket = Just bucket-                               , riObject = Just object-                               , riHeaders = reqHeaders-                               }--  let-    headers = NC.responseHeaders resp-    modTime = getLastModifiedHeader headers-    etag = getETagHeader headers-    size = getContentLength headers-    metadata = getMetadataMap headers+                                            , riBucket = Just bucket+                                            , riObject = Just object+                                            , riHeaders = reqHeaders+                                            }    maybe (throwIO MErrVInvalidObjectInfoResponse) return $-    ObjectInfo <$> Just object <*> modTime <*> etag <*> size <*> Just metadata+    parseGetObjectHeaders object $ NC.responseHeaders resp   -- | Query the object store if a given bucket exists.
src/Network/Minio/Sign/V4.hs view
@@ -22,8 +22,8 @@ import qualified Data.ByteString.Char8         as B8 import           Data.CaseInsensitive          (mk) import qualified Data.CaseInsensitive          as CI-import qualified Data.Map.Strict               as Map-import qualified Data.Set                      as Set+import qualified Data.HashMap.Strict           as Map+import qualified Data.HashSet                  as Set import qualified Data.Time                     as Time import qualified Network.HTTP.Conduit          as NC import           Network.HTTP.Types            (Header, parseQuery)@@ -39,7 +39,7 @@  -- these headers are not included in the string to sign when signing a -- request-ignoredHeaders :: Set ByteString+ignoredHeaders :: Set.HashSet ByteString ignoredHeaders = Set.fromList $ map CI.foldedCase                  [ H.hAuthorization                  , H.hContentType@@ -178,7 +178,7 @@  getHeadersToSign :: [Header] -> [(ByteString, ByteString)] getHeadersToSign !h =-  filter (flip Set.notMember ignoredHeaders . fst) $+  filter ((\hdr -> not $ Set.member hdr ignoredHeaders) . fst) $   map (\(x, y) -> (CI.foldedCase x, stripBS y)) h  mkCanonicalRequest :: Bool -> SignParams -> NC.Request -> [(ByteString, ByteString)]@@ -234,7 +234,7 @@ -- and ConnInfo and returns form-data for the POST upload containing -- just the signature and the encoded post-policy. signV4PostPolicy :: ByteString -> SignParams-                 -> Map.Map Text ByteString+                 -> Map.HashMap Text ByteString signV4PostPolicy !postPolicyJSON !sp =   let     stringToSign = Base64.encode postPolicyJSON
src/Network/Minio/Utils.hs view
@@ -23,8 +23,8 @@ import qualified Data.ByteString.Lazy          as LB import           Data.CaseInsensitive          (mk, original) import qualified Data.Conduit.Binary           as CB+import qualified Data.HashMap.Strict           as H import qualified Data.List                     as List-import qualified Data.Map                      as Map import qualified Data.Text                     as T import           Data.Text.Encoding.Error      (lenientDecode) import           Data.Text.Read                (decimal)@@ -103,11 +103,26 @@ getETagHeader hs = decodeUtf8Lenient <$> lookupHeader Hdr.hETag hs  getMetadata :: [HT.Header] -> [(Text, Text)]-getMetadata = map ((\(x, y) -> (decodeUtf8Lenient $ original x, decodeUtf8Lenient $ stripBS y)))+getMetadata =+    map ((\(x, y) -> (decodeUtf8Lenient $ original x, decodeUtf8Lenient $ stripBS y))) -getMetadataMap :: [HT.Header] -> Map Text Text-getMetadataMap hs = Map.fromList (getMetadata hs)+toMaybeMetadataHeader :: (Text, Text) -> Maybe (Text, Text)+toMaybeMetadataHeader (k, v) =+    (, v) <$> userMetadataHeaderNameMaybe k +getNonUserMetadataMap :: [(Text, Text)] -> H.HashMap Text Text+getNonUserMetadataMap = H.fromList+                      . filter ( isNothing+                               . userMetadataHeaderNameMaybe+                               . fst+                               )++-- | This function collects all headers starting with `x-amz-meta-`+-- and strips off this prefix, and returns a map.+getUserMetadataMap :: [(Text, Text)] -> H.HashMap Text Text+getUserMetadataMap = H.fromList+                   . mapMaybe toMaybeMetadataHeader+ getLastModifiedHeader :: [HT.Header] -> Maybe UTCTime getLastModifiedHeader hs = do   modTimebs <- decodeUtf8Lenient <$> lookupHeader Hdr.hLastModified hs@@ -245,14 +260,14 @@ lookupRegionCache b = do     rMVar <- asks mcRegionMap     rMap <- UM.readMVar rMVar-    return $ Map.lookup b rMap+    return $ H.lookup b rMap  addToRegionCache :: Bucket -> Region -> Minio () addToRegionCache b region = do     rMVar <- asks mcRegionMap-    UM.modifyMVar_ rMVar $ return . Map.insert b region+    UM.modifyMVar_ rMVar $ return . H.insert b region  deleteFromRegionCache :: Bucket -> Minio () deleteFromRegionCache b = do     rMVar <- asks mcRegionMap-    UM.modifyMVar_ rMVar $ return . Map.delete b+    UM.modifyMVar_ rMVar $ return . H.delete b
src/Network/Minio/XmlParser.hs view
@@ -30,8 +30,8 @@   ) where  import qualified Data.ByteString.Lazy as LB-import           Data.List            (zip3, zip4, zip5)-import qualified Data.Map             as Map+import qualified Data.HashMap.Strict  as H+import           Data.List            (zip3, zip4, zip6) import qualified Data.Text            as T import           Data.Text.Read       (decimal) import           Data.Time@@ -52,8 +52,8 @@ uncurry4 :: (a -> b -> c -> d -> e) -> (a, b, c, d) -> e uncurry4 f (a, b, c, d) = f a b c d -uncurry5 :: (a -> b -> c -> d -> e -> f) -> (a, b, c, d, e) -> f-uncurry5 f (a, b, c, d, e) = f a b c d e+uncurry6 :: (a -> b -> c -> d -> e -> f -> g) -> (a, b, c, d, e, f) -> g+uncurry6 f (a, b, c, d, e, g) = f a b c d e g  -- | Parse time strings from XML parseS3XMLTime :: (MonadIO m) => Text -> m UTCTime@@ -149,7 +149,8 @@   sizes <- parseDecimals sizeStr    let-    objects = map (uncurry5 ObjectInfo) $ zip5 keys modTimes etags sizes (repeat Map.empty)+    objects = map (uncurry6 ObjectInfo) $+              zip6 keys modTimes etags sizes (repeat H.empty) (repeat H.empty)    return $ ListObjectsV1Result hasMore nextMarker objects prefixes @@ -178,7 +179,8 @@   sizes <- parseDecimals sizeStr    let-    objects = map (uncurry5 ObjectInfo) $ zip5 keys modTimes etags sizes (repeat Map.empty)+    objects = map (uncurry6 ObjectInfo) $+              zip6 keys modTimes etags sizes (repeat H.empty) (repeat H.empty)    return $ ListObjectsResult hasMore nextToken objects prefixes 
test/LiveServer.hs view
@@ -21,13 +21,13 @@ import           Test.Tasty.QuickCheck                 as QC  import           Conduit                               (replicateC)+import qualified Conduit                               as C import qualified Control.Monad.Trans.Resource          as R import qualified Data.ByteString                       as BS import           Data.Conduit                          (yield)-import qualified Data.Conduit                          as C import qualified Data.Conduit.Binary                   as CB import           Data.Conduit.Combinators              (sinkList)-import qualified Data.Map.Strict                       as Map+import qualified Data.HashMap.Strict                   as H import qualified Data.Text                             as T import           Data.Time                             (fromGregorian) import qualified Data.Time                             as Time@@ -42,6 +42,7 @@  import           Network.Minio import           Network.Minio.Data+import           Network.Minio.Data.Crypto import           Network.Minio.PutObject import           Network.Minio.S3API import           Network.Minio.Utils@@ -108,6 +109,8 @@   , putObjectContentTypeTest   , putObjectContentLanguageTest   , putObjectStorageClassTest+  , putObjectUserMetadataTest+  , getObjectTest   , copyObjectTests   , presignedUrlFunTest   , presignedPostPolicyFunTest@@ -513,8 +516,8 @@       "presigned HEAD failed (presignedHeadObjectUrl)"      -- check that header info is accurate-    let h = Map.fromList $ NC.responseHeaders headResp-        cLen = Map.findWithDefault "0" HT.hContentLength h+    let h = H.fromList $ NC.responseHeaders headResp+        cLen = H.lookupDefault "0" HT.hContentLength h     liftIO $ (cLen == show size2) @? "Head req returned bad content length"      step "GET object presigned URL - presignedGetObjectUrl"@@ -580,7 +583,7 @@       postForm url formData inputFile = do         req <- NC.parseRequest $ toS url         let parts = map (\(x, y) -> Form.partBS x y) $-                    Map.toList formData+                    H.toList formData             parts' = parts ++ [Form.partFile "file" inputFile]         req' <- Form.formDataBody parts' req         mgr <- NC.newManager NC.tlsManagerSettings@@ -698,7 +701,7 @@     let m = oiMetadata oi      step "Validate content-type"-    liftIO $ assertEqual "Content-Type did not match" (Just "application/javascript") (Map.lookup "Content-Type" m)+    liftIO $ assertEqual "Content-Type did not match" (Just "application/javascript") (H.lookup "Content-Type" m)      step "upload object with content-encoding set to identity"     fPutObject bucket object inputFile defaultPutObjectOptions {@@ -710,7 +713,7 @@      step "Validate content-encoding"     liftIO $ assertEqual "Content-Encoding did not match" (Just "identity")-      (Map.lookup "Content-Encoding" m')+      (H.lookup "Content-Encoding" m')      step "Cleanup actions" @@ -735,11 +738,74 @@      step "Validate content-language"     liftIO $ assertEqual "content-language did not match" (Just "en-US")-      (Map.lookup "Content-Language" m)+      (H.lookup "Content-Language" m)     step "Cleanup actions"      removeObject bucket object +putObjectUserMetadataTest :: TestTree+putObjectUserMetadataTest = funTestWithBucket "putObject user-metadata test" $+  \step bucket -> do+    step "putObject user-metadata test"+    let object = "object-with-metadata"+        size1 = 100 :: Int64++    step "create server object with usermetdata"+    inputFile <- mkRandFile size1++    fPutObject bucket object inputFile defaultPutObjectOptions {+      pooUserMetadata = [ ("x-Amz-meta-mykey1", "myval1")+                        , ("mykey2", "myval2")+                        ]+      }++    step "Validate user-metadata"+    -- retrieve obj info to check+    oi <- headObject bucket object []+    let m = oiUserMetadata oi+        -- need to do a case-insensitive comparison+        sortedMeta = sort $ map (\(k, v) -> (T.toLower k, T.toLower v)) $+                     H.toList m+        ref = sort [("mykey1", "myval1"), ("mykey2", "myval2")]++    liftIO $ (sortedMeta == ref) @? "Metadata mismatch!"++    step "Cleanup actions"+    removeObject bucket object++getObjectTest :: TestTree+getObjectTest = funTestWithBucket "getObject test" $+  \step bucket -> do+    step "putObject with some metadata"+    let object = "object-with-metadata"+        size1 = 100 :: Int64++    inputFile <- mkRandFile size1+    fPutObject bucket object inputFile defaultPutObjectOptions {+      pooUserMetadata = [ ("x-Amz-meta-mykey1", "myval1")+                        , ("mykey2", "myval2")+                        ]+      }++    step "get the object - check the metadata matches"+    -- retrieve obj info to check+    gor <- getObject bucket object defaultGetObjectOptions+    let m = oiUserMetadata $ gorObjectInfo gor+        -- need to do a case-insensitive comparison+        sortedMeta = sort $ map (\(k, v) -> (T.toLower k, T.toLower v)) $+                     H.toList m+        ref = sort [("mykey1", "myval1"), ("mykey2", "myval2")]++    liftIO $ (sortedMeta == ref) @? "Metadata mismatch!"++    step "get the object content"+    getObjectHash <- hashSHA256FromSource $ gorObjectStream gor+    inputHash <- hashSHA256FromSource $ C.sourceFile inputFile+    liftIO $ (getObjectHash == inputHash) @? "Input file and output file mismatched!"++    step "Cleanup actions"+    removeObject bucket object+ putObjectStorageClassTest :: TestTree putObjectStorageClassTest = funTestWithBucket "putObject storageClass tests" $   \step bucket -> do@@ -771,7 +837,7 @@      step "Validate x-amz-storage-class rrs"     liftIO $ assertEqual "storageClass did not match" (Just "REDUCED_REDUNDANCY")-      (Map.lookup "X-Amz-Storage-Class" m')+      (H.lookup "X-Amz-Storage-Class" m')      fpE <- try $ fPutObject bucket object'' inputFile'' defaultPutObjectOptions {       pooStorageClass = Just "INVALID_STORAGE_CLASS"
test/Network/Minio/XmlParser/Test.hs view
@@ -19,7 +19,7 @@   ( xmlParserTests   ) where -import qualified Data.Map                  as Map+import qualified Data.HashMap.Strict       as H import           Data.Time                 (fromGregorian) import           Test.Tasty import           Test.Tasty.HUnit@@ -128,7 +128,7 @@               \</ListBucketResult>"      expectedListResult = ListObjectsResult True (Just "opaque") [object1] []-    object1 = ObjectInfo "my-image.jpg" modifiedTime1 "\"fba9dede5f27731c9771645a39863328\"" 434234 Map.empty+    object1 = ObjectInfo "my-image.jpg" modifiedTime1 "\"fba9dede5f27731c9771645a39863328\"" 434234 H.empty H.empty     modifiedTime1 = flip UTCTime 64230 $ fromGregorian 2009 10 12    parsedListObjectsResult <- tryValidationErr $ runTestNS $ parseListObjectsResponse xmldata@@ -155,7 +155,7 @@               \</ListBucketResult>"      expectedListResult = ListObjectsV1Result True (Just "my-image1.jpg") [object1] []-    object1 = ObjectInfo "my-image.jpg" modifiedTime1 "\"fba9dede5f27731c9771645a39863328\"" 434234 Map.empty+    object1 = ObjectInfo "my-image.jpg" modifiedTime1 "\"fba9dede5f27731c9771645a39863328\"" 434234 H.empty H.empty     modifiedTime1 = flip UTCTime 64230 $ fromGregorian 2009 10 12    parsedListObjectsV1Result <- tryValidationErr $ runTestNS $ parseListObjectsV1Response xmldata