Fix conflict SLO reponse

This patch fixes Swift to respond "409 Conflict"
when a segment object path of the manifest on PUT SLO
is same as requested object path. It is because
the request will overwrite the segment and then it
will absolutely cause "409 Conflict" on GET SLO.

e.g.:

request:
PUT "http://hostname/v1/AUTH_account/container/segment_object_00?multipart-manifest=put"

manifest file:
[{"path" : "container/segment_object_00", "etag" : "<etag of segment_object_00>", "size_bytes" : <size of segment_object_00>},
{"path" : "container/segment_object_01", "etag" : "<etag of segment_object_01>", "size_bytes" : <size of segment_object_01>},
{"path" : "container/segment_object_02", "etag" : "<etag of segment_object_02>", "size_bytes" : <size of segment_object_02>}]

Change-Id: I4f4f7b9dbeb6a7c355b801c7e0ae560aa19a70b4
Closes-Bug: 1417936
This commit is contained in:
Kazuhiro MIYAHARA 2015-02-19 17:38:10 +09:00 committed by Samuel Merritt
parent 399a66fb12
commit e4d326b5a7
3 changed files with 57 additions and 1 deletions

View File

@ -223,3 +223,4 @@ Hua Zhang (zhuadl@cn.ibm.com)
Jian Zhang (jian.zhang@intel.com)
Ning Zhang (ning@zmanda.com)
Yuan Zhou (yuan.zhou@intel.com)
Kazuhiro Miyahara (miyahara.kazuhiro@lab.ntt.co.jp)

View File

@ -586,6 +586,11 @@ class StaticLargeObject(object):
if isinstance(obj_name, unicode):
obj_name = obj_name.encode('utf-8')
obj_path = '/'.join(['', vrs, account, obj_name.lstrip('/')])
if req.path == quote(obj_path):
raise HTTPConflict(
'Manifest object name "%s" '
'cannot be included in the manifest'
% obj_name)
try:
seg_size = int(seg_dict['size_bytes'])
except (ValueError, TypeError):

View File

@ -24,7 +24,7 @@ from swift.common import swob, utils
from swift.common.exceptions import ListingIterError, SegmentError
from swift.common.middleware import slo
from swift.common.swob import Request, Response, HTTPException
from swift.common.utils import json
from swift.common.utils import quote, json
from test.unit.common.middleware.helpers import FakeSwift
@ -139,6 +139,11 @@ class TestSloPutManifest(SloTestCase):
swob.HTTPOk,
{'Content-Length': '100', 'Etag': 'etagoftheobjectsegment'},
None)
self.app.register(
'HEAD', '/v1/AUTH_test/cont/object2',
swob.HTTPOk,
{'Content-Length': '100', 'Etag': 'etagoftheobjectsegment'},
None)
self.app.register(
'HEAD', '/v1/AUTH_test/cont/object\xe2\x99\xa1',
swob.HTTPOk,
@ -149,6 +154,11 @@ class TestSloPutManifest(SloTestCase):
swob.HTTPOk,
{'Content-Length': '10', 'Etag': 'etagoftheobjectsegment'},
None)
self.app.register(
'HEAD', u'/v1/AUTH_test/cont/あ_1',
swob.HTTPOk,
{'Content-Length': '1', 'Etag': 'a'},
None)
self.app.register(
'PUT', '/v1/AUTH_test/c/man', swob.HTTPCreated, {}, None)
self.app.register(
@ -391,6 +401,46 @@ class TestSloPutManifest(SloTestCase):
self.assertEquals(errors[4][0], '/checktest/slob')
self.assertEquals(errors[4][1], 'Etag Mismatch')
def test_handle_multipart_put_manifest_equal_slo(self):
test_json_data = json.dumps([{'path': '/cont/object',
'etag': 'etagoftheobjectsegment',
'size_bytes': 100}])
req = Request.blank(
'/v1/AUTH_test/cont/object?multipart-manifest=put',
environ={'REQUEST_METHOD': 'PUT'}, headers={'Accept': 'test'},
body=test_json_data)
status, headers, body = self.call_slo(req)
self.assertEqual(status, '409 Conflict')
self.assertEqual(self.app.call_count, 0)
def test_handle_multipart_put_manifest_equal_slo_non_ascii(self):
test_json_data = json.dumps([{'path': u'/cont/あ_1',
'etag': 'a',
'size_bytes': 1}])
path = quote(u'/v1/AUTH_test/cont/あ_1')
req = Request.blank(
path + '?multipart-manifest=put',
environ={'REQUEST_METHOD': 'PUT'}, headers={'Accept': 'test'},
body=test_json_data)
status, headers, body = self.call_slo(req)
self.assertEqual(status, '409 Conflict')
self.assertEqual(self.app.call_count, 0)
def test_handle_multipart_put_manifest_equal_last_segment(self):
test_json_data = json.dumps([{'path': '/cont/object',
'etag': 'etagoftheobjectsegment',
'size_bytes': 100},
{'path': '/cont/object2',
'etag': 'etagoftheobjectsegment',
'size_bytes': 100}])
req = Request.blank(
'/v1/AUTH_test/cont/object2?multipart-manifest=put',
environ={'REQUEST_METHOD': 'PUT'}, headers={'Accept': 'test'},
body=test_json_data)
status, headers, body = self.call_slo(req)
self.assertEqual(status, '409 Conflict')
self.assertEqual(self.app.call_count, 1)
class TestSloDeleteManifest(SloTestCase):