From 10442ccf02a4ec20bda4a5633760ec22d2324533 Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Wed, 2 Jul 2014 09:30:03 +0900 Subject: [PATCH] request: add support for virtual-hosted-style access Change-Id: Iec71b46373a823ae9e89caf8655f56dbe2a26b79 --- swift3/request.py | 42 +++++++++++++++++++++++++++-- swift3/test/unit/__init__.py | 1 + swift3/test/unit/test_middleware.py | 18 +++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/swift3/request.py b/swift3/request.py index 66c74b9a..6dc276a9 100644 --- a/swift3/request.py +++ b/swift3/request.py @@ -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: diff --git a/swift3/test/unit/__init__.py b/swift3/test/unit/__init__.py index e21a45b9..2689a520 100644 --- a/swift3/test/unit/__init__.py +++ b/swift3/test/unit/__init__.py @@ -52,6 +52,7 @@ class Swift3TestCase(unittest.TestCase): unittest.TestCase.__init__(self, name) self.conf = { 'log_level': 'debug', + 'storage_domain': 'localhost', } def setUp(self): diff --git a/swift3/test/unit/test_middleware.py b/swift3/test/unit/test_middleware.py index 2b1c83a9..d93b040a 100644 --- a/swift3/test/unit/test_middleware.py +++ b/swift3/test/unit/test_middleware.py @@ -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',