Object COPY requests now always copy the newest object they can find.

This commit is contained in:
gholt 2011-06-08 02:26:16 +00:00
parent 6c50e9b3a1
commit 37fbf5ab77
2 changed files with 69 additions and 16 deletions

View File

@ -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

View File

@ -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():