Skip to content

Commit

Permalink
Merge pull request boto#2477 from opottone/develop
Browse files Browse the repository at this point in the history
Add recognized HTTP headers for S3 metadata. Fixes boto#2477, boto#2050.
  • Loading branch information
danielgtaylor committed Aug 19, 2014
2 parents 2f0e689 + 3cf9199 commit c8c625a
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 25 deletions.
10 changes: 3 additions & 7 deletions boto/s3/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,9 @@ def _get_key_internal(self, key_name, headers, query_args_l):
k = self.key_class(self)
provider = self.connection.provider
k.metadata = boto.utils.get_aws_metadata(response.msg, provider)
k.etag = response.getheader('etag')
k.content_type = response.getheader('content-type')
k.content_encoding = response.getheader('content-encoding')
k.content_disposition = response.getheader('content-disposition')
k.content_language = response.getheader('content-language')
k.last_modified = response.getheader('last-modified')
for field in Key.base_fields:
k.__dict__[field.lower().replace('-', '_')] = \
response.getheader(field)
# the following machinations are a workaround to the fact that
# apache/fastcgi omits the content-length header on HEAD
# requests when the content-length is zero.
Expand All @@ -219,7 +216,6 @@ def _get_key_internal(self, key_name, headers, query_args_l):
k.size = int(response.getheader('content-length'))
else:
k.size = 0
k.cache_control = response.getheader('cache-control')
k.name = key_name
k.handle_version_headers(response)
k.handle_encryption_headers(response)
Expand Down
26 changes: 11 additions & 15 deletions boto/s3/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,16 @@ class Key(object):
# x-amz-meta).
base_user_settable_fields = set(["cache-control", "content-disposition",
"content-encoding", "content-language",
"content-md5", "content-type"])
"content-md5", "content-type",
"x-robots-tag", "expires"])
_underscore_base_user_settable_fields = set()
for f in base_user_settable_fields:
_underscore_base_user_settable_fields.add(f.replace('-', '_'))
# Metadata fields, whether user-settable or not, other than custom
# metadata fields (i.e., those beginning with a provider specific prefix
# like x-amz-meta).
base_fields = (base_user_settable_fields |
set(["last-modified", "content-length", "date", "etag"]))



Expand Down Expand Up @@ -302,20 +308,8 @@ def open_read(self, headers=None, query_args='',
elif name.lower() == 'content-range':
end_range = re.sub('.*/(.*)', '\\1', value)
self.size = int(end_range)
elif name.lower() == 'etag':
self.etag = value
elif name.lower() == 'content-type':
self.content_type = value
elif name.lower() == 'content-encoding':
self.content_encoding = value
elif name.lower() == 'content-language':
self.content_language = value
elif name.lower() == 'last-modified':
self.last_modified = value
elif name.lower() == 'cache-control':
self.cache_control = value
elif name.lower() == 'content-disposition':
self.content_disposition = value
elif name.lower() in Key.base_fields:
self.__dict__[name.lower().replace('-', '_')] = value
self.handle_version_headers(self.resp)
self.handle_encryption_headers(self.resp)
self.handle_restore_headers(self.resp)
Expand Down Expand Up @@ -555,6 +549,8 @@ def set_metadata(self, name, value):
self.metadata['Content-MD5'] = value
else:
self.metadata[name] = value
if name.lower() in Key.base_user_settable_fields:
self.__dict__[name.lower().replace('-', '_')] = value

def update_metadata(self, d):
self.metadata.update(d)
Expand Down
4 changes: 1 addition & 3 deletions boto/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,7 @@ def merge_meta(headers, metadata, provider=None):
metadata_prefix = provider.metadata_prefix
final_headers = headers.copy()
for k in metadata.keys():
if k.lower() in ['cache-control', 'content-md5', 'content-type',
'content-encoding', 'content-disposition',
'expires']:
if k.lower() in boto.s3.key.Key.base_user_settable_fields:
final_headers[k] = metadata[k]
else:
final_headers[metadata_prefix + k] = metadata[k]
Expand Down
20 changes: 20 additions & 0 deletions tests/integration/s3/test_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,13 +403,33 @@ def test_header_encoding(self):
key.set_metadata('Cache-control', u'public, max-age=500')
key.set_metadata('Test-Plus', u'A plus (+)')
key.set_metadata('Content-disposition', u'filename=Schöne Zeit.txt')
key.set_metadata('Content-Encoding', 'gzip')
key.set_metadata('Content-Language', 'de')
key.set_metadata('Content-Type', 'application/pdf')
self.assertEqual(key.content_type, 'application/pdf')
key.set_metadata('X-Robots-Tag', 'all')
key.set_metadata('Expires', u'Thu, 01 Dec 1994 16:00:00 GMT')
key.set_contents_from_string('foo')

check = self.bucket.get_key('test_header_encoding')
remote_metadata = check._get_remote_metadata()

# TODO: investigate whether encoding ' ' as '%20' makes sense
self.assertEqual(check.cache_control, 'public,%20max-age=500')
self.assertEqual(remote_metadata['cache-control'], 'public,%20max-age=500')
self.assertEqual(check.get_metadata('test-plus'), 'A plus (+)')
self.assertEqual(check.content_disposition, 'filename=Sch%C3%B6ne%20Zeit.txt')
self.assertEqual(remote_metadata['content-disposition'], 'filename=Sch%C3%B6ne%20Zeit.txt')
self.assertEqual(check.content_encoding, 'gzip')
self.assertEqual(remote_metadata['content-encoding'], 'gzip')
self.assertEqual(check.content_language, 'de')
self.assertEqual(remote_metadata['content-language'], 'de')
self.assertEqual(check.content_type, 'application/pdf')
self.assertEqual(remote_metadata['content-type'], 'application/pdf')
self.assertEqual(check.x_robots_tag, 'all')
self.assertEqual(remote_metadata['x-robots-tag'], 'all')
self.assertEqual(check.expires, 'Thu,%2001%20Dec%201994%2016:00:00%20GMT')
self.assertEqual(remote_metadata['expires'], 'Thu,%2001%20Dec%201994%2016:00:00%20GMT')

expected = u'filename=Schöne Zeit.txt'
if six.PY2:
Expand Down

0 comments on commit c8c625a

Please sign in to comment.