diff --git a/swift/proxy/controllers/account.py b/swift/proxy/controllers/account.py index 8751fcb93e..174d87a317 100644 --- a/swift/proxy/controllers/account.py +++ b/swift/proxy/controllers/account.py @@ -21,7 +21,6 @@ from swift.account.utils import account_listing_response from swift.common.middleware.acl import parse_acl, format_acl from swift.common.utils import public from swift.common.constraints import check_metadata -from swift.common import constraints from swift.common.http import HTTP_NOT_FOUND, HTTP_GONE from swift.proxy.controllers.base import Controller, clear_info_cache, \ set_info_cache @@ -53,11 +52,11 @@ class AccountController(Controller): def GETorHEAD(self, req): """Handler for HTTP GET/HEAD requests.""" - if len(self.account_name) > constraints.MAX_ACCOUNT_NAME_LENGTH: + length_limit = self.get_name_length_limit() + if len(self.account_name) > length_limit: resp = HTTPBadRequest(request=req) resp.body = 'Account name length of %d longer than %d' % \ - (len(self.account_name), - constraints.MAX_ACCOUNT_NAME_LENGTH) + (len(self.account_name), length_limit) # Don't cache this. We know the account doesn't exist because # the name is bad; we don't need to cache that because it's # really cheap to recompute. @@ -117,11 +116,11 @@ class AccountController(Controller): error_response = check_metadata(req, 'account') if error_response: return error_response - if len(self.account_name) > constraints.MAX_ACCOUNT_NAME_LENGTH: + length_limit = self.get_name_length_limit() + if len(self.account_name) > length_limit: resp = HTTPBadRequest(request=req) resp.body = 'Account name length of %d longer than %d' % \ - (len(self.account_name), - constraints.MAX_ACCOUNT_NAME_LENGTH) + (len(self.account_name), length_limit) return resp account_partition, accounts = \ self.app.account_ring.get_nodes(self.account_name) @@ -136,11 +135,11 @@ class AccountController(Controller): @public def POST(self, req): """HTTP POST request handler.""" - if len(self.account_name) > constraints.MAX_ACCOUNT_NAME_LENGTH: + length_limit = self.get_name_length_limit() + if len(self.account_name) > length_limit: resp = HTTPBadRequest(request=req) resp.body = 'Account name length of %d longer than %d' % \ - (len(self.account_name), - constraints.MAX_ACCOUNT_NAME_LENGTH) + (len(self.account_name), length_limit) return resp error_response = check_metadata(req, 'account') if error_response: diff --git a/swift/proxy/controllers/base.py b/swift/proxy/controllers/base.py index 576bcf68c7..df0ea71b89 100644 --- a/swift/proxy/controllers/base.py +++ b/swift/proxy/controllers/base.py @@ -46,6 +46,7 @@ from swift.common.utils import Timestamp, config_true_value, \ GreenAsyncPile, quorum_size, parse_content_type, \ document_iters_to_http_response_body from swift.common.bufferedhttp import http_connect +from swift.common import constraints from swift.common.exceptions import ChunkReadTimeout, ChunkWriteTimeout, \ ConnectionTimeout, RangeAlreadyComplete from swift.common.header_key_dict import HeaderKeyDict @@ -1979,3 +1980,17 @@ class Controller(object): resp.headers = headers return resp + + def get_name_length_limit(self): + if self.account_name.startswith(self.app.auto_create_account_prefix): + multiplier = 2 + else: + multiplier = 1 + + if self.server_type == 'Account': + return constraints.MAX_ACCOUNT_NAME_LENGTH * multiplier + elif self.server_type == 'Container': + return constraints.MAX_CONTAINER_NAME_LENGTH * multiplier + else: + raise ValueError( + "server_type can only be 'account' or 'container'") diff --git a/swift/proxy/controllers/container.py b/swift/proxy/controllers/container.py index 0894829a4c..15c67858ea 100644 --- a/swift/proxy/controllers/container.py +++ b/swift/proxy/controllers/container.py @@ -18,7 +18,6 @@ from swift import gettext_ as _ from six.moves.urllib.parse import unquote from swift.common.utils import public, csv_append, Timestamp from swift.common.constraints import check_metadata -from swift.common import constraints from swift.common.http import HTTP_ACCEPTED, is_success from swift.proxy.controllers.base import Controller, delay_denial, \ cors_validation, set_info_cache, clear_info_cache @@ -151,11 +150,11 @@ class ContainerController(Controller): if not req.environ.get('swift_owner'): for key in self.app.swift_owner_headers: req.headers.pop(key, None) - if len(self.container_name) > constraints.MAX_CONTAINER_NAME_LENGTH: + length_limit = self.get_name_length_limit() + if len(self.container_name) > length_limit: resp = HTTPBadRequest(request=req) resp.body = 'Container name length of %d longer than %d' % \ - (len(self.container_name), - constraints.MAX_CONTAINER_NAME_LENGTH) + (len(self.container_name), length_limit) return resp account_partition, accounts, container_count = \ self.account_info(self.account_name, req) diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py index 878ce33cba..bee74c380a 100644 --- a/test/unit/proxy/test_server.py +++ b/test/unit/proxy/test_server.py @@ -7643,10 +7643,9 @@ class TestContainerController(unittest.TestCase): def assert_status_map(self, method, statuses, expected, raise_exc=False, missing_container=False): with save_globals(): - kwargs = {} + kwargs = {'missing_container': missing_container} if raise_exc: kwargs['raise_exc'] = raise_exc - kwargs['missing_container'] = missing_container set_http_connect(*statuses, **kwargs) self.app.memcache.store = {} req = Request.blank('/v1/a/c', headers={'Content-Length': '0', @@ -7954,17 +7953,36 @@ class TestContainerController(unittest.TestCase): missing_container=True) def test_PUT_max_container_name_length(self): - with save_globals(): - limit = constraints.MAX_CONTAINER_NAME_LENGTH - controller = proxy_server.ContainerController(self.app, 'account', - '1' * limit) - self.assert_status_map(controller.PUT, - (200, 201, 201, 201), 201, - missing_container=True) - controller = proxy_server.ContainerController(self.app, 'account', - '2' * (limit + 1)) - self.assert_status_map(controller.PUT, (201, 201, 201), 400, - missing_container=True) + limit = constraints.MAX_CONTAINER_NAME_LENGTH + controller = proxy_server.ContainerController(self.app, 'account', + '1' * limit) + self.assert_status_map(controller.PUT, (200, 201, 201, 201), 201, + missing_container=True) + controller = proxy_server.ContainerController(self.app, 'account', + '2' * (limit + 1)) + self.assert_status_map(controller.PUT, (), 400, + missing_container=True) + + # internal auto-created-accounts get higher limits + limit *= 2 + controller = proxy_server.ContainerController(self.app, '.account', + '3' * limit) + self.assert_status_map(controller.PUT, (200, 201, 201, 201), 201, + missing_container=True) + controller = proxy_server.ContainerController(self.app, '.account', + '4' * (limit + 1)) + self.assert_status_map(controller.PUT, (), 400, + missing_container=True) + + self.app.auto_create_account_prefix = 'acc' + controller = proxy_server.ContainerController(self.app, 'account', + '1' * limit) + self.assert_status_map(controller.PUT, (200, 201, 201, 201), 201, + missing_container=True) + controller = proxy_server.ContainerController(self.app, 'account', + '2' * (limit + 1)) + self.assert_status_map(controller.PUT, (), 400, + missing_container=True) def test_PUT_connect_exceptions(self): with save_globals(): @@ -9093,14 +9111,39 @@ class TestAccountController(unittest.TestCase): test_status_map((204, 500, 404), 503) def test_PUT_max_account_name_length(self): - with save_globals(): - self.app.allow_account_management = True - limit = constraints.MAX_ACCOUNT_NAME_LENGTH - controller = proxy_server.AccountController(self.app, '1' * limit) - self.assert_status_map(controller.PUT, (201, 201, 201), 201) - controller = proxy_server.AccountController( - self.app, '2' * (limit + 1)) - self.assert_status_map(controller.PUT, (201, 201, 201), 400) + self.app.allow_account_management = True + limit = constraints.MAX_ACCOUNT_NAME_LENGTH + controller = proxy_server.AccountController(self.app, '1' * limit) + self.assert_status_map(controller.PUT, (201, 201, 201), 201) + controller = proxy_server.AccountController( + self.app, '2' * (limit + 1)) + self.assert_status_map(controller.PUT, (), 400) + + # internal auto-created accounts get higher limits + limit *= 2 + controller = proxy_server.AccountController( + self.app, '.' + '3' * (limit - 1)) + self.assert_status_map(controller.PUT, (201, 201, 201), 201) + controller = proxy_server.AccountController( + self.app, '.' + '4' * limit) + self.assert_status_map(controller.PUT, (), 400) + + self.app.auto_create_account_prefix = 'FOO_' + limit /= 2 + controller = proxy_server.AccountController( + self.app, '.' + '5' * (limit - 1)) + self.assert_status_map(controller.PUT, (201, 201, 201), 201) + controller = proxy_server.AccountController( + self.app, '.' + '6' * limit) + self.assert_status_map(controller.PUT, (), 400) + + limit *= 2 + controller = proxy_server.AccountController( + self.app, 'FOO_' + '7' * (limit - 4)) + self.assert_status_map(controller.PUT, (201, 201, 201), 201) + controller = proxy_server.AccountController( + self.app, 'FOO_' + '8' * (limit - 3)) + self.assert_status_map(controller.PUT, (), 400) def test_PUT_connect_exceptions(self): with save_globals():