Catch swob responses that are raised.

This lets us get rid of some really repetitive exception conversion
code, like everybody that called common.utils.get_param() had to catch
a UnicodeDecodeError and turn that into returning HTTPBadRequest. Now
get_param() just raises HTTPBadRequest directly, and the __call__
methods in the account/container/object servers catch and return
it. All that "except UnicodeDecodeError" stuff goes away.

Refactored the path splitting and device validation in the object
server too.

There are other things that can benefit from this as well, but this
patch is big enough.

Change-Id: I2be96ef757d04bfd6af180cd9c92393c841db21f
This commit is contained in:
Samuel Merritt 2013-07-24 12:55:25 -07:00
parent 541c189533
commit df7fc9658b
9 changed files with 179 additions and 172 deletions

View File

@ -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 '),

View File

@ -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'])

View File

@ -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

View File

@ -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)

View File

@ -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 '),

View File

@ -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'

View File

@ -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)

View File

@ -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)

View File

@ -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):