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:
charz 2014-12-04 16:10:02 +08:00 committed by Charles Hsu
parent 58ded99729
commit bd18bf100c
4 changed files with 64 additions and 43 deletions

View File

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

View File

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

View File

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

View File

@ -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__':