Object COPY requests now always copy the newest object they can find.
This commit is contained in:
parent
6c50e9b3a1
commit
37fbf5ab77
@ -632,10 +632,10 @@ class Controller(object):
|
|||||||
if newest:
|
if newest:
|
||||||
ts = 0
|
ts = 0
|
||||||
if source:
|
if source:
|
||||||
ts = float(source.getheader('x-put-timestamp',
|
ts = float(source.getheader('x-put-timestamp') or
|
||||||
source.getheader('x-timestamp', 0)))
|
source.getheader('x-timestamp') or 0)
|
||||||
pts = float(possible_source.getheader('x-put-timestamp',
|
pts = float(possible_source.getheader('x-put-timestamp') or
|
||||||
possible_source.getheader('x-timestamp', 0)))
|
possible_source.getheader('x-timestamp') or 0)
|
||||||
if pts > ts:
|
if pts > ts:
|
||||||
source = possible_source
|
source = possible_source
|
||||||
continue
|
continue
|
||||||
@ -956,6 +956,7 @@ class ObjectController(Controller):
|
|||||||
reader = req.environ['wsgi.input'].read
|
reader = req.environ['wsgi.input'].read
|
||||||
data_source = iter(lambda: reader(self.app.client_chunk_size), '')
|
data_source = iter(lambda: reader(self.app.client_chunk_size), '')
|
||||||
source_header = req.headers.get('X-Copy-From')
|
source_header = req.headers.get('X-Copy-From')
|
||||||
|
source_resp = None
|
||||||
if source_header:
|
if source_header:
|
||||||
source_header = unquote(source_header)
|
source_header = unquote(source_header)
|
||||||
acct = req.path_info.split('/', 2)[1]
|
acct = req.path_info.split('/', 2)[1]
|
||||||
@ -971,6 +972,7 @@ class ObjectController(Controller):
|
|||||||
'<container name>/<object name>')
|
'<container name>/<object name>')
|
||||||
source_req = req.copy_get()
|
source_req = req.copy_get()
|
||||||
source_req.path_info = source_header
|
source_req.path_info = source_header
|
||||||
|
source_req.headers['X-Newest'] = 'true'
|
||||||
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
|
||||||
@ -1103,6 +1105,9 @@ class ObjectController(Controller):
|
|||||||
if source_header:
|
if source_header:
|
||||||
resp.headers['X-Copied-From'] = quote(
|
resp.headers['X-Copied-From'] = quote(
|
||||||
source_header.split('/', 2)[2])
|
source_header.split('/', 2)[2])
|
||||||
|
if 'last-modified' in source_resp.headers:
|
||||||
|
resp.headers['X-Copied-From-Last-Modified'] = \
|
||||||
|
source_resp.headers['last-modified']
|
||||||
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
|
||||||
|
@ -211,8 +211,8 @@ def fake_http_connect(*code_iter, **kwargs):
|
|||||||
def getheader(self, name, default=None):
|
def getheader(self, name, default=None):
|
||||||
return dict(self.getheaders()).get(name.lower(), default)
|
return dict(self.getheaders()).get(name.lower(), default)
|
||||||
|
|
||||||
timestamps_iter = iter(kwargs.get('timestamps') or [None] * len(code_iter))
|
timestamps_iter = iter(kwargs.get('timestamps') or ['1'] * len(code_iter))
|
||||||
etag_iter = iter(kwargs.get('etags') or ['1'] * len(code_iter))
|
etag_iter = iter(kwargs.get('etags') or [None] * len(code_iter))
|
||||||
x = kwargs.get('missing_container', [False] * len(code_iter))
|
x = kwargs.get('missing_container', [False] * len(code_iter))
|
||||||
if not isinstance(x, (tuple, list)):
|
if not isinstance(x, (tuple, list)):
|
||||||
x = [x] * len(code_iter)
|
x = [x] * len(code_iter)
|
||||||
@ -1014,6 +1014,29 @@ class TestObjectController(unittest.TestCase):
|
|||||||
test_status_map((200, 200, 200), 200, ('1', '3', '1'), '3')
|
test_status_map((200, 200, 200), 200, ('1', '3', '1'), '3')
|
||||||
test_status_map((200, 200, 200), 200, ('3', '3', '1'), '3')
|
test_status_map((200, 200, 200), 200, ('3', '3', '1'), '3')
|
||||||
|
|
||||||
|
def test_GET_newest(self):
|
||||||
|
with save_globals():
|
||||||
|
controller = proxy_server.ObjectController(self.app, 'account',
|
||||||
|
'container', 'object')
|
||||||
|
|
||||||
|
def test_status_map(statuses, expected, timestamps,
|
||||||
|
expected_timestamp):
|
||||||
|
proxy_server.http_connect = \
|
||||||
|
fake_http_connect(*statuses, timestamps=timestamps)
|
||||||
|
self.app.memcache.store = {}
|
||||||
|
req = Request.blank('/a/c/o', {}, headers={'x-newest': 'true'})
|
||||||
|
self.app.update_request(req)
|
||||||
|
res = controller.GET(req)
|
||||||
|
self.assertEquals(res.status[:len(str(expected))],
|
||||||
|
str(expected))
|
||||||
|
self.assertEquals(res.headers.get('last-modified'),
|
||||||
|
expected_timestamp)
|
||||||
|
|
||||||
|
test_status_map((200, 200, 200), 200, ('1', '2', '3'), '3')
|
||||||
|
test_status_map((200, 200, 200), 200, ('1', '3', '2'), '3')
|
||||||
|
test_status_map((200, 200, 200), 200, ('1', '3', '1'), '3')
|
||||||
|
test_status_map((200, 200, 200), 200, ('3', '3', '1'), '3')
|
||||||
|
|
||||||
with save_globals():
|
with save_globals():
|
||||||
controller = proxy_server.ObjectController(self.app, 'account',
|
controller = proxy_server.ObjectController(self.app, 'account',
|
||||||
'container', 'object')
|
'container', 'object')
|
||||||
@ -1725,8 +1748,10 @@ class TestObjectController(unittest.TestCase):
|
|||||||
headers={'Destination': 'c/o'})
|
headers={'Destination': 'c/o'})
|
||||||
req.account = 'a'
|
req.account = 'a'
|
||||||
proxy_server.http_connect = \
|
proxy_server.http_connect = \
|
||||||
fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
|
fake_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201,
|
||||||
# acct cont acct cont objc obj obj obj
|
201)
|
||||||
|
# acct cont acct cont objc objc objc obj obj
|
||||||
|
# obj
|
||||||
self.app.memcache.store = {}
|
self.app.memcache.store = {}
|
||||||
resp = controller.COPY(req)
|
resp = controller.COPY(req)
|
||||||
self.assertEquals(resp.status_int, 201)
|
self.assertEquals(resp.status_int, 201)
|
||||||
@ -1738,8 +1763,10 @@ class TestObjectController(unittest.TestCase):
|
|||||||
req.account = 'a'
|
req.account = 'a'
|
||||||
controller.object_name = 'o/o2'
|
controller.object_name = 'o/o2'
|
||||||
proxy_server.http_connect = \
|
proxy_server.http_connect = \
|
||||||
fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
|
fake_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201,
|
||||||
# acct cont acct cont objc obj obj obj
|
201)
|
||||||
|
# acct cont acct cont objc objc objc obj obj
|
||||||
|
# obj
|
||||||
self.app.memcache.store = {}
|
self.app.memcache.store = {}
|
||||||
resp = controller.COPY(req)
|
resp = controller.COPY(req)
|
||||||
self.assertEquals(resp.status_int, 201)
|
self.assertEquals(resp.status_int, 201)
|
||||||
@ -1750,8 +1777,10 @@ class TestObjectController(unittest.TestCase):
|
|||||||
req.account = 'a'
|
req.account = 'a'
|
||||||
controller.object_name = 'o'
|
controller.object_name = 'o'
|
||||||
proxy_server.http_connect = \
|
proxy_server.http_connect = \
|
||||||
fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
|
fake_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201,
|
||||||
# acct cont acct cont objc obj obj obj
|
201)
|
||||||
|
# acct cont acct cont objc objc objc obj obj
|
||||||
|
# obj
|
||||||
self.app.memcache.store = {}
|
self.app.memcache.store = {}
|
||||||
resp = controller.COPY(req)
|
resp = controller.COPY(req)
|
||||||
self.assertEquals(resp.status_int, 201)
|
self.assertEquals(resp.status_int, 201)
|
||||||
@ -1763,8 +1792,10 @@ class TestObjectController(unittest.TestCase):
|
|||||||
req.account = 'a'
|
req.account = 'a'
|
||||||
controller.object_name = 'o/o2'
|
controller.object_name = 'o/o2'
|
||||||
proxy_server.http_connect = \
|
proxy_server.http_connect = \
|
||||||
fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
|
fake_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201,
|
||||||
# acct cont acct cont objc obj obj obj
|
201)
|
||||||
|
# acct cont acct cont objc objc objc obj obj
|
||||||
|
# obj
|
||||||
self.app.memcache.store = {}
|
self.app.memcache.store = {}
|
||||||
resp = controller.COPY(req)
|
resp = controller.COPY(req)
|
||||||
self.assertEquals(resp.status_int, 201)
|
self.assertEquals(resp.status_int, 201)
|
||||||
@ -1820,8 +1851,8 @@ class TestObjectController(unittest.TestCase):
|
|||||||
req.account = 'a'
|
req.account = 'a'
|
||||||
controller.object_name = 'o'
|
controller.object_name = 'o'
|
||||||
proxy_server.http_connect = \
|
proxy_server.http_connect = \
|
||||||
fake_http_connect(200, 200, 200, 201, 201, 201)
|
fake_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
|
||||||
# acct cont objc obj obj obj
|
# acct cont objc objc objc obj obj obj
|
||||||
self.app.memcache.store = {}
|
self.app.memcache.store = {}
|
||||||
resp = controller.COPY(req)
|
resp = controller.COPY(req)
|
||||||
self.assertEquals(resp.status_int, 201)
|
self.assertEquals(resp.status_int, 201)
|
||||||
@ -1829,6 +1860,23 @@ class TestObjectController(unittest.TestCase):
|
|||||||
'testing')
|
'testing')
|
||||||
self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay')
|
self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay')
|
||||||
|
|
||||||
|
def test_COPY_newest(self):
|
||||||
|
with save_globals():
|
||||||
|
controller = proxy_server.ObjectController(self.app, 'a', 'c', 'o')
|
||||||
|
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,
|
||||||
|
timestamps=('1', '1', '1', '3', '2', '4', '4', '4'))
|
||||||
|
# acct cont objc objc 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-last-modified'],
|
||||||
|
'3')
|
||||||
|
|
||||||
def test_chunked_put(self):
|
def test_chunked_put(self):
|
||||||
|
|
||||||
class ChunkedFile():
|
class ChunkedFile():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user