mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-13 03:24:26 +00:00
fix(api): return correct http code on assets api (#6388)
* fix(api): return correct http code on assets api * add test * fix test
This commit is contained in:
parent
8b44794c75
commit
69b49ac0ed
@ -42,7 +42,7 @@ func (h *Handler) Commands() *command.Commands {
|
||||
}
|
||||
|
||||
func (h *Handler) ErrorHandler() ErrorHandler {
|
||||
return DefaultErrorHandler
|
||||
return h.errorHandler
|
||||
}
|
||||
|
||||
func (h *Handler) Storage() static.Storage {
|
||||
@ -75,10 +75,14 @@ type Downloader interface {
|
||||
ResourceOwner(ctx context.Context, ownerPath string) string
|
||||
}
|
||||
|
||||
type ErrorHandler func(http.ResponseWriter, *http.Request, error, int)
|
||||
type ErrorHandler func(w http.ResponseWriter, r *http.Request, err error, defaultCode int)
|
||||
|
||||
func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error, code int) {
|
||||
func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error, defaultCode int) {
|
||||
logging.WithFields("uri", r.RequestURI).WithError(err).Warn("error occurred on asset api")
|
||||
code, ok := http_util.ZitadelErrorToHTTPStatusCode(err)
|
||||
if !ok {
|
||||
code = defaultCode
|
||||
}
|
||||
http.Error(w, err.Error(), code)
|
||||
}
|
||||
|
||||
@ -162,7 +166,7 @@ func UploadHandleFunc(s AssetsService, uploader Uploader) func(http.ResponseWrit
|
||||
}
|
||||
err = uploader.UploadAsset(ctx, ctxData.OrgID, uploadInfo, s.Commands())
|
||||
if err != nil {
|
||||
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
|
||||
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %w", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -190,10 +194,6 @@ func DownloadHandleFunc(s AssetsService, downloader Downloader) func(http.Respon
|
||||
return
|
||||
}
|
||||
if err = GetAsset(w, r, resourceOwner, objectName, s.Storage()); err != nil {
|
||||
if strings.Contains(err.Error(), "DATAB-pCP8P") {
|
||||
s.ErrorHandler()(w, r, err, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
s.ErrorHandler()(w, r, err, http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
@ -206,11 +206,11 @@ func GetAsset(w http.ResponseWriter, r *http.Request, resourceOwner, objectName
|
||||
}
|
||||
data, getInfo, err := storage.GetObject(r.Context(), authz.GetInstance(r.Context()).InstanceID(), resourceOwner, objectName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("download failed: %v", err)
|
||||
return fmt.Errorf("download failed: %w", err)
|
||||
}
|
||||
info, err := getInfo()
|
||||
if err != nil {
|
||||
return fmt.Errorf("download failed: %v", err)
|
||||
return fmt.Errorf("download failed: %w", err)
|
||||
}
|
||||
if info.Hash == strings.Trim(r.Header.Get(http_util.IfNoneMatch), "\"") {
|
||||
w.Header().Set(http_util.LastModified, info.LastModified.Format(time.RFC1123))
|
||||
|
47
internal/api/http/error.go
Normal file
47
internal/api/http/error.go
Normal file
@ -0,0 +1,47 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
func ZitadelErrorToHTTPStatusCode(err error) (statusCode int, ok bool) {
|
||||
if err == nil {
|
||||
return http.StatusOK, true
|
||||
}
|
||||
//nolint:errorlint
|
||||
switch err.(type) {
|
||||
case *caos_errs.AlreadyExistsError:
|
||||
return http.StatusConflict, true
|
||||
case *caos_errs.DeadlineExceededError:
|
||||
return http.StatusGatewayTimeout, true
|
||||
case *caos_errs.InternalError:
|
||||
return http.StatusInternalServerError, true
|
||||
case *caos_errs.InvalidArgumentError:
|
||||
return http.StatusBadRequest, true
|
||||
case *caos_errs.NotFoundError:
|
||||
return http.StatusNotFound, true
|
||||
case *caos_errs.PermissionDeniedError:
|
||||
return http.StatusForbidden, true
|
||||
case *caos_errs.PreconditionFailedError:
|
||||
// use the same code as grpc-gateway:
|
||||
// https://github.com/grpc-ecosystem/grpc-gateway/blob/9e33e38f15cb7d2f11096366e62ea391a3459ba9/runtime/errors.go#L59
|
||||
return http.StatusBadRequest, true
|
||||
case *caos_errs.UnauthenticatedError:
|
||||
return http.StatusUnauthorized, true
|
||||
case *caos_errs.UnavailableError:
|
||||
return http.StatusServiceUnavailable, true
|
||||
case *caos_errs.UnimplementedError:
|
||||
return http.StatusNotImplemented, true
|
||||
case *caos_errs.ResourceExhaustedError:
|
||||
return http.StatusTooManyRequests, true
|
||||
default:
|
||||
c := new(caos_errs.CaosError)
|
||||
if errors.As(err, &c) {
|
||||
return ZitadelErrorToHTTPStatusCode(errors.Unwrap(err))
|
||||
}
|
||||
return http.StatusInternalServerError, false
|
||||
}
|
||||
}
|
138
internal/api/http/error_test.go
Normal file
138
internal/api/http/error_test.go
Normal file
@ -0,0 +1,138 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
caos_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
func TestZitadelErrorToHTTPStatusCode(t *testing.T) {
|
||||
type args struct {
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantStatusCode int
|
||||
wantOk bool
|
||||
}{
|
||||
{
|
||||
name: "no error",
|
||||
args: args{
|
||||
err: nil,
|
||||
},
|
||||
wantStatusCode: http.StatusOK,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped already exists",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowAlreadyExists(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusConflict,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped deadline exceeded",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowDeadlineExceeded(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusGatewayTimeout,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped internal",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowInternal(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusInternalServerError,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped invalid argument",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowInvalidArgument(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusBadRequest,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped not found",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowNotFound(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusNotFound,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped permission denied",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowPermissionDenied(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusForbidden,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped precondition failed",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowPreconditionFailed(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusBadRequest,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped unauthenticated",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowUnauthenticated(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusUnauthorized,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped unavailable",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowUnavailable(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusServiceUnavailable,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped unimplemented",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowUnimplemented(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusNotImplemented,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "wrapped resource exhausted",
|
||||
args: args{
|
||||
err: fmt.Errorf("wrapped %w", caos_errors.ThrowResourceExhausted(nil, "id", "message")),
|
||||
},
|
||||
wantStatusCode: http.StatusTooManyRequests,
|
||||
wantOk: true,
|
||||
},
|
||||
{
|
||||
name: "no caos/zitadel error",
|
||||
args: args{
|
||||
err: errors.New("error"),
|
||||
},
|
||||
wantStatusCode: http.StatusInternalServerError,
|
||||
wantOk: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotStatusCode, gotOk := ZitadelErrorToHTTPStatusCode(tt.args.err)
|
||||
if gotStatusCode != tt.wantStatusCode {
|
||||
t.Errorf("ZitadelErrorToHTTPStatusCode() gotStatusCode = %v, want %v", gotStatusCode, tt.wantStatusCode)
|
||||
}
|
||||
if gotOk != tt.wantOk {
|
||||
t.Errorf("ZitadelErrorToHTTPStatusCode() gotOk = %v, want %v", gotOk, tt.wantOk)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user