mirror of https://github.com/minio/minio.git
				
				
				
			
		
			
				
	
	
		
			421 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			421 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
/*
 | 
						|
 * Minio Cloud Storage, (C) 2015 Minio, Inc.
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/xml"
 | 
						|
	"net/http"
 | 
						|
)
 | 
						|
 | 
						|
// APIError structure
 | 
						|
type APIError struct {
 | 
						|
	Code           string
 | 
						|
	Description    string
 | 
						|
	HTTPStatusCode int
 | 
						|
}
 | 
						|
 | 
						|
// APIErrorResponse - error response format
 | 
						|
type APIErrorResponse struct {
 | 
						|
	XMLName    xml.Name `xml:"Error" json:"-"`
 | 
						|
	Code       string
 | 
						|
	Message    string
 | 
						|
	Key        string
 | 
						|
	BucketName string
 | 
						|
	Resource   string
 | 
						|
	RequestID  string `xml:"RequestId"`
 | 
						|
	HostID     string `xml:"HostId"`
 | 
						|
}
 | 
						|
 | 
						|
// APIErrorCode type of error status.
 | 
						|
type APIErrorCode int
 | 
						|
 | 
						|
// Error codes, non exhaustive list - http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
 | 
						|
const (
 | 
						|
	ErrNone APIErrorCode = iota
 | 
						|
	ErrAccessDenied
 | 
						|
	ErrBadDigest
 | 
						|
	ErrBucketAlreadyExists
 | 
						|
	ErrEntityTooSmall
 | 
						|
	ErrEntityTooLarge
 | 
						|
	ErrIncompleteBody
 | 
						|
	ErrInternalError
 | 
						|
	ErrInvalidAccessKeyID
 | 
						|
	ErrInvalidBucketName
 | 
						|
	ErrInvalidDigest
 | 
						|
	ErrInvalidRange
 | 
						|
	ErrInvalidMaxKeys
 | 
						|
	ErrInvalidMaxUploads
 | 
						|
	ErrInvalidMaxParts
 | 
						|
	ErrInvalidPartNumberMarker
 | 
						|
	ErrInvalidRequestBody
 | 
						|
	ErrInvalidCopySource
 | 
						|
	ErrInvalidCopyDest
 | 
						|
	ErrInvalidPolicyDocument
 | 
						|
	ErrMalformedXML
 | 
						|
	ErrMissingContentLength
 | 
						|
	ErrMissingContentMD5
 | 
						|
	ErrMissingRequestBodyError
 | 
						|
	ErrNoSuchBucket
 | 
						|
	ErrNoSuchBucketPolicy
 | 
						|
	ErrNoSuchKey
 | 
						|
	ErrNoSuchUpload
 | 
						|
	ErrNotImplemented
 | 
						|
	ErrRequestTimeTooSkewed
 | 
						|
	ErrSignatureDoesNotMatch
 | 
						|
	ErrMethodNotAllowed
 | 
						|
	ErrInvalidPart
 | 
						|
	ErrInvalidPartOrder
 | 
						|
	ErrAuthorizationHeaderMalformed
 | 
						|
	ErrMalformedPOSTRequest
 | 
						|
	ErrSignatureVersionNotSupported
 | 
						|
	ErrBucketNotEmpty
 | 
						|
	ErrRootPathFull
 | 
						|
	ErrObjectExistsAsPrefix
 | 
						|
	ErrAllAccessDisabled
 | 
						|
	ErrMalformedPolicy
 | 
						|
	ErrMissingFields
 | 
						|
	ErrMissingCredTag
 | 
						|
	ErrCredMalformed
 | 
						|
	ErrInvalidRegion
 | 
						|
	ErrInvalidService
 | 
						|
	ErrInvalidRequestVersion
 | 
						|
	ErrMissingSignTag
 | 
						|
	ErrMissingSignHeadersTag
 | 
						|
	ErrPolicyAlreadyExpired
 | 
						|
	ErrMalformedDate
 | 
						|
	ErrMalformedExpires
 | 
						|
	ErrAuthHeaderEmpty
 | 
						|
	ErrDateHeaderMissing
 | 
						|
	ErrExpiredPresignRequest
 | 
						|
	ErrMissingDateHeader
 | 
						|
	ErrInvalidQuerySignatureAlgo
 | 
						|
	ErrInvalidQueryParams
 | 
						|
	// Add new error codes here.
 | 
						|
)
 | 
						|
 | 
						|
// error code to APIError structure, these fields carry respective
 | 
						|
// descriptions for all the error responses.
 | 
						|
var errorCodeResponse = map[APIErrorCode]APIError{
 | 
						|
	ErrInvalidCopyDest: {
 | 
						|
		Code:           "InvalidRequest",
 | 
						|
		Description:    "This copy request is illegal because it is trying to copy an object to itself.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidCopySource: {
 | 
						|
		Code:           "InvalidArgument",
 | 
						|
		Description:    "Copy Source must mention the source bucket and key: sourcebucket/sourcekey.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidRequestBody: {
 | 
						|
		Code:           "InvalidArgument",
 | 
						|
		Description:    "Body shouldn't be set for this request.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidMaxUploads: {
 | 
						|
		Code:           "InvalidArgument",
 | 
						|
		Description:    "Argument maxUploads must be an integer between 0 and 2147483647.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidMaxKeys: {
 | 
						|
		Code:           "InvalidArgument",
 | 
						|
		Description:    "Argument maxKeys must be an integer between 0 and 2147483647.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidMaxParts: {
 | 
						|
		Code:           "InvalidArgument",
 | 
						|
		Description:    "Argument maxParts must be an integer between 1 and 10000.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidPartNumberMarker: {
 | 
						|
		Code:           "InvalidArgument",
 | 
						|
		Description:    "Argument partNumberMarker must be an integer.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidPolicyDocument: {
 | 
						|
		Code:           "InvalidPolicyDocument",
 | 
						|
		Description:    "The content of the form does not meet the conditions specified in the policy document.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrAccessDenied: {
 | 
						|
		Code:           "AccessDenied",
 | 
						|
		Description:    "Access Denied.",
 | 
						|
		HTTPStatusCode: http.StatusForbidden,
 | 
						|
	},
 | 
						|
	ErrBadDigest: {
 | 
						|
		Code:           "BadDigest",
 | 
						|
		Description:    "The Content-Md5 you specified did not match what we received.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrBucketAlreadyExists: {
 | 
						|
		Code:           "BucketAlreadyExists",
 | 
						|
		Description:    "The requested bucket name is not available.",
 | 
						|
		HTTPStatusCode: http.StatusConflict,
 | 
						|
	},
 | 
						|
	ErrEntityTooSmall: {
 | 
						|
		Code:           "EntityTooSmall",
 | 
						|
		Description:    "Your proposed upload is smaller than the minimum allowed object size.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrEntityTooLarge: {
 | 
						|
		Code:           "EntityTooLarge",
 | 
						|
		Description:    "Your proposed upload exceeds the maximum allowed object size.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrIncompleteBody: {
 | 
						|
		Code:           "IncompleteBody",
 | 
						|
		Description:    "You did not provide the number of bytes specified by the Content-Length HTTP header.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInternalError: {
 | 
						|
		Code:           "InternalError",
 | 
						|
		Description:    "We encountered an internal error, please try again.",
 | 
						|
		HTTPStatusCode: http.StatusInternalServerError,
 | 
						|
	},
 | 
						|
	ErrInvalidAccessKeyID: {
 | 
						|
		Code:           "InvalidAccessKeyID",
 | 
						|
		Description:    "The access key ID you provided does not exist in our records.",
 | 
						|
		HTTPStatusCode: http.StatusForbidden,
 | 
						|
	},
 | 
						|
	ErrInvalidBucketName: {
 | 
						|
		Code:           "InvalidBucketName",
 | 
						|
		Description:    "The specified bucket is not valid.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidDigest: {
 | 
						|
		Code:           "InvalidDigest",
 | 
						|
		Description:    "The Content-Md5 you specified is not valid.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidRange: {
 | 
						|
		Code:           "InvalidRange",
 | 
						|
		Description:    "The requested range cannot be satisfied.",
 | 
						|
		HTTPStatusCode: http.StatusRequestedRangeNotSatisfiable,
 | 
						|
	},
 | 
						|
	ErrMalformedXML: {
 | 
						|
		Code:           "MalformedXML",
 | 
						|
		Description:    "The XML you provided was not well-formed or did not validate against our published schema.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMissingContentLength: {
 | 
						|
		Code:           "MissingContentLength",
 | 
						|
		Description:    "You must provide the Content-Length HTTP header.",
 | 
						|
		HTTPStatusCode: http.StatusLengthRequired,
 | 
						|
	},
 | 
						|
	ErrMissingContentMD5: {
 | 
						|
		Code:           "MissingContentMD5",
 | 
						|
		Description:    "Missing required header for this request: Content-Md5.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMissingRequestBodyError: {
 | 
						|
		Code:           "MissingRequestBodyError",
 | 
						|
		Description:    "Request body is empty.",
 | 
						|
		HTTPStatusCode: http.StatusLengthRequired,
 | 
						|
	},
 | 
						|
	ErrNoSuchBucket: {
 | 
						|
		Code:           "NoSuchBucket",
 | 
						|
		Description:    "The specified bucket does not exist.",
 | 
						|
		HTTPStatusCode: http.StatusNotFound,
 | 
						|
	},
 | 
						|
	ErrNoSuchBucketPolicy: {
 | 
						|
		Code:           "NoSuchBucketPolicy",
 | 
						|
		Description:    "The specified bucket does not have a bucket policy.",
 | 
						|
		HTTPStatusCode: http.StatusNotFound,
 | 
						|
	},
 | 
						|
	ErrNoSuchKey: {
 | 
						|
		Code:           "NoSuchKey",
 | 
						|
		Description:    "The specified key does not exist.",
 | 
						|
		HTTPStatusCode: http.StatusNotFound,
 | 
						|
	},
 | 
						|
	ErrNoSuchUpload: {
 | 
						|
		Code:           "NoSuchUpload",
 | 
						|
		Description:    "The specified multipart upload does not exist.",
 | 
						|
		HTTPStatusCode: http.StatusNotFound,
 | 
						|
	},
 | 
						|
	ErrNotImplemented: {
 | 
						|
		Code:           "NotImplemented",
 | 
						|
		Description:    "A header you provided implies functionality that is not implemented.",
 | 
						|
		HTTPStatusCode: http.StatusNotImplemented,
 | 
						|
	},
 | 
						|
	ErrRequestTimeTooSkewed: {
 | 
						|
		Code:           "RequestTimeTooSkewed",
 | 
						|
		Description:    "The difference between the request time and the server's time is too large.",
 | 
						|
		HTTPStatusCode: http.StatusForbidden,
 | 
						|
	},
 | 
						|
	ErrSignatureDoesNotMatch: {
 | 
						|
		Code:           "SignatureDoesNotMatch",
 | 
						|
		Description:    "The request signature we calculated does not match the signature you provided.",
 | 
						|
		HTTPStatusCode: http.StatusForbidden,
 | 
						|
	},
 | 
						|
	ErrMethodNotAllowed: {
 | 
						|
		Code:           "MethodNotAllowed",
 | 
						|
		Description:    "The specified method is not allowed against this resource.",
 | 
						|
		HTTPStatusCode: http.StatusMethodNotAllowed,
 | 
						|
	},
 | 
						|
	ErrInvalidPart: {
 | 
						|
		Code:           "InvalidPart",
 | 
						|
		Description:    "One or more of the specified parts could not be found.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	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,
 | 
						|
	},
 | 
						|
	ErrAuthorizationHeaderMalformed: {
 | 
						|
		Code:           "AuthorizationHeaderMalformed",
 | 
						|
		Description:    "The authorization header is malformed; the region is wrong; expecting 'us-east-1'.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMalformedPOSTRequest: {
 | 
						|
		Code:           "MalformedPOSTRequest",
 | 
						|
		Description:    "The body of your POST request is not well-formed multipart/form-data.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrSignatureVersionNotSupported: {
 | 
						|
		Code:           "InvalidRequest",
 | 
						|
		Description:    "The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrBucketNotEmpty: {
 | 
						|
		Code:           "BucketNotEmpty",
 | 
						|
		Description:    "The bucket you tried to delete is not empty.",
 | 
						|
		HTTPStatusCode: http.StatusConflict,
 | 
						|
	},
 | 
						|
	ErrRootPathFull: {
 | 
						|
		Code:           "RootPathFull",
 | 
						|
		Description:    "Root path has reached its minimum free disk threshold. Please delete few objects to proceed.",
 | 
						|
		HTTPStatusCode: http.StatusInternalServerError,
 | 
						|
	},
 | 
						|
	ErrObjectExistsAsPrefix: {
 | 
						|
		Code:           "ObjectExistsAsPrefix",
 | 
						|
		Description:    "An object already exists as your prefix, choose a different prefix to proceed.",
 | 
						|
		HTTPStatusCode: http.StatusConflict,
 | 
						|
	},
 | 
						|
	ErrAllAccessDisabled: {
 | 
						|
		Code:           "AllAccessDisabled",
 | 
						|
		Description:    "All access to this bucket has been disabled.",
 | 
						|
		HTTPStatusCode: http.StatusForbidden,
 | 
						|
	},
 | 
						|
	ErrMalformedPolicy: {
 | 
						|
		Code:           "MalformedPolicy",
 | 
						|
		Description:    "Policy has invalid resource.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMissingFields: {
 | 
						|
		Code:           "MissingFields",
 | 
						|
		Description:    "Missing fields in request.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMissingCredTag: {
 | 
						|
		Code:           "InvalidRequest",
 | 
						|
		Description:    "Missing Credential field for this request.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrCredMalformed: {
 | 
						|
		Code:           "CredentialMalformed",
 | 
						|
		Description:    "Credential field malformed does not follow accessKeyID/credScope.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMalformedDate: {
 | 
						|
		Code:           "MalformedDate",
 | 
						|
		Description:    "Invalid date format header, expected to be in ISO8601, RFC1123 or RFC1123Z time format.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidRegion: {
 | 
						|
		Code:           "InvalidRegion",
 | 
						|
		Description:    "Region does not match.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidService: {
 | 
						|
		Code:           "AccessDenied",
 | 
						|
		Description:    "Service scope should be of value 's3'.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidRequestVersion: {
 | 
						|
		Code:           "AccessDenied",
 | 
						|
		Description:    "Request scope should be of value 'aws4_request'.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMissingSignTag: {
 | 
						|
		Code:           "AccessDenied",
 | 
						|
		Description:    "Signature header missing Signature field.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMissingSignHeadersTag: {
 | 
						|
		Code:           "InvalidArgument",
 | 
						|
		Description:    "Signature header missing SignedHeaders field.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrPolicyAlreadyExpired: {
 | 
						|
		Code:           "AccessDenied",
 | 
						|
		Description:    "Invalid according to Policy: Policy expired.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMalformedExpires: {
 | 
						|
		Code:           "MalformedExpires",
 | 
						|
		Description:    "Malformed expires header, expected non-zero number.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrAuthHeaderEmpty: {
 | 
						|
		Code:           "InvalidArgument",
 | 
						|
		Description:    "Authorization header is invalid -- one and only one ' ' (space) required.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrMissingDateHeader: {
 | 
						|
		Code:           "AccessDenied",
 | 
						|
		Description:    "AWS authentication requires a valid Date or x-amz-date header",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrInvalidQuerySignatureAlgo: {
 | 
						|
		Code:           "AuthorizationQueryParametersError",
 | 
						|
		Description:    "X-Amz-Algorithm only supports \"AWS4-HMAC-SHA256\".",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	ErrExpiredPresignRequest: {
 | 
						|
		Code:           "AccessDenied",
 | 
						|
		Description:    "Request has expired.",
 | 
						|
		HTTPStatusCode: http.StatusBadRequest,
 | 
						|
	},
 | 
						|
	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,
 | 
						|
	},
 | 
						|
	// Add your error structure here.
 | 
						|
}
 | 
						|
 | 
						|
// getAPIError provides API Error for input API error code.
 | 
						|
func getAPIError(code APIErrorCode) APIError {
 | 
						|
	return errorCodeResponse[code]
 | 
						|
}
 | 
						|
 | 
						|
// getErrorResponse gets in standard error and resource value and
 | 
						|
// provides a encodable populated response values
 | 
						|
func getAPIErrorResponse(err APIError, resource string) APIErrorResponse {
 | 
						|
	var data = APIErrorResponse{}
 | 
						|
	data.Code = err.Code
 | 
						|
	data.Message = err.Description
 | 
						|
	if resource != "" {
 | 
						|
		data.Resource = resource
 | 
						|
	}
 | 
						|
	// TODO implement this in future
 | 
						|
	data.RequestID = "3L137"
 | 
						|
	data.HostID = "3L137"
 | 
						|
 | 
						|
	return data
 | 
						|
}
 |