request: add support for virtual-hosted-style access

Change-Id: Iec71b46373a823ae9e89caf8655f56dbe2a26b79
This commit is contained in:
MORITA Kazutaka
2014-07-02 09:30:03 +09:00
parent 1d63a85c4c
commit 10442ccf02
3 changed files with 59 additions and 2 deletions

View File

@@ -37,6 +37,7 @@ from swift3.response import AccessDenied, InvalidArgument, InvalidDigest, \
InternalError, NoSuchBucket, NoSuchKey, PreconditionFailed, InvalidRange, \
MissingContentLength
from swift3.exception import NotS3Request, BadSwiftRequest
from swift3.cfg import CONF
# List of sub-resources that must be maintained as part of the HMAC
# signature string.
@@ -58,11 +59,42 @@ class Request(swob.Request):
swob.Request.__init__(self, env)
self.access_key, self.signature = self._parse_authorization()
self.container_name, self.object_name = self.split_path(0, 2, True)
self.bucket_in_host = self._parse_host()
self.container_name, self.object_name = self._parse_uri()
self._validate_headers()
self.token = base64.urlsafe_b64encode(self._canonical_string())
self.user_id = None
def _parse_host(self):
storage_domain = CONF.get('storage_domain')
if not storage_domain:
return None
if not storage_domain.startswith('.'):
storage_domain = '.' + storage_domain
if 'HTTP_HOST' in self.environ:
given_domain = self.environ['HTTP_HOST']
elif 'SERVER_NAME' in self.environ:
given_domain = self.environ['SERVER_NAME']
else:
return None
port = ''
if ':' in given_domain:
given_domain, port = given_domain.rsplit(':', 1)
if given_domain.endswith(storage_domain):
return given_domain[:-len(storage_domain)]
return None
def _parse_uri(self):
if self.bucket_in_host:
obj = self.environ['PATH_INFO'][1:] or None
return self.bucket_in_host, obj
return self.split_path(0, 2, True)
def _parse_authorization(self):
if 'AWSAccessKeyId' in self.params:
try:
@@ -143,6 +175,12 @@ class Request(swob.Request):
if self.headers['ETag'] == '':
raise SignatureDoesNotMatch()
def _canonical_uri(self):
raw_path_info = self.environ.get('RAW_PATH_INFO', self.path)
if self.bucket_in_host:
raw_path_info = '/' + self.bucket_in_host + raw_path_info
return raw_path_info
def _canonical_string(self):
"""
Canonicalize a request to a token that can be signed.
@@ -165,7 +203,7 @@ class Request(swob.Request):
for k in sorted(key.lower() for key in amz_headers):
buf += "%s:%s\n" % (k, amz_headers[k])
path = self.environ.get('RAW_PATH_INFO', self.path)
path = self._canonical_uri()
if self.query_string:
path += '?' + self.query_string
if '?' in path:

View File

@@ -52,6 +52,7 @@ class Swift3TestCase(unittest.TestCase):
unittest.TestCase.__init__(self, name)
self.conf = {
'log_level': 'debug',
'storage_domain': 'localhost',
}
def setUp(self):

View File

@@ -198,6 +198,24 @@ class TestSwift3Middleware(Swift3TestCase):
status, headers, body = self.call_swift3(req)
self.assertEquals(self._get_error_code(body), 'AccessDenied')
def test_bucket_virtual_hosted_style(self):
req = Request.blank('/',
environ={'HTTP_HOST': 'bucket.localhost:80',
'REQUEST_METHOD': 'HEAD',
'HTTP_AUTHORIZATION':
'AWS test:tester:hmac'})
status, headers, body = self.call_swift3(req)
self.assertEquals(status.split()[0], '200')
def test_object_virtual_hosted_style(self):
req = Request.blank('/object',
environ={'HTTP_HOST': 'bucket.localhost:80',
'REQUEST_METHOD': 'HEAD',
'HTTP_AUTHORIZATION':
'AWS test:tester:hmac'})
status, headers, body = self.call_swift3(req)
self.assertEquals(status.split()[0], '200')
def test_token_generation(self):
req = Request.blank('/bucket/object?uploadId=123456789abcdef'
'&partNumber=1',