error: Add proper prefixes for s3Error codes.

This patch adds 'Err' prefix for all standard API
error codes and also adds a proper type for them.
This commit is contained in:
Harshavardhana 2016-03-10 02:24:52 -08:00
parent 373d335d94
commit fdf3d64793
8 changed files with 334 additions and 340 deletions

View file

@ -40,269 +40,275 @@ type APIErrorResponse struct {
HostID string `xml:"HostId"` 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 // Error codes, non exhaustive list - http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
const ( const (
None = iota ErrNone APIErrorCode = iota
AccessDenied ErrAccessDenied
BadDigest ErrBadDigest
BucketAlreadyExists ErrBucketAlreadyExists
EntityTooSmall ErrEntityTooSmall
EntityTooLarge ErrEntityTooLarge
IncompleteBody ErrIncompleteBody
InternalError ErrInternalError
InvalidAccessKeyID ErrInvalidAccessKeyID
InvalidBucketName ErrInvalidBucketName
InvalidDigest ErrInvalidDigest
InvalidRange ErrInvalidRange
InvalidMaxKeys ErrInvalidMaxKeys
InvalidMaxUploads ErrInvalidMaxUploads
InvalidMaxParts ErrInvalidMaxParts
InvalidPartNumberMarker ErrInvalidPartNumberMarker
InvalidRequestBody ErrInvalidRequestBody
InvalidCopySource ErrInvalidCopySource
InvalidCopyDest ErrInvalidCopyDest
InvalidPolicyDocument ErrInvalidPolicyDocument
MalformedXML ErrMalformedXML
MissingContentLength ErrMissingContentLength
MissingContentMD5 ErrMissingContentMD5
MissingRequestBodyError ErrMissingRequestBodyError
NoSuchBucket ErrNoSuchBucket
NoSuchBucketPolicy ErrNoSuchBucketPolicy
NoSuchKey ErrNoSuchKey
NoSuchUpload ErrNoSuchUpload
NotImplemented ErrNotImplemented
RequestTimeTooSkewed ErrRequestTimeTooSkewed
SignatureDoesNotMatch ErrSignatureDoesNotMatch
MethodNotAllowed ErrMethodNotAllowed
InvalidPart ErrInvalidPart
InvalidPartOrder ErrInvalidPartOrder
AuthorizationHeaderMalformed ErrAuthorizationHeaderMalformed
MalformedPOSTRequest ErrMalformedPOSTRequest
SignatureVersionNotSupported ErrSignatureVersionNotSupported
BucketNotEmpty ErrBucketNotEmpty
RootPathFull ErrRootPathFull
ObjectExistsAsPrefix ErrObjectExistsAsPrefix
AllAccessDisabled ErrAllAccessDisabled
MalformedPolicy ErrMalformedPolicy
// Add new error codes here.
) )
// APIError code to Error structure map // error code to APIError structure, these fields carry respective
var errorCodeResponse = map[int]APIError{ // descriptions for all the error responses.
InvalidCopyDest: { var errorCodeResponse = map[APIErrorCode]APIError{
ErrInvalidCopyDest: {
Code: "InvalidRequest", Code: "InvalidRequest",
Description: "This copy request is illegal because it is trying to copy an object to itself.", Description: "This copy request is illegal because it is trying to copy an object to itself.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidCopySource: { ErrInvalidCopySource: {
Code: "InvalidArgument", Code: "InvalidArgument",
Description: "Copy Source must mention the source bucket and key: sourcebucket/sourcekey.", Description: "Copy Source must mention the source bucket and key: sourcebucket/sourcekey.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidRequestBody: { ErrInvalidRequestBody: {
Code: "InvalidArgument", Code: "InvalidArgument",
Description: "Body shouldn't be set for this request.", Description: "Body shouldn't be set for this request.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidMaxUploads: { ErrInvalidMaxUploads: {
Code: "InvalidArgument", Code: "InvalidArgument",
Description: "Argument maxUploads must be an integer between 0 and 2147483647.", Description: "Argument maxUploads must be an integer between 0 and 2147483647.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidMaxKeys: { ErrInvalidMaxKeys: {
Code: "InvalidArgument", Code: "InvalidArgument",
Description: "Argument maxKeys must be an integer between 0 and 2147483647.", Description: "Argument maxKeys must be an integer between 0 and 2147483647.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidMaxParts: { ErrInvalidMaxParts: {
Code: "InvalidArgument", Code: "InvalidArgument",
Description: "Argument maxParts must be an integer between 1 and 10000.", Description: "Argument maxParts must be an integer between 1 and 10000.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidPartNumberMarker: { ErrInvalidPartNumberMarker: {
Code: "InvalidArgument", Code: "InvalidArgument",
Description: "Argument partNumberMarker must be an integer.", Description: "Argument partNumberMarker must be an integer.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidPolicyDocument: { ErrInvalidPolicyDocument: {
Code: "InvalidPolicyDocument", Code: "InvalidPolicyDocument",
Description: "The content of the form does not meet the conditions specified in the policy document.", Description: "The content of the form does not meet the conditions specified in the policy document.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
AccessDenied: { ErrAccessDenied: {
Code: "AccessDenied", Code: "AccessDenied",
Description: "Access Denied.", Description: "Access Denied.",
HTTPStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
}, },
BadDigest: { ErrBadDigest: {
Code: "BadDigest", Code: "BadDigest",
Description: "The Content-Md5 you specified did not match what we received.", Description: "The Content-Md5 you specified did not match what we received.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
BucketAlreadyExists: { ErrBucketAlreadyExists: {
Code: "BucketAlreadyExists", Code: "BucketAlreadyExists",
Description: "The requested bucket name is not available.", Description: "The requested bucket name is not available.",
HTTPStatusCode: http.StatusConflict, HTTPStatusCode: http.StatusConflict,
}, },
EntityTooSmall: { ErrEntityTooSmall: {
Code: "EntityTooSmall", Code: "EntityTooSmall",
Description: "Your proposed upload is smaller than the minimum allowed object size.", Description: "Your proposed upload is smaller than the minimum allowed object size.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
EntityTooLarge: { ErrEntityTooLarge: {
Code: "EntityTooLarge", Code: "EntityTooLarge",
Description: "Your proposed upload exceeds the maximum allowed object size.", Description: "Your proposed upload exceeds the maximum allowed object size.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
IncompleteBody: { ErrIncompleteBody: {
Code: "IncompleteBody", Code: "IncompleteBody",
Description: "You did not provide the number of bytes specified by the Content-Length HTTP header.", Description: "You did not provide the number of bytes specified by the Content-Length HTTP header.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InternalError: { ErrInternalError: {
Code: "InternalError", Code: "InternalError",
Description: "We encountered an internal error, please try again.", Description: "We encountered an internal error, please try again.",
HTTPStatusCode: http.StatusInternalServerError, HTTPStatusCode: http.StatusInternalServerError,
}, },
InvalidAccessKeyID: { ErrInvalidAccessKeyID: {
Code: "InvalidAccessKeyID", Code: "InvalidAccessKeyID",
Description: "The access key ID you provided does not exist in our records.", Description: "The access key ID you provided does not exist in our records.",
HTTPStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
}, },
InvalidBucketName: { ErrInvalidBucketName: {
Code: "InvalidBucketName", Code: "InvalidBucketName",
Description: "The specified bucket is not valid.", Description: "The specified bucket is not valid.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidDigest: { ErrInvalidDigest: {
Code: "InvalidDigest", Code: "InvalidDigest",
Description: "The Content-Md5 you specified is not valid.", Description: "The Content-Md5 you specified is not valid.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidRange: { ErrInvalidRange: {
Code: "InvalidRange", Code: "InvalidRange",
Description: "The requested range cannot be satisfied.", Description: "The requested range cannot be satisfied.",
HTTPStatusCode: http.StatusRequestedRangeNotSatisfiable, HTTPStatusCode: http.StatusRequestedRangeNotSatisfiable,
}, },
MalformedXML: { ErrMalformedXML: {
Code: "MalformedXML", Code: "MalformedXML",
Description: "The XML you provided was not well-formed or did not validate against our published schema.", Description: "The XML you provided was not well-formed or did not validate against our published schema.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
MissingContentLength: { ErrMissingContentLength: {
Code: "MissingContentLength", Code: "MissingContentLength",
Description: "You must provide the Content-Length HTTP header.", Description: "You must provide the Content-Length HTTP header.",
HTTPStatusCode: http.StatusLengthRequired, HTTPStatusCode: http.StatusLengthRequired,
}, },
MissingContentMD5: { ErrMissingContentMD5: {
Code: "MissingContentMD5", Code: "MissingContentMD5",
Description: "Missing required header for this request: Content-Md5.", Description: "Missing required header for this request: Content-Md5.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
MissingRequestBodyError: { ErrMissingRequestBodyError: {
Code: "MissingRequestBodyError", Code: "MissingRequestBodyError",
Description: "Request body is empty.", Description: "Request body is empty.",
HTTPStatusCode: http.StatusLengthRequired, HTTPStatusCode: http.StatusLengthRequired,
}, },
NoSuchBucket: { ErrNoSuchBucket: {
Code: "NoSuchBucket", Code: "NoSuchBucket",
Description: "The specified bucket does not exist.", Description: "The specified bucket does not exist.",
HTTPStatusCode: http.StatusNotFound, HTTPStatusCode: http.StatusNotFound,
}, },
NoSuchBucketPolicy: { ErrNoSuchBucketPolicy: {
Code: "NoSuchBucketPolicy", Code: "NoSuchBucketPolicy",
Description: "The specified bucket does not have a bucket policy.", Description: "The specified bucket does not have a bucket policy.",
HTTPStatusCode: http.StatusNotFound, HTTPStatusCode: http.StatusNotFound,
}, },
NoSuchKey: { ErrNoSuchKey: {
Code: "NoSuchKey", Code: "NoSuchKey",
Description: "The specified key does not exist.", Description: "The specified key does not exist.",
HTTPStatusCode: http.StatusNotFound, HTTPStatusCode: http.StatusNotFound,
}, },
NoSuchUpload: { ErrNoSuchUpload: {
Code: "NoSuchUpload", Code: "NoSuchUpload",
Description: "The specified multipart upload does not exist.", Description: "The specified multipart upload does not exist.",
HTTPStatusCode: http.StatusNotFound, HTTPStatusCode: http.StatusNotFound,
}, },
NotImplemented: { ErrNotImplemented: {
Code: "NotImplemented", Code: "NotImplemented",
Description: "A header you provided implies functionality that is not implemented.", Description: "A header you provided implies functionality that is not implemented.",
HTTPStatusCode: http.StatusNotImplemented, HTTPStatusCode: http.StatusNotImplemented,
}, },
RequestTimeTooSkewed: { ErrRequestTimeTooSkewed: {
Code: "RequestTimeTooSkewed", Code: "RequestTimeTooSkewed",
Description: "The difference between the request time and the server's time is too large.", Description: "The difference between the request time and the server's time is too large.",
HTTPStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
}, },
SignatureDoesNotMatch: { ErrSignatureDoesNotMatch: {
Code: "SignatureDoesNotMatch", Code: "SignatureDoesNotMatch",
Description: "The request signature we calculated does not match the signature you provided.", Description: "The request signature we calculated does not match the signature you provided.",
HTTPStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
}, },
MethodNotAllowed: { ErrMethodNotAllowed: {
Code: "MethodNotAllowed", Code: "MethodNotAllowed",
Description: "The specified method is not allowed against this resource.", Description: "The specified method is not allowed against this resource.",
HTTPStatusCode: http.StatusMethodNotAllowed, HTTPStatusCode: http.StatusMethodNotAllowed,
}, },
InvalidPart: { ErrInvalidPart: {
Code: "InvalidPart", Code: "InvalidPart",
Description: "One or more of the specified parts could not be found.", Description: "One or more of the specified parts could not be found.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidPartOrder: { ErrInvalidPartOrder: {
Code: "InvalidPartOrder", Code: "InvalidPartOrder",
Description: "The list of parts was not in ascending order. The parts list must be specified in order by part number.", Description: "The list of parts was not in ascending order. The parts list must be specified in order by part number.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
AuthorizationHeaderMalformed: { ErrAuthorizationHeaderMalformed: {
Code: "AuthorizationHeaderMalformed", Code: "AuthorizationHeaderMalformed",
Description: "The authorization header is malformed; the region is wrong; expecting 'us-east-1'.", Description: "The authorization header is malformed; the region is wrong; expecting 'us-east-1'.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
MalformedPOSTRequest: { ErrMalformedPOSTRequest: {
Code: "MalformedPOSTRequest", Code: "MalformedPOSTRequest",
Description: "The body of your POST request is not well-formed multipart/form-data.", Description: "The body of your POST request is not well-formed multipart/form-data.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
SignatureVersionNotSupported: { ErrSignatureVersionNotSupported: {
Code: "InvalidRequest", Code: "InvalidRequest",
Description: "The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.", Description: "The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
BucketNotEmpty: { ErrBucketNotEmpty: {
Code: "BucketNotEmpty", Code: "BucketNotEmpty",
Description: "The bucket you tried to delete is not empty.", Description: "The bucket you tried to delete is not empty.",
HTTPStatusCode: http.StatusConflict, HTTPStatusCode: http.StatusConflict,
}, },
RootPathFull: { ErrRootPathFull: {
Code: "RootPathFull", Code: "RootPathFull",
Description: "Root path has reached its minimum free disk threshold. Please delete few objects to proceed.", Description: "Root path has reached its minimum free disk threshold. Please delete few objects to proceed.",
HTTPStatusCode: http.StatusInternalServerError, HTTPStatusCode: http.StatusInternalServerError,
}, },
ObjectExistsAsPrefix: { ErrObjectExistsAsPrefix: {
Code: "ObjectExistsAsPrefix", Code: "ObjectExistsAsPrefix",
Description: "An object already exists as your prefix, choose a different prefix to proceed.", Description: "An object already exists as your prefix, choose a different prefix to proceed.",
HTTPStatusCode: http.StatusConflict, HTTPStatusCode: http.StatusConflict,
}, },
AllAccessDisabled: { ErrAllAccessDisabled: {
Code: "AllAccessDisabled", Code: "AllAccessDisabled",
Description: "All access to this bucket has been disabled.", Description: "All access to this bucket has been disabled.",
HTTPStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
}, },
MalformedPolicy: { ErrMalformedPolicy: {
Code: "MalformedPolicy", Code: "MalformedPolicy",
Description: "Policy has invalid resource", Description: "Policy has invalid resource",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
// Add your error structure here.
} }
// errorCodeError provides errorCode to Error. It returns empty if the code provided is unknown // getAPIError provides API Error for input API error code.
func getErrorCode(code int) APIError { func getAPIError(code APIErrorCode) APIError {
return errorCodeResponse[code] return errorCodeResponse[code]
} }
// getErrorResponse gets in standard error and resource value and // getErrorResponse gets in standard error and resource value and
// provides a encodable populated response values // provides a encodable populated response values
func getErrorResponse(err APIError, resource string) APIErrorResponse { func getAPIErrorResponse(err APIError, resource string) APIErrorResponse {
var data = APIErrorResponse{} var data = APIErrorResponse{}
data.Code = err.Code data.Code = err.Code
data.Message = err.Description data.Message = err.Description

View file

@ -423,10 +423,10 @@ func writeSuccessNoContent(w http.ResponseWriter) {
} }
// writeErrorRespone write error headers // writeErrorRespone write error headers
func writeErrorResponse(w http.ResponseWriter, req *http.Request, errorType int, resource string) { func writeErrorResponse(w http.ResponseWriter, req *http.Request, errorCode APIErrorCode, resource string) {
error := getErrorCode(errorType) error := getAPIError(errorCode)
// generate error response // generate error response
errorResponse := getErrorResponse(error, resource) errorResponse := getAPIErrorResponse(error, resource)
encodedErrorResponse := encodeResponse(errorResponse) encodedErrorResponse := encodeResponse(errorResponse)
// set common headers // set common headers
setCommonHeaders(w) setCommonHeaders(w)

View file

@ -106,31 +106,31 @@ func getRequestAuthType(r *http.Request) authType {
} }
// Verify if request has valid AWS Signature Version '4'. // Verify if request has valid AWS Signature Version '4'.
func isSignV4ReqAuthenticated(sign *signature4.Sign, r *http.Request) (match bool, s3Error int) { func isReqAuthenticated(sign *signature4.Sign, r *http.Request) (s3Error APIErrorCode) {
auth := sign.SetHTTPRequestToVerify(r) auth := sign.SetHTTPRequestToVerify(r)
if isRequestSignatureV4(r) { if isRequestSignatureV4(r) {
dummyPayload := sha256.Sum256([]byte("")) dummyPayload := sha256.Sum256([]byte(""))
ok, err := auth.DoesSignatureMatch(hex.EncodeToString(dummyPayload[:])) ok, err := auth.DoesSignatureMatch(hex.EncodeToString(dummyPayload[:]))
if err != nil { if err != nil {
errorIf(err.Trace(), "Signature verification failed.", nil) errorIf(err.Trace(), "Signature verification failed.", nil)
return false, InternalError return ErrInternalError
} }
if !ok { if !ok {
return false, SignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }
return ok, None return ErrNone
} else if isRequestPresignedSignatureV4(r) { } else if isRequestPresignedSignatureV4(r) {
ok, err := auth.DoesPresignedSignatureMatch() ok, err := auth.DoesPresignedSignatureMatch()
if err != nil { if err != nil {
errorIf(err.Trace(), "Presigned signature verification failed.", nil) errorIf(err.Trace(), "Presigned signature verification failed.", nil)
return false, InternalError return ErrInternalError
} }
if !ok { if !ok {
return false, SignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }
return ok, None return ErrNone
} }
return false, AccessDenied return ErrAccessDenied
} }
// authHandler - handles all the incoming authorization headers and // authHandler - handles all the incoming authorization headers and
@ -160,7 +160,7 @@ func (a authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
a.handler.ServeHTTP(w, r) a.handler.ServeHTTP(w, r)
default: default:
writeErrorResponse(w, r, SignatureVersionNotSupported, r.URL.Path) writeErrorResponse(w, r, ErrSignatureVersionNotSupported, r.URL.Path)
return return
} }
} }

View file

@ -38,26 +38,26 @@ import (
) )
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
func enforceBucketPolicy(action string, bucket string, reqURL *url.URL) (isAllowed bool, s3Error int) { func enforceBucketPolicy(action string, bucket string, reqURL *url.URL) (s3Error APIErrorCode) {
// Read saved bucket policy. // Read saved bucket policy.
policy, err := readBucketPolicy(bucket) policy, err := readBucketPolicy(bucket)
if err != nil { if err != nil {
errorIf(err.Trace(bucket), "GetBucketPolicy failed.", nil) errorIf(err.Trace(bucket), "GetBucketPolicy failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNotFound: case fs.BucketNotFound:
return false, NoSuchBucket return ErrNoSuchBucket
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
return false, InvalidBucketName return ErrInvalidBucketName
default: default:
// For any other error just return AccessDenied. // For any other error just return AccessDenied.
return false, AccessDenied return ErrAccessDenied
} }
} }
// Parse the saved policy. // Parse the saved policy.
accessPolicy, e := accesspolicy.Validate(policy) accessPolicy, e := accesspolicy.Validate(policy)
if e != nil { if e != nil {
errorIf(probe.NewError(e), "Parse policy failed.", nil) errorIf(probe.NewError(e), "Parse policy failed.", nil)
return false, AccessDenied return ErrAccessDenied
} }
// Construct resource in 'arn:aws:s3:::examplebucket' format. // Construct resource in 'arn:aws:s3:::examplebucket' format.
@ -71,9 +71,9 @@ func enforceBucketPolicy(action string, bucket string, reqURL *url.URL) (isAllow
// Validate action, resource and conditions with current policy statements. // Validate action, resource and conditions with current policy statements.
if !bucketPolicyEvalStatements(action, resource, conditions, accessPolicy.Statements) { if !bucketPolicyEvalStatements(action, resource, conditions, accessPolicy.Statements) {
return false, AccessDenied return ErrAccessDenied
} }
return true, None return ErrNone
} }
// GetBucketLocationHandler - GET Bucket location. // GetBucketLocationHandler - GET Bucket location.
@ -86,17 +86,16 @@ func (api storageAPI) GetBucketLocationHandler(w http.ResponseWriter, r *http.Re
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:GetBucketLocation", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:GetBucketLocation", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
case authTypeSigned, authTypePresigned: case authTypeSigned, authTypePresigned:
match, s3Error := isSignV4ReqAuthenticated(api.Signature, r) if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
if !match {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -107,11 +106,11 @@ func (api storageAPI) GetBucketLocationHandler(w http.ResponseWriter, r *http.Re
errorIf(err.Trace(), "GetBucketMetadata failed.", nil) errorIf(err.Trace(), "GetBucketMetadata failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -142,17 +141,16 @@ func (api storageAPI) ListMultipartUploadsHandler(w http.ResponseWriter, r *http
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:ListBucketMultipartUploads", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:ListBucketMultipartUploads", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
case authTypePresigned, authTypeSigned: case authTypePresigned, authTypeSigned:
match, s3Error := isSignV4ReqAuthenticated(api.Signature, r) if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
if !match {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -160,7 +158,7 @@ func (api storageAPI) ListMultipartUploadsHandler(w http.ResponseWriter, r *http
resources := getBucketMultipartResources(r.URL.Query()) resources := getBucketMultipartResources(r.URL.Query())
if resources.MaxUploads < 0 { if resources.MaxUploads < 0 {
writeErrorResponse(w, r, InvalidMaxUploads, r.URL.Path) writeErrorResponse(w, r, ErrInvalidMaxUploads, r.URL.Path)
return return
} }
if resources.MaxUploads == 0 { if resources.MaxUploads == 0 {
@ -172,9 +170,9 @@ func (api storageAPI) ListMultipartUploadsHandler(w http.ResponseWriter, r *http
errorIf(err.Trace(), "ListMultipartUploads failed.", nil) errorIf(err.Trace(), "ListMultipartUploads failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -200,17 +198,16 @@ func (api storageAPI) ListObjectsHandler(w http.ResponseWriter, r *http.Request)
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:ListBucket", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:ListBucket", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
case authTypeSigned, authTypePresigned: case authTypeSigned, authTypePresigned:
match, s3Error := isSignV4ReqAuthenticated(api.Signature, r) if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
if !match {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -219,7 +216,7 @@ func (api storageAPI) ListObjectsHandler(w http.ResponseWriter, r *http.Request)
// TODO handle encoding type. // TODO handle encoding type.
prefix, marker, delimiter, maxkeys, _ := getBucketResources(r.URL.Query()) prefix, marker, delimiter, maxkeys, _ := getBucketResources(r.URL.Query())
if maxkeys < 0 { if maxkeys < 0 {
writeErrorResponse(w, r, InvalidMaxKeys, r.URL.Path) writeErrorResponse(w, r, ErrInvalidMaxKeys, r.URL.Path)
return return
} }
if maxkeys == 0 { if maxkeys == 0 {
@ -239,16 +236,16 @@ func (api storageAPI) ListObjectsHandler(w http.ResponseWriter, r *http.Request)
} }
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.ObjectNotFound: case fs.ObjectNotFound:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
default: default:
errorIf(err.Trace(), "ListObjects failed.", nil) errorIf(err.Trace(), "ListObjects failed.", nil)
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
} }
@ -261,10 +258,10 @@ func (api storageAPI) ListBucketsHandler(w http.ResponseWriter, r *http.Request)
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeSigned, authTypePresigned: case authTypeSigned, authTypePresigned:
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -282,7 +279,7 @@ func (api storageAPI) ListBucketsHandler(w http.ResponseWriter, r *http.Request)
return return
} }
errorIf(err.Trace(), "ListBuckets failed.", nil) errorIf(err.Trace(), "ListBuckets failed.", nil)
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
// DeleteMultipleObjectsHandler - deletes multiple objects. // DeleteMultipleObjectsHandler - deletes multiple objects.
@ -293,14 +290,14 @@ func (api storageAPI) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *htt
// Content-Length is required and should be non-zero // Content-Length is required and should be non-zero
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html // http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
if r.ContentLength <= 0 { if r.ContentLength <= 0 {
writeErrorResponse(w, r, MissingContentLength, r.URL.Path) writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
return return
} }
// Content-Md5 is requied should be set // Content-Md5 is requied should be set
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html // http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
if _, ok := r.Header["Content-Md5"]; !ok { if _, ok := r.Header["Content-Md5"]; !ok {
writeErrorResponse(w, r, MissingContentMD5, r.URL.Path) writeErrorResponse(w, r, ErrMissingContentMD5, r.URL.Path)
return return
} }
@ -314,18 +311,18 @@ func (api storageAPI) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *htt
_, e := io.ReadFull(r.Body, deleteXMLBytes) _, e := io.ReadFull(r.Body, deleteXMLBytes)
if e != nil { if e != nil {
errorIf(probe.NewError(e), "DeleteMultipleObjects failed.", nil) errorIf(probe.NewError(e), "DeleteMultipleObjects failed.", nil)
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
return return
} }
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:DeleteObject", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:DeleteObject", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -334,11 +331,11 @@ func (api storageAPI) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *htt
ok, err := auth.DoesPresignedSignatureMatch() ok, err := auth.DoesPresignedSignatureMatch()
if err != nil { if err != nil {
errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil) errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil)
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
case authTypeSigned: case authTypeSigned:
@ -350,16 +347,16 @@ func (api storageAPI) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *htt
ok, err := auth.DoesSignatureMatch(hex.EncodeToString(sha.Sum(nil))) ok, err := auth.DoesSignatureMatch(hex.EncodeToString(sha.Sum(nil)))
if err != nil { if err != nil {
errorIf(err.Trace(), "DeleteMultipleObjects failed.", nil) errorIf(err.Trace(), "DeleteMultipleObjects failed.", nil)
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
// Verify content md5. // Verify content md5.
if r.Header.Get("Content-Md5") != base64.StdEncoding.EncodeToString(mdSh.Sum(nil)) { if r.Header.Get("Content-Md5") != base64.StdEncoding.EncodeToString(mdSh.Sum(nil)) {
writeErrorResponse(w, r, BadDigest, r.URL.Path) writeErrorResponse(w, r, ErrBadDigest, r.URL.Path)
return return
} }
} }
@ -367,7 +364,7 @@ func (api storageAPI) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *htt
// Unmarshal list of keys to be deleted. // Unmarshal list of keys to be deleted.
deleteObjects := &DeleteObjectsRequest{} deleteObjects := &DeleteObjectsRequest{}
if e := xml.Unmarshal(deleteXMLBytes, deleteObjects); e != nil { if e := xml.Unmarshal(deleteXMLBytes, deleteObjects); e != nil {
writeErrorResponse(w, r, MalformedXML, r.URL.Path) writeErrorResponse(w, r, ErrMalformedXML, r.URL.Path)
return return
} }
@ -385,32 +382,32 @@ func (api storageAPI) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *htt
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
deleteErrors = append(deleteErrors, DeleteError{ deleteErrors = append(deleteErrors, DeleteError{
Code: errorCodeResponse[InvalidBucketName].Code, Code: errorCodeResponse[ErrInvalidBucketName].Code,
Message: errorCodeResponse[InvalidBucketName].Description, Message: errorCodeResponse[ErrInvalidBucketName].Description,
Key: object.ObjectName, Key: object.ObjectName,
}) })
case fs.BucketNotFound: case fs.BucketNotFound:
deleteErrors = append(deleteErrors, DeleteError{ deleteErrors = append(deleteErrors, DeleteError{
Code: errorCodeResponse[NoSuchBucket].Code, Code: errorCodeResponse[ErrNoSuchBucket].Code,
Message: errorCodeResponse[NoSuchBucket].Description, Message: errorCodeResponse[ErrNoSuchBucket].Description,
Key: object.ObjectName, Key: object.ObjectName,
}) })
case fs.ObjectNotFound: case fs.ObjectNotFound:
deleteErrors = append(deleteErrors, DeleteError{ deleteErrors = append(deleteErrors, DeleteError{
Code: errorCodeResponse[NoSuchKey].Code, Code: errorCodeResponse[ErrNoSuchKey].Code,
Message: errorCodeResponse[NoSuchKey].Description, Message: errorCodeResponse[ErrNoSuchKey].Description,
Key: object.ObjectName, Key: object.ObjectName,
}) })
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
deleteErrors = append(deleteErrors, DeleteError{ deleteErrors = append(deleteErrors, DeleteError{
Code: errorCodeResponse[NoSuchKey].Code, Code: errorCodeResponse[ErrNoSuchKey].Code,
Message: errorCodeResponse[NoSuchKey].Description, Message: errorCodeResponse[ErrNoSuchKey].Description,
Key: object.ObjectName, Key: object.ObjectName,
}) })
default: default:
deleteErrors = append(deleteErrors, DeleteError{ deleteErrors = append(deleteErrors, DeleteError{
Code: errorCodeResponse[InternalError].Code, Code: errorCodeResponse[ErrInternalError].Code,
Message: errorCodeResponse[InternalError].Description, Message: errorCodeResponse[ErrInternalError].Description,
Key: object.ObjectName, Key: object.ObjectName,
}) })
} }
@ -437,11 +434,11 @@ func (api storageAPI) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:CreateBucket", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:CreateBucket", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -449,11 +446,11 @@ func (api storageAPI) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
ok, err := auth.DoesPresignedSignatureMatch() ok, err := auth.DoesPresignedSignatureMatch()
if err != nil { if err != nil {
errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil) errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil)
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
case authTypeSigned: case authTypeSigned:
@ -461,7 +458,7 @@ func (api storageAPI) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
locationBytes, e := ioutil.ReadAll(r.Body) locationBytes, e := ioutil.ReadAll(r.Body)
if e != nil { if e != nil {
errorIf(probe.NewError(e), "MakeBucket failed.", nil) errorIf(probe.NewError(e), "MakeBucket failed.", nil)
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
return return
} }
sh := sha256.New() sh := sha256.New()
@ -469,11 +466,11 @@ func (api storageAPI) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
ok, err := auth.DoesSignatureMatch(hex.EncodeToString(sh.Sum(nil))) ok, err := auth.DoesSignatureMatch(hex.EncodeToString(sh.Sum(nil)))
if err != nil { if err != nil {
errorIf(err.Trace(), "MakeBucket failed.", nil) errorIf(err.Trace(), "MakeBucket failed.", nil)
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
} }
@ -484,11 +481,11 @@ func (api storageAPI) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
errorIf(err.Trace(), "MakeBucket failed.", nil) errorIf(err.Trace(), "MakeBucket failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketExists: case fs.BucketExists:
writeErrorResponse(w, r, BucketAlreadyExists, r.URL.Path) writeErrorResponse(w, r, ErrBucketAlreadyExists, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -527,29 +524,20 @@ func extractHTTPFormValues(reader *multipart.Reader) (io.Reader, map[string]stri
// This implementation of the POST operation handles object creation with a specified // This implementation of the POST operation handles object creation with a specified
// signature policy in multipart/form-data // signature policy in multipart/form-data
func (api storageAPI) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) { func (api storageAPI) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
// if body of request is non-nil then check for validity of Content-Length
if r.Body != nil {
/// if Content-Length is unknown/missing, deny the request
if r.ContentLength == -1 {
writeErrorResponse(w, r, MissingContentLength, r.URL.Path)
return
}
}
// Here the parameter is the size of the form data that should // Here the parameter is the size of the form data that should
// be loaded in memory, the remaining being put in temporary // be loaded in memory, the remaining being put in temporary
// files // files
reader, e := r.MultipartReader() reader, e := r.MultipartReader()
if e != nil { if e != nil {
errorIf(probe.NewError(e), "Unable to initialize multipart reader.", nil) errorIf(probe.NewError(e), "Unable to initialize multipart reader.", nil)
writeErrorResponse(w, r, MalformedPOSTRequest, r.URL.Path) writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
return return
} }
fileBody, formValues, err := extractHTTPFormValues(reader) fileBody, formValues, err := extractHTTPFormValues(reader)
if err != nil { if err != nil {
errorIf(err.Trace(), "Unable to parse form values.", nil) errorIf(err.Trace(), "Unable to parse form values.", nil)
writeErrorResponse(w, r, MalformedPOSTRequest, r.URL.Path) writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
return return
} }
bucket := mux.Vars(r)["bucket"] bucket := mux.Vars(r)["bucket"]
@ -564,16 +552,16 @@ func (api storageAPI) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Req
ok, err = auth.DoesPolicySignatureMatch(formValues) ok, err = auth.DoesPolicySignatureMatch(formValues)
if err != nil { if err != nil {
errorIf(err.Trace(), "Unable to verify signature.", nil) errorIf(err.Trace(), "Unable to verify signature.", nil)
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
if err = signature4.ApplyPolicyCond(formValues); err != nil { if err = signature4.ApplyPolicyCond(formValues); err != nil {
errorIf(err.Trace(), "Invalid request, policy doesn't match with the endpoint.", nil) errorIf(err.Trace(), "Invalid request, policy doesn't match with the endpoint.", nil)
writeErrorResponse(w, r, MalformedPOSTRequest, r.URL.Path) writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
return return
} }
metadata, err := api.Filesystem.CreateObject(bucket, object, "", -1, fileBody, nil) metadata, err := api.Filesystem.CreateObject(bucket, object, "", -1, fileBody, nil)
@ -581,19 +569,19 @@ func (api storageAPI) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Req
errorIf(err.Trace(), "CreateObject failed.", nil) errorIf(err.Trace(), "CreateObject failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.RootPathFull: case fs.RootPathFull:
writeErrorResponse(w, r, RootPathFull, r.URL.Path) writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BadDigest: case fs.BadDigest:
writeErrorResponse(w, r, BadDigest, r.URL.Path) writeErrorResponse(w, r, ErrBadDigest, r.URL.Path)
case fs.IncompleteBody: case fs.IncompleteBody:
writeErrorResponse(w, r, IncompleteBody, r.URL.Path) writeErrorResponse(w, r, ErrIncompleteBody, r.URL.Path)
case fs.InvalidDigest: case fs.InvalidDigest:
writeErrorResponse(w, r, InvalidDigest, r.URL.Path) writeErrorResponse(w, r, ErrInvalidDigest, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -616,10 +604,10 @@ func (api storageAPI) HeadBucketHandler(w http.ResponseWriter, r *http.Request)
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypePresigned, authTypeSigned: case authTypePresigned, authTypeSigned:
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -630,11 +618,11 @@ func (api storageAPI) HeadBucketHandler(w http.ResponseWriter, r *http.Request)
errorIf(err.Trace(), "GetBucketMetadata failed.", nil) errorIf(err.Trace(), "GetBucketMetadata failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -649,16 +637,16 @@ func (api storageAPI) DeleteBucketHandler(w http.ResponseWriter, r *http.Request
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:DeleteBucket", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:DeleteBucket", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
case authTypePresigned, authTypeSigned: case authTypePresigned, authTypeSigned:
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -669,11 +657,11 @@ func (api storageAPI) DeleteBucketHandler(w http.ResponseWriter, r *http.Request
errorIf(err.Trace(), "DeleteBucket failed.", nil) errorIf(err.Trace(), "DeleteBucket failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.BucketNotEmpty: case fs.BucketNotEmpty:
writeErrorResponse(w, r, BucketNotEmpty, r.URL.Path) writeErrorResponse(w, r, ErrBucketNotEmpty, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }

View file

@ -139,12 +139,12 @@ func (api storageAPI) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Requ
// incoming request is not chunked. // incoming request is not chunked.
if !contains(r.TransferEncoding, "chunked") { if !contains(r.TransferEncoding, "chunked") {
if r.ContentLength == -1 || r.ContentLength == 0 { if r.ContentLength == -1 || r.ContentLength == 0 {
writeErrorResponse(w, r, MissingContentLength, r.URL.Path) writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
return return
} }
// If Content-Length is greater than maximum allowed policy size. // If Content-Length is greater than maximum allowed policy size.
if r.ContentLength > maxAccessPolicySize { if r.ContentLength > maxAccessPolicySize {
writeErrorResponse(w, r, EntityTooLarge, r.URL.Path) writeErrorResponse(w, r, ErrEntityTooLarge, r.URL.Path)
return return
} }
} }
@ -155,14 +155,14 @@ func (api storageAPI) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Requ
accessPolicyBytes, e := ioutil.ReadAll(io.LimitReader(r.Body, maxAccessPolicySize)) accessPolicyBytes, e := ioutil.ReadAll(io.LimitReader(r.Body, maxAccessPolicySize))
if e != nil { if e != nil {
errorIf(probe.NewError(e).Trace(bucket), "Reading policy failed.", nil) errorIf(probe.NewError(e).Trace(bucket), "Reading policy failed.", nil)
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
return return
} }
// Parse access access. // Parse access access.
accessPolicy, e := accesspolicy.Validate(accessPolicyBytes) accessPolicy, e := accesspolicy.Validate(accessPolicyBytes)
if e != nil { if e != nil {
writeErrorResponse(w, r, InvalidPolicyDocument, r.URL.Path) writeErrorResponse(w, r, ErrInvalidPolicyDocument, r.URL.Path)
return return
} }
@ -171,7 +171,7 @@ func (api storageAPI) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Requ
for _, resource := range statement.Resources { for _, resource := range statement.Resources {
resourcePrefix := strings.SplitAfter(resource, accesspolicy.AWSResourcePrefix)[1] resourcePrefix := strings.SplitAfter(resource, accesspolicy.AWSResourcePrefix)[1]
if !strings.HasPrefix(resourcePrefix, bucket) { if !strings.HasPrefix(resourcePrefix, bucket) {
writeErrorResponse(w, r, MalformedPolicy, r.URL.Path) writeErrorResponse(w, r, ErrMalformedPolicy, r.URL.Path)
return return
} }
} }
@ -183,11 +183,11 @@ func (api storageAPI) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Requ
ok, err := auth.DoesPresignedSignatureMatch() ok, err := auth.DoesPresignedSignatureMatch()
if err != nil { if err != nil {
errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil) errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil)
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
} else if isRequestSignatureV4(r) { } else if isRequestSignatureV4(r) {
@ -196,11 +196,11 @@ func (api storageAPI) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Requ
ok, err := api.Signature.DoesSignatureMatch(hex.EncodeToString(sh.Sum(nil))) ok, err := api.Signature.DoesSignatureMatch(hex.EncodeToString(sh.Sum(nil)))
if err != nil { if err != nil {
errorIf(err.Trace(string(accessPolicyBytes)), "SaveBucketPolicy failed.", nil) errorIf(err.Trace(string(accessPolicyBytes)), "SaveBucketPolicy failed.", nil)
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
} }
@ -211,9 +211,9 @@ func (api storageAPI) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Requ
errorIf(err.Trace(bucket), "SaveBucketPolicy failed.", nil) errorIf(err.Trace(bucket), "SaveBucketPolicy failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -229,7 +229,7 @@ func (api storageAPI) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.R
bucket := vars["bucket"] bucket := vars["bucket"]
// Validate incoming signature. // Validate incoming signature.
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -240,11 +240,11 @@ func (api storageAPI) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.R
errorIf(err.Trace(bucket), "DeleteBucketPolicy failed.", nil) errorIf(err.Trace(bucket), "DeleteBucketPolicy failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketPolicyNotFound: case fs.BucketPolicyNotFound:
writeErrorResponse(w, r, NoSuchBucketPolicy, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucketPolicy, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -260,7 +260,7 @@ func (api storageAPI) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Requ
bucket := vars["bucket"] bucket := vars["bucket"]
// Validate incoming signature. // Validate incoming signature.
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -271,11 +271,11 @@ func (api storageAPI) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Requ
errorIf(err.Trace(bucket), "GetBucketPolicy failed.", nil) errorIf(err.Trace(bucket), "GetBucketPolicy failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketPolicyNotFound: case fs.BucketPolicyNotFound:
writeErrorResponse(w, r, NoSuchBucketPolicy, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucketPolicy, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }

View file

@ -86,7 +86,7 @@ func (h cacheControlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// For all browser requests set appropriate Cache-Control policies // For all browser requests set appropriate Cache-Control policies
match, e := regexp.MatchString(privateBucket+`/([^/]+\.js|favicon.ico)`, r.URL.Path) match, e := regexp.MatchString(privateBucket+`/([^/]+\.js|favicon.ico)`, r.URL.Path)
if e != nil { if e != nil {
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
return return
} }
if match { if match {
@ -114,7 +114,7 @@ func setPrivateBucketHandler(h http.Handler) http.Handler {
func (h minioPrivateBucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h minioPrivateBucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// For all non browser requests, reject access to 'privateBucket'. // For all non browser requests, reject access to 'privateBucket'.
if !strings.Contains(r.Header.Get("User-Agent"), "Mozilla") && path.Clean(r.URL.Path) == privateBucket { if !strings.Contains(r.Header.Get("User-Agent"), "Mozilla") && path.Clean(r.URL.Path) == privateBucket {
writeErrorResponse(w, r, AllAccessDisabled, r.URL.Path) writeErrorResponse(w, r, ErrAllAccessDisabled, r.URL.Path)
return return
} }
h.handler.ServeHTTP(w, r) h.handler.ServeHTTP(w, r)
@ -184,13 +184,13 @@ func (h timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// All our internal APIs are sensitive towards Date // All our internal APIs are sensitive towards Date
// header, for all requests where Date header is not // header, for all requests where Date header is not
// present we will reject such clients. // present we will reject such clients.
writeErrorResponse(w, r, RequestTimeTooSkewed, r.URL.Path) writeErrorResponse(w, r, ErrRequestTimeTooSkewed, r.URL.Path)
return return
} }
// Verify if the request date header is more than 5minutes // Verify if the request date header is more than 5minutes
// late, reject such clients. // late, reject such clients.
if time.Now().UTC().Sub(date)/time.Minute > time.Duration(5)*time.Minute { if time.Now().UTC().Sub(date)/time.Minute > time.Duration(5)*time.Minute {
writeErrorResponse(w, r, RequestTimeTooSkewed, r.URL.Path) writeErrorResponse(w, r, ErrRequestTimeTooSkewed, r.URL.Path)
return return
} }
} }
@ -237,20 +237,20 @@ func (h resourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// level resource queries. // level resource queries.
if bucketName != "" && objectName == "" { if bucketName != "" && objectName == "" {
if ignoreNotImplementedBucketResources(r) { if ignoreNotImplementedBucketResources(r) {
writeErrorResponse(w, r, NotImplemented, r.URL.Path) writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
return return
} }
} }
// If bucketName and objectName are present check for its resource queries. // If bucketName and objectName are present check for its resource queries.
if bucketName != "" && objectName != "" { if bucketName != "" && objectName != "" {
if ignoreNotImplementedObjectResources(r) { if ignoreNotImplementedObjectResources(r) {
writeErrorResponse(w, r, NotImplemented, r.URL.Path) writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
return return
} }
} }
// A put method on path "/" doesn't make sense, ignore it. // A put method on path "/" doesn't make sense, ignore it.
if r.Method == "PUT" && r.URL.Path == "/" { if r.Method == "PUT" && r.URL.Path == "/" {
writeErrorResponse(w, r, NotImplemented, r.URL.Path) writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
return return
} }
h.handler.ServeHTTP(w, r) h.handler.ServeHTTP(w, r)

View file

@ -64,16 +64,16 @@ func (api storageAPI) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:GetObject", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:GetObject", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
case authTypePresigned, authTypeSigned: case authTypePresigned, authTypeSigned:
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -84,15 +84,15 @@ func (api storageAPI) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
errorIf(err.Trace(), "GetObject failed.", nil) errorIf(err.Trace(), "GetObject failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.ObjectNotFound: case fs.ObjectNotFound:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -100,7 +100,7 @@ func (api storageAPI) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
var hrange *httpRange var hrange *httpRange
hrange, err = getRequestedRange(r.Header.Get("Range"), metadata.Size) hrange, err = getRequestedRange(r.Header.Get("Range"), metadata.Size)
if err != nil { if err != nil {
writeErrorResponse(w, r, InvalidRange, r.URL.Path) writeErrorResponse(w, r, ErrInvalidRange, r.URL.Path)
return return
} }
@ -231,7 +231,7 @@ func (api storageAPI) HeadObjectHandler(w http.ResponseWriter, r *http.Request)
bucket = vars["bucket"] bucket = vars["bucket"]
object = vars["object"] object = vars["object"]
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -240,15 +240,15 @@ func (api storageAPI) HeadObjectHandler(w http.ResponseWriter, r *http.Request)
if err != nil { if err != nil {
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.ObjectNotFound: case fs.ObjectNotFound:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -288,16 +288,16 @@ func (api storageAPI) CopyObjectHandler(w http.ResponseWriter, r *http.Request)
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:GetBucketLocation", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:GetBucketLocation", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
case authTypePresigned, authTypeSigned: case authTypePresigned, authTypeSigned:
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -323,13 +323,13 @@ func (api storageAPI) CopyObjectHandler(w http.ResponseWriter, r *http.Request)
} }
// If source object is empty, reply back error. // If source object is empty, reply back error.
if sourceObject == "" { if sourceObject == "" {
writeErrorResponse(w, r, InvalidCopySource, r.URL.Path) writeErrorResponse(w, r, ErrInvalidCopySource, r.URL.Path)
return return
} }
// Source and destination objects cannot be same, reply back error. // Source and destination objects cannot be same, reply back error.
if sourceObject == object && sourceBucket == bucket { if sourceObject == object && sourceBucket == bucket {
writeErrorResponse(w, r, InvalidCopyDest, r.URL.Path) writeErrorResponse(w, r, ErrInvalidCopyDest, r.URL.Path)
return return
} }
@ -338,22 +338,22 @@ func (api storageAPI) CopyObjectHandler(w http.ResponseWriter, r *http.Request)
errorIf(err.Trace(), "GetObjectMetadata failed.", nil) errorIf(err.Trace(), "GetObjectMetadata failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, objectSource) writeErrorResponse(w, r, ErrInvalidBucketName, objectSource)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, objectSource) writeErrorResponse(w, r, ErrNoSuchBucket, objectSource)
case fs.ObjectNotFound: case fs.ObjectNotFound:
writeErrorResponse(w, r, NoSuchKey, objectSource) writeErrorResponse(w, r, ErrNoSuchKey, objectSource)
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
writeErrorResponse(w, r, NoSuchKey, objectSource) writeErrorResponse(w, r, ErrNoSuchKey, objectSource)
default: default:
writeErrorResponse(w, r, InternalError, objectSource) writeErrorResponse(w, r, ErrInternalError, objectSource)
} }
return return
} }
/// maximum Upload size for object in a single CopyObject operation. /// maximum Upload size for object in a single CopyObject operation.
if isMaxObjectSize(metadata.Size) { if isMaxObjectSize(metadata.Size) {
writeErrorResponse(w, r, EntityTooLarge, objectSource) writeErrorResponse(w, r, ErrEntityTooLarge, objectSource)
return return
} }
@ -380,21 +380,21 @@ func (api storageAPI) CopyObjectHandler(w http.ResponseWriter, r *http.Request)
errorIf(err.Trace(), "CreateObject failed.", nil) errorIf(err.Trace(), "CreateObject failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.RootPathFull: case fs.RootPathFull:
writeErrorResponse(w, r, RootPathFull, r.URL.Path) writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BadDigest: case fs.BadDigest:
writeErrorResponse(w, r, BadDigest, r.URL.Path) writeErrorResponse(w, r, ErrBadDigest, r.URL.Path)
case fs.IncompleteBody: case fs.IncompleteBody:
writeErrorResponse(w, r, IncompleteBody, r.URL.Path) writeErrorResponse(w, r, ErrIncompleteBody, r.URL.Path)
case fs.InvalidDigest: case fs.InvalidDigest:
writeErrorResponse(w, r, InvalidDigest, r.URL.Path) writeErrorResponse(w, r, ErrInvalidDigest, r.URL.Path)
case fs.ObjectExistsAsPrefix: case fs.ObjectExistsAsPrefix:
writeErrorResponse(w, r, ObjectExistsAsPrefix, r.URL.Path) writeErrorResponse(w, r, ErrObjectExistsAsPrefix, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -413,7 +413,7 @@ func (api storageAPI) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
// If the matching failed, it means that the X-Amz-Copy-Source was // If the matching failed, it means that the X-Amz-Copy-Source was
// wrong, fail right here. // wrong, fail right here.
if _, ok := r.Header["X-Amz-Copy-Source"]; ok { if _, ok := r.Header["X-Amz-Copy-Source"]; ok {
writeErrorResponse(w, r, InvalidCopySource, r.URL.Path) writeErrorResponse(w, r, ErrInvalidCopySource, r.URL.Path)
return return
} }
vars := mux.Vars(r) vars := mux.Vars(r)
@ -423,18 +423,18 @@ func (api storageAPI) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
// get Content-Md5 sent by client and verify if valid // get Content-Md5 sent by client and verify if valid
md5 := r.Header.Get("Content-Md5") md5 := r.Header.Get("Content-Md5")
if !isValidMD5(md5) { if !isValidMD5(md5) {
writeErrorResponse(w, r, InvalidDigest, r.URL.Path) writeErrorResponse(w, r, ErrInvalidDigest, r.URL.Path)
return return
} }
/// if Content-Length is unknown/missing, deny the request /// if Content-Length is unknown/missing, deny the request
size := r.ContentLength size := r.ContentLength
if size == -1 && !contains(r.TransferEncoding, "chunked") { if size == -1 && !contains(r.TransferEncoding, "chunked") {
writeErrorResponse(w, r, MissingContentLength, r.URL.Path) writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
return return
} }
/// maximum Upload size for objects in a single operation /// maximum Upload size for objects in a single operation
if isMaxObjectSize(size) { if isMaxObjectSize(size) {
writeErrorResponse(w, r, EntityTooLarge, r.URL.Path) writeErrorResponse(w, r, ErrEntityTooLarge, r.URL.Path)
return return
} }
@ -445,11 +445,11 @@ func (api storageAPI) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -461,11 +461,11 @@ func (api storageAPI) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
ok, err = auth.DoesPresignedSignatureMatch() ok, err = auth.DoesPresignedSignatureMatch()
if err != nil { if err != nil {
errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil) errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil)
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
// Create presigned object. // Create presigned object.
@ -478,23 +478,23 @@ func (api storageAPI) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
errorIf(err.Trace(), "CreateObject failed.", nil) errorIf(err.Trace(), "CreateObject failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.RootPathFull: case fs.RootPathFull:
writeErrorResponse(w, r, RootPathFull, r.URL.Path) writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BadDigest: case fs.BadDigest:
writeErrorResponse(w, r, BadDigest, r.URL.Path) writeErrorResponse(w, r, ErrBadDigest, r.URL.Path)
case fs.SignDoesNotMatch: case fs.SignDoesNotMatch:
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
case fs.IncompleteBody: case fs.IncompleteBody:
writeErrorResponse(w, r, IncompleteBody, r.URL.Path) writeErrorResponse(w, r, ErrIncompleteBody, r.URL.Path)
case fs.InvalidDigest: case fs.InvalidDigest:
writeErrorResponse(w, r, InvalidDigest, r.URL.Path) writeErrorResponse(w, r, ErrInvalidDigest, r.URL.Path)
case fs.ObjectExistsAsPrefix: case fs.ObjectExistsAsPrefix:
writeErrorResponse(w, r, ObjectExistsAsPrefix, r.URL.Path) writeErrorResponse(w, r, ErrObjectExistsAsPrefix, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -516,12 +516,12 @@ func (api storageAPI) NewMultipartUploadHandler(w http.ResponseWriter, r *http.R
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
default: default:
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -532,17 +532,17 @@ func (api storageAPI) NewMultipartUploadHandler(w http.ResponseWriter, r *http.R
errorIf(err.Trace(), "NewMultipartUpload failed.", nil) errorIf(err.Trace(), "NewMultipartUpload failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.RootPathFull: case fs.RootPathFull:
writeErrorResponse(w, r, RootPathFull, r.URL.Path) writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.ObjectNotFound: case fs.ObjectNotFound:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -564,20 +564,20 @@ func (api storageAPI) PutObjectPartHandler(w http.ResponseWriter, r *http.Reques
// get Content-Md5 sent by client and verify if valid // get Content-Md5 sent by client and verify if valid
md5 := r.Header.Get("Content-Md5") md5 := r.Header.Get("Content-Md5")
if !isValidMD5(md5) { if !isValidMD5(md5) {
writeErrorResponse(w, r, InvalidDigest, r.URL.Path) writeErrorResponse(w, r, ErrInvalidDigest, r.URL.Path)
return return
} }
/// if Content-Length is unknown/missing, throw away /// if Content-Length is unknown/missing, throw away
size := r.ContentLength size := r.ContentLength
if size == -1 { if size == -1 {
writeErrorResponse(w, r, MissingContentLength, r.URL.Path) writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
return return
} }
/// maximum Upload size for multipart objects in a single operation /// maximum Upload size for multipart objects in a single operation
if isMaxObjectSize(size) { if isMaxObjectSize(size) {
writeErrorResponse(w, r, EntityTooLarge, r.URL.Path) writeErrorResponse(w, r, ErrEntityTooLarge, r.URL.Path)
return return
} }
@ -586,7 +586,7 @@ func (api storageAPI) PutObjectPartHandler(w http.ResponseWriter, r *http.Reques
partID, e := strconv.Atoi(partIDString) partID, e := strconv.Atoi(partIDString)
if e != nil { if e != nil {
writeErrorResponse(w, r, InvalidPart, r.URL.Path) writeErrorResponse(w, r, ErrInvalidPart, r.URL.Path)
return return
} }
@ -597,7 +597,7 @@ func (api storageAPI) PutObjectPartHandler(w http.ResponseWriter, r *http.Reques
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -610,11 +610,11 @@ func (api storageAPI) PutObjectPartHandler(w http.ResponseWriter, r *http.Reques
ok, err = auth.DoesPresignedSignatureMatch() ok, err = auth.DoesPresignedSignatureMatch()
if err != nil { if err != nil {
errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil) errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil)
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
partMD5, err = api.Filesystem.CreateObjectPart(bucket, object, uploadID, md5, partID, size, r.Body, nil) partMD5, err = api.Filesystem.CreateObjectPart(bucket, object, uploadID, md5, partID, size, r.Body, nil)
@ -625,19 +625,19 @@ func (api storageAPI) PutObjectPartHandler(w http.ResponseWriter, r *http.Reques
errorIf(err.Trace(), "CreateObjectPart failed.", nil) errorIf(err.Trace(), "CreateObjectPart failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.RootPathFull: case fs.RootPathFull:
writeErrorResponse(w, r, RootPathFull, r.URL.Path) writeErrorResponse(w, r, ErrRootPathFull, r.URL.Path)
case fs.InvalidUploadID: case fs.InvalidUploadID:
writeErrorResponse(w, r, NoSuchUpload, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchUpload, r.URL.Path)
case fs.BadDigest: case fs.BadDigest:
writeErrorResponse(w, r, BadDigest, r.URL.Path) writeErrorResponse(w, r, ErrBadDigest, r.URL.Path)
case fs.SignDoesNotMatch: case fs.SignDoesNotMatch:
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
case fs.IncompleteBody: case fs.IncompleteBody:
writeErrorResponse(w, r, IncompleteBody, r.URL.Path) writeErrorResponse(w, r, ErrIncompleteBody, r.URL.Path)
case fs.InvalidDigest: case fs.InvalidDigest:
writeErrorResponse(w, r, InvalidDigest, r.URL.Path) writeErrorResponse(w, r, ErrInvalidDigest, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -656,12 +656,12 @@ func (api storageAPI) AbortMultipartUploadHandler(w http.ResponseWriter, r *http
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:AbortMultipartUpload", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:AbortMultipartUpload", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
default: default:
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -673,17 +673,17 @@ func (api storageAPI) AbortMultipartUploadHandler(w http.ResponseWriter, r *http
errorIf(err.Trace(), "AbortMutlipartUpload failed.", nil) errorIf(err.Trace(), "AbortMutlipartUpload failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.ObjectNotFound: case fs.ObjectNotFound:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.InvalidUploadID: case fs.InvalidUploadID:
writeErrorResponse(w, r, NoSuchUpload, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchUpload, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -699,12 +699,12 @@ func (api storageAPI) ListObjectPartsHandler(w http.ResponseWriter, r *http.Requ
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:ListMultipartUploadParts", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:ListMultipartUploadParts", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
default: default:
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -712,11 +712,11 @@ func (api storageAPI) ListObjectPartsHandler(w http.ResponseWriter, r *http.Requ
objectResourcesMetadata := getObjectResources(r.URL.Query()) objectResourcesMetadata := getObjectResources(r.URL.Query())
if objectResourcesMetadata.PartNumberMarker < 0 { if objectResourcesMetadata.PartNumberMarker < 0 {
writeErrorResponse(w, r, InvalidPartNumberMarker, r.URL.Path) writeErrorResponse(w, r, ErrInvalidPartNumberMarker, r.URL.Path)
return return
} }
if objectResourcesMetadata.MaxParts < 0 { if objectResourcesMetadata.MaxParts < 0 {
writeErrorResponse(w, r, InvalidMaxParts, r.URL.Path) writeErrorResponse(w, r, ErrInvalidMaxParts, r.URL.Path)
return return
} }
if objectResourcesMetadata.MaxParts == 0 { if objectResourcesMetadata.MaxParts == 0 {
@ -728,17 +728,17 @@ func (api storageAPI) ListObjectPartsHandler(w http.ResponseWriter, r *http.Requ
errorIf(err.Trace(), "ListObjectParts failed.", nil) errorIf(err.Trace(), "ListObjectParts failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.ObjectNotFound: case fs.ObjectNotFound:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.InvalidUploadID: case fs.InvalidUploadID:
writeErrorResponse(w, r, NoSuchUpload, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchUpload, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -767,11 +767,11 @@ func (api storageAPI) CompleteMultipartUploadHandler(w http.ResponseWriter, r *h
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:PutObject", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -783,11 +783,11 @@ func (api storageAPI) CompleteMultipartUploadHandler(w http.ResponseWriter, r *h
ok, err = auth.DoesPresignedSignatureMatch() ok, err = auth.DoesPresignedSignatureMatch()
if err != nil { if err != nil {
errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil) errorIf(err.Trace(r.URL.String()), "Presigned signature verification failed.", nil)
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
if !ok { if !ok {
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
return return
} }
// Complete multipart upload presigned. // Complete multipart upload presigned.
@ -800,27 +800,27 @@ func (api storageAPI) CompleteMultipartUploadHandler(w http.ResponseWriter, r *h
errorIf(err.Trace(), "CompleteMultipartUpload failed.", nil) errorIf(err.Trace(), "CompleteMultipartUpload failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.ObjectNotFound: case fs.ObjectNotFound:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.InvalidUploadID: case fs.InvalidUploadID:
writeErrorResponse(w, r, NoSuchUpload, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchUpload, r.URL.Path)
case fs.InvalidPart: case fs.InvalidPart:
writeErrorResponse(w, r, InvalidPart, r.URL.Path) writeErrorResponse(w, r, ErrInvalidPart, r.URL.Path)
case fs.InvalidPartOrder: case fs.InvalidPartOrder:
writeErrorResponse(w, r, InvalidPartOrder, r.URL.Path) writeErrorResponse(w, r, ErrInvalidPartOrder, r.URL.Path)
case fs.SignDoesNotMatch: case fs.SignDoesNotMatch:
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path) writeErrorResponse(w, r, ErrSignatureDoesNotMatch, r.URL.Path)
case fs.IncompleteBody: case fs.IncompleteBody:
writeErrorResponse(w, r, IncompleteBody, r.URL.Path) writeErrorResponse(w, r, ErrIncompleteBody, r.URL.Path)
case fs.MalformedXML: case fs.MalformedXML:
writeErrorResponse(w, r, MalformedXML, r.URL.Path) writeErrorResponse(w, r, ErrMalformedXML, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
return return
} }
@ -846,16 +846,16 @@ func (api storageAPI) DeleteObjectHandler(w http.ResponseWriter, r *http.Request
switch getRequestAuthType(r) { switch getRequestAuthType(r) {
default: default:
// For all unknown auth types return error. // For all unknown auth types return error.
writeErrorResponse(w, r, AccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeAnonymous: case authTypeAnonymous:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
if isAllowed, s3Error := enforceBucketPolicy("s3:DeleteObject", bucket, r.URL); !isAllowed { if s3Error := enforceBucketPolicy("s3:DeleteObject", bucket, r.URL); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
case authTypeSigned, authTypePresigned: case authTypeSigned, authTypePresigned:
if match, s3Error := isSignV4ReqAuthenticated(api.Signature, r); !match { if s3Error := isReqAuthenticated(api.Signature, r); s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -865,15 +865,15 @@ func (api storageAPI) DeleteObjectHandler(w http.ResponseWriter, r *http.Request
errorIf(err.Trace(), "DeleteObject failed.", nil) errorIf(err.Trace(), "DeleteObject failed.", nil)
switch err.ToGoError().(type) { switch err.ToGoError().(type) {
case fs.BucketNameInvalid: case fs.BucketNameInvalid:
writeErrorResponse(w, r, InvalidBucketName, r.URL.Path) writeErrorResponse(w, r, ErrInvalidBucketName, r.URL.Path)
case fs.BucketNotFound: case fs.BucketNotFound:
writeErrorResponse(w, r, NoSuchBucket, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchBucket, r.URL.Path)
case fs.ObjectNotFound: case fs.ObjectNotFound:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
case fs.ObjectNameInvalid: case fs.ObjectNameInvalid:
writeErrorResponse(w, r, NoSuchKey, r.URL.Path) writeErrorResponse(w, r, ErrNoSuchKey, r.URL.Path)
default: default:
writeErrorResponse(w, r, InternalError, r.URL.Path) writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
} }
} }
writeSuccessNoContent(w) writeSuccessNoContent(w)

View file

@ -40,7 +40,7 @@ func TestListBuckets(t *testing.T) {
// Create a few buckets. // Create a few buckets.
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
err = filesystem.MakeBucket("testbucket."+strconv.Itoa(i), "public-read") err = filesystem.MakeBucket("testbucket." + strconv.Itoa(i))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -53,7 +53,7 @@ func TestListBuckets(t *testing.T) {
} }
if len(metadatas) != 10 { if len(metadatas) != 10 {
t.Errorf("incorrect length of metadatas (%i)\n", len(metadatas)) t.Errorf("incorrect length of metadatas (%d)\n", len(metadatas))
} }
// Iterate over the buckets, ensuring that the name is correct. // Iterate over the buckets, ensuring that the name is correct.
@ -101,7 +101,7 @@ func BenchmarkListBuckets(b *testing.B) {
// Create a few buckets. // Create a few buckets.
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
err = filesystem.MakeBucket("bucket."+strconv.Itoa(i), "public-read") err = filesystem.MakeBucket("bucket." + strconv.Itoa(i))
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }