Merge "HTTP status value naming normalization"

This commit is contained in:
Jenkins 2012-05-03 23:59:02 +00:00 committed by Gerrit Code Review
commit 96476846b6
17 changed files with 397 additions and 169 deletions

View File

@ -36,6 +36,7 @@ from swift.common.utils import get_logger, get_param, hash_path, \
from swift.common.constraints import ACCOUNT_LISTING_LIMIT, \
check_mount, check_float, check_utf8
from swift.common.db_replicator import ReplicatorRpc
from swift.common.http import HTTPInsufficientStorage
DATADIR = 'accounts'
@ -70,7 +71,7 @@ class AccountController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
if 'x-timestamp' not in req.headers or \
not check_float(req.headers['x-timestamp']):
return HTTPBadRequest(body='Missing timestamp', request=req,
@ -90,7 +91,7 @@ class AccountController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
broker = self._get_account_broker(drive, part, account)
if container: # put account container
if 'x-trans-id' in req.headers:
@ -149,7 +150,7 @@ class AccountController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
broker = self._get_account_broker(drive, part, account)
if not container:
broker.pending_timeout = 0.1
@ -180,7 +181,7 @@ class AccountController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
broker = self._get_account_broker(drive, part, account)
broker.pending_timeout = 0.1
broker.stale_reads_ok = True
@ -274,7 +275,7 @@ class AccountController(object):
request=req)
drive, partition, hash = post_args
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
try:
args = simplejson.load(req.environ['wsgi.input'])
except ValueError, err:
@ -295,7 +296,7 @@ class AccountController(object):
return HTTPBadRequest(body='Missing or bad timestamp',
request=req, content_type='text/plain')
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
broker = self._get_account_broker(drive, part, account)
if broker.is_deleted():
return HTTPNotFound(request=req)

View File

@ -24,6 +24,7 @@ from eventlet.green.httplib import CannotSendRequest
from swift.common.utils import TRUE_VALUES
from swift.common import client
from swift.common import direct_client
from swift.common.http import HTTP_CONFLICT
class ConnectionPool(eventlet.pools.Pool):
@ -152,7 +153,7 @@ class BenchDELETE(Bench):
try:
client.delete_container(self.url, self.token, container)
except client.ClientException, e:
if e.http_status != 409:
if e.http_status != HTTP_CONFLICT:
self._log_status("Unable to delete container '%s'. " \
"Got http status '%d'." % (container, e.http_status))

View File

