Use application/directory content-type for dir markers
Previously, we were using a content-type of text/directory, but that is already defined in RFC 2425 and doesn't reflect our usage: The text/directory Content-Type is defined for holding a variety of directory information, for example, name, or email address, or logo. (From there it goes on to describe a superset of the vCard format defined in RFC 2426.) application/directory, on the other hand, is used by Static Web [1] and is used by cloudfuse [2]. Seems like as sane a choice as any to standardize on. [1] https://github.com/openstack/swift/blob/2.5.0/swift/common/middleware/staticweb.py#L71-L75 [2] https://github.com/redbo/cloudfuse/blob/1.0/README#L105-L106 Change-Id: I19e30484270886292d83f50e7ee997b6e1623ec7
This commit is contained in:
parent
015903e383
commit
9fd537a082
@ -189,6 +189,10 @@ _default_local_options = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
POLICY = 'X-Storage-Policy'
|
POLICY = 'X-Storage-Policy'
|
||||||
|
KNOWN_DIR_MARKERS = (
|
||||||
|
'application/directory', # Preferred
|
||||||
|
'text/directory', # Historically relevant
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_from_queue(q, timeout=864000):
|
def get_from_queue(q, timeout=864000):
|
||||||
@ -1130,9 +1134,8 @@ class SwiftService(object):
|
|||||||
|
|
||||||
fp = None
|
fp = None
|
||||||
try:
|
try:
|
||||||
content_type = headers.get('content-type')
|
content_type = headers.get('content-type', '').split(';', 1)[0]
|
||||||
if (content_type and
|
if content_type in KNOWN_DIR_MARKERS:
|
||||||
content_type.split(';', 1)[0] == 'text/directory'):
|
|
||||||
make_dir = not no_file and out_file != "-"
|
make_dir = not no_file and out_file != "-"
|
||||||
if make_dir and not isdir(path):
|
if make_dir and not isdir(path):
|
||||||
mkdirs(path)
|
mkdirs(path)
|
||||||
@ -1590,12 +1593,12 @@ class SwiftService(object):
|
|||||||
if options['changed']:
|
if options['changed']:
|
||||||
try:
|
try:
|
||||||
headers = conn.head_object(container, obj)
|
headers = conn.head_object(container, obj)
|
||||||
ct = headers.get('content-type')
|
ct = headers.get('content-type', '').split(';', 1)[0]
|
||||||
cl = int(headers.get('content-length'))
|
cl = int(headers.get('content-length'))
|
||||||
et = headers.get('etag')
|
et = headers.get('etag')
|
||||||
mt = headers.get('x-object-meta-mtime')
|
mt = headers.get('x-object-meta-mtime')
|
||||||
|
|
||||||
if (ct.split(';', 1)[0] == 'text/directory' and
|
if (ct in KNOWN_DIR_MARKERS and
|
||||||
cl == 0 and
|
cl == 0 and
|
||||||
et == EMPTY_ETAG and
|
et == EMPTY_ETAG and
|
||||||
mt == put_headers['x-object-meta-mtime']):
|
mt == put_headers['x-object-meta-mtime']):
|
||||||
@ -1614,7 +1617,7 @@ class SwiftService(object):
|
|||||||
return res
|
return res
|
||||||
try:
|
try:
|
||||||
conn.put_object(container, obj, '', content_length=0,
|
conn.put_object(container, obj, '', content_length=0,
|
||||||
content_type='text/directory',
|
content_type=KNOWN_DIR_MARKERS[0],
|
||||||
headers=put_headers,
|
headers=put_headers,
|
||||||
response_dict=results_dict)
|
response_dict=results_dict)
|
||||||
res.update({
|
res.update({
|
||||||
|
@ -1348,6 +1348,142 @@ class TestServiceUpload(_TestServiceBase):
|
|||||||
errors.append(msg)
|
errors.append(msg)
|
||||||
self.assertFalse(errors, "\nERRORS:\n%s" % '\n'.join(errors))
|
self.assertFalse(errors, "\nERRORS:\n%s" % '\n'.join(errors))
|
||||||
|
|
||||||
|
def test_create_dir_marker_job_unchanged(self):
|
||||||
|
mock_conn = mock.Mock()
|
||||||
|
mock_conn.head_object.return_value = {
|
||||||
|
'content-type': 'application/directory',
|
||||||
|
'content-length': '0',
|
||||||
|
'x-object-meta-mtime': '1.234000',
|
||||||
|
'etag': md5().hexdigest()}
|
||||||
|
|
||||||
|
s = SwiftService()
|
||||||
|
with mock.patch('swiftclient.service.get_conn',
|
||||||
|
return_value=mock_conn):
|
||||||
|
with mock.patch('swiftclient.service.getmtime',
|
||||||
|
return_value=1.234):
|
||||||
|
r = s._create_dir_marker_job(conn=mock_conn,
|
||||||
|
container='test_c',
|
||||||
|
obj='test_o',
|
||||||
|
path='test',
|
||||||
|
options={'changed': True,
|
||||||
|
'skip_identical': True,
|
||||||
|
'leave_segments': True,
|
||||||
|
'header': '',
|
||||||
|
'segment_size': 10})
|
||||||
|
self.assertEqual({
|
||||||
|
'action': 'create_dir_marker',
|
||||||
|
'container': 'test_c',
|
||||||
|
'object': 'test_o',
|
||||||
|
'path': 'test',
|
||||||
|
'headers': {'x-object-meta-mtime': '1.234000'},
|
||||||
|
# NO response dict!
|
||||||
|
'success': True,
|
||||||
|
}, r)
|
||||||
|
self.assertEqual([], mock_conn.put_object.mock_calls)
|
||||||
|
|
||||||
|
def test_create_dir_marker_job_unchanged_old_type(self):
|
||||||
|
mock_conn = mock.Mock()
|
||||||
|
mock_conn.head_object.return_value = {
|
||||||
|
'content-type': 'text/directory',
|
||||||
|
'content-length': '0',
|
||||||
|
'x-object-meta-mtime': '1.000000',
|
||||||
|
'etag': md5().hexdigest()}
|
||||||
|
|
||||||
|
s = SwiftService()
|
||||||
|
with mock.patch('swiftclient.service.get_conn',
|
||||||
|
return_value=mock_conn):
|
||||||
|
with mock.patch('swiftclient.service.time',
|
||||||
|
return_value=1.234):
|
||||||
|
r = s._create_dir_marker_job(conn=mock_conn,
|
||||||
|
container='test_c',
|
||||||
|
obj='test_o',
|
||||||
|
options={'changed': True,
|
||||||
|
'skip_identical': True,
|
||||||
|
'leave_segments': True,
|
||||||
|
'header': '',
|
||||||
|
'segment_size': 10})
|
||||||
|
self.assertEqual({
|
||||||
|
'action': 'create_dir_marker',
|
||||||
|
'container': 'test_c',
|
||||||
|
'object': 'test_o',
|
||||||
|
'path': None,
|
||||||
|
'headers': {'x-object-meta-mtime': '1.000000'},
|
||||||
|
# NO response dict!
|
||||||
|
'success': True,
|
||||||
|
}, r)
|
||||||
|
self.assertEqual([], mock_conn.put_object.mock_calls)
|
||||||
|
|
||||||
|
def test_create_dir_marker_job_overwrites_bad_type(self):
|
||||||
|
mock_conn = mock.Mock()
|
||||||
|
mock_conn.head_object.return_value = {
|
||||||
|
'content-type': 'text/plain',
|
||||||
|
'content-length': '0',
|
||||||
|
'x-object-meta-mtime': '1.000000',
|
||||||
|
'etag': md5().hexdigest()}
|
||||||
|
|
||||||
|
s = SwiftService()
|
||||||
|
with mock.patch('swiftclient.service.get_conn',
|
||||||
|
return_value=mock_conn):
|
||||||
|
with mock.patch('swiftclient.service.time',
|
||||||
|
return_value=1.234):
|
||||||
|
r = s._create_dir_marker_job(conn=mock_conn,
|
||||||
|
container='test_c',
|
||||||
|
obj='test_o',
|
||||||
|
options={'changed': True,
|
||||||
|
'skip_identical': True,
|
||||||
|
'leave_segments': True,
|
||||||
|
'header': '',
|
||||||
|
'segment_size': 10})
|
||||||
|
self.assertEqual({
|
||||||
|
'action': 'create_dir_marker',
|
||||||
|
'container': 'test_c',
|
||||||
|
'object': 'test_o',
|
||||||
|
'path': None,
|
||||||
|
'headers': {'x-object-meta-mtime': '1.000000'},
|
||||||
|
'response_dict': {},
|
||||||
|
'success': True,
|
||||||
|
}, r)
|
||||||
|
self.assertEqual([mock.call(
|
||||||
|
'test_c', 'test_o', '',
|
||||||
|
content_length=0,
|
||||||
|
content_type='application/directory',
|
||||||
|
headers={'x-object-meta-mtime': '1.000000'},
|
||||||
|
response_dict={})], mock_conn.put_object.mock_calls)
|
||||||
|
|
||||||
|
def test_create_dir_marker_job_missing(self):
|
||||||
|
mock_conn = mock.Mock()
|
||||||
|
mock_conn.head_object.side_effect = \
|
||||||
|
ClientException('Not Found', http_status=404)
|
||||||
|
|
||||||
|
s = SwiftService()
|
||||||
|
with mock.patch('swiftclient.service.get_conn',
|
||||||
|
return_value=mock_conn):
|
||||||
|
with mock.patch('swiftclient.service.time',
|
||||||
|
return_value=1.234):
|
||||||
|
r = s._create_dir_marker_job(conn=mock_conn,
|
||||||
|
container='test_c',
|
||||||
|
obj='test_o',
|
||||||
|
options={'changed': True,
|
||||||
|
'skip_identical': True,
|
||||||
|
'leave_segments': True,
|
||||||
|
'header': '',
|
||||||
|
'segment_size': 10})
|
||||||
|
self.assertEqual({
|
||||||
|
'action': 'create_dir_marker',
|
||||||
|
'container': 'test_c',
|
||||||
|
'object': 'test_o',
|
||||||
|
'path': None,
|
||||||
|
'headers': {'x-object-meta-mtime': '1.000000'},
|
||||||
|
'response_dict': {},
|
||||||
|
'success': True,
|
||||||
|
}, r)
|
||||||
|
self.assertEqual([mock.call(
|
||||||
|
'test_c', 'test_o', '',
|
||||||
|
content_length=0,
|
||||||
|
content_type='application/directory',
|
||||||
|
headers={'x-object-meta-mtime': '1.000000'},
|
||||||
|
response_dict={})], mock_conn.put_object.mock_calls)
|
||||||
|
|
||||||
|
|
||||||
class TestServiceDownload(_TestServiceBase):
|
class TestServiceDownload(_TestServiceBase):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user