Skip to content

Commit 78be131

Browse files
g-cassiebalamurugana
authored andcommitted
Add support for response_headers argument on presigned_get_object (#434)
* Add support for `response_headers` argument on `presigned_get_object` This allows users to specify additional querystring params supported by S3 API such as `response-content-type` and `response-content-disposition`.
1 parent 574a39e commit 78be131

File tree

4 files changed

+32
-4
lines changed

4 files changed

+32
-4
lines changed

docs/API.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,7 @@ __Parameters__
957957
|``bucket_name`` |_string_ |Name of the bucket. |
958958
|``object_name`` |_string_ |Name of the object. |
959959
|``expiry`` | _datetime.datetime_ |Expiry in seconds. Default expiry is set to 7 days. |
960+
|``response_headers`` | _dictionary_ |Additional headers to include (e.g. `Response-Content-Type` or `Response-Content-Disposition`) |
960961

961962
__Example__
962963

minio/api.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,8 @@ def remove_incomplete_upload(self, bucket_name, object_name):
12861286
return
12871287

12881288
def presigned_get_object(self, bucket_name, object_name,
1289-
expires=timedelta(days=7)):
1289+
expires=timedelta(days=7),
1290+
response_headers=None):
12901291
"""
12911292
Presigns a get object request and provides a url
12921293
@@ -1313,7 +1314,8 @@ def presigned_get_object(self, bucket_name, object_name,
13131314

13141315
return self._presigned_get_partial_object(bucket_name,
13151316
object_name,
1316-
expires)
1317+
expires,
1318+
response_headers=response_headers)
13171319

13181320
def presigned_put_object(self, bucket_name, object_name,
13191321
expires=timedelta(days=7)):
@@ -1463,7 +1465,8 @@ def _get_partial_object(self, bucket_name, object_name,
14631465

14641466
def _presigned_get_partial_object(self, bucket_name, object_name,
14651467
expires=timedelta(days=7),
1466-
offset=0, length=0):
1468+
offset=0, length=0,
1469+
response_headers=None):
14671470
"""
14681471
Presigns a get partial object request and provides a url,
14691472
this is a internal function not exposed.
@@ -1491,6 +1494,7 @@ def _presigned_get_partial_object(self, bucket_name, object_name,
14911494
bucket_name=bucket_name,
14921495
object_name=object_name,
14931496
bucket_region=region)
1497+
14941498
headers = {}
14951499

14961500
if request_range:
@@ -1502,6 +1506,7 @@ def _presigned_get_partial_object(self, bucket_name, object_name,
15021506
self._secret_key,
15031507
region=region,
15041508
headers=headers,
1509+
response_headers=response_headers,
15051510
expires=int(expires.total_seconds()))
15061511
return presign_url
15071512

minio/signer.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def post_presign_signature(date, region, secret_key, policy_str):
6060

6161

6262
def presign_v4(method, url, access_key, secret_key, region=None,
63-
headers=None, expires=None):
63+
headers=None, expires=None, response_headers=None):
6464
"""
6565
Calculates signature version '4' for regular presigned URLs.
6666
@@ -96,6 +96,9 @@ def presign_v4(method, url, access_key, secret_key, region=None,
9696

9797
headers_to_sign = dict(headers)
9898

99+
if response_headers is not None:
100+
headers_to_sign.update(response_headers)
101+
99102
# Remove amazon recommended headers.
100103
headers_to_sign = ignore_headers(headers)
101104

@@ -109,6 +112,9 @@ def presign_v4(method, url, access_key, secret_key, region=None,
109112
signed_headers = get_signed_headers(headers_to_sign)
110113
query['X-Amz-SignedHeaders'] = ';'.join(signed_headers)
111114

115+
if response_headers is not None:
116+
query.update(response_headers)
117+
112118
# URL components.
113119
url_components = [parsed_url.geturl()]
114120
if query is not None:
@@ -146,6 +152,7 @@ def presign_v4(method, url, access_key, secret_key, region=None,
146152
return new_parsed_url.geturl()
147153

148154

155+
149156
def get_signed_headers(headers):
150157
"""
151158
Get signed headers.

tests/unit/presigned_get_object_test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from minio import Minio
2323
from minio.error import InvalidArgumentError
2424

25+
2526
class PresignedGetObjectTest(TestCase):
2627
@raises(TypeError)
2728
def test_object_is_string(self):
@@ -37,3 +38,17 @@ def test_object_is_not_empty_string(self):
3738
def test_expiry_limit(self):
3839
client = Minio('localhost:9000')
3940
client.presigned_get_object('hello', 'key', expires=timedelta(days=8))
41+
42+
def test_can_include_response_headers(self):
43+
client = Minio('localhost:9000', 'my_access_key', 'my_secret_key',
44+
secure=True)
45+
client._get_bucket_region = mock.Mock(return_value='us-east-1')
46+
r = client.presigned_get_object(
47+
'mybucket', 'myfile.pdf',
48+
response_headers={
49+
'Response-Content-Type': 'application/pdf',
50+
'Response-Content-Disposition': 'inline; filename="test.pdf"'
51+
})
52+
self.assertIn('inline', r)
53+
self.assertIn('test.pdf', r)
54+
self.assertIn('application%2Fpdf', r)

0 commit comments

Comments
 (0)