Fix multipart upload is required SLO in pipeline
Multipart upload is enable by default, but it needs "slo" middleware support. If it isn't exist in pipeline, multipart upload still work, but download is not work(that's only xml file you can get.) If there is no "slo" in pipeline, all requests of multipart from client will be reject(return S3NotImplemented, 501 Not Implemented). Change-Id: If0a862d9f80cc806f5b0a8a0e87c70b17920f635 Closes-Bug: #1396039
This commit is contained in:
parent
58ded99729
commit
bd18bf100c
|
@ -94,12 +94,15 @@ def validate_bucket_name(name):
|
|||
|
||||
class Swift3Middleware(object):
|
||||
"""Swift3 S3 compatibility midleware"""
|
||||
def __init__(self, app, *args, **kwargs):
|
||||
def __init__(self, app, conf, *args, **kwargs):
|
||||
self.app = app
|
||||
self.slo_enabled = True
|
||||
|
||||
self.check_pipeline(conf)
|
||||
|
||||
def __call__(self, env, start_response):
|
||||
try:
|
||||
req = Request(env)
|
||||
req = Request(env, self.slo_enabled)
|
||||
resp = self.handle_request(req)
|
||||
except NotS3Request:
|
||||
resp = self.app
|
||||
|
@ -131,6 +134,45 @@ class Swift3Middleware(object):
|
|||
|
||||
return res
|
||||
|
||||
def check_pipeline(self, conf):
|
||||
"""
|
||||
Check that proxy-server.conf has an appropriate pipeline for swift3.
|
||||
"""
|
||||
if conf.get('__file__', None) is None:
|
||||
return
|
||||
|
||||
ctx = loadcontext(loadwsgi.APP, conf.__file__)
|
||||
pipeline = str(PipelineWrapper(ctx)).split(' ')
|
||||
|
||||
# Add compatible with 3rd party middleware.
|
||||
if check_filter_order(pipeline, ['swift3', 'proxy-server']):
|
||||
|
||||
auth_pipeline = pipeline[pipeline.index('swift3') + 1:
|
||||
pipeline.index('proxy-server')]
|
||||
|
||||
# Check SLO middleware
|
||||
if 'slo' not in auth_pipeline:
|
||||
self.slo_enabled = False
|
||||
LOGGER.debug('swift3 middleware is required SLO middleware '
|
||||
'to support multi-part upload, please add it '
|
||||
'in pipline')
|
||||
|
||||
if 'tempauth' in auth_pipeline:
|
||||
LOGGER.debug('Use tempauth middleware.')
|
||||
return
|
||||
elif 'keystoneauth' in auth_pipeline:
|
||||
if check_filter_order(auth_pipeline, ['s3token',
|
||||
'authtoken',
|
||||
'keystoneauth']):
|
||||
LOGGER.debug('Use keystone middleware.')
|
||||
return
|
||||
|
||||
elif len(auth_pipeline):
|
||||
LOGGER.debug('Use third party(unknown) auth middleware.')
|
||||
return
|
||||
|
||||
raise ValueError('Invalid proxy pipeline: %s' % pipeline)
|
||||
|
||||
|
||||
def check_filter_order(pipeline, required_filters):
|
||||
"""
|
||||
|
@ -145,36 +187,6 @@ def check_filter_order(pipeline, required_filters):
|
|||
return indexes == sorted(indexes)
|
||||
|
||||
|
||||
def check_pipeline():
|
||||
"""
|
||||
Check that proxy-server.conf has an appropriate pipeline for swift3.
|
||||
"""
|
||||
ctx = loadcontext(loadwsgi.APP, CONF.__file__)
|
||||
pipeline = str(PipelineWrapper(ctx)).split(' ')
|
||||
|
||||
# Add compatible with 3rd party middleware.
|
||||
if check_filter_order(pipeline, ['swift3', 'proxy-server']):
|
||||
|
||||
auth_pipeline = pipeline[pipeline.index('swift3') + 1:
|
||||
pipeline.index('proxy-server')]
|
||||
|
||||
if 'tempauth' in auth_pipeline:
|
||||
LOGGER.debug('Use tempauth middleware.')
|
||||
return
|
||||
elif 'keystoneauth' in auth_pipeline:
|
||||
if check_filter_order(auth_pipeline, ['s3token',
|
||||
'authtoken',
|
||||
'keystoneauth']):
|
||||
LOGGER.debug('Use keystone middleware.')
|
||||
return
|
||||
|
||||
elif len(auth_pipeline):
|
||||
LOGGER.debug('Use third party(unknown) auth middleware.')
|
||||
return
|
||||
|
||||
raise ValueError('Invalid proxy pipeline: %s' % pipeline)
|
||||
|
||||
|
||||
def filter_factory(global_conf, **local_conf):
|
||||
"""Standard filter factory to use the middleware with paste.deploy"""
|
||||
CONF.update(global_conf)
|
||||
|
@ -184,6 +196,7 @@ def filter_factory(global_conf, **local_conf):
|
|||
global LOGGER
|
||||
LOGGER = get_logger(CONF, log_route='swift3')
|
||||
|
||||
check_pipeline()
|
||||
def swift3_filter(app):
|
||||
return Swift3Middleware(app, CONF)
|
||||
|
||||
return Swift3Middleware
|
||||
return swift3_filter
|
||||
|
|
|
@ -61,7 +61,7 @@ class Request(swob.Request):
|
|||
"""
|
||||
S3 request object.
|
||||
"""
|
||||
def __init__(self, env):
|
||||
def __init__(self, env, slo_enabled=True):
|
||||
swob.Request.__init__(self, env)
|
||||
|
||||
self.access_key, self.signature = self._parse_authorization()
|
||||
|
@ -70,6 +70,7 @@ class Request(swob.Request):
|
|||
self._validate_headers()
|
||||
self.token = base64.urlsafe_b64encode(self._canonical_string())
|
||||
self.user_id = None
|
||||
self.slo_enabled = slo_enabled
|
||||
|
||||
# Avoids that swift.swob.Response replaces Location header value
|
||||
# by full URL when absolute path given. See swift.swob for more detail.
|
||||
|
@ -295,6 +296,11 @@ class Request(swob.Request):
|
|||
if self.is_service_request:
|
||||
return ServiceController
|
||||
|
||||
if not self.slo_enabled:
|
||||
multi_part = ['partNumber', 'uploadId', 'uploads']
|
||||
if len([p for p in multi_part if p in self.params]):
|
||||
raise S3NotImplemented("Multi-part feature isn't support")
|
||||
|
||||
if 'acl' in self.params:
|
||||
return AclController
|
||||
if 'delete' in self.params:
|
||||
|
|
|
@ -58,7 +58,7 @@ class Swift3TestCase(unittest.TestCase):
|
|||
def setUp(self):
|
||||
self.app = FakeApp()
|
||||
self.swift = self.app.swift
|
||||
self.swift3 = Swift3Middleware(self.app)
|
||||
self.swift3 = Swift3Middleware(self.app, CONF)
|
||||
|
||||
self.swift.register('HEAD', '/v1/AUTH_test/bucket',
|
||||
swob.HTTPNoContent, {}, None)
|
||||
|
|
|
@ -27,7 +27,6 @@ from swift.common.swob import Request
|
|||
from swift3.test.unit import Swift3TestCase
|
||||
from swift3.request import Request as S3Request
|
||||
from swift3.etree import fromstring
|
||||
from swift3.middleware import check_pipeline
|
||||
|
||||
|
||||
class TestSwift3Middleware(Swift3TestCase):
|
||||
|
@ -318,24 +317,27 @@ class TestSwift3Middleware(Swift3TestCase):
|
|||
conf.__file__ = ''
|
||||
|
||||
pipeline.return_value = 'swift3 tempauth proxy-server'
|
||||
check_pipeline()
|
||||
self.swift3.check_pipeline(conf)
|
||||
|
||||
pipeline.return_value = 'swift3 s3token authtoken keystoneauth ' \
|
||||
'proxy-server'
|
||||
check_pipeline()
|
||||
self.swift3.check_pipeline(conf)
|
||||
|
||||
pipeline.return_value = 'swift3 swauth proxy-server'
|
||||
check_pipeline()
|
||||
self.swift3.check_pipeline(conf)
|
||||
|
||||
pipeline.return_value = 'swift3 authtoken s3token keystoneauth ' \
|
||||
'proxy-server'
|
||||
self.assertRaises(ValueError, check_pipeline)
|
||||
with self.assertRaises(ValueError):
|
||||
self.swift3.check_pipeline(conf)
|
||||
|
||||
pipeline.return_value = 'swift3 proxy-server'
|
||||
self.assertRaises(ValueError, check_pipeline)
|
||||
with self.assertRaises(ValueError):
|
||||
self.swift3.check_pipeline(conf)
|
||||
|
||||
pipeline.return_value = 'proxy-server'
|
||||
self.assertRaises(ValueError, check_pipeline)
|
||||
with self.assertRaises(ValueError):
|
||||
self.swift3.check_pipeline(conf)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in New Issue