mirror of
https://github.com/pgsty/minio.git
synced 2026-07-21 13:10:22 +03:00
web: Add more data for jsonrpc responses. (#3296)
This change adds more richer error response
for JSON-RPC by interpreting object layer
errors to corresponding meaningful errors
for the web browser.
```go
&json2.Error{
Message: "Bucket Name Invalid, Only lowercase letters, full stops, and numbers are allowed.",
}
```
Additionally this patch also allows PresignedGetObject()
to take expiry parameter to have variable expiry.
This commit is contained in:
+182
-121
@@ -19,6 +19,7 @@ package cmd
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -41,7 +42,7 @@ import (
|
||||
// isJWTReqAuthenticated validates if any incoming request to be a
|
||||
// valid JWT authenticated request.
|
||||
func isJWTReqAuthenticated(req *http.Request) bool {
|
||||
jwt, err := newJWT(defaultJWTExpiry)
|
||||
jwt, err := newJWT(defaultJWTExpiry, serverConfig.GetCredential())
|
||||
if err != nil {
|
||||
errorIf(err, "unable to initialize a new JWT")
|
||||
return false
|
||||
@@ -85,7 +86,7 @@ type ServerInfoRep struct {
|
||||
// ServerInfo - get server info.
|
||||
func (web *webAPIHandlers) ServerInfo(r *http.Request, args *WebGenericArgs, reply *ServerInfoRep) error {
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
host, err := os.Hostname()
|
||||
if err != nil {
|
||||
@@ -123,10 +124,10 @@ type StorageInfoRep struct {
|
||||
func (web *webAPIHandlers) StorageInfo(r *http.Request, args *GenericArgs, reply *StorageInfoRep) error {
|
||||
objectAPI := web.ObjectAPI()
|
||||
if objectAPI == nil {
|
||||
return &json2.Error{Message: errServerNotInitialized.Error()}
|
||||
return toJSONError(errServerNotInitialized)
|
||||
}
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
reply.StorageInfo = objectAPI.StorageInfo()
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
@@ -142,13 +143,13 @@ type MakeBucketArgs struct {
|
||||
func (web *webAPIHandlers) MakeBucket(r *http.Request, args *MakeBucketArgs, reply *WebGenericRep) error {
|
||||
objectAPI := web.ObjectAPI()
|
||||
if objectAPI == nil {
|
||||
return &json2.Error{Message: errServerNotInitialized.Error()}
|
||||
return toJSONError(errServerNotInitialized)
|
||||
}
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
if err := objectAPI.MakeBucket(args.BucketName); err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err, args.BucketName)
|
||||
}
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
return nil
|
||||
@@ -172,14 +173,14 @@ type WebBucketInfo struct {
|
||||
func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, reply *ListBucketsRep) error {
|
||||
objectAPI := web.ObjectAPI()
|
||||
if objectAPI == nil {
|
||||
return &json2.Error{Message: errServerNotInitialized.Error()}
|
||||
return toJSONError(errServerNotInitialized)
|
||||
}
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
buckets, err := objectAPI.ListBuckets()
|
||||
if err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err)
|
||||
}
|
||||
for _, bucket := range buckets {
|
||||
// List all buckets which are not private.
|
||||
@@ -222,12 +223,12 @@ type WebObjectInfo struct {
|
||||
func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, reply *ListObjectsRep) error {
|
||||
objectAPI := web.ObjectAPI()
|
||||
if objectAPI == nil {
|
||||
return &json2.Error{Message: errServerNotInitialized.Error()}
|
||||
return toJSONError(errServerNotInitialized)
|
||||
}
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
marker := ""
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
}
|
||||
for {
|
||||
lo, err := objectAPI.ListObjects(args.BucketName, args.Prefix, marker, "/", 1000)
|
||||
if err != nil {
|
||||
@@ -266,10 +267,10 @@ type RemoveObjectArgs struct {
|
||||
func (web *webAPIHandlers) RemoveObject(r *http.Request, args *RemoveObjectArgs, reply *WebGenericRep) error {
|
||||
objectAPI := web.ObjectAPI()
|
||||
if objectAPI == nil {
|
||||
return &json2.Error{Message: errServerNotInitialized.Error()}
|
||||
return toJSONError(errServerNotInitialized)
|
||||
}
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
if err := objectAPI.DeleteObject(args.BucketName, args.ObjectName); err != nil {
|
||||
if isErrObjectNotFound(err) {
|
||||
@@ -277,7 +278,7 @@ func (web *webAPIHandlers) RemoveObject(r *http.Request, args *RemoveObjectArgs,
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
return nil
|
||||
}
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err, args.BucketName, args.ObjectName)
|
||||
}
|
||||
|
||||
// Notify object deleted event.
|
||||
@@ -310,18 +311,18 @@ type LoginRep struct {
|
||||
|
||||
// Login - user login handler.
|
||||
func (web *webAPIHandlers) Login(r *http.Request, args *LoginArgs, reply *LoginRep) error {
|
||||
jwt, err := newJWT(defaultJWTExpiry)
|
||||
jwt, err := newJWT(defaultJWTExpiry, serverConfig.GetCredential())
|
||||
if err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err)
|
||||
}
|
||||
|
||||
if err = jwt.Authenticate(args.Username, args.Password); err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err)
|
||||
}
|
||||
|
||||
token, err := jwt.GenerateToken(args.Username)
|
||||
if err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err)
|
||||
}
|
||||
reply.Token = token
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
@@ -337,7 +338,7 @@ type GenerateAuthReply struct {
|
||||
|
||||
func (web webAPIHandlers) GenerateAuth(r *http.Request, args *WebGenericArgs, reply *GenerateAuthReply) error {
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
cred := mustGenAccessKeys()
|
||||
reply.AccessKey = cred.AccessKeyID
|
||||
@@ -362,34 +363,46 @@ type SetAuthReply struct {
|
||||
// SetAuth - Set accessKey and secretKey credentials.
|
||||
func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *SetAuthReply) error {
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
if !isValidAccessKey(args.AccessKey) {
|
||||
return &json2.Error{Message: errInvalidAccessKeyLength.Error()}
|
||||
|
||||
// Initialize jwt with the new access keys, fail if not possible.
|
||||
jwt, err := newJWT(defaultJWTExpiry, credential{
|
||||
AccessKeyID: args.AccessKey,
|
||||
SecretAccessKey: args.SecretKey,
|
||||
}) // JWT Expiry set to 24Hrs.
|
||||
if err != nil {
|
||||
return toJSONError(err)
|
||||
}
|
||||
if !isValidSecretKey(args.SecretKey) {
|
||||
return &json2.Error{Message: errInvalidSecretKeyLength.Error()}
|
||||
|
||||
// Authenticate the secret key properly.
|
||||
if err = jwt.Authenticate(args.AccessKey, args.SecretKey); err != nil {
|
||||
return toJSONError(err)
|
||||
|
||||
}
|
||||
|
||||
unexpErrsMsg := "Unexpected error(s) occurred - please check minio server logs."
|
||||
gaveUpMsg := func(errMsg error, moreErrors bool) *json2.Error {
|
||||
msg := fmt.Sprintf(
|
||||
"We gave up due to: '%s', but there were more errors. Please check minio server logs.",
|
||||
errMsg.Error(),
|
||||
)
|
||||
var err *json2.Error
|
||||
if moreErrors {
|
||||
err = toJSONError(errors.New(msg))
|
||||
} else {
|
||||
err = toJSONError(errMsg)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
cred := credential{args.AccessKey, args.SecretKey}
|
||||
unexpErrsMsg := "ALERT: Unexpected error(s) happened - please check the server logs."
|
||||
gaveUpMsg := func(errMsg error, moreErrors bool) *json2.Error {
|
||||
msg := fmt.Sprintf(
|
||||
"ALERT: We gave up due to: '%s', but there were more errors. Please check the server logs.",
|
||||
errMsg.Error(),
|
||||
)
|
||||
if moreErrors {
|
||||
return &json2.Error{Message: msg}
|
||||
}
|
||||
return &json2.Error{Message: errMsg.Error()}
|
||||
}
|
||||
|
||||
// Notify all other Minio peers to update credentials
|
||||
errsMap := updateCredsOnPeers(cred)
|
||||
|
||||
// Update local credentials
|
||||
serverConfig.SetCredential(cred)
|
||||
if err := serverConfig.Save(); err != nil {
|
||||
if err = serverConfig.Save(); err != nil {
|
||||
errsMap[globalMinioAddr] = err
|
||||
}
|
||||
|
||||
@@ -407,7 +420,7 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se
|
||||
// Since the error message may be very long to display
|
||||
// on the browser, we tell the user to check the
|
||||
// server logs.
|
||||
return &json2.Error{Message: unexpErrsMsg}
|
||||
return toJSONError(errors.New(unexpErrsMsg))
|
||||
}
|
||||
|
||||
// Did we have peer errors?
|
||||
@@ -416,16 +429,7 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se
|
||||
moreErrors = true
|
||||
}
|
||||
|
||||
// If we were able to update locally, we try to generate a new
|
||||
// token and complete the request.
|
||||
jwt, err := newJWT(defaultJWTExpiry) // JWT Expiry set to 24Hrs.
|
||||
if err != nil {
|
||||
return gaveUpMsg(err, moreErrors)
|
||||
}
|
||||
|
||||
if err = jwt.Authenticate(args.AccessKey, args.SecretKey); err != nil {
|
||||
return gaveUpMsg(err, moreErrors)
|
||||
}
|
||||
// Generate a JWT token.
|
||||
token, err := jwt.GenerateToken(args.AccessKey)
|
||||
if err != nil {
|
||||
return gaveUpMsg(err, moreErrors)
|
||||
@@ -446,7 +450,7 @@ type GetAuthReply struct {
|
||||
// GetAuth - return accessKey and secretKey credentials.
|
||||
func (web *webAPIHandlers) GetAuth(r *http.Request, args *WebGenericArgs, reply *GetAuthReply) error {
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
creds := serverConfig.GetCredential()
|
||||
reply.AccessKey = creds.AccessKeyID
|
||||
@@ -511,7 +515,7 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
||||
object := vars["object"]
|
||||
tokenStr := r.URL.Query().Get("token")
|
||||
|
||||
jwt, err := newJWT(defaultJWTExpiry) // Expiry set to 24Hrs.
|
||||
jwt, err := newJWT(defaultJWTExpiry, serverConfig.GetCredential()) // Expiry set to 24Hrs.
|
||||
if err != nil {
|
||||
errorIf(err, "error in getting new JWT")
|
||||
return
|
||||
@@ -543,50 +547,6 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// writeWebErrorResponse - set HTTP status code and write error description to the body.
|
||||
func writeWebErrorResponse(w http.ResponseWriter, err error) {
|
||||
if err == errAuthentication {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
if err == errServerNotInitialized {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// Convert error type to api error code.
|
||||
var apiErrCode APIErrorCode
|
||||
switch err.(type) {
|
||||
case StorageFull:
|
||||
apiErrCode = ErrStorageFull
|
||||
case BucketNotFound:
|
||||
apiErrCode = ErrNoSuchBucket
|
||||
case BucketNameInvalid:
|
||||
apiErrCode = ErrInvalidBucketName
|
||||
case BadDigest:
|
||||
apiErrCode = ErrBadDigest
|
||||
case IncompleteBody:
|
||||
apiErrCode = ErrIncompleteBody
|
||||
case ObjectExistsAsDirectory:
|
||||
apiErrCode = ErrObjectExistsAsDirectory
|
||||
case ObjectNotFound:
|
||||
apiErrCode = ErrNoSuchKey
|
||||
case ObjectNameInvalid:
|
||||
apiErrCode = ErrNoSuchKey
|
||||
case InsufficientWriteQuorum:
|
||||
apiErrCode = ErrWriteQuorum
|
||||
case InsufficientReadQuorum:
|
||||
apiErrCode = ErrReadQuorum
|
||||
default:
|
||||
apiErrCode = ErrInternalError
|
||||
}
|
||||
apiErr := getAPIError(apiErrCode)
|
||||
w.WriteHeader(apiErr.HTTPStatusCode)
|
||||
w.Write([]byte(apiErr.Description))
|
||||
}
|
||||
|
||||
// GetBucketPolicyArgs - get bucket policy args.
|
||||
type GetBucketPolicyArgs struct {
|
||||
BucketName string `json:"bucketName"`
|
||||
@@ -627,16 +587,16 @@ func readBucketAccessPolicy(objAPI ObjectLayer, bucketName string) (policy.Bucke
|
||||
func (web *webAPIHandlers) GetBucketPolicy(r *http.Request, args *GetBucketPolicyArgs, reply *GetBucketPolicyRep) error {
|
||||
objectAPI := web.ObjectAPI()
|
||||
if objectAPI == nil {
|
||||
return &json2.Error{Message: errServerNotInitialized.Error()}
|
||||
return toJSONError(errServerNotInitialized)
|
||||
}
|
||||
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
|
||||
policyInfo, err := readBucketAccessPolicy(objectAPI, args.BucketName)
|
||||
if err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err, args.BucketName)
|
||||
}
|
||||
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
@@ -666,16 +626,16 @@ type ListAllBucketPoliciesRep struct {
|
||||
func (web *webAPIHandlers) ListAllBucketPolicies(r *http.Request, args *ListAllBucketPoliciesArgs, reply *ListAllBucketPoliciesRep) error {
|
||||
objectAPI := web.ObjectAPI()
|
||||
if objectAPI == nil {
|
||||
return &json2.Error{Message: errServerNotInitialized.Error()}
|
||||
return toJSONError(errServerNotInitialized)
|
||||
}
|
||||
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
|
||||
policyInfo, err := readBucketAccessPolicy(objectAPI, args.BucketName)
|
||||
if err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err, args.BucketName)
|
||||
}
|
||||
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
@@ -699,33 +659,36 @@ type SetBucketPolicyArgs struct {
|
||||
func (web *webAPIHandlers) SetBucketPolicy(r *http.Request, args *SetBucketPolicyArgs, reply *WebGenericRep) error {
|
||||
objectAPI := web.ObjectAPI()
|
||||
if objectAPI == nil {
|
||||
return &json2.Error{Message: errServerNotInitialized.Error()}
|
||||
return toJSONError(errServerNotInitialized)
|
||||
}
|
||||
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
|
||||
bucketP := policy.BucketPolicy(args.Policy)
|
||||
if !bucketP.IsValidBucketPolicy() {
|
||||
return &json2.Error{Message: "Invalid policy type " + args.Policy}
|
||||
return &json2.Error{
|
||||
Message: "Invalid policy type " + args.Policy,
|
||||
}
|
||||
}
|
||||
|
||||
policyInfo, err := readBucketAccessPolicy(objectAPI, args.BucketName)
|
||||
if err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err, args.BucketName)
|
||||
}
|
||||
policyInfo.Statements = policy.SetPolicy(policyInfo.Statements, bucketP, args.BucketName, args.Prefix)
|
||||
if len(policyInfo.Statements) == 0 {
|
||||
if err = persistAndNotifyBucketPolicyChange(args.BucketName, policyChange{true, nil}, objectAPI); err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
err = persistAndNotifyBucketPolicyChange(args.BucketName, policyChange{true, nil}, objectAPI)
|
||||
if err != nil {
|
||||
return toJSONError(err, args.BucketName)
|
||||
}
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
return nil
|
||||
}
|
||||
data, err := json.Marshal(policyInfo)
|
||||
if err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err)
|
||||
}
|
||||
|
||||
// Parse bucket policy.
|
||||
@@ -733,18 +696,19 @@ func (web *webAPIHandlers) SetBucketPolicy(r *http.Request, args *SetBucketPolic
|
||||
err = parseBucketPolicy(bytes.NewReader(data), policy)
|
||||
if err != nil {
|
||||
errorIf(err, "Unable to parse bucket policy.")
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err)
|
||||
}
|
||||
|
||||
// Parse check bucket policy.
|
||||
if s3Error := checkBucketPolicyResources(args.BucketName, policy); s3Error != ErrNone {
|
||||
return &json2.Error{Message: getAPIError(s3Error).Description}
|
||||
apiErr := getAPIError(s3Error)
|
||||
return toJSONError(errors.New(apiErr.Description), args.BucketName)
|
||||
}
|
||||
|
||||
// TODO: update policy statements according to bucket name,
|
||||
// prefix and policy arguments.
|
||||
if err := persistAndNotifyBucketPolicyChange(args.BucketName, policyChange{false, policy}, objectAPI); err != nil {
|
||||
return &json2.Error{Message: err.Error()}
|
||||
return toJSONError(err, args.BucketName)
|
||||
}
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
return nil
|
||||
@@ -760,6 +724,9 @@ type PresignedGetArgs struct {
|
||||
|
||||
// Object name to be presigned.
|
||||
ObjectName string `json:"object"`
|
||||
|
||||
// Expiry in seconds.
|
||||
Expiry int64 `json:"expiry"`
|
||||
}
|
||||
|
||||
// PresignedGetRep - presigned-get URL reply.
|
||||
@@ -771,22 +738,22 @@ type PresignedGetRep struct {
|
||||
|
||||
// PresignedGET - returns presigned-Get url.
|
||||
func (web *webAPIHandlers) PresignedGet(r *http.Request, args *PresignedGetArgs, reply *PresignedGetRep) error {
|
||||
if web.ObjectAPI() == nil {
|
||||
return &json2.Error{Message: errServerNotInitialized.Error()}
|
||||
}
|
||||
if !isJWTReqAuthenticated(r) {
|
||||
return &json2.Error{Message: errAuthentication.Error()}
|
||||
return toJSONError(errAuthentication)
|
||||
}
|
||||
|
||||
if args.BucketName == "" || args.ObjectName == "" {
|
||||
return &json2.Error{Message: "Bucket, Object are mandatory arguments."}
|
||||
return &json2.Error{
|
||||
Message: "Bucket and Object are mandatory arguments.",
|
||||
}
|
||||
}
|
||||
reply.UIVersion = miniobrowser.UIVersion
|
||||
reply.URL = presignedGet(args.HostName, args.BucketName, args.ObjectName)
|
||||
reply.URL = presignedGet(args.HostName, args.BucketName, args.ObjectName, args.Expiry)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns presigned url for GET method.
|
||||
func presignedGet(host, bucket, object string) string {
|
||||
func presignedGet(host, bucket, object string, expiry int64) string {
|
||||
cred := serverConfig.GetCredential()
|
||||
region := serverConfig.GetRegion()
|
||||
|
||||
@@ -797,11 +764,15 @@ func presignedGet(host, bucket, object string) string {
|
||||
dateStr := date.Format(iso8601Format)
|
||||
credential := fmt.Sprintf("%s/%s", accessKey, getScope(date, region))
|
||||
|
||||
var expiryStr = "604800" // Default set to be expire in 7days.
|
||||
if expiry < 604800 && expiry > 0 {
|
||||
expiryStr = strconv.FormatInt(expiry, 10)
|
||||
}
|
||||
query := strings.Join([]string{
|
||||
"X-Amz-Algorithm=" + signV4Algorithm,
|
||||
"X-Amz-Credential=" + strings.Replace(credential, "/", "%2F", -1),
|
||||
"X-Amz-Date=" + dateStr,
|
||||
"X-Amz-Expires=" + "604800", // Default set to be expire in 7days.
|
||||
"X-Amz-Expires=" + expiryStr,
|
||||
"X-Amz-SignedHeaders=host",
|
||||
}, "&")
|
||||
|
||||
@@ -818,3 +789,93 @@ func presignedGet(host, bucket, object string) string {
|
||||
// Construct the final presigned URL.
|
||||
return host + path + "?" + query + "&" + "X-Amz-Signature=" + signature
|
||||
}
|
||||
|
||||
// toJSONError converts regular errors into more user friendly
|
||||
// and consumable error message for the browser UI.
|
||||
func toJSONError(err error, params ...string) (jerr *json2.Error) {
|
||||
apiErr := toWebAPIError(err)
|
||||
jerr = &json2.Error{
|
||||
Message: apiErr.Description,
|
||||
}
|
||||
switch apiErr.Code {
|
||||
// Bucket name invalid with custom error message.
|
||||
case "InvalidBucketName":
|
||||
if len(params) > 0 {
|
||||
jerr = &json2.Error{
|
||||
Message: fmt.Sprintf("Bucket Name %s is invalid. Lowercase letters, period and numerals are the only allowed characters.",
|
||||
params[0]),
|
||||
}
|
||||
}
|
||||
// Bucket not found custom error message.
|
||||
case "NoSuchBucket":
|
||||
if len(params) > 0 {
|
||||
jerr = &json2.Error{
|
||||
Message: fmt.Sprintf("The specified bucket %s does not exist.", params[0]),
|
||||
}
|
||||
}
|
||||
// Object not found custom error message.
|
||||
case "NoSuchKey":
|
||||
if len(params) > 1 {
|
||||
jerr = &json2.Error{
|
||||
Message: fmt.Sprintf("The specified key %s does not exist", params[1]),
|
||||
}
|
||||
}
|
||||
// Add more custom error messages here with more context.
|
||||
}
|
||||
return jerr
|
||||
}
|
||||
|
||||
// toWebAPIError - convert into error into APIError.
|
||||
func toWebAPIError(err error) APIError {
|
||||
err = errorCause(err)
|
||||
if err == errAuthentication {
|
||||
return APIError{
|
||||
Code: "AccessDenied",
|
||||
HTTPStatusCode: http.StatusForbidden,
|
||||
Description: err.Error(),
|
||||
}
|
||||
}
|
||||
if err == errServerNotInitialized {
|
||||
return APIError{
|
||||
Code: "XMinioServerNotInitialized",
|
||||
HTTPStatusCode: http.StatusServiceUnavailable,
|
||||
Description: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
// Convert error type to api error code.
|
||||
var apiErrCode APIErrorCode
|
||||
switch err.(type) {
|
||||
case StorageFull:
|
||||
apiErrCode = ErrStorageFull
|
||||
case BucketNotFound:
|
||||
apiErrCode = ErrNoSuchBucket
|
||||
case BucketNameInvalid:
|
||||
apiErrCode = ErrInvalidBucketName
|
||||
case BadDigest:
|
||||
apiErrCode = ErrBadDigest
|
||||
case IncompleteBody:
|
||||
apiErrCode = ErrIncompleteBody
|
||||
case ObjectExistsAsDirectory:
|
||||
apiErrCode = ErrObjectExistsAsDirectory
|
||||
case ObjectNotFound:
|
||||
apiErrCode = ErrNoSuchKey
|
||||
case ObjectNameInvalid:
|
||||
apiErrCode = ErrNoSuchKey
|
||||
case InsufficientWriteQuorum:
|
||||
apiErrCode = ErrWriteQuorum
|
||||
case InsufficientReadQuorum:
|
||||
apiErrCode = ErrReadQuorum
|
||||
default:
|
||||
apiErrCode = ErrInternalError
|
||||
}
|
||||
apiErr := getAPIError(apiErrCode)
|
||||
return apiErr
|
||||
}
|
||||
|
||||
// writeWebErrorResponse - set HTTP status code and write error description to the body.
|
||||
func writeWebErrorResponse(w http.ResponseWriter, err error) {
|
||||
apiErr := toWebAPIError(err)
|
||||
w.WriteHeader(apiErr.HTTPStatusCode)
|
||||
w.Write([]byte(apiErr.Description))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user