Two small account-quota fixes
First: even if a user has exceeded their account quota, they should be able to make object POST requests. Updating an object's metadata isn't going to make them any more over quota, so should be allowed. Second: don't bother with the reseller_admin check for container or object requests. If I send the header X-Account-Meta-Quota-Bytes: 100 on e.g. an object PUT request, the proxy will (rightly) ignore it. Now account-quotas does too. Change-Id: I970a76349659acdd8229a324bd33bfe7fe7261a4
This commit is contained in:
parent
10bb74a872
commit
d5fcc9aaf3
@ -67,12 +67,22 @@ class AccountQuotaMiddleware(object):
|
||||
return self.app
|
||||
|
||||
try:
|
||||
ver, acc, cont, obj = request.split_path(2, 4, rest_with_last=True)
|
||||
ver, account, container, obj = request.split_path(
|
||||
2, 4, rest_with_last=True)
|
||||
except ValueError:
|
||||
return self.app
|
||||
|
||||
new_quota = request.headers.get('X-Account-Meta-Quota-Bytes')
|
||||
remove_quota = request.headers.get('X-Remove-Account-Meta-Quota-Bytes')
|
||||
if not container:
|
||||
# account request, so we pay attention to the quotas
|
||||
new_quota = request.headers.get(
|
||||
'X-Account-Meta-Quota-Bytes')
|
||||
remove_quota = request.headers.get(
|
||||
'X-Remove-Account-Meta-Quota-Bytes')
|
||||
else:
|
||||
# container or object request; even if the quota headers are set
|
||||
# in the request, they're meaningless
|
||||
new_quota = remove_quota = None
|
||||
|
||||
if remove_quota:
|
||||
new_quota = 0 # X-Remove dominates if both are present
|
||||
|
||||
@ -85,11 +95,14 @@ class AccountQuotaMiddleware(object):
|
||||
if new_quota is not None:
|
||||
return HTTPForbidden()
|
||||
|
||||
if obj and request.method == "POST":
|
||||
return self.app
|
||||
|
||||
copy_from = request.headers.get('X-Copy-From')
|
||||
content_length = (request.content_length or 0)
|
||||
|
||||
if obj and copy_from:
|
||||
path = '/' + ver + '/' + acc + '/' + copy_from.lstrip('/')
|
||||
path = '/' + ver + '/' + account + '/' + copy_from.lstrip('/')
|
||||
object_info = get_object_info(request.environ, self.app, path)
|
||||
if not object_info or not object_info['length']:
|
||||
content_length = 0
|
||||
|
@ -86,6 +86,33 @@ class TestAccountQuota(unittest.TestCase):
|
||||
res = req.get_response(app)
|
||||
self.assertEquals(res.status_int, 200)
|
||||
|
||||
def test_obj_request_ignores_attempt_to_set_quotas(self):
|
||||
# If you try to set X-Account-Meta-* on an object, it's ignored, so
|
||||
# the quota middleware shouldn't complain about it even if we're not a
|
||||
# reseller admin.
|
||||
headers = [('x-account-bytes-used', '1000')]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c/o',
|
||||
headers={'X-Account-Meta-Quota-Bytes': '99999'},
|
||||
environ={'REQUEST_METHOD': 'PUT',
|
||||
'swift.cache': cache})
|
||||
res = req.get_response(app)
|
||||
self.assertEquals(res.status_int, 200)
|
||||
|
||||
def test_container_request_ignores_attempt_to_set_quotas(self):
|
||||
# As with an object, if you try to set X-Account-Meta-* on a
|
||||
# container, it's ignored.
|
||||
headers = [('x-account-bytes-used', '1000')]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c',
|
||||
headers={'X-Account-Meta-Quota-Bytes': '99999'},
|
||||
environ={'REQUEST_METHOD': 'PUT',
|
||||
'swift.cache': cache})
|
||||
res = req.get_response(app)
|
||||
self.assertEquals(res.status_int, 200)
|
||||
|
||||
def test_exceed_bytes_quota(self):
|
||||
headers = [('x-account-bytes-used', '1000'),
|
||||
('x-account-meta-quota-bytes', '0')]
|
||||
@ -97,6 +124,18 @@ class TestAccountQuota(unittest.TestCase):
|
||||
res = req.get_response(app)
|
||||
self.assertEquals(res.status_int, 413)
|
||||
|
||||
def test_over_quota_obj_post_still_works(self):
|
||||
headers = [('x-account-bytes-used', '1001'),
|
||||
('x-account-meta-quota-bytes', '1000')]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c/o',
|
||||
environ={'REQUEST_METHOD': 'POST',
|
||||
'HTTP_X_OBJECT_META_BERT': 'ernie',
|
||||
'swift.cache': cache})
|
||||
res = req.get_response(app)
|
||||
self.assertEquals(res.status_int, 200)
|
||||
|
||||
def test_exceed_bytes_quota_copy_from(self):
|
||||
headers = [('x-account-bytes-used', '500'),
|
||||
('x-account-meta-quota-bytes', '1000'),
|
||||
@ -139,7 +178,7 @@ class TestAccountQuota(unittest.TestCase):
|
||||
('x-account-meta-quota-bytes', '0')]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c/o',
|
||||
req = Request.blank('/v1/a',
|
||||
environ={'REQUEST_METHOD': 'PUT',
|
||||
'swift.cache': cache,
|
||||
'reseller_request': True})
|
||||
@ -194,7 +233,7 @@ class TestAccountQuota(unittest.TestCase):
|
||||
headers = [('x-account-bytes-used', '0'), ]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c',
|
||||
req = Request.blank('/v1/a',
|
||||
environ={'REQUEST_METHOD': 'POST',
|
||||
'swift.cache': cache,
|
||||
'HTTP_X_ACCOUNT_META_QUOTA_BYTES': 'abc',
|
||||
@ -206,7 +245,7 @@ class TestAccountQuota(unittest.TestCase):
|
||||
headers = [('x-account-bytes-used', '0'), ]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c',
|
||||
req = Request.blank('/v1/a',
|
||||
environ={'REQUEST_METHOD': 'POST',
|
||||
'swift.cache': cache,
|
||||
'HTTP_X_ACCOUNT_META_QUOTA_BYTES': '100'})
|
||||
@ -217,7 +256,7 @@ class TestAccountQuota(unittest.TestCase):
|
||||
headers = [('x-account-bytes-used', '0'), ]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c',
|
||||
req = Request.blank('/v1/a',
|
||||
environ={'REQUEST_METHOD': 'POST',
|
||||
'swift.cache': cache,
|
||||
'HTTP_X_ACCOUNT_META_QUOTA_BYTES': '100',
|
||||
@ -229,7 +268,7 @@ class TestAccountQuota(unittest.TestCase):
|
||||
headers = [('x-account-bytes-used', '0'), ]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c',
|
||||
req = Request.blank('/v1/a',
|
||||
environ={'REQUEST_METHOD': 'POST',
|
||||
'swift.cache': cache,
|
||||
'HTTP_X_ACCOUNT_META_QUOTA_BYTES': ''})
|
||||
@ -240,7 +279,7 @@ class TestAccountQuota(unittest.TestCase):
|
||||
headers = [('x-account-bytes-used', '0'), ]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c', environ={
|
||||
req = Request.blank('/v1/a', environ={
|
||||
'REQUEST_METHOD': 'POST',
|
||||
'swift.cache': cache,
|
||||
'HTTP_X_REMOVE_ACCOUNT_META_QUOTA_BYTES': 'True'})
|
||||
@ -250,7 +289,7 @@ class TestAccountQuota(unittest.TestCase):
|
||||
def test_delete_quotas_reseller(self):
|
||||
headers = [('x-account-bytes-used', '0'), ]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
req = Request.blank('/v1/a/c',
|
||||
req = Request.blank('/v1/a',
|
||||
environ={'REQUEST_METHOD': 'POST',
|
||||
'HTTP_X_ACCOUNT_META_QUOTA_BYTES': '',
|
||||
'reseller_request': True})
|
||||
@ -261,7 +300,7 @@ class TestAccountQuota(unittest.TestCase):
|
||||
headers = [('x-account-bytes-used', '0'), ]
|
||||
app = account_quotas.AccountQuotaMiddleware(FakeApp(headers))
|
||||
cache = FakeCache(None)
|
||||
req = Request.blank('/v1/a/c', environ={
|
||||
req = Request.blank('/v1/a', environ={
|
||||
'REQUEST_METHOD': 'POST',
|
||||
'swift.cache': cache,
|
||||
'HTTP_X_REMOVE_ACCOUNT_META_QUOTA_BYTES': 'True',
|
||||
@ -277,7 +316,7 @@ class TestAccountQuota(unittest.TestCase):
|
||||
environ={'REQUEST_METHOD': 'PUT',
|
||||
'swift.cache': cache})
|
||||
res = req.get_response(app)
|
||||
#Response code of 200 because authentication itself is not done here
|
||||
# Response code of 200 because authentication itself is not done here
|
||||
self.assertEquals(res.status_int, 200)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user