diff --git a/swift/account/server.py b/swift/account/server.py index 848c91780b..e53929fd85 100644 --- a/swift/account/server.py +++ b/swift/account/server.py @@ -25,7 +25,8 @@ import swift.common.db from swift.account.utils import account_listing_response, \ account_listing_content_type from swift.common.db import AccountBroker, DatabaseConnectionError -from swift.common.utils import get_logger, get_param, hash_path, public, \ +from swift.common.request_helpers import get_param +from swift.common.utils import get_logger, hash_path, public, \ normalize_timestamp, storage_directory, config_true_value, \ validate_device_partition, json, timing_stats, replication from swift.common.constraints import ACCOUNT_LISTING_LIMIT, \ @@ -35,7 +36,7 @@ from swift.common.swob import HTTPAccepted, HTTPBadRequest, \ HTTPCreated, HTTPForbidden, HTTPInternalServerError, \ HTTPMethodNotAllowed, HTTPNoContent, HTTPNotFound, \ HTTPPreconditionFailed, HTTPConflict, Request, \ - HTTPInsufficientStorage, HTTPNotAcceptable + HTTPInsufficientStorage, HTTPNotAcceptable, HTTPException DATADIR = 'accounts' @@ -176,11 +177,7 @@ class AccountController(object): except ValueError, err: return HTTPBadRequest(body=str(err), content_type='text/plain', request=req) - try: - query_format = get_param(req, 'format') - except UnicodeDecodeError: - return HTTPBadRequest(body='parameters not utf8', - content_type='text/plain', request=req) + query_format = get_param(req, 'format') if query_format: req.accept = FORMAT2CONTENT_TYPE.get( query_format.lower(), FORMAT2CONTENT_TYPE['plain']) @@ -218,25 +215,21 @@ class AccountController(object): except ValueError, err: return HTTPBadRequest(body=str(err), content_type='text/plain', request=req) - try: - prefix = get_param(req, 'prefix') - delimiter = get_param(req, 'delimiter') - if delimiter and (len(delimiter) > 1 or ord(delimiter) > 254): - # delimiters can be made more flexible later - return HTTPPreconditionFailed(body='Bad delimiter') - limit = ACCOUNT_LISTING_LIMIT - given_limit = get_param(req, 'limit') - if given_limit and given_limit.isdigit(): - limit = int(given_limit) - if limit > ACCOUNT_LISTING_LIMIT: - return HTTPPreconditionFailed(request=req, - body='Maximum limit is %d' % - ACCOUNT_LISTING_LIMIT) - marker = get_param(req, 'marker', '') - end_marker = get_param(req, 'end_marker') - except UnicodeDecodeError, err: - return HTTPBadRequest(body='parameters not utf8', - content_type='text/plain', request=req) + prefix = get_param(req, 'prefix') + delimiter = get_param(req, 'delimiter') + if delimiter and (len(delimiter) > 1 or ord(delimiter) > 254): + # delimiters can be made more flexible later + return HTTPPreconditionFailed(body='Bad delimiter') + limit = ACCOUNT_LISTING_LIMIT + given_limit = get_param(req, 'limit') + if given_limit and given_limit.isdigit(): + limit = int(given_limit) + if limit > ACCOUNT_LISTING_LIMIT: + return HTTPPreconditionFailed(request=req, + body='Maximum limit is %d' % + ACCOUNT_LISTING_LIMIT) + marker = get_param(req, 'marker', '') + end_marker = get_param(req, 'end_marker') out_content_type, error = account_listing_content_type(req) if error: return error @@ -326,6 +319,8 @@ class AccountController(object): res = HTTPMethodNotAllowed() else: res = method(req) + except HTTPException as error_response: + res = error_response except (Exception, Timeout): self.logger.exception(_('ERROR __call__ error with %(method)s' ' %(path)s '), diff --git a/swift/account/utils.py b/swift/account/utils.py index 6b18850f78..e4c3b053b8 100644 --- a/swift/account/utils.py +++ b/swift/account/utils.py @@ -17,9 +17,9 @@ import time from xml.sax import saxutils from swift.common.constraints import FORMAT2CONTENT_TYPE -from swift.common.swob import HTTPOk, HTTPNoContent, HTTPNotAcceptable, \ - HTTPBadRequest -from swift.common.utils import get_param, json, normalize_timestamp +from swift.common.swob import HTTPOk, HTTPNoContent, HTTPNotAcceptable +from swift.common.request_helpers import get_param +from swift.common.utils import json, normalize_timestamp class FakeAccountBroker(object): @@ -50,11 +50,7 @@ def account_listing_content_type(req): Returns a 2-tuple: (content_type, error). Only one of them will be set; the other will be None. """ - try: - query_format = get_param(req, 'format') - except UnicodeDecodeError: - return (None, HTTPBadRequest(body='parameters not utf8', - content_type='text/plain', request=req)) + query_format = get_param(req, 'format') if query_format: req.accept = FORMAT2CONTENT_TYPE.get(query_format.lower(), FORMAT2CONTENT_TYPE['plain']) diff --git a/swift/common/request_helpers.py b/swift/common/request_helpers.py new file mode 100644 index 0000000000..5dd8b940fa --- /dev/null +++ b/swift/common/request_helpers.py @@ -0,0 +1,47 @@ +# Copyright (c) 2010-2013 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. + +""" +Miscellaneous utility functions for use in generating responses. + +Why not swift.common.utils, you ask? Because this way we can import things +from swob in here without creating circular imports. +""" + + +from swift.common.swob import HTTPBadRequest + + +def get_param(req, name, default=None): + """ + Get parameters from an HTTP request ensuring proper handling UTF-8 + encoding. + + :param req: request object + :param name: parameter name + :param default: result to return if the parameter is not found + :returns: HTTP request parameter value + (as UTF-8 encoded str, not unicode object) + :raises: HTTPBadRequest if param not valid UTF-8 byte sequence + """ + value = req.params.get(name, default) + if value and not isinstance(value, unicode): + try: + value.decode('utf8') # Ensure UTF8ness + except UnicodeDecodeError: + raise HTTPBadRequest( + request=req, content_type='text/plain', + body='"%s" parameter not valid UTF-8' % name) + return value diff --git a/swift/common/utils.py b/swift/common/utils.py index 5970165477..78f4fad8df 100644 --- a/swift/common/utils.py +++ b/swift/common/utils.py @@ -170,22 +170,6 @@ def load_libc_function(func_name, log_error=True): return noop_libc_function -def get_param(req, name, default=None): - """ - Get parameters from an HTTP request ensuring proper handling UTF-8 - encoding. - - :param req: request object - :param name: parameter name - :param default: result to return if the parameter is not found - :returns: HTTP request parameter value - """ - value = req.params.get(name, default) - if value and not isinstance(value, unicode): - value.decode('utf8') # Ensure UTF8ness - return value - - def generate_trans_id(trans_id_suffix): return 'tx%s-%010x%s' % ( uuid.uuid4().hex[:21], time.time(), trans_id_suffix) diff --git a/swift/container/server.py b/swift/container/server.py index 660ef947de..51fef685a1 100644 --- a/swift/container/server.py +++ b/swift/container/server.py @@ -25,7 +25,8 @@ from eventlet import Timeout import swift.common.db from swift.common.db import ContainerBroker -from swift.common.utils import get_logger, get_param, hash_path, public, \ +from swift.common.request_helpers import get_param +from swift.common.utils import get_logger, hash_path, public, \ normalize_timestamp, storage_directory, validate_sync_to, \ config_true_value, validate_device_partition, json, timing_stats, \ replication @@ -38,7 +39,7 @@ from swift.common.http import HTTP_NOT_FOUND, is_success from swift.common.swob import HTTPAccepted, HTTPBadRequest, HTTPConflict, \ HTTPCreated, HTTPInternalServerError, HTTPNoContent, HTTPNotFound, \ HTTPPreconditionFailed, HTTPMethodNotAllowed, Request, Response, \ - HTTPInsufficientStorage, HTTPNotAcceptable, HeaderKeyDict + HTTPInsufficientStorage, HTTPNotAcceptable, HTTPException, HeaderKeyDict DATADIR = 'containers' @@ -298,11 +299,7 @@ class ContainerController(object): except ValueError, err: return HTTPBadRequest(body=str(err), content_type='text/plain', request=req) - try: - query_format = get_param(req, 'format') - except UnicodeDecodeError: - return HTTPBadRequest(body='parameters not utf8', - content_type='text/plain', request=req) + query_format = get_param(req, 'format') if query_format: req.accept = FORMAT2CONTENT_TYPE.get( query_format.lower(), FORMAT2CONTENT_TYPE['plain']) @@ -362,27 +359,23 @@ class ContainerController(object): except ValueError, err: return HTTPBadRequest(body=str(err), content_type='text/plain', request=req) - try: - path = get_param(req, 'path') - prefix = get_param(req, 'prefix') - delimiter = get_param(req, 'delimiter') - if delimiter and (len(delimiter) > 1 or ord(delimiter) > 254): - # delimiters can be made more flexible later - return HTTPPreconditionFailed(body='Bad delimiter') - marker = get_param(req, 'marker', '') - end_marker = get_param(req, 'end_marker') - limit = CONTAINER_LISTING_LIMIT - given_limit = get_param(req, 'limit') - if given_limit and given_limit.isdigit(): - limit = int(given_limit) - if limit > CONTAINER_LISTING_LIMIT: - return HTTPPreconditionFailed( - request=req, - body='Maximum limit is %d' % CONTAINER_LISTING_LIMIT) - query_format = get_param(req, 'format') - except UnicodeDecodeError, err: - return HTTPBadRequest(body='parameters not utf8', - content_type='text/plain', request=req) + path = get_param(req, 'path') + prefix = get_param(req, 'prefix') + delimiter = get_param(req, 'delimiter') + if delimiter and (len(delimiter) > 1 or ord(delimiter) > 254): + # delimiters can be made more flexible later + return HTTPPreconditionFailed(body='Bad delimiter') + marker = get_param(req, 'marker', '') + end_marker = get_param(req, 'end_marker') + limit = CONTAINER_LISTING_LIMIT + given_limit = get_param(req, 'limit') + if given_limit and given_limit.isdigit(): + limit = int(given_limit) + if limit > CONTAINER_LISTING_LIMIT: + return HTTPPreconditionFailed( + request=req, + body='Maximum limit is %d' % CONTAINER_LISTING_LIMIT) + query_format = get_param(req, 'format') if query_format: req.accept = FORMAT2CONTENT_TYPE.get(query_format.lower(), FORMAT2CONTENT_TYPE['plain']) @@ -548,6 +541,8 @@ class ContainerController(object): res = HTTPMethodNotAllowed() else: res = method(req) + except HTTPException as error_response: + res = error_response except (Exception, Timeout): self.logger.exception(_( 'ERROR __call__ error with %(method)s %(path)s '), diff --git a/swift/obj/server.py b/swift/obj/server.py index 47a79abc47..37511bc090 100644 --- a/swift/obj/server.py +++ b/swift/obj/server.py @@ -43,7 +43,7 @@ from swift.common.swob import HTTPAccepted, HTTPBadRequest, HTTPCreated, \ HTTPInternalServerError, HTTPNoContent, HTTPNotFound, HTTPNotModified, \ HTTPPreconditionFailed, HTTPRequestTimeout, HTTPUnprocessableEntity, \ HTTPClientDisconnect, HTTPMethodNotAllowed, Request, Response, UTC, \ - HTTPInsufficientStorage, HTTPForbidden, HeaderKeyDict + HTTPInsufficientStorage, HTTPForbidden, HTTPException, HeaderKeyDict from swift.obj.diskfile import DiskFile @@ -276,17 +276,27 @@ class ObjectController(object): '%s-%s/%s/%s' % (delete_at, account, container, obj), host, partition, contdevice, headers_out, objdevice) + def _parse_path(self, request, minsegs=5, maxsegs=5): + """ + Utility function to split and validate the request path. + + :returns: result of split_path if everything's okay + :raises: HTTPBadRequest if something's not okay + """ + try: + segs = split_path(unquote(request.path), minsegs, maxsegs, True) + validate_device_partition(segs[0], segs[1]) + return segs + except ValueError as err: + raise HTTPBadRequest(body=str(err), request=request, + content_type='text/plain') + @public @timing_stats() def POST(self, request): """Handle HTTP POST requests for the Swift Object Server.""" - try: - device, partition, account, container, obj = \ - split_path(unquote(request.path), 5, 5, True) - validate_device_partition(device, partition) - except ValueError, err: - return HTTPBadRequest(body=str(err), request=request, - content_type='text/plain') + device, partition, account, container, obj = self._parse_path(request) + if 'x-timestamp' not in request.headers or \ not check_float(request.headers['x-timestamp']): return HTTPBadRequest(body='Missing timestamp', request=request, @@ -329,13 +339,8 @@ class ObjectController(object): @timing_stats() def PUT(self, request): """Handle HTTP PUT requests for the Swift Object Server.""" - try: - device, partition, account, container, obj = \ - split_path(unquote(request.path), 5, 5, True) - validate_device_partition(device, partition) - except ValueError, err: - return HTTPBadRequest(body=str(err), request=request, - content_type='text/plain') + device, partition, account, container, obj = self._parse_path(request) + if 'x-timestamp' not in request.headers or \ not check_float(request.headers['x-timestamp']): return HTTPBadRequest(body='Missing timestamp', request=request, @@ -428,13 +433,8 @@ class ObjectController(object): @timing_stats() def GET(self, request): """Handle HTTP GET requests for the Swift Object Server.""" - try: - device, partition, account, container, obj = \ - split_path(unquote(request.path), 5, 5, True) - validate_device_partition(device, partition) - except ValueError, err: - return HTTPBadRequest(body=str(err), request=request, - content_type='text/plain') + device, partition, account, container, obj = self._parse_path(request) + try: disk_file = self._diskfile(device, partition, account, container, obj, keep_data_fp=True, iter_hook=sleep) @@ -507,15 +507,8 @@ class ObjectController(object): @timing_stats(sample_rate=0.8) def HEAD(self, request): """Handle HTTP HEAD requests for the Swift Object Server.""" - try: - device, partition, account, container, obj = \ - split_path(unquote(request.path), 5, 5, True) - validate_device_partition(device, partition) - except ValueError, err: - resp = HTTPBadRequest(request=request) - resp.content_type = 'text/plain' - resp.body = str(err) - return resp + device, partition, account, container, obj = self._parse_path(request) + try: disk_file = self._diskfile(device, partition, account, container, obj) @@ -601,13 +594,8 @@ class ObjectController(object): Handle REPLICATE requests for the Swift Object Server. This is used by the object replicator to get hashes for directories. """ - try: - device, partition, suffix = split_path( - unquote(request.path), 2, 3, True) - validate_device_partition(device, partition) - except ValueError, e: - return HTTPBadRequest(body=str(e), request=request, - content_type='text/plain') + device, partition, suffix = self._parse_path(request, 2, 3) + if self.mount_check and not check_mount(self.devices, device): return HTTPInsufficientStorage(drive=device, request=request) path = os.path.join(self.devices, device, DATADIR, partition) @@ -642,6 +630,8 @@ class ObjectController(object): res = method(req) except DiskFileCollision: res = HTTPForbidden(request=req) + except HTTPException as error_response: + res = error_response except (Exception, Timeout): self.logger.exception(_( 'ERROR __call__ error with %(method)s' diff --git a/test/unit/account/test_server.py b/test/unit/account/test_server.py index 516cbce023..8f2afb22f3 100644 --- a/test/unit/account/test_server.py +++ b/test/unit/account/test_server.py @@ -145,9 +145,9 @@ class TestAccountController(unittest.TestCase): self.controller.PUT(req) req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE', 'HTTP_X_TIMESTAMP': '1'}) - resp = self.controller.DELETE(req) + resp = req.get_response(self.controller) req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'}) - resp = self.controller.HEAD(req) + resp = req.get_response(self.controller) self.assertEquals(resp.status_int, 404) self.assertEquals(resp.headers['X-Account-Status'], 'Deleted') @@ -231,7 +231,7 @@ class TestAccountController(unittest.TestCase): format = '%D1%BD%8A9' # invalid UTF-8; should be %E1%BD%8A9 (E -> D) req = Request.blank('/sda1/p/a?format=' + format, environ={'REQUEST_METHOD': 'HEAD'}) - resp = self.controller.HEAD(req) + resp = req.get_response(self.controller) self.assertEquals(resp.status_int, 400) def test_PUT_not_found(self): @@ -1251,7 +1251,7 @@ class TestAccountController(unittest.TestCase): for format in ('xml', 'json'): req = Request.blank('/sda1/p/a?format=%s' % format, environ={'REQUEST_METHOD': 'GET'}) - resp = self.controller.GET(req) + resp = req.get_response(self.controller) self.assertEquals(resp.status_int, 200) def test_params_utf8(self): @@ -1260,7 +1260,7 @@ class TestAccountController(unittest.TestCase): 'format'): req = Request.blank('/sda1/p/a?%s=\xce' % param, environ={'REQUEST_METHOD': 'GET'}) - resp = self.controller.GET(req) + resp = req.get_response(self.controller) self.assertEquals(resp.status_int, 400, "%d on param %s" % (resp.status_int, param)) # Good UTF8 sequence for delimiter, too long (1 byte delimiters only) diff --git a/test/unit/container/test_server.py b/test/unit/container/test_server.py index ab88d8cac5..e70c70e246 100644 --- a/test/unit/container/test_server.py +++ b/test/unit/container/test_server.py @@ -147,7 +147,7 @@ class TestContainerController(unittest.TestCase): format = '%D1%BD%8A9' # invalid UTF-8; should be %E1%BD%8A9 (E -> D) req = Request.blank('/sda1/p/a/c?format=' + format, environ={'REQUEST_METHOD': 'HEAD'}) - resp = self.controller.HEAD(req) + resp = req.get_response(self.controller) self.assertEquals(resp.status_int, 400) def test_PUT(self): @@ -1245,7 +1245,7 @@ class TestContainerController(unittest.TestCase): 'end_marker', 'format'): req = Request.blank('/sda1/p/a/c?%s=\xce' % param, environ={'REQUEST_METHOD': 'GET'}) - resp = self.controller.GET(req) + resp = req.get_response(self.controller) self.assertEquals(resp.status_int, 400, "%d on param %s" % (resp.status_int, param)) # Good UTF8 sequence for delimiter, too long (1 byte delimiters only) diff --git a/test/unit/obj/test_server.py b/test/unit/obj/test_server.py index 77985de46b..75871e6059 100755 --- a/test/unit/obj/test_server.py +++ b/test/unit/obj/test_server.py @@ -231,7 +231,7 @@ class TestObjectController(unittest.TestCase): 'X-Object-Meta-1': 'One', 'X-Object-Meta-2': 'Two', 'Content-Type': 'text/plain'}) - resp = self.object_controller.POST(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 404) def test_POST_invalid_path(self): @@ -241,7 +241,7 @@ class TestObjectController(unittest.TestCase): 'X-Object-Meta-1': 'One', 'X-Object-Meta-2': 'Two', 'Content-Type': 'text/plain'}) - resp = self.object_controller.POST(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 400) def test_POST_container_connection(self): @@ -341,13 +341,13 @@ class TestObjectController(unittest.TestCase): def test_PUT_invalid_path(self): req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}) - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 400) def test_PUT_no_timestamp(self): req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT', 'CONTENT_LENGTH': '0'}) - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 400) def test_PUT_no_content_type(self): @@ -355,7 +355,7 @@ class TestObjectController(unittest.TestCase): headers={'X-Timestamp': normalize_timestamp(time()), 'Content-Length': '6'}) req.body = 'VERIFY' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 400) def test_PUT_invalid_content_type(self): @@ -364,7 +364,7 @@ class TestObjectController(unittest.TestCase): 'Content-Length': '6', 'Content-Type': '\xff\xff'}) req.body = 'VERIFY' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 400) self.assert_('Content-Type' in resp.body) @@ -374,7 +374,7 @@ class TestObjectController(unittest.TestCase): 'Content-Type': 'application/octet-stream'}) req.body = 'VERIFY' del req.headers['Content-Length'] - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 411) def test_PUT_zero_content_length(self): @@ -383,7 +383,7 @@ class TestObjectController(unittest.TestCase): 'Content-Type': 'application/octet-stream'}) req.body = '' self.assertEquals(req.headers['Content-Length'], '0') - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) def test_PUT_common(self): @@ -393,7 +393,7 @@ class TestObjectController(unittest.TestCase): 'Content-Length': '6', 'Content-Type': 'application/octet-stream'}) req.body = 'VERIFY' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) objfile = os.path.join(self.testdir, 'sda1', storage_directory(object_server.DATADIR, 'p', @@ -414,7 +414,7 @@ class TestObjectController(unittest.TestCase): 'Content-Length': '6', 'Content-Type': 'application/octet-stream'}) req.body = 'VERIFY' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) sleep(.00001) timestamp = normalize_timestamp(time()) @@ -423,7 +423,7 @@ class TestObjectController(unittest.TestCase): 'Content-Type': 'text/plain', 'Content-Encoding': 'gzip'}) req.body = 'VERIFY TWO' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) objfile = os.path.join(self.testdir, 'sda1', storage_directory(object_server.DATADIR, 'p', @@ -444,7 +444,7 @@ class TestObjectController(unittest.TestCase): headers={'X-Timestamp': normalize_timestamp(time()), 'Content-Type': 'text/plain'}) req.body = 'test' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) def test_PUT_invalid_etag(self): @@ -453,7 +453,7 @@ class TestObjectController(unittest.TestCase): 'Content-Type': 'text/plain', 'ETag': 'invalid'}) req.body = 'test' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 422) def test_PUT_user_metadata(self): @@ -465,7 +465,7 @@ class TestObjectController(unittest.TestCase): 'X-Object-Meta-1': 'One', 'X-Object-Meta-Two': 'Two'}) req.body = 'VERIFY THREE' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) objfile = os.path.join(self.testdir, 'sda1', storage_directory(object_server.DATADIR, 'p', @@ -551,12 +551,12 @@ class TestObjectController(unittest.TestCase): def test_HEAD(self): """ Test swift.object_server.ObjectController.HEAD """ - req = Request.blank('/sda1/p/a/c') - resp = self.object_controller.HEAD(req) + req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 400) - req = Request.blank('/sda1/p/a/c/o') - resp = self.object_controller.HEAD(req) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'HEAD'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 404) timestamp = normalize_timestamp(time()) @@ -566,11 +566,11 @@ class TestObjectController(unittest.TestCase): 'X-Object-Meta-1': 'One', 'X-Object-Meta-Two': 'Two'}) req.body = 'VERIFY' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) - req = Request.blank('/sda1/p/a/c/o') - resp = self.object_controller.HEAD(req) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'HEAD'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 200) self.assertEquals(resp.content_length, 6) self.assertEquals(resp.content_type, 'application/x-test') @@ -587,8 +587,8 @@ class TestObjectController(unittest.TestCase): hash_path('a', 'c', 'o')), timestamp + '.data') os.unlink(objfile) - req = Request.blank('/sda1/p/a/c/o') - resp = self.object_controller.HEAD(req) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'HEAD'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 404) sleep(.00001) @@ -599,7 +599,7 @@ class TestObjectController(unittest.TestCase): 'Content-Type': 'application/octet-stream', 'Content-length': '6'}) req.body = 'VERIFY' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) sleep(.00001) @@ -607,11 +607,11 @@ class TestObjectController(unittest.TestCase): req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': timestamp}) - resp = self.object_controller.DELETE(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 204) - req = Request.blank('/sda1/p/a/c/o') - resp = self.object_controller.HEAD(req) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'HEAD'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 404) def test_HEAD_quarantine_zbyte(self): @@ -621,7 +621,7 @@ class TestObjectController(unittest.TestCase): headers={'X-Timestamp': timestamp, 'Content-Type': 'application/x-test'}) req.body = 'VERIFY' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) file = diskfile.DiskFile(self.testdir, 'sda1', 'p', 'a', 'c', 'o', FakeLogger(), keep_data_fp=True) @@ -634,8 +634,8 @@ class TestObjectController(unittest.TestCase): diskfile.write_metadata(fp, metadata) self.assertEquals(os.listdir(file.datadir)[0], file_name) - req = Request.blank('/sda1/p/a/c/o') - resp = self.object_controller.HEAD(req) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'HEAD'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 404) quar_dir = os.path.join(self.testdir, 'sda1', 'quarantined', 'objects', @@ -644,12 +644,12 @@ class TestObjectController(unittest.TestCase): def test_GET(self): """ Test swift.object_server.ObjectController.GET """ - req = Request.blank('/sda1/p/a/c') - resp = self.object_controller.GET(req) + req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'GET'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 400) - req = Request.blank('/sda1/p/a/c/o') - resp = self.object_controller.GET(req) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'GET'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 404) timestamp = normalize_timestamp(time()) @@ -659,11 +659,11 @@ class TestObjectController(unittest.TestCase): 'X-Object-Meta-1': 'One', 'X-Object-Meta-Two': 'Two'}) req.body = 'VERIFY' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) - req = Request.blank('/sda1/p/a/c/o') - resp = self.object_controller.GET(req) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'GET'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 200) self.assertEquals(resp.body, 'VERIFY') self.assertEquals(resp.content_length, 6) @@ -677,23 +677,23 @@ class TestObjectController(unittest.TestCase): self.assertEquals(resp.headers['x-object-meta-1'], 'One') self.assertEquals(resp.headers['x-object-meta-two'], 'Two') - req = Request.blank('/sda1/p/a/c/o') + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'GET'}) req.range = 'bytes=1-3' - resp = self.object_controller.GET(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 206) self.assertEquals(resp.body, 'ERI') self.assertEquals(resp.headers['content-length'], '3') - req = Request.blank('/sda1/p/a/c/o') + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'GET'}) req.range = 'bytes=1-' - resp = self.object_controller.GET(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 206) self.assertEquals(resp.body, 'ERIFY') self.assertEquals(resp.headers['content-length'], '5') - req = Request.blank('/sda1/p/a/c/o') + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'GET'}) req.range = 'bytes=-2' - resp = self.object_controller.GET(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 206) self.assertEquals(resp.body, 'FY') self.assertEquals(resp.headers['content-length'], '2') @@ -703,8 +703,8 @@ class TestObjectController(unittest.TestCase): hash_path('a', 'c', 'o')), timestamp + '.data') os.unlink(objfile) - req = Request.blank('/sda1/p/a/c/o') - resp = self.object_controller.GET(req) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'GET'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 404) sleep(.00001) @@ -715,7 +715,7 @@ class TestObjectController(unittest.TestCase): 'Content-Type': 'application:octet-stream', 'Content-Length': '6'}) req.body = 'VERIFY' - resp = self.object_controller.PUT(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 201) sleep(.00001) @@ -723,11 +723,11 @@ class TestObjectController(unittest.TestCase): req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': timestamp}) - resp = self.object_controller.DELETE(req) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 204) - req = Request.blank('/sda1/p/a/c/o') - resp = self.object_controller.GET(req) + req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'GET'}) + resp = req.get_response(self.object_controller) self.assertEquals(resp.status_int, 404) def test_GET_if_match(self):