fixed auth_copy bug, bytes_transferred copy logging bug, and early denial for proxy.server.ObjectController.COPY method; added tests
This commit is contained in:
commit
a35a887d74
@ -629,7 +629,8 @@ class ObjectController(Controller):
|
|||||||
return HTTPPreconditionFailed(request=req,
|
return HTTPPreconditionFailed(request=req,
|
||||||
body='X-Copy-From header must be of the form'
|
body='X-Copy-From header must be of the form'
|
||||||
'<container name>/<object name>')
|
'<container name>/<object name>')
|
||||||
source_req = Request.blank(source_header)
|
source_req = req.copy_get()
|
||||||
|
source_req.path_info = source_header
|
||||||
orig_obj_name = self.object_name
|
orig_obj_name = self.object_name
|
||||||
orig_container_name = self.container_name
|
orig_container_name = self.container_name
|
||||||
self.object_name = src_obj_name
|
self.object_name = src_obj_name
|
||||||
@ -774,6 +775,8 @@ class ObjectController(Controller):
|
|||||||
for k, v in req.headers.items():
|
for k, v in req.headers.items():
|
||||||
if k.lower().startswith('x-object-meta-'):
|
if k.lower().startswith('x-object-meta-'):
|
||||||
resp.headers[k] = v
|
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'])
|
resp.last_modified = float(req.headers['X-Timestamp'])
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
@ -820,6 +823,7 @@ class ObjectController(Controller):
|
|||||||
'Object DELETE')
|
'Object DELETE')
|
||||||
|
|
||||||
@public
|
@public
|
||||||
|
@delay_denial
|
||||||
def COPY(self, req):
|
def COPY(self, req):
|
||||||
"""HTTP COPY request handler."""
|
"""HTTP COPY request handler."""
|
||||||
dest = req.headers.get('Destination')
|
dest = req.headers.get('Destination')
|
||||||
@ -845,8 +849,8 @@ class ObjectController(Controller):
|
|||||||
new_headers['Content-Length'] = 0
|
new_headers['Content-Length'] = 0
|
||||||
del new_headers['Destination']
|
del new_headers['Destination']
|
||||||
new_path = '/' + self.account_name + dest
|
new_path = '/' + self.account_name + dest
|
||||||
new_req = Request.blank(new_path,
|
new_req = Request.blank(new_path, environ=req.environ,
|
||||||
environ={'REQUEST_METHOD': 'PUT'}, headers=new_headers)
|
headers=new_headers)
|
||||||
return self.PUT(new_req)
|
return self.PUT(new_req)
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ from uuid import uuid4
|
|||||||
from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
|
from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
|
||||||
MAX_META_OVERALL_SIZE, MAX_META_VALUE_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):
|
class TestObject(unittest.TestCase):
|
||||||
@ -86,6 +86,93 @@ class TestObject(unittest.TestCase):
|
|||||||
except Exception, err:
|
except Exception, err:
|
||||||
self.assert_(str(err).startswith('No result after '))
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -1782,6 +1782,21 @@ class TestObjectController(unittest.TestCase):
|
|||||||
self.assert_(hasattr(req, 'bytes_transferred'))
|
self.assert_(hasattr(req, 'bytes_transferred'))
|
||||||
self.assertEquals(req.bytes_transferred, 10)
|
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):
|
def test_response_bytes_transferred_attr(self):
|
||||||
with save_globals():
|
with save_globals():
|
||||||
proxy_server.http_connect = \
|
proxy_server.http_connect = \
|
||||||
@ -1904,6 +1919,23 @@ class TestObjectController(unittest.TestCase):
|
|||||||
res = controller.PUT(req)
|
res = controller.PUT(req)
|
||||||
self.assert_(called[0])
|
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):
|
class TestContainerController(unittest.TestCase):
|
||||||
"Test swift.proxy_server.ContainerController"
|
"Test swift.proxy_server.ContainerController"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user