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:
|
||||
ts = 0
|
||||
if source:
|
||||
ts = float(source.getheader('x-put-timestamp',
|
||||
source.getheader('x-timestamp', 0)))
|
||||
pts = float(possible_source.getheader('x-put-timestamp',
|
||||
possible_source.getheader('x-timestamp', 0)))
|
||||
ts = float(source.getheader('x-put-timestamp') or
|
||||
source.getheader('x-timestamp') or 0)
|
||||
pts = float(possible_source.getheader('x-put-timestamp') or
|
||||
possible_source.getheader('x-timestamp') or 0)
|
||||
if pts > ts:
|
||||
source = possible_source
|
||||
continue
|
||||
@ -956,6 +956,7 @@ class ObjectController(Controller):
|
||||
reader = req.environ['wsgi.input'].read
|
||||
data_source = iter(lambda: reader(self.app.client_chunk_size), '')
|
||||
source_header = req.headers.get('X-Copy-From')
|
||||
source_resp = None
|
||||
if source_header:
|
||||
source_header = unquote(source_header)
|
||||
acct = req.path_info.split('/', 2)[1]
|
||||
@ -971,6 +972,7 @@ class ObjectController(Controller):
|
||||
'<container name>/<object name>')
|
||||
source_req = req.copy_get()
|
||||
source_req.path_info = source_header
|
||||
source_req.headers['X-Newest'] = 'true'
|
||||
orig_obj_name = self.object_name
|
||||
orig_container_name = self.container_name
|
||||
self.object_name = src_obj_name
|
||||
@ -1103,6 +1105,9 @@ class ObjectController(Controller):
|
||||
if source_header:
|
||||
resp.headers['X-Copied-From'] = quote(
|
||||
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():
|
||||
if k.lower().startswith('x-object-meta-'):
|
||||
resp.headers[k] = v
|
||||
|
@ -211,8 +211,8 @@ def fake_http_connect(*code_iter, **kwargs):
|
||||
def getheader(self, name, default=None):
|
||||
return dict(self.getheaders()).get(name.lower(), default)
|
||||
|
||||
timestamps_iter = iter(kwargs.get('timestamps') or [None] * len(code_iter))
|
||||
etag_iter = iter(kwargs.get('etags') or ['1'] * len(code_iter))
|
||||
timestamps_iter = iter(kwargs.get('timestamps') 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))
|
||||
if not isinstance(x, (tuple, list)):
|
||||
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, ('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():
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
'container', 'object')
|
||||
@ -1725,8 +1748,10 @@ class TestObjectController(unittest.TestCase):
|
||||
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
|
||||
fake_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201,
|
||||
201)
|
||||
# acct cont acct cont objc objc objc obj obj
|
||||
# obj
|
||||
self.app.memcache.store = {}
|
||||
resp = controller.COPY(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
@ -1738,8 +1763,10 @@ class TestObjectController(unittest.TestCase):
|
||||
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
|
||||
fake_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201,
|
||||
201)
|
||||
# acct cont acct cont objc objc objc obj obj
|
||||
# obj
|
||||
self.app.memcache.store = {}
|
||||
resp = controller.COPY(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
@ -1750,8 +1777,10 @@ class TestObjectController(unittest.TestCase):
|
||||
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
|
||||
fake_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201,
|
||||
201)
|
||||
# acct cont acct cont objc objc objc obj obj
|
||||
# obj
|
||||
self.app.memcache.store = {}
|
||||
resp = controller.COPY(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
@ -1763,8 +1792,10 @@ class TestObjectController(unittest.TestCase):
|
||||
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
|
||||
fake_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201,
|
||||
201)
|
||||
# acct cont acct cont objc objc objc obj obj
|
||||
# obj
|
||||
self.app.memcache.store = {}
|
||||
resp = controller.COPY(req)
|
||||
self.assertEquals(resp.status_int, 201)
|
||||
@ -1820,8 +1851,8 @@ class TestObjectController(unittest.TestCase):
|
||||
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
|
||||
fake_http_connect(200, 200, 200, 200, 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)
|
||||
@ -1829,6 +1860,23 @@ class TestObjectController(unittest.TestCase):
|
||||
'testing')
|
||||
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):
|
||||
|
||||
class ChunkedFile():
|
||||
|
Loading…
Reference in New Issue
Block a user