diff --git a/swift/proxy/server.py b/swift/proxy/server.py index 0145857236..5046c8d96f 100644 --- a/swift/proxy/server.py +++ b/swift/proxy/server.py @@ -618,7 +618,7 @@ class ObjectController(Controller): except ValueError: return HTTPPreconditionFailed(request=req, body='X-Copy-From header must be of the form' - 'container/object') + '/') source_req = Request.blank(source_header) orig_obj_name = self.object_name orig_container_name = self.container_name @@ -809,11 +809,11 @@ class ObjectController(Controller): if not dest.startswith('/'): dest = '/' + dest try: - _, dest_container, dest_object = dest.split('/', 3) + _, dest_container, dest_object = dest.split('/', 2) except ValueError: return HTTPPreconditionFailed(request=req, body='Destination header must be of the form ' - 'container/object') + '/') new_source = '/' + self.container_name + '/' + self.object_name self.container_name = dest_container self.object_name = dest_object diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py index 24dd14facc..2f205b44f0 100644 --- a/test/unit/proxy/test_server.py +++ b/test/unit/proxy/test_server.py @@ -1014,6 +1014,18 @@ class TestObjectController(unittest.TestCase): self.assertEquals(resp.status_int, 201) self.assertEquals(resp.headers['x-copied-from'], 'c/o') + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, + headers={'Content-Length': '0', + 'X-Copy-From': 'c/o/o2'}) + req.account = 'a' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) + # acct cont acct cont objc obj obj obj + self.app.memcache.store = {} + resp = controller.PUT(req) + self.assertEquals(resp.status_int, 201) + self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2') + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, headers={'Content-Length': '0', 'X-Copy-From': '/c/o'}) @@ -1026,6 +1038,18 @@ class TestObjectController(unittest.TestCase): self.assertEquals(resp.status_int, 201) self.assertEquals(resp.headers['x-copied-from'], 'c/o') + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, + headers={'Content-Length': '0', + 'X-Copy-From': '/c/o/o2'}) + req.account = 'a' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) + # acct cont acct cont objc obj obj obj + self.app.memcache.store = {} + resp = controller.PUT(req) + self.assertEquals(resp.status_int, 201) + self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2') + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, headers={'Content-Length': '0', 'X-Copy-From': '/c/o'}) @@ -1073,6 +1097,123 @@ class TestObjectController(unittest.TestCase): self.assertEquals(resp.headers.get('x-object-meta-test'), 'testing') self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay') + def test_COPY(self): + with save_globals(): + controller = proxy_server.ObjectController(self.app, 'a', 'c', 'o') + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, + headers={'Content-Length': '0'}) + req.account = 'a' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 201, 201, 201) + # acct cont obj obj obj + resp = controller.PUT(req) + self.assertEquals(resp.status_int, 201) + + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': 'c/o'}) + req.account = 'a' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) + # acct cont acct cont objc obj obj obj + self.app.memcache.store = {} + resp = controller.COPY(req) + self.assertEquals(resp.status_int, 201) + self.assertEquals(resp.headers['x-copied-from'], 'c/o') + + req = Request.blank('/a/c/o/o2', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': 'c/o'}) + req.account = 'a' + controller.object_name = 'o/o2' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) + # acct cont acct cont objc obj obj obj + self.app.memcache.store = {} + resp = controller.COPY(req) + self.assertEquals(resp.status_int, 201) + self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2') + + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': '/c/o'}) + req.account = 'a' + controller.object_name = 'o' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) + # acct cont acct cont objc obj obj obj + self.app.memcache.store = {} + resp = controller.COPY(req) + self.assertEquals(resp.status_int, 201) + self.assertEquals(resp.headers['x-copied-from'], 'c/o') + + req = Request.blank('/a/c/o/o2', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': '/c/o'}) + req.account = 'a' + controller.object_name = 'o/o2' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) + # acct cont acct cont objc obj obj obj + self.app.memcache.store = {} + resp = controller.COPY(req) + self.assertEquals(resp.status_int, 201) + self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2') + + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': 'c_o'}) + req.account = 'a' + controller.object_name = 'o' + proxy_server.http_connect = \ + fake_http_connect(200, 200) + # acct cont + self.app.memcache.store = {} + resp = controller.COPY(req) + self.assertEquals(resp.status_int, 412) + + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': '/c/o'}) + req.account = 'a' + controller.object_name = 'o' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 503, 503, 503) + # acct cont objc objc objc + self.app.memcache.store = {} + resp = controller.COPY(req) + self.assertEquals(resp.status_int, 503) + + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': '/c/o'}) + req.account = 'a' + controller.object_name = 'o' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 404, 404, 404) + # acct cont objc objc objc + self.app.memcache.store = {} + resp = controller.COPY(req) + self.assertEquals(resp.status_int, 404) + + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': '/c/o'}) + req.account = 'a' + controller.object_name = 'o' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 404, 404, 200, 201, 201, 201) + # acct cont objc objc objc obj obj obj + self.app.memcache.store = {} + resp = controller.COPY(req) + self.assertEquals(resp.status_int, 201) + + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': '/c/o', + 'X-Object-Meta-Ours': 'okay'}) + req.account = 'a' + controller.object_name = 'o' + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 201, 201, 201) + # acct cont objc obj obj obj + self.app.memcache.store = {} + resp = controller.COPY(req) + self.assertEquals(resp.status_int, 201) + self.assertEquals(resp.headers.get('x-object-meta-test'), 'testing') + self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay') + def test_chunked_put_and_a_bit_more(self): # Since we're starting up a lot here, we're going to test more than # just chunked puts; we're also going to test parts of