612 lines
16 KiB
Python
612 lines
16 KiB
Python
from moto.core.exceptions import RESTError
|
|
|
|
ERROR_WITH_BUCKET_NAME = """{% extends 'single_error' %}
|
|
{% block extra %}<BucketName>{{ bucket }}</BucketName>{% endblock %}
|
|
"""
|
|
|
|
ERROR_WITH_KEY_NAME = """{% extends 'single_error' %}
|
|
{% block extra %}<Key>{{ key }}</Key>{% endblock %}
|
|
"""
|
|
|
|
ERROR_WITH_ARGUMENT = """{% extends 'single_error' %}
|
|
{% block extra %}<ArgumentName>{{ name }}</ArgumentName>
|
|
<ArgumentValue>{{ value }}</ArgumentValue>{% endblock %}
|
|
"""
|
|
|
|
ERROR_WITH_UPLOADID = """{% extends 'single_error' %}
|
|
{% block extra %}<UploadId>{{ upload_id }}</UploadId>{% endblock %}
|
|
"""
|
|
|
|
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 %}
|
|
"""
|
|
|
|
ERROR_WITH_STORAGE_CLASS = """{% extends 'single_error' %}
|
|
{% block extra %}<StorageClass>{{ storage_class }}</StorageClass>{% endblock %}
|
|
"""
|
|
|
|
|
|
class S3ClientError(RESTError):
|
|
# S3 API uses <RequestID> as the XML tag in response messages
|
|
request_id_tag_name = "RequestID"
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
kwargs.setdefault("template", "single_error")
|
|
self.templates["bucket_error"] = ERROR_WITH_BUCKET_NAME
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
|
class InvalidArgumentError(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, message, name, value, *args, **kwargs):
|
|
kwargs.setdefault("template", "argument_error")
|
|
kwargs["name"] = name
|
|
kwargs["value"] = value
|
|
self.templates["argument_error"] = ERROR_WITH_ARGUMENT
|
|
super().__init__("InvalidArgument", message, *args, **kwargs)
|
|
|
|
|
|
class BucketError(S3ClientError):
|
|
def __init__(self, *args, **kwargs):
|
|
kwargs.setdefault("template", "bucket_error")
|
|
self.templates["bucket_error"] = ERROR_WITH_BUCKET_NAME
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
|
class BucketAlreadyExists(BucketError):
|
|
code = 409
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
kwargs.setdefault("template", "bucket_error")
|
|
self.templates["bucket_error"] = ERROR_WITH_BUCKET_NAME
|
|
super().__init__(
|
|
"BucketAlreadyExists",
|
|
(
|
|
"The requested bucket name is not available. The bucket "
|
|
"namespace is shared by all users of the system. Please "
|
|
"select a different name and try again"
|
|
),
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class MissingBucket(BucketError):
|
|
code = 404
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"NoSuchBucket", "The specified bucket does not exist", *args, **kwargs
|
|
)
|
|
|
|
|
|
class MissingKey(S3ClientError):
|
|
code = 404
|
|
|
|
def __init__(self, **kwargs):
|
|
kwargs.setdefault("template", "key_error")
|
|
self.templates["key_error"] = ERROR_WITH_KEY_NAME
|
|
super().__init__("NoSuchKey", "The specified key does not exist.", **kwargs)
|
|
|
|
|
|
class MissingVersion(S3ClientError):
|
|
code = 404
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"NoSuchVersion", "The specified version does not exist.", *args, **kwargs
|
|
)
|
|
|
|
|
|
class InvalidVersion(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, version_id, *args, **kwargs):
|
|
kwargs.setdefault("template", "argument_error")
|
|
kwargs["name"] = "versionId"
|
|
kwargs["value"] = version_id
|
|
self.templates["argument_error"] = ERROR_WITH_ARGUMENT
|
|
super().__init__(
|
|
"InvalidArgument", "Invalid version id specified", *args, **kwargs
|
|
)
|
|
|
|
|
|
class ObjectNotInActiveTierError(S3ClientError):
|
|
code = 403
|
|
|
|
def __init__(self, key_name):
|
|
super().__init__(
|
|
"ObjectNotInActiveTierError",
|
|
"The source object of the COPY operation is not in the active tier and is only stored in Amazon Glacier.",
|
|
Key=key_name,
|
|
)
|
|
|
|
|
|
class InvalidPartOrder(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidPartOrder",
|
|
(
|
|
"The list of parts was not in ascending order. The parts "
|
|
"list must be specified in order by part number."
|
|
),
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidPart(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidPart",
|
|
(
|
|
"One or more of the specified parts could not be found. "
|
|
"The part might not have been uploaded, or the specified "
|
|
"entity tag might not have matched the part's entity tag."
|
|
),
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class EntityTooSmall(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"EntityTooSmall",
|
|
"Your proposed upload is smaller than the minimum allowed object size.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidRequest(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, method, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidRequest",
|
|
f"Found unsupported HTTP method in CORS config. Unsupported method is {method}",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class IllegalLocationConstraintException(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"IllegalLocationConstraintException",
|
|
"The unspecified location constraint is incompatible for the region specific endpoint this request was sent to.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class MalformedXML(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"MalformedXML",
|
|
"The XML you provided was not well-formed or did not validate against our published schema",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class MalformedACLError(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"MalformedACLError",
|
|
"The XML you provided was not well-formed or did not validate against our published schema",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidTargetBucketForLogging(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, msg):
|
|
super().__init__("InvalidTargetBucketForLogging", msg)
|
|
|
|
|
|
class CrossLocationLoggingProhibitted(S3ClientError):
|
|
code = 403
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
"CrossLocationLoggingProhibitted", "Cross S3 location logging not allowed."
|
|
)
|
|
|
|
|
|
class InvalidMaxPartArgument(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, arg, min_val, max_val):
|
|
error = f"Argument {arg} must be an integer between {min_val} and {max_val}"
|
|
super().__init__("InvalidArgument", error)
|
|
|
|
|
|
class InvalidMaxPartNumberArgument(InvalidArgumentError):
|
|
code = 400
|
|
|
|
def __init__(self, value, *args, **kwargs):
|
|
error = "Part number must be an integer between 1 and 10000, inclusive"
|
|
super().__init__(message=error, name="partNumber", value=value, *args, **kwargs)
|
|
|
|
|
|
class NotAnIntegerException(InvalidArgumentError):
|
|
code = 400
|
|
|
|
def __init__(self, name, value, *args, **kwargs):
|
|
error = f"Provided {name} not an integer or within integer range"
|
|
super().__init__(message=error, name=name, value=value, *args, **kwargs)
|
|
|
|
|
|
class InvalidNotificationARN(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidArgument", "The ARN is not well formed", *args, **kwargs
|
|
)
|
|
|
|
|
|
class InvalidNotificationDestination(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidArgument",
|
|
"The notification destination service region is not valid for the bucket location constraint",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidNotificationEvent(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidArgument",
|
|
"The event is not supported for notifications",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidStorageClass(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidStorageClass",
|
|
"The storage class you specified is not valid",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidBucketName(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidBucketName", "The specified bucket is not valid.", *args, **kwargs
|
|
)
|
|
|
|
|
|
class DuplicateTagKeys(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidTag",
|
|
"Cannot provide multiple Tags with the same key",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class S3AccessDeniedError(S3ClientError):
|
|
code = 403
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__("AccessDenied", "Access Denied", *args, **kwargs)
|
|
|
|
|
|
class BucketAccessDeniedError(BucketError):
|
|
code = 403
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__("AccessDenied", "Access Denied", *args, **kwargs)
|
|
|
|
|
|
class S3InvalidTokenError(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidToken",
|
|
"The provided token is malformed or otherwise invalid.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class S3AclAndGrantError(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidRequest",
|
|
"Specifying both Canned ACLs and Header Grants is not allowed",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class BucketInvalidTokenError(BucketError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidToken",
|
|
"The provided token is malformed or otherwise invalid.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class S3InvalidAccessKeyIdError(S3ClientError):
|
|
code = 403
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidAccessKeyId",
|
|
"The AWS Access Key Id you provided does not exist in our records.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class BucketInvalidAccessKeyIdError(S3ClientError):
|
|
code = 403
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidAccessKeyId",
|
|
"The AWS Access Key Id you provided does not exist in our records.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class S3SignatureDoesNotMatchError(S3ClientError):
|
|
code = 403
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"SignatureDoesNotMatch",
|
|
"The request signature we calculated does not match the signature you provided. Check your key and signing method.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class BucketSignatureDoesNotMatchError(S3ClientError):
|
|
code = 403
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"SignatureDoesNotMatch",
|
|
"The request signature we calculated does not match the signature you provided. Check your key and signing method.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class NoSuchPublicAccessBlockConfiguration(S3ClientError):
|
|
code = 404
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"NoSuchPublicAccessBlockConfiguration",
|
|
"The public access block configuration was not found",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidPublicAccessBlockConfiguration(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidRequest",
|
|
"Must specify at least one configuration.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class WrongPublicAccessBlockAccountIdError(S3ClientError):
|
|
code = 403
|
|
|
|
def __init__(self):
|
|
super().__init__("AccessDenied", "Access Denied")
|
|
|
|
|
|
class NoSystemTags(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
"InvalidTag", "System tags cannot be added/updated by requester"
|
|
)
|
|
|
|
|
|
class NoSuchUpload(S3ClientError):
|
|
code = 404
|
|
|
|
def __init__(self, upload_id, *args, **kwargs):
|
|
kwargs.setdefault("template", "error_uploadid")
|
|
kwargs["upload_id"] = upload_id
|
|
self.templates["error_uploadid"] = ERROR_WITH_UPLOADID
|
|
super().__init__(
|
|
"NoSuchUpload",
|
|
"The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class PreconditionFailed(S3ClientError):
|
|
code = 412
|
|
|
|
def __init__(self, failed_condition, **kwargs):
|
|
kwargs.setdefault("template", "condition_error")
|
|
self.templates["condition_error"] = ERROR_WITH_CONDITION_NAME
|
|
super().__init__(
|
|
"PreconditionFailed",
|
|
"At least one of the pre-conditions you specified did not hold",
|
|
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().__init__(
|
|
"InvalidRange",
|
|
"The requested range is not satisfiable",
|
|
range_requested=range_requested,
|
|
actual_size=actual_size,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidContinuationToken(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(
|
|
"InvalidArgument",
|
|
"The continuation token provided is incorrect",
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidObjectState(BucketError):
|
|
code = 403
|
|
|
|
def __init__(self, storage_class, **kwargs):
|
|
kwargs.setdefault("template", "storage_error")
|
|
self.templates["storage_error"] = ERROR_WITH_STORAGE_CLASS
|
|
super().__init__(
|
|
error_type="InvalidObjectState",
|
|
message="The operation is not valid for the object's storage class",
|
|
storage_class=storage_class,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class LockNotEnabled(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self):
|
|
super().__init__("InvalidRequest", "Bucket is missing ObjectLockConfiguration")
|
|
|
|
|
|
class AccessDeniedByLock(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self):
|
|
super().__init__("AccessDenied", "Access Denied")
|
|
|
|
|
|
class InvalidContentMD5(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self):
|
|
super().__init__("InvalidContentMD5", "Content MD5 header is invalid")
|
|
|
|
|
|
class BucketNeedsToBeNew(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self):
|
|
super().__init__("InvalidBucket", "Bucket needs to be empty")
|
|
|
|
|
|
class BucketMustHaveLockeEnabled(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
"InvalidBucketState",
|
|
"Object Lock configuration cannot be enabled on existing buckets",
|
|
)
|
|
|
|
|
|
class CopyObjectMustChangeSomething(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
"InvalidRequest",
|
|
"This copy request is illegal because it is trying to copy an object to itself without changing the object's metadata, storage class, website redirect location or encryption attributes.",
|
|
)
|
|
|
|
|
|
class InvalidFilterRuleName(InvalidArgumentError):
|
|
code = 400
|
|
|
|
def __init__(self, value, *args, **kwargs):
|
|
super().__init__(
|
|
"filter rule name must be either prefix or suffix",
|
|
"FilterRule.Name",
|
|
value,
|
|
*args,
|
|
**kwargs,
|
|
)
|
|
|
|
|
|
class InvalidTagError(S3ClientError):
|
|
code = 400
|
|
|
|
def __init__(self, value, *args, **kwargs):
|
|
super().__init__("InvalidTag", value, *args, **kwargs)
|
|
|
|
|
|
class ObjectLockConfigurationNotFoundError(S3ClientError):
|
|
code = 404
|
|
|
|
def __init__(self):
|
|
super().__init__(
|
|
"ObjectLockConfigurationNotFoundError",
|
|
"Object Lock configuration does not exist for this bucket",
|
|
)
|