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)