diff --git a/swift/common/middleware/s3api/controllers/multi_upload.py b/swift/common/middleware/s3api/controllers/multi_upload.py index bc6473e3e6..3ce12c5f7b 100644 --- a/swift/common/middleware/s3api/controllers/multi_upload.py +++ b/swift/common/middleware/s3api/controllers/multi_upload.py @@ -652,6 +652,9 @@ class UploadController(Controller): _key = key.lower() if _key.startswith('x-amz-meta-'): headers['x-object-meta-' + _key[11:]] = val + elif _key in ('content-encoding', 'content-language', + 'content-disposition', 'expires', 'cache-control'): + headers[key] = val hct_header = sysmeta_header('object', 'has-content-type') if resp.sysmeta_headers.get(hct_header) == 'yes': diff --git a/test/functional/s3api/test_multi_upload.py b/test/functional/s3api/test_multi_upload.py index 4f0e98bcb1..5b79d7e79e 100644 --- a/test/functional/s3api/test_multi_upload.py +++ b/test/functional/s3api/test_multi_upload.py @@ -115,7 +115,11 @@ class TestS3ApiMultiUpload(S3ApiBase): bucket = 'bucket' keys = [u'obj1\N{SNOWMAN}', u'obj2\N{SNOWMAN}', 'obj3'] bad_content_md5 = base64.b64encode(b'a' * 16).strip().decode('ascii') - headers = [{'Content-Type': 'foo/bar', 'x-amz-meta-baz': 'quux'}, + headers = [{'Content-Type': 'foo/bar', 'x-amz-meta-baz': 'quux', + 'Content-Encoding': 'gzip', 'Content-Language': 'en-US', + 'Expires': 'Thu, 01 Dec 1994 16:00:00 GMT', + 'Cache-Control': 'no-cache', + 'Content-Disposition': 'attachment'}, {'Content-MD5': bad_content_md5}, {'Etag': 'nonsense'}] uploads = [] @@ -346,6 +350,11 @@ class TestS3ApiMultiUpload(S3ApiBase): self.assertEqual(status, 200) self.assertEqual(headers['content-length'], str(exp_size)) self.assertEqual(headers['content-type'], 'foo/bar') + self.assertEqual(headers['content-encoding'], 'gzip') + self.assertEqual(headers['content-language'], 'en-US') + self.assertEqual(headers['content-disposition'], 'attachment') + self.assertEqual(headers['expires'], 'Thu, 01 Dec 1994 16:00:00 GMT') + self.assertEqual(headers['cache-control'], 'no-cache') self.assertEqual(headers['x-amz-meta-baz'], 'quux') swift_etag = '"%s"' % md5( diff --git a/test/unit/common/middleware/s3api/test_multi_upload.py b/test/unit/common/middleware/s3api/test_multi_upload.py index bcc89fc1d1..63ab8e81fb 100644 --- a/test/unit/common/middleware/s3api/test_multi_upload.py +++ b/test/unit/common/middleware/s3api/test_multi_upload.py @@ -654,6 +654,7 @@ class TestS3ApiMultiUpload(S3ApiTestCase): 'Authorization': 'AWS test:tester:hmac', 'Date': self.get_date_header(), 'x-amz-meta-foo': 'bar', + 'content-encoding': 'gzip', }) req = Request.blank('/bucket/object?uploads', environ={'REQUEST_METHOD': 'POST', @@ -665,6 +666,7 @@ class TestS3ApiMultiUpload(S3ApiTestCase): _, _, req_headers = self.swift.calls_with_headers[-1] self.assertEqual(req_headers.get('X-Object-Meta-Foo'), 'bar') + self.assertEqual(req_headers.get('Content-Encoding'), 'gzip') self.assertNotIn('Etag', req_headers) self.assertNotIn('Content-MD5', req_headers) if bucket_exists: @@ -964,7 +966,7 @@ class TestS3ApiMultiUpload(S3ApiTestCase): status, headers, body = self.call_s3api(req) self.assertEqual(self._get_error_code(body), 'NoSuchBucket') - def test_object_multipart_upload_complete(self): + def _do_test_object_multipart_upload_complete(self): content_md5 = base64.b64encode(md5( XML.encode('ascii'), usedforsecurity=False).digest()) req = Request.blank('/bucket/object?uploadId=X', @@ -1001,6 +1003,31 @@ class TestS3ApiMultiUpload(S3ApiTestCase): self.assertEqual(headers.get(h), override_etag) self.assertEqual(headers.get('X-Object-Sysmeta-S3Api-Upload-Id'), 'X') + def test_object_multipart_upload_complete(self): + self._do_test_object_multipart_upload_complete() + + def test_object_multipart_upload_complete_other_headers(self): + headers = {'x-object-meta-foo': 'bar', + 'content-type': 'application/directory', + 'x-object-sysmeta-s3api-has-content-type': 'yes', + 'x-object-sysmeta-s3api-content-type': 'baz/quux', + 'content-encoding': 'gzip', + 'content-language': 'de-DE', + 'content-disposition': 'attachment', + 'expires': 'Fri, 25 Mar 2022 09:34:00 GMT', + 'cache-control': 'no-cache' + } + self.swift.register('HEAD', self.segment_bucket + '/object/X', + swob.HTTPOk, headers, None) + self._do_test_object_multipart_upload_complete() + _, _, headers = self.swift.calls_with_headers[-2] + self.assertEqual('gzip', headers.get('Content-Encoding')) + self.assertEqual('de-DE', headers.get('Content-Language')) + self.assertEqual('attachment', headers.get('Content-Disposition')) + self.assertEqual('Fri, 25 Mar 2022 09:34:00 GMT', + headers.get('Expires')) + self.assertEqual('no-cache', headers.get('Cache-Control')) + def test_object_multipart_upload_complete_non_ascii(self): wsgi_snowman = '\xe2\x98\x83'