From 791482675db0d1cc4c84d4776859319ff7caaac7 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 11 Sep 2018 17:59:11 -0500 Subject: [PATCH] Let error messages to be normal strings again This changes how we decided to handle HTTPBadRequest and friends. Previously, we came to forcing everything to be bytes, because obviously WSGI bodies can only be bytes. But it turned out to be too much hassle, so let's revisit that decision. We aren't going to back-convert all the bytes bodies. That is already too much hassle too. But this patch throws in a few examples, just to showcase what this patch does. Change-Id: I206a9611e7f348f49e5c2d0e677fed3b0739c167 --- swift/common/constraints.py | 38 ++++++++++++++++++------------------- swift/common/swob.py | 3 +++ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/swift/common/constraints.py b/swift/common/constraints.py index e1c4e7260e..8639279a71 100644 --- a/swift/common/constraints.py +++ b/swift/common/constraints.py @@ -139,12 +139,12 @@ def check_metadata(req, target_type): continue key = key[len(prefix):] if not key: - return HTTPBadRequest(body=b'Metadata name cannot be empty', + return HTTPBadRequest(body='Metadata name cannot be empty', request=req, content_type='text/plain') bad_key = not check_utf8(wsgi_to_str(key)) bad_value = value and not check_utf8(wsgi_to_str(value)) if target_type in ('account', 'container') and (bad_key or bad_value): - return HTTPBadRequest(body=b'Metadata must be valid UTF-8', + return HTTPBadRequest(body='Metadata must be valid UTF-8', request=req, content_type='text/plain') meta_count += 1 meta_size += len(key) + len(value) @@ -160,11 +160,11 @@ def check_metadata(req, target_type): request=req, content_type='text/plain') if meta_count > MAX_META_COUNT: return HTTPBadRequest( - body=b'Too many metadata items; max %d' % MAX_META_COUNT, + body='Too many metadata items; max %d' % MAX_META_COUNT, request=req, content_type='text/plain') if meta_size > MAX_META_OVERALL_SIZE: return HTTPBadRequest( - body=b'Total metadata too large; max %d' + body='Total metadata too large; max %d' % MAX_META_OVERALL_SIZE, request=req, content_type='text/plain') return None @@ -187,22 +187,22 @@ def check_object_creation(req, object_name): ml = req.message_length() except ValueError as e: return HTTPBadRequest(request=req, content_type='text/plain', - body=str(e).encode('ascii')) + body=str(e)) except AttributeError as e: return HTTPNotImplemented(request=req, content_type='text/plain', - body=str(e).encode('ascii')) + body=str(e)) if ml is not None and ml > MAX_FILE_SIZE: - return HTTPRequestEntityTooLarge(body=b'Your request is too large.', + return HTTPRequestEntityTooLarge(body='Your request is too large.', request=req, content_type='text/plain') if req.content_length is None and \ req.headers.get('transfer-encoding') != 'chunked': - return HTTPLengthRequired(body=b'Missing Content-Length header.', + return HTTPLengthRequired(body='Missing Content-Length header.', request=req, content_type='text/plain') if len(object_name) > MAX_OBJECT_NAME_LENGTH: - return HTTPBadRequest(body=b'Object name length of %d longer than %d' % + return HTTPBadRequest(body='Object name length of %d longer than %d' % (len(object_name), MAX_OBJECT_NAME_LENGTH), request=req, content_type='text/plain') @@ -217,7 +217,7 @@ def check_object_creation(req, object_name): content_type='text/plain') if not check_utf8(wsgi_to_str(req.headers['Content-Type'])): - return HTTPBadRequest(request=req, body=b'Invalid Content-Type', + return HTTPBadRequest(request=req, body='Invalid Content-Type', content_type='text/plain') return check_metadata(req, 'object') @@ -300,7 +300,7 @@ def valid_timestamp(request): try: return request.timestamp except exceptions.InvalidTimestamp as e: - raise HTTPBadRequest(body=str(e).encode('ascii'), request=request, + raise HTTPBadRequest(body=str(e), request=request, content_type='text/plain') @@ -325,13 +325,13 @@ def check_delete_headers(request): except ValueError: raise HTTPBadRequest(request=request, content_type='text/plain', - body=b'Non-integer X-Delete-After') + body='Non-integer X-Delete-After') actual_del_time = utils.normalize_delete_at_timestamp( now + x_delete_after) if int(actual_del_time) <= now: raise HTTPBadRequest(request=request, content_type='text/plain', - body=b'X-Delete-After in past') + body='X-Delete-After in past') request.headers['x-delete-at'] = actual_del_time del request.headers['x-delete-after'] @@ -341,12 +341,12 @@ def check_delete_headers(request): int(request.headers['x-delete-at']))) except ValueError: raise HTTPBadRequest(request=request, content_type='text/plain', - body=b'Non-integer X-Delete-At') + body='Non-integer X-Delete-At') if x_delete_at <= now and not utils.config_true_value( request.headers.get('x-backend-replication', 'f')): raise HTTPBadRequest(request=request, content_type='text/plain', - body=b'X-Delete-At in past') + body='X-Delete-At in past') return request @@ -407,19 +407,19 @@ def check_name_format(req, name, target_type): if not name: raise HTTPPreconditionFailed( request=req, - body=b'%s name cannot be empty' % target_type) + body='%s name cannot be empty' % target_type) if isinstance(name, six.text_type): name = name.encode('utf-8') if b'/' in name: raise HTTPPreconditionFailed( request=req, - body=b'%s name cannot contain slashes' % target_type) + body='%s name cannot contain slashes' % target_type) return name check_account_format = functools.partial(check_name_format, - target_type=b'Account') + target_type='Account') check_container_format = functools.partial(check_name_format, - target_type=b'Container') + target_type='Container') def valid_api_version(version): diff --git a/swift/common/swob.py b/swift/common/swob.py index 00e8b9a8fa..f1a9a2fca3 100644 --- a/swift/common/swob.py +++ b/swift/common/swob.py @@ -1179,6 +1179,9 @@ class Response(object): self._conditional_etag = conditional_etag self.request = request self._app_iter = None + # Allow error messages to come as natural strings on py3. + if isinstance(body, six.text_type): + body = body.encode('utf8') self.body = body self.app_iter = app_iter self.response_iter = None