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, \ from swift.common.constraints import ACCOUNT_LISTING_LIMIT, \
check_mount, check_float, check_utf8 check_mount, check_float, check_utf8
from swift.common.db_replicator import ReplicatorRpc from swift.common.db_replicator import ReplicatorRpc
from swift.common.http import HTTPInsufficientStorage
DATADIR = 'accounts' DATADIR = 'accounts'
@ -70,7 +71,7 @@ class AccountController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain', return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req) request=req)
if self.mount_check and not check_mount(self.root, drive): 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 \ if 'x-timestamp' not in req.headers or \
not check_float(req.headers['x-timestamp']): not check_float(req.headers['x-timestamp']):
return HTTPBadRequest(body='Missing timestamp', request=req, return HTTPBadRequest(body='Missing timestamp', request=req,
@ -90,7 +91,7 @@ class AccountController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain', return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req) request=req)
if self.mount_check and not check_mount(self.root, drive): 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 = self._get_account_broker(drive, part, account)
if container: # put account container if container: # put account container
if 'x-trans-id' in req.headers: if 'x-trans-id' in req.headers:
@ -149,7 +150,7 @@ class AccountController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain', return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req) request=req)
if self.mount_check and not check_mount(self.root, drive): 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 = self._get_account_broker(drive, part, account)
if not container: if not container:
broker.pending_timeout = 0.1 broker.pending_timeout = 0.1
@ -180,7 +181,7 @@ class AccountController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain', return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req) request=req)
if self.mount_check and not check_mount(self.root, drive): 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 = self._get_account_broker(drive, part, account)
broker.pending_timeout = 0.1 broker.pending_timeout = 0.1
broker.stale_reads_ok = True broker.stale_reads_ok = True
@ -274,7 +275,7 @@ class AccountController(object):
request=req) request=req)
drive, partition, hash = post_args drive, partition, hash = post_args
if self.mount_check and not check_mount(self.root, drive): 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: try:
args = simplejson.load(req.environ['wsgi.input']) args = simplejson.load(req.environ['wsgi.input'])
except ValueError, err: except ValueError, err:
@ -295,7 +296,7 @@ class AccountController(object):
return HTTPBadRequest(body='Missing or bad timestamp', return HTTPBadRequest(body='Missing or bad timestamp',
request=req, content_type='text/plain') request=req, content_type='text/plain')
if self.mount_check and not check_mount(self.root, drive): 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 = self._get_account_broker(drive, part, account)
if broker.is_deleted(): if broker.is_deleted():
return HTTPNotFound(request=req) 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.utils import TRUE_VALUES
from swift.common import client from swift.common import client
from swift.common import direct_client from swift.common import direct_client
from swift.common.http import HTTP_CONFLICT
class ConnectionPool(eventlet.pools.Pool): class ConnectionPool(eventlet.pools.Pool):
@ -152,7 +153,7 @@ class BenchDELETE(Bench):
try: try:
client.delete_container(self.url, self.token, container) client.delete_container(self.url, self.token, container)
except client.ClientException, e: except client.ClientException, e:
if e.http_status != 409: if e.http_status != HTTP_CONFLICT:
self._log_status("Unable to delete container '%s'. " \ self._log_status("Unable to delete container '%s'. " \
"Got http status '%d'." % (container, e.http_status)) "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.bufferedhttp import http_connect
from swift.common.client import ClientException, json_loads from swift.common.client import ClientException, json_loads
from swift.common.utils import normalize_timestamp 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='/'): def quote(value, safe='/'):
@ -69,7 +71,7 @@ def direct_get_account(node, part, account, marker=None, limit=None,
'GET', path, query_string=qs) 'GET', path, query_string=qs)
with Timeout(response_timeout): with Timeout(response_timeout):
resp = conn.getresponse() resp = conn.getresponse()
if resp.status < 200 or resp.status >= 300: if not is_success(resp.status):
resp.read() resp.read()
raise ClientException( raise ClientException(
'Account server %s:%s direct GET %s gave status %s' % (node['ip'], '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 = {} resp_headers = {}
for header, value in resp.getheaders(): for header, value in resp.getheaders():
resp_headers[header.lower()] = value resp_headers[header.lower()] = value
if resp.status == 204: if resp.status == HTTP_NO_CONTENT:
resp.read() resp.read()
return resp_headers, [] return resp_headers, []
return resp_headers, json_loads(resp.read()) 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): with Timeout(response_timeout):
resp = conn.getresponse() resp = conn.getresponse()
resp.read() resp.read()
if resp.status < 200 or resp.status >= 300: if not is_success(resp.status):
raise ClientException( raise ClientException(
'Container server %s:%s direct HEAD %s gave status %s' % 'Container server %s:%s direct HEAD %s gave status %s' %
(node['ip'], node['port'], (node['ip'], node['port'],
@ -157,7 +159,7 @@ def direct_get_container(node, part, account, container, marker=None,
'GET', path, query_string=qs) 'GET', path, query_string=qs)
with Timeout(response_timeout): with Timeout(response_timeout):
resp = conn.getresponse() resp = conn.getresponse()
if resp.status < 200 or resp.status >= 300: if not is_success(resp.status):
resp.read() resp.read()
raise ClientException( raise ClientException(
'Container server %s:%s direct GET %s gave stats %s' % (node['ip'], '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 = {} resp_headers = {}
for header, value in resp.getheaders(): for header, value in resp.getheaders():
resp_headers[header.lower()] = value resp_headers[header.lower()] = value
if resp.status == 204: if resp.status == HTTP_NO_CONTENT:
resp.read() resp.read()
return resp_headers, [] return resp_headers, []
return resp_headers, json_loads(resp.read()) 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): with Timeout(response_timeout):
resp = conn.getresponse() resp = conn.getresponse()
resp.read() resp.read()
if resp.status < 200 or resp.status >= 300: if not is_success(resp.status):
raise ClientException( raise ClientException(
'Container server %s:%s direct DELETE %s gave status %s' % 'Container server %s:%s direct DELETE %s gave status %s' %
(node['ip'], node['port'], (node['ip'], node['port'],
@ -218,7 +220,7 @@ def direct_head_object(node, part, account, container, obj, conn_timeout=5,
with Timeout(response_timeout): with Timeout(response_timeout):
resp = conn.getresponse() resp = conn.getresponse()
resp.read() resp.read()
if resp.status < 200 or resp.status >= 300: if not is_success(resp.status):
raise ClientException( raise ClientException(
'Object server %s:%s direct HEAD %s gave status %s' % 'Object server %s:%s direct HEAD %s gave status %s' %
(node['ip'], node['port'], (node['ip'], node['port'],
@ -256,7 +258,7 @@ def direct_get_object(node, part, account, container, obj, conn_timeout=5,
'GET', path, headers=headers) 'GET', path, headers=headers)
with Timeout(response_timeout): with Timeout(response_timeout):
resp = conn.getresponse() resp = conn.getresponse()
if resp.status < 200 or resp.status >= 300: if not is_success(resp.status):
resp.read() resp.read()
raise ClientException( raise ClientException(
'Object server %s:%s direct GET %s gave status %s' % '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): with Timeout(response_timeout):
resp = conn.getresponse() resp = conn.getresponse()
resp.read() resp.read()
if resp.status < 200 or resp.status >= 300: if not is_success(resp.status):
raise ClientException( raise ClientException(
'Object server %s:%s direct PUT %s gave status %s' % 'Object server %s:%s direct PUT %s gave status %s' %
(node['ip'], node['port'], (node['ip'], node['port'],
@ -361,7 +363,7 @@ def direct_post_object(node, part, account, container, name, headers,
with Timeout(response_timeout): with Timeout(response_timeout):
resp = conn.getresponse() resp = conn.getresponse()
resp.read() resp.read()
if resp.status < 200 or resp.status >= 300: if not is_success(resp.status):
raise ClientException( raise ClientException(
'Object server %s:%s direct POST %s gave status %s' % 'Object server %s:%s direct POST %s gave status %s' %
(node['ip'], node['port'], (node['ip'], node['port'],
@ -394,7 +396,7 @@ def direct_delete_object(node, part, account, container, obj,
with Timeout(response_timeout): with Timeout(response_timeout):
resp = conn.getresponse() resp = conn.getresponse()
resp.read() resp.read()
if resp.status < 200 or resp.status >= 300: if not is_success(resp.status):
raise ClientException( raise ClientException(
'Object server %s:%s direct DELETE %s gave status %s' % 'Object server %s:%s direct DELETE %s gave status %s' %
(node['ip'], node['port'], (node['ip'], node['port'],
@ -440,8 +442,8 @@ def retry(func, *args, **kwargs):
except ClientException, err: except ClientException, err:
if error_log: if error_log:
error_log(err) error_log(err)
if attempts > retries or err.http_status < 500 or \ if attempts > retries or not is_server_error(err.http_status) or \
err.http_status == 507 or err.http_status > 599: err.http_status == HTTP_INSUFFICIENT_STORAGE:
raise raise
sleep(backoff) sleep(backoff)
backoff *= 2 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.utils import get_logger, streq_const_time
from swift.common.wsgi import make_pre_authed_env 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. #: 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, return self._translate_form(env, start_response,
attrs['boundary']) attrs['boundary'])
except (FormInvalid, EOFError), err: except (FormInvalid, EOFError), err:
self._log_request(env, 400) self._log_request(env, HTTP_BAD_REQUEST)
body = 'FormPost: %s' % err body = 'FormPost: %s' % err
start_response('400 Bad Request', start_response('400 Bad Request',
(('Content-Type', 'text/plain'), (('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 split_path, TRUE_VALUES
from swift.common.wsgi import make_pre_authed_env, make_pre_authed_request, \ from swift.common.wsgi import make_pre_authed_env, make_pre_authed_request, \
WSGIContext WSGIContext
from swift.common.http import is_success, is_redirection, HTTP_NOT_FOUND
def quote(value, safe='/'): def quote(value, safe='/'):
@ -183,7 +184,7 @@ class _StaticWebContext(WSGIContext):
'/%s/%s/%s/%s%s' % (self.version, self.account, self.container, '/%s/%s/%s/%s%s' % (self.version, self.account, self.container,
self._get_status_int(), self._error), self._get_status_int(), self._error),
self.agent)) self.agent))
if self._get_status_int() // 100 == 2: if is_success(self._get_status_int()):
start_response(save_response_status, self._response_headers, start_response(save_response_status, self._response_headers,
self._response_exc_info) self._response_exc_info)
return resp return resp
@ -213,7 +214,7 @@ class _StaticWebContext(WSGIContext):
resp = make_pre_authed_request(env, 'HEAD', resp = make_pre_authed_request(env, 'HEAD',
'/%s/%s/%s' % (self.version, self.account, self.container), '/%s/%s/%s' % (self.version, self.account, self.container),
agent=self.agent).get_response(self.app) agent=self.agent).get_response(self.app)
if resp.status_int // 100 == 2: if is_success(resp.status_int):
self._index = \ self._index = \
resp.headers.get('x-container-meta-web-index', '').strip() resp.headers.get('x-container-meta-web-index', '').strip()
self._error = \ self._error = \
@ -249,7 +250,7 @@ class _StaticWebContext(WSGIContext):
else: else:
prefix = '' prefix = ''
resp = self._app_call(tmp_env) 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) return self._error_response(resp, env, start_response)
listing = None listing = None
body = ''.join(resp) body = ''.join(resp)
@ -363,9 +364,10 @@ class _StaticWebContext(WSGIContext):
tmp_env['PATH_INFO'] += self._index tmp_env['PATH_INFO'] += self._index
resp = self._app_call(tmp_env) resp = self._app_call(tmp_env)
status_int = self._get_status_int() status_int = self._get_status_int()
if status_int == 404: if status_int == HTTP_NOT_FOUND:
return self._listing(env, start_response) 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) return self._error_response(resp, env, start_response)
start_response(self._response_status, self._response_headers, start_response(self._response_status, self._response_headers,
self._response_exc_info) self._response_exc_info)
@ -384,16 +386,16 @@ class _StaticWebContext(WSGIContext):
'%s StaticWeb' % env.get('HTTP_USER_AGENT') '%s StaticWeb' % env.get('HTTP_USER_AGENT')
resp = self._app_call(tmp_env) resp = self._app_call(tmp_env)
status_int = self._get_status_int() 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, start_response(self._response_status, self._response_headers,
self._response_exc_info) self._response_exc_info)
return resp return resp
if status_int != 404: if status_int != HTTP_NOT_FOUND:
return self._error_response(resp, env, start_response) return self._error_response(resp, env, start_response)
self._get_container_info(env) self._get_container_info(env)
if not self._listings and not self._index: if not self._listings and not self._index:
return self.app(env, start_response) return self.app(env, start_response)
status_int = 404 status_int = HTTP_NOT_FOUND
if self._index: if self._index:
tmp_env = dict(env) tmp_env = dict(env)
tmp_env['HTTP_USER_AGENT'] = \ tmp_env['HTTP_USER_AGENT'] = \
@ -403,7 +405,7 @@ class _StaticWebContext(WSGIContext):
tmp_env['PATH_INFO'] += self._index tmp_env['PATH_INFO'] += self._index
resp = self._app_call(tmp_env) resp = self._app_call(tmp_env)
status_int = self._get_status_int() 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] != '/': if env['PATH_INFO'][-1] != '/':
resp = HTTPMovedPermanently( resp = HTTPMovedPermanently(
location=env['PATH_INFO'] + '/') location=env['PATH_INFO'] + '/')
@ -412,7 +414,7 @@ class _StaticWebContext(WSGIContext):
start_response(self._response_status, self._response_headers, start_response(self._response_status, self._response_headers,
self._response_exc_info) self._response_exc_info)
return resp return resp
if status_int == 404: if status_int == HTTP_NOT_FOUND:
if env['PATH_INFO'][-1] != '/': if env['PATH_INFO'][-1] != '/':
tmp_env = make_pre_authed_env(env, 'GET', tmp_env = make_pre_authed_env(env, 'GET',
'/%s/%s/%s' % (self.version, self.account, '/%s/%s/%s' % (self.version, self.account,
@ -422,7 +424,7 @@ class _StaticWebContext(WSGIContext):
'=/&limit=1&prefix=%s' % quote(self.obj + '/') '=/&limit=1&prefix=%s' % quote(self.obj + '/')
resp = self._app_call(tmp_env) resp = self._app_call(tmp_env)
body = ''.join(resp) 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): not json.loads(body):
resp = HTTPNotFound()(env, self._start_response) resp = HTTPNotFound()(env, self._start_response)
return self._error_response(resp, env, 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.utils import split_path
from swift.common.wsgi import WSGIContext 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 MAX_BUCKET_LISTING = 1000
@ -74,24 +77,24 @@ def get_err_response(code):
""" """
error_table = { error_table = {
'AccessDenied': 'AccessDenied':
(403, 'Access denied'), (HTTP_FORBIDDEN, 'Access denied'),
'BucketAlreadyExists': 'BucketAlreadyExists':
(409, 'The requested bucket name is not available'), (HTTP_CONFLICT, 'The requested bucket name is not available'),
'BucketNotEmpty': 'BucketNotEmpty':
(409, 'The bucket you tried to delete is not empty'), (HTTP_CONFLICT, 'The bucket you tried to delete is not empty'),
'InvalidArgument': 'InvalidArgument':
(400, 'Invalid Argument'), (HTTP_BAD_REQUEST, 'Invalid Argument'),
'InvalidBucketName': 'InvalidBucketName':
(400, 'The specified bucket is not valid'), (HTTP_BAD_REQUEST, 'The specified bucket is not valid'),
'InvalidURI': 'InvalidURI':
(400, 'Could not parse the specified URI'), (HTTP_BAD_REQUEST, 'Could not parse the specified URI'),
'NoSuchBucket': 'NoSuchBucket':
(404, 'The specified bucket does not exist'), (HTTP_NOT_FOUND, 'The specified bucket does not exist'),
'SignatureDoesNotMatch': 'SignatureDoesNotMatch':
(403, 'The calculated request signature does not match '\ (HTTP_FORBIDDEN, 'The calculated request signature does not '\
'your provided one'), 'match your provided one'),
'NoSuchKey': '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 = Response(content_type='text/xml')
resp.status = error_table[code][0] resp.status = error_table[code][0]
@ -169,8 +172,8 @@ class ServiceController(WSGIContext):
body_iter = self._app_call(env) body_iter = self._app_call(env)
status = self._get_status_int() status = self._get_status_int()
if status != 200: if status != HTTP_OK:
if status == 401: if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied') return get_err_response('AccessDenied')
else: else:
return get_err_response('InvalidURI') return get_err_response('InvalidURI')
@ -186,7 +189,8 @@ class ServiceController(WSGIContext):
% ("".join(['<Bucket><Name>%s</Name><CreationDate>' \ % ("".join(['<Bucket><Name>%s</Name><CreationDate>' \
'2009-02-03T16:45:09.000Z</CreationDate></Bucket>' % '2009-02-03T16:45:09.000Z</CreationDate></Bucket>' %
xml_escape(i['name']) for i in containers])) 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 return resp
@ -222,10 +226,10 @@ class BucketController(WSGIContext):
body_iter = self._app_call(env) body_iter = self._app_call(env)
status = self._get_status_int() status = self._get_status_int()
if status != 200: if status != HTTP_OK:
if status == 401: if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied') return get_err_response('AccessDenied')
elif status == 404: elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchBucket') return get_err_response('NoSuchBucket')
else: else:
return get_err_response('InvalidURI') return get_err_response('InvalidURI')
@ -271,17 +275,17 @@ class BucketController(WSGIContext):
body_iter = self._app_call(env) body_iter = self._app_call(env)
status = self._get_status_int() status = self._get_status_int()
if status != 201: if status != HTTP_CREATED:
if status == 401: if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied') return get_err_response('AccessDenied')
elif status == 202: elif status == HTTP_ACCEPTED:
return get_err_response('BucketAlreadyExists') return get_err_response('BucketAlreadyExists')
else: else:
return get_err_response('InvalidURI') return get_err_response('InvalidURI')
resp = Response() resp = Response()
resp.headers.add('Location', self.container_name) resp.headers.add('Location', self.container_name)
resp.status = 200 resp.status = HTTP_OK
return resp return resp
def DELETE(self, env, start_response): def DELETE(self, env, start_response):
@ -291,18 +295,18 @@ class BucketController(WSGIContext):
body_iter = self._app_call(env) body_iter = self._app_call(env)
status = self._get_status_int() status = self._get_status_int()
if status != 204: if status != HTTP_NO_CONTENT:
if status == 401: if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied') return get_err_response('AccessDenied')
elif status == 404: elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchBucket') return get_err_response('NoSuchBucket')
elif status == 409: elif status == HTTP_CONFLICT:
return get_err_response('BucketNotEmpty') return get_err_response('BucketNotEmpty')
else: else:
return get_err_response('InvalidURI') return get_err_response('InvalidURI')
resp = Response() resp = Response()
resp.status = 204 resp.status = HTTP_NO_CONTENT
return resp return resp
@ -324,7 +328,7 @@ class ObjectController(WSGIContext):
status = self._get_status_int() status = self._get_status_int()
headers = dict(self._response_headers) headers = dict(self._response_headers)
if 200 <= status < 300: if is_success(status):
if 'QUERY_STRING' in env: if 'QUERY_STRING' in env:
args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1)) args = dict(urlparse.parse_qsl(env['QUERY_STRING'], 1))
else: else:
@ -342,9 +346,9 @@ class ObjectController(WSGIContext):
'etag', 'last-modified'): 'etag', 'last-modified'):
new_hdrs[key] = val new_hdrs[key] = val
return Response(status=status, headers=new_hdrs, app_iter=app_iter) return Response(status=status, headers=new_hdrs, app_iter=app_iter)
elif status == 401: elif status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied') return get_err_response('AccessDenied')
elif status == 404: elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchKey') return get_err_response('NoSuchKey')
else: else:
return get_err_response('InvalidURI') return get_err_response('InvalidURI')
@ -377,10 +381,10 @@ class ObjectController(WSGIContext):
body_iter = self._app_call(env) body_iter = self._app_call(env)
status = self._get_status_int() status = self._get_status_int()
if status != 201: if status != HTTP_CREATED:
if status == 401: if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied') return get_err_response('AccessDenied')
elif status == 404: elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchBucket') return get_err_response('NoSuchBucket')
else: else:
return get_err_response('InvalidURI') return get_err_response('InvalidURI')
@ -389,7 +393,7 @@ class ObjectController(WSGIContext):
body = '<CopyObjectResult>' \ body = '<CopyObjectResult>' \
'<ETag>"%s"</ETag>' \ '<ETag>"%s"</ETag>' \
'</CopyObjectResult>' % self._response_header_value('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')) return Response(status=200, etag=self._response_header_value('etag'))
@ -400,16 +404,16 @@ class ObjectController(WSGIContext):
body_iter = self._app_call(env) body_iter = self._app_call(env)
status = self._get_status_int() status = self._get_status_int()
if status != 204: if status != HTTP_NO_CONTENT:
if status == 401: if status == HTTP_UNAUTHORIZED:
return get_err_response('AccessDenied') return get_err_response('AccessDenied')
elif status == 404: elif status == HTTP_NOT_FOUND:
return get_err_response('NoSuchKey') return get_err_response('NoSuchKey')
else: else:
return get_err_response('InvalidURI') return get_err_response('InvalidURI')
resp = Response() resp = Response()
resp.status = 204 resp.status = HTTP_NO_CONTENT
return resp 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.middleware.acl import clean_acl, parse_acl, referrer_allowed
from swift.common.utils import cache_from_env, get_logger, get_remote_client, \ from swift.common.utils import cache_from_env, get_logger, get_remote_client, \
split_path, TRUE_VALUES split_path, TRUE_VALUES
from swift.common.http import HTTP_CLIENT_CLOSED_REQUEST
class TempAuth(object): class TempAuth(object):
@ -458,7 +459,7 @@ class TempAuth(object):
status_int = response.status_int status_int = response.status_int
if getattr(req, 'client_disconnect', False) or \ if getattr(req, 'client_disconnect', False) or \
getattr(response, 'client_disconnect', False): 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 '-', 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.remote_addr or '-', strftime('%d/%b/%Y/%H/%M/%S', gmtime()),
req.method, the_request, req.environ['SERVER_PROTOCOL'], 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.utils import get_logger
from swift.common.wsgi import make_pre_authed_env 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 #: 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. :param start_response: The WSGI start_response hook.
:returns: 401 response as per WSGI. :returns: 401 response as per WSGI.
""" """
self._log_request(env, 401) self._log_request(env, HTTP_UNAUTHORIZED)
body = '401 Unauthorized: Temp URL invalid\n' body = '401 Unauthorized: Temp URL invalid\n'
start_response('401 Unauthorized', start_response('401 Unauthorized',
[('Content-Type', 'text/plain'), [('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.bufferedhttp import http_connect
from swift.common.exceptions import ConnectionTimeout from swift.common.exceptions import ConnectionTimeout
from swift.common.db_replicator import ReplicatorRpc from swift.common.db_replicator import ReplicatorRpc
from swift.common.http import HTTP_NOT_FOUND, is_success, \
HTTPInsufficientStorage
DATADIR = 'containers' DATADIR = 'containers'
@ -119,10 +121,9 @@ class ContainerController(object):
with Timeout(self.node_timeout): with Timeout(self.node_timeout):
account_response = conn.getresponse() account_response = conn.getresponse()
account_response.read() account_response.read()
if account_response.status == 404: if account_response.status == HTTP_NOT_FOUND:
return HTTPNotFound(request=req) return HTTPNotFound(request=req)
elif account_response.status < 200 or \ elif not is_success(account_response.status):
account_response.status > 299:
self.logger.error(_('ERROR Account update failed ' self.logger.error(_('ERROR Account update failed '
'with %(ip)s:%(port)s/%(device)s (will retry ' 'with %(ip)s:%(port)s/%(device)s (will retry '
'later): Response %(status)s %(reason)s'), 'later): Response %(status)s %(reason)s'),
@ -150,7 +151,7 @@ class ContainerController(object):
return HTTPBadRequest(body='Missing timestamp', request=req, return HTTPBadRequest(body='Missing timestamp', request=req,
content_type='text/plain') content_type='text/plain')
if self.mount_check and not check_mount(self.root, drive): 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 = self._get_container_broker(drive, part, account, container)
if account.startswith(self.auto_create_account_prefix) and obj and \ if account.startswith(self.auto_create_account_prefix) and obj and \
not os.path.exists(broker.db_file): not os.path.exists(broker.db_file):
@ -195,7 +196,7 @@ class ContainerController(object):
if err: if err:
return HTTPBadRequest(err) return HTTPBadRequest(err)
if self.mount_check and not check_mount(self.root, drive): 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']) timestamp = normalize_timestamp(req.headers['x-timestamp'])
broker = self._get_container_broker(drive, part, account, container) broker = self._get_container_broker(drive, part, account, container)
if obj: # put container object if obj: # put container object
@ -245,7 +246,7 @@ class ContainerController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain', return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req) request=req)
if self.mount_check and not check_mount(self.root, drive): 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 = self._get_container_broker(drive, part, account, container)
broker.pending_timeout = 0.1 broker.pending_timeout = 0.1
broker.stale_reads_ok = True broker.stale_reads_ok = True
@ -273,7 +274,7 @@ class ContainerController(object):
return HTTPBadRequest(body=str(err), content_type='text/plain', return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req) request=req)
if self.mount_check and not check_mount(self.root, drive): 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 = self._get_container_broker(drive, part, account, container)
broker.pending_timeout = 0.1 broker.pending_timeout = 0.1
broker.stale_reads_ok = True broker.stale_reads_ok = True
@ -388,7 +389,7 @@ class ContainerController(object):
request=req) request=req)
drive, partition, hash = post_args drive, partition, hash = post_args
if self.mount_check and not check_mount(self.root, drive): 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: try:
args = simplejson.load(req.environ['wsgi.input']) args = simplejson.load(req.environ['wsgi.input'])
except ValueError, err: except ValueError, err:
@ -414,7 +415,7 @@ class ContainerController(object):
if err: if err:
return HTTPBadRequest(err) return HTTPBadRequest(err)
if self.mount_check and not check_mount(self.root, drive): 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 = self._get_container_broker(drive, part, account, container)
if broker.is_deleted(): if broker.is_deleted():
return HTTPNotFound(request=req) 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, \ from swift.common.utils import audit_location_generator, get_logger, \
hash_path, TRUE_VALUES, validate_sync_to, whataremyips hash_path, TRUE_VALUES, validate_sync_to, whataremyips
from swift.common.daemon import Daemon from swift.common.daemon import Daemon
from swift.common.http import HTTP_UNAUTHORIZED, HTTP_NOT_FOUND
class _Iter2FileLikeObject(object): class _Iter2FileLikeObject(object):
@ -349,7 +350,7 @@ class ContainerSync(Daemon):
'x-container-sync-key': sync_key}, 'x-container-sync-key': sync_key},
proxy=self.proxy) proxy=self.proxy)
except ClientException, err: except ClientException, err:
if err.http_status != 404: if err.http_status != HTTP_NOT_FOUND:
raise raise
self.container_deletes += 1 self.container_deletes += 1
else: else:
@ -376,7 +377,7 @@ class ContainerSync(Daemon):
# non-404 one. We don't want to mistakenly assume the # non-404 one. We don't want to mistakenly assume the
# object no longer exists just because one says so and # object no longer exists just because one says so and
# the others errored for some other reason. # 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 exc = err
if timestamp < looking_for_timestamp: if timestamp < looking_for_timestamp:
if exc: if exc:
@ -398,13 +399,13 @@ class ContainerSync(Daemon):
contents=_Iter2FileLikeObject(body), proxy=self.proxy) contents=_Iter2FileLikeObject(body), proxy=self.proxy)
self.container_puts += 1 self.container_puts += 1
except ClientException, err: except ClientException, err:
if err.http_status == 401: if err.http_status == HTTP_UNAUTHORIZED:
self.logger.info(_('Unauth %(sync_from)r ' self.logger.info(_('Unauth %(sync_from)r '
'=> %(sync_to)r'), '=> %(sync_to)r'),
{'sync_from': '%s/%s' % {'sync_from': '%s/%s' %
(quote(info['account']), quote(info['container'])), (quote(info['account']), quote(info['container'])),
'sync_to': sync_to}) 'sync_to': sync_to})
elif err.http_status == 404: elif err.http_status == HTTP_NOT_FOUND:
self.logger.info(_('Not found %(sync_from)r ' self.logger.info(_('Not found %(sync_from)r '
'=> %(sync_to)r'), '=> %(sync_to)r'),
{'sync_from': '%s/%s' % {'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.ring import Ring
from swift.common.utils import get_logger, TRUE_VALUES from swift.common.utils import get_logger, TRUE_VALUES
from swift.common.daemon import Daemon from swift.common.daemon import Daemon
from swift.common.http import is_success, HTTP_INTERNAL_SERVER_ERROR
class ContainerUpdater(Daemon): class ContainerUpdater(Daemon):
@ -214,7 +215,7 @@ class ContainerUpdater(Daemon):
successes = 0 successes = 0
failures = 0 failures = 0
for event in events: for event in events:
if 200 <= event.wait() < 300: if is_success(event.wait()):
successes += 1 successes += 1
else: else:
failures += 1 failures += 1
@ -265,7 +266,7 @@ class ContainerUpdater(Daemon):
except (Exception, Timeout): except (Exception, Timeout):
self.logger.exception(_('ERROR account update failed with ' self.logger.exception(_('ERROR account update failed with '
'%(ip)s:%(port)s/%(device)s (will retry later): '), node) '%(ip)s:%(port)s/%(device)s (will retry later): '), node)
return 500 return HTTP_INTERNAL_SERVER_ERROR
with Timeout(self.node_timeout): with Timeout(self.node_timeout):
try: try:
resp = conn.getresponse() resp = conn.getresponse()
@ -275,4 +276,4 @@ class ContainerUpdater(Daemon):
if self.logger.getEffectiveLevel() <= logging.DEBUG: if self.logger.getEffectiveLevel() <= logging.DEBUG:
self.logger.exception( self.logger.exception(
_('Exception with %(ip)s:%(port)s/%(device)s'), node) _('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.daemon import Daemon
from swift.common.utils import get_logger from swift.common.utils import get_logger
from swift.common.http import HTTP_NO_CONTENT, HTTP_NOT_FOUND, HTTP_CONFLICT, \
HTTP_PRECONDITION_FAILED
try: try:
import simplejson as json import simplejson as json
@ -161,8 +163,9 @@ class ObjectExpirer(Daemon):
the hidden expiration account. the hidden expiration account.
""" """
resp = self.get_response('HEAD', resp = self.get_response('HEAD',
'/v1/' + quote(self.expiring_objects_account), {}, (2, 404)) '/v1/' + quote(self.expiring_objects_account), {},
if resp.status_int == 404: (2, HTTP_NOT_FOUND))
if resp.status_int == HTTP_NOT_FOUND:
return (0, 0) return (0, 0)
return (int(resp.headers['x-account-container-count']), return (int(resp.headers['x-account-container-count']),
int(resp.headers['x-account-object-count'])) int(resp.headers['x-account-object-count']))
@ -176,8 +179,8 @@ class ObjectExpirer(Daemon):
marker = '' marker = ''
while True: while True:
resp = self.get_response('GET', path + '&marker=' + quote(marker), resp = self.get_response('GET', path + '&marker=' + quote(marker),
{}, (2, 404)) {}, (2, HTTP_NOT_FOUND))
if resp.status_int in (204, 404): if resp.status_int in (HTTP_NO_CONTENT, HTTP_NOT_FOUND):
break break
data = json.loads(resp.body) data = json.loads(resp.body)
if not data: if not data:
@ -198,8 +201,8 @@ class ObjectExpirer(Daemon):
marker = '' marker = ''
while True: while True:
resp = self.get_response('GET', path + '&marker=' + quote(marker), resp = self.get_response('GET', path + '&marker=' + quote(marker),
{}, (2, 404)) {}, (2, HTTP_NOT_FOUND))
if resp.status_int in (204, 404): if resp.status_int in (HTTP_NO_CONTENT, HTTP_NOT_FOUND):
break break
data = json.loads(resp.body) data = json.loads(resp.body)
if not data: if not data:
@ -220,7 +223,8 @@ class ObjectExpirer(Daemon):
perform the actual delete. perform the actual delete.
""" """
self.get_response('DELETE', '/v1/%s' % (quote(actual_obj),), 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): def delete_object(self, container, obj):
""" """
@ -232,7 +236,7 @@ class ObjectExpirer(Daemon):
self.get_response('DELETE', self.get_response('DELETE',
'/v1/%s/%s/%s' % (quote(self.expiring_objects_account), '/v1/%s/%s/%s' % (quote(self.expiring_objects_account),
quote(container), quote(obj)), quote(container), quote(obj)),
{}, (2, 404)) {}, (2, HTTP_NOT_FOUND))
def delete_container(self, container): def delete_container(self, container):
""" """
@ -243,4 +247,4 @@ class ObjectExpirer(Daemon):
self.get_response('DELETE', self.get_response('DELETE',
'/v1/%s/%s' % (quote(self.expiring_objects_account), '/v1/%s/%s' % (quote(self.expiring_objects_account),
quote(container)), 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 TRUE_VALUES
from swift.common.bufferedhttp import http_connect from swift.common.bufferedhttp import http_connect
from swift.common.daemon import Daemon from swift.common.daemon import Daemon
from swift.common.http import HTTP_OK, HTTP_INSUFFICIENT_STORAGE
hubs.use_hub('poll') hubs.use_hub('poll')
@ -408,12 +409,12 @@ class ObjectReplicator(Daemon):
resp = http_connect(node['ip'], node['port'], resp = http_connect(node['ip'], node['port'],
node['device'], job['partition'], 'REPLICATE', node['device'], job['partition'], 'REPLICATE',
'', headers={'Content-Length': '0'}).getresponse() '', headers={'Content-Length': '0'}).getresponse()
if resp.status == 507: if resp.status == HTTP_INSUFFICIENT_STORAGE:
self.logger.error(_('%(ip)s/%(device)s responded' self.logger.error(_('%(ip)s/%(device)s responded'
' as unmounted'), node) ' as unmounted'), node)
attempts_left += 1 attempts_left += 1
continue continue
if resp.status != 200: if resp.status != HTTP_OK:
self.logger.error(_("Invalid response %(resp)s " self.logger.error(_("Invalid response %(resp)s "
"from %(ip)s"), "from %(ip)s"),
{'resp': resp.status, 'ip': node['ip']}) {'resp': resp.status, 'ip': node['ip']})

View File

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