diff --git a/swift/proxy/server.py b/swift/proxy/server.py index ca7543cc8f..0cf9e5ebdd 100644 --- a/swift/proxy/server.py +++ b/swift/proxy/server.py @@ -629,7 +629,8 @@ class ObjectController(Controller): return HTTPPreconditionFailed(request=req, body='X-Copy-From header must be of the form' '/') - source_req = Request.blank(source_header) + source_req = req.copy_get() + source_req.path_info = source_header orig_obj_name = self.object_name orig_container_name = self.container_name self.object_name = src_obj_name @@ -774,6 +775,8 @@ class ObjectController(Controller): for k, v in req.headers.items(): if k.lower().startswith('x-object-meta-'): resp.headers[k] = v + # reset the bytes, since the user didn't actually send anything + req.bytes_transferred = 0 resp.last_modified = float(req.headers['X-Timestamp']) return resp @@ -820,6 +823,7 @@ class ObjectController(Controller): 'Object DELETE') @public + @delay_denial def COPY(self, req): """HTTP COPY request handler.""" dest = req.headers.get('Destination') @@ -845,8 +849,8 @@ class ObjectController(Controller): new_headers['Content-Length'] = 0 del new_headers['Destination'] new_path = '/' + self.account_name + dest - new_req = Request.blank(new_path, - environ={'REQUEST_METHOD': 'PUT'}, headers=new_headers) + new_req = Request.blank(new_path, environ=req.environ, + headers=new_headers) return self.PUT(new_req) diff --git a/test/functionalnosetests/test_object.py b/test/functionalnosetests/test_object.py index 4a12bf088f..e4b2fc48c5 100644 --- a/test/functionalnosetests/test_object.py +++ b/test/functionalnosetests/test_object.py @@ -7,7 +7,7 @@ from uuid import uuid4 from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \ MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH -from swift_testing import check_response, retry, skip +from swift_testing import check_response, retry, skip, skip3, swift_test_user class TestObject(unittest.TestCase): @@ -86,6 +86,93 @@ class TestObject(unittest.TestCase): except Exception, err: self.assert_(str(err).startswith('No result after ')) + def test_private_object(self): + if skip or skip3: + raise SkipTest + # Ensure we can't access the object with the third account + def get(url, token, parsed, conn): + conn.request('GET', '%s/%s/%s' % (parsed.path, self.container, + self.obj), '', + {'X-Auth-Token': token}) + return check_response(conn) + resp = retry(get, use_account=3) + resp.read() + self.assertEquals(resp.status, 403) + # create a shared container writable by account3 + shared_container = uuid4().hex + def put(url, token, parsed, conn): + conn.request('PUT', '%s/%s' % (parsed.path, + shared_container), '', + {'X-Auth-Token': token, + 'X-Container-Read': swift_test_user[2], + 'X-Container-Write': swift_test_user[2]}) + return check_response(conn) + resp = retry(put) + resp.read() + self.assertEquals(resp.status, 201) + # verify third account can not copy from private container + def copy(url, token, parsed, conn): + conn.request('PUT', '%s/%s/%s' % (parsed.path, + shared_container, + 'private_object'), + '', {'X-Auth-Token': token, + 'Content-Length': '0', + 'X-Copy-From': '%s/%s' % (self.container, + self.obj)}) + return check_response(conn) + resp = retry(copy, use_account=3) + resp.read() + self.assertEquals(resp.status, 403) + # verify third account can write "obj1" to shared container + def put(url, token, parsed, conn): + conn.request('PUT', '%s/%s/%s' % (parsed.path, shared_container, + 'obj1'), 'test', {'X-Auth-Token': token}) + return check_response(conn) + resp = retry(put, use_account=3) + resp.read() + self.assertEquals(resp.status, 201) + # verify third account can copy "obj1" to shared container + def copy2(url, token, parsed, conn): + conn.request('COPY', '%s/%s/%s' % (parsed.path, + shared_container, + 'obj1'), + '', {'X-Auth-Token': token, + 'Destination': '%s/%s' % (shared_container, + 'obj1')}) + return check_response(conn) + resp = retry(copy2, use_account=3) + resp.read() + self.assertEquals(resp.status, 201) + # verify third account STILL can not copy from private container + def copy3(url, token, parsed, conn): + conn.request('COPY', '%s/%s/%s' % (parsed.path, + self.container, + self.obj), + '', {'X-Auth-Token': token, + 'Destination': '%s/%s' % (shared_container, + 'private_object')}) + return check_response(conn) + resp = retry(copy3, use_account=3) + resp.read() + self.assertEquals(resp.status, 403) + # clean up "obj1" + def delete(url, token, parsed, conn): + conn.request('DELETE', '%s/%s/%s' % (parsed.path, shared_container, + 'obj1'), '', {'X-Auth-Token': token}) + return check_response(conn) + resp = retry(delete) + resp.read() + self.assertEquals(resp.status, 204) + # clean up shared_container + def delete(url, token, parsed, conn): + conn.request('DELETE', + parsed.path + '/' + shared_container, '', + {'X-Auth-Token': token}) + return check_response(conn) + resp = retry(delete) + resp.read() + self.assertEquals(resp.status, 204) + if __name__ == '__main__': unittest.main() diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py index 72aac0eb5e..2bf85c139c 100644 --- a/test/unit/proxy/test_server.py +++ b/test/unit/proxy/test_server.py @@ -1782,6 +1782,21 @@ class TestObjectController(unittest.TestCase): self.assert_(hasattr(req, 'bytes_transferred')) self.assertEquals(req.bytes_transferred, 10) + def test_copy_zero_bytes_transferred_attr(self): + with save_globals(): + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201, + body='1234567890') + controller = proxy_server.ObjectController(self.app, 'account', + 'container', 'object') + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, + headers={'X-Copy-From': 'c/o2', + 'Content-Length': '0'}) + self.app.update_request(req) + res = controller.PUT(req) + self.assert_(hasattr(req, 'bytes_transferred')) + self.assertEquals(req.bytes_transferred, 0) + def test_response_bytes_transferred_attr(self): with save_globals(): proxy_server.http_connect = \ @@ -1904,6 +1919,23 @@ class TestObjectController(unittest.TestCase): res = controller.PUT(req) self.assert_(called[0]) + def test_COPY_calls_authorize(self): + called = [False] + + def authorize(req): + called[0] = True + return HTTPUnauthorized(request=req) + with save_globals(): + proxy_server.http_connect = \ + fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201) + controller = proxy_server.ObjectController(self.app, 'account', + 'container', 'object') + req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'}, + headers={'Destination': 'c/o'}) + req.environ['swift.authorize'] = authorize + self.app.update_request(req) + res = controller.COPY(req) + self.assert_(called[0]) class TestContainerController(unittest.TestCase): "Test swift.proxy_server.ContainerController"