S3 - Add more detail to error responses

This commit is contained in:
Bert Blommers 2020-10-28 14:22:18 +00:00
commit cc27f1ef0c
4 changed files with 67 additions and 5 deletions

View file

@ -14,6 +14,11 @@ ERROR_WITH_CONDITION_NAME = """{% extends 'single_error' %}
{% block extra %}<Condition>{{ condition }}</Condition>{% endblock %}
"""
ERROR_WITH_RANGE = """{% extends 'single_error' %}
{% block extra %}<ActualObjectSize>{{ actual_size }}</ActualObjectSize>
<RangeRequested>{{ range_requested }}</RangeRequested>{% endblock %}
"""
class S3ClientError(RESTError):
def __init__(self, *args, **kwargs):
@ -404,3 +409,18 @@ class PreconditionFailed(S3ClientError):
condition=failed_condition,
**kwargs
)
class InvalidRange(S3ClientError):
code = 416
def __init__(self, range_requested, actual_size, **kwargs):
kwargs.setdefault("template", "range_error")
self.templates["range_error"] = ERROR_WITH_RANGE
super(InvalidRange, self).__init__(
"InvalidRange",
"The requested range is not satisfiable",
range_requested=range_requested,
actual_size=actual_size,
**kwargs
)

View file

@ -37,6 +37,7 @@ from .exceptions import (
ObjectNotInActiveTierError,
NoSystemTags,
PreconditionFailed,
InvalidRange,
)
from .models import (
s3_backend,
@ -936,11 +937,15 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
else:
return 400, response_headers, ""
if begin < 0 or end > last or begin > min(end, last):
return 416, response_headers, ""
raise InvalidRange(
actual_size=str(length), range_requested=request.headers.get("range")
)
response_headers["content-range"] = "bytes {0}-{1}/{2}".format(
begin, end, length
)
return 206, response_headers, response_content[begin : end + 1]
content = response_content[begin : end + 1]
response_headers["content-length"] = len(content)
return 206, response_headers, content
def key_or_control_response(self, request, full_url, headers):
# Key and Control are lumped in because splitting out the regex is too much of a pain :/
@ -967,9 +972,12 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
status_code, response_headers, response_content = response
if status_code == 200 and "range" in request.headers:
return self._handle_range_header(
request, response_headers, response_content
)
try:
return self._handle_range_header(
request, response_headers, response_content
)
except S3ClientError as s3error:
return s3error.code, {}, s3error.description
return status_code, response_headers, response_content
def _control_response(self, request, full_url, headers):