objects md5-collisions
This patch identifies md5 collisions on objects and sends a 403 from the object server. Credits for originating this fix are to Michael Factor. Change-Id: I4f1b32183e2be6bbea56eaff86b9a4c7f440804a Fix: Bug #1157454
This commit is contained in:
parent
b93b1327f7
commit
caa01cd81e
@ -42,6 +42,10 @@ class DiskFileError(SwiftException):
|
||||
pass
|
||||
|
||||
|
||||
class DiskFileCollision(SwiftException):
|
||||
pass
|
||||
|
||||
|
||||
class DiskFileNotExist(SwiftException):
|
||||
pass
|
||||
|
||||
|
@ -38,7 +38,7 @@ from swift.common.bufferedhttp import http_connect
|
||||
from swift.common.constraints import check_object_creation, check_mount, \
|
||||
check_float, check_utf8
|
||||
from swift.common.exceptions import ConnectionTimeout, DiskFileError, \
|
||||
DiskFileNotExist
|
||||
DiskFileNotExist, DiskFileCollision
|
||||
from swift.obj.replicator import tpool_reraise, invalidate_hash, \
|
||||
quarantine_renamer, get_hashes
|
||||
from swift.common.http import is_success
|
||||
@ -46,7 +46,7 @@ from swift.common.swob import HTTPAccepted, HTTPBadRequest, HTTPCreated, \
|
||||
HTTPInternalServerError, HTTPNoContent, HTTPNotFound, HTTPNotModified, \
|
||||
HTTPPreconditionFailed, HTTPRequestTimeout, HTTPUnprocessableEntity, \
|
||||
HTTPClientDisconnect, HTTPMethodNotAllowed, Request, Response, UTC, \
|
||||
HTTPInsufficientStorage, multi_range_iterator
|
||||
HTTPInsufficientStorage, HTTPForbidden, multi_range_iterator
|
||||
|
||||
|
||||
DATADIR = 'objects'
|
||||
@ -105,6 +105,7 @@ class DiskFile(object):
|
||||
:param keep_data_fp: if True, don't close the fp, otherwise close it
|
||||
:param disk_chunk_size: size of chunks on file reads
|
||||
:param iter_hook: called when __iter__ returns a chunk
|
||||
:raises DiskFileCollision: on md5 collision
|
||||
"""
|
||||
|
||||
def __init__(self, path, device, partition, account, container, obj,
|
||||
@ -155,6 +156,14 @@ class DiskFile(object):
|
||||
if key.lower() not in DISALLOWED_HEADERS:
|
||||
del self.metadata[key]
|
||||
self.metadata.update(read_metadata(mfp))
|
||||
if 'name' in self.metadata:
|
||||
if self.metadata['name'] != self.name:
|
||||
self.logger.error(_('Client path %(client)s does not match '
|
||||
'path stored in object metadata %(meta)s'),
|
||||
{'client': self.name,
|
||||
'meta': self.metadata['name']})
|
||||
raise DiskFileCollision('Client path does not match path '
|
||||
'stored in object metadata')
|
||||
|
||||
def __iter__(self):
|
||||
"""Returns an iterator over the data file."""
|
||||
@ -926,6 +935,8 @@ class ObjectController(object):
|
||||
res = HTTPMethodNotAllowed()
|
||||
else:
|
||||
res = method(req)
|
||||
except DiskFileCollision:
|
||||
res = HTTPForbidden(request=req)
|
||||
except (Exception, Timeout):
|
||||
self.logger.exception(_(
|
||||
'ERROR __call__ error with %(method)s'
|
||||
|
@ -153,7 +153,6 @@ class TestDiskFile(unittest.TestCase):
|
||||
hook_call_count[0] += 1
|
||||
|
||||
df = self._get_data_file(fsize=65, csize=8, iter_hook=hook)
|
||||
print repr(df.__dict__)
|
||||
for _ in df:
|
||||
pass
|
||||
|
||||
@ -1416,6 +1415,65 @@ class TestObjectController(unittest.TestCase):
|
||||
self.assertEquals(errbuf.getvalue(), '')
|
||||
self.assertEquals(outbuf.getvalue()[:4], '405 ')
|
||||
|
||||
def my_check(*args):
|
||||
return False
|
||||
def my_storage_directory(*args):
|
||||
return self.testdir+'/collide'
|
||||
_storage_directory = object_server.storage_directory
|
||||
_check = object_server.check_object_creation
|
||||
try:
|
||||
object_server.storage_directory = my_storage_directory
|
||||
object_server.check_object_creation = my_check
|
||||
inbuf = StringIO()
|
||||
errbuf = StringIO()
|
||||
outbuf = StringIO()
|
||||
self.object_controller.__call__({'REQUEST_METHOD': 'PUT',
|
||||
'SCRIPT_NAME': '',
|
||||
'PATH_INFO': '/sda1/p/a/c/o',
|
||||
'SERVER_NAME': '127.0.0.1',
|
||||
'SERVER_PORT': '8080',
|
||||
'SERVER_PROTOCOL': 'HTTP/1.0',
|
||||
'CONTENT_LENGTH': '0',
|
||||
'CONTENT_TYPE': 'text/html',
|
||||
'HTTP_X_TIMESTAMP': 1.2,
|
||||
'wsgi.version': (1, 0),
|
||||
'wsgi.url_scheme': 'http',
|
||||
'wsgi.input': inbuf,
|
||||
'wsgi.errors': errbuf,
|
||||
'wsgi.multithread': False,
|
||||
'wsgi.multiprocess': False,
|
||||
'wsgi.run_once': False},
|
||||
start_response)
|
||||
self.assertEquals(errbuf.getvalue(), '')
|
||||
self.assertEquals(outbuf.getvalue()[:4], '201 ')
|
||||
|
||||
inbuf = StringIO()
|
||||
errbuf = StringIO()
|
||||
outbuf = StringIO()
|
||||
self.object_controller.__call__({'REQUEST_METHOD': 'PUT',
|
||||
'SCRIPT_NAME': '',
|
||||
'PATH_INFO': '/sda1/q/b/d/x',
|
||||
'SERVER_NAME': '127.0.0.1',
|
||||
'SERVER_PORT': '8080',
|
||||
'SERVER_PROTOCOL': 'HTTP/1.0',
|
||||
'CONTENT_LENGTH': '0',
|
||||
'CONTENT_TYPE': 'text/html',
|
||||
'HTTP_X_TIMESTAMP': 1.3,
|
||||
'wsgi.version': (1, 0),
|
||||
'wsgi.url_scheme': 'http',
|
||||
'wsgi.input': inbuf,
|
||||
'wsgi.errors': errbuf,
|
||||
'wsgi.multithread': False,
|
||||
'wsgi.multiprocess': False,
|
||||
'wsgi.run_once': False},
|
||||
start_response)
|
||||
self.assertEquals(errbuf.getvalue(), '')
|
||||
self.assertEquals(outbuf.getvalue()[:4], '403 ')
|
||||
|
||||
finally:
|
||||
object_server.storage_directory = _storage_directory
|
||||
object_server.check_object_creation = _check
|
||||
|
||||
def test_invalid_method_doesnt_exist(self):
|
||||
errbuf = StringIO()
|
||||
outbuf = StringIO()
|
||||
|
Loading…
Reference in New Issue
Block a user