From fef5416b3cbe095f5c87b31c5d1c8ae6f9a66f6c Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Tue, 12 Feb 2019 01:25:52 -0800 Subject: [PATCH] Support unknown gateway errors and convert at handler layer (#7219) Different gateway implementations due to different backend API errors, might return different unsupported errors at our handler layer. Current code posed a problem for us because this information was lost and we would convert it to InternalError in this situation all S3 clients end up retrying the request. To avoid this unexpected situation implement a way to support this cleanly such that the underlying information is not lost which is returned by gateway. --- cmd/acl-handlers.go | 16 +- cmd/admin-handlers.go | 486 +++++++++------------------- cmd/admin-handlers_test.go | 14 +- cmd/admin-heal-ops.go | 18 +- cmd/api-errors.go | 77 ++++- cmd/api-errors_test.go | 4 +- cmd/api-response-multipart.go | 2 +- cmd/api-response.go | 32 +- cmd/auth-handler.go | 2 +- cmd/auth-handler_test.go | 2 +- cmd/bucket-handlers-listobjects.go | 39 ++- cmd/bucket-handlers.go | 143 ++++---- cmd/bucket-handlers_test.go | 4 +- cmd/bucket-notification-handlers.go | 65 ++-- cmd/bucket-policy-handlers.go | 34 +- cmd/copy-part-range.go | 9 +- cmd/dummy-handlers.go | 24 +- cmd/encryption-v1.go | 10 +- cmd/gateway/gcs/gateway-gcs.go | 2 - cmd/gateway/gcs/gateway-gcs_test.go | 9 - cmd/generic-handlers.go | 38 +-- cmd/handler-utils.go | 4 +- cmd/object-handlers-common.go | 12 +- cmd/object-handlers.go | 386 +++++++++++----------- cmd/object-handlers_test.go | 8 +- cmd/signature-v4-parser_test.go | 2 +- cmd/signature-v4_test.go | 2 +- cmd/test-utils_test.go | 4 +- cmd/web-handlers.go | 8 +- 29 files changed, 677 insertions(+), 779 deletions(-) diff --git a/cmd/acl-handlers.go b/cmd/acl-handlers.go index f96be62f0..2feb458c1 100644 --- a/cmd/acl-handlers.go +++ b/cmd/acl-handlers.go @@ -64,21 +64,21 @@ func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http. objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } // Allow getBucketACL if policy action is set, since this is a dummy call // we are simply re-purposing the bucketPolicyAction. if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketPolicyAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Before proceeding validate if bucket exists. _, err := objAPI.GetBucketInfo(ctx, bucket) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -92,7 +92,7 @@ func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http. Permission: "FULL_CONTROL", }) if err := xml.NewEncoder(w).Encode(acl); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -114,21 +114,21 @@ func (api objectAPIHandlers) GetObjectACLHandler(w http.ResponseWriter, r *http. objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } // Allow getObjectACL if policy action is set, since this is a dummy call // we are simply re-purposing the bucketPolicyAction. if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketPolicyAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Before proceeding validate if object exists. _, err := objAPI.GetObjectInfo(ctx, bucket, object, ObjectOptions{}) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -142,7 +142,7 @@ func (api objectAPIHandlers) GetObjectACLHandler(w http.ResponseWriter, r *http. Permission: "FULL_CONTROL", }) if err := xml.NewEncoder(w).Encode(acl); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index ff7e291f7..5b770bf74 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -76,15 +76,14 @@ var ( func (a adminAPIHandlers) VersionHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "Version") - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } jsonBytes, err := json.Marshal(adminAPIVersionInfo) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -97,14 +96,8 @@ func (a adminAPIHandlers) VersionHandler(w http.ResponseWriter, r *http.Request) func (a adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ServiceStatus") - if globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } @@ -126,7 +119,7 @@ func (a adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *http.Re // Marshal API response jsonBytes, err := json.Marshal(serverStatus) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -143,21 +136,15 @@ func (a adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *http.Re func (a adminAPIHandlers) ServiceStopNRestartHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ServiceStopNRestart") - if globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } var sa madmin.ServiceAction err := json.NewDecoder(r.Body).Decode(&sa) if err != nil { - writeErrorResponseJSON(w, ErrRequestBodyParse, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrRequestBodyParse), r.URL) return } @@ -168,7 +155,7 @@ func (a adminAPIHandlers) ServiceStopNRestartHandler(w http.ResponseWriter, r *h case madmin.ServiceActionValueStop: serviceSig = serviceStop default: - writeErrorResponseJSON(w, ErrMalformedPOSTRequest, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL) logger.LogIf(ctx, errors.New("Invalid service action received")) return } @@ -248,24 +235,14 @@ type ServerInfo struct { func (a adminAPIHandlers) ServerInfoHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ServerInfo") - objectAPI := newObjectLayerFn() - if objectAPI == nil || globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Authenticate request - - // Setting the region as empty so as the mc server info command is irrespective to the region. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } thisAddr, err := xnet.ParseHost(GetLocalPeer(globalEndpoints)) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -291,7 +268,7 @@ func (a adminAPIHandlers) ServerInfoHandler(w http.ResponseWriter, r *http.Reque // Marshal API response jsonBytes, err := json.Marshal(serverInfo) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -336,18 +313,8 @@ type ServerMemUsageInfo struct { func (a adminAPIHandlers) PerfInfoHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "PerfInfo") - // Get object layer instance. - objLayer := newObjectLayerFn() - if objLayer == nil || globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Authenticate request - // Setting the region as empty so as the mc server info command is irrespective to the region. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } @@ -355,10 +322,9 @@ func (a adminAPIHandlers) PerfInfoHandler(w http.ResponseWriter, r *http.Request perfType := vars["perfType"] if perfType == "drive" { - info := objLayer.StorageInfo(ctx) + info := objectAPI.StorageInfo(ctx) if !(info.Backend.Type == BackendFS || info.Backend.Type == BackendErasure) { - - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } // Get drive performance details from local server's drive(s) @@ -371,7 +337,7 @@ func (a adminAPIHandlers) PerfInfoHandler(w http.ResponseWriter, r *http.Request // Marshal API response jsonBytes, err := json.Marshal(dps) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -388,7 +354,7 @@ func (a adminAPIHandlers) PerfInfoHandler(w http.ResponseWriter, r *http.Request // Marshal API response jsonBytes, err := json.Marshal(cpus) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -405,7 +371,7 @@ func (a adminAPIHandlers) PerfInfoHandler(w http.ResponseWriter, r *http.Request // Marshal API response jsonBytes, err := json.Marshal(mems) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -413,7 +379,7 @@ func (a adminAPIHandlers) PerfInfoHandler(w http.ResponseWriter, r *http.Request // distributed setup) as json. writeSuccessResponseJSON(w, jsonBytes) } else { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) } return } @@ -466,29 +432,20 @@ type PeerLocks struct { func (a adminAPIHandlers) TopLocksHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "TopLocks") - objectAPI := newObjectLayerFn() - if objectAPI == nil || globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } - // Method only allowed in Distributed XL mode. - if globalIsDistXL == false { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) - return - } - - // Authenticate request - // Setting the region as empty so as the mc server info command is irrespective to the region. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + // Method only allowed in XL mode. + if !globalIsDistXL { + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } thisAddr, err := xnet.ParseHost(GetLocalPeer(globalEndpoints)) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -506,7 +463,7 @@ func (a adminAPIHandlers) TopLocksHandler(w http.ResponseWriter, r *http.Request // Marshal API response jsonBytes, err := json.Marshal(topLocks) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -529,14 +486,8 @@ type StartProfilingResult struct { func (a adminAPIHandlers) StartProfilingHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "StartProfiling") - if globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } @@ -545,7 +496,7 @@ func (a adminAPIHandlers) StartProfilingHandler(w http.ResponseWriter, r *http.R thisAddr, err := xnet.ParseHost(GetLocalPeer(globalEndpoints)) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -586,7 +537,7 @@ func (a adminAPIHandlers) StartProfilingHandler(w http.ResponseWriter, r *http.R // Create JSON result and send it to the client startProfilingResultInBytes, err := json.Marshal(startProfilingResult) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -617,19 +568,13 @@ func (f dummyFileInfo) Sys() interface{} { return f.sys } func (a adminAPIHandlers) DownloadProfilingHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "DownloadProfiling") - if globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } if !globalNotificationSys.DownloadProfilingData(ctx, w) { - writeErrorResponseJSON(w, ErrAdminProfilerNotEnabled, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminProfilerNotEnabled), r.URL) return } } @@ -700,35 +645,26 @@ func extractHealInitParams(r *http.Request) (bucket, objPrefix string, func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "Heal") - // Get object layer instance. - objLayer := newObjectLayerFn() - if objLayer == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } // Check if this setup has an erasure coded backend. if !globalIsXL { - writeErrorResponseJSON(w, ErrHealNotImplemented, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrHealNotImplemented), r.URL) return } - bucket, objPrefix, hs, clientToken, forceStart, forceStop, apiErr := extractHealInitParams(r) - if apiErr != ErrNone { - writeErrorResponseJSON(w, apiErr, r.URL) + bucket, objPrefix, hs, clientToken, forceStart, forceStop, errCode := extractHealInitParams(r) + if errCode != ErrNone { + writeErrorResponseJSON(w, errorCodes.ToAPIErr(errCode), r.URL) return } type healResp struct { respBytes []byte - errCode APIErrorCode + apiErr APIError errBody string } @@ -754,8 +690,8 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("\n\r")) w.(http.Flusher).Flush() case hr := <-respCh: - switch hr.errCode { - case ErrNone: + switch hr.apiErr { + case noError: if started { w.Write(hr.respBytes) w.(http.Flusher).Flush() @@ -763,13 +699,13 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { writeSuccessResponseJSON(w, hr.respBytes) } default: - apiError := getAPIError(hr.errCode) var errorRespJSON []byte if hr.errBody == "" { - errorRespJSON = encodeResponseJSON(getAPIErrorResponse(apiError, r.URL.Path, w.Header().Get(responseRequestIDKey))) + errorRespJSON = encodeResponseJSON(getAPIErrorResponse(hr.apiErr, + r.URL.Path, w.Header().Get(responseRequestIDKey))) } else { errorRespJSON = encodeResponseJSON(APIErrorResponse{ - Code: apiError.Code, + Code: hr.apiErr.Code, Message: hr.errBody, Resource: r.URL.Path, RequestID: w.Header().Get(responseRequestIDKey), @@ -779,7 +715,7 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { if !started { setCommonHeaders(w) w.Header().Set("Content-Type", string(mimeJSON)) - w.WriteHeader(apiError.HTTPStatusCode) + w.WriteHeader(hr.apiErr.HTTPStatusCode) } w.Write(errorRespJSON) w.(http.Flusher).Flush() @@ -790,7 +726,7 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { } // find number of disks in the setup - info := objLayer.StorageInfo(ctx) + info := objectAPI.StorageInfo(ctx) numDisks := info.Backend.OfflineDisks + info.Backend.OnlineDisks healPath := pathJoin(bucket, objPrefix) @@ -803,7 +739,7 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { StartTime: nh.startTime, }) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } // Client token not specified but a heal sequence exists on a path, @@ -819,7 +755,7 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { respBytes, errCode := globalAllHealState.PopHealStatusJSON( healPath, clientToken) if errCode != ErrNone { - writeErrorResponseJSON(w, errCode, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(errCode), r.URL) } else { writeSuccessResponseJSON(w, respBytes) } @@ -830,15 +766,15 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { switch { case forceStop: go func() { - respBytes, errCode := globalAllHealState.stopHealSequence(healPath) - hr := healResp{respBytes: respBytes, errCode: errCode} + respBytes, apiErr := globalAllHealState.stopHealSequence(healPath) + hr := healResp{respBytes: respBytes, apiErr: apiErr} respCh <- hr }() case clientToken == "": nh := newHealSequence(bucket, objPrefix, handlers.GetSourceIP(r), numDisks, hs, forceStart) go func() { - respBytes, errCode, errMsg := globalAllHealState.LaunchNewHealSequence(nh) - hr := healResp{respBytes, errCode, errMsg} + respBytes, apiErr, errMsg := globalAllHealState.LaunchNewHealSequence(nh) + hr := healResp{respBytes, apiErr, errMsg} respCh <- hr }() } @@ -854,36 +790,27 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) { func (a adminAPIHandlers) GetConfigHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "GetConfigHandler") - // Get current object layer instance. - objectAPI := newObjectLayerFn() + objectAPI := validateAdminReq(ctx, w, r) if objectAPI == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) return } config, err := readServerConfig(ctx, objectAPI) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } configData, err := json.MarshalIndent(config, "", "\t") if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } password := config.GetCredential().SecretKey econfigData, err := madmin.EncryptData(password, configData) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -909,22 +836,31 @@ func normalizeJSONKey(input string) (key string) { return } -// GetConfigHandler - GET /minio/admin/v1/config-keys -// Get some keys in config.json of this minio setup. -func (a adminAPIHandlers) GetConfigKeysHandler(w http.ResponseWriter, r *http.Request) { - ctx := newContext(r, w, "GetConfigKeysHandler") - +func validateAdminReq(ctx context.Context, w http.ResponseWriter, r *http.Request) ObjectLayer { // Get current object layer instance. objectAPI := newObjectLayerFn() - if objectAPI == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return + if objectAPI == nil || globalNotificationSys == nil || globalIAMSys == nil { + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) + return nil } // Validate request signature. adminAPIErr := checkAdminRequestAuthType(ctx, r, "") if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(adminAPIErr), r.URL) + return nil + } + + return objectAPI +} + +// GetConfigHandler - GET /minio/admin/v1/config-keys +// Get some keys in config.json of this minio setup. +func (a adminAPIHandlers) GetConfigKeysHandler(w http.ResponseWriter, r *http.Request) { + ctx := newContext(r, w, "GetConfigKeysHandler") + + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } @@ -937,13 +873,13 @@ func (a adminAPIHandlers) GetConfigKeysHandler(w http.ResponseWriter, r *http.Re config, err := readServerConfig(ctx, objectAPI) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } configData, err := json.Marshal(config) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -965,7 +901,7 @@ func (a adminAPIHandlers) GetConfigKeysHandler(w http.ResponseWriter, r *http.Re password := config.GetCredential().SecretKey econfigData, err := madmin.EncryptData(password, []byte(newConfigStr)) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -983,34 +919,29 @@ func toAdminAPIErrCode(ctx context.Context, err error) APIErrorCode { } } +func toAdminAPIErr(ctx context.Context, err error) APIError { + return errorCodes.ToAPIErr(toAdminAPIErrCode(ctx, err)) +} + // RemoveUser - DELETE /minio/admin/v1/remove-user?accessKey= func (a adminAPIHandlers) RemoveUser(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "RemoveUser") - // Get current object layer instance. - objectAPI := newObjectLayerFn() + objectAPI := validateAdminReq(ctx, w, r) if objectAPI == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) return } // Deny if WORM is enabled if globalWORMEnabled { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } vars := mux.Vars(r) accessKey := vars["accessKey"] if err := globalIAMSys.DeleteUser(accessKey); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) } } @@ -1018,36 +949,27 @@ func (a adminAPIHandlers) RemoveUser(w http.ResponseWriter, r *http.Request) { func (a adminAPIHandlers) ListUsers(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ListUsers") - // Get current object layer instance. - objectAPI := newObjectLayerFn() + objectAPI := validateAdminReq(ctx, w, r) if objectAPI == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) return } allCredentials, err := globalIAMSys.ListUsers() if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } data, err := json.Marshal(allCredentials) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } password := globalServerConfig.GetCredential().SecretKey econfigData, err := madmin.EncryptData(password, data) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1058,28 +980,14 @@ func (a adminAPIHandlers) ListUsers(w http.ResponseWriter, r *http.Request) { func (a adminAPIHandlers) SetUserStatus(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "SetUserStatus") - if globalNotificationSys == nil || globalIAMSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Get current object layer instance. - objectAPI := newObjectLayerFn() + objectAPI := validateAdminReq(ctx, w, r) if objectAPI == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) return } // Deny if WORM is enabled if globalWORMEnabled { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } @@ -1089,12 +997,12 @@ func (a adminAPIHandlers) SetUserStatus(w http.ResponseWriter, r *http.Request) // Custom IAM policies not allowed for admin user. if accessKey == globalServerConfig.GetCredential().AccessKey { - writeErrorResponseJSON(w, ErrInvalidRequest, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) return } if err := globalIAMSys.SetUserStatus(accessKey, madmin.AccountStatus(status)); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1111,23 +1019,14 @@ func (a adminAPIHandlers) SetUserStatus(w http.ResponseWriter, r *http.Request) func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "AddUser") - // Get current object layer instance. - objectAPI := newObjectLayerFn() - if objectAPI == nil || globalNotificationSys == nil || globalIAMSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } // Deny if WORM is enabled if globalWORMEnabled { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } @@ -1136,13 +1035,13 @@ func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) { // Custom IAM policies not allowed for admin user. if accessKey == globalServerConfig.GetCredential().AccessKey { - writeErrorResponseJSON(w, ErrAddUserInvalidArgument, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAddUserInvalidArgument), r.URL) return } if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { // More than maxConfigSize bytes were available - writeErrorResponseJSON(w, ErrAdminConfigTooLarge, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) return } @@ -1150,19 +1049,19 @@ func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) { configBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) if err != nil { logger.LogIf(ctx, err) - writeErrorResponseJSON(w, ErrAdminConfigBadJSON, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) return } var uinfo madmin.UserInfo if err = json.Unmarshal(configBytes, &uinfo); err != nil { logger.LogIf(ctx, err) - writeErrorResponseJSON(w, ErrAdminConfigBadJSON, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) return } if err = globalIAMSys.SetUser(accessKey, uinfo); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1179,28 +1078,19 @@ func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) { func (a adminAPIHandlers) ListCannedPolicies(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ListCannedPolicies") - // Get current object layer instance. - objectAPI := newObjectLayerFn() - if objectAPI == nil || globalIAMSys == nil || globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } policies, err := globalIAMSys.ListCannedPolicies() if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } if err = json.NewEncoder(w).Encode(policies); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1211,31 +1101,22 @@ func (a adminAPIHandlers) ListCannedPolicies(w http.ResponseWriter, r *http.Requ func (a adminAPIHandlers) RemoveCannedPolicy(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "RemoveCannedPolicy") - // Get current object layer instance. - objectAPI := newObjectLayerFn() - if objectAPI == nil || globalIAMSys == nil || globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } vars := mux.Vars(r) policyName := vars["name"] - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) - return - } - // Deny if WORM is enabled if globalWORMEnabled { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } if err := globalIAMSys.DeleteCannedPolicy(policyName); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1252,55 +1133,46 @@ func (a adminAPIHandlers) RemoveCannedPolicy(w http.ResponseWriter, r *http.Requ func (a adminAPIHandlers) AddCannedPolicy(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "AddCannedPolicy") - // Get current object layer instance. - objectAPI := newObjectLayerFn() - if objectAPI == nil || globalIAMSys == nil || globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } vars := mux.Vars(r) policyName := vars["name"] - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) - return - } - // Deny if WORM is enabled if globalWORMEnabled { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } // Error out if Content-Length is missing. if r.ContentLength <= 0 { - writeErrorResponseJSON(w, ErrMissingContentLength, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL) return } // Error out if Content-Length is beyond allowed size. if r.ContentLength > maxBucketPolicySize { - writeErrorResponseJSON(w, ErrEntityTooLarge, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrEntityTooLarge), r.URL) return } iamPolicy, err := iampolicy.ParseConfig(io.LimitReader(r.Body, r.ContentLength)) if err != nil { - writeErrorResponseJSON(w, ErrMalformedPolicy, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMalformedPolicy), r.URL) return } // Version in policy must not be empty if iamPolicy.Version == "" { - writeErrorResponseJSON(w, ErrMalformedPolicy, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMalformedPolicy), r.URL) return } if err = globalIAMSys.SetCannedPolicy(policyName, *iamPolicy); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1317,10 +1189,8 @@ func (a adminAPIHandlers) AddCannedPolicy(w http.ResponseWriter, r *http.Request func (a adminAPIHandlers) SetUserPolicy(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "SetUserPolicy") - // Get current object layer instance. - objectAPI := newObjectLayerFn() - if objectAPI == nil || globalIAMSys == nil || globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } @@ -1328,27 +1198,20 @@ func (a adminAPIHandlers) SetUserPolicy(w http.ResponseWriter, r *http.Request) accessKey := vars["accessKey"] policyName := vars["name"] - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) - return - } - // Deny if WORM is enabled if globalWORMEnabled { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } // Custom IAM policies not allowed for admin user. if accessKey == globalServerConfig.GetCredential().AccessKey { - writeErrorResponseJSON(w, ErrInvalidRequest, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) return } if err := globalIAMSys.SetUserPolicy(accessKey, policyName); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) } // Notify all other Minio peers to reload users @@ -1364,29 +1227,20 @@ func (a adminAPIHandlers) SetUserPolicy(w http.ResponseWriter, r *http.Request) func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "SetConfigHandler") - // Get current object layer instance. - objectAPI := newObjectLayerFn() - if objectAPI == nil || globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) - return - } - - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } // Deny if WORM is enabled if globalWORMEnabled { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { // More than maxConfigSize bytes were available - writeErrorResponseJSON(w, ErrAdminConfigTooLarge, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) return } @@ -1394,7 +1248,7 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques configBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) if err != nil { logger.LogIf(ctx, err) - writeErrorResponseJSON(w, ErrAdminConfigBadJSON, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) return } @@ -1402,40 +1256,38 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques // client has not sent JSON objects with duplicate keys. if err = quick.CheckDuplicateKeys(string(configBytes)); err != nil { logger.LogIf(ctx, err) - writeErrorResponseJSON(w, ErrAdminConfigBadJSON, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) return } var config serverConfig if err = json.Unmarshal(configBytes, &config); err != nil { logger.LogIf(ctx, err) - writeCustomErrorResponseJSON(w, ErrAdminConfigBadJSON, err.Error(), r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } // If credentials for the server are provided via environment, // then credentials in the provided configuration must match. if globalIsEnvCreds { - creds := globalServerConfig.GetCredential() - if config.Credential.AccessKey != creds.AccessKey || - config.Credential.SecretKey != creds.SecretKey { - writeErrorResponseJSON(w, ErrAdminCredentialsMismatch, r.URL) + if !globalServerConfig.GetCredential().Equal(config.Credential) { + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminCredentialsMismatch), r.URL) return } } if err = config.Validate(); err != nil { - writeCustomErrorResponseJSON(w, ErrAdminConfigBadJSON, err.Error(), r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } if err = config.TestNotificationTargets(); err != nil { - writeCustomErrorResponseJSON(w, ErrAdminConfigBadJSON, err.Error(), r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } if err = saveServerConfig(ctx, objectAPI, &config); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1463,37 +1315,28 @@ func convertValueType(elem []byte, jsonType gjson.Type) (interface{}, error) { func (a adminAPIHandlers) SetConfigKeysHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "SetConfigKeysHandler") - // Get current object layer instance. - objectAPI := newObjectLayerFn() + objectAPI := validateAdminReq(ctx, w, r) if objectAPI == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) return } // Deny if WORM is enabled if globalWORMEnabled { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) - return - } - - // Validate request signature. - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } // Load config configStruct, err := readServerConfig(ctx, objectAPI) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } // Convert config to json bytes configBytes, err := json.Marshal(configStruct) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1510,22 +1353,24 @@ func (a adminAPIHandlers) SetConfigKeysHandler(w http.ResponseWriter, r *http.Re reqInfo := (&logger.ReqInfo{}).AppendTags("key", k) ctx = logger.SetReqInfo(ctx, reqInfo) logger.LogIf(ctx, dErr) - writeErrorResponseJSON(w, ErrAdminConfigBadJSON, r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), dErr.Error(), r.URL) return } + elem, dErr := madmin.DecryptData(password, bytes.NewBuffer([]byte(encryptedElem))) if dErr != nil { logger.LogIf(ctx, dErr) - writeErrorResponseJSON(w, ErrAdminConfigBadJSON, r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), dErr.Error(), r.URL) return } + // Calculate the type of the current key from the // original config json jsonFieldType := gjson.Get(configStr, k).Type // Convert passed value to json filed type val, cErr := convertValueType(elem, jsonFieldType) if cErr != nil { - writeCustomErrorResponseJSON(w, ErrAdminConfigBadJSON, cErr.Error(), r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), cErr.Error(), r.URL) return } // Set the key/value in the new json document @@ -1539,33 +1384,31 @@ func (a adminAPIHandlers) SetConfigKeysHandler(w http.ResponseWriter, r *http.Re // Validate config var config serverConfig if err = json.Unmarshal(configBytes, &config); err != nil { - writeCustomErrorResponseJSON(w, ErrAdminConfigBadJSON, err.Error(), r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } if err = config.Validate(); err != nil { - writeCustomErrorResponseJSON(w, ErrAdminConfigBadJSON, err.Error(), r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } if err = config.TestNotificationTargets(); err != nil { - writeCustomErrorResponseJSON(w, ErrAdminConfigBadJSON, err.Error(), r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } // If credentials for the server are provided via environment, // then credentials in the provided configuration must match. if globalIsEnvCreds { - creds := globalServerConfig.GetCredential() - if config.Credential.AccessKey != creds.AccessKey || - config.Credential.SecretKey != creds.SecretKey { - writeErrorResponseJSON(w, ErrAdminCredentialsMismatch, r.URL) + if !globalServerConfig.GetCredential().Equal(config.Credential) { + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminCredentialsMismatch), r.URL) return } } if err = saveServerConfig(ctx, objectAPI, &config); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1581,30 +1424,21 @@ func (a adminAPIHandlers) UpdateAdminCredentialsHandler(w http.ResponseWriter, ctx := newContext(r, w, "UpdateCredentialsHandler") - // Get current object layer instance. - objectAPI := newObjectLayerFn() - if objectAPI == nil || globalNotificationSys == nil { - writeErrorResponseJSON(w, ErrServerNotInitialized, r.URL) + objectAPI := validateAdminReq(ctx, w, r) + if objectAPI == nil { return } // Avoid setting new credentials when they are already passed // by the environment. Deny if WORM is enabled. if globalIsEnvCreds || globalWORMEnabled { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) - return - } - - // Authenticate request - adminAPIErr := checkAdminRequestAuthType(ctx, r, "") - if adminAPIErr != ErrNone { - writeErrorResponseJSON(w, adminAPIErr, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { // More than maxConfigSize bytes were available - writeErrorResponseJSON(w, ErrAdminConfigTooLarge, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) return } @@ -1612,7 +1446,7 @@ func (a adminAPIHandlers) UpdateAdminCredentialsHandler(w http.ResponseWriter, configBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) if err != nil { logger.LogIf(ctx, err) - writeErrorResponseJSON(w, ErrAdminConfigBadJSON, r.URL) + writeCustomErrorResponseJSON(w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) return } @@ -1620,13 +1454,13 @@ func (a adminAPIHandlers) UpdateAdminCredentialsHandler(w http.ResponseWriter, var req madmin.SetCredsReq if err = json.Unmarshal(configBytes, &req); err != nil { logger.LogIf(ctx, err) - writeErrorResponseJSON(w, ErrRequestBodyParse, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrRequestBodyParse), r.URL) return } creds, err := auth.CreateCredentials(req.AccessKey, req.SecretKey) if err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } @@ -1641,7 +1475,7 @@ func (a adminAPIHandlers) UpdateAdminCredentialsHandler(w http.ResponseWriter, globalActiveCred = creds if err = saveServerConfig(ctx, objectAPI, globalServerConfig); err != nil { - writeErrorResponseJSON(w, toAdminAPIErrCode(ctx, err), r.URL) + writeErrorResponseJSON(w, toAdminAPIErr(ctx, err), r.URL) return } diff --git a/cmd/admin-handlers_test.go b/cmd/admin-handlers_test.go index e4249851f..9a60459ab 100644 --- a/cmd/admin-handlers_test.go +++ b/cmd/admin-handlers_test.go @@ -270,10 +270,16 @@ func prepareAdminXLTestBed() (*adminXLTestBed, error) { // Init global heal state initAllHealState(globalIsXL) - globalNotificationSys = NewNotificationSys(globalServerConfig, globalEndpoints) + globalConfigSys = NewConfigSys() + + globalIAMSys = NewIAMSys() + globalIAMSys.Init(objLayer) - // Create new policy system. globalPolicySys = NewPolicySys() + globalPolicySys.Init(objLayer) + + globalNotificationSys = NewNotificationSys(globalServerConfig, globalEndpoints) + globalNotificationSys.Init(objLayer) // Setup admin mgmt REST API handlers. adminRouter := mux.NewRouter() @@ -842,8 +848,8 @@ func TestAdminServerInfo(t *testing.T) { } } -// TestToAdminAPIErr - test for toAdminAPIErr helper function. -func TestToAdminAPIErr(t *testing.T) { +// TestToAdminAPIErrCode - test for toAdminAPIErrCode helper function. +func TestToAdminAPIErrCode(t *testing.T) { testCases := []struct { err error expectedAPIErr APIErrorCode diff --git a/cmd/admin-heal-ops.go b/cmd/admin-heal-ops.go index 3db347481..b083f84ca 100644 --- a/cmd/admin-heal-ops.go +++ b/cmd/admin-heal-ops.go @@ -63,8 +63,7 @@ var ( errHealStopSignalled = fmt.Errorf("heal stop signaled") errFnHealFromAPIErr = func(ctx context.Context, err error) error { - errCode := toAPIErrorCode(ctx, err) - apiErr := getAPIError(errCode) + apiErr := toAPIError(ctx, err) return fmt.Errorf("Heal internal error: %s: %s", apiErr.Code, apiErr.Description) } @@ -150,7 +149,7 @@ func (ahs *allHealState) getHealSequence(path string) (h *healSequence, exists b return h, exists } -func (ahs *allHealState) stopHealSequence(path string) ([]byte, APIErrorCode) { +func (ahs *allHealState) stopHealSequence(path string) ([]byte, APIError) { var hsp madmin.HealStopSuccess he, exists := ahs.getHealSequence(path) if !exists { @@ -176,7 +175,7 @@ func (ahs *allHealState) stopHealSequence(path string) ([]byte, APIErrorCode) { } b, err := json.Marshal(&hsp) - return b, toAdminAPIErrCode(context.Background(), err) + return b, toAdminAPIErr(context.Background(), err) } // LaunchNewHealSequence - launches a background routine that performs @@ -190,7 +189,7 @@ func (ahs *allHealState) stopHealSequence(path string) ([]byte, APIErrorCode) { // background routine to clean up heal results after the // aforementioned duration. func (ahs *allHealState) LaunchNewHealSequence(h *healSequence) ( - respBytes []byte, errCode APIErrorCode, errMsg string) { + respBytes []byte, apiErr APIError, errMsg string) { existsAndLive := false he, exists := ahs.getHealSequence(h.path) @@ -213,8 +212,7 @@ func (ahs *allHealState) LaunchNewHealSequence(h *healSequence) ( "(use force-start option to stop and start afresh). " + fmt.Sprintf("The heal was started by IP %s at %s, token is %s", h.clientAddress, h.startTime.Format(http.TimeFormat), h.clientToken) - - return nil, ErrHealAlreadyRunning, errMsg + return nil, errorCodes.ToAPIErr(ErrHealAlreadyRunning), errMsg } } @@ -229,7 +227,7 @@ func (ahs *allHealState) LaunchNewHealSequence(h *healSequence) ( errMsg = "The provided heal sequence path overlaps with an existing " + fmt.Sprintf("heal path: %s", k) - return nil, ErrHealOverlappingPaths, errMsg + return nil, errorCodes.ToAPIErr(ErrHealOverlappingPaths), errMsg } } @@ -246,9 +244,9 @@ func (ahs *allHealState) LaunchNewHealSequence(h *healSequence) ( }) if err != nil { logger.LogIf(h.ctx, err) - return nil, ErrInternalError, "" + return nil, toAPIError(h.ctx, err), "" } - return b, ErrNone, "" + return b, noError, "" } // PopHealStatusJSON - Called by heal-status API. It fetches the heal diff --git a/cmd/api-errors.go b/cmd/api-errors.go index d1161e36e..35e0476cc 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -22,6 +22,11 @@ import ( "fmt" "net/http" + "github.com/Azure/azure-sdk-for-go/storage" + "github.com/aliyun/aliyun-oss-go-sdk/oss" + "google.golang.org/api/googleapi" + + minio "github.com/minio/minio-go" "github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" @@ -212,7 +217,7 @@ const ( ErrHealOverlappingPaths ErrIncorrectContinuationToken - //S3 Select Errors + // S3 Select Errors ErrEmptyRequestBody ErrUnsupportedFunction ErrInvalidExpressionType @@ -304,9 +309,19 @@ const ( ErrAddUserInvalidArgument ) +type errorCodeMap map[APIErrorCode]APIError + +func (e errorCodeMap) ToAPIErr(errCode APIErrorCode) APIError { + apiErr, ok := e[errCode] + if !ok { + return e[ErrInternalError] + } + return apiErr +} + // error code to APIError structure, these fields carry respective // descriptions for all the error responses. -var errorCodeResponse = map[APIErrorCode]APIError{ +var errorCodes = errorCodeMap{ ErrInvalidCopyDest: { Code: "InvalidRequest", Description: "This copy request is illegal because it is trying to copy an object to itself without changing the object's metadata, storage class, website redirect location or encryption attributes.", @@ -1636,12 +1651,66 @@ func toAPIErrorCode(ctx context.Context, err error) (apiErr APIErrorCode) { return apiErr } +var noError = APIError{} + +// toAPIError - Converts embedded errors. Convenience +// function written to handle all cases where we have known types of +// errors returned by underlying layers. +func toAPIError(ctx context.Context, err error) APIError { + if err == nil { + return noError + } + + var apiErr = errorCodes.ToAPIErr(toAPIErrorCode(ctx, err)) + if apiErr.Code == "InternalError" { + // If we see an internal error try to interpret + // any underlying errors if possible depending on + // their internal error types. This code is only + // useful with gateway implementations. + switch e := err.(type) { + case minio.ErrorResponse: + apiErr = APIError{ + Code: e.Code, + Description: e.Message, + HTTPStatusCode: e.StatusCode, + } + case *googleapi.Error: + apiErr = APIError{ + Code: "XGCSInternalError", + Description: e.Message, + HTTPStatusCode: e.Code, + } + // GCS may send multiple errors, just pick the first one + // since S3 only sends one Error XML response. + if len(e.Errors) >= 1 { + apiErr.Code = e.Errors[0].Reason + + } + case storage.AzureStorageServiceError: + apiErr = APIError{ + Code: e.Code, + Description: e.Message, + HTTPStatusCode: e.StatusCode, + } + case oss.ServiceError: + apiErr = APIError{ + Code: e.Code, + Description: e.Message, + HTTPStatusCode: e.StatusCode, + } + // Add more Gateway SDKs here if any in future. + } + } + + return apiErr +} + // getAPIError provides API Error for input API error code. func getAPIError(code APIErrorCode) APIError { - if apiErr, ok := errorCodeResponse[code]; ok { + if apiErr, ok := errorCodes[code]; ok { return apiErr } - return errorCodeResponse[ErrInternalError] + return errorCodes.ToAPIErr(ErrInternalError) } // getErrorResponse gets in standard error and resource value and diff --git a/cmd/api-errors_test.go b/cmd/api-errors_test.go index e2bfd283d..d959e3006 100644 --- a/cmd/api-errors_test.go +++ b/cmd/api-errors_test.go @@ -25,7 +25,7 @@ import ( "github.com/minio/minio/pkg/hash" ) -var toAPIErrorCodeTests = []struct { +var toAPIErrorTests = []struct { err error errCode APIErrorCode }{ @@ -66,7 +66,7 @@ var toAPIErrorCodeTests = []struct { func TestAPIErrCode(t *testing.T) { ctx := context.Background() - for i, testCase := range toAPIErrorCodeTests { + for i, testCase := range toAPIErrorTests { errCode := toAPIErrorCode(ctx, testCase.err) if errCode != testCase.errCode { t.Errorf("Test %d: Expected error code %d, got %d", i+1, testCase.errCode, errCode) diff --git a/cmd/api-response-multipart.go b/cmd/api-response-multipart.go index dcb25273a..edb0b0cfe 100644 --- a/cmd/api-response-multipart.go +++ b/cmd/api-response-multipart.go @@ -45,7 +45,7 @@ type completeMultipartAPIError struct { // of this function. func writePartSmallErrorResponse(w http.ResponseWriter, r *http.Request, err PartTooSmall) { - apiError := getAPIError(toAPIErrorCode(context.Background(), err)) + apiError := toAPIError(context.Background(), err) // Generate complete multipart error response. errorResponse := getAPIErrorResponse(apiError, r.URL.Path, w.Header().Get(responseRequestIDKey)) cmpErrResp := completeMultipartAPIError{err.PartSize, int64(5242880), err.PartNumber, err.PartETag, errorResponse} diff --git a/cmd/api-response.go b/cmd/api-response.go index 2977ffc37..b2c76fcb5 100644 --- a/cmd/api-response.go +++ b/cmd/api-response.go @@ -568,13 +568,13 @@ func writeSuccessResponseHeadersOnly(w http.ResponseWriter) { } // writeErrorRespone writes error headers -func writeErrorResponse(w http.ResponseWriter, errorCode APIErrorCode, reqURL *url.URL, browser bool) { - switch errorCode { - case ErrSlowDown, ErrServerNotInitialized, ErrReadQuorum, ErrWriteQuorum: +func writeErrorResponse(w http.ResponseWriter, err APIError, reqURL *url.URL, browser bool) { + switch err.Code { + case "SlowDown", "XMinioServerNotInitialized", "XMinioReadQuorum", "XMinioWriteQuorum": // Set retry-after header to indicate user-agents to retry request after 120secs. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After w.Header().Set("Retry-After", "120") - case ErrAccessDenied: + case "AccessDenied": // The request is from browser and also if browser // is enabled we need to redirect. if browser && globalIsBrowserEnabled { @@ -584,42 +584,38 @@ func writeErrorResponse(w http.ResponseWriter, errorCode APIErrorCode, reqURL *u } } - apiError := getAPIError(errorCode) // Generate error response. - errorResponse := getAPIErrorResponse(apiError, reqURL.Path, w.Header().Get(responseRequestIDKey)) + errorResponse := getAPIErrorResponse(err, reqURL.Path, w.Header().Get(responseRequestIDKey)) encodedErrorResponse := encodeResponse(errorResponse) - writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeXML) + writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeXML) } -func writeErrorResponseHeadersOnly(w http.ResponseWriter, errorCode APIErrorCode) { - apiError := getAPIError(errorCode) - writeResponse(w, apiError.HTTPStatusCode, nil, mimeNone) +func writeErrorResponseHeadersOnly(w http.ResponseWriter, err APIError) { + writeResponse(w, err.HTTPStatusCode, nil, mimeNone) } // writeErrorResponseJSON - writes error response in JSON format; // useful for admin APIs. -func writeErrorResponseJSON(w http.ResponseWriter, errorCode APIErrorCode, reqURL *url.URL) { - apiError := getAPIError(errorCode) +func writeErrorResponseJSON(w http.ResponseWriter, err APIError, reqURL *url.URL) { // Generate error response. - errorResponse := getAPIErrorResponse(apiError, reqURL.Path, w.Header().Get(responseRequestIDKey)) + errorResponse := getAPIErrorResponse(err, reqURL.Path, w.Header().Get(responseRequestIDKey)) encodedErrorResponse := encodeResponseJSON(errorResponse) - writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeJSON) + writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeJSON) } // writeCustomErrorResponseJSON - similar to writeErrorResponseJSON, // but accepts the error message directly (this allows messages to be // dynamically generated.) -func writeCustomErrorResponseJSON(w http.ResponseWriter, errorCode APIErrorCode, +func writeCustomErrorResponseJSON(w http.ResponseWriter, err APIError, errBody string, reqURL *url.URL) { - apiError := getAPIError(errorCode) errorResponse := APIErrorResponse{ - Code: apiError.Code, + Code: err.Code, Message: errBody, Resource: reqURL.Path, RequestID: w.Header().Get(responseRequestIDKey), HostID: "3L137", } encodedErrorResponse := encodeResponseJSON(errorResponse) - writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeJSON) + writeResponse(w, err.HTTPStatusCode, encodedErrorResponse, mimeJSON) } diff --git a/cmd/auth-handler.go b/cmd/auth-handler.go index 5859ca678..f7ffe7875 100644 --- a/cmd/auth-handler.go +++ b/cmd/auth-handler.go @@ -416,7 +416,7 @@ func (a authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { a.handler.ServeHTTP(w, r) return } - writeErrorResponse(w, ErrSignatureVersionNotSupported, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrSignatureVersionNotSupported), r.URL, guessIsBrowserReq(r)) } // isPutAllowed - check if PUT operation is allowed on the resource, this diff --git a/cmd/auth-handler_test.go b/cmd/auth-handler_test.go index a2dc0cec8..bf977e3ee 100644 --- a/cmd/auth-handler_test.go +++ b/cmd/auth-handler_test.go @@ -383,7 +383,7 @@ func TestIsReqAuthenticated(t *testing.T) { for i, testCase := range testCases { if s3Error := isReqAuthenticated(ctx, testCase.req, globalServerConfig.GetRegion()); s3Error != testCase.s3Error { if _, err := ioutil.ReadAll(testCase.req.Body); toAPIErrorCode(ctx, err) != testCase.s3Error { - t.Fatalf("Test %d: Unexpected S3 error: want %d - got %d (got after reading request %d)", i, testCase.s3Error, s3Error, toAPIErrorCode(ctx, err)) + t.Fatalf("Test %d: Unexpected S3 error: want %d - got %d (got after reading request %s)", i, testCase.s3Error, s3Error, toAPIError(ctx, err).Code) } } } diff --git a/cmd/bucket-handlers-listobjects.go b/cmd/bucket-handlers-listobjects.go index f90258ba3..afdf48cbf 100644 --- a/cmd/bucket-handlers-listobjects.go +++ b/cmd/bucket-handlers-listobjects.go @@ -66,12 +66,12 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.ListBucketAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -79,18 +79,18 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http // Extract all the listObjectsV2 query params to their native values. prefix, token, startAfter, delimiter, fetchOwner, maxKeys, _, errCode := getListObjectsV2Args(urlValues) - if errCode != ErrNone { - writeErrorResponse(w, errCode, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(errCode), r.URL, guessIsBrowserReq(r)) return } // Validate the query params before beginning to serve the request. // fetch-owner is not validated since it is a boolean if s3Error := validateListObjectsArgs(prefix, token, delimiter, maxKeys); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } + listObjectsV2 := objectAPI.ListObjectsV2 if api.CacheAPI() != nil { listObjectsV2 = api.CacheAPI().ListObjectsV2 @@ -100,7 +100,7 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http // marshaled into S3 compatible XML header. listObjectsV2Info, err := listObjectsV2(ctx, bucket, prefix, token, delimiter, maxKeys, fetchOwner, startAfter) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -110,7 +110,7 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http // Read the decompressed size from the meta.json. actualSize = listObjectsV2Info.Objects[i].GetActualSize() if actualSize < 0 { - writeErrorResponse(w, ErrInvalidDecompressedSize, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidDecompressedSize), r.URL, guessIsBrowserReq(r)) return } // Set the info.Size to the actualSize. @@ -119,7 +119,7 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http listObjectsV2Info.Objects[i].ETag = getDecryptedETag(r.Header, listObjectsV2Info.Objects[i], false) listObjectsV2Info.Objects[i].Size, err = listObjectsV2Info.Objects[i].DecryptedSize() if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -148,42 +148,39 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.ListBucketAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Extract all the litsObjectsV1 query params to their native values. prefix, marker, delimiter, maxKeys, _, s3Error := getListObjectsV1Args(r.URL.Query()) if s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } - // Validate the maxKeys lowerbound. When maxKeys > 1000, S3 returns 1000 but - // does not throw an error. - if maxKeys < 0 { - writeErrorResponse(w, ErrInvalidMaxKeys, r.URL, guessIsBrowserReq(r)) - return - } // Validate all the query params before beginning to serve the request. + // Validate all the query params before beginning to serve the request. if s3Error := validateListObjectsArgs(prefix, marker, delimiter, maxKeys); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } + listObjects := objectAPI.ListObjects if api.CacheAPI() != nil { listObjects = api.CacheAPI().ListObjects } + // Inititate a list objects operation based on the input params. // On success would return back ListObjectsInfo object to be // marshaled into S3 compatible XML header. listObjectsInfo, err := listObjects(ctx, bucket, prefix, marker, delimiter, maxKeys) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -193,7 +190,7 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http // Read the decompressed size from the meta.json. actualSize = listObjectsInfo.Objects[i].GetActualSize() if actualSize < 0 { - writeErrorResponse(w, ErrInvalidDecompressedSize, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidDecompressedSize), r.URL, guessIsBrowserReq(r)) return } // Set the info.Size to the actualSize. @@ -202,7 +199,7 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http listObjectsInfo.Objects[i].ETag = getDecryptedETag(r.Header, listObjectsInfo.Objects[i], false) listObjectsInfo.Objects[i].Size, err = listObjectsInfo.Objects[i].DecryptedSize() if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 6f97cfa2c..39af10edf 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -96,12 +96,12 @@ func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r * objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketLocationAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -110,7 +110,7 @@ func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r * getBucketInfo = api.CacheAPI().GetBucketInfo } if _, err := getBucketInfo(ctx, bucket); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -146,35 +146,37 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.ListBucketMultipartUploadsAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } - prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, _, s3Error := getBucketMultipartResources(r.URL.Query()) - if s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, _, errCode := getBucketMultipartResources(r.URL.Query()) + if errCode != ErrNone { + writeErrorResponse(w, errorCodes.ToAPIErr(errCode), r.URL, guessIsBrowserReq(r)) return } + if maxUploads < 0 { - writeErrorResponse(w, ErrInvalidMaxUploads, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidMaxUploads), r.URL, guessIsBrowserReq(r)) return } + if keyMarker != "" { // Marker not common with prefix is not implemented. if !hasPrefix(keyMarker, prefix) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } } listMultipartsInfo, err := objectAPI.ListMultipartUploads(ctx, bucket, prefix, keyMarker, uploadIDMarker, delimiter, maxUploads) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // generate response @@ -196,25 +198,26 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } - listBuckets := objectAPI.ListBuckets + listBuckets := objectAPI.ListBuckets if api.CacheAPI() != nil { listBuckets = api.CacheAPI().ListBuckets } if s3Error := checkRequestAuthType(ctx, r, policy.ListAllMyBucketsAction, "", ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } + // If etcd, dns federation configured list buckets from etcd. var bucketsInfo []BucketInfo if globalDNSConfig != nil { dnsBuckets, err := globalDNSConfig.List() if err != nil && err != dns.ErrNoEntriesFound { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } bucketSet := set.NewStringSet() @@ -233,7 +236,7 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R var err error bucketsInfo, err = listBuckets(ctx) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -257,7 +260,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } @@ -266,7 +269,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, // In the event access is denied, a 200 response should still be returned // http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html if s3Error != ErrAccessDenied { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } } @@ -274,14 +277,14 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, // Content-Length is required and should be non-zero // http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html if r.ContentLength <= 0 { - writeErrorResponse(w, ErrMissingContentLength, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) return } // Content-Md5 is requied should be set // http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html if _, ok := r.Header["Content-Md5"]; !ok { - writeErrorResponse(w, ErrMissingContentMD5, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMissingContentMD5), r.URL, guessIsBrowserReq(r)) return } @@ -297,7 +300,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, // Read incoming body XML bytes. if _, err := io.ReadFull(r.Body, deleteXMLBytes); err != nil { logger.LogIf(ctx, err) - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAdminAPIErr(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -305,7 +308,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, deleteObjects := &DeleteObjectsRequest{} if err := xml.Unmarshal(deleteXMLBytes, deleteObjects); err != nil { logger.LogIf(ctx, err) - writeErrorResponse(w, ErrMalformedXML, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedXML), r.URL, guessIsBrowserReq(r)) return } @@ -313,7 +316,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, if globalWORMEnabled { // Not required to check whether given objects exist or not, because // DeleteMultipleObject is always successful irrespective of object existence. - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } @@ -352,10 +355,11 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, deletedObjects = append(deletedObjects, object) continue } + apiErr := toAPIError(ctx, err) // Error during delete should be collected separately. deleteErrors = append(deleteErrors, DeleteError{ - Code: errorCodeResponse[toAPIErrorCode(ctx, err)].Code, - Message: errorCodeResponse[toAPIErrorCode(ctx, err)].Description, + Code: apiErr.Code, + Message: apiErr.Description, Key: object.ObjectName, }) } @@ -401,7 +405,7 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } @@ -409,21 +413,21 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req bucket := vars["bucket"] if s3Error := checkRequestAuthType(ctx, r, policy.CreateBucketAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Parse incoming location constraint. location, s3Error := parseLocationConstraint(r) if s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Validate if location sent by the client is valid, reject // requests which do not follow valid region requirements. if !isValidLocation(location) { - writeErrorResponse(w, ErrInvalidRegion, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidRegion), r.URL, guessIsBrowserReq(r)) return } @@ -432,12 +436,12 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req if err == dns.ErrNoEntriesFound { // Proceed to creating a bucket. if err = objectAPI.MakeBucketWithLocation(ctx, bucket, location); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } if err = globalDNSConfig.Put(bucket); err != nil { objectAPI.DeleteBucket(ctx, bucket) - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -447,18 +451,18 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req writeSuccessResponseHeadersOnly(w) return } - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } - writeErrorResponse(w, ErrBucketAlreadyOwnedByYou, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrBucketAlreadyOwnedByYou), r.URL, guessIsBrowserReq(r)) return } // Proceed to creating a bucket. err := objectAPI.MakeBucketWithLocation(ctx, bucket, location) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -479,33 +483,36 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } + if crypto.S3KMS.IsRequested(r.Header) { // SSE-KMS is not supported - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } + if !api.EncryptionEnabled() && hasServerSideEncryptionHeader(r.Header) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } + bucket := mux.Vars(r)["bucket"] // Require Content-Length to be set in the request size := r.ContentLength if size < 0 { - writeErrorResponse(w, ErrMissingContentLength, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) return } resource, err := getResource(r.URL.Path, r.Host, globalDomainName) if err != nil { - writeErrorResponse(w, ErrInvalidRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL, guessIsBrowserReq(r)) return } // Make sure that the URL does not contain object name. if bucket != filepath.Clean(resource[1:]) { - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } @@ -514,7 +521,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h reader, err := r.MultipartReader() if err != nil { logger.LogIf(ctx, err) - writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL, guessIsBrowserReq(r)) return } @@ -522,7 +529,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h form, err := reader.ReadForm(maxFormMemory) if err != nil { logger.LogIf(ctx, err) - writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL, guessIsBrowserReq(r)) return } @@ -533,13 +540,13 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h fileBody, fileName, fileSize, formValues, err := extractPostPolicyFormValues(ctx, form) if err != nil { logger.LogIf(ctx, err) - writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL, guessIsBrowserReq(r)) return } // Check if file is provided, error out otherwise. if fileBody == nil { - writeErrorResponse(w, ErrPOSTFileRequired, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrPOSTFileRequired), r.URL, guessIsBrowserReq(r)) return } @@ -561,21 +568,21 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h if successRedirect != "" { redirectURL, err = url.Parse(successRedirect) if err != nil { - writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL, guessIsBrowserReq(r)) return } } // Verify policy signature. - apiErr := doesPolicySignatureMatch(formValues) - if apiErr != ErrNone { - writeErrorResponse(w, apiErr, r.URL, guessIsBrowserReq(r)) + errCode := doesPolicySignatureMatch(formValues) + if errCode != ErrNone { + writeErrorResponse(w, errorCodes.ToAPIErr(errCode), r.URL, guessIsBrowserReq(r)) return } policyBytes, err := base64.StdEncoding.DecodeString(formValues.Get("Policy")) if err != nil { - writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL, guessIsBrowserReq(r)) return } @@ -583,13 +590,13 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h if len(policyBytes) > 0 { postPolicyForm, err := parsePostPolicyForm(string(policyBytes)) if err != nil { - writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedPOSTRequest), r.URL, guessIsBrowserReq(r)) return } // Make sure formValues adhere to policy restrictions. - if apiErr = checkPostPolicy(formValues, postPolicyForm); apiErr != ErrNone { - writeErrorResponse(w, apiErr, r.URL, guessIsBrowserReq(r)) + if errCode = checkPostPolicy(formValues, postPolicyForm); errCode != ErrNone { + writeErrorResponse(w, errorCodes.ToAPIErr(errCode), r.URL, guessIsBrowserReq(r)) return } @@ -598,12 +605,12 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h lengthRange := postPolicyForm.Conditions.ContentLengthRange if lengthRange.Valid { if fileSize < lengthRange.Min { - writeErrorResponse(w, toAPIErrorCode(ctx, errDataTooSmall), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, errDataTooSmall), r.URL, guessIsBrowserReq(r)) return } if fileSize > lengthRange.Max || isMaxObjectSize(fileSize) { - writeErrorResponse(w, toAPIErrorCode(ctx, errDataTooLarge), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, errDataTooLarge), r.URL, guessIsBrowserReq(r)) return } } @@ -613,14 +620,14 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h metadata := make(map[string]string) err = extractMetadataFromMap(ctx, formValues, metadata) if err != nil { - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } hashReader, err := hash.NewReader(fileBody, fileSize, "", "", fileSize) if err != nil { logger.LogIf(ctx, err) - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } rawReader := hashReader @@ -635,7 +642,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h var opts ObjectOptions opts, err = putOpts(ctx, r, bucket, object, metadata) if err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } if objectAPI.IsEncryptionSupported() { @@ -645,19 +652,19 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h if crypto.SSEC.IsRequested(formValues) { key, err = ParseSSECustomerHeader(formValues) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } reader, objectEncryptionKey, err = newEncryptReader(hashReader, key, bucket, object, metadata, crypto.S3.IsRequested(formValues)) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } info := ObjectInfo{Size: fileSize} hashReader, err = hash.NewReader(reader, info.EncryptedSize(), "", "", fileSize) // do not try to verify encrypted content if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } pReader = NewPutObjReader(rawReader, hashReader, objectEncryptionKey) @@ -666,7 +673,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h objInfo, err := objectAPI.PutObject(ctx, bucket, object, pReader, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -732,12 +739,12 @@ func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Re objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponseHeadersOnly(w, ErrServerNotInitialized) + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrServerNotInitialized)) return } if s3Error := checkRequestAuthType(ctx, r, policy.ListBucketAction, bucket, ""); s3Error != ErrNone { - writeErrorResponseHeadersOnly(w, s3Error) + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(s3Error)) return } @@ -746,7 +753,7 @@ func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Re getBucketInfo = api.CacheAPI().GetBucketInfo } if _, err := getBucketInfo(ctx, bucket); err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } @@ -764,12 +771,12 @@ func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http. objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.DeleteBucketAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -779,7 +786,7 @@ func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http. } // Attempt to delete bucket. if err := deleteBucket(ctx, bucket); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -791,7 +798,7 @@ func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http. if err := globalDNSConfig.Delete(bucket); err != nil { // Deleting DNS entry failed, attempt to create the bucket again. objectAPI.MakeBucketWithLocation(ctx, bucket, "") - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } diff --git a/cmd/bucket-handlers_test.go b/cmd/bucket-handlers_test.go index 0beedf856..765dce76b 100644 --- a/cmd/bucket-handlers_test.go +++ b/cmd/bucket-handlers_test.go @@ -645,8 +645,8 @@ func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketNa getDeleteErrorList := func(objects []ObjectIdentifier) (deleteErrorList []DeleteError) { for _, obj := range objects { deleteErrorList = append(deleteErrorList, DeleteError{ - Code: errorCodeResponse[ErrAccessDenied].Code, - Message: errorCodeResponse[ErrAccessDenied].Description, + Code: errorCodes[ErrAccessDenied].Code, + Message: errorCodes[ErrAccessDenied].Description, Key: obj.ObjectName, }) } diff --git a/cmd/bucket-notification-handlers.go b/cmd/bucket-notification-handlers.go index 5a0014ee8..401b6ee37 100644 --- a/cmd/bucket-notification-handlers.go +++ b/cmd/bucket-notification-handlers.go @@ -51,23 +51,23 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if !objAPI.IsNotificationSupported() { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketNotificationAction, bucketName, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } _, err := objAPI.GetBucketInfo(ctx, bucketName) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -76,7 +76,7 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, if err != nil { // Ignore errNoSuchNotifications to comply with AWS S3. if err != errNoSuchNotifications { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -90,7 +90,7 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, notificationBytes, err := xml.Marshal(nConfig) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -106,12 +106,12 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if !objectAPI.IsNotificationSupported() { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } @@ -119,28 +119,28 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, bucketName := vars["bucket"] if s3Error := checkRequestAuthType(ctx, r, policy.PutBucketNotificationAction, bucketName, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } _, err := objectAPI.GetBucketInfo(ctx, bucketName) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // PutBucketNotification always needs a Content-Length. if r.ContentLength <= 0 { - writeErrorResponse(w, ErrMissingContentLength, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) return } var config *event.Config config, err = event.ParseConfig(io.LimitReader(r.Body, r.ContentLength), globalServerConfig.GetRegion(), globalNotificationSys.targetList) if err != nil { - apiErr := ErrMalformedXML + apiErr := errorCodes.ToAPIErr(ErrMalformedXML) if event.IsEventError(err) { - apiErr = toAPIErrorCode(ctx, err) + apiErr = toAPIError(ctx, err) } writeErrorResponse(w, apiErr, r.URL, guessIsBrowserReq(r)) @@ -148,7 +148,7 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, } if err = saveNotificationConfig(ctx, objectAPI, bucketName, config); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -169,23 +169,24 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit // Validate if bucket exists. objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } + if !objAPI.IsNotificationSupported() { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } if !objAPI.IsListenBucketSupported() { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } vars := mux.Vars(r) bucketName := vars["bucket"] if s3Error := checkRequestAuthType(ctx, r, policy.ListenBucketNotificationAction, bucketName, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -193,11 +194,13 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit var prefix string if len(values["prefix"]) > 1 { - writeErrorResponse(w, ErrFilterNamePrefix, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrFilterNamePrefix), r.URL, guessIsBrowserReq(r)) + return } + if len(values["prefix"]) == 1 { if err := event.ValidateFilterRuleValue(values["prefix"][0]); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -206,11 +209,13 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit var suffix string if len(values["suffix"]) > 1 { - writeErrorResponse(w, ErrFilterNameSuffix, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrFilterNameSuffix), r.URL, guessIsBrowserReq(r)) + return } + if len(values["suffix"]) == 1 { if err := event.ValidateFilterRuleValue(values["suffix"][0]); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -223,7 +228,7 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit for _, s := range values["events"] { eventName, err := event.ParseName(s) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -231,19 +236,19 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit } if _, err := objAPI.GetBucketInfo(ctx, bucketName); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } host, err := xnet.ParseHost(r.RemoteAddr) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } target, err := target.NewHTTPClientTarget(*host, w) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -251,7 +256,7 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit if err = globalNotificationSys.AddRemoteTarget(bucketName, target, rulesMap); err != nil { logger.GetReqInfo(ctx).AppendTags("target", target.ID().Name) - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } defer globalNotificationSys.RemoveRemoteTarget(bucketName, target.ID()) @@ -259,13 +264,13 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit thisAddr, err := xnet.ParseHost(GetLocalPeer(globalEndpoints)) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } if err = SaveListener(objAPI, bucketName, eventNames, pattern, target.ID(), *thisAddr); err != nil { logger.GetReqInfo(ctx).AppendTags("target", target.ID().Name) - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -275,7 +280,7 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit if err = RemoveListener(objAPI, bucketName, target.ID(), *thisAddr); err != nil { logger.GetReqInfo(ctx).AppendTags("target", target.ID().Name) - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } diff --git a/cmd/bucket-policy-handlers.go b/cmd/bucket-policy-handlers.go index fbf453fc1..ac8c59eba 100644 --- a/cmd/bucket-policy-handlers.go +++ b/cmd/bucket-policy-handlers.go @@ -44,7 +44,7 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } @@ -52,43 +52,43 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht bucket := vars["bucket"] if s3Error := checkRequestAuthType(ctx, r, policy.PutBucketPolicyAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Check if bucket exists. if _, err := objAPI.GetBucketInfo(ctx, bucket); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // Error out if Content-Length is missing. // PutBucketPolicy always needs Content-Length. if r.ContentLength <= 0 { - writeErrorResponse(w, ErrMissingContentLength, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) return } // Error out if Content-Length is beyond allowed size. if r.ContentLength > maxBucketPolicySize { - writeErrorResponse(w, ErrEntityTooLarge, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrEntityTooLarge), r.URL, guessIsBrowserReq(r)) return } bucketPolicy, err := policy.ParseConfig(io.LimitReader(r.Body, r.ContentLength), bucket) if err != nil { - writeErrorResponse(w, ErrMalformedPolicy, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedPolicy), r.URL, guessIsBrowserReq(r)) return } // Version in policy must not be empty if bucketPolicy.Version == "" { - writeErrorResponse(w, ErrMalformedPolicy, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedPolicy), r.URL, guessIsBrowserReq(r)) return } if err = objAPI.SetBucketPolicy(ctx, bucket, bucketPolicy); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -107,7 +107,7 @@ func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } @@ -115,18 +115,18 @@ func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r bucket := vars["bucket"] if s3Error := checkRequestAuthType(ctx, r, policy.DeleteBucketPolicyAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Check if bucket exists. if _, err := objAPI.GetBucketInfo(ctx, bucket); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } if err := objAPI.DeleteBucketPolicy(ctx, bucket); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -145,7 +145,7 @@ func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *ht objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } @@ -153,26 +153,26 @@ func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *ht bucket := vars["bucket"] if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketPolicyAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Check if bucket exists. if _, err := objAPI.GetBucketInfo(ctx, bucket); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // Read bucket access policy. bucketPolicy, err := objAPI.GetBucketPolicy(ctx, bucket) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } policyData, err := json.Marshal(bucketPolicy) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } diff --git a/cmd/copy-part-range.go b/cmd/copy-part-range.go index 2f2b319d2..db1ae3260 100644 --- a/cmd/copy-part-range.go +++ b/cmd/copy-part-range.go @@ -17,21 +17,22 @@ package cmd import ( + "context" "net/http" "net/url" ) // Writes S3 compatible copy part range error. -func writeCopyPartErr(w http.ResponseWriter, err error, url *url.URL, browser bool) { +func writeCopyPartErr(ctx context.Context, w http.ResponseWriter, err error, url *url.URL, browser bool) { switch err { case errInvalidRange: - writeErrorResponse(w, ErrInvalidCopyPartRange, url, browser) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidCopyPartRange), url, browser) return case errInvalidRangeSource: - writeErrorResponse(w, ErrInvalidCopyPartRangeSource, url, browser) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidCopyPartRangeSource), url, browser) return default: - writeErrorResponse(w, ErrInternalError, url, browser) + writeErrorResponse(w, toAPIError(ctx, err), url, browser) return } } diff --git a/cmd/dummy-handlers.go b/cmd/dummy-handlers.go index 3c195abfc..bdac2a590 100644 --- a/cmd/dummy-handlers.go +++ b/cmd/dummy-handlers.go @@ -129,27 +129,27 @@ func (api objectAPIHandlers) GetBucketCorsHandler(w http.ResponseWriter, r *http objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } // Allow getBucketCors if policy action is set, since this is a dummy call // we are simply re-purposing the bucketPolicyAction. if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketPolicyAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Validate if bucket exists, before proceeding further... _, err := objAPI.GetBucketInfo(ctx, bucket) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } cors := &corsConfiguration{} if err := xml.NewEncoder(w).Encode(cors); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -165,21 +165,21 @@ func (api objectAPIHandlers) GetBucketTaggingHandler(w http.ResponseWriter, r *h objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } // Allow getBucketTagging if policy action is set, since this is a dummy call // we are simply re-purposing the bucketPolicyAction. if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketPolicyAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Validate if bucket exists, before proceeding further... _, err := objAPI.GetBucketInfo(ctx, bucket) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -187,7 +187,7 @@ func (api objectAPIHandlers) GetBucketTaggingHandler(w http.ResponseWriter, r *h tags.TagSet.Tag = append(tags.TagSet.Tag, tagElem{}) if err := xml.NewEncoder(w).Encode(tags); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -204,21 +204,21 @@ func (api objectAPIHandlers) GetObjectTaggingHandler(w http.ResponseWriter, r *h objAPI := api.ObjectAPI() if objAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } // Allow getObjectTagging if policy action is set, since this is a dummy call // we are simply re-purposing the bucketPolicyAction. if s3Error := checkRequestAuthType(ctx, r, policy.GetBucketPolicyAction, bucket, ""); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Validate if object exists, before proceeding further... _, err := objAPI.GetObjectInfo(ctx, bucket, object, ObjectOptions{}) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -226,7 +226,7 @@ func (api objectAPIHandlers) GetObjectTaggingHandler(w http.ResponseWriter, r *h tags.TagSet.Tag = append(tags.TagSet.Tag, tagElem{}) if err := xml.NewEncoder(w).Encode(tags); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } diff --git a/cmd/encryption-v1.go b/cmd/encryption-v1.go index 548a3d7ca..ac0199c54 100644 --- a/cmd/encryption-v1.go +++ b/cmd/encryption-v1.go @@ -1103,22 +1103,22 @@ func (o *ObjectInfo) EncryptedSize() int64 { // decryption succeeded. // // DecryptCopyObjectInfo also returns whether the object is encrypted or not. -func DecryptCopyObjectInfo(info *ObjectInfo, headers http.Header) (apiErr APIErrorCode, encrypted bool) { +func DecryptCopyObjectInfo(info *ObjectInfo, headers http.Header) (errCode APIErrorCode, encrypted bool) { // Directories are never encrypted. if info.IsDir { return ErrNone, false } - if apiErr, encrypted = ErrNone, crypto.IsEncrypted(info.UserDefined); !encrypted && crypto.SSECopy.IsRequested(headers) { - apiErr = ErrInvalidEncryptionParameters + if errCode, encrypted = ErrNone, crypto.IsEncrypted(info.UserDefined); !encrypted && crypto.SSECopy.IsRequested(headers) { + errCode = ErrInvalidEncryptionParameters } else if encrypted { if (!crypto.SSECopy.IsRequested(headers) && crypto.SSEC.IsEncrypted(info.UserDefined)) || (crypto.SSECopy.IsRequested(headers) && crypto.S3.IsEncrypted(info.UserDefined)) { - apiErr = ErrSSEEncryptedObject + errCode = ErrSSEEncryptedObject return } var err error if info.Size, err = info.DecryptedSize(); err != nil { - apiErr = toAPIErrorCode(context.Background(), err) + errCode = toAPIErrorCode(context.Background(), err) } } return diff --git a/cmd/gateway/gcs/gateway-gcs.go b/cmd/gateway/gcs/gateway-gcs.go index 720ec14b5..dd1adf38d 100644 --- a/cmd/gateway/gcs/gateway-gcs.go +++ b/cmd/gateway/gcs/gateway-gcs.go @@ -324,8 +324,6 @@ func gcsToObjectError(err error, params ...string) error { break } err = minio.BucketNotEmpty{Bucket: bucket} - default: - err = fmt.Errorf("Unsupported error reason: %s", reason) } return err diff --git a/cmd/gateway/gcs/gateway-gcs_test.go b/cmd/gateway/gcs/gateway-gcs_test.go index 68d67fcd8..3a06ad5b1 100644 --- a/cmd/gateway/gcs/gateway-gcs_test.go +++ b/cmd/gateway/gcs/gateway-gcs_test.go @@ -375,15 +375,6 @@ func TestGCSToObjectError(t *testing.T) { Object: "object", }, }, - { - []string{"bucket", "object"}, - &googleapi.Error{ - Errors: []googleapi.ErrorItem{{ - Reason: "unknown", - }}, - }, - fmt.Errorf("Unsupported error reason: unknown"), - }, } for i, testCase := range testCases { diff --git a/cmd/generic-handlers.go b/cmd/generic-handlers.go index 16c5e2a9c..ecfe36a5c 100644 --- a/cmd/generic-handlers.go +++ b/cmd/generic-handlers.go @@ -90,7 +90,7 @@ func setRequestHeaderSizeLimitHandler(h http.Handler) http.Handler { // of the user-defined metadata to 2 KB. func (h requestHeaderSizeLimitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if isHTTPHeaderSizeTooLarge(r.Header) { - writeErrorResponse(w, ErrMetadataTooLarge, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMetadataTooLarge), r.URL, guessIsBrowserReq(r)) return } h.Handler.ServeHTTP(w, r) @@ -133,7 +133,7 @@ func filterReservedMetadata(h http.Handler) http.Handler { // would be treated as metadata. func (h reservedMetadataHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if containsReservedMetadata(r.Header) { - writeErrorResponse(w, ErrUnsupportedMetadata, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrUnsupportedMetadata), r.URL, guessIsBrowserReq(r)) return } h.Handler.ServeHTTP(w, r) @@ -300,7 +300,7 @@ func (h minioReservedBucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Req // buckets bucketName, _ := urlPath2BucketObjectName(r.URL.Path) if isMinioReservedBucket(bucketName) || isMinioMetaBucket(bucketName) { - writeErrorResponse(w, ErrAllAccessDisabled, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrAllAccessDisabled), r.URL, guessIsBrowserReq(r)) return } } @@ -358,19 +358,19 @@ func (h timeValidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { aType := getRequestAuthType(r) if aType == authTypeSigned || aType == authTypeSignedV2 || aType == authTypeStreamingSigned { // Verify if date headers are set, if not reject the request - amzDate, apiErr := parseAmzDateHeader(r) - if apiErr != ErrNone { + amzDate, errCode := parseAmzDateHeader(r) + if errCode != ErrNone { // All our internal APIs are sensitive towards Date // header, for all requests where Date header is not // present we will reject such clients. - writeErrorResponse(w, apiErr, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(errCode), r.URL, guessIsBrowserReq(r)) return } // Verify if the request date header is shifted by less than globalMaxSkewTime parameter in the past // or in the future, reject request otherwise. curTime := UTCNow() if curTime.Sub(amzDate) > globalMaxSkewTime || amzDate.Sub(curTime) > globalMaxSkewTime { - writeErrorResponse(w, ErrRequestTimeTooSkewed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrRequestTimeTooSkewed), r.URL, guessIsBrowserReq(r)) return } } @@ -473,14 +473,14 @@ func (h resourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // If bucketName is present and not objectName check for bucket level resource queries. if bucketName != "" && objectName == "" { if ignoreNotImplementedBucketResources(r) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } } // If bucketName and objectName are present check for its resource queries. if bucketName != "" && objectName != "" { if ignoreNotImplementedObjectResources(r) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } } @@ -584,14 +584,14 @@ func hasBadPathComponent(path string) bool { func (h pathValidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Check for bad components in URL path. if hasBadPathComponent(r.URL.Path) { - writeErrorResponse(w, ErrInvalidResourceName, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidResourceName), r.URL, guessIsBrowserReq(r)) return } // Check for bad components in URL query values. for _, vv := range r.URL.Query() { for _, v := range vv { if hasBadPathComponent(v) { - writeErrorResponse(w, ErrInvalidResourceName, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidResourceName), r.URL, guessIsBrowserReq(r)) return } } @@ -635,9 +635,9 @@ func (f bucketForwardingHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques sr, err := globalDNSConfig.Get(bucket) if err != nil { if err == dns.ErrNoEntriesFound { - writeErrorResponse(w, ErrNoSuchBucket, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNoSuchBucket), r.URL, guessIsBrowserReq(r)) } else { - writeErrorResponse(w, toAPIErrorCode(context.Background(), err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(context.Background(), err), r.URL, guessIsBrowserReq(r)) } return } @@ -679,9 +679,9 @@ func (f bucketForwardingHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques sr, err := globalDNSConfig.Get(bucket) if err != nil { if err == dns.ErrNoEntriesFound { - writeErrorResponse(w, ErrNoSuchBucket, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNoSuchBucket), r.URL, guessIsBrowserReq(r)) } else { - writeErrorResponse(w, toAPIErrorCode(context.Background(), err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(context.Background(), err), r.URL, guessIsBrowserReq(r)) } return } @@ -741,7 +741,7 @@ func (l rateLimit) ServeHTTP(w http.ResponseWriter, r *http.Request) { // potential pileup on the server. if err := l.Wait(ctx); err != nil { // Send an S3 compatible error, SlowDown. - writeErrorResponse(w, ErrSlowDown, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrSlowDown), r.URL, guessIsBrowserReq(r)) return } @@ -795,7 +795,7 @@ type criticalErrorHandler struct{ handler http.Handler } func (h criticalErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err == logger.ErrCritical { // handle - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInternalError), r.URL, guessIsBrowserReq(r)) } else if err != nil { panic(err) // forward other panic calls } @@ -812,9 +812,9 @@ func (h sseTLSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Deny SSE-C requests if not made over TLS if !globalIsSSL && (crypto.SSEC.IsRequested(r.Header) || crypto.SSECopy.IsRequested(r.Header)) { if r.Method == http.MethodHead { - writeErrorResponseHeadersOnly(w, ErrInsecureSSECustomerRequest) + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrInsecureSSECustomerRequest)) } else { - writeErrorResponse(w, ErrInsecureSSECustomerRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInsecureSSECustomerRequest), r.URL, guessIsBrowserReq(r)) } return } diff --git a/cmd/handler-utils.go b/cmd/handler-utils.go index f5e4e94a5..a466af641 100644 --- a/cmd/handler-utils.go +++ b/cmd/handler-utils.go @@ -366,12 +366,12 @@ func getResource(path string, host string, domain string) (string, error) { // If none of the http routes match respond with MethodNotAllowed, in JSON func notFoundHandlerJSON(w http.ResponseWriter, r *http.Request) { - writeErrorResponseJSON(w, ErrMethodNotAllowed, r.URL) + writeErrorResponseJSON(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) return } // If none of the http routes match respond with MethodNotAllowed func notFoundHandler(w http.ResponseWriter, r *http.Request) { - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } diff --git a/cmd/object-handlers-common.go b/cmd/object-handlers-common.go index d0a6a32aa..3cf7b8236 100644 --- a/cmd/object-handlers-common.go +++ b/cmd/object-handlers-common.go @@ -75,7 +75,7 @@ func checkCopyObjectPreconditions(w http.ResponseWriter, r *http.Request, objInf if !ifModifiedSince(objInfo.ModTime, givenTime) { // If the object is not modified since the specified time. writeHeaders() - writeErrorResponse(w, ErrPreconditionFailed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrPreconditionFailed), r.URL, guessIsBrowserReq(r)) return true } } @@ -89,7 +89,7 @@ func checkCopyObjectPreconditions(w http.ResponseWriter, r *http.Request, objInf if ifModifiedSince(objInfo.ModTime, givenTime) { // If the object is modified since the specified time. writeHeaders() - writeErrorResponse(w, ErrPreconditionFailed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrPreconditionFailed), r.URL, guessIsBrowserReq(r)) return true } } @@ -102,7 +102,7 @@ func checkCopyObjectPreconditions(w http.ResponseWriter, r *http.Request, objInf if objInfo.ETag != "" && !isETagEqual(objInfo.ETag, ifMatchETagHeader) { // If the object ETag does not match with the specified ETag. writeHeaders() - writeErrorResponse(w, ErrPreconditionFailed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrPreconditionFailed), r.URL, guessIsBrowserReq(r)) return true } } @@ -114,7 +114,7 @@ func checkCopyObjectPreconditions(w http.ResponseWriter, r *http.Request, objInf if objInfo.ETag != "" && isETagEqual(objInfo.ETag, ifNoneMatchETagHeader) { // If the object ETag matches with the specified ETag. writeHeaders() - writeErrorResponse(w, ErrPreconditionFailed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrPreconditionFailed), r.URL, guessIsBrowserReq(r)) return true } } @@ -174,7 +174,7 @@ func checkPreconditions(w http.ResponseWriter, r *http.Request, objInfo ObjectIn if ifModifiedSince(objInfo.ModTime, givenTime) { // If the object is modified since the specified time. writeHeaders() - writeErrorResponse(w, ErrPreconditionFailed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrPreconditionFailed), r.URL, guessIsBrowserReq(r)) return true } } @@ -187,7 +187,7 @@ func checkPreconditions(w http.ResponseWriter, r *http.Request, objInfo ObjectIn if !isETagEqual(objInfo.ETag, ifMatchETagHeader) { // If the object ETag does not match with the specified ETag. writeHeaders() - writeErrorResponse(w, ErrPreconditionFailed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrPreconditionFailed), r.URL, guessIsBrowserReq(r)) return true } } diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index 3cb36da1f..e63f8ede5 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -86,15 +86,15 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r // Fetch object stat info. objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if crypto.S3KMS.IsRequested(r.Header) { // SSE-KMS is not supported - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } if !api.EncryptionEnabled() && hasServerSideEncryptionHeader(r.Header) { - writeErrorResponse(w, ErrBadRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrBadRequest), r.URL, guessIsBrowserReq(r)) return } vars := mux.Vars(r) @@ -104,7 +104,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r // get gateway encryption options opts, err := getOpts(ctx, r, bucket, object) if err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } @@ -137,24 +137,24 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r IsOwner: false, }) { _, err = getObjectInfo(ctx, bucket, object, opts) - if toAPIErrorCode(ctx, err) == ErrNoSuchKey { + if toAPIError(ctx, err).Code == "NoSuchKey" { s3Error = ErrNoSuchKey } } } - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Get request range. rangeHeader := r.Header.Get("Range") if rangeHeader != "" { - writeErrorResponse(w, ErrUnsupportedRangeHeader, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrUnsupportedRangeHeader), r.URL, guessIsBrowserReq(r)) return } if r.ContentLength <= 0 { - writeErrorResponse(w, ErrEmptyRequestBody, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrEmptyRequestBody), r.URL, guessIsBrowserReq(r)) return } @@ -164,7 +164,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r w.WriteHeader(serr.HTTPStatusCode()) w.Write(s3select.NewErrorMessage(serr.ErrorCode(), serr.ErrorMessage())) } else { - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) } return } @@ -189,7 +189,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r objInfo, err := getObjectInfo(ctx, bucket, object, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -198,7 +198,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r w.WriteHeader(serr.HTTPStatusCode()) w.Write(s3select.NewErrorMessage(serr.ErrorCode(), serr.ErrorMessage())) } else { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) } return } @@ -236,15 +236,15 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if crypto.S3.IsRequested(r.Header) || crypto.S3KMS.IsRequested(r.Header) { // If SSE-S3 or SSE-KMS present -> AWS fails with undefined error - writeErrorResponse(w, ErrBadRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrBadRequest), r.URL, guessIsBrowserReq(r)) return } if !api.EncryptionEnabled() && hasServerSideEncryptionHeader(r.Header) { - writeErrorResponse(w, ErrBadRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrBadRequest), r.URL, guessIsBrowserReq(r)) return } vars := mux.Vars(r) @@ -252,14 +252,14 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req object := vars["object"] if vid := r.URL.Query().Get("versionId"); vid != "" && vid != "null" { - writeErrorResponse(w, ErrNoSuchVersion, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNoSuchVersion), r.URL, guessIsBrowserReq(r)) return } // get gateway encryption options opts, err := getOpts(ctx, r, bucket, object) if err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } @@ -292,12 +292,12 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req } _, err = getObjectInfo(ctx, bucket, object, opts) - if toAPIErrorCode(ctx, err) == ErrNoSuchKey { + if toAPIError(ctx, err).Code == "NoSuchKey" { s3Error = ErrNoSuchKey } } } - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -315,7 +315,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req // parse error and treat it as regular Get // request like Amazon S3. if err == errInvalidRange { - writeErrorResponse(w, ErrInvalidRange, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidRange), r.URL, guessIsBrowserReq(r)) return } @@ -325,7 +325,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req gr, err := getObjectNInfo(ctx, bucket, object, rs, r.Header, readLock, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } defer gr.Close() @@ -335,7 +335,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req if objectAPI.IsEncryptionSupported() { objInfo.UserDefined = CleanMinioInternalMetadataKeys(objInfo.UserDefined) if _, err = DecryptObjectInfo(&objInfo, r.Header); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -359,7 +359,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req } if err = setObjectHeaders(w, objInfo, rs); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -375,14 +375,14 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req // Write object content to response body if _, err = io.Copy(httpWriter, gr); err != nil { if !httpWriter.HasWritten() && !statusCodeWritten { // write error response only if no data or headers has been written to client yet - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) } return } if err = httpWriter.Close(); err != nil { if !httpWriter.HasWritten() && !statusCodeWritten { // write error response only if no data or headers has been written to client yet - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -416,15 +416,15 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponseHeadersOnly(w, ErrServerNotInitialized) + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrServerNotInitialized)) return } if crypto.S3.IsRequested(r.Header) || crypto.S3KMS.IsRequested(r.Header) { // If SSE-S3 or SSE-KMS present -> AWS fails with undefined error - writeErrorResponseHeadersOnly(w, ErrBadRequest) + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrBadRequest)) return } if !api.EncryptionEnabled() && hasServerSideEncryptionHeader(r.Header) { - writeErrorResponse(w, ErrBadRequest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrBadRequest), r.URL, guessIsBrowserReq(r)) return } vars := mux.Vars(r) @@ -432,7 +432,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re object := vars["object"] if vid := r.URL.Query().Get("versionId"); vid != "" && vid != "null" { - writeErrorResponseHeadersOnly(w, ErrNoSuchVersion) + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrNoSuchVersion)) return } @@ -443,7 +443,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re opts, err := getOpts(ctx, r, bucket, object) if err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } @@ -469,12 +469,12 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re IsOwner: false, }) { _, err = getObjectInfo(ctx, bucket, object, opts) - if toAPIErrorCode(ctx, err) == ErrNoSuchKey { + if toAPIError(ctx, err).Code == "NoSuchKey" { s3Error = ErrNoSuchKey } } } - writeErrorResponseHeadersOnly(w, s3Error) + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(s3Error)) return } @@ -487,7 +487,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re // parse error and treat it as regular Get // request like Amazon S3. if err == errInvalidRange { - writeErrorResponseHeadersOnly(w, ErrInvalidRange) + writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrInvalidRange)) return } @@ -497,12 +497,12 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re objInfo, err := getObjectInfo(ctx, bucket, object, opts) if err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } if objectAPI.IsEncryptionSupported() { if _, err = DecryptObjectInfo(&objInfo, r.Header); err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } objInfo.UserDefined = CleanMinioInternalMetadataKeys(objInfo.UserDefined) @@ -517,7 +517,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re case crypto.SSEC.IsEncrypted(objInfo.UserDefined): // Validate the SSE-C Key set in the header. if _, err = crypto.SSEC.UnsealObjectKey(r.Header, objInfo.UserDefined, bucket, object); err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } w.Header().Set(crypto.SSECAlgorithm, r.Header.Get(crypto.SSECAlgorithm)) @@ -533,7 +533,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re // Set standard object headers. if err = setObjectHeaders(w, objInfo, rs); err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } @@ -633,15 +633,15 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if crypto.S3KMS.IsRequested(r.Header) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported return } if !api.EncryptionEnabled() && (hasServerSideEncryptionHeader(r.Header) || crypto.SSECopy.IsRequested(r.Header)) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } vars := mux.Vars(r) @@ -649,7 +649,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re dstObject := vars["object"] if s3Error := checkRequestAuthType(ctx, r, policy.PutObjectAction, dstBucket, dstObject); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -668,7 +668,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re // its non "null" value, we should error out since we do not support // any versions other than "null". if vid := u.Query().Get("versionId"); vid != "" && vid != "null" { - writeErrorResponse(w, ErrNoSuchVersion, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNoSuchVersion), r.URL, guessIsBrowserReq(r)) return } // Note that url.Parse does the unescaping @@ -679,7 +679,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re // its non "null" value, we should error out since we do not support // any versions other than "null". if vid != "null" { - writeErrorResponse(w, ErrNoSuchVersion, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNoSuchVersion), r.URL, guessIsBrowserReq(r)) return } } @@ -687,18 +687,18 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re srcBucket, srcObject := path2BucketAndObject(cpSrcPath) // If source object is empty or bucket is empty, reply back invalid copy source. if srcObject == "" || srcBucket == "" { - writeErrorResponse(w, ErrInvalidCopySource, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidCopySource), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.GetObjectAction, srcBucket, srcObject); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Check if metadata directive is valid. if !isMetadataDirectiveValid(r.Header) { - writeErrorResponse(w, ErrInvalidMetadataDirective, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidMetadataDirective), r.URL, guessIsBrowserReq(r)) return } // This request header needs to be set prior to setting ObjectOptions @@ -710,7 +710,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re srcOpts, err := copySrcOpts(ctx, r, srcBucket, srcObject) if err != nil { logger.LogIf(ctx, err) - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // convert copy src encryption options for GET calls @@ -722,14 +722,14 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re dstOpts, err = copyDstOpts(ctx, r, dstBucket, dstObject, nil) if err != nil { logger.LogIf(ctx, err) - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // Deny if WORM is enabled if globalWORMEnabled { if _, err = objectAPI.GetObjectInfo(ctx, dstBucket, dstObject, dstOpts); err == nil { - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } } @@ -749,7 +749,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re var rs *HTTPRangeSpec gr, err := getObjectNInfo(ctx, srcBucket, srcObject, rs, r.Header, lock, getOpts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } defer gr.Close() @@ -762,7 +762,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re /// maximum Upload size for object in a single CopyObject operation. if isMaxObjectSize(srcInfo.Size) { - writeErrorResponse(w, ErrEntityTooLarge, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrEntityTooLarge), r.URL, guessIsBrowserReq(r)) return } @@ -780,7 +780,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re if crypto.IsEncrypted(srcInfo.UserDefined) { actualSize, err = srcInfo.DecryptedSize() if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } length = actualSize @@ -839,7 +839,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re srcInfo.Reader, err = hash.NewReader(reader, length, "", "", actualSize) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -850,12 +850,12 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re if objectAPI.IsEncryptionSupported() && !isCompressed { // Encryption parameters not applicable for this object. if !crypto.IsEncrypted(srcInfo.UserDefined) && crypto.SSECopy.IsRequested(r.Header) { - writeErrorResponse(w, toAPIErrorCode(ctx, errInvalidEncryptionParameters), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, errInvalidEncryptionParameters), r.URL, guessIsBrowserReq(r)) return } // Encryption parameters not present for this object. if crypto.SSEC.IsEncrypted(srcInfo.UserDefined) && !crypto.SSECopy.IsRequested(r.Header) { - writeErrorResponse(w, ErrInvalidSSECustomerAlgorithm, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidSSECustomerAlgorithm), r.URL, guessIsBrowserReq(r)) return } @@ -871,7 +871,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re if sseC { newKey, err = ParseSSECustomerRequest(r) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -885,7 +885,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re if sseCopyC && sseC { oldKey, err = ParseSSECopyCustomerRequest(r.Header, srcInfo.UserDefined) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -898,7 +898,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re // In case of SSE-S3 oldKey and newKey aren't used - the KMS manages the keys. if err = rotateKey(oldKey, newKey, srcBucket, srcObject, encMetadata); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -933,7 +933,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re if isTargetEncrypted { reader, objEncKey, err = newEncryptReader(srcInfo.Reader, newKey, dstBucket, dstObject, encMetadata, sseS3) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -946,7 +946,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re srcInfo.Reader, err = hash.NewReader(reader, targetSize, "", "", targetSize) // do not try to verify encrypted content if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -958,7 +958,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re srcInfo.UserDefined, err = getCpObjMetadataFromHeader(ctx, r, srcInfo.UserDefined) if err != nil { - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -983,7 +983,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re if !isMetadataReplace(r.Header) && srcInfo.metadataOnly && !crypto.IsEncrypted(srcInfo.UserDefined) { // If x-amz-metadata-directive is not set to REPLACE then we need // to error out if source and destination are same. - writeErrorResponse(w, ErrInvalidCopyDest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidCopyDest), r.URL, guessIsBrowserReq(r)) return } @@ -993,20 +993,20 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re var dstRecords []dns.SrvRecord dstRecords, err = globalDNSConfig.Get(dstBucket) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // Send PutObject request to appropriate instance (in federated deployment) client, rerr := getRemoteInstanceClient(r, getHostFromSrv(dstRecords)) if rerr != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, rerr), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, rerr), r.URL, guessIsBrowserReq(r)) return } remoteObjInfo, rerr := client.PutObject(dstBucket, dstObject, srcInfo.Reader, srcInfo.Size, "", "", srcInfo.UserDefined, dstOpts.ServerSideEncryption) if rerr != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, rerr), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, rerr), r.URL, guessIsBrowserReq(r)) return } objInfo.ETag = remoteObjInfo.ETag @@ -1016,7 +1016,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re // object is same then only metadata is updated. objInfo, err = objectAPI.CopyObject(ctx, srcBucket, srcObject, dstBucket, dstObject, srcInfo, srcOpts, dstOpts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -1065,15 +1065,15 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if crypto.S3KMS.IsRequested(r.Header) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported return } if !api.EncryptionEnabled() && hasServerSideEncryptionHeader(r.Header) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } vars := mux.Vars(r) @@ -1082,14 +1082,14 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req // X-Amz-Copy-Source shouldn't be set for this call. if _, ok := r.Header["X-Amz-Copy-Source"]; ok { - writeErrorResponse(w, ErrInvalidCopySource, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidCopySource), r.URL, guessIsBrowserReq(r)) return } // Validate storage class metadata if present if _, ok := r.Header[amzStorageClassCanonical]; ok { if !isValidStorageClassMeta(r.Header.Get(amzStorageClassCanonical)) { - writeErrorResponse(w, ErrInvalidStorageClass, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidStorageClass), r.URL, guessIsBrowserReq(r)) return } } @@ -1097,7 +1097,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req // Get Content-Md5 sent by client and verify if valid md5Bytes, err := checkValidMD5(r.Header) if err != nil { - writeErrorResponse(w, ErrInvalidDigest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidDigest), r.URL, guessIsBrowserReq(r)) return } /// if Content-Length is unknown/missing, deny the request @@ -1106,30 +1106,30 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req if rAuthType == authTypeStreamingSigned { if sizeStr, ok := r.Header["X-Amz-Decoded-Content-Length"]; ok { if sizeStr[0] == "" { - writeErrorResponse(w, ErrMissingContentLength, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) return } size, err = strconv.ParseInt(sizeStr[0], 10, 64) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } } if size == -1 { - writeErrorResponse(w, ErrMissingContentLength, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) return } /// maximum Upload size for objects in a single operation if isMaxObjectSize(size) { - writeErrorResponse(w, ErrEntityTooLarge, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrEntityTooLarge), r.URL, guessIsBrowserReq(r)) return } metadata, err := extractMetadata(ctx, r) if err != nil { - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1164,7 +1164,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req // Check if put is allowed if s3Err = isPutAllowed(rAuthType, bucket, object, r); s3Err != ErrNone { - writeErrorResponse(w, s3Err, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r)) return } @@ -1173,19 +1173,19 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req // Initialize stream signature verifier. reader, s3Err = newSignV4ChunkedReader(r) if s3Err != ErrNone { - writeErrorResponse(w, s3Err, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r)) return } case authTypeSignedV2, authTypePresignedV2: s3Err = isReqAuthenticatedV2(r) if s3Err != ErrNone { - writeErrorResponse(w, s3Err, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r)) return } case authTypePresigned, authTypeSigned: if s3Err = reqSignatureV4Verify(r, globalServerConfig.GetRegion()); s3Err != ErrNone { - writeErrorResponse(w, s3Err, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r)) return } if !skipContentSha256Cksum(r) { @@ -1206,7 +1206,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req var actualReader *hash.Reader actualReader, err = hash.NewReader(reader, size, md5hex, sha256hex, actualSize) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1226,7 +1226,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req hashReader, err := hash.NewReader(reader, size, md5hex, sha256hex, actualSize) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1241,14 +1241,14 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req var opts ObjectOptions opts, err = putOpts(ctx, r, bucket, object, metadata) if err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } // Deny if WORM is enabled if globalWORMEnabled { if _, err = objectAPI.GetObjectInfo(ctx, bucket, object, opts); err == nil { - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } } @@ -1258,13 +1258,13 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req if hasServerSideEncryptionHeader(r.Header) && !hasSuffix(object, slashSeparator) { // handle SSE requests reader, objectEncryptionKey, err = EncryptRequest(hashReader, r, bucket, object, metadata) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } info := ObjectInfo{Size: size} hashReader, err = hash.NewReader(reader, info.EncryptedSize(), "", "", size) // do not try to verify encrypted content if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } pReader = NewPutObjReader(rawReader, hashReader, objectEncryptionKey) @@ -1281,7 +1281,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req // Create the object.. objInfo, err := putObject(ctx, bucket, object, pReader, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1342,15 +1342,15 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if crypto.S3KMS.IsRequested(r.Header) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported return } if !api.EncryptionEnabled() && hasServerSideEncryptionHeader(r.Header) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } vars := mux.Vars(r) @@ -1358,7 +1358,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r object := vars["object"] if s3Error := checkRequestAuthType(ctx, r, policy.PutObjectAction, bucket, object); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -1373,14 +1373,14 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r opts, err = putOpts(ctx, r, bucket, object, nil) if err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } // Deny if WORM is enabled if globalWORMEnabled { if _, err = objectAPI.GetObjectInfo(ctx, bucket, object, opts); err == nil { - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } } @@ -1388,7 +1388,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r // Validate storage class metadata if present if _, ok := r.Header[amzStorageClassCanonical]; ok { if !isValidStorageClassMeta(r.Header.Get(amzStorageClassCanonical)) { - writeErrorResponse(w, ErrInvalidStorageClass, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidStorageClass), r.URL, guessIsBrowserReq(r)) return } } @@ -1398,7 +1398,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r if objectAPI.IsEncryptionSupported() { if hasServerSideEncryptionHeader(r.Header) { if err = setEncryptionMetadata(r, bucket, object, encMetadata); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // Set this for multipart only operations, we need to differentiate during @@ -1410,7 +1410,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r // Extract metadata that needs to be saved. metadata, err := extractMetadata(ctx, r) if err != nil { - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1430,7 +1430,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r opts, err = putOpts(ctx, r, bucket, object, metadata) if err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } newMultipartUpload := objectAPI.NewMultipartUpload @@ -1439,7 +1439,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r } uploadID, err := newMultipartUpload(ctx, bucket, object, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1458,15 +1458,15 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if crypto.S3KMS.IsRequested(r.Header) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported return } if !api.EncryptionEnabled() && (hasServerSideEncryptionHeader(r.Header) || crypto.SSECopy.IsRequested(r.Header)) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } @@ -1475,7 +1475,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt dstObject := vars["object"] if s3Error := checkRequestAuthType(ctx, r, policy.PutObjectAction, dstBucket, dstObject); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -1492,7 +1492,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt // its non "null" value, we should error out since we do not support // any versions other than "null". if vid := u.Query().Get("versionId"); vid != "" && vid != "null" { - writeErrorResponse(w, ErrNoSuchVersion, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNoSuchVersion), r.URL, guessIsBrowserReq(r)) return } // Note that url.Parse does the unescaping @@ -1503,7 +1503,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt // its non "null" value, we should error out since we do not support // any versions other than "null". if vid != "null" { - writeErrorResponse(w, ErrNoSuchVersion, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNoSuchVersion), r.URL, guessIsBrowserReq(r)) return } } @@ -1511,12 +1511,12 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt srcBucket, srcObject := path2BucketAndObject(cpSrcPath) // If source object is empty or bucket is empty, reply back invalid copy source. if srcObject == "" || srcBucket == "" { - writeErrorResponse(w, ErrInvalidCopySource, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidCopySource), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.GetObjectAction, srcBucket, srcObject); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -1525,20 +1525,20 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt partID, err := strconv.Atoi(partIDString) if err != nil { - writeErrorResponse(w, ErrInvalidPart, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidPart), r.URL, guessIsBrowserReq(r)) return } // check partID with maximum part ID for multipart objects if isMaxPartID(partID) { - writeErrorResponse(w, ErrInvalidMaxParts, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidMaxParts), r.URL, guessIsBrowserReq(r)) return } var srcOpts, dstOpts ObjectOptions srcOpts, err = copySrcOpts(ctx, r, srcBucket, srcObject) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // convert copy src and dst encryption options for GET/PUT calls @@ -1548,14 +1548,14 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt } dstOpts, err = copyDstOpts(ctx, r, dstBucket, dstObject, nil) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // Deny if WORM is enabled if globalWORMEnabled { if _, err = objectAPI.GetObjectInfo(ctx, dstBucket, dstObject, dstOpts); err == nil { - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } } @@ -1575,7 +1575,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt // Ignore other parse error and treat it as regular Get request like Amazon S3. logger.GetReqInfo(ctx).AppendTags("rangeHeader", rangeHeader) logger.LogIf(ctx, parseRangeErr) - writeCopyPartErr(w, parseRangeErr, r.URL, guessIsBrowserReq(r)) + writeCopyPartErr(ctx, w, parseRangeErr, r.URL, guessIsBrowserReq(r)) return } @@ -1583,7 +1583,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt gr, err := getObjectNInfo(ctx, srcBucket, srcObject, rs, r.Header, readLock, getOpts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } defer gr.Close() @@ -1593,14 +1593,14 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt if crypto.IsEncrypted(srcInfo.UserDefined) { actualPartSize, err = srcInfo.DecryptedSize() if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } // Special care for CopyObjectPart if partRangeErr := checkCopyPartRangeWithSize(rs, actualPartSize); partRangeErr != nil { - writeCopyPartErr(w, partRangeErr, r.URL, guessIsBrowserReq(r)) + writeCopyPartErr(ctx, w, partRangeErr, r.URL, guessIsBrowserReq(r)) return } @@ -1612,13 +1612,13 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt // Get the object offset & length startOffset, length, err := rs.GetOffsetLength(actualPartSize) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } /// maximum copy size for multipart objects in a single operation if isMaxAllowedPartSize(length) { - writeErrorResponse(w, ErrEntityTooLarge, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrEntityTooLarge), r.URL, guessIsBrowserReq(r)) return } @@ -1628,7 +1628,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt var li ListPartsInfo li, err = objectAPI.ListObjectParts(ctx, dstBucket, dstObject, uploadID, 0, 1, dstOpts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1658,7 +1658,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt srcInfo.Reader, err = hash.NewReader(reader, length, "", "", actualPartSize) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1670,22 +1670,22 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt if objectAPI.IsEncryptionSupported() && !isCompressed { li, lerr := objectAPI.ListObjectParts(ctx, dstBucket, dstObject, uploadID, 0, 1, dstOpts) if lerr != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, lerr), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, lerr), r.URL, guessIsBrowserReq(r)) return } li.UserDefined = CleanMinioInternalMetadataKeys(li.UserDefined) dstOpts, err = copyDstOpts(ctx, r, dstBucket, dstObject, li.UserDefined) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } if crypto.IsEncrypted(li.UserDefined) { if !crypto.SSEC.IsRequested(r.Header) && crypto.SSEC.IsEncrypted(li.UserDefined) { - writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrSSEMultipartEncrypted), r.URL, guessIsBrowserReq(r)) return } if crypto.S3.IsEncrypted(li.UserDefined) && crypto.SSEC.IsRequested(r.Header) { - writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrSSEMultipartEncrypted), r.URL, guessIsBrowserReq(r)) return } isEncrypted = true @@ -1693,13 +1693,13 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt if crypto.SSEC.IsRequested(r.Header) { key, err = ParseSSECustomerRequest(r) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } objectEncryptionKey, err = decryptObjectInfo(key, dstBucket, dstObject, li.UserDefined) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1711,14 +1711,14 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt partEncryptionKey := mac.Sum(nil) reader, err = sio.EncryptReader(reader, sio.Config{Key: partEncryptionKey}) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } info := ObjectInfo{Size: length} srcInfo.Reader, err = hash.NewReader(reader, info.EncryptedSize(), "", "", length) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } pReader = NewPutObjReader(rawReader, srcInfo.Reader, objectEncryptionKey) @@ -1730,7 +1730,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt partInfo, err := objectAPI.CopyObjectPart(ctx, srcBucket, srcObject, dstBucket, dstObject, uploadID, partID, startOffset, length, srcInfo, srcOpts, dstOpts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1753,15 +1753,15 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if crypto.S3KMS.IsRequested(r.Header) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) // SSE-KMS is not supported return } if !api.EncryptionEnabled() && hasServerSideEncryptionHeader(r.Header) { - writeErrorResponse(w, ErrNotImplemented, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } vars := mux.Vars(r) @@ -1770,14 +1770,14 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http // X-Amz-Copy-Source shouldn't be set for this call. if _, ok := r.Header["X-Amz-Copy-Source"]; ok { - writeErrorResponse(w, ErrInvalidCopySource, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidCopySource), r.URL, guessIsBrowserReq(r)) return } // get Content-Md5 sent by client and verify if valid md5Bytes, err := checkValidMD5(r.Header) if err != nil { - writeErrorResponse(w, ErrInvalidDigest, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidDigest), r.URL, guessIsBrowserReq(r)) return } @@ -1789,24 +1789,24 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http if rAuthType == authTypeStreamingSigned { if sizeStr, ok := r.Header["X-Amz-Decoded-Content-Length"]; ok { if sizeStr[0] == "" { - writeErrorResponse(w, ErrMissingContentLength, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) return } size, err = strconv.ParseInt(sizeStr[0], 10, 64) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } } if size == -1 { - writeErrorResponse(w, ErrMissingContentLength, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) return } /// maximum Upload size for multipart objects in a single operation if isMaxAllowedPartSize(size) { - writeErrorResponse(w, ErrEntityTooLarge, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrEntityTooLarge), r.URL, guessIsBrowserReq(r)) return } @@ -1815,13 +1815,13 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http partID, err := strconv.Atoi(partIDString) if err != nil { - writeErrorResponse(w, ErrInvalidPart, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidPart), r.URL, guessIsBrowserReq(r)) return } // check partID with maximum part ID for multipart objects if isMaxPartID(partID) { - writeErrorResponse(w, ErrInvalidMaxParts, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidMaxParts), r.URL, guessIsBrowserReq(r)) return } @@ -1833,7 +1833,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http ) reader = r.Body if s3Error = isPutAllowed(rAuthType, bucket, object, r); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -1842,17 +1842,17 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http // Initialize stream signature verifier. reader, s3Error = newSignV4ChunkedReader(r) if s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } case authTypeSignedV2, authTypePresignedV2: if s3Error = isReqAuthenticatedV2(r); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } case authTypePresigned, authTypeSigned: if s3Error = reqSignatureV4Verify(r, globalServerConfig.GetRegion()); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } @@ -1870,14 +1870,14 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http if crypto.SSEC.IsRequested(r.Header) { opts, err = putOpts(ctx, r, bucket, object, nil) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } var li ListPartsInfo li, err = objectAPI.ListObjectParts(ctx, bucket, object, uploadID, 0, 1, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // Read compression metadata preserved in the init multipart for the decision. @@ -1891,7 +1891,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http var actualReader *hash.Reader actualReader, err = hash.NewReader(reader, size, md5hex, sha256hex, actualSize) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1912,7 +1912,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http hashReader, err := hash.NewReader(reader, size, md5hex, sha256hex, actualSize) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } rawReader := hashReader @@ -1921,7 +1921,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http // Deny if WORM is enabled if globalWORMEnabled { if _, err = objectAPI.GetObjectInfo(ctx, bucket, object, opts); err == nil { - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } } @@ -1932,20 +1932,20 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http var li ListPartsInfo li, err = objectAPI.ListObjectParts(ctx, bucket, object, uploadID, 0, 1, ObjectOptions{}) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } li.UserDefined = CleanMinioInternalMetadataKeys(li.UserDefined) if crypto.IsEncrypted(li.UserDefined) { if !crypto.SSEC.IsRequested(r.Header) && crypto.SSEC.IsEncrypted(li.UserDefined) { - writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrSSEMultipartEncrypted), r.URL, guessIsBrowserReq(r)) return } isEncrypted = true // to detect SSE-S3 encryption opts, err = putOpts(ctx, r, bucket, object, li.UserDefined) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -1953,7 +1953,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http if crypto.SSEC.IsRequested(r.Header) { key, err = ParseSSECustomerRequest(r) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -1961,7 +1961,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http // Calculating object encryption key objectEncryptionKey, err = decryptObjectInfo(key, bucket, object, li.UserDefined) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } var partIDbin [4]byte @@ -1973,13 +1973,13 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http reader, err = sio.EncryptReader(hashReader, sio.Config{Key: partEncryptionKey}) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } info := ObjectInfo{Size: size} hashReader, err = hash.NewReader(reader, info.EncryptedSize(), "", "", size) // do not try to verify encrypted content if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } pReader = NewPutObjReader(rawReader, hashReader, objectEncryptionKey) @@ -1993,7 +1993,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http partInfo, err := putObjectPart(ctx, bucket, object, uploadID, partID, pReader, opts) if err != nil { // Verify if the underlying error is signature mismatch. - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -2022,7 +2022,7 @@ func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter, objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } abortMultipartUpload := objectAPI.AbortMultipartUpload @@ -2031,25 +2031,25 @@ func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter, } if s3Error := checkRequestAuthType(ctx, r, policy.AbortMultipartUploadAction, bucket, object); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Deny if WORM is enabled if globalWORMEnabled { if _, err := objectAPI.GetObjectInfo(ctx, bucket, object, ObjectOptions{}); err == nil { - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } } uploadID, _, _, _, s3Error := getObjectResources(r.URL.Query()) if s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } if err := abortMultipartUpload(ctx, bucket, object, uploadID); err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -2068,32 +2068,32 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.ListMultipartUploadPartsAction, bucket, object); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } uploadID, partNumberMarker, maxParts, _, s3Error := getObjectResources(r.URL.Query()) if s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } if partNumberMarker < 0 { - writeErrorResponse(w, ErrInvalidPartNumberMarker, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidPartNumberMarker), r.URL, guessIsBrowserReq(r)) return } if maxParts < 0 { - writeErrorResponse(w, ErrInvalidMaxParts, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidMaxParts), r.URL, guessIsBrowserReq(r)) return } var opts ObjectOptions listPartsInfo, err := objectAPI.ListObjectParts(ctx, bucket, object, uploadID, partNumberMarker, maxParts, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } var ssec bool @@ -2101,7 +2101,7 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht var li ListPartsInfo li, err = objectAPI.ListObjectParts(ctx, bucket, object, uploadID, 0, 1, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } if crypto.IsEncrypted(li.UserDefined) { @@ -2114,7 +2114,7 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht // Calculating object encryption key objectEncryptionKey, err = decryptObjectInfo(key, bucket, object, li.UserDefined) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -2177,19 +2177,19 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.PutObjectAction, bucket, object); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } // Deny if WORM is enabled if globalWORMEnabled { if _, err := objectAPI.GetObjectInfo(ctx, bucket, object, ObjectOptions{}); err == nil { - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } } @@ -2197,26 +2197,26 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite // Get upload id. uploadID, _, _, _, s3Error := getObjectResources(r.URL.Query()) if s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } completeMultipartBytes, err := goioutil.ReadAll(r.Body) if err != nil { - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } complMultipartUpload := &CompleteMultipartUpload{} if err = xml.Unmarshal(completeMultipartBytes, complMultipartUpload); err != nil { - writeErrorResponse(w, ErrMalformedXML, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedXML), r.URL, guessIsBrowserReq(r)) return } if len(complMultipartUpload.Parts) == 0 { - writeErrorResponse(w, ErrMalformedXML, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMalformedXML), r.URL, guessIsBrowserReq(r)) return } if !sort.IsSorted(CompletedParts(complMultipartUpload.Parts)) { - writeErrorResponse(w, ErrInvalidPartOrder, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidPartOrder), r.URL, guessIsBrowserReq(r)) return } var objectEncryptionKey []byte @@ -2226,7 +2226,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite var li ListPartsInfo li, err = objectAPI.ListObjectParts(ctx, bucket, object, uploadID, 0, 1, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } if crypto.IsEncrypted(li.UserDefined) { @@ -2237,7 +2237,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite // Calculating object encryption key objectEncryptionKey, err = decryptObjectInfo(key, bucket, object, li.UserDefined) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } @@ -2251,7 +2251,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite for { listPartsInfo, err := objectAPI.ListObjectParts(ctx, bucket, object, uploadID, partNumberMarker, maxParts, opts) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } for _, part := range listPartsInfo.Parts { @@ -2279,7 +2279,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite if bkPartInfo, ok := partsMap[strconv.Itoa(part.PartNumber)]; ok { bkETag := tryDecryptETag(objectEncryptionKey, bkPartInfo.ETag, ssec) if bkETag != part.ETag { - writeErrorResponse(w, ErrInvalidPart, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrInvalidPart), r.URL, guessIsBrowserReq(r)) return } part.ETag = bkPartInfo.ETag @@ -2304,7 +2304,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite writePartSmallErrorResponse(w, r, oErr) default: // Handle all other generic issues. - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) } return } @@ -2315,7 +2315,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite response := generateCompleteMultpartUploadResponse(bucket, object, location, objInfo.ETag) encodedSuccessResponse := encodeResponse(response) if err != nil { - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAdminAPIErr(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -2358,17 +2358,17 @@ func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http. objectAPI := api.ObjectAPI() if objectAPI == nil { - writeErrorResponse(w, ErrServerNotInitialized, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL, guessIsBrowserReq(r)) return } if s3Error := checkRequestAuthType(ctx, r, policy.DeleteObjectAction, bucket, object); s3Error != ErrNone { - writeErrorResponse(w, s3Error, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return } if vid := r.URL.Query().Get("versionId"); vid != "" && vid != "null" { - writeErrorResponse(w, ErrNoSuchVersion, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrNoSuchVersion), r.URL, guessIsBrowserReq(r)) return } @@ -2376,28 +2376,24 @@ func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http. if globalWORMEnabled { // Not required to check whether given object exists or not, because // DeleteObject is always successful irrespective of object existence. - writeErrorResponse(w, ErrMethodNotAllowed, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } if globalDNSConfig != nil { _, err := globalDNSConfig.Get(bucket) if err != nil { - if err == dns.ErrNoEntriesFound { - writeErrorResponse(w, ErrNoSuchBucket, r.URL, guessIsBrowserReq(r)) - } else { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) - } + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } } // http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectDELETE.html if err := deleteObject(ctx, objectAPI, api.CacheAPI(), bucket, object, r); err != nil { - switch toAPIErrorCode(ctx, err) { - case ErrNoSuchBucket: + switch err.(type) { + case BucketNotFound: // When bucket doesn't exist specially handle it. - writeErrorResponse(w, ErrNoSuchBucket, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } // Ignore delete object errors while replying to client, since we are suppposed to reply only 204. diff --git a/cmd/object-handlers_test.go b/cmd/object-handlers_test.go index af7db210c..38858757b 100644 --- a/cmd/object-handlers_test.go +++ b/cmd/object-handlers_test.go @@ -2640,7 +2640,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s accessKey: credentials.AccessKey, secretKey: credentials.SecretKey, - expectedContent: encodeResponse(getAPIErrorResponse(getAPIError(toAPIErrorCode(ctx, InvalidPart{})), + expectedContent: encodeResponse(getAPIErrorResponse(toAPIError(ctx, InvalidPart{}), getGetObjectURL("", bucketName, objectName), "")), expectedRespStatus: http.StatusBadRequest, }, @@ -2670,7 +2670,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s accessKey: credentials.AccessKey, secretKey: credentials.SecretKey, - expectedContent: encodeResponse(getAPIErrorResponse(getAPIError(toAPIErrorCode(ctx, InvalidUploadID{UploadID: "abc"})), + expectedContent: encodeResponse(getAPIErrorResponse(toAPIError(ctx, InvalidUploadID{UploadID: "abc"}), getGetObjectURL("", bucketName, objectName), "")), expectedRespStatus: http.StatusNotFound, }, @@ -2685,7 +2685,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s secretKey: credentials.SecretKey, expectedContent: encodeResponse(completeMultipartAPIError{int64(4), int64(5242880), 1, "e2fc714c4727ee9395f324cd2e7f331f", - getAPIErrorResponse(getAPIError(toAPIErrorCode(ctx, PartTooSmall{PartNumber: 1})), + getAPIErrorResponse(toAPIError(ctx, PartTooSmall{PartNumber: 1}), getGetObjectURL("", bucketName, objectName), "")}), expectedRespStatus: http.StatusBadRequest, }, @@ -2699,7 +2699,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s accessKey: credentials.AccessKey, secretKey: credentials.SecretKey, - expectedContent: encodeResponse(getAPIErrorResponse(getAPIError(toAPIErrorCode(ctx, InvalidPart{})), + expectedContent: encodeResponse(getAPIErrorResponse(toAPIError(ctx, InvalidPart{}), getGetObjectURL("", bucketName, objectName), "")), expectedRespStatus: http.StatusBadRequest, }, diff --git a/cmd/signature-v4-parser_test.go b/cmd/signature-v4-parser_test.go index 712864874..865756da5 100644 --- a/cmd/signature-v4-parser_test.go +++ b/cmd/signature-v4-parser_test.go @@ -222,7 +222,7 @@ func TestParseCredentialHeader(t *testing.T) { actualCredential, actualErrCode := parseCredentialHeader(testCase.inputCredentialStr, "us-west-1") // validating the credential fields. if testCase.expectedErrCode != actualErrCode { - t.Fatalf("Test %d: Expected the APIErrCode to be %s, got %s", i+1, errorCodeResponse[testCase.expectedErrCode].Code, errorCodeResponse[actualErrCode].Code) + t.Fatalf("Test %d: Expected the APIErrCode to be %s, got %s", i+1, errorCodes[testCase.expectedErrCode].Code, errorCodes[actualErrCode].Code) } if actualErrCode == ErrNone { validateCredentialfields(t, i+1, testCase.expectedCredentials, actualCredential) diff --git a/cmd/signature-v4_test.go b/cmd/signature-v4_test.go index 96f515d2d..5be80ad54 100644 --- a/cmd/signature-v4_test.go +++ b/cmd/signature-v4_test.go @@ -31,7 +31,7 @@ func niceError(code APIErrorCode) string { return "ErrNone" } - return fmt.Sprintf("%s (%s)", errorCodeResponse[code].Code, errorCodeResponse[code].Description) + return fmt.Sprintf("%s (%s)", errorCodes[code].Code, errorCodes[code].Description) } func TestDoesPolicySignatureMatch(t *testing.T) { diff --git a/cmd/test-utils_test.go b/cmd/test-utils_test.go index bc0db1362..9bbb2ecf7 100644 --- a/cmd/test-utils_test.go +++ b/cmd/test-utils_test.go @@ -2357,8 +2357,8 @@ func TestToErrIsNil(t *testing.T) { t.Errorf("Test expected to return nil, failed instead got a non-nil value %s", toStorageErr(nil)) } ctx := context.Background() - if toAPIErrorCode(ctx, nil) != ErrNone { - t.Errorf("Test expected error code to be ErrNone, failed instead provided %d", toAPIErrorCode(ctx, nil)) + if toAPIError(ctx, nil) != noError { + t.Errorf("Test expected error code to be ErrNone, failed instead provided %s", toAPIError(ctx, nil).Code) } } diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index 02b122ad9..afec74ceb 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -894,7 +894,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { // Extract incoming metadata if any. metadata, err := extractMetadata(context.Background(), r) if err != nil { - writeErrorResponse(w, ErrInternalError, r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } @@ -943,7 +943,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { var opts ObjectOptions opts, err = putOpts(ctx, r, bucket, object, metadata) if err != nil { - writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) return } if objectAPI.IsEncryptionSupported() { @@ -952,13 +952,13 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { var objectEncryptionKey []byte reader, objectEncryptionKey, err = EncryptRequest(hashReader, r, bucket, object, metadata) if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } info := ObjectInfo{Size: size} hashReader, err = hash.NewReader(reader, info.EncryptedSize(), "", "", size) // do not try to verify encrypted content if err != nil { - writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } pReader = NewPutObjReader(rawReader, hashReader, objectEncryptionKey)