Skip to content

Commit

Permalink
Add support for custom headers for get, fget and get_partial methods (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
DrJackilD authored and harshavardhana committed May 14, 2017
1 parent 7d0007c commit 8889020
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 10 deletions.
5 changes: 4 additions & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ __Parameters__
|:---|:---|:---|
|``bucket_name`` |_string_ |Name of the bucket. |
|``object_name`` |_string_ |Name of the object. |
|``request_headers`` |_dict_ |Any additional headers (optional, defaults to None). |

__Return Value__

Expand Down Expand Up @@ -600,6 +601,7 @@ __Parameters__
|``object_name`` |_string_ |Name of the object. |
|``offset`` |_int_ |``offset`` of the object from where the stream will start. |
|``length`` |_int_ |``length`` of the object that will be read in the stream (optional, if not specified we read the rest of the file from the offset). |
|``request_headers`` |_dict_ |Any additional headers (optional, defaults to None). |

__Return Value__

Expand Down Expand Up @@ -631,7 +633,8 @@ __Parameters__
|:---|:---|:---|
|``bucket_name`` |_string_ |Name of the bucket. |
|``object_name`` |_string_ |Name of the object. |
|``file_path`` |_string_ | Path on the local filesystem to which the object data will be written. |
|``file_path`` |_dict_ | Path on the local filesystem to which the object data will be written. |
|``request_headers`` |_dict_ |Any additional headers (optional, defaults to None). |

__Return Value__

Expand Down
41 changes: 41 additions & 0 deletions examples/put_and_get_encrypted_object.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import base64
from io import BytesIO
import hashlib

from minio.api import Minio

AWSAccessKeyId = ''
AWSSecretKey = ''

STORAGE_ENDPOINT = 's3.amazonaws.com'
STORAGE_BUCKET = ''


def main():
content = BytesIO(b'Hello again')

key = b'32byteslongsecretkeymustprovided'
encryption_key = base64.b64encode(key).decode()
encryption_key_md5 = base64.b64encode(hashlib.md5(key).digest()).decode()

minio = Minio(STORAGE_ENDPOINT, access_key=AWSAccessKeyId, secret_key=AWSSecretKey)

# Put object with special headers which encrypt object in S3 with provided key
minio.put_object(STORAGE_BUCKET, 'test_crypt.txt', content, content.getbuffer().nbytes,
metadata={
'x-amz-server-side-encryption-customer-algorithm': 'AES256',
'x-amz-server-side-encryption-customer-key': encryption_key,
'x-amz-server-side-encryption-customer-key-MD5': encryption_key_md5
})

# Get decrypted object with same headers
obj = minio.get_object(STORAGE_BUCKET, 'test_crypt1.txt', request_headers={
'x-amz-server-side-encryption-customer-algorithm': 'AES256',
'x-amz-server-side-encryption-customer-key': encryption_key,
'x-amz-server-side-encryption-customer-key-MD5': encryption_key_md5
})

print(obj.read())

if __name__ == '__main__':
main()
25 changes: 18 additions & 7 deletions minio/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ def fput_object(self, bucket_name, object_name, file_path,
# Return etag here.
return mpart_result.etag

def fget_object(self, bucket_name, object_name, file_path):
def fget_object(self, bucket_name, object_name, file_path, request_headers=None):
"""
Retrieves an object from a bucket and writes at file_path.
Expand All @@ -698,6 +698,7 @@ def fget_object(self, bucket_name, object_name, file_path):
:param bucket_name: Bucket to read object from.
:param object_name: Name of the object to read.
:param file_path: Local file path to save the object.
:param request_headers: Any additional headers to be added with GET request.
"""
is_valid_bucket_name(bucket_name)
is_non_empty_string(object_name)
Expand All @@ -723,7 +724,8 @@ def fget_object(self, bucket_name, object_name, file_path):
# Get partial object.
response = self._get_partial_object(bucket_name, object_name,
offset=file_statinfo.st_size,
length=0)
length=0,
request_headers=request_headers)

# Save content_size to verify if we wrote more data.
content_size = int(response.headers['content-length'])
Expand Down Expand Up @@ -756,7 +758,7 @@ def fget_object(self, bucket_name, object_name, file_path):
# Return the stat
return stat

def get_object(self, bucket_name, object_name):
def get_object(self, bucket_name, object_name, request_headers=None):
"""
Retrieves an object from a bucket.
Expand All @@ -771,16 +773,18 @@ def get_object(self, bucket_name, object_name):
:param bucket_name: Bucket to read object from
:param object_name: Name of object to read
:param request_headers: Any additional headers to be added with GET request.
:return: :class:`urllib3.response.HTTPResponse` object.
"""
is_valid_bucket_name(bucket_name)
is_non_empty_string(object_name)

return self._get_partial_object(bucket_name,
object_name)
object_name,
request_headers=request_headers)

def get_partial_object(self, bucket_name, object_name, offset=0, length=0):
def get_partial_object(self, bucket_name, object_name, offset=0, length=0, request_headers=None):
"""
Retrieves an object from a bucket.
Expand All @@ -801,6 +805,7 @@ def get_partial_object(self, bucket_name, object_name, offset=0, length=0):
Must be >= 0.
:param length: Optional number of bytes to retrieve.
Must be an integer.
:param request_headers: Any additional headers to be added with GET request.
:return: :class:`urllib3.response.HTTPResponse` object.
"""
Expand All @@ -809,7 +814,8 @@ def get_partial_object(self, bucket_name, object_name, offset=0, length=0):

return self._get_partial_object(bucket_name,
object_name,
offset, length)
offset, length,
request_headers=request_headers)

def copy_object(self, bucket_name, object_name, object_source,
conditions=None):
Expand Down Expand Up @@ -1445,7 +1451,7 @@ def presigned_post_policy(self, post_policy):

# All private functions below.
def _get_partial_object(self, bucket_name, object_name,
offset=0, length=0):
offset=0, length=0, request_headers=None):
"""Retrieves an object from a bucket.
Optionally takes an offset and length of data to retrieve.
Expand All @@ -1466,13 +1472,18 @@ def _get_partial_object(self, bucket_name, object_name,
Must be >= 0.
:param length: Optional number of bytes to retrieve.
Must be > 0.
:param request_headers: Any additional metadata to be uploaded along
with request.
:return: :class:`urllib3.response.HTTPResponse` object.
"""
is_valid_bucket_name(bucket_name)
is_non_empty_string(object_name)

headers = {}
if request_headers:
headers = request_headers

if offset != 0 or length != 0:
request_range = '{}-{}'.format(
offset, "" if length == 0 else offset + length - 1
Expand Down
6 changes: 4 additions & 2 deletions tests/functional/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,16 @@ def main():
client.stat_object(bucket_name, object_name+'-copy')

# Get a full object
object_data = client.get_object(bucket_name, object_name)
object_data = client.get_object(bucket_name, object_name,
request_headers={'x-amz-meta-testing': 'value'})
with open('newfile', 'wb') as file_data:
for data in object_data:
file_data.write(data)
file_data.close()

# Get a full object locally.
client.fget_object(bucket_name, object_name, 'newfile-f')
client.fget_object(bucket_name, object_name, 'newfile-f',
request_headers={'x-amz-meta-testing': 'value'})

client.fput_object(bucket_name, object_name+'-f', 'testfile',
metadata={'x-amz-meta-testing': 'value'})
Expand Down

0 comments on commit 8889020

Please sign in to comment.