frostfs-http-gw/internal/handler/utils.go
Roman Loginov ed69ccfd5d [#187] Add handling quota limit reached error
The Access Denied status may be received
from APE due to exceeding the quota. In
this situation, you need to return the
appropriate status code.

Signed-off-by: Roman Loginov <r.loginov@yadro.com>
2024-12-25 16:37:21 +03:00

121 lines
2.9 KiB
Go

package handler
import (
"context"
"errors"
"fmt"
"strings"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/tokens"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
)
type request struct {
*fasthttp.RequestCtx
log *zap.Logger
}
func (r *request) handleFrostFSErr(err error, start time.Time) {
logFields := []zap.Field{
zap.Stringer("elapsed", time.Since(start)),
zap.Error(err),
}
statusCode, msg := formErrorResponse("could not receive object", err)
r.log.Error(logs.CouldNotReceiveObject, logFields...)
ResponseError(r.RequestCtx, msg, statusCode)
}
func bearerToken(ctx context.Context) *bearer.Token {
if tkn, err := tokens.LoadBearerToken(ctx); err == nil {
return tkn
}
return nil
}
func isDir(name string) bool {
return name == "" || strings.HasSuffix(name, "/")
}
func loadAttributes(attrs []object.Attribute) map[string]string {
result := make(map[string]string)
for _, attr := range attrs {
result[attr.Key()] = attr.Value()
}
return result
}
func isValidToken(s string) bool {
for _, c := range s {
if c <= ' ' || c > 127 {
return false
}
if strings.ContainsRune("()<>@,;:\\\"/[]?={}", c) {
return false
}
}
return true
}
func isValidValue(s string) bool {
for _, c := range s {
// HTTP specification allows for more technically, but we don't want to escape things.
if c < ' ' || c > 127 || c == '"' {
return false
}
}
return true
}
func logAndSendBucketError(c *fasthttp.RequestCtx, log *zap.Logger, err error) {
statusCode, msg := formErrorResponse("could not get bucket", err)
log.Error(logs.CouldntGetBucket, zap.Error(err))
ResponseError(c, msg, statusCode)
}
func newAddress(cnr cid.ID, obj oid.ID) oid.Address {
var addr oid.Address
addr.SetContainer(cnr)
addr.SetObject(obj)
return addr
}
func ResponseError(r *fasthttp.RequestCtx, msg string, code int) {
r.Error(msg+"\n", code)
}
func formErrorResponse(message string, err error) (int, string) {
var (
errMsg string
statusCode int
)
switch {
case errors.Is(err, ErrAccessDenied):
statusCode = fasthttp.StatusForbidden
errMsg = err.Error()
case errors.Is(err, ErrGatewayTimeout):
statusCode = fasthttp.StatusBadGateway
errMsg = err.Error()
case errors.Is(err, ErrQuotaLimitReached):
statusCode = fasthttp.StatusConflict
errMsg = err.Error()
case client.IsErrObjectNotFound(err) || client.IsErrContainerNotFound(err):
statusCode = fasthttp.StatusNotFound
errMsg = "Not Found"
default:
statusCode = fasthttp.StatusBadRequest
errMsg = err.Error()
}
return statusCode, fmt.Sprintf("%s: %s", message, errMsg)
}