diff --git a/etc/object-server.conf-sample b/etc/object-server.conf-sample index 9d57f8f02d..8831048e43 100644 --- a/etc/object-server.conf-sample +++ b/etc/object-server.conf-sample @@ -33,7 +33,7 @@ use = egg:swift#object # Comma separated list of headers that can be set in metadata on an object. # This list is in addition to X-Object-Meta-* headers and cannot include # Content-Type, etag, Content-Length, or deleted -# allowed_headers = Content-Encoding +# allowed_headers = Content-Encoding, Content-Disposition, X-Object-Manifest [object-replicator] # You can override the default log routing for this app here (don't use set!): diff --git a/swift/obj/server.py b/swift/obj/server.py index 89cc1db428..0d5207e788 100644 --- a/swift/obj/server.py +++ b/swift/obj/server.py @@ -279,7 +279,8 @@ class ObjectController(object): self.max_upload_time = int(conf.get('max_upload_time', 86400)) self.slow = int(conf.get('slow', 0)) self.bytes_per_sync = int(conf.get('mb_per_sync', 512)) * 1024 * 1024 - default_allowed_headers = 'content-encoding' + default_allowed_headers = 'content-encoding, x-object-manifest, ' \ + 'content-disposition' self.allowed_headers = set(i.strip().lower() for i in \ conf.get('allowed_headers', \ default_allowed_headers).split(',') if i.strip() and \ @@ -421,9 +422,6 @@ class ObjectController(object): 'ETag': etag, 'Content-Length': str(os.fstat(fd).st_size), } - if 'x-object-manifest' in request.headers: - metadata['X-Object-Manifest'] = \ - request.headers['x-object-manifest'] metadata.update(val for val in request.headers.iteritems() if val[0].lower().startswith('x-object-meta-') and len(val[0]) > 14) @@ -494,8 +492,7 @@ class ObjectController(object): 'application/octet-stream'), app_iter=file, request=request, conditional_response=True) for key, value in file.metadata.iteritems(): - if key == 'X-Object-Manifest' or \ - key.lower().startswith('x-object-meta-') or \ + if key.lower().startswith('x-object-meta-') or \ key.lower() in self.allowed_headers: response.headers[key] = value response.etag = file.metadata['ETag'] diff --git a/test/unit/obj/test_server.py b/test/unit/obj/test_server.py index 904eb93c79..3b2e8f6a61 100644 --- a/test/unit/obj/test_server.py +++ b/test/unit/obj/test_server.py @@ -57,6 +57,7 @@ class TestObjectController(unittest.TestCase): def test_POST_update_meta(self): """ Test swift.object_server.ObjectController.POST """ + original_headers = self.object_controller.allowed_headers test_headers = 'content-encoding foo bar'.split() self.object_controller.allowed_headers = set(test_headers) timestamp = normalize_timestamp(time()) @@ -86,13 +87,13 @@ class TestObjectController(unittest.TestCase): req = Request.blank('/sda1/p/a/c/o') resp = self.object_controller.GET(req) - self.assert_("X-Object-Meta-1" not in resp.headers and \ - "X-Object-Meta-Two" not in resp.headers and \ - "X-Object-Meta-3" in resp.headers and \ - "X-Object-Meta-4" in resp.headers and \ - "Foo" in resp.headers and \ - "Bar" in resp.headers and \ - "Baz" not in resp.headers and \ + self.assert_("X-Object-Meta-1" not in resp.headers and + "X-Object-Meta-Two" not in resp.headers and + "X-Object-Meta-3" in resp.headers and + "X-Object-Meta-4" in resp.headers and + "Foo" in resp.headers and + "Bar" in resp.headers and + "Baz" not in resp.headers and "Content-Encoding" in resp.headers) self.assertEquals(resp.headers['Content-Type'], 'application/x-test') @@ -105,13 +106,56 @@ class TestObjectController(unittest.TestCase): self.assertEquals(resp.status_int, 202) req = Request.blank('/sda1/p/a/c/o') resp = self.object_controller.GET(req) - self.assert_("X-Object-Meta-3" not in resp.headers and \ - "X-Object-Meta-4" not in resp.headers and \ - "Foo" not in resp.headers and \ - "Bar" not in resp.headers and \ + self.assert_("X-Object-Meta-3" not in resp.headers and + "X-Object-Meta-4" not in resp.headers and + "Foo" not in resp.headers and + "Bar" not in resp.headers and "Content-Encoding" not in resp.headers) self.assertEquals(resp.headers['Content-Type'], 'application/x-test') + # test defaults + self.object_controller.allowed_headers = original_headers + timestamp = normalize_timestamp(time()) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, + headers={'X-Timestamp': timestamp, + 'Content-Type': 'application/x-test', + 'Foo': 'fooheader', + 'X-Object-Meta-1': 'One', + 'X-Object-Manifest': 'c/bar', + 'Content-Encoding': 'gzip', + 'Content-Disposition': 'bar', + }) + req.body = 'VERIFY' + resp = self.object_controller.PUT(req) + self.assertEquals(resp.status_int, 201) + req = Request.blank('/sda1/p/a/c/o') + resp = self.object_controller.GET(req) + self.assert_("X-Object-Meta-1" in resp.headers and + "Foo" not in resp.headers and + "Content-Encoding" in resp.headers and + "X-Object-Manifest" in resp.headers and + "Content-Disposition" in resp.headers) + self.assertEquals(resp.headers['Content-Type'], 'application/x-test') + + timestamp = normalize_timestamp(time()) + req = Request.blank('/sda1/p/a/c/o', + environ={'REQUEST_METHOD': 'POST'}, + headers={'X-Timestamp': timestamp, + 'X-Object-Meta-3': 'Three', + 'Foo': 'fooheader', + 'Content-Type': 'application/x-test'}) + resp = self.object_controller.POST(req) + self.assertEquals(resp.status_int, 202) + req = Request.blank('/sda1/p/a/c/o') + resp = self.object_controller.GET(req) + self.assert_("X-Object-Meta-1" not in resp.headers and + "Foo" not in resp.headers and + "Content-Encoding" not in resp.headers and + "X-Object-Manifest" not in resp.headers and + "Content-Disposition" not in resp.headers and + "X-Object-Meta-3" in resp.headers) + self.assertEquals(resp.headers['Content-Type'], 'application/x-test') + def test_POST_not_exist(self): timestamp = normalize_timestamp(time()) req = Request.blank('/sda1/p/a/c/fail',