diff --git a/api/errors.go b/api/errors.go index e216f207..9d40d704 100644 --- a/api/errors.go +++ b/api/errors.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/http" - "path" ) type ( @@ -306,291 +305,349 @@ const ( // descriptions for all the error responses. var errorCodes = errorCodeMap{ ErrInvalidCopyDest: { + ErrCode: ErrInvalidCopyDest, Code: "InvalidRequest", Description: "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.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidCopySource: { + ErrCode: ErrInvalidCopySource, Code: "InvalidArgument", Description: "Copy Source must mention the source bucket and key: sourcebucket/sourcekey.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidMetadataDirective: { + ErrCode: ErrInvalidMetadataDirective, Code: "InvalidArgument", Description: "Unknown metadata directive.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidStorageClass: { + ErrCode: ErrInvalidStorageClass, Code: "InvalidStorageClass", Description: "Invalid storage class.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidRequestBody: { + ErrCode: ErrInvalidRequestBody, Code: "InvalidArgument", Description: "Body shouldn't be set for this request.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidMaxUploads: { + ErrCode: ErrInvalidMaxUploads, Code: "InvalidArgument", Description: "Argument max-uploads must be an integer between 0 and 2147483647", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidMaxKeys: { + ErrCode: ErrInvalidMaxKeys, Code: "InvalidArgument", Description: "Argument maxKeys must be an integer between 0 and 2147483647", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidEncodingMethod: { + ErrCode: ErrInvalidEncodingMethod, Code: "InvalidArgument", Description: "Invalid Encoding Method specified in Request", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidMaxParts: { + ErrCode: ErrInvalidMaxParts, Code: "InvalidArgument", Description: "Argument max-parts must be an integer between 0 and 2147483647", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidPartNumberMarker: { + ErrCode: ErrInvalidPartNumberMarker, Code: "InvalidArgument", Description: "Argument partNumberMarker must be an integer.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidPolicyDocument: { + ErrCode: ErrInvalidPolicyDocument, Code: "InvalidPolicyDocument", Description: "The content of the form does not meet the conditions specified in the policy document.", HTTPStatusCode: http.StatusBadRequest, }, ErrAccessDenied: { + ErrCode: ErrAccessDenied, Code: "AccessDenied", Description: "Access Denied.", HTTPStatusCode: http.StatusForbidden, }, ErrBadDigest: { + ErrCode: ErrBadDigest, Code: "BadDigest", Description: "The Content-Md5 you specified did not match what we received.", HTTPStatusCode: http.StatusBadRequest, }, ErrEntityTooSmall: { + ErrCode: ErrEntityTooSmall, Code: "EntityTooSmall", Description: "Your proposed upload is smaller than the minimum allowed object size.", HTTPStatusCode: http.StatusBadRequest, }, ErrEntityTooLarge: { + ErrCode: ErrEntityTooLarge, Code: "EntityTooLarge", Description: "Your proposed upload exceeds the maximum allowed object size.", HTTPStatusCode: http.StatusBadRequest, }, ErrPolicyTooLarge: { + ErrCode: ErrPolicyTooLarge, Code: "PolicyTooLarge", Description: "Policy exceeds the maximum allowed document size.", HTTPStatusCode: http.StatusBadRequest, }, ErrIllegalVersioningConfigurationException: { + ErrCode: ErrIllegalVersioningConfigurationException, Code: "IllegalVersioningConfigurationException", Description: "Indicates that the versioning configuration specified in the request is invalid.", HTTPStatusCode: http.StatusBadRequest, }, ErrIncompleteBody: { + ErrCode: ErrIncompleteBody, Code: "IncompleteBody", Description: "You did not provide the number of bytes specified by the Content-Length HTTP header.", HTTPStatusCode: http.StatusBadRequest, }, ErrInternalError: { + ErrCode: ErrInternalError, Code: "InternalError", Description: "We encountered an internal error, please try again.", HTTPStatusCode: http.StatusInternalServerError, }, ErrInvalidAccessKeyID: { + ErrCode: ErrInvalidAccessKeyID, Code: "InvalidAccessKeyId", Description: "The Access Key Id you provided does not exist in our records.", HTTPStatusCode: http.StatusForbidden, }, ErrInvalidBucketName: { + ErrCode: ErrInvalidBucketName, Code: "InvalidBucketName", Description: "The specified bucket is not valid.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidDigest: { + ErrCode: ErrInvalidDigest, Code: "InvalidDigest", Description: "The Content-Md5 you specified is not valid.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidRange: { + ErrCode: ErrInvalidRange, Code: "InvalidRange", Description: "The requested range is not satisfiable", HTTPStatusCode: http.StatusRequestedRangeNotSatisfiable, }, ErrMalformedXML: { + ErrCode: ErrMalformedXML, Code: "MalformedXML", Description: "The XML you provided was not well-formed or did not validate against our published schema.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingContentLength: { + ErrCode: ErrMissingContentLength, Code: "MissingContentLength", Description: "You must provide the Content-Length HTTP header.", HTTPStatusCode: http.StatusLengthRequired, }, ErrMissingContentMD5: { + ErrCode: ErrMissingContentMD5, Code: "MissingContentMD5", Description: "Missing required header for this request: Content-Md5.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingSecurityHeader: { + ErrCode: ErrMissingSecurityHeader, Code: "MissingSecurityHeader", Description: "Your request was missing a required header", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingRequestBodyError: { + ErrCode: ErrMissingRequestBodyError, Code: "MissingRequestBodyError", Description: "Request body is empty.", HTTPStatusCode: http.StatusLengthRequired, }, ErrNoSuchBucket: { + ErrCode: ErrNoSuchBucket, Code: "NoSuchBucket", Description: "The specified bucket does not exist", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchBucketPolicy: { + ErrCode: ErrNoSuchBucketPolicy, Code: "NoSuchBucketPolicy", Description: "The bucket policy does not exist", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchBucketLifecycle: { + ErrCode: ErrNoSuchBucketLifecycle, Code: "NoSuchBucketLifecycle", Description: "The bucket lifecycle configuration does not exist", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchLifecycleConfiguration: { + ErrCode: ErrNoSuchLifecycleConfiguration, Code: "NoSuchLifecycleConfiguration", Description: "The lifecycle configuration does not exist", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchBucketSSEConfig: { + ErrCode: ErrNoSuchBucketSSEConfig, Code: "ServerSideEncryptionConfigurationNotFoundError", Description: "The server side encryption configuration was not found", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchKey: { + ErrCode: ErrNoSuchKey, Code: "NoSuchKey", Description: "The specified key does not exist.", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchUpload: { + ErrCode: ErrNoSuchUpload, Code: "NoSuchUpload", Description: "The specified multipart upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchVersion: { + ErrCode: ErrNoSuchVersion, Code: "NoSuchVersion", Description: "Indicates that the version ID specified in the request does not match an existing version.", HTTPStatusCode: http.StatusNotFound, }, ErrNotImplemented: { + ErrCode: ErrNotImplemented, Code: "NotImplemented", Description: "A header you provided implies functionality that is not implemented", HTTPStatusCode: http.StatusNotImplemented, }, ErrPreconditionFailed: { + ErrCode: ErrPreconditionFailed, Code: "PreconditionFailed", Description: "At least one of the pre-conditions you specified did not hold", HTTPStatusCode: http.StatusPreconditionFailed, }, ErrNotModified: { + ErrCode: ErrNotModified, Code: "NotModified", Description: "The resource was not changed.", HTTPStatusCode: http.StatusNotModified, }, ErrRequestTimeTooSkewed: { + ErrCode: ErrRequestTimeTooSkewed, Code: "RequestTimeTooSkewed", Description: "The difference between the request time and the server's time is too large.", HTTPStatusCode: http.StatusForbidden, }, ErrSignatureDoesNotMatch: { + ErrCode: ErrSignatureDoesNotMatch, Code: "SignatureDoesNotMatch", Description: "The request signature we calculated does not match the signature you provided. Check your key and signing method.", HTTPStatusCode: http.StatusForbidden, }, ErrMethodNotAllowed: { + ErrCode: ErrMethodNotAllowed, Code: "MethodNotAllowed", Description: "The specified method is not allowed against this resource.", HTTPStatusCode: http.StatusMethodNotAllowed, }, ErrInvalidPart: { + ErrCode: ErrInvalidPart, Code: "InvalidPart", Description: "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidPartOrder: { + ErrCode: ErrInvalidPartOrder, Code: "InvalidPartOrder", Description: "The list of parts was not in ascending order. The parts list must be specified in order by part number.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidObjectState: { + ErrCode: ErrInvalidObjectState, Code: "InvalidObjectState", Description: "The operation is not valid for the current state of the object.", HTTPStatusCode: http.StatusForbidden, }, ErrAuthorizationHeaderMalformed: { + ErrCode: ErrAuthorizationHeaderMalformed, Code: "AuthorizationHeaderMalformed", Description: "The authorization header is malformed; the region is wrong; expecting 'us-east-1'.", HTTPStatusCode: http.StatusBadRequest, }, ErrMalformedPOSTRequest: { + ErrCode: ErrMalformedPOSTRequest, Code: "MalformedPOSTRequest", Description: "The body of your POST request is not well-formed multipart/form-data.", HTTPStatusCode: http.StatusBadRequest, }, ErrPOSTFileRequired: { + ErrCode: ErrPOSTFileRequired, Code: "InvalidArgument", Description: "POST requires exactly one file upload per request.", HTTPStatusCode: http.StatusBadRequest, }, ErrSignatureVersionNotSupported: { + ErrCode: ErrSignatureVersionNotSupported, Code: "InvalidRequest", Description: "The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.", HTTPStatusCode: http.StatusBadRequest, }, ErrBucketNotEmpty: { + ErrCode: ErrBucketNotEmpty, Code: "BucketNotEmpty", Description: "The bucket you tried to delete is not empty", HTTPStatusCode: http.StatusConflict, }, ErrBucketAlreadyExists: { + ErrCode: ErrBucketAlreadyExists, Code: "BucketAlreadyExists", Description: "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.", HTTPStatusCode: http.StatusConflict, }, ErrAllAccessDisabled: { + ErrCode: ErrAllAccessDisabled, Code: "AllAccessDisabled", Description: "All access to this bucket has been disabled.", HTTPStatusCode: http.StatusForbidden, }, ErrMalformedPolicy: { + ErrCode: ErrMalformedPolicy, Code: "MalformedPolicy", Description: "Policy has invalid resource.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingFields: { + ErrCode: ErrMissingFields, Code: "MissingFields", Description: "Missing fields in request.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingCredTag: { + ErrCode: ErrMissingCredTag, Code: "InvalidRequest", Description: "Missing Credential field for this request.", HTTPStatusCode: http.StatusBadRequest, }, ErrCredMalformed: { + ErrCode: ErrCredMalformed, Code: "AuthorizationQueryParametersError", Description: "Error parsing the X-Amz-Credential parameter; the Credential is mal-formed; expecting \"/YYYYMMDD/REGION/SERVICE/aws4_request\".", HTTPStatusCode: http.StatusBadRequest, }, ErrMalformedDate: { + ErrCode: ErrMalformedDate, Code: "MalformedDate", Description: "Invalid date format header, expected to be in ISO8601, RFC1123 or RFC1123Z time format.", HTTPStatusCode: http.StatusBadRequest, }, ErrMalformedPresignedDate: { + ErrCode: ErrMalformedPresignedDate, Code: "AuthorizationQueryParametersError", Description: "X-Amz-Date must be in the ISO8601 Long Format \"yyyyMMdd'T'HHmmss'Z'\"", HTTPStatusCode: http.StatusBadRequest, @@ -599,6 +656,7 @@ var errorCodes = errorCodeMap{ // right Description: "Error parsing the X-Amz-Credential parameter; incorrect date format \"%s\". This date in the credential must be in the format \"yyyyMMdd\".", // Need changes to make sure variable messages can be constructed. ErrMalformedCredentialDate: { + ErrCode: ErrMalformedCredentialDate, Code: "AuthorizationQueryParametersError", Description: "Error parsing the X-Amz-Credential parameter; incorrect date format \"%s\". This date in the credential must be in the format \"yyyyMMdd\".", HTTPStatusCode: http.StatusBadRequest, @@ -607,11 +665,13 @@ var errorCodes = errorCodeMap{ // right Description: "Error parsing the X-Amz-Credential parameter; the region 'us-east-' is wrong; expecting 'us-east-1'". // Need changes to make sure variable messages can be constructed. ErrMalformedCredentialRegion: { + ErrCode: ErrMalformedCredentialRegion, Code: "AuthorizationQueryParametersError", Description: "Error parsing the X-Amz-Credential parameter; the region is wrong;", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidRegion: { + ErrCode: ErrInvalidRegion, Code: "InvalidRegion", Description: "Region does not match.", HTTPStatusCode: http.StatusBadRequest, @@ -620,11 +680,13 @@ var errorCodes = errorCodeMap{ // right Description: "Error parsing the X-Amz-Credential parameter; incorrect service \"s4\". This endpoint belongs to \"s3\".". // Need changes to make sure variable messages can be constructed. ErrInvalidServiceS3: { + ErrCode: ErrInvalidServiceS3, Code: "AuthorizationParametersError", Description: "Error parsing the Credential/X-Amz-Credential parameter; incorrect service. This endpoint belongs to \"s3\".", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidServiceSTS: { + ErrCode: ErrInvalidServiceSTS, Code: "AuthorizationParametersError", Description: "Error parsing the Credential parameter; incorrect service. This endpoint belongs to \"sts\".", HTTPStatusCode: http.StatusBadRequest, @@ -633,71 +695,85 @@ var errorCodes = errorCodeMap{ // Description: "Error parsing the X-Amz-Credential parameter; incorrect terminal "aws4_reque". This endpoint uses "aws4_request". // Need changes to make sure variable messages can be constructed. ErrInvalidRequestVersion: { + ErrCode: ErrInvalidRequestVersion, Code: "AuthorizationQueryParametersError", Description: "Error parsing the X-Amz-Credential parameter; incorrect terminal. This endpoint uses \"aws4_request\".", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingSignTag: { + ErrCode: ErrMissingSignTag, Code: "AccessDenied", Description: "Signature header missing Signature field.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingSignHeadersTag: { + ErrCode: ErrMissingSignHeadersTag, Code: "InvalidArgument", Description: "Signature header missing SignedHeaders field.", HTTPStatusCode: http.StatusBadRequest, }, ErrMalformedExpires: { + ErrCode: ErrMalformedExpires, Code: "AuthorizationQueryParametersError", Description: "X-Amz-Expires should be a number", HTTPStatusCode: http.StatusBadRequest, }, ErrNegativeExpires: { + ErrCode: ErrNegativeExpires, Code: "AuthorizationQueryParametersError", Description: "X-Amz-Expires must be non-negative", HTTPStatusCode: http.StatusBadRequest, }, ErrAuthHeaderEmpty: { + ErrCode: ErrAuthHeaderEmpty, Code: "InvalidArgument", Description: "Authorization header is invalid -- one and only one ' ' (space) required.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingDateHeader: { + ErrCode: ErrMissingDateHeader, Code: "AccessDenied", Description: "AWS authentication requires a valid Date or x-amz-date header", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidQuerySignatureAlgo: { + ErrCode: ErrInvalidQuerySignatureAlgo, Code: "AuthorizationQueryParametersError", Description: "X-Amz-Algorithm only supports \"AWS4-HMAC-SHA256\".", HTTPStatusCode: http.StatusBadRequest, }, ErrExpiredPresignRequest: { + ErrCode: ErrExpiredPresignRequest, Code: "AccessDenied", Description: "Request has expired", HTTPStatusCode: http.StatusForbidden, }, ErrRequestNotReadyYet: { + ErrCode: ErrRequestNotReadyYet, Code: "AccessDenied", Description: "Request is not valid yet", HTTPStatusCode: http.StatusForbidden, }, ErrSlowDown: { + ErrCode: ErrSlowDown, Code: "SlowDown", Description: "Please reduce your request", HTTPStatusCode: http.StatusServiceUnavailable, }, ErrInvalidPrefixMarker: { + ErrCode: ErrInvalidPrefixMarker, Code: "InvalidPrefixMarker", Description: "Invalid marker prefix combination", HTTPStatusCode: http.StatusBadRequest, }, ErrBadRequest: { + ErrCode: ErrBadRequest, Code: "BadRequest", Description: "400 BadRequest", HTTPStatusCode: http.StatusBadRequest, }, ErrKeyTooLongError: { + ErrCode: ErrKeyTooLongError, Code: "KeyTooLongError", Description: "Your key is too long", HTTPStatusCode: http.StatusBadRequest, @@ -705,237 +781,284 @@ var errorCodes = errorCodeMap{ // FIXME: Actual XML error response also contains the header which missed in list of signed header parameters. ErrUnsignedHeaders: { + ErrCode: ErrUnsignedHeaders, Code: "AccessDenied", Description: "There were headers present in the request which were not signed", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidQueryParams: { + ErrCode: ErrInvalidQueryParams, Code: "AuthorizationQueryParametersError", Description: "Query-string authentication version 4 requires the X-Amz-Algorithm, X-Amz-Credential, X-Amz-Signature, X-Amz-Date, X-Amz-SignedHeaders, and X-Amz-Expires parameters.", HTTPStatusCode: http.StatusBadRequest, }, ErrBucketAlreadyOwnedByYou: { + ErrCode: ErrBucketAlreadyOwnedByYou, Code: "BucketAlreadyOwnedByYou", Description: "Your previous request to create the named bucket succeeded and you already own it.", HTTPStatusCode: http.StatusConflict, }, ErrInvalidDuration: { + ErrCode: ErrInvalidDuration, Code: "InvalidDuration", Description: "Duration provided in the request is invalid.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidBucketObjectLockConfiguration: { + ErrCode: ErrInvalidBucketObjectLockConfiguration, Code: "InvalidRequest", Description: "Bucket is missing ObjectLockConfiguration", HTTPStatusCode: http.StatusBadRequest, }, ErrBucketTaggingNotFound: { + ErrCode: ErrBucketTaggingNotFound, Code: "NoSuchTagSet", Description: "The TagSet does not exist", HTTPStatusCode: http.StatusNotFound, }, ErrObjectLockConfigurationNotFound: { + ErrCode: ErrObjectLockConfigurationNotFound, Code: "ObjectLockConfigurationNotFoundError", Description: "Object Lock configuration does not exist for this bucket", HTTPStatusCode: http.StatusNotFound, }, ErrObjectLockConfigurationNotAllowed: { + ErrCode: ErrObjectLockConfigurationNotAllowed, Code: "InvalidBucketState", Description: "Object Lock configuration cannot be enabled on existing buckets", HTTPStatusCode: http.StatusConflict, }, ErrNoSuchCORSConfiguration: { + ErrCode: ErrNoSuchCORSConfiguration, Code: "NoSuchCORSConfiguration", Description: "The CORS configuration does not exist", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchWebsiteConfiguration: { + ErrCode: ErrNoSuchWebsiteConfiguration, Code: "NoSuchWebsiteConfiguration", Description: "The specified bucket does not have a website configuration", HTTPStatusCode: http.StatusNotFound, }, ErrReplicationConfigurationNotFoundError: { + ErrCode: ErrReplicationConfigurationNotFoundError, Code: "ReplicationConfigurationNotFoundError", Description: "The replication configuration was not found", HTTPStatusCode: http.StatusNotFound, }, ErrNoSuchObjectLockConfiguration: { + ErrCode: ErrNoSuchObjectLockConfiguration, Code: "NoSuchObjectLockConfiguration", Description: "The specified object does not have a ObjectLock configuration", HTTPStatusCode: http.StatusBadRequest, }, ErrObjectLocked: { + ErrCode: ErrObjectLocked, Code: "InvalidRequest", Description: "Object is WORM protected and cannot be overwritten", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidRetentionDate: { + ErrCode: ErrInvalidRetentionDate, Code: "InvalidRequest", Description: "Date must be provided in ISO 8601 format", HTTPStatusCode: http.StatusBadRequest, }, ErrPastObjectLockRetainDate: { + ErrCode: ErrPastObjectLockRetainDate, Code: "InvalidRequest", Description: "the retain until date must be in the future", HTTPStatusCode: http.StatusBadRequest, }, ErrUnknownWORMModeDirective: { + ErrCode: ErrUnknownWORMModeDirective, Code: "InvalidRequest", Description: "unknown wormMode directive", HTTPStatusCode: http.StatusBadRequest, }, ErrObjectLockInvalidHeaders: { + ErrCode: ErrObjectLockInvalidHeaders, Code: "InvalidRequest", Description: "x-amz-object-lock-retain-until-date and x-amz-object-lock-mode must both be supplied", HTTPStatusCode: http.StatusBadRequest, }, // Bucket notification related errors. ErrEventNotification: { + ErrCode: ErrEventNotification, Code: "InvalidArgument", Description: "A specified event is not supported for notifications.", HTTPStatusCode: http.StatusBadRequest, }, ErrARNNotification: { + ErrCode: ErrARNNotification, Code: "InvalidArgument", Description: "A specified destination ARN does not exist or is not well-formed. Verify the destination ARN.", HTTPStatusCode: http.StatusBadRequest, }, ErrRegionNotification: { + ErrCode: ErrRegionNotification, Code: "InvalidArgument", Description: "A specified destination is in a different region than the bucket. You must use a destination that resides in the same region as the bucket.", HTTPStatusCode: http.StatusBadRequest, }, ErrOverlappingFilterNotification: { + ErrCode: ErrOverlappingFilterNotification, Code: "InvalidArgument", Description: "An object key name filtering rule defined with overlapping prefixes, overlapping suffixes, or overlapping combinations of prefixes and suffixes for the same event types.", HTTPStatusCode: http.StatusBadRequest, }, ErrFilterNameInvalid: { + ErrCode: ErrFilterNameInvalid, Code: "InvalidArgument", Description: "filter rule name must be either prefix or suffix", HTTPStatusCode: http.StatusBadRequest, }, ErrFilterNamePrefix: { + ErrCode: ErrFilterNamePrefix, Code: "InvalidArgument", Description: "Cannot specify more than one prefix rule in a filter.", HTTPStatusCode: http.StatusBadRequest, }, ErrFilterNameSuffix: { + ErrCode: ErrFilterNameSuffix, Code: "InvalidArgument", Description: "Cannot specify more than one suffix rule in a filter.", HTTPStatusCode: http.StatusBadRequest, }, ErrFilterValueInvalid: { + ErrCode: ErrFilterValueInvalid, Code: "InvalidArgument", Description: "Size of filter rule value cannot exceed 1024 bytes in UTF-8 representation", HTTPStatusCode: http.StatusBadRequest, }, ErrOverlappingConfigs: { + ErrCode: ErrOverlappingConfigs, Code: "InvalidArgument", Description: "Configurations overlap. Configurations on the same bucket cannot share a common event type.", HTTPStatusCode: http.StatusBadRequest, }, ErrUnsupportedNotification: { + ErrCode: ErrUnsupportedNotification, Code: "UnsupportedNotification", Description: "MinIO server does not support Topic or Cloud Function based notifications.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidCopyPartRange: { + ErrCode: ErrInvalidCopyPartRange, Code: "InvalidArgument", Description: "The x-amz-copy-source-range value must be of the form bytes=first-last where first and last are the zero-based offsets of the first and last bytes to copy", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidCopyPartRangeSource: { + ErrCode: ErrInvalidCopyPartRangeSource, Code: "InvalidArgument", Description: "Range specified is not valid for source object", HTTPStatusCode: http.StatusBadRequest, }, ErrMetadataTooLarge: { + ErrCode: ErrMetadataTooLarge, Code: "InvalidArgument", Description: "Your metadata headers exceed the maximum allowed metadata size.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidTagDirective: { + ErrCode: ErrInvalidTagDirective, Code: "InvalidArgument", Description: "Unknown tag directive.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidEncryptionMethod: { + ErrCode: ErrInvalidEncryptionMethod, Code: "InvalidRequest", Description: "The encryption method specified is not supported", HTTPStatusCode: http.StatusBadRequest, }, ErrInsecureSSECustomerRequest: { + ErrCode: ErrInsecureSSECustomerRequest, Code: "InvalidRequest", Description: "Requests specifying Server Side Encryption with Customer provided keys must be made over a secure connection.", HTTPStatusCode: http.StatusBadRequest, }, ErrSSEMultipartEncrypted: { + ErrCode: ErrSSEMultipartEncrypted, Code: "InvalidRequest", Description: "The multipart upload initiate requested encryption. Subsequent part requests must include the appropriate encryption parameters.", HTTPStatusCode: http.StatusBadRequest, }, ErrSSEEncryptedObject: { + ErrCode: ErrSSEEncryptedObject, Code: "InvalidRequest", Description: "The object was stored using a form of Server Side Encryption. The correct parameters must be provided to retrieve the object.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidEncryptionParameters: { + ErrCode: ErrInvalidEncryptionParameters, Code: "InvalidRequest", Description: "The encryption parameters are not applicable to this object.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidSSECustomerAlgorithm: { + ErrCode: ErrInvalidSSECustomerAlgorithm, Code: "InvalidArgument", Description: "Requests specifying Server Side Encryption with Customer provided keys must provide a valid encryption algorithm.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidSSECustomerKey: { + ErrCode: ErrInvalidSSECustomerKey, Code: "InvalidArgument", Description: "The secret key was invalid for the specified algorithm.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingSSECustomerKey: { + ErrCode: ErrMissingSSECustomerKey, Code: "InvalidArgument", Description: "Requests specifying Server Side Encryption with Customer provided keys must provide an appropriate secret key.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingSSECustomerKeyMD5: { + ErrCode: ErrMissingSSECustomerKeyMD5, Code: "InvalidArgument", Description: "Requests specifying Server Side Encryption with Customer provided keys must provide the client calculated MD5 of the secret key.", HTTPStatusCode: http.StatusBadRequest, }, ErrSSECustomerKeyMD5Mismatch: { + ErrCode: ErrSSECustomerKeyMD5Mismatch, Code: "InvalidArgument", Description: "The calculated MD5 hash of the key did not match the hash that was provided.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidSSECustomerParameters: { + ErrCode: ErrInvalidSSECustomerParameters, Code: "InvalidArgument", Description: "The provided encryption parameters did not match the ones used originally.", HTTPStatusCode: http.StatusBadRequest, }, ErrIncompatibleEncryptionMethod: { + ErrCode: ErrIncompatibleEncryptionMethod, Code: "InvalidArgument", Description: "Server side encryption specified with both SSE-C and SSE-S3 headers", HTTPStatusCode: http.StatusBadRequest, }, ErrKMSNotConfigured: { + ErrCode: ErrKMSNotConfigured, Code: "InvalidArgument", Description: "Server side encryption specified but KMS is not configured", HTTPStatusCode: http.StatusBadRequest, }, ErrKMSAuthFailure: { + ErrCode: ErrKMSAuthFailure, Code: "InvalidArgument", Description: "Server side encryption specified but KMS authorization failed", HTTPStatusCode: http.StatusBadRequest, }, ErrNoAccessKey: { + ErrCode: ErrNoAccessKey, Code: "AccessDenied", Description: "No AWSAccessKey was presented", HTTPStatusCode: http.StatusForbidden, }, ErrInvalidToken: { + ErrCode: ErrInvalidToken, Code: "InvalidTokenId", Description: "The security token included in the request is invalid", HTTPStatusCode: http.StatusForbidden, @@ -943,6 +1066,7 @@ var errorCodes = errorCodeMap{ // S3 extensions. ErrContentSHA256Mismatch: { + ErrCode: ErrContentSHA256Mismatch, Code: "XAmzContentSHA256Mismatch", Description: "The provided 'x-amz-content-sha256' header does not match what was computed.", HTTPStatusCode: http.StatusBadRequest, @@ -950,162 +1074,194 @@ var errorCodes = errorCodeMap{ // MinIO extensions. ErrStorageFull: { + ErrCode: ErrStorageFull, Code: "XMinioStorageFull", Description: "Storage backend has reached its minimum free disk threshold. Please delete a few objects to proceed.", HTTPStatusCode: http.StatusInsufficientStorage, }, ErrParentIsObject: { + ErrCode: ErrParentIsObject, Code: "XMinioParentIsObject", Description: "Object-prefix is already an object, please choose a different object-prefix name.", HTTPStatusCode: http.StatusBadRequest, }, ErrRequestBodyParse: { + ErrCode: ErrRequestBodyParse, Code: "XMinioRequestBodyParse", Description: "The request body failed to parse.", HTTPStatusCode: http.StatusBadRequest, }, ErrObjectExistsAsDirectory: { + ErrCode: ErrObjectExistsAsDirectory, Code: "XMinioObjectExistsAsDirectory", Description: "Object name already exists as a directory.", HTTPStatusCode: http.StatusConflict, }, ErrInvalidObjectName: { + ErrCode: ErrInvalidObjectName, Code: "XMinioInvalidObjectName", Description: "Object name contains unsupported characters.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidObjectNamePrefixSlash: { + ErrCode: ErrInvalidObjectNamePrefixSlash, Code: "XMinioInvalidObjectName", Description: "Object name contains a leading slash.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidResourceName: { + ErrCode: ErrInvalidResourceName, Code: "XMinioInvalidResourceName", Description: "Resource name contains bad components such as \"..\" or \".\".", HTTPStatusCode: http.StatusBadRequest, }, ErrServerNotInitialized: { + ErrCode: ErrServerNotInitialized, Code: "XMinioServerNotInitialized", Description: "Server not initialized, please try again.", HTTPStatusCode: http.StatusServiceUnavailable, }, ErrMalformedJSON: { + ErrCode: ErrMalformedJSON, Code: "XMinioMalformedJSON", Description: "The JSON you provided was not well-formed or did not validate against our published format.", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminNoSuchUser: { + ErrCode: ErrAdminNoSuchUser, Code: "XMinioAdminNoSuchUser", Description: "The specified user does not exist.", HTTPStatusCode: http.StatusNotFound, }, ErrAdminNoSuchGroup: { + ErrCode: ErrAdminNoSuchGroup, Code: "XMinioAdminNoSuchGroup", Description: "The specified group does not exist.", HTTPStatusCode: http.StatusNotFound, }, ErrAdminGroupNotEmpty: { + ErrCode: ErrAdminGroupNotEmpty, Code: "XMinioAdminGroupNotEmpty", Description: "The specified group is not empty - cannot remove it.", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminNoSuchPolicy: { + ErrCode: ErrAdminNoSuchPolicy, Code: "XMinioAdminNoSuchPolicy", Description: "The canned policy does not exist.", HTTPStatusCode: http.StatusNotFound, }, ErrAdminInvalidArgument: { + ErrCode: ErrAdminInvalidArgument, Code: "XMinioAdminInvalidArgument", Description: "Invalid arguments specified.", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminInvalidAccessKey: { + ErrCode: ErrAdminInvalidAccessKey, Code: "XMinioAdminInvalidAccessKey", Description: "The access key is invalid.", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminInvalidSecretKey: { + ErrCode: ErrAdminInvalidSecretKey, Code: "XMinioAdminInvalidSecretKey", Description: "The secret key is invalid.", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminConfigNoQuorum: { + ErrCode: ErrAdminConfigNoQuorum, Code: "XMinioAdminConfigNoQuorum", Description: "Configuration update failed because server quorum was not met", HTTPStatusCode: http.StatusServiceUnavailable, }, ErrAdminConfigTooLarge: { - Code: "XMinioAdminConfigTooLarge", + ErrCode: ErrAdminConfigTooLarge, + Code: "XMinioAdminConfigTooLarge", Description: fmt.Sprintf("Configuration data provided exceeds the allowed maximum of %d bytes", maxEConfigJSONSize), HTTPStatusCode: http.StatusBadRequest, }, ErrAdminConfigBadJSON: { + ErrCode: ErrAdminConfigBadJSON, Code: "XMinioAdminConfigBadJSON", Description: "JSON configuration provided is of incorrect format", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminConfigDuplicateKeys: { + ErrCode: ErrAdminConfigDuplicateKeys, Code: "XMinioAdminConfigDuplicateKeys", Description: "JSON configuration provided has objects with duplicate keys", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminConfigNotificationTargetsFailed: { + ErrCode: ErrAdminConfigNotificationTargetsFailed, Code: "XMinioAdminNotificationTargetsTestFailed", Description: "Configuration update failed due an unsuccessful attempt to connect to one or more notification servers", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminProfilerNotEnabled: { + ErrCode: ErrAdminProfilerNotEnabled, Code: "XMinioAdminProfilerNotEnabled", Description: "Unable to perform the requested operation because profiling is not enabled", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminCredentialsMismatch: { + ErrCode: ErrAdminCredentialsMismatch, Code: "XMinioAdminCredentialsMismatch", Description: "Credentials in config mismatch with server environment variables", HTTPStatusCode: http.StatusServiceUnavailable, }, ErrAdminBucketQuotaExceeded: { + ErrCode: ErrAdminBucketQuotaExceeded, Code: "XMinioAdminBucketQuotaExceeded", Description: "Bucket quota exceeded", HTTPStatusCode: http.StatusBadRequest, }, ErrAdminNoSuchQuotaConfiguration: { + ErrCode: ErrAdminNoSuchQuotaConfiguration, Code: "XMinioAdminNoSuchQuotaConfiguration", Description: "The quota configuration does not exist", HTTPStatusCode: http.StatusNotFound, }, ErrAdminBucketQuotaDisabled: { + ErrCode: ErrAdminBucketQuotaDisabled, Code: "XMinioAdminBucketQuotaDisabled", Description: "Quota specified but disk usage crawl is disabled on MinIO server", HTTPStatusCode: http.StatusBadRequest, }, ErrInsecureClientRequest: { + ErrCode: ErrInsecureClientRequest, Code: "XMinioInsecureClientRequest", Description: "Cannot respond to plain-text request from TLS-encrypted server", HTTPStatusCode: http.StatusBadRequest, }, ErrOperationTimedOut: { + ErrCode: ErrOperationTimedOut, Code: "RequestTimeout", Description: "A timeout occurred while trying to lock a resource, please reduce your request rate", HTTPStatusCode: http.StatusServiceUnavailable, }, ErrOperationMaxedOut: { + ErrCode: ErrOperationMaxedOut, Code: "SlowDown", Description: "A timeout exceeded while waiting to proceed with the request, please reduce your request rate", HTTPStatusCode: http.StatusServiceUnavailable, }, ErrUnsupportedMetadata: { + ErrCode: ErrUnsupportedMetadata, Code: "InvalidArgument", Description: "Your metadata headers are not supported.", HTTPStatusCode: http.StatusBadRequest, }, ErrObjectTampered: { + ErrCode: ErrObjectTampered, Code: "XMinioObjectTampered", Description: "The requested object was modified and may be compromised", HTTPStatusCode: http.StatusPartialContent, }, ErrMaximumExpires: { + ErrCode: ErrMaximumExpires, Code: "AuthorizationQueryParametersError", Description: "X-Amz-Expires must be less than a week (in seconds); that is, the given X-Amz-Expires must be less than 604800 seconds", HTTPStatusCode: http.StatusBadRequest, @@ -1115,46 +1271,55 @@ var errorCodes = errorCodeMap{ // corner case errors for which introducing new ErrorCode is not worth it. LogIf() // should be used to log the error at the source of the error for debugging purposes. ErrInvalidRequest: { + ErrCode: ErrInvalidRequest, Code: "InvalidRequest", Description: "Invalid Request", HTTPStatusCode: http.StatusBadRequest, }, ErrHealNotImplemented: { + ErrCode: ErrHealNotImplemented, Code: "XMinioHealNotImplemented", Description: "This server does not implement heal functionality.", HTTPStatusCode: http.StatusBadRequest, }, ErrHealNoSuchProcess: { + ErrCode: ErrHealNoSuchProcess, Code: "XMinioHealNoSuchProcess", Description: "No such heal process is running on the server", HTTPStatusCode: http.StatusBadRequest, }, ErrHealInvalidClientToken: { + ErrCode: ErrHealInvalidClientToken, Code: "XMinioHealInvalidClientToken", Description: "Client token mismatch", HTTPStatusCode: http.StatusBadRequest, }, ErrHealMissingBucket: { + ErrCode: ErrHealMissingBucket, Code: "XMinioHealMissingBucket", Description: "A heal start request with a non-empty object-prefix parameter requires a bucket to be specified.", HTTPStatusCode: http.StatusBadRequest, }, ErrHealAlreadyRunning: { + ErrCode: ErrHealAlreadyRunning, Code: "XMinioHealAlreadyRunning", Description: "", HTTPStatusCode: http.StatusBadRequest, }, ErrHealOverlappingPaths: { + ErrCode: ErrHealOverlappingPaths, Code: "XMinioHealOverlappingPaths", Description: "", HTTPStatusCode: http.StatusBadRequest, }, ErrBackendDown: { + ErrCode: ErrBackendDown, Code: "XMinioBackendDown", Description: "Object storage backend is unreachable", HTTPStatusCode: http.StatusServiceUnavailable, }, ErrIncorrectContinuationToken: { + ErrCode: ErrIncorrectContinuationToken, Code: "InvalidArgument", Description: "The continuation token provided is incorrect", HTTPStatusCode: http.StatusBadRequest, @@ -1162,446 +1327,535 @@ var errorCodes = errorCodeMap{ // S3 Select API Errors ErrEmptyRequestBody: { + ErrCode: ErrEmptyRequestBody, Code: "EmptyRequestBody", Description: "Request body cannot be empty.", HTTPStatusCode: http.StatusBadRequest, }, ErrUnsupportedFunction: { + ErrCode: ErrUnsupportedFunction, Code: "UnsupportedFunction", Description: "Encountered an unsupported SQL function.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidDataSource: { + ErrCode: ErrInvalidDataSource, Code: "InvalidDataSource", Description: "Invalid data source type. Only CSV and JSON are supported at this time.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidExpressionType: { + ErrCode: ErrInvalidExpressionType, Code: "InvalidExpressionType", Description: "The ExpressionType is invalid. Only SQL expressions are supported at this time.", HTTPStatusCode: http.StatusBadRequest, }, ErrBusy: { + ErrCode: ErrBusy, Code: "Busy", Description: "The service is unavailable. Please retry.", HTTPStatusCode: http.StatusServiceUnavailable, }, ErrUnauthorizedAccess: { + ErrCode: ErrUnauthorizedAccess, Code: "UnauthorizedAccess", Description: "You are not authorized to perform this operation", HTTPStatusCode: http.StatusUnauthorized, }, ErrExpressionTooLong: { + ErrCode: ErrExpressionTooLong, Code: "ExpressionTooLong", Description: "The SQL expression is too long: The maximum byte-length for the SQL expression is 256 KB.", HTTPStatusCode: http.StatusBadRequest, }, ErrIllegalSQLFunctionArgument: { + ErrCode: ErrIllegalSQLFunctionArgument, Code: "IllegalSqlFunctionArgument", Description: "Illegal argument was used in the SQL function.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidKeyPath: { + ErrCode: ErrInvalidKeyPath, Code: "InvalidKeyPath", Description: "Key path in the SQL expression is invalid.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidCompressionFormat: { + ErrCode: ErrInvalidCompressionFormat, Code: "InvalidCompressionFormat", Description: "The file is not in a supported compression format. Only GZIP is supported at this time.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidFileHeaderInfo: { + ErrCode: ErrInvalidFileHeaderInfo, Code: "InvalidFileHeaderInfo", Description: "The FileHeaderInfo is invalid. Only NONE, USE, and IGNORE are supported.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidJSONType: { + ErrCode: ErrInvalidJSONType, Code: "InvalidJsonType", Description: "The JsonType is invalid. Only DOCUMENT and LINES are supported at this time.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidQuoteFields: { + ErrCode: ErrInvalidQuoteFields, Code: "InvalidQuoteFields", Description: "The QuoteFields is invalid. Only ALWAYS and ASNEEDED are supported.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidRequestParameter: { + ErrCode: ErrInvalidRequestParameter, Code: "InvalidRequestParameter", Description: "The value of a parameter in SelectRequest element is invalid. Check the service API documentation and try again.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidDataType: { + ErrCode: ErrInvalidDataType, Code: "InvalidDataType", Description: "The SQL expression contains an invalid data type.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidTextEncoding: { + ErrCode: ErrInvalidTextEncoding, Code: "InvalidTextEncoding", Description: "Invalid encoding type. Only UTF-8 encoding is supported at this time.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidTableAlias: { + ErrCode: ErrInvalidTableAlias, Code: "InvalidTableAlias", Description: "The SQL expression contains an invalid table alias.", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingRequiredParameter: { + ErrCode: ErrMissingRequiredParameter, Code: "MissingRequiredParameter", Description: "The SelectRequest entity is missing a required parameter. Check the service documentation and try again.", HTTPStatusCode: http.StatusBadRequest, }, ErrObjectSerializationConflict: { + ErrCode: ErrObjectSerializationConflict, Code: "ObjectSerializationConflict", Description: "The SelectRequest entity can only contain one of CSV or JSON. Check the service documentation and try again.", HTTPStatusCode: http.StatusBadRequest, }, ErrUnsupportedSQLOperation: { + ErrCode: ErrUnsupportedSQLOperation, Code: "UnsupportedSqlOperation", Description: "Encountered an unsupported SQL operation.", HTTPStatusCode: http.StatusBadRequest, }, ErrUnsupportedSQLStructure: { + ErrCode: ErrUnsupportedSQLStructure, Code: "UnsupportedSqlStructure", Description: "Encountered an unsupported SQL structure. Check the SQL Reference.", HTTPStatusCode: http.StatusBadRequest, }, ErrUnsupportedSyntax: { + ErrCode: ErrUnsupportedSyntax, Code: "UnsupportedSyntax", Description: "Encountered invalid syntax.", HTTPStatusCode: http.StatusBadRequest, }, ErrUnsupportedRangeHeader: { + ErrCode: ErrUnsupportedRangeHeader, Code: "UnsupportedRangeHeader", Description: "Range header is not supported for this operation.", HTTPStatusCode: http.StatusBadRequest, }, ErrLexerInvalidChar: { + ErrCode: ErrLexerInvalidChar, Code: "LexerInvalidChar", Description: "The SQL expression contains an invalid character.", HTTPStatusCode: http.StatusBadRequest, }, ErrLexerInvalidOperator: { + ErrCode: ErrLexerInvalidOperator, Code: "LexerInvalidOperator", Description: "The SQL expression contains an invalid literal.", HTTPStatusCode: http.StatusBadRequest, }, ErrLexerInvalidLiteral: { + ErrCode: ErrLexerInvalidLiteral, Code: "LexerInvalidLiteral", Description: "The SQL expression contains an invalid operator.", HTTPStatusCode: http.StatusBadRequest, }, ErrLexerInvalidIONLiteral: { + ErrCode: ErrLexerInvalidIONLiteral, Code: "LexerInvalidIONLiteral", Description: "The SQL expression contains an invalid operator.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedDatePart: { + ErrCode: ErrParseExpectedDatePart, Code: "ParseExpectedDatePart", Description: "Did not find the expected date part in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedKeyword: { + ErrCode: ErrParseExpectedKeyword, Code: "ParseExpectedKeyword", Description: "Did not find the expected keyword in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedTokenType: { + ErrCode: ErrParseExpectedTokenType, Code: "ParseExpectedTokenType", Description: "Did not find the expected token in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpected2TokenTypes: { + ErrCode: ErrParseExpected2TokenTypes, Code: "ParseExpected2TokenTypes", Description: "Did not find the expected token in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedNumber: { + ErrCode: ErrParseExpectedNumber, Code: "ParseExpectedNumber", Description: "Did not find the expected number in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedRightParenBuiltinFunctionCall: { + ErrCode: ErrParseExpectedRightParenBuiltinFunctionCall, Code: "ParseExpectedRightParenBuiltinFunctionCall", Description: "Did not find the expected right parenthesis character in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedTypeName: { + ErrCode: ErrParseExpectedTypeName, Code: "ParseExpectedTypeName", Description: "Did not find the expected type name in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedWhenClause: { + ErrCode: ErrParseExpectedWhenClause, Code: "ParseExpectedWhenClause", Description: "Did not find the expected WHEN clause in the SQL expression. CASE is not supported.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnsupportedToken: { + ErrCode: ErrParseUnsupportedToken, Code: "ParseUnsupportedToken", Description: "The SQL expression contains an unsupported token.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnsupportedLiteralsGroupBy: { + ErrCode: ErrParseUnsupportedLiteralsGroupBy, Code: "ParseUnsupportedLiteralsGroupBy", Description: "The SQL expression contains an unsupported use of GROUP BY.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedMember: { + ErrCode: ErrParseExpectedMember, Code: "ParseExpectedMember", Description: "The SQL expression contains an unsupported use of MEMBER.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnsupportedSelect: { + ErrCode: ErrParseUnsupportedSelect, Code: "ParseUnsupportedSelect", Description: "The SQL expression contains an unsupported use of SELECT.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnsupportedCase: { + ErrCode: ErrParseUnsupportedCase, Code: "ParseUnsupportedCase", Description: "The SQL expression contains an unsupported use of CASE.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnsupportedCaseClause: { + ErrCode: ErrParseUnsupportedCaseClause, Code: "ParseUnsupportedCaseClause", Description: "The SQL expression contains an unsupported use of CASE.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnsupportedAlias: { + ErrCode: ErrParseUnsupportedAlias, Code: "ParseUnsupportedAlias", Description: "The SQL expression contains an unsupported use of ALIAS.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnsupportedSyntax: { + ErrCode: ErrParseUnsupportedSyntax, Code: "ParseUnsupportedSyntax", Description: "The SQL expression contains unsupported syntax.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnknownOperator: { + ErrCode: ErrParseUnknownOperator, Code: "ParseUnknownOperator", Description: "The SQL expression contains an invalid operator.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseMissingIdentAfterAt: { + ErrCode: ErrParseMissingIdentAfterAt, Code: "ParseMissingIdentAfterAt", Description: "Did not find the expected identifier after the @ symbol in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnexpectedOperator: { + ErrCode: ErrParseUnexpectedOperator, Code: "ParseUnexpectedOperator", Description: "The SQL expression contains an unexpected operator.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnexpectedTerm: { + ErrCode: ErrParseUnexpectedTerm, Code: "ParseUnexpectedTerm", Description: "The SQL expression contains an unexpected term.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnexpectedToken: { + ErrCode: ErrParseUnexpectedToken, Code: "ParseUnexpectedToken", Description: "The SQL expression contains an unexpected token.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnexpectedKeyword: { + ErrCode: ErrParseUnexpectedKeyword, Code: "ParseUnexpectedKeyword", Description: "The SQL expression contains an unexpected keyword.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedExpression: { + ErrCode: ErrParseExpectedExpression, Code: "ParseExpectedExpression", Description: "Did not find the expected SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedLeftParenAfterCast: { + ErrCode: ErrParseExpectedLeftParenAfterCast, Code: "ParseExpectedLeftParenAfterCast", Description: "Did not find expected the left parenthesis in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedLeftParenValueConstructor: { + ErrCode: ErrParseExpectedLeftParenValueConstructor, Code: "ParseExpectedLeftParenValueConstructor", Description: "Did not find expected the left parenthesis in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedLeftParenBuiltinFunctionCall: { + ErrCode: ErrParseExpectedLeftParenBuiltinFunctionCall, Code: "ParseExpectedLeftParenBuiltinFunctionCall", Description: "Did not find the expected left parenthesis in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedArgumentDelimiter: { + ErrCode: ErrParseExpectedArgumentDelimiter, Code: "ParseExpectedArgumentDelimiter", Description: "Did not find the expected argument delimiter in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseCastArity: { + ErrCode: ErrParseCastArity, Code: "ParseCastArity", Description: "The SQL expression CAST has incorrect arity.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseInvalidTypeParam: { + ErrCode: ErrParseInvalidTypeParam, Code: "ParseInvalidTypeParam", Description: "The SQL expression contains an invalid parameter value.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseEmptySelect: { + ErrCode: ErrParseEmptySelect, Code: "ParseEmptySelect", Description: "The SQL expression contains an empty SELECT.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseSelectMissingFrom: { + ErrCode: ErrParseSelectMissingFrom, Code: "ParseSelectMissingFrom", Description: "GROUP is not supported in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedIdentForGroupName: { + ErrCode: ErrParseExpectedIdentForGroupName, Code: "ParseExpectedIdentForGroupName", Description: "GROUP is not supported in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedIdentForAlias: { + ErrCode: ErrParseExpectedIdentForAlias, Code: "ParseExpectedIdentForAlias", Description: "Did not find the expected identifier for the alias in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseUnsupportedCallWithStar: { + ErrCode: ErrParseUnsupportedCallWithStar, Code: "ParseUnsupportedCallWithStar", Description: "Only COUNT with (*) as a parameter is supported in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseNonUnaryAgregateFunctionCall: { + ErrCode: ErrParseNonUnaryAgregateFunctionCall, Code: "ParseNonUnaryAgregateFunctionCall", Description: "Only one argument is supported for aggregate functions in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseMalformedJoin: { + ErrCode: ErrParseMalformedJoin, Code: "ParseMalformedJoin", Description: "JOIN is not supported in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseExpectedIdentForAt: { + ErrCode: ErrParseExpectedIdentForAt, Code: "ParseExpectedIdentForAt", Description: "Did not find the expected identifier for AT name in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseAsteriskIsNotAloneInSelectList: { + ErrCode: ErrParseAsteriskIsNotAloneInSelectList, Code: "ParseAsteriskIsNotAloneInSelectList", Description: "Other expressions are not allowed in the SELECT list when '*' is used without dot notation in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseCannotMixSqbAndWildcardInSelectList: { + ErrCode: ErrParseCannotMixSqbAndWildcardInSelectList, Code: "ParseCannotMixSqbAndWildcardInSelectList", Description: "Cannot mix [] and * in the same expression in a SELECT list in SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrParseInvalidContextForWildcardInSelectList: { + ErrCode: ErrParseInvalidContextForWildcardInSelectList, Code: "ParseInvalidContextForWildcardInSelectList", Description: "Invalid use of * in SELECT list in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrIncorrectSQLFunctionArgumentType: { + ErrCode: ErrIncorrectSQLFunctionArgumentType, Code: "IncorrectSqlFunctionArgumentType", Description: "Incorrect type of arguments in function call in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrValueParseFailure: { + ErrCode: ErrValueParseFailure, Code: "ValueParseFailure", Description: "Time stamp parse failure in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrEvaluatorInvalidArguments: { + ErrCode: ErrEvaluatorInvalidArguments, Code: "EvaluatorInvalidArguments", Description: "Incorrect number of arguments in the function call in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrIntegerOverflow: { + ErrCode: ErrIntegerOverflow, Code: "IntegerOverflow", Description: "Int overflow or underflow in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrLikeInvalidInputs: { + ErrCode: ErrLikeInvalidInputs, Code: "LikeInvalidInputs", Description: "Invalid argument given to the LIKE clause in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrCastFailed: { + ErrCode: ErrCastFailed, Code: "CastFailed", Description: "Attempt to convert from one data type to another using CAST failed in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidCast: { + ErrCode: ErrInvalidCast, Code: "InvalidCast", Description: "Attempt to convert from one data type to another using CAST failed in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrEvaluatorInvalidTimestampFormatPattern: { + ErrCode: ErrEvaluatorInvalidTimestampFormatPattern, Code: "EvaluatorInvalidTimestampFormatPattern", Description: "Time stamp format pattern requires additional fields in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing: { + ErrCode: ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing, Code: "EvaluatorInvalidTimestampFormatPatternSymbolForParsing", Description: "Time stamp format pattern contains a valid format symbol that cannot be applied to time stamp parsing in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrEvaluatorTimestampFormatPatternDuplicateFields: { + ErrCode: ErrEvaluatorTimestampFormatPatternDuplicateFields, Code: "EvaluatorTimestampFormatPatternDuplicateFields", Description: "Time stamp format pattern contains multiple format specifiers representing the time stamp field in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch: { + ErrCode: ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch, Code: "EvaluatorUnterminatedTimestampFormatPatternToken", Description: "Time stamp format pattern contains unterminated token in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrEvaluatorUnterminatedTimestampFormatPatternToken: { + ErrCode: ErrEvaluatorUnterminatedTimestampFormatPatternToken, Code: "EvaluatorInvalidTimestampFormatPatternToken", Description: "Time stamp format pattern contains an invalid token in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrEvaluatorInvalidTimestampFormatPatternToken: { + ErrCode: ErrEvaluatorInvalidTimestampFormatPatternToken, Code: "EvaluatorInvalidTimestampFormatPatternToken", Description: "Time stamp format pattern contains an invalid token in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrEvaluatorInvalidTimestampFormatPatternSymbol: { + ErrCode: ErrEvaluatorInvalidTimestampFormatPatternSymbol, Code: "EvaluatorInvalidTimestampFormatPatternSymbol", Description: "Time stamp format pattern contains an invalid symbol in the SQL expression.", HTTPStatusCode: http.StatusBadRequest, }, ErrEvaluatorBindingDoesNotExist: { + ErrCode: ErrEvaluatorBindingDoesNotExist, Code: "ErrEvaluatorBindingDoesNotExist", Description: "A column name or a path provided does not exist in the SQL expression", HTTPStatusCode: http.StatusBadRequest, }, ErrMissingHeaders: { + ErrCode: ErrMissingHeaders, Code: "MissingHeaders", Description: "Some headers in the query are missing from the file. Check the file and try again.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidColumnIndex: { + ErrCode: ErrInvalidColumnIndex, Code: "InvalidColumnIndex", Description: "The column index is invalid. Please check the service documentation and try again.", HTTPStatusCode: http.StatusBadRequest, }, ErrInvalidDecompressedSize: { + ErrCode: ErrInvalidDecompressedSize, Code: "XMinioInvalidDecompressedSize", Description: "The data provided is unfit for decompression", HTTPStatusCode: http.StatusBadRequest, }, ErrAddUserInvalidArgument: { + ErrCode: ErrAddUserInvalidArgument, Code: "XMinioInvalidIAMCredentials", Description: "User is not allowed to be same as admin access key", HTTPStatusCode: http.StatusConflict, }, ErrAdminAccountNotEligible: { + ErrCode: ErrAdminAccountNotEligible, Code: "XMinioInvalidIAMCredentials", Description: "The administrator key is not eligible for this operation", HTTPStatusCode: http.StatusConflict, }, ErrServiceAccountNotFound: { + ErrCode: ErrServiceAccountNotFound, Code: "XMinioInvalidIAMCredentials", Description: "The specified service account is not found", HTTPStatusCode: http.StatusNotFound, }, ErrPostPolicyConditionInvalidFormat: { + ErrCode: ErrPostPolicyConditionInvalidFormat, Code: "PostPolicyInvalidKeyName", Description: "Invalid according to Policy: Policy Condition failed", HTTPStatusCode: http.StatusForbidden, @@ -1609,6 +1863,12 @@ var errorCodes = errorCodeMap{ // Add your error structure here. } +// IsS3Error check if the provided error is a specific s3 error. +func IsS3Error(err error, code ErrorCode) bool { + e, ok := err.(Error) + return ok && e.ErrCode == code +} + func (e errorCodeMap) ToAPIErrWithErr(errCode ErrorCode, err error) Error { apiErr, ok := e[errCode] if !ok { @@ -1663,365 +1923,20 @@ func getAPIErrorResponse(ctx context.Context, err error, resource, requestID, ho } } -// SignatureDoesNotMatch - when content md5 does not match with what was sent from client. -type SignatureDoesNotMatch struct{} - -func (e SignatureDoesNotMatch) Error() string { - return "The request signature we calculated does not match the signature you provided. Check your key and signing method." -} - -// StorageFull storage ran out of space. -type StorageFull struct{} - -func (e StorageFull) Error() string { - return "Storage reached its minimum free disk threshold." -} - -// SlowDown too many file descriptors open or backend busy . -type SlowDown struct{} - -func (e SlowDown) Error() string { - return "Please reduce your request rate" -} - -// InsufficientReadQuorum storage cannot satisfy quorum for read operation. -type InsufficientReadQuorum struct{} - -func (e InsufficientReadQuorum) Error() string { - return "Storage resources are insufficient for the read operation." -} - -// InsufficientWriteQuorum storage cannot satisfy quorum for write operation. -type InsufficientWriteQuorum struct{} - -func (e InsufficientWriteQuorum) Error() string { - return "Storage resources are insufficient for the write operation." -} - // GenericError - generic object layer error. type GenericError struct { Bucket string Object string } -// BucketNotFound bucket does not exist. -type BucketNotFound GenericError - -func (e BucketNotFound) Error() string { - return "Bucket not found: " + e.Bucket -} - -// BucketAlreadyExists the requested bucket name is not available. -type BucketAlreadyExists GenericError - -func (e BucketAlreadyExists) Error() string { - return "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." -} - -// BucketAlreadyOwnedByYou already owned by you. -type BucketAlreadyOwnedByYou GenericError - -func (e BucketAlreadyOwnedByYou) Error() string { - return "Bucket already owned by you: " + e.Bucket -} - -// BucketNotEmpty bucket is not empty. -type BucketNotEmpty GenericError - -func (e BucketNotEmpty) Error() string { - return "Bucket not empty: " + e.Bucket -} - -// ObjectNotFound object does not exist. -type ObjectNotFound GenericError - -func (e ObjectNotFound) Error() string { - return "Object not found: " + e.Bucket + "#" + e.Object -} - // ObjectAlreadyExists object already exists. +// This type should be removed when s3-gw will support versioning. type ObjectAlreadyExists GenericError func (e ObjectAlreadyExists) Error() string { return "Object: " + e.Bucket + "#" + e.Object + " already exists" } -// ObjectExistsAsDirectory object already exists as a directory. -type ObjectExistsAsDirectory GenericError - -func (e ObjectExistsAsDirectory) Error() string { - return "Object exists on : " + e.Bucket + " as directory " + e.Object -} - -// PrefixAccessDenied object access is denied. -type PrefixAccessDenied GenericError - -func (e PrefixAccessDenied) Error() string { - return "Prefix access is denied: " + e.Bucket + SlashSeparator + e.Object -} - -// ParentIsObject object access is denied. -type ParentIsObject GenericError - -func (e ParentIsObject) Error() string { - return "Parent is object " + e.Bucket + SlashSeparator + path.Dir(e.Object) -} - -// BucketExists bucket exists. -type BucketExists GenericError - -func (e BucketExists) Error() string { - return "Bucket exists: " + e.Bucket -} - -// UnsupportedDelimiter - unsupported delimiter. -type UnsupportedDelimiter struct { - Delimiter string -} - -func (e UnsupportedDelimiter) Error() string { - return fmt.Sprintf("delimiter '%s' is not supported. Only '/' is supported", e.Delimiter) -} - -// InvalidUploadIDKeyCombination - invalid upload id and key marker combination. -type InvalidUploadIDKeyCombination struct { - UploadIDMarker, KeyMarker string -} - -func (e InvalidUploadIDKeyCombination) Error() string { - return fmt.Sprintf("Invalid combination of uploadID marker '%s' and marker '%s'", e.UploadIDMarker, e.KeyMarker) -} - -// InvalidMarkerPrefixCombination - invalid marker and prefix combination. -type InvalidMarkerPrefixCombination struct { - Marker, Prefix string -} - -func (e InvalidMarkerPrefixCombination) Error() string { - return fmt.Sprintf("Invalid combination of marker '%s' and prefix '%s'", e.Marker, e.Prefix) -} - -// BucketPolicyNotFound - no bucket policy found. -type BucketPolicyNotFound GenericError - -func (e BucketPolicyNotFound) Error() string { - return "No bucket policy configuration found for bucket: " + e.Bucket -} - -// BucketLifecycleNotFound - no bucket lifecycle found. -type BucketLifecycleNotFound GenericError - -func (e BucketLifecycleNotFound) Error() string { - return "No bucket lifecycle configuration found for bucket : " + e.Bucket -} - -// BucketSSEConfigNotFound - no bucket encryption found. -type BucketSSEConfigNotFound GenericError - -func (e BucketSSEConfigNotFound) Error() string { - return "No bucket encryption configuration found for bucket: " + e.Bucket -} - -// BucketTaggingNotFound - no bucket tags found. -type BucketTaggingNotFound GenericError - -func (e BucketTaggingNotFound) Error() string { - return "No bucket tags found for bucket: " + e.Bucket -} - -// BucketObjectLockConfigNotFound - no bucket object lock config found. -type BucketObjectLockConfigNotFound GenericError - -func (e BucketObjectLockConfigNotFound) Error() string { - return "No bucket object lock configuration found for bucket: " + e.Bucket -} - -// BucketQuotaConfigNotFound - no bucket quota config found. -type BucketQuotaConfigNotFound GenericError - -func (e BucketQuotaConfigNotFound) Error() string { - return "No quota config found for bucket : " + e.Bucket -} - -// BucketQuotaExceeded - bucket quota exceeded. -type BucketQuotaExceeded GenericError - -func (e BucketQuotaExceeded) Error() string { - return "Bucket quota exceeded for bucket: " + e.Bucket -} - -// Bucket related errors. - -// BucketNameInvalid - bucketname provided is invalid. -type BucketNameInvalid GenericError - -// Error returns string an error formatted as the given text. -func (e BucketNameInvalid) Error() string { - return "Bucket name invalid: " + e.Bucket -} - -// Object related errors. - -// ObjectNameInvalid - object name provided is invalid. -type ObjectNameInvalid GenericError - -// ObjectNameTooLong - object name too long. -type ObjectNameTooLong GenericError - -// ObjectNamePrefixAsSlash - object name has a slash as prefix. -type ObjectNamePrefixAsSlash GenericError - -// Error returns string an error formatted as the given text. -func (e ObjectNameInvalid) Error() string { - return "Object name invalid: " + e.Bucket + "#" + e.Object -} - -// Error returns string an error formatted as the given text. -func (e ObjectNameTooLong) Error() string { - return "Object name too long: " + e.Bucket + "#" + e.Object -} - -// Error returns string an error formatted as the given text. -func (e ObjectNamePrefixAsSlash) Error() string { - return "Object name contains forward slash as pefix: " + e.Bucket + "#" + e.Object -} - -// AllAccessDisabled All access to this object has been disabled. -type AllAccessDisabled GenericError - -// Error returns string an error formatted as the given text. -func (e AllAccessDisabled) Error() string { - return "All access to this object has been disabled" -} - -// IncompleteBody You did not provide the number of bytes specified by the Content-Length HTTP header. -type IncompleteBody GenericError - -// Error returns string an error formatted as the given text. -func (e IncompleteBody) Error() string { - return e.Bucket + "#" + e.Object + "has incomplete body" -} - -// InvalidRange - invalid range typed error. -type InvalidRange struct { - OffsetBegin int64 - OffsetEnd int64 - ResourceSize int64 -} - -func (e InvalidRange) Error() string { - return fmt.Sprintf("The requested range \"bytes %d-%d/%d\" is not satisfiable.", e.OffsetBegin, e.OffsetEnd, e.ResourceSize) -} - -// ObjectTooLarge error returned when the size of the object > max object size allowed (5G) per request. -type ObjectTooLarge GenericError - -func (e ObjectTooLarge) Error() string { - return "size of the object greater than what is allowed(5G)" -} - -// ObjectTooSmall error returned when the size of the object < what is expected. -type ObjectTooSmall GenericError - -func (e ObjectTooSmall) Error() string { - return "size of the object less than what is expected" -} - -// OperationTimedOut - a timeout occurred. -type OperationTimedOut struct { -} - -func (e OperationTimedOut) Error() string { - return "Operation timed out" -} - -// Multipart related errors. - -// MalformedUploadID malformed upload id. -type MalformedUploadID struct { - UploadID string -} - -func (e MalformedUploadID) Error() string { - return "Malformed upload id " + e.UploadID -} - -// InvalidUploadID invalid upload id. -type InvalidUploadID struct { - Bucket string - Object string - UploadID string -} - -func (e InvalidUploadID) Error() string { - return "Invalid upload id " + e.UploadID -} - -// InvalidPart One or more of the specified parts could not be found. -type InvalidPart struct { - PartNumber int - ExpETag string - GotETag string -} - -func (e InvalidPart) Error() string { - return fmt.Sprintf("Specified part could not be found. PartNumber %d, Expected %s, got %s", - e.PartNumber, e.ExpETag, e.GotETag) -} - -// PartTooSmall - error if part size is less than 5MB. -type PartTooSmall struct { - PartSize int64 - PartNumber int - PartETag string -} - -func (e PartTooSmall) Error() string { - return fmt.Sprintf("Part size for %d should be at least 5MB", e.PartNumber) -} - -// PartTooBig returned if size of part is bigger than the allowed limit. -type PartTooBig struct{} - -func (e PartTooBig) Error() string { - return "Part size bigger than the allowed limit" -} - -// InvalidETag error returned when the etag has changed on disk. -type InvalidETag struct{} - -func (e InvalidETag) Error() string { - return "etag of the object has changed" -} - -// NotImplemented If a feature is not implemented. -type NotImplemented struct{} - -func (e NotImplemented) Error() string { - return "Not Implemented" -} - -// UnsupportedMetadata - unsupported metadata. -type UnsupportedMetadata struct{} - -func (e UnsupportedMetadata) Error() string { - return "Unsupported headers in Metadata" -} - -// BackendDown is returned for network errors or if the gateway's backend is down. -type BackendDown struct{} - -func (e BackendDown) Error() string { - return "Backend down" -} - -// PreConditionFailed - Check if copy precondition failed. -type PreConditionFailed struct{} - -func (e PreConditionFailed) Error() string { - return "At least one of the pre-conditions you specified did not hold" -} - // DeleteError - returns when cant remove object. type DeleteError struct { Err error diff --git a/api/errors_test.go b/api/errors_test.go new file mode 100644 index 00000000..17e272e8 --- /dev/null +++ b/api/errors_test.go @@ -0,0 +1,26 @@ +package api + +import ( + "errors" + "testing" +) + +func BenchmarkErrCode(b *testing.B) { + err := GetAPIError(ErrNoSuchKey) + + for i := 0; i < b.N; i++ { + if IsS3Error(err, ErrNoSuchKey) { + _ = err + } + } +} + +func BenchmarkErrorsIs(b *testing.B) { + err := GetAPIError(ErrNoSuchKey) + + for i := 0; i < b.N; i++ { + if errors.Is(err, GetAPIError(ErrNoSuchKey)) { + _ = err + } + } +} diff --git a/api/handler/delete.go b/api/handler/delete.go index f6cc9945..1898949c 100644 --- a/api/handler/delete.go +++ b/api/handler/delete.go @@ -8,7 +8,6 @@ import ( "github.com/nspcc-dev/neofs-s3-gw/api" "github.com/nspcc-dev/neofs-s3-gw/api/layer" "go.uber.org/zap" - "google.golang.org/grpc/status" ) // DeleteObjectsRequest - xml carrying the object key names which needs to be deleted. @@ -122,11 +121,6 @@ func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Re code := "BadRequest" desc := err.Error() - if st, ok := status.FromError(err.Err); ok && st != nil { - desc = st.Message() - code = st.Code().String() - } - response.Errors = append(response.Errors, DeleteError{ Code: code, Message: desc, diff --git a/api/handler/head.go b/api/handler/head.go index 16a686d1..d64a21cf 100644 --- a/api/handler/head.go +++ b/api/handler/head.go @@ -2,7 +2,6 @@ package handler import ( "bytes" - "errors" "net/http" "github.com/gorilla/mux" @@ -43,10 +42,6 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) { zap.String("object_name", obj), zap.Error(err)) - var genErr *api.ObjectNotFound - if ok := errors.As(err, &genErr); ok { - err = api.GetAPIError(api.ErrNoSuchKey) - } api.WriteErrorResponse(r.Context(), w, err, r.URL) return } @@ -87,13 +82,7 @@ func (h *handler) HeadBucketHandler(w http.ResponseWriter, r *http.Request) { zap.String("bucket_name", bkt), zap.Error(err)) - code := http.StatusBadRequest - if errors.Is(err, layer.ErrBucketNotFound) { - code = http.StatusNotFound - } - - api.WriteResponse(w, code, nil, api.MimeNone) - + api.WriteErrorResponse(r.Context(), w, err, r.URL) return } diff --git a/api/layer/container.go b/api/layer/container.go index c5619686..0c9e36ef 100644 --- a/api/layer/container.go +++ b/api/layer/container.go @@ -50,7 +50,7 @@ func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*BucketInfo, er zap.Error(err)) if strings.Contains(err.Error(), "container not found") { - return nil, ErrBucketNotFound + return nil, api.GetAPIError(api.ErrNoSuchBucket) } return nil, err } diff --git a/api/layer/layer.go b/api/layer/layer.go index a3d348b9..9918a08a 100644 --- a/api/layer/layer.go +++ b/api/layer/layer.go @@ -3,7 +3,6 @@ package layer import ( "context" "crypto/ecdsa" - "errors" "fmt" "io" "net/url" @@ -19,8 +18,6 @@ import ( "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox" "github.com/nspcc-dev/neofs-sdk-go/pkg/pool" "go.uber.org/zap" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type ( @@ -122,17 +119,6 @@ type ( } ) -var ( - // ErrObjectExists is returned on attempts to create already existing object. - ErrObjectExists = errors.New("object exists") - // ErrObjectNotExists is returned on attempts to work with non-existing object. - ErrObjectNotExists = errors.New("object not exists") - // ErrBucketAlreadyExists is returned on attempts to create already existing bucket. - ErrBucketAlreadyExists = errors.New("bucket exists") - // ErrBucketNotFound is returned on attempts to get not existing bucket. - ErrBucketNotFound = errors.New("bucket not found") -) - const ( unversionedObjectVersionID = "null" ) @@ -198,7 +184,7 @@ func (n *layer) GetBucketInfo(ctx context.Context, name string) (*BucketInfo, er } } - return nil, ErrBucketNotFound + return nil, api.GetAPIError(api.ErrNoSuchBucket) } return n.containerInfo(ctx, containerID) @@ -257,11 +243,7 @@ func (n *layer) checkObject(ctx context.Context, cid *cid.ID, filename string) e var err error if _, err = n.objectFindID(ctx, &findParams{cid: cid, val: filename}); err == nil { - return ErrObjectExists - } else if state, ok := status.FromError(err); !ok || state == nil { - return err - } else if state.Code() == codes.NotFound { - return ErrObjectNotExists + return new(api.ObjectAlreadyExists) } return err @@ -378,13 +360,13 @@ func (n *layer) DeleteObjects(ctx context.Context, bucket string, objects []stri func (n *layer) CreateBucket(ctx context.Context, p *CreateBucketParams) (*cid.ID, error) { _, err := n.GetBucketInfo(ctx, p.Name) if err != nil { - if errors.Is(err, ErrBucketNotFound) { + if api.IsS3Error(err, api.ErrNoSuchBucket) { return n.createContainer(ctx, p) } return nil, err } - return nil, ErrBucketAlreadyExists + return nil, api.GetAPIError(api.ErrBucketAlreadyExists) } func (n *layer) DeleteBucket(ctx context.Context, p *DeleteBucketParams) error { diff --git a/api/layer/object.go b/api/layer/object.go index 3116aad5..fb31e220 100644 --- a/api/layer/object.go +++ b/api/layer/object.go @@ -81,7 +81,7 @@ func (n *layer) objectFindID(ctx context.Context, p *findParams) (*object.ID, er if result, err := n.objectSearch(ctx, p); err != nil { return nil, err } else if ln := len(result); ln == 0 { - return nil, &api.ObjectNotFound{Bucket: p.cid.String(), Object: p.val} + return nil, api.GetAPIError(api.ErrNoSuchKey) } else if ln == 1 { return result[0], nil } @@ -123,12 +123,16 @@ func (n *layer) objectPut(ctx context.Context, p *PutObjectParams) (*ObjectInfo, return nil, err } else if bkt, err = n.GetBucketInfo(ctx, p.Bucket); err != nil { return nil, err - } else if err = n.checkObject(ctx, bkt.CID, p.Object); err != nil && err != ErrObjectNotExists { - return nil, err - } else if err == ErrObjectExists { - return nil, &api.ObjectAlreadyExists{ - Bucket: p.Bucket, - Object: p.Object, + } else if err = n.checkObject(ctx, bkt.CID, p.Object); err != nil { + var errExist *api.ObjectAlreadyExists + if ok := errors.As(err, &errExist); ok { + errExist.Bucket = p.Bucket + errExist.Object = p.Object + return nil, errExist + } + + if !api.IsS3Error(err, api.ErrNoSuchKey) { + return nil, err } } diff --git a/api/response.go b/api/response.go index f739198c..dbfd26b2 100644 --- a/api/response.go +++ b/api/response.go @@ -38,6 +38,7 @@ type ( // Error structure represents API error. Error struct { + ErrCode ErrorCode Code string Description string HTTPStatusCode int