frostfs-http-gw/internal/handler/utils.go
Roman Loginov ce04b0836a [#187] Fix handling ErrAccessDenied and ErrGatewayTimeout
If an Access Denied error occurs, we should
return 403 Forbidden instead of 400 Bad Request.
Gateway Timeout error we also need to process
and return the 504 Gateway Timeout code.

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

118 lines
2.8 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 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)
}