@ -28,6 +28,8 @@ from eventlet import sleep, Timeout
from swift.common.bufferedhttp import http_connect
from swift.common.client import ClientException, json_loads
from swift.common.utils import normalize_timestamp
from swift.common.http import HTTP_NO_CONTENT, HTTP_INSUFFICIENT_STORAGE, \
is_success, is_server_error
def quote(value, safe='/'):
@ -69,7 +71,7 @@ def direct_get_account(node, part, account, marker=None, limit=None,
'GET', path, query_string=qs)
with Timeout(response_timeout):
resp = conn.getresponse()
if resp.status < 200 or resp.status >= 300:
if not is_success(resp.status):
resp.read()
raise ClientException(
'Account server %s:%s direct GET %s gave status %s' % (node['ip'],
@ -81,7 +83,7 @@ def direct_get_account(node, part, account, marker=None, limit=None,
resp_headers = {}
for header, value in resp.getheaders():
resp_headers[header.lower()] = value
if resp.status == 204:
if resp.status == HTTP_NO_CONTENT:
resp.read()
return resp_headers, []
return resp_headers, json_loads(resp.read())
@ -108,7 +110,7 @@ def direct_head_container(node, part, account, container, conn_timeout=5,
with Timeout(response_timeout):
resp = conn.getresponse()
resp.read()
if resp.status < 200 or resp.status >= 300:
if not is_success(resp.status):
raise ClientException(
'Container server %s:%s direct HEAD %s gave status %s' %
(node['ip'], node['port'],
@ -157,7 +159,7 @@ def direct_get_container(node, part, account, container, marker=None,
'GET', path, query_string=qs)
with Timeout(response_timeout):
resp = conn.getresponse()
if resp.status < 200 or resp.status >= 300:
if not is_success(resp.status):
resp.read()
raise ClientException(
'Container server %s:%s direct GET %s gave stats %s' % (node['ip'],
@ -169,7 +171,7 @@ def direct_get_container(node, part, account, container, marker=None,
resp_headers = {}
for header, value in resp.getheaders():
resp_headers[header.lower()] = value
if resp.status == 204:
if resp.status == HTTP_NO_CONTENT:
resp.read()
return resp_headers, []
return resp_headers, json_loads(resp.read())
@ -185,7 +187,7 @@ def direct_delete_container(node, part, account, container, conn_timeout=5,
with Timeout(response_timeout):
resp = conn.getresponse()
resp.read()
if resp.status < 200 or resp.status >= 300:
if not is_success(resp.status):
raise ClientException(
'Container server %s:%s direct DELETE %s gave status %s' %
(node['ip'], node['port'],
@ -218,7 +220,7 @@ def direct_head_object(node, part, account, container, obj, conn_timeout=5,
with Timeout(response_timeout):
resp = conn.getresponse()
resp.read()
if resp.status < 200 or resp.status >= 300:
if not is_success(resp.status):
raise ClientException(
'Object server %s:%s direct HEAD %s gave status %s' %
(node['ip'], node['port'],
@ -256,7 +258,7 @@ def direct_get_object(node, part, account, container, obj, conn_timeout=5,
'GET', path, headers=headers)
with Timeout(response_timeout):
resp = conn.getresponse()
if resp.status < 200 or resp.status >= 300:
if not is_success(resp.status):
resp.read()
raise ClientException(
'Object server %s:%s direct GET %s gave status %s' %
@ -326,7 +328,7 @@ def direct_put_object(node, part, account, container, name, contents,
with Timeout(response_timeout):
resp = conn.getresponse()
resp.read()
if resp.status < 200 or resp.status >= 300:
if not is_success(resp.status):
raise ClientException(
'Object server %s:%s direct PUT %s gave status %s' %
(node['ip'], node['port'],
@ -361,7 +363,7 @@ def direct_post_object(node, part, account, container, name, headers,
with Timeout(response_timeout):
resp = conn.getresponse()
resp.read()
if resp.status < 200 or resp.status >= 300:
if not is_success(resp.status):
raise ClientException(
'Object server %s:%s direct POST %s gave status %s' %
(node['ip'], node['port'],
@ -394,7 +396,7 @@ def direct_delete_object(node, part, account, container, obj,
with Timeout(response_timeout):
resp = conn.getresponse()
resp.read()
if resp.status < 200 or resp.status >= 300:
if not is_success(resp.status):
raise ClientException(
'Object server %s:%s direct DELETE %s gave status %s' %
(node['ip'], node['port'],
@ -440,8 +442,8 @@ def retry(func, *args, **kwargs):
except ClientException, err:
if error_log:
error_log(err)
if attempts > retries or err.http_status < 500 or \
err.http_status == 507 or err.http_status > 599:
if attempts > retries or not is_server_error(err.http_status) or \
err.http_status == HTTP_INSUFFICIENT_STORAGE:
raise
sleep(backoff)
backoff *= 2

193
swift/common/http.py Normal file
View File

@ -0,0 +1,193 @@
# 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.
from webob.exc import HTTPClientError,\
HTTPInsufficientStorage as BaseHTTPInsufficientStorage
class HTTPClientDisconnect(HTTPClientError):
"""
subclass of :class:`~HTTPClientError`
This code is introduced to log the case when the connection is closed by
client while HTTP server is processing its request
code: 499, title: Client Disconnect
"""
code = 499
title = 'Client Disconnect'
explanation = (
'This code is introduced to log the case when the connection '
'is closed by client while HTTP server is processing its request')
class HTTPInsufficientStorage(BaseHTTPInsufficientStorage):
"""
subclass of :class:`~HTTPInsufficientStorage`
The server is unable to store the representation needed to
complete the request.
code: 507, title: Insufficient Storage
"""
def __init__(self, drive=None, *args, **kwargs):
if drive:
self.explanation = ('%s is not mounted' % drive)
super(HTTPInsufficientStorage, self).__init__(*args, **kwargs)
def is_informational(status):
"""
Check if HTTP status code is informational.
:param status: http status code
:returns: True if status is successful, else False
"""
return 100 <= status and status <= 199
def is_success(status):
"""
Check if HTTP status code is successful.
:param status: http status code
:returns: True if status is successful, else False
"""
return 200 <= status and status <= 299
def is_redirection(status):
"""
Check if HTTP status code is redirection.
:param status: http status code
:returns: True if status is redirection, else False
"""
return 300 <= status and status <= 399
def is_client_error(status):
"""
Check if HTTP status code is client error.
:param status: http status code
:returns: True if status is client error, else False
"""
return 400 <= status and status <= 499
def is_server_error(status):
"""
Check if HTTP status code is server error.
:param status: http status code
:returns: True if status is server error, else False
"""
return 500 <= status and status <= 599
# List of HTTP status codes
###############################################################################
## 1xx Informational
###############################################################################
HTTP_CONTINUE = 100
HTTP_SWITCHING_PROTOCOLS = 101
HTTP_PROCESSING = 102 # WebDAV
HTTP_CHECKPOINT = 103
HTTP_REQUEST_URI_TOO_LONG = 122
###############################################################################
## 2xx Success
###############################################################################
HTTP_OK = 200
HTTP_CREATED = 201
HTTP_ACCEPTED = 202
HTTP_NON_AUTHORITATIVE_INFORMATION = 203
HTTP_NO_CONTENT = 204
HTTP_RESET_CONTENT = 205
HTTP_PARTIAL_CONTENT = 206
HTTP_MULTI_STATUS = 207 # WebDAV
HTTP_IM_USED = 226
###############################################################################
## 3xx Redirection
###############################################################################
HTTP_MULTIPLE_CHOICES = 300
HTTP_MOVED_PERMANENTLY = 301
HTTP_FOUND = 302
HTTP_SEE_OTHER = 303
HTTP_NOT_MODIFIED = 304
HTTP_USE_PROXY = 305
HTTP_SWITCH_PROXY = 306
HTTP_TEMPORARY_REDIRECT = 307
HTTP_RESUME_INCOMPLETE = 308
###############################################################################
## 4xx Client Error
###############################################################################
HTTP_BAD_REQUEST = 400
HTTP_UNAUTHORIZED = 401
HTTP_PAYMENT_REQUIRED = 402
HTTP_FORBIDDEN = 403
HTTP_NOT_FOUND = 404
HTTP_METHOD_NOT_ALLOWED = 405
HTTP_NOT_ACCEPTABLE = 406
HTTP_PROXY_AUTHENTICATION_REQUIRED = 407
HTTP_REQUEST_TIMEOUT = 408
HTTP_CONFLICT = 409
HTTP_GONE = 410
HTTP_LENGTH_REQUIRED = 411
HTTP_PRECONDITION_FAILED = 412
HTTP_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_REQUEST_URI_TOO_LONG = 414
HTTP_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416
HTTP_EXPECTATION_FAILED = 417
HTTP_IM_A_TEAPOT = 418
HTTP_UNPROCESSABLE_ENTITY = 422 # WebDAV
HTTP_LOCKED = 423 # WebDAV
HTTP_FAILED_DEPENDENCY = 424 # WebDAV
HTTP_UNORDERED_COLLECTION = 425
HTTP_UPGRADE_REQUIED = 426
HTTP_PRECONDITION_REQUIRED = 428
HTTP_TOO_MANY_REQUESTS = 429
HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431
HTTP_NO_RESPONSE = 444
HTTP_RETRY_WITH = 449
HTTP_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS = 450
HTTP_CLIENT_CLOSED_REQUEST = 499
###############################################################################
## 5xx Server Error
###############################################################################
HTTP_INTERNAL_SERVER_ERROR = 500
HTTP_NOT_IMPLEMENTED = 501
HTTP_BAD_GATEWAY = 502
HTTP_SERVICE_UNAVAILABLE = 503
HTTP_GATEWAY_TIMEOUT = 504
HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_VARIANT_ALSO_NEGOTIATES = 506
HTTP_INSUFFICIENT_STORAGE = 507 # WebDAV
HTTP_BANDWIDTH_LIMIT_EXCEEDED = 509
HTTP_NOT_EXTENDED = 510
HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511
HTTP_NETWORK_READ_TIMEOUT_ERROR = 598 # not used in RFC
HTTP_NETWORK_CONNECT_TIMEOUT_ERROR = 599 # not used in RFC

View File

@ -112,6 +112,7 @@ from urllib import quote, unquote
from swift.common.utils import get_logger, streq_const_time
from swift.common.wsgi import make_pre_authed_env
from swift.common.http import HTTP_BAD_REQUEST
#: The size of data to read from the form at any given time.
@ -324,7 +325,7 @@ class FormPost(object):
return self._translate_form(env, start_response,
attrs['boundary'])
except (FormInvalid, EOFError), err:
self._log_request(env, 400)
self._log_request(env, HTTP_BAD_REQUEST)
body = 'FormPost: %s' % err
start_response('400 Bad Request',
(('Content-Type', 'text/plain'),

View File

@ -125,6 +125,7 @@ from swift.common.utils import cache_from_env, get_logger, human_readable, \
split_path, TRUE_VALUES
from swift.common.wsgi import make_pre_authed_env, make_pre_authed_request, \
WSGIContext
from swift.common.http import is_success, is_redirection, HTTP_NOT_FOUND
def quote(value, safe='/'):
@ -183,7 +184,7 @@ class _StaticWebContext(WSGIContext):
'/%s/%s/%s/%s%s' % (self.version, self.account, self.container,
self._get_status_int(), self._error),
self.agent))
if self._get_status_int() // 100 == 2:
if is_success(self._get_status_int()):
start_response(save_response_status, self._response_headers,
self._response_exc_info)
return resp
@ -213,7 +214,7 @@ class _StaticWebContext(WSGIContext):
resp = make_pre_authed_request(env, 'HEAD',
'/%s/%s/%s' % (self.version, self.account, self.container),
agent=self.agent).get_response(self.app)
if resp.status_int // 100 == 2:
if is_success(resp.status_int):
self._index = \
resp.headers.get('x-container-meta-web-index', '').strip()
self._error = \
@ -249,7 +250,7 @@ class _StaticWebContext(WSGIContext):
else:
prefix = ''
resp = self._app_call(tmp_env)
if self._get_status_int() // 100 != 2:
if not is_success(self._get_status_int()):
return self._error_response(resp, env, start_response)
listing = None
body = ''.join(resp)
@ -363,9 +364,10 @@ class _StaticWebContext(WSGIContext):
tmp_env['PATH_INFO'] += self._index
resp = self._app_call(tmp_env)
status_int = self._get_status_int()
if status_int == 404:
if status_int == HTTP_NOT_FOUND:
return self._listing(env, start_response)
elif self._get_status_int() // 100 not in (2, 3):
elif not is_success(self._get_status_int()) or \
not is_redirection(self._get_status_int()):
return self._error_response(resp, env, start_response)
start_response(self._response_status, self._response_headers,
self._response_exc_info)
@ -384,16 +386,16 @@ class _StaticWebContext(WSGIContext):
'%s StaticWeb' % env.get('HTTP_USER_AGENT')
resp = self._app_call(tmp_env)
status_int = self._get_status_int()
if status_int // 100 in (2, 3):
if is_success(status_int) or is_redirection(status_int):
start_response(self._response_status, self._response_headers,
self._response_exc_info)
return resp
if status_int != 404:
if status_int != HTTP_NOT_FOUND:
return self._error_response(resp, env, start_response)
self._get_container_info(env)
if not self._listings and not self._index:
return self.app(env, start_response)
status_int = 404
status_int = HTTP_NOT_FOUND
if self._index:
tmp_env = dict(env)
tmp_env['HTTP_USER_AGENT'] = \
@ -403,7 +405,7 @@ class _StaticWebContext(WSGIContext):
tmp_env['PATH_INFO'] += self._index
resp = self._app_call(tmp_env)
status_int = self._get_status_int()
if status_int // 100 in (2, 3):
if is_success(status_int) or is_redirection(status_int):
if env['PATH_INFO'][-1] != '/':
resp = HTTPMovedPermanently(
location=env['PATH_INFO'] + '/')
@ -412,7 +414,7 @@ class _StaticWebContext(WSGIContext):
start_response(self._response_status, self._response_headers,
self._response_exc_info)
return resp
if status_int == 404:
if status_int == HTTP_NOT_FOUND:
if env['PATH_INFO'][-1] != '/':
tmp_env = make_pre_authed_env(env, 'GET',
'/%s/%s/%s' % (self.version, self.account,
@ -422,7 +424,7 @@ class _StaticWebContext(WSGIContext):
'=/&limit=1&prefix=%s' % quote(self.obj + '/')
resp = self._app_call(tmp_env)
body = ''.join(resp)
if self._get_status_int() // 100 != 2 or not body or \
if not is_success(self._get_status_int()) or not body or \
not json.loads(body):
resp = HTTPNotFound()(env, self._start_response)
return self._error_response(resp, env, start_response)

View File

@ -60,6 +60,9 @@ from simplejson import loads
from swift.common.utils import split_path
from swift.common.wsgi import WSGIContext
from swift.common.http import HTTP_OK, HTTP_CREATED, HTTP_ACCEPTED, \
HTTP_NO_CONTENT, HTTP_BAD_REQUEST, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, \
HTTP_NOT_FOUND, HTTP_CONFLICT, is_success
MAX_BUCKET_LISTING = 1000
@ -74,24 +77,24 @@ def get_err_response(code):
"""
error_table = {
'AccessDenied':
(403, 'Access denied'),
(HTTP_FORBIDDEN, 'Access denied'),
'BucketAlreadyExists':
(409, 'The requested bucket name is not available'),
(HTTP_CONFLICT, 'The requested bucket name is not available'),
'BucketNotEmpty':
(409, 'The bucket you tried to delete is not empty'),
(HTTP_CONFLICT, 'The bucket you tried to delete is not empty'),
'InvalidArgument':
(400, 'Invalid Argument'),
(HTTP_BAD_REQUEST, 'Invalid Argument'),
'InvalidBucketName':
(400, 'The specified bucket is not valid'),
(HTTP_BAD_REQUEST, 'The specified bucket is not valid'),
'InvalidURI':
(400, 'Could not parse the specified URI'),
(HTTP_BAD_REQUEST, 'Could not parse the specified URI'),
'NoSuchBucket':
(404, 'The specified bucket does not exist'),
(HTTP_NOT_FOUND, 'The specified bucket does not exist'),
'SignatureDoesNotMatch':
(403, 'The calculated request signature does not match '\
'your provided one'),
(HTTP_FORBIDDEN, 'The calculated request signature does not '\
'match your provided one'),
'NoSuchKey':
(404, 'The resource you requested does not exist')}
(HTTP_NOT_FOUND, 'The resource you requested does not exist')}
resp = Response(content_type='text/xml')
resp.status = error_table[code][0]
@ -169,8 +172,8 @@ class ServiceController(WSGIContext):
body_iter = self._app_call(env)
status = self._get_status_int()
if status != 200:
if status == 401:
if status != HTTP_OK:
if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied')
else:
return get_err_response('InvalidURI')
@ -186,7 +189,8 @@ class ServiceController(WSGIContext):
% ("".join(['<Bucket><Name>%s</Name><CreationDate>' \
'2009-02-03T16:45:09.000Z</CreationDate></Bucket>' %
xml_escape(i['name']) for i in containers]))
resp = Response(status=200, content_type='application/xml', body=body)
resp = Response(status=HTTP_OK, content_type='application/xml',
body=body)
return resp
@ -222,10 +226,10 @@ class BucketController(WSGIContext):
body_iter = self._app_call(env)
status = self._get_status_int()
if status != 200:
if status == 401:
if status != HTTP_OK:
if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied')
elif status == 404:
elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchBucket')
else:
return get_err_response('InvalidURI')
@ -271,17 +275,17 @@ class BucketController(WSGIContext):
body_iter = self._app_call(env)
status = self._get_status_int()
if status != 201:
if status == 401:
if status != HTTP_CREATED:
if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied')
elif status == 202:
elif status == HTTP_ACCEPTED:
return get_err_response('BucketAlreadyExists')
else:
return get_err_response('InvalidURI')
resp = Response()
resp.headers.add('Location', self.container_name)
resp.status = 200
resp.status = HTTP_OK
return resp
def DELETE(self, env, start_response):
@ -291,18 +295,18 @@ class BucketController(WSGIContext):
body_iter = self._app_call(env)
status = self._get_status_int()
if status != 204:
if status == 401:
if status != HTTP_NO_CONTENT:
if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied')
elif status == 404:
elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchBucket')
elif status == 409:
elif status == HTTP_CONFLICT:
return get_err_response('BucketNotEmpty')
else:
return get_err_response('InvalidURI')
resp = Response()
resp.status = 204
resp.status = HTTP_NO_CONTENT
return resp
@ -324,7 +328,7 @@ class ObjectController(WSGIContext):
status = self._get_status_int()
headers = dict(self._response_headers)
if 200 <= status < 300:
if is_success(status):
if 'QUERY_STRING' in env:
args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1))
else:
@ -342,9 +346,9 @@ class ObjectController(WSGIContext):
'etag', 'last-modified'):
new_hdrs[key] = val
return Response(status=status, headers=new_hdrs, app_iter=app_iter)
elif status == 401:
elif status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied')
elif status == 404:
elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchKey')
else:
return get_err_response('InvalidURI')
@ -377,10 +381,10 @@ class ObjectController(WSGIContext):
body_iter = self._app_call(env)
status = self._get_status_int()
if status != 201:
if status == 401:
if status != HTTP_CREATED:
if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied')
elif status == 404:
elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchBucket')
else:
return get_err_response('InvalidURI')
@ -389,7 +393,7 @@ class ObjectController(WSGIContext):
body = '<CopyObjectResult>' \
'<ETag>"%s"</ETag>' \
'</CopyObjectResult>' % self._response_header_value('etag')
return Response(status=200, body=body)
return Response(status=HTTP_OK, body=body)
return Response(status=200, etag=self._response_header_value('etag'))
@ -400,16 +404,16 @@ class ObjectController(WSGIContext):
body_iter = self._app_call(env)
status = self._get_status_int()
if status != 204:
if status == 401:
if status != HTTP_NO_CONTENT:
if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied')
elif status == 404:
elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchKey')
else:
return get_err_response('InvalidURI')
resp = Response()
resp.status = 204
resp.status = HTTP_NO_CONTENT
return resp

View File

@ -29,6 +29,7 @@ from webob.exc import HTTPBadRequest, HTTPForbidden, HTTPNotFound, \
from swift.common.middleware.acl import clean_acl, parse_acl, referrer_allowed
from swift.common.utils import cache_from_env, get_logger, get_remote_client, \
split_path, TRUE_VALUES
from swift.common.http import HTTP_CLIENT_CLOSED_REQUEST
class TempAuth(object):
@ -458,7 +459,7 @@ class TempAuth(object):
status_int = response.status_int
if getattr(req, 'client_disconnect', False) or \
getattr(response, 'client_disconnect', False):
status_int = 499
status_int = HTTP_CLIENT_CLOSED_REQUEST
self.logger.info(' '.join(quote(str(x)) for x in (client or '-',
req.remote_addr or '-', strftime('%d/%b/%Y/%H/%M/%S', gmtime()),
req.method, the_request, req.environ['SERVER_PROTOCOL'],

View File

@ -88,6 +88,7 @@ from urlparse import parse_qs
from swift.common.utils import get_logger
from swift.common.wsgi import make_pre_authed_env
from swift.common.http import HTTP_UNAUTHORIZED
#: Default headers to remove from incoming requests. Simply a whitespace
@ -376,7 +377,7 @@ class TempURL(object):
:param start_response: The WSGI start_response hook.
:returns: 401 response as per WSGI.
"""
self._log_request(env, 401)
self._log_request(env, HTTP_UNAUTHORIZED)
body = '401 Unauthorized: Temp URL invalid\n'
start_response('401 Unauthorized',
[('Content-Type', 'text/plain'),

View File

@ -39,6 +39,8 @@ from swift.common.constraints import CONTAINER_LISTING_LIMIT, \
from swift.common.bufferedhttp import http_connect
from swift.common.exceptions import ConnectionTimeout
from swift.common.db_replicator import ReplicatorRpc
from swift.common.http import HTTP_NOT_FOUND, is_success, \
HTTPInsufficientStorage
DATADIR = 'containers'
@ -119,10 +121,9 @@ class ContainerController(object):
with Timeout(self.node_timeout):
account_response = conn.getresponse()
account_response.read()
if account_response.status == 404:
if account_response.status == HTTP_NOT_FOUND:
return HTTPNotFound(request=req)
elif account_response.status < 200 or \
account_response.status > 299:
elif not is_success(account_response.status):
self.logger.error(_('ERROR Account update failed '
'with %(ip)s:%(port)s/%(device)s (will retry '
'later): Response %(status)s %(reason)s'),
@ -150,7 +151,7 @@ class ContainerController(object):
return HTTPBadRequest(body='Missing timestamp', request=req,
content_type='text/plain')
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
broker = self._get_container_broker(drive, part, account, container)
if account.startswith(self.auto_create_account_prefix) and obj and \
not os.path.exists(broker.db_file):
@ -195,7 +196,7 @@ class ContainerController(object):
if err:
return HTTPBadRequest(err)
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
timestamp = normalize_timestamp(req.headers['x-timestamp'])
broker = self._get_container_broker(drive, part, account, container)
if obj: # put container object
@ -245,7 +246,7 @@ class ContainerController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
broker = self._get_container_broker(drive, part, account, container)
broker.pending_timeout = 0.1
broker.stale_reads_ok = True
@ -273,7 +274,7 @@ class ContainerController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
broker = self._get_container_broker(drive, part, account, container)
broker.pending_timeout = 0.1
broker.stale_reads_ok = True
@ -388,7 +389,7 @@ class ContainerController(object):
request=req)
drive, partition, hash = post_args
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
try:
args = simplejson.load(req.environ['wsgi.input'])
except ValueError, err:
@ -414,7 +415,7 @@ class ContainerController(object):
if err:
return HTTPBadRequest(err)
if self.mount_check and not check_mount(self.root, drive):
return Response(status='507 %s is not mounted' % drive)
return HTTPInsufficientStorage(drive=drive, request=req)
broker = self._get_container_broker(drive, part, account, container)
if broker.is_deleted():
return HTTPNotFound(request=req)

View File

@ -29,6 +29,7 @@ from swift.common.db import ContainerBroker
from swift.common.utils import audit_location_generator, get_logger, \
hash_path, TRUE_VALUES, validate_sync_to, whataremyips
from swift.common.daemon import Daemon
from swift.common.http import HTTP_UNAUTHORIZED, HTTP_NOT_FOUND
class _Iter2FileLikeObject(object):
@ -349,7 +350,7 @@ class ContainerSync(Daemon):
'x-container-sync-key': sync_key},
proxy=self.proxy)
except ClientException, err:
if err.http_status != 404:
if err.http_status != HTTP_NOT_FOUND:
raise
self.container_deletes += 1
else:
@ -376,7 +377,7 @@ class ContainerSync(Daemon):
# non-404 one. We don't want to mistakenly assume the
# object no longer exists just because one says so and
# the others errored for some other reason.
if not exc or exc.http_status == 404:
if not exc or exc.http_status == HTTP_NOT_FOUND:
exc = err
if timestamp < looking_for_timestamp:
if exc:
@ -398,13 +399,13 @@ class ContainerSync(Daemon):
contents=_Iter2FileLikeObject(body), proxy=self.proxy)
self.container_puts += 1
except ClientException, err:
if err.http_status == 401:
if err.http_status == HTTP_UNAUTHORIZED:
self.logger.info(_('Unauth %(sync_from)r '
'=> %(sync_to)r'),
{'sync_from': '%s/%s' %
(quote(info['account']), quote(info['container'])),
'sync_to': sync_to})
elif err.http_status == 404:
elif err.http_status == HTTP_NOT_FOUND:
self.logger.info(_('Not found %(sync_from)r '
'=> %(sync_to)r'),
{'sync_from': '%s/%s' %

View File

@ -31,6 +31,7 @@ from swift.common.exceptions import ConnectionTimeout
from swift.common.ring import Ring
from swift.common.utils import get_logger, TRUE_VALUES
from swift.common.daemon import Daemon
from swift.common.http import is_success, HTTP_INTERNAL_SERVER_ERROR
class ContainerUpdater(Daemon):
@ -214,7 +215,7 @@ class ContainerUpdater(Daemon):
successes = 0
failures = 0
for event in events:
if 200 <= event.wait() < 300:
if is_success(event.wait()):
successes += 1
else:
failures += 1
@ -265,7 +266,7 @@ class ContainerUpdater(Daemon):
except (Exception, Timeout):
self.logger.exception(_('ERROR account update failed with '
'%(ip)s:%(port)s/%(device)s (will retry later): '), node)
return 500
return HTTP_INTERNAL_SERVER_ERROR
with Timeout(self.node_timeout):
try:
resp = conn.getresponse()
@ -275,4 +276,4 @@ class ContainerUpdater(Daemon):
if self.logger.getEffectiveLevel() <= logging.DEBUG:
self.logger.exception(
_('Exception with %(ip)s:%(port)s/%(device)s'), node)
return 500
return HTTP_INTERNAL_SERVER_ERROR

View File

@ -24,6 +24,8 @@ from webob import Request
from swift.common.daemon import Daemon
from swift.common.utils import get_logger
from swift.common.http import HTTP_NO_CONTENT, HTTP_NOT_FOUND, HTTP_CONFLICT, \
HTTP_PRECONDITION_FAILED
try:
import simplejson as json
@ -161,8 +163,9 @@ class ObjectExpirer(Daemon):
the hidden expiration account.
"""
resp = self.get_response('HEAD',
'/v1/' + quote(self.expiring_objects_account), {}, (2, 404))
if resp.status_int == 404:
'/v1/' + quote(self.expiring_objects_account), {},
(2, HTTP_NOT_FOUND))
if resp.status_int == HTTP_NOT_FOUND:
return (0, 0)
return (int(resp.headers['x-account-container-count']),
int(resp.headers['x-account-object-count']))
@ -176,8 +179,8 @@ class ObjectExpirer(Daemon):
marker = ''
while True:
resp = self.get_response('GET', path + '&marker=' + quote(marker),
{}, (2, 404))
if resp.status_int in (204, 404):
{}, (2, HTTP_NOT_FOUND))
if resp.status_int in (HTTP_NO_CONTENT, HTTP_NOT_FOUND):
break
data = json.loads(resp.body)
if not data:
@ -198,8 +201,8 @@ class ObjectExpirer(Daemon):
marker = ''
while True:
resp = self.get_response('GET', path + '&marker=' + quote(marker),
{}, (2, 404))
if resp.status_int in (204, 404):
{}, (2, HTTP_NOT_FOUND))
if resp.status_int in (HTTP_NO_CONTENT, HTTP_NOT_FOUND):
break
data = json.loads(resp.body)
if not data:
@ -220,7 +223,8 @@ class ObjectExpirer(Daemon):
perform the actual delete.
"""
self.get_response('DELETE', '/v1/%s' % (quote(actual_obj),),
{'X-If-Delete-At': str(timestamp)}, (2, 404, 412))
{'X-If-Delete-At': str(timestamp)},
(2, HTTP_NOT_FOUND, HTTP_PRECONDITION_FAILED))
def delete_object(self, container, obj):
"""
@ -232,7 +236,7 @@ class ObjectExpirer(Daemon):
self.get_response('DELETE',
'/v1/%s/%s/%s' % (quote(self.expiring_objects_account),
quote(container), quote(obj)),
{}, (2, 404))
{}, (2, HTTP_NOT_FOUND))
def delete_container(self, container):
"""
@ -243,4 +247,4 @@ class ObjectExpirer(Daemon):
self.get_response('DELETE',
'/v1/%s/%s' % (quote(self.expiring_objects_account),
quote(container)),
{}, (2, 404, 409))
{}, (2, HTTP_NOT_FOUND, HTTP_CONFLICT))

View File

@ -36,6 +36,7 @@ from swift.common.utils import whataremyips, unlink_older_than, lock_path, \
TRUE_VALUES
from swift.common.bufferedhttp import http_connect
from swift.common.daemon import Daemon
from swift.common.http import HTTP_OK, HTTP_INSUFFICIENT_STORAGE
hubs.use_hub('poll')
@ -408,12 +409,12 @@ class ObjectReplicator(Daemon):
resp = http_connect(node['ip'], node['port'],
node['device'], job['partition'], 'REPLICATE',
'', headers={'Content-Length': '0'}).getresponse()
if resp.status == 507:
if resp.status == HTTP_INSUFFICIENT_STORAGE:
self.logger.error(_('%(ip)s/%(device)s responded'
' as unmounted'), node)
attempts_left += 1
continue
if resp.status != 200:
if resp.status != HTTP_OK:
self.logger.error(_("Invalid response %(resp)s "
"from %(ip)s"),
{'resp': resp.status, 'ip': node['ip']})

View File

@ -45,6 +45,8 @@ from swift.common.exceptions import ConnectionTimeout, DiskFileError, \
DiskFileNotExist
from swift.obj.replicator import tpooled_get_hashes, invalidate_hash, \
quarantine_renamer
from swift.common.http import is_success, HTTPInsufficientStorage, \
HTTPClientDisconnect
DATADIR = 'objects'
@ -404,7 +406,7 @@ class ObjectController(object):
with Timeout(self.node_timeout):
response = conn.getresponse()
response.read()
if 200 <= response.status < 300:
if is_success(response.status):
return
else:
self.logger.error(_('ERROR Container update failed '
@ -492,7 +494,7 @@ class ObjectController(object):
return HTTPBadRequest(body='X-Delete-At in past', request=request,
content_type='text/plain')
if self.mount_check and not check_mount(self.devices, device):
return Response(status='507 %s is not mounted' % device)
return HTTPInsufficientStorage(drive=device, request=request)
file = DiskFile(self.devices, device, partition, account, container,
obj, self.logger, disk_chunk_size=self.disk_chunk_size)
@ -536,7 +538,7 @@ class ObjectController(object):
return HTTPBadRequest(body=str(err), request=request,
content_type='text/plain')
if self.mount_check and not check_mount(self.devices, device):
return Response(status='507 %s is not mounted' % device)
return HTTPInsufficientStorage(drive=device, request=request)
if 'x-timestamp' not in request.headers or \
not check_float(request.headers['x-timestamp']):
return HTTPBadRequest(body='Missing timestamp', request=request,
@ -575,7 +577,7 @@ class ObjectController(object):
if 'content-length' in request.headers and \
int(request.headers['content-length']) != upload_size:
return Response(status='499 Client Disconnect')
return HTTPClientDisconnect(request=request)
etag = etag.hexdigest()
if 'etag' in request.headers and \
request.headers['etag'].lower() != etag:
@ -625,7 +627,7 @@ class ObjectController(object):
return HTTPBadRequest(body=str(err), request=request,
content_type='text/plain')
if self.mount_check and not check_mount(self.devices, device):
return Response(status='507 %s is not mounted' % device)
return HTTPInsufficientStorage(drive=device, request=request)
file = DiskFile(self.devices, device, partition, account, container,
obj, self.logger, keep_data_fp=True,
disk_chunk_size=self.disk_chunk_size)
@ -701,7 +703,7 @@ class ObjectController(object):
resp.body = str(err)
return resp
if self.mount_check and not check_mount(self.devices, device):
return Response(status='507 %s is not mounted' % device)
return HTTPInsufficientStorage(drive=device, request=request)
file = DiskFile(self.devices, device, partition, account, container,
obj, self.logger, disk_chunk_size=self.disk_chunk_size)
if file.is_deleted() or ('X-Delete-At' in file.metadata and
@ -742,7 +744,7 @@ class ObjectController(object):
return HTTPBadRequest(body='Missing timestamp', request=request,
content_type='text/plain')
if self.mount_check and not check_mount(self.devices, device):
return Response(status='507 %s is not mounted' % device)
return HTTPInsufficientStorage(drive=device, request=request)
response_class = HTTPNoContent
file = DiskFile(self.devices, device, partition, account, container,
obj, self.logger, disk_chunk_size=self.disk_chunk_size)
@ -785,7 +787,7 @@ class ObjectController(object):
return HTTPBadRequest(body=str(e), request=request,
content_type='text/plain')
if self.mount_check and not check_mount(self.devices, device):
return Response(status='507 %s is not mounted' % device)
return HTTPInsufficientStorage(drive=device, request=request)
path = os.path.join(self.devices, device, DATADIR, partition)
if not os.path.exists(path):
mkdirs(path)

View File

@ -28,6 +28,8 @@ from swift.common.ring import Ring
from swift.common.utils import get_logger, renamer, write_pickle
from swift.common.daemon import Daemon
from swift.obj.server import ASYNCDIR
from swift.common.http import is_success, HTTP_NOT_FOUND, \
HTTP_INTERNAL_SERVER_ERROR
class ObjectUpdater(Daemon):
@ -178,7 +180,7 @@ class ObjectUpdater(Daemon):
if node['id'] not in successes:
status = self.object_update(node, part, update['op'], obj,
update['headers'])
if not (200 <= status < 300) and status != 404:
if not is_success(status) and status != HTTP_NOT_FOUND:
success = False
else:
successes.append(node['id'])
@ -217,4 +219,4 @@ class ObjectUpdater(Daemon):
except (Exception, Timeout):
self.logger.exception(_('ERROR with remote server '
'%(ip)s:%(port)s/%(device)s'), node)
return 500
return HTTP_INTERNAL_SERVER_ERROR

View File

@ -61,6 +61,12 @@ from swift.common.constraints import check_metadata, check_object_creation, \
from swift.common.exceptions import ChunkReadTimeout, \
ChunkWriteTimeout, ConnectionTimeout, ListingIterNotFound, \
ListingIterNotAuthorized, ListingIterError
from swift.common.http import is_informational, is_success, is_redirection, \
is_client_error, is_server_error, HTTP_CONTINUE, HTTP_OK, HTTP_CREATED, \
HTTP_ACCEPTED, HTTP_PARTIAL_CONTENT, HTTP_MULTIPLE_CHOICES, \
HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_REQUESTED_RANGE_NOT_SATISFIABLE, \
HTTP_CLIENT_CLOSED_REQUEST, HTTP_INTERNAL_SERVER_ERROR, \
HTTP_SERVICE_UNAVAILABLE, HTTP_INSUFFICIENT_STORAGE, HTTPClientDisconnect
def update_headers(response, headers):
@ -181,7 +187,7 @@ class SegmentedIterable(object):
self.controller.iter_nodes(partition, nodes,
self.controller.app.object_ring), path,
self.controller.app.object_ring.replica_count)
if resp.status_int // 100 != 2:
if not is_success(resp.status_int):
raise Exception(_('Could not load object segment %(path)s:' \
' %(status)s') % {'path': path, 'status': resp.status_int})
self.segment_iter = resp.app_iter
@ -197,7 +203,7 @@ class SegmentedIterable(object):
'cont': self.controller.container_name,
'obj': self.controller.object_name})
err.swift_logged = True
self.response.status_int = 503
self.response.status_int = HTTP_SERVICE_UNAVAILABLE
raise
def next(self):
@ -230,7 +236,7 @@ class SegmentedIterable(object):
'cont': self.controller.container_name,
'obj': self.controller.object_name})
err.swift_logged = True
self.response.status_int = 503
self.response.status_int = HTTP_SERVICE_UNAVAILABLE
raise
def app_iter_range(self, start, stop):
@ -291,7 +297,7 @@ class SegmentedIterable(object):
'cont': self.controller.container_name,
'obj': self.controller.object_name})
err.swift_logged = True
self.response.status_int = 503
self.response.status_int = HTTP_SERVICE_UNAVAILABLE
raise
@ -402,9 +408,9 @@ class Controller(object):
else:
result_code = cache_value['status']
container_count = cache_value['container_count']
if result_code == 200:
if result_code == HTTP_OK:
return partition, nodes, container_count
elif result_code == 404 and not autocreate:
elif result_code == HTTP_NOT_FOUND and not autocreate:
return None, None, None
result_code = 0
container_count = 0
@ -419,17 +425,17 @@ class Controller(object):
with Timeout(self.app.node_timeout):
resp = conn.getresponse()
body = resp.read()
if 200 <= resp.status <= 299:
result_code = 200
if is_success(resp.status):
result_code = HTTP_OK
container_count = int(
resp.getheader('x-account-container-count') or 0)
break
elif resp.status == 404:
elif resp.status == HTTP_NOT_FOUND:
if result_code == 0:
result_code = 404
elif result_code != 404:
result_code = HTTP_NOT_FOUND
elif result_code != HTTP_NOT_FOUND:
result_code = -1
elif resp.status == 507:
elif resp.status == HTTP_INSUFFICIENT_STORAGE:
self.error_limit(node)
continue
else:
@ -440,7 +446,7 @@ class Controller(object):
except (Exception, Timeout):
self.exception_occurred(node, _('Account'),
_('Trying to get account info for %s') % path)
if result_code == 404 and autocreate:
if result_code == HTTP_NOT_FOUND and autocreate:
if len(account) > MAX_ACCOUNT_NAME_LENGTH:
return None, None, None
headers = {'X-Timestamp': normalize_timestamp(time.time()),
@ -449,18 +455,18 @@ class Controller(object):
resp = self.make_requests(Request.blank('/v1' + path),
self.app.account_ring, partition, 'PUT',
path, [headers] * len(nodes))
if resp.status_int // 100 != 2:
if not is_success(resp.status_int):
raise Exception('Could not autocreate account %r' % path)
result_code = 200
if self.app.memcache and result_code in (200, 404):
if result_code == 200:
result_code = HTTP_OK
if self.app.memcache and result_code in (HTTP_OK, HTTP_NOT_FOUND):
if result_code == HTTP_OK:
cache_timeout = self.app.recheck_account_existence
else:
cache_timeout = self.app.recheck_account_existence * 0.1
self.app.memcache.set(cache_key,
{'status': result_code, 'container_count': container_count},
timeout=cache_timeout)
if result_code == 200:
if result_code == HTTP_OK:
return partition, nodes, container_count
return None, None, None
@ -488,10 +494,10 @@ class Controller(object):
write_acl = cache_value['write_acl']
sync_key = cache_value.get('sync_key')
versions = cache_value.get('versions')
if status == 200:
if status == HTTP_OK:
return partition, nodes, read_acl, write_acl, sync_key, \
versions
elif status == 404:
elif status == HTTP_NOT_FOUND:
return None, None, None, None, None, None
if not self.account_info(account, autocreate=account_autocreate)[1]:
return None, None, None, None, None, None
@ -511,8 +517,8 @@ class Controller(object):
with Timeout(self.app.node_timeout):
resp = conn.getresponse()
body = resp.read()
if 200 <= resp.status <= 299:
result_code = 200
if is_success(resp.status):
result_code = HTTP_OK
read_acl = resp.getheader('x-container-read')
write_acl = resp.getheader('x-container-write')
sync_key = resp.getheader('x-container-sync-key')
@ -520,12 +526,12 @@ class Controller(object):
resp.getheader('X-Container-Object-Count')
versions = resp.getheader('x-versions-location')
break
elif resp.status == 404:
elif resp.status == HTTP_NOT_FOUND:
if result_code == 0:
result_code = 404
elif result_code != 404:
result_code = HTTP_NOT_FOUND
elif result_code != HTTP_NOT_FOUND:
result_code = -1
elif resp.status == 507:
elif resp.status == HTTP_INSUFFICIENT_STORAGE:
self.error_limit(node)
continue
else:
@ -536,8 +542,8 @@ class Controller(object):
except (Exception, Timeout):
self.exception_occurred(node, _('Container'),
_('Trying to get container info for %s') % path)
if self.app.memcache and result_code in (200, 404):
if result_code == 200:
if self.app.memcache and result_code in (HTTP_OK, HTTP_NOT_FOUND):
if result_code == HTTP_OK:
cache_timeout = self.app.recheck_container_existence
else:
cache_timeout = self.app.recheck_container_existence * 0.1
@ -549,7 +555,7 @@ class Controller(object):
'container_size': container_size,
'versions': versions},
timeout=cache_timeout)
if result_code == 200:
if result_code == HTTP_OK:
return partition, nodes, read_acl, write_acl, sync_key, versions
return None, None, None, None, None, None
@ -579,9 +585,10 @@ class Controller(object):
conn.node = node
with Timeout(self.app.node_timeout):
resp = conn.getresponse()
if 200 <= resp.status < 500:
if not is_informational(resp.status) and \
not is_server_error(resp.status):
return resp.status, resp.reason, resp.read()
elif resp.status == 507:
elif resp.status == HTTP_INSUFFICIENT_STORAGE:
self.error_limit(node)
except (Exception, Timeout):
self.exception_occurred(node, self.server_type,
@ -606,7 +613,7 @@ class Controller(object):
head, query_string)
response = [resp for resp in pile if resp]
while len(response) < ring.replica_count:
response.append((503, '', ''))
response.append((HTTP_SERVICE_UNAVAILABLE, '', ''))
statuses, reasons, bodies = zip(*response)
return self.best_response(req, statuses, reasons, bodies,
'%s %s' % (self.server_type, req.method))
@ -627,7 +634,7 @@ class Controller(object):
"""
resp = Response(request=req)
if len(statuses):
for hundred in (200, 300, 400):
for hundred in (HTTP_OK, HTTP_MULTIPLE_CHOICES, HTTP_BAD_REQUEST):
hstatuses = \
[s for s in statuses if hundred <= s < hundred + 100]
if len(hstatuses) > len(statuses) / 2:
@ -782,13 +789,14 @@ class Controller(object):
_('Trying to %(method)s %(path)s') %
{'method': req.method, 'path': req.path})
continue
if possible_source.status == 507:
if possible_source.status == HTTP_INSUFFICIENT_STORAGE:
self.error_limit(node)
continue
if 200 <= possible_source.status <= 399:
if is_success(possible_source.status) or \
is_redirection(possible_source.status):
# 404 if we know we don't have a synced copy
if not float(possible_source.getheader('X-PUT-Timestamp', 1)):
statuses.append(404)
statuses.append(HTTP_NOT_FOUND)
reasons.append('')
bodies.append('')
possible_source.read()
@ -811,13 +819,14 @@ class Controller(object):
statuses.append(possible_source.status)
reasons.append(possible_source.reason)
bodies.append(possible_source.read())
if possible_source.status >= 500:
if is_server_error(possible_source.status):
self.error_occurred(node, _('ERROR %(status)d %(body)s ' \
'From %(type)s Server') %
{'status': possible_source.status,
'body': bodies[-1][:1024], 'type': server_type})
if source:
if req.method == 'GET' and source.status in (200, 206):
if req.method == 'GET' and \
source.status in (HTTP_OK, HTTP_PARTIAL_CONTENT):
res = Response(request=req, conditional_response=True)
res.bytes_transferred = 0
res.app_iter = self._make_app_iter(node, source, res)
@ -834,7 +843,7 @@ class Controller(object):
res.charset = None
res.content_type = source.getheader('Content-Type')
return res
elif 200 <= source.status <= 399:
elif is_success(source.status) or is_redirection(source.status):
res = status_map[source.status](request=req)
update_headers(res, source.getheaders())
# Used by container sync feature
@ -883,9 +892,9 @@ class ObjectController(Controller):
aresp = env['swift.authorize'](lreq)
if aresp:
raise ListingIterNotAuthorized(aresp)
if lresp.status_int == 404:
if lresp.status_int == HTTP_NOT_FOUND:
raise ListingIterNotFound()
elif lresp.status_int // 100 != 2:
elif not is_success(lresp.status_int):
raise ListingIterError()
if not lresp.body:
break
@ -914,7 +923,7 @@ class ObjectController(Controller):
# If we get a 416 Requested Range Not Satisfiable we have to check if
# we were actually requesting a manifest and then redo
# the range request on the whole object.
if resp.status_int == 416:
if resp.status_int == HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
req_range = req.range
req.range = None
resp2 = self.GETorHEAD_base(req, _('Object'), partition,
@ -1022,7 +1031,7 @@ class ObjectController(Controller):
# Older editions returned 202 Accepted on object POSTs, so we'll
# convert any 201 Created responses to that for compatibility with
# picky clients.
if resp.status_int != 201:
if resp.status_int != HTTP_CREATED:
return resp
return HTTPAccepted(request=req)
else:
@ -1098,10 +1107,10 @@ class ObjectController(Controller):
node['device'], part, 'PUT', path, headers)
with Timeout(self.app.node_timeout):
resp = conn.getexpect()
if resp.status == 100:
if resp.status == HTTP_CONTINUE:
conn.node = node
return conn
elif resp.status == 507:
elif resp.status == HTTP_INSUFFICIENT_STORAGE:
self.error_limit(node)
except:
self.exception_occurred(node, _('Object'),
@ -1183,7 +1192,7 @@ class ObjectController(Controller):
if object_versions and not req.environ.get('swift_versioned_copy'):
is_manifest = 'x-object-manifest' in req.headers or \
'x-object-manifest' in hresp.headers
if hresp.status_int != 404 and not is_manifest:
if hresp.status_int != HTTP_NOT_FOUND and not is_manifest:
# This is a version manifest and needs to be handled
# differently. First copy the existing data to a new object,
# then write the data from this request to the version manifest
@ -1206,10 +1215,10 @@ class ObjectController(Controller):
copy_req = Request.blank(req.path_info, headers=copy_headers,
environ=copy_environ)
copy_resp = self.COPY(copy_req)
if copy_resp.status_int // 100 == 4:
if is_client_error(copy_resp.status_int):
# missing container or bad permissions
return HTTPPreconditionFailed(request=req)
elif copy_resp.status_int // 100 != 2:
elif not is_success(copy_resp.status_int):
# could not copy the data, bail
return HTTPServiceUnavailable(request=req)
@ -1238,7 +1247,7 @@ class ObjectController(Controller):
self.object_name = src_obj_name
self.container_name = src_container_name
source_resp = self.GET(source_req)
if source_resp.status_int >= 300:
if source_resp.status_int >= HTTP_MULTIPLE_CHOICES:
return source_resp
self.object_name = orig_obj_name
self.container_name = orig_container_name
@ -1332,12 +1341,12 @@ class ObjectController(Controller):
req.client_disconnect = True
self.app.logger.exception(
_('ERROR Exception causing client disconnect'))
return Response(status='499 Client Disconnect')
return HTTPClientDisconnect(request=req)
if req.content_length and req.bytes_transferred < req.content_length:
req.client_disconnect = True
self.app.logger.warn(
_('Client disconnected without sending enough data'))
return Response(status='499 Client Disconnect')
return HTTPClientDisconnect(request=req)
statuses = []
reasons = []
bodies = []
@ -1349,12 +1358,12 @@ class ObjectController(Controller):
statuses.append(response.status)
reasons.append(response.reason)
bodies.append(response.read())
if response.status >= 500:
if response.status >= HTTP_INTERNAL_SERVER_ERROR:
self.error_occurred(conn.node,
_('ERROR %(status)d %(body)s From Object Server ' \
're: %(path)s') % {'status': response.status,
'body': bodies[-1][:1024], 'path': req.path})
elif 200 <= response.status < 300:
elif is_success(response.status):
etags.add(response.getheader('etag').strip('"'))
except (Exception, Timeout):
self.exception_occurred(conn.node, _('Object'),
@ -1365,7 +1374,7 @@ class ObjectController(Controller):
return HTTPServerError(request=req)
etag = len(etags) and etags.pop() or None
while len(statuses) < len(nodes):
statuses.append(503)
statuses.append(HTTP_SERVICE_UNAVAILABLE)
reasons.append('')
bodies.append('')
resp = self.best_response(req, statuses, reasons, bodies,
@ -1426,10 +1435,10 @@ class ObjectController(Controller):
creq = Request.blank(copy_path, headers=copy_headers,
environ=copy_environ)
copy_resp = self.COPY(creq)
if copy_resp.status_int // 100 == 4:
if is_client_error(copy_resp.status_int):
# some user error, maybe permissions
return HTTPPreconditionFailed(request=req)
elif copy_resp.status_int // 100 != 2:
elif not is_success(copy_resp.status_int):
# could not copy the data, bail
return HTTPServiceUnavailable(request=req)
# reset these because the COPY changed them
@ -1666,7 +1675,8 @@ class ContainerController(Controller):
self.app.memcache.delete(cache_key)
resp = self.make_requests(req, self.app.container_ring,
container_partition, 'DELETE', req.path_info, headers)
if resp.status_int == 202: # Indicates no server had the container
# Indicates no server had the container
if resp.status_int == HTTP_ACCEPTED:
return HTTPNotFound(request=req)
return resp
@ -1685,7 +1695,7 @@ class AccountController(Controller):
shuffle(nodes)
resp = self.GETorHEAD_base(req, _('Account'), partition, nodes,
req.path_info.rstrip('/'), self.app.account_ring.replica_count)
if resp.status_int == 404 and self.app.account_autocreate:
if resp.status_int == HTTP_NOT_FOUND and self.app.account_autocreate:
if len(self.account_name) > MAX_ACCOUNT_NAME_LENGTH:
resp = HTTPBadRequest(request=req)
resp.body = 'Account name length of %d longer than %d' % \
@ -1698,7 +1708,7 @@ class AccountController(Controller):
Request.blank('/v1/' + self.account_name),
self.app.account_ring, partition, 'PUT',
'/' + self.account_name, [headers] * len(nodes))
if resp.status_int // 100 != 2:
if not is_success(resp.status_int):
raise Exception('Could not autocreate account %r' %
self.account_name)
resp = self.GETorHEAD_base(req, _('Account'), partition, nodes,
@ -1746,7 +1756,7 @@ class AccountController(Controller):
resp = self.make_requests(req, self.app.account_ring,
account_partition, 'POST', req.path_info,
[headers] * len(accounts))
if resp.status_int == 404 and self.app.account_autocreate:
if resp.status_int == HTTP_NOT_FOUND and self.app.account_autocreate:
if len(self.account_name) > MAX_ACCOUNT_NAME_LENGTH:
resp = HTTPBadRequest(request=req)
resp.body = 'Account name length of %d longer than %d' % \
@ -1756,7 +1766,7 @@ class AccountController(Controller):
Request.blank('/v1/' + self.account_name),
self.app.account_ring, account_partition, 'PUT',
'/' + self.account_name, [headers] * len(accounts))
if resp.status_int // 100 != 2:
if not is_success(resp.status_int):
raise Exception('Could not autocreate account %r' %
self.account_name)
return resp
@ -1996,7 +2006,7 @@ class Application(BaseApplication):
status_int = response.status_int
if getattr(req, 'client_disconnect', False) or \
getattr(response, 'client_disconnect', False):
status_int = 499
status_int = HTTP_CLIENT_CLOSED_REQUEST
self.access_logger.info(' '.join(quote(str(x)) for x in (
client or '-',
req.remote_addr or '-',