re-use headers_to_container_info on container GET
Currently, a container's info can be cached without cors data intact after a container GET. I made headers_to_container_info a function instead of a method and I crammed all container metadata into container_info. This is so e.g. staticweb can eventually re-use the same container info cache. Fix pep8 in swift/proxy/controllers/container.py Change-Id: I4bbb042dde79afac48395efc38bd80f0ff240e1f
This commit is contained in:
parent
c7948ec5d9
commit
af031138be
@ -94,6 +94,33 @@ def get_container_memcache_key(account, container):
|
||||
return 'container/%s/%s' % (account, container)
|
||||
|
||||
|
||||
def headers_to_container_info(headers, status_int=HTTP_OK):
|
||||
"""
|
||||
Construct a cacheable dict of container info based on response headers.
|
||||
"""
|
||||
headers = dict(headers)
|
||||
return {
|
||||
'status': status_int,
|
||||
'read_acl': headers.get('x-container-read'),
|
||||
'write_acl': headers.get('x-container-write'),
|
||||
'sync_key': headers.get('x-container-sync-key'),
|
||||
'count': headers.get('x-container-object-count'),
|
||||
'bytes': headers.get('x-container-bytes-used'),
|
||||
'versions': headers.get('x-versions-location'),
|
||||
'cors': {
|
||||
'allow_origin': headers.get(
|
||||
'x-container-meta-access-control-allow-origin'),
|
||||
'allow_headers': headers.get(
|
||||
'x-container-meta-access-control-allow-headers'),
|
||||
'max_age': headers.get(
|
||||
'x-container-meta-access-control-max-age')
|
||||
},
|
||||
'meta': dict((key.lower()[17:], value)
|
||||
for key, value in headers.iteritems()
|
||||
if key.lower().startswith('x-container-meta-'))
|
||||
}
|
||||
|
||||
|
||||
class Controller(object):
|
||||
"""Base WSGI controller class for the proxy"""
|
||||
server_type = 'Base'
|
||||
@ -278,25 +305,6 @@ class Controller(object):
|
||||
return partition, nodes, container_count
|
||||
return None, None, None
|
||||
|
||||
def headers_to_container_info(self, headers):
|
||||
headers = dict(headers)
|
||||
return {
|
||||
'read_acl': headers.get('x-container-read'),
|
||||
'write_acl': headers.get('x-container-write'),
|
||||
'sync_key': headers.get('x-container-sync-key'),
|
||||
'count': headers.get('x-container-object-count'),
|
||||
'bytes': headers.get('x-container-bytes-used'),
|
||||
'versions': headers.get('x-versions-location'),
|
||||
'cors': {
|
||||
'allow_origin': headers.get(
|
||||
'x-container-meta-access-control-allow-origin'),
|
||||
'allow_headers': headers.get(
|
||||
'x-container-meta-access-control-allow-headers'),
|
||||
'max_age': headers.get(
|
||||
'x-container-meta-access-control-max-age')
|
||||
}
|
||||
}
|
||||
|
||||
def container_info(self, account, container, account_autocreate=False):
|
||||
"""
|
||||
Get container information and thusly verify container existance.
|
||||
@ -344,8 +352,7 @@ class Controller(object):
|
||||
body = resp.read()
|
||||
if is_success(resp.status):
|
||||
container_info.update(
|
||||
self.headers_to_container_info(resp.getheaders()))
|
||||
container_info['status'] = HTTP_OK
|
||||
headers_to_container_info(resp.getheaders()))
|
||||
break
|
||||
elif resp.status == HTTP_NOT_FOUND:
|
||||
container_info['status'] = HTTP_NOT_FOUND
|
||||
|
@ -32,7 +32,7 @@ from swift.common.utils import normalize_timestamp, public
|
||||
from swift.common.constraints import check_metadata, MAX_CONTAINER_NAME_LENGTH
|
||||
from swift.common.http import HTTP_ACCEPTED
|
||||
from swift.proxy.controllers.base import Controller, delay_denial, \
|
||||
get_container_memcache_key
|
||||
get_container_memcache_key, headers_to_container_info
|
||||
from swift.common.swob import HTTPBadRequest, HTTPForbidden, \
|
||||
HTTPNotFound
|
||||
|
||||
@ -68,24 +68,18 @@ class ContainerController(Controller):
|
||||
if not self.account_info(self.account_name)[1]:
|
||||
return HTTPNotFound(request=req)
|
||||
part, nodes = self.app.container_ring.get_nodes(
|
||||
self.account_name, self.container_name)
|
||||
self.account_name, self.container_name)
|
||||
shuffle(nodes)
|
||||
resp = self.GETorHEAD_base(req, _('Container'), part, nodes,
|
||||
req.path_info, len(nodes))
|
||||
|
||||
resp = self.GETorHEAD_base(
|
||||
req, _('Container'), part, nodes, req.path_info, len(nodes))
|
||||
if self.app.memcache:
|
||||
# set the memcache container size for ratelimiting
|
||||
cache_key = get_container_memcache_key(self.account_name,
|
||||
self.container_name)
|
||||
self.app.memcache.set(cache_key,
|
||||
{'status': resp.status_int,
|
||||
'read_acl': resp.headers.get('x-container-read'),
|
||||
'write_acl': resp.headers.get('x-container-write'),
|
||||
'sync_key': resp.headers.get('x-container-sync-key'),
|
||||
'count': resp.headers.get('x-container-object-count'),
|
||||
'bytes': resp.headers.get('x-container-bytes-used'),
|
||||
'versions': resp.headers.get('x-versions-location')},
|
||||
timeout=self.app.recheck_container_existence)
|
||||
self.app.memcache.set(
|
||||
cache_key,
|
||||
headers_to_container_info(resp.headers, resp.status_int),
|
||||
timeout=self.app.recheck_container_existence)
|
||||
|
||||
if 'swift.authorize' in req.environ:
|
||||
req.acl = resp.headers.get('x-container-read')
|
||||
@ -151,8 +145,9 @@ class ContainerController(Controller):
|
||||
cache_key = get_container_memcache_key(self.account_name,
|
||||
self.container_name)
|
||||
self.app.memcache.delete(cache_key)
|
||||
resp = self.make_requests(req, self.app.container_ring,
|
||||
container_partition, 'PUT', req.path_info, headers)
|
||||
resp = self.make_requests(
|
||||
req, self.app.container_ring,
|
||||
container_partition, 'PUT', req.path_info, headers)
|
||||
return resp
|
||||
|
||||
@public
|
||||
@ -176,9 +171,9 @@ class ContainerController(Controller):
|
||||
if self.app.memcache:
|
||||
self.app.memcache.delete(get_container_memcache_key(
|
||||
self.account_name, self.container_name))
|
||||
resp = self.make_requests(req, self.app.container_ring,
|
||||
container_partition, 'POST', req.path_info,
|
||||
[headers] * len(containers))
|
||||
resp = self.make_requests(
|
||||
req, self.app.container_ring, container_partition, 'POST',
|
||||
req.path_info, [headers] * len(containers))
|
||||
return resp
|
||||
|
||||
@public
|
||||
@ -202,8 +197,9 @@ class ContainerController(Controller):
|
||||
cache_key = get_container_memcache_key(self.account_name,
|
||||
self.container_name)
|
||||
self.app.memcache.delete(cache_key)
|
||||
resp = self.make_requests(req, self.app.container_ring,
|
||||
container_partition, 'DELETE', req.path_info, headers)
|
||||
resp = self.make_requests(
|
||||
req, self.app.container_ring, container_partition, 'DELETE',
|
||||
req.path_info, headers)
|
||||
# Indicates no server had the container
|
||||
if resp.status_int == HTTP_ACCEPTED:
|
||||
return HTTPNotFound(request=req)
|
||||
|
0
test/unit/proxy/controllers/__init__.py
Normal file
0
test/unit/proxy/controllers/__init__.py
Normal file
50
test/unit/proxy/controllers/test_base.py
Normal file
50
test/unit/proxy/controllers/test_base.py
Normal file
@ -0,0 +1,50 @@
|
||||
# Copyright (c) 2010-2012 OpenStack, LLC.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
from swift.proxy.controllers.base import headers_to_container_info
|
||||
|
||||
|
||||
class TestFuncs(unittest.TestCase):
|
||||
def test_headers_to_container_info_missing(self):
|
||||
resp = headers_to_container_info({}, 404)
|
||||
self.assertEquals(resp['status'], 404)
|
||||
self.assertEquals(resp['read_acl'], None)
|
||||
self.assertEquals(resp['write_acl'], None)
|
||||
|
||||
def test_headers_to_container_info_meta(self):
|
||||
headers = {'X-Container-Meta-Whatevs': 14,
|
||||
'x-container-meta-somethingelse': 0}
|
||||
resp = headers_to_container_info(headers.items(), 200)
|
||||
self.assertEquals(len(resp['meta']), 2)
|
||||
self.assertEquals(resp['meta']['whatevs'], 14)
|
||||
self.assertEquals(resp['meta']['somethingelse'], 0)
|
||||
|
||||
def test_headers_to_container_info_values(self):
|
||||
headers = {
|
||||
'x-container-read': 'readvalue',
|
||||
'x-container-write': 'writevalue',
|
||||
'x-container-sync-key': 'keyvalue',
|
||||
'x-container-meta-access-control-allow-origin': 'here',
|
||||
}
|
||||
resp = headers_to_container_info(headers.items(), 200)
|
||||
self.assertEquals(resp['read_acl'], 'readvalue')
|
||||
self.assertEquals(resp['write_acl'], 'writevalue')
|
||||
self.assertEquals(resp['cors']['allow_origin'], 'here')
|
||||
|
||||
headers['x-unused-header'] = 'blahblahblah'
|
||||
self.assertEquals(
|
||||
resp,
|
||||
headers_to_container_info(headers.items(), 200))
|
Loading…
Reference in New Issue
Block a user