Merge pull request #2182 from versity/sis/fiber-migration-v3

feat: migrate Fiber to v3.3.0
This commit is contained in:
Ben McClelland
2026-06-16 21:00:09 -07:00
committed by GitHub
83 changed files with 855 additions and 644 deletions
-2
View File
@@ -222,7 +222,6 @@ func TestVerifyObjectCopyAccess_URLEncodedSlashSeparator(t *testing.T) {
opts := AccessOptions{
Acl: ACL{Owner: testUser},
AclPermission: PermissionWrite,
IsRoot: false,
Acc: Account{Access: testUser, Role: RoleUser},
Bucket: "dst-bucket",
Object: "dst-key",
@@ -276,7 +275,6 @@ func TestVerifyObjectCopyAccess_LiteralSlashSeparator(t *testing.T) {
opts := AccessOptions{
Acl: ACL{Owner: testUser},
AclPermission: PermissionWrite,
IsRoot: false,
Acc: Account{Access: testUser, Role: RoleUser},
Bucket: "dst-bucket",
Object: "dst-key",
+108 -26
View File
@@ -22,7 +22,7 @@ import (
"strings"
"sync/atomic"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)
type Color string
@@ -40,9 +40,12 @@ const (
prefixInfo prefix = "[INFO]: "
prefixDebug prefix = "[DEBUG]: "
reset = "\033[0m"
borderChar = "─"
boxWidth = 120
reset = "\033[0m"
borderChar = "─"
boxWidth = 120
boxContentWidth = boxWidth - 4 // visible width between "│ " and " │"
minKeyColumnWidth = 13
keyValueSeparator = " : "
)
// Panic prints the panics out in the console
@@ -60,9 +63,9 @@ func printError(prefix prefix, er error) {
}
// Logs http request details: headers, body, params, query args
func LogFiberRequestDetails(ctx *fiber.Ctx) {
func LogFiberRequestDetails(ctx fiber.Ctx) {
// Log the full request url
fullURL := ctx.Protocol() + "://" + ctx.Hostname() + ctx.OriginalURL()
fullURL := ctx.Scheme() + "://" + ctx.Host() + ctx.OriginalURL()
fmt.Printf("%s[URL]: %s%s\n", green, fullURL, reset)
// log request headers
@@ -90,7 +93,7 @@ func LogFiberRequestDetails(ctx *fiber.Ctx) {
}
// Logs http response details: body, headers
func LogFiberResponseDetails(ctx *fiber.Ctx) {
func LogFiberResponseDetails(ctx fiber.Ctx) {
wrapInBox(green, "RESPONSE HEADERS", boxWidth, func() {
for key, value := range ctx.Response().Header.All() {
printWrappedLine(yellow, string(key), string(value))
@@ -213,11 +216,10 @@ func wrapInBox(color Color, title string, length int, fn func()) {
printHorizontalBorder(color, length, true)
}
// returns the provided string length
// defaulting to 13 for exceeding lengths
func getLen(str string) int {
if len(str) < 13 {
return 13
// paddedKeyLen returns the visible key column width used by printWrappedLine.
func paddedKeyLen(str string) int {
if len(str) < minKeyColumnWidth {
return minKeyColumnWidth
}
return len(str)
@@ -226,32 +228,112 @@ func getLen(str string) int {
// prints a formatted key-value pair within a box layout,
// wrapping the value text if it exceeds the allowed width.
func printWrappedLine(keyColor Color, key, value string) {
prefix := fmt.Sprintf("%s│%s %s%-13s%s : ", green, reset, keyColor, key, reset)
prefixLen := len(prefix) - len(green) - len(reset) - len(keyColor) - len(reset)
// the actual prefix size without colors
actualPrefixLen := getLen(key) + 5
keyLen := paddedKeyLen(key)
valueIndent := keyLen + len(keyValueSeparator)
lineWidth := boxContentWidth - valueIndent
if lineWidth < 1 {
printWrappedLongKeyLine(keyColor, key, value)
return
}
lineWidth := boxWidth - prefixLen
prefix := fmt.Sprintf("%s│%s %s%-*s%s%s", green, reset, keyColor, minKeyColumnWidth, key, reset, keyValueSeparator)
valueLines := wrapText(value, lineWidth)
if len(valueLines) == 0 {
valueLines = []string{""}
}
for i, line := range valueLines {
if i == 0 {
if len(line) < lineWidth {
line += strings.Repeat(" ", lineWidth-len(line))
}
line += rightPadding(line, lineWidth)
fmt.Printf("%s%s%s %s│%s\n", prefix, reset, line, green, reset)
} else {
line = strings.Repeat(" ", actualPrefixLen-2) + line
if len(line) < boxWidth-4 {
line += strings.Repeat(" ", boxWidth-len(line)-4)
}
line = spaces(valueIndent) + line
line += rightPadding(line, boxContentWidth)
fmt.Printf("%s│ %s%s %s│%s\n", green, reset, line, green, reset)
}
}
}
// wrapText splits the input text into lines of at most `width` characters each.
// printWrappedLongKeyLine handles headers whose key is too wide to leave
// room for a value in the fixed key/value layout. It wraps the key and value
// independently so keyColor never leaks into the separator or value text.
func printWrappedLongKeyLine(keyColor Color, key, value string) {
keyLine, remainingKey := splitText(key, boxContentWidth)
for remainingKey != "" {
printColoredBoxLine(keyColor, keyLine, boxContentWidth)
keyLine, remainingKey = splitText(remainingKey, boxContentWidth)
}
valueLineWidth := boxContentWidth - len(keyLine) - len(keyValueSeparator)
if valueLineWidth < 1 {
printColoredBoxLine(keyColor, keyLine, boxContentWidth)
printWrappedPlainText(keyValueSeparator+value, boxContentWidth)
return
}
valueLine, remainingValue := splitText(value, valueLineWidth)
printKeyValueBoxLine(keyColor, keyLine, keyValueSeparator, valueLine, boxContentWidth)
printWrappedPlainText(remainingValue, boxContentWidth)
}
func printColoredBoxLine(color Color, text string, width int) {
fmt.Printf("%s│%s %s%s%s%s %s│%s\n", green, reset, color, text, reset, rightPadding(text, width), green, reset)
}
func printKeyValueBoxLine(keyColor Color, key, separator, value string, width int) {
lineLen := len(key) + len(separator) + len(value)
fmt.Printf("%s│%s %s%s%s%s%s%s %s│%s\n", green, reset, keyColor, key, reset, separator, value, spaces(width-lineLen), green, reset)
}
func printPlainBoxLine(text string, width int) {
fmt.Printf("%s│%s %s%s %s│%s\n", green, reset, text, rightPadding(text, width), green, reset)
}
func printWrappedPlainText(text string, width int) {
for text != "" {
var line string
line, text = splitText(text, width)
printPlainBoxLine(line, width)
}
}
func rightPadding(text string, width int) string {
return spaces(width - len(text))
}
func spaces(count int) string {
if count < 1 {
return ""
}
return strings.Repeat(" ", count)
}
// splitText returns the first width bytes from text and the remaining suffix.
// The debug logger already measures line width with len, so this keeps the
// wrapping behavior consistent with the rest of this file.
func splitText(text string, width int) (string, string) {
if width < 1 {
return "", text
}
if len(text) <= width {
return text, ""
}
return text[:width], text[width:]
}
// wrapText splits the input text into lines of at most width bytes each.
// When width is not positive, it returns the original text as one line so
// callers never slice with an invalid bound while handling malformed layouts.
func wrapText(text string, width int) []string {
if width < 1 {
if text == "" {
return nil
}
return []string{text}
}
var lines []string
for len(text) > width {
lines = append(lines, text[:width])
@@ -265,7 +347,7 @@ func wrapText(text string, width int) []string {
// TODO: remove this and use utils.IsBidDataAction after refactoring
// and creating 'internal' package
func isLargeDataAction(ctx *fiber.Ctx) bool {
func isLargeDataAction(ctx fiber.Ctx) bool {
pathParts := strings.Split(ctx.Path(), "/")
// PutObject and UploadPart
+4 -1
View File
@@ -899,11 +899,14 @@ func RunVersityGW(ctx context.Context, be backend.Backend, cfg *Config) error {
webOpts = append(webOpts, webui.WithSocketPerm(parsedSocketPerm))
}
webSrv = webui.NewServer(&webui.ServerConfig{
webSrv, err = webui.NewServer(&webui.ServerConfig{
Gateways: gateways,
AdminGateways: adminGateways,
Region: cfg.Region,
}, webOpts...)
if err != nil {
return fmt.Errorf("init webui: %w", err)
}
}
var wsSrv *website.Server
+5 -3
View File
@@ -16,7 +16,7 @@ require (
github.com/cespare/xxhash/v2 v2.3.0
github.com/davecgh/go-spew v1.1.1
github.com/go-ldap/ldap/v3 v3.4.13
github.com/gofiber/fiber/v2 v2.52.13
github.com/gofiber/fiber/v3 v3.3.0
github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0
github.com/hashicorp/vault-client-go v0.4.3
@@ -56,9 +56,10 @@ require (
github.com/aws/aws-sdk-go-v2/service/sso v1.31.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 // indirect
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
github.com/gofiber/schema v1.7.1 // indirect
github.com/gofiber/utils/v2 v2.0.6 // indirect
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
@@ -69,15 +70,16 @@ require (
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.15 // indirect
github.com/mattn/go-isatty v0.0.22 // indirect
github.com/mattn/go-runewidth v0.0.24 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/nats-io/nkeys v0.4.16 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/philhofer/fwd v1.2.0 // indirect
github.com/pierrec/lz4/v4 v4.1.27 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/tinylib/msgp v1.6.4 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
golang.org/x/crypto v0.53.0 // indirect
+16 -6
View File
@@ -65,8 +65,6 @@ github.com/aws/smithy-go v1.27.1 h1:4T340VFndXtADGF52gYa1POyL7s9E4Z1OeZ1hCscIw8=
github.com/aws/smithy-go v1.27.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -74,12 +72,18 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78=
github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.4.13 h1:+x1nG9h+MZN7h/lUi5Q3UZ0fJ1GyDQYbPvbuH38baDQ=
github.com/go-ldap/ldap/v3 v3.4.13/go.mod h1:LxsGZV6vbaK0sIvYfsv47rfh4ca0JXokCoKjZxsszv0=
github.com/gofiber/fiber/v2 v2.52.13 h1:TOKP64iqC9b5P49VrBW5tHhUOvDyrtJ0xePEfzJbCbk=
github.com/gofiber/fiber/v2 v2.52.13/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/gofiber/fiber/v3 v3.3.0 h1:QBd3sYCqdy6Qs5gJYzSw4I4SbqL204jPqpdub/ueiw8=
github.com/gofiber/fiber/v3 v3.3.0/go.mod h1:YH7/TAoRaU4kF8slDCtQuFJ1NzC+3MtxUI4KfvQtaIA=
github.com/gofiber/schema v1.7.1 h1:oSJBKdgP8JeIME4TQSAqlNKTU2iBB+2RNmKi8Nsc+TI=
github.com/gofiber/schema v1.7.1/go.mod h1:A/X5Ffyru4p9eBdp99qu+nzviHzQiZ7odLT+TwxWhbk=
github.com/gofiber/utils/v2 v2.0.6 h1:7fXYy7nSsyqbH0GQUMtK4Kwjy4J7R5742VM7JsZxzOs=
github.com/gofiber/utils/v2 v2.0.6/go.mod h1:p7mAHAk3+oUK10ZX2xTw9fZQixb4hCg8SKd4IH2xroU=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
@@ -129,8 +133,6 @@ github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI=
github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -144,6 +146,8 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pierrec/lz4/v4 v4.1.27 h1:+PhzhWDrjRj89TH2sw43nE3+4+W8lSxIuQadEHZyjUk=
github.com/pierrec/lz4/v4 v4.1.27/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
@@ -163,6 +167,8 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/segmentio/kafka-go v0.4.51 h1:JgDPPG75tC1rWIS2Me6MwcvXJ6f49UQ4HjAOef71Hno=
github.com/segmentio/kafka-go v0.4.51/go.mod h1:Y1gn60kzLEEaW28YshXyk2+VCUKbJ3Qr6DrnT3i4+9E=
github.com/shamaton/msgpack/v3 v3.1.2 h1:d5gWAIyMU4M0WgDjz6IFSCuXJUA2dFwRHBpDclE8CLw=
github.com/shamaton/msgpack/v3 v3.1.2/go.mod h1:DcQG8jrdrQCIxr3HlMYkiXdMhK+KfN2CitkyzsQV4uc=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smira/go-statsd v1.3.4 h1:kBYWcLSGT+qC6JVbvfz48kX7mQys32fjDOPrfmsSx2c=
github.com/smira/go-statsd v1.3.4/go.mod h1:RjdsESPgDODtg1VpVVf9MJrEW2Hw0wtRNbmB1CAhu6A=
@@ -177,6 +183,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ=
github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
@@ -185,6 +193,8 @@ github.com/valyala/fasthttp v1.71.0 h1:tepR7H+Guh9VUqxxcPggYi8R3lGUu2Rsdh+z7/FCY
github.com/valyala/fasthttp v1.71.0/go.mod h1:z1sDUvOShhXq/C9mwH/fSm1Vb71tUJwmQdgkBrBNwnA=
github.com/versity/scoutfs-go v0.0.0-20260414000839-70f8b6bdfa96 h1:tUE4nwTlAfgc8neNzODemrv3LLe1ZpLG99desvXxYW8=
github.com/versity/scoutfs-go v0.0.0-20260414000839-70f8b6bdfa96/go.mod h1:gJsq73k+4685y+rbDIpPY8i/5GbsiwP6JFoFyUDB1fQ=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
+3 -3
View File
@@ -23,7 +23,7 @@ import (
"strings"
"sync"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/s3err"
)
@@ -43,7 +43,7 @@ type Tag struct {
// Manager is the interface definition for metrics manager
type Manager interface {
Send(ctx *fiber.Ctx, err error, action string, count int64, status int)
Send(ctx fiber.Ctx, err error, action string, count int64, status int)
Close()
}
@@ -118,7 +118,7 @@ func NewManager(ctx context.Context, conf Config) (Manager, error) {
return mgr, nil
}
func (m *manager) Send(ctx *fiber.Ctx, err error, action string, count int64, status int) {
func (m *manager) Send(ctx fiber.Ctx, err error, action string, count int64, status int) {
// In case of Authentication failures, url parsing ...
if action == "" {
action = ActionUndetected
+1 -1
View File
@@ -15,7 +15,7 @@
package s3api
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/metrics"
+18 -18
View File
@@ -19,9 +19,9 @@ import (
"net"
"os"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/logger"
"github.com/gofiber/fiber/v3/middleware/recover"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/debuglogger"
@@ -57,17 +57,15 @@ func NewAdminServer(be backend.Backend, root middlewares.RootUserConfig, region
}
app := fiber.New(fiber.Config{
AppName: "versitygw",
ServerHeader: "VERSITYGW",
Network: fiber.NetworkTCP,
DisableStartupMessage: true,
ErrorHandler: globalErrorHandler,
Concurrency: server.maxConnections,
AppName: "versitygw",
ServerHeader: "VERSITYGW",
ErrorHandler: globalErrorHandler,
Concurrency: server.maxConnections,
})
server.app = app
app.Use(recover.New(
app.Use("*", recover.New(
recover.Config{
EnableStackTrace: true,
StackTraceHandler: stackTraceHandler,
@@ -75,21 +73,21 @@ func NewAdminServer(be backend.Backend, root middlewares.RootUserConfig, region
// Logging middlewares
if !server.quiet {
app.Use(logger.New(logger.Config{
app.Use("*", logger.New(logger.Config{
Format: "${time} | adm | ${status} | ${latency} | ${ip} | ${method} | ${path} | ${error} | ${queryParams}\n",
}))
}
// initialize requestId middleware
app.Use(middlewares.RequestIDs())
app.Use("*", middlewares.RequestIDs())
// initialize total requests cap limiter middleware
app.Use(middlewares.RateLimiter(server.maxRequests, nil, l))
app.Use("*", middlewares.RateLimiter(server.maxRequests, nil, l))
app.Use(controllers.WrapMiddleware(middlewares.DecodeURL, l, nil))
app.Use("*", controllers.WrapMiddleware(middlewares.DecodeURL, l, nil))
// initialize the debug logger in debug mode
if debuglogger.IsDebugEnabled() {
app.Use(middlewares.DebugLogger())
app.Use("*", middlewares.DebugLogger())
}
server.router.Init(app, be, iam, l, root, region, server.debug, server.corsAllowOrigin)
@@ -151,9 +149,9 @@ func (sa *S3AdminServer) ServeMultiPort(ports []string) error {
var err error
if sa.CertStorage != nil {
ln, err = utils.NewMultiAddrTLSListener(sa.app.Config().Network, portSpec, sa.CertStorage.GetCertificate, utils.ListenerOptions{SocketPerm: sa.socketPerm})
ln, err = utils.NewMultiAddrTLSListener(fiber.NetworkTCP, portSpec, sa.CertStorage.GetCertificate, utils.ListenerOptions{SocketPerm: sa.socketPerm})
} else {
ln, err = utils.NewMultiAddrListener(sa.app.Config().Network, portSpec, utils.ListenerOptions{SocketPerm: sa.socketPerm})
ln, err = utils.NewMultiAddrListener(fiber.NetworkTCP, portSpec, utils.ListenerOptions{SocketPerm: sa.socketPerm})
}
if err != nil {
@@ -170,7 +168,9 @@ func (sa *S3AdminServer) ServeMultiPort(ports []string) error {
// Combine all listeners
finalListener := utils.NewMultiListener(listeners...)
return sa.app.Listener(finalListener)
return sa.app.Listener(finalListener, fiber.ListenConfig{
DisableStartupMessage: true,
})
}
// ShutDown gracefully shuts down the server with a context timeout
+13 -13
View File
@@ -19,7 +19,7 @@ import (
"net/http"
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/s3err"
@@ -38,9 +38,9 @@ func NewAdminController(iam auth.IAMService, be backend.Backend, l s3log.AuditLo
return AdminController{iam: iam, be: be, l: l, s3api: s3api}
}
func (c AdminController) CreateUser(ctx *fiber.Ctx) (*Response, error) {
func (c AdminController) CreateUser(ctx fiber.Ctx) (*Response, error) {
var usr auth.Account
err := xml.Unmarshal(ctx.Body(), &usr)
err := xml.Unmarshal(ctx.BodyRaw(), &usr)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{},
@@ -71,7 +71,7 @@ func (c AdminController) CreateUser(ctx *fiber.Ctx) (*Response, error) {
}, nil
}
func (c AdminController) UpdateUser(ctx *fiber.Ctx) (*Response, error) {
func (c AdminController) UpdateUser(ctx fiber.Ctx) (*Response, error) {
access := ctx.Query("access")
if access == "" {
return &Response{
@@ -80,7 +80,7 @@ func (c AdminController) UpdateUser(ctx *fiber.Ctx) (*Response, error) {
}
var props auth.MutableProps
if err := xml.Unmarshal(ctx.Body(), &props); err != nil {
if err := xml.Unmarshal(ctx.BodyRaw(), &props); err != nil {
return &Response{
MetaOpts: &MetaOptions{},
}, s3err.GetAPIError(s3err.ErrMalformedXML)
@@ -109,7 +109,7 @@ func (c AdminController) UpdateUser(ctx *fiber.Ctx) (*Response, error) {
}, nil
}
func (c AdminController) DeleteUser(ctx *fiber.Ctx) (*Response, error) {
func (c AdminController) DeleteUser(ctx fiber.Ctx) (*Response, error) {
access := ctx.Query("access")
if access == "" {
return &Response{
@@ -123,7 +123,7 @@ func (c AdminController) DeleteUser(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c AdminController) ListUsers(ctx *fiber.Ctx) (*Response, error) {
func (c AdminController) ListUsers(ctx fiber.Ctx) (*Response, error) {
accs, err := c.iam.ListUserAccounts()
return &Response{
Data: auth.ListUserAccountsResult{Accounts: accs},
@@ -131,7 +131,7 @@ func (c AdminController) ListUsers(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c AdminController) ChangeBucketOwner(ctx *fiber.Ctx) (*Response, error) {
func (c AdminController) ChangeBucketOwner(ctx fiber.Ctx) (*Response, error) {
owner := ctx.Query("owner")
bucket := ctx.Query("bucket")
@@ -147,14 +147,14 @@ func (c AdminController) ChangeBucketOwner(ctx *fiber.Ctx) (*Response, error) {
}, s3err.GetAPIError(s3err.ErrAdminUserNotFound)
}
err = c.be.ChangeBucketOwner(ctx.Context(), bucket, owner)
err = c.be.ChangeBucketOwner(ctx.RequestCtx(), bucket, owner)
return &Response{
MetaOpts: &MetaOptions{},
}, err
}
func (c AdminController) ListBuckets(ctx *fiber.Ctx) (*Response, error) {
buckets, err := c.be.ListBucketsAndOwners(ctx.Context())
func (c AdminController) ListBuckets(ctx fiber.Ctx) (*Response, error) {
buckets, err := c.be.ListBucketsAndOwners(ctx.RequestCtx())
return &Response{
Data: s3response.ListBucketsResult{
Buckets: buckets,
@@ -163,7 +163,7 @@ func (c AdminController) ListBuckets(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c AdminController) CreateBucket(ctx *fiber.Ctx) (*Response, error) {
func (c AdminController) CreateBucket(ctx fiber.Ctx) (*Response, error) {
owner := ctx.Get("x-vgw-owner")
if owner == "" {
return &Response{
@@ -183,7 +183,7 @@ func (c AdminController) CreateBucket(ctx *fiber.Ctx) (*Response, error) {
}
// store the owner access key id in context
ctx.Context().SetUserValue("bucket-owner", acc)
ctx.RequestCtx().SetUserValue("bucket-owner", acc)
_, err = c.s3api.CreateBucket(ctx)
if err != nil {
+11 -11
View File
@@ -21,7 +21,7 @@ import (
"sort"
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/debuglogger"
@@ -76,7 +76,7 @@ func New(be backend.Backend, iam auth.IAMService, logger s3log.AuditLogger, evs
}
}
func (c S3ApiController) getAclHeaderValue(ctx *fiber.Ctx, key string, defaultValues ...string) string {
func (c S3ApiController) getAclHeaderValue(ctx fiber.Ctx, key string, defaultValues ...string) string {
if c.disableACL {
return ""
}
@@ -86,7 +86,7 @@ func (c S3ApiController) getAclHeaderValue(ctx *fiber.Ctx, key string, defaultVa
// Returns MethodNotAllowed for unmatched routes
func (c S3ApiController) HandleErrorRoute(err error) Controller {
return func(ctx *fiber.Ctx) (*Response, error) {
return func(ctx fiber.Ctx) (*Response, error) {
return &Response{}, err
}
}
@@ -121,11 +121,11 @@ type Services struct {
}
// Controller is the type definition for an s3api controller
type Controller func(ctx *fiber.Ctx) (*Response, error)
type Controller func(ctx fiber.Ctx) (*Response, error)
// ProcessHandlers groups a controller and multiple middlewares into a single fiber handler
func ProcessHandlers(controller Controller, s3action string, svc *Services, handlers ...fiber.Handler) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
// if skip locals is set, skip to the next rout handler
if utils.ContextKeySkip.IsSet(ctx) {
utils.ContextKeySkip.Delete(ctx)
@@ -135,7 +135,7 @@ func ProcessHandlers(controller Controller, s3action string, svc *Services, hand
for _, handler := range handlers {
err := handler(ctx)
if err != nil {
return ProcessController(ctx, func(ctx *fiber.Ctx) (*Response, error) {
return ProcessController(ctx, func(ctx fiber.Ctx) (*Response, error) {
return &Response{
MetaOpts: &MetaOptions{},
}, err
@@ -150,7 +150,7 @@ func ProcessHandlers(controller Controller, s3action string, svc *Services, hand
// WrapMiddleware executes the given middleware and handles sending the audit logs
// and metrics. It also handles the error parsing
func WrapMiddleware(handler fiber.Handler, logger s3log.AuditLogger, mm metrics.Manager) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
requestID, hostID := utils.EnsureRequestIDs(ctx)
err := handler(ctx)
@@ -159,7 +159,7 @@ func WrapMiddleware(handler fiber.Handler, logger s3log.AuditLogger, mm metrics.
mm.Send(ctx, err, metrics.ActionUndetected, 0, 0)
}
if logger != nil {
logger.Log(ctx, err, ctx.Body(), s3log.LogMeta{
logger.Log(ctx, err, ctx.BodyRaw(), s3log.LogMeta{
Action: metrics.ActionUndetected,
})
}
@@ -187,7 +187,7 @@ func WrapMiddleware(handler fiber.Handler, logger s3log.AuditLogger, mm metrics.
// ProcessController executes the given s3api controller and handles the metrics
// access logs and s3 events
func ProcessController(ctx *fiber.Ctx, controller Controller, s3action string, svc *Services) error {
func ProcessController(ctx fiber.Ctx, controller Controller, s3action string, svc *Services) error {
response, err := controller(ctx)
// Set the response headers
@@ -342,7 +342,7 @@ func ProcessController(ctx *fiber.Ctx, controller Controller, s3action string, s
return ctx.Status(opts.Status).Send(res)
}
func ensureExposeMetaHeaders(ctx *fiber.Ctx) {
func ensureExposeMetaHeaders(ctx fiber.Ctx) {
// Only attempt to modify expose headers when CORS is actually in use.
if len(ctx.Response().Header.Peek("Access-Control-Allow-Origin")) == 0 {
return
@@ -414,7 +414,7 @@ func ensureExposeMetaHeaders(ctx *fiber.Ctx) {
}
// Sets the response headers
func SetResponseHeaders(ctx *fiber.Ctx, headers map[string]*string) {
func SetResponseHeaders(ctx fiber.Ctx, headers map[string]*string) {
if headers == nil {
return
}
+31 -31
View File
@@ -26,7 +26,7 @@ import (
"strings"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
"github.com/versity/versitygw/auth"
@@ -95,7 +95,7 @@ type ctxInputs struct {
func testController(t *testing.T, ctrl Controller, resp *Response, expectedErr error, input ctxInputs) {
app := fiber.New()
app.Post("/:bucket/*", func(ctx *fiber.Ctx) error {
app.Post("/:bucket/*", func(ctx fiber.Ctx) error {
// set the request body
ctx.Request().SetBody(input.body)
// set the request locals
@@ -259,23 +259,23 @@ func TestEnsureExposeMetaHeaders_AddsActualMetaHeaderNames(t *testing.T) {
type mockAuditLogger struct {
}
func (m *mockAuditLogger) Log(_ *fiber.Ctx, _ error, _ []byte, _ s3log.LogMeta) {}
func (m *mockAuditLogger) HangUp() error { return nil }
func (m *mockAuditLogger) Shutdown() error { return nil }
func (m *mockAuditLogger) Log(_ fiber.Ctx, _ error, _ []byte, _ s3log.LogMeta) {}
func (m *mockAuditLogger) HangUp() error { return nil }
func (m *mockAuditLogger) Shutdown() error { return nil }
// mock S3 event sender
type mockEvSender struct {
}
func (m *mockEvSender) SendEvent(_ *fiber.Ctx, _ s3event.EventMeta) {}
func (m *mockEvSender) Close() error { return nil }
func (m *mockEvSender) SendEvent(_ fiber.Ctx, _ s3event.EventMeta) {}
func (m *mockEvSender) Close() error { return nil }
// mock metrics manager
type mockMetricsManager struct{}
func (m *mockMetricsManager) Send(_ *fiber.Ctx, _ error, _ string, _ int64, _ int) {}
func (m *mockMetricsManager) Close() {}
func (m *mockMetricsManager) Send(_ fiber.Ctx, _ error, _ string, _ int64, _ int) {}
func (m *mockMetricsManager) Close() {}
func TestProcessController(t *testing.T) {
payload, err := xml.Marshal(s3response.Bucket{
@@ -308,7 +308,7 @@ func TestProcessController(t *testing.T) {
name: "no services successful response",
args: args{
svc: &Services{},
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{}, nil
},
},
@@ -320,7 +320,7 @@ func TestProcessController(t *testing.T) {
name: "handle api error",
args: args{
svc: services,
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{}, s3err.GetAPIError(s3err.ErrInvalidRequest)
},
},
@@ -333,7 +333,7 @@ func TestProcessController(t *testing.T) {
name: "handle custom error",
args: args{
svc: services,
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{}, errors.New("custom error")
},
},
@@ -346,7 +346,7 @@ func TestProcessController(t *testing.T) {
name: "body parsing fails",
args: args{
svc: services,
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{
Data: make(chan int),
}, nil
@@ -361,7 +361,7 @@ func TestProcessController(t *testing.T) {
name: "no data payload",
args: args{
svc: services,
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{
MetaOpts: &MetaOptions{
ObjectCount: 2,
@@ -377,7 +377,7 @@ func TestProcessController(t *testing.T) {
name: "should return 204 http status",
args: args{
svc: services,
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{
MetaOpts: &MetaOptions{
Status: http.StatusNoContent,
@@ -393,7 +393,7 @@ func TestProcessController(t *testing.T) {
name: "already encoded payload",
args: args{
svc: services,
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{
Data: []byte("encoded_data"),
}, nil
@@ -411,7 +411,7 @@ func TestProcessController(t *testing.T) {
name: "should set response headers",
args: args{
svc: services,
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{
Headers: map[string]*string{
"X-Amz-My-Custom-Header": utils.GetStringPtr("my_value"),
@@ -432,7 +432,7 @@ func TestProcessController(t *testing.T) {
name: "large payload: should return internal error",
args: args{
svc: services,
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
type Item struct {
Value string `xml:"value"`
}
@@ -475,7 +475,7 @@ func TestProcessController(t *testing.T) {
name: "not encoded payload",
args: args{
svc: services,
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{
Data: s3response.Bucket{
Name: "something",
@@ -553,10 +553,10 @@ func TestProcessHandlers(t *testing.T) {
name: "handler returns error",
args: args{
handlers: []fiber.Handler{
func(ctx *fiber.Ctx) error {
func(ctx fiber.Ctx) error {
return nil
},
func(ctx *fiber.Ctx) error {
func(ctx fiber.Ctx) error {
return s3err.GetAPIError(s3err.ErrAccessDenied)
},
},
@@ -570,15 +570,15 @@ func TestProcessHandlers(t *testing.T) {
name: "should process the controller",
args: args{
handlers: []fiber.Handler{
func(ctx *fiber.Ctx) error {
func(ctx fiber.Ctx) error {
return nil
},
func(ctx *fiber.Ctx) error {
func(ctx fiber.Ctx) error {
return nil
},
},
svc: &Services{},
controller: func(ctx *fiber.Ctx) (*Response, error) {
controller: func(ctx fiber.Ctx) (*Response, error) {
return &Response{
Data: s3response.Checksum{
CRC32: utils.GetStringPtr("crc32"),
@@ -597,7 +597,7 @@ func TestProcessHandlers(t *testing.T) {
app := fiber.New()
app.Post("/:bucket/*", func(ctx *fiber.Ctx) error {
app.Post("/:bucket/*", func(ctx fiber.Ctx) error {
utils.ContextKeyRequestID.Set(ctx, testRequestID)
utils.ContextKeyHostID.Set(ctx, testHostID)
@@ -620,7 +620,7 @@ func TestProcessHandlers(t *testing.T) {
return nil
})
app.All("*", func(ctx *fiber.Ctx) error {
app.All("*", func(ctx fiber.Ctx) error {
return nil
})
@@ -649,7 +649,7 @@ func TestWrapMiddleware(t *testing.T) {
{
name: "handler returns no error",
args: args{
handler: func(ctx *fiber.Ctx) error {
handler: func(ctx fiber.Ctx) error {
return nil
},
},
@@ -657,7 +657,7 @@ func TestWrapMiddleware(t *testing.T) {
{
name: "handler returns api error",
args: args{
handler: func(ctx *fiber.Ctx) error {
handler: func(ctx fiber.Ctx) error {
return s3err.GetAPIError(s3err.ErrAclNotSupported)
},
mm: &mockMetricsManager{},
@@ -670,7 +670,7 @@ func TestWrapMiddleware(t *testing.T) {
{
name: "handler returns custom error",
args: args{
handler: func(ctx *fiber.Ctx) error {
handler: func(ctx fiber.Ctx) error {
return errors.New("custom error")
},
},
@@ -684,7 +684,7 @@ func TestWrapMiddleware(t *testing.T) {
mdlwr := WrapMiddleware(tt.args.handler, tt.args.logger, tt.args.mm)
app := fiber.New()
app.Post("/:bucket/*", func(ctx *fiber.Ctx) error {
app.Post("/:bucket/*", func(ctx fiber.Ctx) error {
utils.ContextKeyRequestID.Set(ctx, testRequestID)
utils.ContextKeyHostID.Set(ctx, testHostID)
@@ -700,7 +700,7 @@ func TestWrapMiddleware(t *testing.T) {
return nil
})
app.All("*", func(ctx *fiber.Ctx) error {
app.All("*", func(ctx fiber.Ctx) error {
return nil
})
+19 -19
View File
@@ -17,19 +17,19 @@ package controllers
import (
"net/http"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
)
func (c S3ApiController) DeleteBucketTagging(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) DeleteBucketTagging(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
IsBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -49,7 +49,7 @@ func (c S3ApiController) DeleteBucketTagging(ctx *fiber.Ctx) (*Response, error)
}, err
}
err = c.be.DeleteBucketTagging(ctx.Context(), bucket)
err = c.be.DeleteBucketTagging(ctx.RequestCtx(), bucket)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -58,13 +58,13 @@ func (c S3ApiController) DeleteBucketTagging(ctx *fiber.Ctx) (*Response, error)
}, err
}
func (c S3ApiController) DeleteBucketOwnershipControls(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) DeleteBucketOwnershipControls(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -83,7 +83,7 @@ func (c S3ApiController) DeleteBucketOwnershipControls(ctx *fiber.Ctx) (*Respons
}, err
}
err = c.be.DeleteBucketOwnershipControls(ctx.Context(), bucket)
err = c.be.DeleteBucketOwnershipControls(ctx.RequestCtx(), bucket)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -92,13 +92,13 @@ func (c S3ApiController) DeleteBucketOwnershipControls(ctx *fiber.Ctx) (*Respons
}, err
}
func (c S3ApiController) DeleteBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) DeleteBucketPolicy(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -117,7 +117,7 @@ func (c S3ApiController) DeleteBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.DeleteBucketPolicy(ctx.Context(), bucket)
err = c.be.DeleteBucketPolicy(ctx.RequestCtx(), bucket)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -126,14 +126,14 @@ func (c S3ApiController) DeleteBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) DeleteBucketCors(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) DeleteBucketCors(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
IsBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -153,7 +153,7 @@ func (c S3ApiController) DeleteBucketCors(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.DeleteBucketCors(ctx.Context(), bucket)
err = c.be.DeleteBucketCors(ctx.RequestCtx(), bucket)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -162,14 +162,14 @@ func (c S3ApiController) DeleteBucketCors(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) DeleteBucketWebsite(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) DeleteBucketWebsite(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
IsBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -189,7 +189,7 @@ func (c S3ApiController) DeleteBucketWebsite(ctx *fiber.Ctx) (*Response, error)
}, err
}
err = c.be.DeleteBucketWebsite(ctx.Context(), bucket)
err = c.be.DeleteBucketWebsite(ctx.RequestCtx(), bucket)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -198,14 +198,14 @@ func (c S3ApiController) DeleteBucketWebsite(ctx *fiber.Ctx) (*Response, error)
}, err
}
func (c S3ApiController) DeleteBucket(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) DeleteBucket(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
IsBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -225,7 +225,7 @@ func (c S3ApiController) DeleteBucket(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.DeleteBucket(ctx.Context(), bucket)
err = c.be.DeleteBucket(ctx.RequestCtx(), bucket)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
+43 -43
View File
@@ -19,20 +19,20 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3response"
)
func (c S3ApiController) GetBucketTagging(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetBucketTagging(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -51,7 +51,7 @@ func (c S3ApiController) GetBucketTagging(ctx *fiber.Ctx) (*Response, error) {
}, err
}
tags, err := c.be.GetBucketTagging(ctx.Context(), bucket)
tags, err := c.be.GetBucketTagging(ctx.RequestCtx(), bucket)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -78,14 +78,14 @@ func (c S3ApiController) GetBucketTagging(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) GetBucketOwnershipControls(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetBucketOwnershipControls(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -104,7 +104,7 @@ func (c S3ApiController) GetBucketOwnershipControls(ctx *fiber.Ctx) (*Response,
}, err
}
data, err := c.be.GetBucketOwnershipControls(ctx.Context(), bucket)
data, err := c.be.GetBucketOwnershipControls(ctx.RequestCtx(), bucket)
return &Response{
Data: s3response.OwnershipControls{
Rules: []types.OwnershipControlsRule{
@@ -119,14 +119,14 @@ func (c S3ApiController) GetBucketOwnershipControls(ctx *fiber.Ctx) (*Response,
}, err
}
func (c S3ApiController) GetBucketVersioning(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetBucketVersioning(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -153,7 +153,7 @@ func (c S3ApiController) GetBucketVersioning(ctx *fiber.Ctx) (*Response, error)
}, err
}
data, err := c.be.GetBucketVersioning(ctx.Context(), bucket)
data, err := c.be.GetBucketVersioning(ctx.RequestCtx(), bucket)
return &Response{
Data: data,
MetaOpts: &MetaOptions{
@@ -162,14 +162,14 @@ func (c S3ApiController) GetBucketVersioning(ctx *fiber.Ctx) (*Response, error)
}, err
}
func (c S3ApiController) GetBucketCors(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetBucketCors(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -188,7 +188,7 @@ func (c S3ApiController) GetBucketCors(ctx *fiber.Ctx) (*Response, error) {
}, err
}
data, err := c.be.GetBucketCors(ctx.Context(), bucket)
data, err := c.be.GetBucketCors(ctx.RequestCtx(), bucket)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -206,14 +206,14 @@ func (c S3ApiController) GetBucketCors(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) GetBucketWebsite(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetBucketWebsite(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -232,7 +232,7 @@ func (c S3ApiController) GetBucketWebsite(ctx *fiber.Ctx) (*Response, error) {
}, err
}
data, err := c.be.GetBucketWebsite(ctx.Context(), bucket)
data, err := c.be.GetBucketWebsite(ctx.RequestCtx(), bucket)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -250,14 +250,14 @@ func (c S3ApiController) GetBucketWebsite(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) GetBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetBucketPolicy(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -276,7 +276,7 @@ func (c S3ApiController) GetBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
}, err
}
data, err := c.be.GetBucketPolicy(ctx.Context(), bucket)
data, err := c.be.GetBucketPolicy(ctx.RequestCtx(), bucket)
return &Response{
Data: data,
MetaOpts: &MetaOptions{
@@ -285,14 +285,14 @@ func (c S3ApiController) GetBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) GetBucketPolicyStatus(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetBucketPolicyStatus(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -311,7 +311,7 @@ func (c S3ApiController) GetBucketPolicyStatus(ctx *fiber.Ctx) (*Response, error
}, err
}
policyRaw, err := c.be.GetBucketPolicy(ctx.Context(), bucket)
policyRaw, err := c.be.GetBucketPolicy(ctx.RequestCtx(), bucket)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -340,7 +340,7 @@ func (c S3ApiController) GetBucketPolicyStatus(ctx *fiber.Ctx) (*Response, error
}, nil
}
func (c S3ApiController) ListObjectVersions(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) ListObjectVersions(ctx fiber.Ctx) (*Response, error) {
// url values
bucket := ctx.Params("bucket")
prefix := ctx.Query("prefix")
@@ -354,7 +354,7 @@ func (c S3ApiController) ListObjectVersions(ctx *fiber.Ctx) (*Response, error) {
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -382,7 +382,7 @@ func (c S3ApiController) ListObjectVersions(ctx *fiber.Ctx) (*Response, error) {
}, err
}
data, err := c.be.ListObjectVersions(ctx.Context(),
data, err := c.be.ListObjectVersions(ctx.RequestCtx(),
&s3.ListObjectVersionsInput{
Bucket: &bucket,
Delimiter: &delimiter,
@@ -399,7 +399,7 @@ func (c S3ApiController) ListObjectVersions(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) GetObjectLockConfiguration(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetObjectLockConfiguration(ctx fiber.Ctx) (*Response, error) {
// url values
bucket := ctx.Params("bucket")
// context keys
@@ -408,7 +408,7 @@ func (c S3ApiController) GetObjectLockConfiguration(ctx *fiber.Ctx) (*Response,
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -427,7 +427,7 @@ func (c S3ApiController) GetObjectLockConfiguration(ctx *fiber.Ctx) (*Response,
}, err
}
data, err := c.be.GetObjectLockConfiguration(ctx.Context(), bucket)
data, err := c.be.GetObjectLockConfiguration(ctx.RequestCtx(), bucket)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -445,7 +445,7 @@ func (c S3ApiController) GetObjectLockConfiguration(ctx *fiber.Ctx) (*Response,
}, err
}
func (c S3ApiController) GetBucketAcl(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetBucketAcl(ctx fiber.Ctx) (*Response, error) {
// url values
bucket := ctx.Params("bucket")
// context keys
@@ -454,7 +454,7 @@ func (c S3ApiController) GetBucketAcl(ctx *fiber.Ctx) (*Response, error) {
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionReadAcp,
@@ -473,7 +473,7 @@ func (c S3ApiController) GetBucketAcl(ctx *fiber.Ctx) (*Response, error) {
}, err
}
data, err := c.be.GetBucketAcl(ctx.Context(),
data, err := c.be.GetBucketAcl(ctx.RequestCtx(),
&s3.GetBucketAclInput{Bucket: &bucket})
if err != nil {
return &Response{
@@ -492,7 +492,7 @@ func (c S3ApiController) GetBucketAcl(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) ListMultipartUploads(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) ListMultipartUploads(ctx fiber.Ctx) (*Response, error) {
// url values
bucket := ctx.Params("bucket")
prefix := ctx.Query("prefix")
@@ -506,7 +506,7 @@ func (c S3ApiController) ListMultipartUploads(ctx *fiber.Ctx) (*Response, error)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -532,7 +532,7 @@ func (c S3ApiController) ListMultipartUploads(ctx *fiber.Ctx) (*Response, error)
},
}, err
}
res, err := c.be.ListMultipartUploads(ctx.Context(),
res, err := c.be.ListMultipartUploads(ctx.RequestCtx(),
&s3.ListMultipartUploadsInput{
Bucket: &bucket,
Delimiter: &delimiter,
@@ -549,7 +549,7 @@ func (c S3ApiController) ListMultipartUploads(ctx *fiber.Ctx) (*Response, error)
}, err
}
func (c S3ApiController) ListObjectsV2(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) ListObjectsV2(ctx fiber.Ctx) (*Response, error) {
// url values
bucket := ctx.Params("bucket")
prefix := ctx.Query("prefix")
@@ -568,7 +568,7 @@ func (c S3ApiController) ListObjectsV2(ctx *fiber.Ctx) (*Response, error) {
region = defaultRegion
}
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -595,7 +595,7 @@ func (c S3ApiController) ListObjectsV2(ctx *fiber.Ctx) (*Response, error) {
}, err
}
res, err := c.be.ListObjectsV2(ctx.Context(),
res, err := c.be.ListObjectsV2(ctx.RequestCtx(),
&s3.ListObjectsV2Input{
Bucket: &bucket,
Prefix: &prefix,
@@ -624,7 +624,7 @@ func (c S3ApiController) ListObjectsV2(ctx *fiber.Ctx) (*Response, error) {
}, nil
}
func (c S3ApiController) ListObjects(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) ListObjects(ctx fiber.Ctx) (*Response, error) {
// url values
bucket := ctx.Params("bucket")
prefix := ctx.Query("prefix")
@@ -641,7 +641,7 @@ func (c S3ApiController) ListObjects(ctx *fiber.Ctx) (*Response, error) {
region = defaultRegion
}
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -669,7 +669,7 @@ func (c S3ApiController) ListObjects(ctx *fiber.Ctx) (*Response, error) {
}, err
}
res, err := c.be.ListObjects(ctx.Context(),
res, err := c.be.ListObjects(ctx.RequestCtx(),
&s3.ListObjectsInput{
Bucket: &bucket,
Prefix: &prefix,
@@ -697,14 +697,14 @@ func (c S3ApiController) ListObjects(ctx *fiber.Ctx) (*Response, error) {
}
// GetBucketLocation handles GET /:bucket?location
func (c S3ApiController) GetBucketLocation(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetBucketLocation(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -724,7 +724,7 @@ func (c S3ApiController) GetBucketLocation(ctx *fiber.Ctx) (*Response, error) {
}
// verify bucket existence/access via backend HeadBucket
_, err = c.be.HeadBucket(ctx.Context(), &s3.HeadBucketInput{Bucket: &bucket})
_, err = c.be.HeadBucket(ctx.RequestCtx(), &s3.HeadBucketInput{Bucket: &bucket})
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
+4 -4
View File
@@ -18,13 +18,13 @@ import (
"errors"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
)
func (c S3ApiController) HeadBucket(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) HeadBucket(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
@@ -32,7 +32,7 @@ func (c S3ApiController) HeadBucket(ctx *fiber.Ctx) (*Response, error) {
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -55,7 +55,7 @@ func (c S3ApiController) HeadBucket(ctx *fiber.Ctx) (*Response, error) {
}, err
}
_, err = c.be.HeadBucket(ctx.Context(),
_, err = c.be.HeadBucket(ctx.RequestCtx(),
&s3.HeadBucketInput{
Bucket: &bucket,
})
+3 -3
View File
@@ -15,13 +15,13 @@
package controllers
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3response"
)
func (c S3ApiController) ListBuckets(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) ListBuckets(ctx fiber.Ctx) (*Response, error) {
cToken := ctx.Query("continuation-token")
prefix := ctx.Query("prefix")
maxBucketsStr := ctx.Query("max-buckets")
@@ -38,7 +38,7 @@ func (c S3ApiController) ListBuckets(ctx *fiber.Ctx) (*Response, error) {
}, err
}
res, err := c.be.ListBuckets(ctx.Context(),
res, err := c.be.ListBuckets(ctx.RequestCtx(),
s3response.ListBucketsInput{
Owner: acct.Access,
IsAdmin: acct.Role == auth.RoleAdmin,
+9 -9
View File
@@ -22,7 +22,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3api/middlewares"
@@ -32,7 +32,7 @@ import (
"github.com/versity/versitygw/s3response"
)
func (c S3ApiController) DeleteObjects(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) DeleteObjects(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
bypass := strings.EqualFold(ctx.Get("X-Amz-Bypass-Governance-Retention"), "true")
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
@@ -40,7 +40,7 @@ func (c S3ApiController) DeleteObjects(ctx *fiber.Ctx) (*Response, error) {
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
IsBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -61,7 +61,7 @@ func (c S3ApiController) DeleteObjects(ctx *fiber.Ctx) (*Response, error) {
}
var dObj s3response.DeleteObjects
err = xml.Unmarshal(ctx.Body(), &dObj)
err = xml.Unmarshal(ctx.BodyRaw(), &dObj)
if err != nil {
debuglogger.Logf("error unmarshalling delete objects: %v", err)
return &Response{
@@ -71,7 +71,7 @@ func (c S3ApiController) DeleteObjects(ctx *fiber.Ctx) (*Response, error) {
}, s3err.GetAPIError(s3err.ErrInvalidRequest)
}
err = auth.CheckObjectAccess(ctx.Context(), bucket, acct.Access, dObj.Objects, bypass, IsBucketPublic, c.be, false)
err = auth.CheckObjectAccess(ctx.RequestCtx(), bucket, acct.Access, dObj.Objects, bypass, IsBucketPublic, c.be, false)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -80,7 +80,7 @@ func (c S3ApiController) DeleteObjects(ctx *fiber.Ctx) (*Response, error) {
}, err
}
res, err := c.be.DeleteObjects(ctx.Context(),
res, err := c.be.DeleteObjects(ctx.RequestCtx(),
&s3.DeleteObjectsInput{
Bucket: &bucket,
Delete: &types.Delete{
@@ -97,7 +97,7 @@ func (c S3ApiController) DeleteObjects(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) POSTObject(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) POSTObject(ctx fiber.Ctx) (*Response, error) {
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
@@ -115,7 +115,7 @@ func (c S3ApiController) POSTObject(ctx *fiber.Ctx) (*Response, error) {
key := parsed.Fields["key"]
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -206,7 +206,7 @@ func (c S3ApiController) POSTObject(ctx *fiber.Ctx) (*Response, error) {
}, err
}
res, err := c.be.PutObject(ctx.Context(), s3response.PutObjectInput{
res, err := c.be.PutObject(ctx.RequestCtx(), s3response.PutObjectInput{
Bucket: &bucket,
Key: &key,
ContentType: &contentType,
+39 -39
View File
@@ -22,7 +22,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3api/utils"
@@ -30,14 +30,14 @@ import (
"github.com/versity/versitygw/s3response"
)
func (c S3ApiController) PutBucketTagging(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutBucketTagging(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -56,7 +56,7 @@ func (c S3ApiController) PutBucketTagging(ctx *fiber.Ctx) (*Response, error) {
}, err
}
tagging, err := utils.ParseTagging(ctx.Body(), utils.TagLimitBucket)
tagging, err := utils.ParseTagging(ctx.BodyRaw(), utils.TagLimitBucket)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -65,7 +65,7 @@ func (c S3ApiController) PutBucketTagging(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.PutBucketTagging(ctx.Context(), bucket, tagging)
err = c.be.PutBucketTagging(ctx.RequestCtx(), bucket, tagging)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -74,13 +74,13 @@ func (c S3ApiController) PutBucketTagging(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) PutBucketOwnershipControls(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutBucketOwnershipControls(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
if err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
if err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -98,7 +98,7 @@ func (c S3ApiController) PutBucketOwnershipControls(ctx *fiber.Ctx) (*Response,
}
var ownershipControls s3response.OwnershipControls
if err := xml.Unmarshal(ctx.Body(), &ownershipControls); err != nil {
if err := xml.Unmarshal(ctx.BodyRaw(), &ownershipControls); err != nil {
debuglogger.Logf("failed to unmarshal request body: %v", err)
return &Response{
MetaOpts: &MetaOptions{
@@ -125,7 +125,7 @@ func (c S3ApiController) PutBucketOwnershipControls(ctx *fiber.Ctx) (*Response,
}, s3err.GetAPIError(s3err.ErrMalformedXML)
}
err := c.be.PutBucketOwnershipControls(ctx.Context(), bucket, ownershipControls.Rules[0].ObjectOwnership)
err := c.be.PutBucketOwnershipControls(ctx.RequestCtx(), bucket, ownershipControls.Rules[0].ObjectOwnership)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -133,14 +133,14 @@ func (c S3ApiController) PutBucketOwnershipControls(ctx *fiber.Ctx) (*Response,
}, err
}
func (c S3ApiController) PutBucketVersioning(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutBucketVersioning(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -160,7 +160,7 @@ func (c S3ApiController) PutBucketVersioning(ctx *fiber.Ctx) (*Response, error)
}
var versioningConf types.VersioningConfiguration
err = xml.Unmarshal(ctx.Body(), &versioningConf)
err = xml.Unmarshal(ctx.BodyRaw(), &versioningConf)
if err != nil {
debuglogger.Logf("error unmarshalling versioning configuration: %v", err)
return &Response{
@@ -180,7 +180,7 @@ func (c S3ApiController) PutBucketVersioning(ctx *fiber.Ctx) (*Response, error)
}, s3err.GetAPIError(s3err.ErrMalformedXML)
}
err = c.be.PutBucketVersioning(ctx.Context(), bucket, versioningConf.Status)
err = c.be.PutBucketVersioning(ctx.RequestCtx(), bucket, versioningConf.Status)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -188,14 +188,14 @@ func (c S3ApiController) PutBucketVersioning(ctx *fiber.Ctx) (*Response, error)
}, err
}
func (c S3ApiController) PutObjectLockConfiguration(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutObjectLockConfiguration(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
if err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
if err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -213,7 +213,7 @@ func (c S3ApiController) PutObjectLockConfiguration(ctx *fiber.Ctx) (*Response,
}, err
}
config, err := auth.ParseBucketLockConfigurationInput(ctx.Body())
config, err := auth.ParseBucketLockConfigurationInput(ctx.BodyRaw())
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -222,7 +222,7 @@ func (c S3ApiController) PutObjectLockConfiguration(ctx *fiber.Ctx) (*Response,
}, err
}
err = c.be.PutObjectLockConfiguration(ctx.Context(), bucket, config)
err = c.be.PutObjectLockConfiguration(ctx.RequestCtx(), bucket, config)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -230,14 +230,14 @@ func (c S3ApiController) PutObjectLockConfiguration(ctx *fiber.Ctx) (*Response,
}, err
}
func (c S3ApiController) PutBucketCors(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutBucketCors(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -256,7 +256,7 @@ func (c S3ApiController) PutBucketCors(ctx *fiber.Ctx) (*Response, error) {
}, err
}
body := ctx.Body()
body := ctx.BodyRaw()
var corsConfig auth.CORSConfiguration
err = xml.Unmarshal(body, &corsConfig)
@@ -279,7 +279,7 @@ func (c S3ApiController) PutBucketCors(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.PutBucketCors(ctx.Context(), bucket, body)
err = c.be.PutBucketCors(ctx.RequestCtx(), bucket, body)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -287,14 +287,14 @@ func (c S3ApiController) PutBucketCors(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) PutBucketWebsite(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutBucketWebsite(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -313,7 +313,7 @@ func (c S3ApiController) PutBucketWebsite(ctx *fiber.Ctx) (*Response, error) {
}, err
}
body := ctx.Body()
body := ctx.BodyRaw()
if len(body) > maxWebsiteConfigurationBytes {
debuglogger.Logf("the request size exceeded the 128KB limit: %d", len(body))
return &Response{
@@ -343,7 +343,7 @@ func (c S3ApiController) PutBucketWebsite(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.PutBucketWebsite(ctx.Context(), bucket, body)
err = c.be.PutBucketWebsite(ctx.RequestCtx(), bucket, body)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -351,13 +351,13 @@ func (c S3ApiController) PutBucketWebsite(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) PutBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutBucketPolicy(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -375,7 +375,7 @@ func (c S3ApiController) PutBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = auth.ValidatePolicyDocument(ctx.Body(), bucket, c.iam)
err = auth.ValidatePolicyDocument(ctx.BodyRaw(), bucket, c.iam)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -384,7 +384,7 @@ func (c S3ApiController) PutBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.PutBucketPolicy(ctx.Context(), bucket, ctx.Body())
err = c.be.PutBucketPolicy(ctx.RequestCtx(), bucket, ctx.BodyRaw())
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -393,7 +393,7 @@ func (c S3ApiController) PutBucketPolicy(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) PutBucketAcl(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutBucketAcl(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acl := types.BucketCannedACL(ctx.Get("X-Amz-Acl"))
grantFullControl := ctx.Get("X-Amz-Grant-Full-Control")
@@ -409,7 +409,7 @@ func (c S3ApiController) PutBucketAcl(ctx *fiber.Ctx) (*Response, error) {
grants := grantFullControl + grantRead + grantReadACP + grantWrite + grantWriteACP
var input *auth.PutBucketAclInput
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -446,7 +446,7 @@ func (c S3ApiController) PutBucketAcl(ctx *fiber.Ctx) (*Response, error) {
}, err
}
ownership, err := c.be.GetBucketOwnershipControls(ctx.Context(), bucket)
ownership, err := c.be.GetBucketOwnershipControls(ctx.RequestCtx(), bucket)
if err != nil && !errors.Is(err, s3err.GetAPIError(s3err.ErrOwnershipControlsNotFound)) {
return &Response{
MetaOpts: &MetaOptions{
@@ -463,9 +463,9 @@ func (c S3ApiController) PutBucketAcl(ctx *fiber.Ctx) (*Response, error) {
}, s3err.GetAPIError(s3err.ErrAclNotSupported)
}
if len(ctx.Body()) > 0 {
if len(ctx.BodyRaw()) > 0 {
var accessControlPolicy auth.AccessControlPolicy
err := xml.Unmarshal(ctx.Body(), &accessControlPolicy)
err := xml.Unmarshal(ctx.BodyRaw(), &accessControlPolicy)
if err != nil {
debuglogger.Logf("error unmarshalling access control policy: %v", err)
return &Response{
@@ -554,7 +554,7 @@ func (c S3ApiController) PutBucketAcl(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.PutBucketAcl(ctx.Context(), bucket, updAcl)
err = c.be.PutBucketAcl(ctx.RequestCtx(), bucket, updAcl)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -562,7 +562,7 @@ func (c S3ApiController) PutBucketAcl(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) CreateBucket(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) CreateBucket(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
acl := types.BucketCannedACL(c.getAclHeaderValue(ctx, "X-Amz-Acl"))
grantFullControl := c.getAclHeaderValue(ctx, "X-Amz-Grant-Full-Control")
@@ -654,9 +654,9 @@ func (c S3ApiController) CreateBucket(ctx *fiber.Ctx) (*Response, error) {
}
var body s3response.CreateBucketConfiguration
if len(ctx.Body()) != 0 {
if len(ctx.BodyRaw()) != 0 {
// request body is optional for CreateBucket
err := xml.Unmarshal(ctx.Body(), &body)
err := xml.Unmarshal(ctx.BodyRaw(), &body)
if err != nil {
debuglogger.Logf("failed to parse the request body: %v", err)
return &Response{
@@ -704,7 +704,7 @@ func (c S3ApiController) CreateBucket(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.CreateBucket(ctx.Context(), &s3.CreateBucketInput{
err = c.be.CreateBucket(ctx.RequestCtx(), &s3.CreateBucketInput{
Bucket: &bucket,
ObjectOwnership: objectOwnership,
ObjectLockEnabledForBucket: &lockEnabled,
@@ -19,7 +19,7 @@ import (
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/s3api/middlewares"
"github.com/versity/versitygw/s3err"
)
@@ -36,7 +36,7 @@ func TestApplyBucketCORS_FallbackOrigin_NoBucketCors_NoRequestOrigin(t *testing.
app := fiber.New()
app.Get("/:bucket/test",
middlewares.ApplyBucketCORS(mockedBackend, middlewares.BucketFromPath, origin),
func(c *fiber.Ctx) error {
func(c fiber.Ctx) error {
return c.SendStatus(http.StatusOK)
},
)
@@ -72,7 +72,7 @@ func TestApplyBucketCORS_FallbackOrigin_NotAppliedWhenBucketCorsExists(t *testin
app := fiber.New()
app.Get("/:bucket/test",
middlewares.ApplyBucketCORS(mockedBackend, middlewares.BucketFromPath, origin),
func(c *fiber.Ctx) error {
func(c fiber.Ctx) error {
return c.SendStatus(http.StatusOK)
},
)
+12 -12
View File
@@ -21,13 +21,13 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3event"
)
func (c S3ApiController) DeleteObjectTagging(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) DeleteObjectTagging(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
@@ -41,7 +41,7 @@ func (c S3ApiController) DeleteObjectTagging(ctx *fiber.Ctx) (*Response, error)
action = auth.DeleteObjectVersionTaggingAction
}
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -62,7 +62,7 @@ func (c S3ApiController) DeleteObjectTagging(ctx *fiber.Ctx) (*Response, error)
}, err
}
err = c.be.DeleteObjectTagging(ctx.Context(), bucket, key, versionId)
err = c.be.DeleteObjectTagging(ctx.RequestCtx(), bucket, key, versionId)
return &Response{
Headers: map[string]*string{
"x-amz-version-id": &versionId,
@@ -75,7 +75,7 @@ func (c S3ApiController) DeleteObjectTagging(ctx *fiber.Ctx) (*Response, error)
}, err
}
func (c S3ApiController) AbortMultipartUpload(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) AbortMultipartUpload(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
uploadId := ctx.Query("uploadId")
@@ -85,7 +85,7 @@ func (c S3ApiController) AbortMultipartUpload(ctx *fiber.Ctx) (*Response, error)
isBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -106,7 +106,7 @@ func (c S3ApiController) AbortMultipartUpload(ctx *fiber.Ctx) (*Response, error)
}, err
}
err = c.be.AbortMultipartUpload(ctx.Context(),
err = c.be.AbortMultipartUpload(ctx.RequestCtx(),
&s3.AbortMultipartUploadInput{
UploadId: &uploadId,
Bucket: &bucket,
@@ -121,12 +121,12 @@ func (c S3ApiController) AbortMultipartUpload(ctx *fiber.Ctx) (*Response, error)
}, err
}
func (c S3ApiController) DeleteObject(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) DeleteObject(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
bypass := strings.EqualFold(ctx.Get("X-Amz-Bypass-Governance-Retention"), "true")
ifMatch := utils.GetStringPtr(utils.TrimQuotes(ctx.Get("If-Match")))
ifMatch := utils.GetStringPtr(strings.Trim(ctx.Get("If-Match"), `"`))
ifMatchLastModTime := utils.ParsePreconditionDateHeader(ctx.Get("X-Amz-If-Match-Last-Modified-Time"))
ifMatchSize := utils.ParseIfMatchSize(ctx)
// context locals
@@ -140,7 +140,7 @@ func (c S3ApiController) DeleteObject(ctx *fiber.Ctx) (*Response, error) {
action = auth.DeleteObjectVersionAction
}
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -162,7 +162,7 @@ func (c S3ApiController) DeleteObject(ctx *fiber.Ctx) (*Response, error) {
}
err = auth.CheckObjectAccess(
ctx.Context(),
ctx.RequestCtx(),
bucket,
acct.Access,
[]types.ObjectIdentifier{
@@ -184,7 +184,7 @@ func (c S3ApiController) DeleteObject(ctx *fiber.Ctx) (*Response, error) {
}, err
}
res, err := c.be.DeleteObject(ctx.Context(),
res, err := c.be.DeleteObject(ctx.RequestCtx(),
&s3.DeleteObjectInput{
Bucket: &bucket,
Key: &key,
+23 -23
View File
@@ -23,7 +23,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3api/utils"
@@ -31,7 +31,7 @@ import (
"github.com/versity/versitygw/s3response"
)
func (c S3ApiController) GetObjectTagging(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetObjectTagging(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
@@ -45,7 +45,7 @@ func (c S3ApiController) GetObjectTagging(ctx *fiber.Ctx) (*Response, error) {
action = auth.GetObjectVersionTaggingAction
}
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -65,7 +65,7 @@ func (c S3ApiController) GetObjectTagging(ctx *fiber.Ctx) (*Response, error) {
}, err
}
data, err := c.be.GetObjectTagging(ctx.Context(), bucket, key, versionId)
data, err := c.be.GetObjectTagging(ctx.RequestCtx(), bucket, key, versionId)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -93,7 +93,7 @@ func (c S3ApiController) GetObjectTagging(ctx *fiber.Ctx) (*Response, error) {
}, nil
}
func (c S3ApiController) GetObjectRetention(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetObjectRetention(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
@@ -103,7 +103,7 @@ func (c S3ApiController) GetObjectRetention(ctx *fiber.Ctx) (*Response, error) {
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -123,7 +123,7 @@ func (c S3ApiController) GetObjectRetention(ctx *fiber.Ctx) (*Response, error) {
}, err
}
data, err := c.be.GetObjectRetention(ctx.Context(), bucket, key, versionId)
data, err := c.be.GetObjectRetention(ctx.RequestCtx(), bucket, key, versionId)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -141,7 +141,7 @@ func (c S3ApiController) GetObjectRetention(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) GetObjectLegalHold(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetObjectLegalHold(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
@@ -151,7 +151,7 @@ func (c S3ApiController) GetObjectLegalHold(ctx *fiber.Ctx) (*Response, error) {
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -171,7 +171,7 @@ func (c S3ApiController) GetObjectLegalHold(ctx *fiber.Ctx) (*Response, error) {
}, err
}
data, err := c.be.GetObjectLegalHold(ctx.Context(), bucket, key, versionId)
data, err := c.be.GetObjectLegalHold(ctx.RequestCtx(), bucket, key, versionId)
return &Response{
Data: auth.ParseObjectLegalHoldOutput(data),
MetaOpts: &MetaOptions{
@@ -180,7 +180,7 @@ func (c S3ApiController) GetObjectLegalHold(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) GetObjectAcl(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetObjectAcl(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
// context locals
@@ -189,7 +189,7 @@ func (c S3ApiController) GetObjectAcl(ctx *fiber.Ctx) (*Response, error) {
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionReadAcp,
@@ -208,7 +208,7 @@ func (c S3ApiController) GetObjectAcl(ctx *fiber.Ctx) (*Response, error) {
},
}, err
}
res, err := c.be.GetObjectAcl(ctx.Context(), &s3.GetObjectAclInput{
res, err := c.be.GetObjectAcl(ctx.RequestCtx(), &s3.GetObjectAclInput{
Bucket: &bucket,
Key: &key,
})
@@ -220,7 +220,7 @@ func (c S3ApiController) GetObjectAcl(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) ListParts(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) ListParts(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
uploadId := ctx.Query("uploadId")
@@ -232,7 +232,7 @@ func (c S3ApiController) ListParts(ctx *fiber.Ctx) (*Response, error) {
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -272,7 +272,7 @@ func (c S3ApiController) ListParts(ctx *fiber.Ctx) (*Response, error) {
}, err
}
res, err := c.be.ListParts(ctx.Context(), &s3.ListPartsInput{
res, err := c.be.ListParts(ctx.RequestCtx(), &s3.ListPartsInput{
Bucket: &bucket,
Key: &key,
UploadId: &uploadId,
@@ -287,7 +287,7 @@ func (c S3ApiController) ListParts(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) GetObjectAttributes(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetObjectAttributes(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
@@ -304,7 +304,7 @@ func (c S3ApiController) GetObjectAttributes(ctx *fiber.Ctx) (*Response, error)
action = auth.GetObjectVersionAttributesAction
}
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -341,7 +341,7 @@ func (c S3ApiController) GetObjectAttributes(ctx *fiber.Ctx) (*Response, error)
}, err
}
res, err := c.be.GetObjectAttributes(ctx.Context(),
res, err := c.be.GetObjectAttributes(ctx.RequestCtx(),
&s3.GetObjectAttributesInput{
Bucket: &bucket,
Key: &key,
@@ -381,13 +381,13 @@ func (c S3ApiController) GetObjectAttributes(ctx *fiber.Ctx) (*Response, error)
}, err
}
func (c S3ApiController) GetObject(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) GetObject(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
acceptRange := ctx.Get("Range")
checksumMode := types.ChecksumMode(strings.ToUpper(ctx.Get("x-amz-checksum-mode")))
partNumberQuery := int32(ctx.QueryInt("partNumber", -1))
partNumberQuery := int32(fiber.Query[int](ctx, "partNumber", -1))
// Extract response override query parameters
responseOverrides := map[string]*string{
@@ -429,7 +429,7 @@ func (c S3ApiController) GetObject(ctx *fiber.Ctx) (*Response, error) {
action = auth.GetObjectVersionAction
}
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
@@ -484,7 +484,7 @@ func (c S3ApiController) GetObject(ctx *fiber.Ctx) (*Response, error) {
conditionalHeaders := utils.ParsePreconditionHeaders(ctx)
res, err := c.be.GetObject(ctx.Context(), &s3.GetObjectInput{
res, err := c.be.GetObject(ctx.RequestCtx(), &s3.GetObjectInput{
Bucket: &bucket,
Key: &key,
Range: &acceptRange,
+5 -5
View File
@@ -22,14 +22,14 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
)
func (c S3ApiController) HeadObject(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) HeadObject(ctx fiber.Ctx) (*Response, error) {
// context locals
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
@@ -37,7 +37,7 @@ func (c S3ApiController) HeadObject(ctx *fiber.Ctx) (*Response, error) {
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
// url values
bucket := ctx.Params("bucket")
partNumberQuery := int32(ctx.QueryInt("partNumber", -1))
partNumberQuery := int32(fiber.Query(ctx, "partNumber", -1))
versionId := ctx.Query("versionId")
objRange := ctx.Get("Range")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
@@ -76,7 +76,7 @@ func (c S3ApiController) HeadObject(ctx *fiber.Ctx) (*Response, error) {
action = auth.GetObjectVersionAction
}
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -132,7 +132,7 @@ func (c S3ApiController) HeadObject(ctx *fiber.Ctx) (*Response, error) {
conditionalHeaders := utils.ParsePreconditionHeaders(ctx)
res, err := c.be.HeadObject(ctx.Context(),
res, err := c.be.HeadObject(ctx.RequestCtx(),
&s3.HeadObjectInput{
Bucket: &bucket,
Key: &key,
+18 -18
View File
@@ -22,7 +22,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3api/utils"
@@ -31,7 +31,7 @@ import (
"github.com/versity/versitygw/s3response"
)
func (c S3ApiController) RestoreObject(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) RestoreObject(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
@@ -39,7 +39,7 @@ func (c S3ApiController) RestoreObject(ctx *fiber.Ctx) (*Response, error) {
isBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -61,7 +61,7 @@ func (c S3ApiController) RestoreObject(ctx *fiber.Ctx) (*Response, error) {
}
var restoreRequest types.RestoreRequest
if err := xml.Unmarshal(ctx.Body(), &restoreRequest); err != nil {
if err := xml.Unmarshal(ctx.BodyRaw(), &restoreRequest); err != nil {
debuglogger.Logf("failed to parse the request body: %v", err)
return &Response{
MetaOpts: &MetaOptions{
@@ -70,7 +70,7 @@ func (c S3ApiController) RestoreObject(ctx *fiber.Ctx) (*Response, error) {
}, s3err.GetAPIError(s3err.ErrMalformedXML)
}
err = c.be.RestoreObject(ctx.Context(), &s3.RestoreObjectInput{
err = c.be.RestoreObject(ctx.RequestCtx(), &s3.RestoreObjectInput{
Bucket: &bucket,
Key: &key,
RestoreRequest: &restoreRequest,
@@ -83,7 +83,7 @@ func (c S3ApiController) RestoreObject(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) SelectObjectContent(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) SelectObjectContent(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
@@ -91,7 +91,7 @@ func (c S3ApiController) SelectObjectContent(ctx *fiber.Ctx) (*Response, error)
isBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -113,7 +113,7 @@ func (c S3ApiController) SelectObjectContent(ctx *fiber.Ctx) (*Response, error)
}
var payload s3response.SelectObjectContentPayload
err = xml.Unmarshal(ctx.Body(), &payload)
err = xml.Unmarshal(ctx.BodyRaw(), &payload)
if err != nil {
debuglogger.Logf("error unmarshalling select object content: %v", err)
return &Response{
@@ -123,7 +123,7 @@ func (c S3ApiController) SelectObjectContent(ctx *fiber.Ctx) (*Response, error)
}, s3err.GetAPIError(s3err.ErrMalformedXML)
}
sw := c.be.SelectObjectContent(ctx.Context(),
sw := c.be.SelectObjectContent(ctx.RequestCtx(),
&s3.SelectObjectContentInput{
Bucket: &bucket,
Key: &key,
@@ -135,7 +135,7 @@ func (c S3ApiController) SelectObjectContent(ctx *fiber.Ctx) (*Response, error)
ScanRange: payload.ScanRange,
})
ctx.Context().SetBodyStreamWriter(sw)
ctx.RequestCtx().SetBodyStreamWriter(sw)
return &Response{
MetaOpts: &MetaOptions{
@@ -144,7 +144,7 @@ func (c S3ApiController) SelectObjectContent(ctx *fiber.Ctx) (*Response, error)
}, nil
}
func (c S3ApiController) CreateMultipartUpload(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) CreateMultipartUpload(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
contentType := ctx.Get("Content-Type", defaultContentType)
@@ -175,7 +175,7 @@ func (c S3ApiController) CreateMultipartUpload(ctx *fiber.Ctx) (*Response, error
actions = append(actions, auth.PutObjectRetentionAction)
}
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -231,7 +231,7 @@ func (c S3ApiController) CreateMultipartUpload(ctx *fiber.Ctx) (*Response, error
}, err
}
res, err := c.be.CreateMultipartUpload(ctx.Context(),
res, err := c.be.CreateMultipartUpload(ctx.RequestCtx(),
s3response.CreateMultipartUploadInput{
Bucket: &bucket,
Key: &key,
@@ -266,7 +266,7 @@ func (c S3ApiController) CreateMultipartUpload(ctx *fiber.Ctx) (*Response, error
}, err
}
func (c S3ApiController) CompleteMultipartUpload(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) CompleteMultipartUpload(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
uploadId := ctx.Query("uploadId")
@@ -278,7 +278,7 @@ func (c S3ApiController) CompleteMultipartUpload(ctx *fiber.Ctx) (*Response, err
isBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -300,7 +300,7 @@ func (c S3ApiController) CompleteMultipartUpload(ctx *fiber.Ctx) (*Response, err
}
var body s3response.CompleteMultipartUploadRequestBody
err = xml.Unmarshal(ctx.Body(), &body)
err = xml.Unmarshal(ctx.BodyRaw(), &body)
if err != nil {
debuglogger.Logf("error unmarshalling complete multipart upload: %v", err)
return &Response{
@@ -363,7 +363,7 @@ func (c S3ApiController) CompleteMultipartUpload(ctx *fiber.Ctx) (*Response, err
ifMatch, ifNoneMatch := utils.ParsePreconditionMatchHeaders(ctx)
err = auth.CheckObjectAccess(ctx.Context(), bucket, acct.Access, []types.ObjectIdentifier{{Key: &key}}, true, isBucketPublic, c.be, true)
err = auth.CheckObjectAccess(ctx.RequestCtx(), bucket, acct.Access, []types.ObjectIdentifier{{Key: &key}}, true, isBucketPublic, c.be, true)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -372,7 +372,7 @@ func (c S3ApiController) CompleteMultipartUpload(ctx *fiber.Ctx) (*Response, err
}, err
}
res, versid, err := c.be.CompleteMultipartUpload(ctx.Context(),
res, versid, err := c.be.CompleteMultipartUpload(ctx.RequestCtx(),
&s3.CompleteMultipartUploadInput{
Bucket: &bucket,
Key: &key,
+33 -33
View File
@@ -24,7 +24,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3api/utils"
@@ -33,7 +33,7 @@ import (
"github.com/versity/versitygw/s3response"
)
func (c S3ApiController) PutObjectTagging(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutObjectTagging(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
@@ -47,7 +47,7 @@ func (c S3ApiController) PutObjectTagging(ctx *fiber.Ctx) (*Response, error) {
action = auth.PutObjectVersionTaggingAction
}
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -67,7 +67,7 @@ func (c S3ApiController) PutObjectTagging(ctx *fiber.Ctx) (*Response, error) {
}, err
}
tagging, err := utils.ParseTagging(ctx.Body(), utils.TagLimitObject)
tagging, err := utils.ParseTagging(ctx.BodyRaw(), utils.TagLimitObject)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -76,7 +76,7 @@ func (c S3ApiController) PutObjectTagging(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.PutObjectTagging(ctx.Context(), bucket, key, versionId, tagging)
err = c.be.PutObjectTagging(ctx.RequestCtx(), bucket, key, versionId, tagging)
return &Response{
Headers: map[string]*string{
"x-amz-version-id": &versionId,
@@ -88,7 +88,7 @@ func (c S3ApiController) PutObjectTagging(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) PutObjectRetention(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutObjectRetention(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
@@ -98,7 +98,7 @@ func (c S3ApiController) PutObjectRetention(ctx *fiber.Ctx) (*Response, error) {
IsBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -119,7 +119,7 @@ func (c S3ApiController) PutObjectRetention(ctx *fiber.Ctx) (*Response, error) {
}
// parse the request body bytes into a go struct and validate
retention, err := auth.ParseObjectLockRetentionInput(ctx.Body())
retention, err := auth.ParseObjectLockRetentionInput(ctx.BodyRaw())
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -129,7 +129,7 @@ func (c S3ApiController) PutObjectRetention(ctx *fiber.Ctx) (*Response, error) {
}
// check if the operation is allowed
err = auth.IsObjectLockRetentionPutAllowed(ctx.Context(), c.be, bucket, key, versionId, acct.Access, retention, bypass)
err = auth.IsObjectLockRetentionPutAllowed(ctx.RequestCtx(), c.be, bucket, key, versionId, acct.Access, retention, bypass)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -148,7 +148,7 @@ func (c S3ApiController) PutObjectRetention(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.PutObjectRetention(ctx.Context(), bucket, key, versionId, data)
err = c.be.PutObjectRetention(ctx.RequestCtx(), bucket, key, versionId, data)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -156,7 +156,7 @@ func (c S3ApiController) PutObjectRetention(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) PutObjectLegalHold(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutObjectLegalHold(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
versionId := ctx.Query("versionId")
@@ -165,7 +165,7 @@ func (c S3ApiController) PutObjectLegalHold(ctx *fiber.Ctx) (*Response, error) {
IsBucketPublic := utils.ContextKeyPublicBucket.IsSet(ctx)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
err := auth.VerifyAccess(ctx.RequestCtx(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -186,7 +186,7 @@ func (c S3ApiController) PutObjectLegalHold(ctx *fiber.Ctx) (*Response, error) {
}
var legalHold types.ObjectLockLegalHold
if err := xml.Unmarshal(ctx.Body(), &legalHold); err != nil {
if err := xml.Unmarshal(ctx.BodyRaw(), &legalHold); err != nil {
debuglogger.Logf("failed to parse request body: %v", err)
return &Response{
MetaOpts: &MetaOptions{
@@ -204,7 +204,7 @@ func (c S3ApiController) PutObjectLegalHold(ctx *fiber.Ctx) (*Response, error) {
}, s3err.GetAPIError(s3err.ErrMalformedXML)
}
err = c.be.PutObjectLegalHold(ctx.Context(), bucket, key, versionId, legalHold.Status == types.ObjectLockLegalHoldStatusOn)
err = c.be.PutObjectLegalHold(ctx.RequestCtx(), bucket, key, versionId, legalHold.Status == types.ObjectLockLegalHoldStatusOn)
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
@@ -212,10 +212,10 @@ func (c S3ApiController) PutObjectLegalHold(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) UploadPart(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) UploadPart(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
partNumber := int32(ctx.QueryInt("partNumber", -1))
partNumber := int32(fiber.Query(ctx, "partNumber", -1))
uploadId := ctx.Query("uploadId")
// context locals
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
@@ -234,7 +234,7 @@ func (c S3ApiController) UploadPart(ctx *fiber.Ctx) (*Response, error) {
contentLengthStr = decodedLength
}
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -292,7 +292,7 @@ func (c S3ApiController) UploadPart(ctx *fiber.Ctx) (*Response, error) {
body = bytes.NewReader([]byte{})
}
res, err := c.be.UploadPart(ctx.Context(),
res, err := c.be.UploadPart(ctx.RequestCtx(),
&s3.UploadPartInput{
Bucket: &bucket,
Key: &key,
@@ -338,13 +338,13 @@ func (c S3ApiController) UploadPart(ctx *fiber.Ctx) (*Response, error) {
}
func (c S3ApiController) UploadPartCopy(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) UploadPartCopy(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
copySource := strings.TrimPrefix(ctx.Get("X-Amz-Copy-Source"), "/")
copySrcRange := ctx.Get("X-Amz-Copy-Source-Range")
expectedSrcBucketOwnerUPC := ctx.Get("X-Amz-Source-Expected-Bucket-Owner")
partNumber := int32(ctx.QueryInt("partNumber", -1))
partNumber := int32(fiber.Query(ctx, "partNumber", -1))
uploadId := ctx.Query("uploadId")
// context locals
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
@@ -361,7 +361,7 @@ func (c S3ApiController) UploadPartCopy(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = auth.VerifyObjectCopyAccess(ctx.Context(), c.be, copySource,
err = auth.VerifyObjectCopyAccess(ctx.RequestCtx(), c.be, copySource,
auth.AccessOptions{
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -401,7 +401,7 @@ func (c S3ApiController) UploadPartCopy(ctx *fiber.Ctx) (*Response, error) {
preconditionHdrs := utils.ParsePreconditionHeaders(ctx, utils.WithCopySource())
resp, err := c.be.UploadPartCopy(ctx.Context(),
resp, err := c.be.UploadPartCopy(ctx.RequestCtx(),
&s3.UploadPartCopyInput{
Bucket: &bucket,
Key: &key,
@@ -430,7 +430,7 @@ func (c S3ApiController) UploadPartCopy(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) PutObjectAcl(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutObjectAcl(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
acl := ctx.Get("X-Amz-Acl")
@@ -444,7 +444,7 @@ func (c S3ApiController) PutObjectAcl(ctx *fiber.Ctx) (*Response, error) {
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -463,7 +463,7 @@ func (c S3ApiController) PutObjectAcl(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = c.be.PutObjectAcl(ctx.Context(), &s3.PutObjectAclInput{
err = c.be.PutObjectAcl(ctx.RequestCtx(), &s3.PutObjectAclInput{
Bucket: &bucket,
Key: &key,
GrantFullControl: &grantFullControl,
@@ -481,7 +481,7 @@ func (c S3ApiController) PutObjectAcl(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) CopyObject(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) CopyObject(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
copySource := strings.TrimPrefix(ctx.Get("X-Amz-Copy-Source"), "/")
@@ -525,7 +525,7 @@ func (c S3ApiController) CopyObject(ctx *fiber.Ctx) (*Response, error) {
actions = append(actions, auth.PutObjectRetentionAction)
}
err = auth.VerifyObjectCopyAccess(ctx.Context(), c.be, copySource,
err = auth.VerifyObjectCopyAccess(ctx.RequestCtx(), c.be, copySource,
auth.AccessOptions{
Acl: parsedAcl,
AclPermission: auth.PermissionWrite,
@@ -609,7 +609,7 @@ func (c S3ApiController) CopyObject(ctx *fiber.Ctx) (*Response, error) {
preconditionHdrs := utils.ParsePreconditionHeaders(ctx, utils.WithCopySource())
err = auth.CheckObjectAccess(ctx.Context(), bucket, acct.Access, []types.ObjectIdentifier{{Key: &key}}, true, false, c.be, true)
err = auth.CheckObjectAccess(ctx.RequestCtx(), bucket, acct.Access, []types.ObjectIdentifier{{Key: &key}}, true, false, c.be, true)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -618,7 +618,7 @@ func (c S3ApiController) CopyObject(ctx *fiber.Ctx) (*Response, error) {
}, err
}
res, err := c.be.CopyObject(ctx.Context(),
res, err := c.be.CopyObject(ctx.RequestCtx(),
s3response.CopyObjectInput{
Bucket: &bucket,
Key: &key,
@@ -667,7 +667,7 @@ func (c S3ApiController) CopyObject(ctx *fiber.Ctx) (*Response, error) {
}, err
}
func (c S3ApiController) PutObject(ctx *fiber.Ctx) (*Response, error) {
func (c S3ApiController) PutObject(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
key := strings.TrimPrefix(ctx.Path(), fmt.Sprintf("/%s/", bucket))
contentType := ctx.Get("Content-Type", defaultContentType)
@@ -710,7 +710,7 @@ func (c S3ApiController) PutObject(ctx *fiber.Ctx) (*Response, error) {
actions = append(actions, auth.PutObjectRetentionAction)
}
err := auth.VerifyAccess(ctx.Context(), c.be,
err := auth.VerifyAccess(ctx.RequestCtx(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -750,7 +750,7 @@ func (c S3ApiController) PutObject(ctx *fiber.Ctx) (*Response, error) {
}, err
}
err = auth.CheckObjectAccess(ctx.Context(), bucket, acct.Access, []types.ObjectIdentifier{{Key: &key}}, true, IsBucketPublic, c.be, true)
err = auth.CheckObjectAccess(ctx.RequestCtx(), bucket, acct.Access, []types.ObjectIdentifier{{Key: &key}}, true, IsBucketPublic, c.be, true)
if err != nil {
return &Response{
MetaOpts: &MetaOptions{
@@ -797,7 +797,7 @@ func (c S3ApiController) PutObject(ctx *fiber.Ctx) (*Response, error) {
ifMatch, ifNoneMatch := utils.ParsePreconditionMatchHeaders(ctx)
res, err := c.be.PutObject(ctx.Context(),
res, err := c.be.PutObject(ctx.RequestCtx(),
s3response.PutObjectInput{
Bucket: &bucket,
Key: &key,
+3 -3
View File
@@ -18,7 +18,7 @@ import (
"errors"
"net/http"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3api/middlewares"
@@ -26,7 +26,7 @@ import (
"github.com/versity/versitygw/s3err"
)
func (s S3ApiController) CORSOptions(ctx *fiber.Ctx) (*Response, error) {
func (s S3ApiController) CORSOptions(ctx fiber.Ctx) (*Response, error) {
bucket := ctx.Params("bucket")
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
// get headers
@@ -65,7 +65,7 @@ func (s S3ApiController) CORSOptions(ctx *fiber.Ctx) (*Response, error) {
}, err
}
cors, err := s.be.GetBucketCors(ctx.Context(), bucket)
cors, err := s.be.GetBucketCors(ctx.RequestCtx(), bucket)
if err != nil {
debuglogger.Logf("failed to get bucket cors: %v", err)
if errors.Is(err, s3err.GetAPIError(s3err.ErrNoSuchCORSConfiguration)) {
+3 -3
View File
@@ -16,7 +16,7 @@ package middlewares
import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/s3api/utils"
@@ -26,9 +26,9 @@ import (
// ParseAcl retreives the bucket acl and stores in the context locals
// if no bucket is found, it returns 'NoSuchBucket'
func ParseAcl(be backend.Backend) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
bucket := ctx.Params("bucket")
data, err := be.GetBucketAcl(ctx.Context(), &s3.GetBucketAclInput{Bucket: &bucket})
data, err := be.GetBucketAcl(ctx.RequestCtx(), &s3.GetBucketAclInput{Bucket: &bucket})
if err != nil {
return err
}
+2 -2
View File
@@ -15,7 +15,7 @@
package middlewares
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
@@ -23,7 +23,7 @@ import (
// IsAdmin is a middleware that restricts access to admin APIs, allowing only admin users
func IsAdmin(action string) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
if acct.Role != auth.RoleAdmin {
return s3err.GetAPIError(s3err.ErrAdminAccessDenied)
@@ -17,7 +17,7 @@ package middlewares
import (
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/s3err"
)
@@ -36,12 +36,12 @@ import (
func ApplyBucketCORSPreflightFallback(be backend.Backend, fallbackOrigin string) fiber.Handler {
fallbackOrigin = strings.TrimSpace(fallbackOrigin)
if fallbackOrigin == "" {
return func(ctx *fiber.Ctx) error { return ctx.Next() }
return func(ctx fiber.Ctx) error { return ctx.Next() }
}
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
bucket := ctx.Params("bucket")
_, err := be.GetBucketCors(ctx.Context(), bucket)
_, err := be.GetBucketCors(ctx.RequestCtx(), bucket)
if err != nil {
if s3Err, ok := err.(s3err.S3Error); ok && (s3Err.BaseError().Code == "NoSuchCORSConfiguration" || s3Err.BaseError().Code == "NoSuchBucket") {
if len(ctx.Response().Header.Peek("Access-Control-Allow-Origin")) == 0 {
@@ -19,7 +19,7 @@ import (
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/s3err"
)
@@ -43,7 +43,7 @@ func TestApplyBucketCORSPreflightFallback_NoBucketCors_Responds204(t *testing.T)
app := fiber.New()
app.Options("/:bucket",
ApplyBucketCORSPreflightFallback(be, "https://example.com"),
func(c *fiber.Ctx) error {
func(c fiber.Ctx) error {
// Should not be reached if fallback triggers
return c.SendStatus(http.StatusTeapot)
},
@@ -87,7 +87,7 @@ func TestApplyBucketCORSPreflightFallback_NoSuchBucket_Responds204(t *testing.T)
app := fiber.New()
app.Options("/:bucket",
ApplyBucketCORSPreflightFallback(be, "https://example.com"),
func(c *fiber.Ctx) error {
func(c fiber.Ctx) error {
return c.SendStatus(http.StatusTeapot)
},
)
@@ -127,7 +127,7 @@ func TestApplyBucketCORSPreflightFallback_BucketHasCors_CallsNext(t *testing.T)
app := fiber.New()
app.Options("/:bucket",
ApplyBucketCORSPreflightFallback(be, "https://example.com"),
func(c *fiber.Ctx) error {
func(c fiber.Ctx) error {
return c.SendStatus(http.StatusOK)
},
)
+5 -5
View File
@@ -18,7 +18,7 @@ import (
"fmt"
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/debuglogger"
@@ -28,9 +28,9 @@ import (
// Vary http response header is always the same below
var VaryHdr = "Origin, Access-Control-Request-Headers, Access-Control-Request-Method"
type BucketResolver func(ctx *fiber.Ctx) (string, error)
type BucketResolver func(ctx fiber.Ctx) (string, error)
func BucketFromPath(ctx *fiber.Ctx) (string, error) {
func BucketFromPath(ctx fiber.Ctx) (string, error) {
return ctx.Params("bucket"), nil
}
@@ -41,7 +41,7 @@ func BucketFromPath(ctx *fiber.Ctx) (string, error) {
func ApplyBucketCORS(be backend.Backend, resolveBucket BucketResolver, fallbackOrigin string) fiber.Handler {
fallbackOrigin = strings.TrimSpace(fallbackOrigin)
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
origin := ctx.Get("Origin")
// If neither Origin is present nor a fallback is configured, skip CORS entirely.
if origin == "" && fallbackOrigin == "" {
@@ -54,7 +54,7 @@ func ApplyBucketCORS(be backend.Backend, resolveBucket BucketResolver, fallbackO
}
// if bucket cors is not set, skip the check
data, err := be.GetBucketCors(ctx.Context(), bucket)
data, err := be.GetBucketCors(ctx.RequestCtx(), bucket)
if err != nil {
// If CORS is not configured, S3Error will have code NoSuchCORSConfiguration.
// In this case, we can safely continue. For any other error, we should log it.
@@ -17,7 +17,7 @@ package middlewares
import (
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)
// ApplyDefaultCORSPreflight responds to CORS preflight (OPTIONS) requests for routes
@@ -29,10 +29,10 @@ import (
func ApplyDefaultCORSPreflight(fallbackOrigin string) fiber.Handler {
fallbackOrigin = strings.TrimSpace(fallbackOrigin)
if fallbackOrigin == "" {
return func(ctx *fiber.Ctx) error { return nil }
return func(ctx fiber.Ctx) error { return nil }
}
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
if len(ctx.Response().Header.Peek("Access-Control-Allow-Origin")) == 0 {
ctx.Response().Header.Add("Access-Control-Allow-Origin", fallbackOrigin)
}
@@ -18,7 +18,7 @@ import (
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)
func TestApplyDefaultCORSPreflight_OptionsSetsPreflightHeaders(t *testing.T) {
@@ -28,7 +28,7 @@ func TestApplyDefaultCORSPreflight_OptionsSetsPreflightHeaders(t *testing.T) {
app.Options("/admin",
ApplyDefaultCORSPreflight(origin),
ApplyDefaultCORS(origin),
func(c *fiber.Ctx) error { return nil },
func(c fiber.Ctx) error { return nil },
)
req, err := http.NewRequest(http.MethodOptions, "/admin", nil)
+4 -4
View File
@@ -17,10 +17,10 @@ package middlewares
import (
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)
func ensureExposeETag(ctx *fiber.Ctx) {
func ensureExposeETag(ctx fiber.Ctx) {
existing := strings.TrimSpace(string(ctx.Response().Header.Peek("Access-Control-Expose-Headers")))
defaults := []string{"ETag", "x-amz-storage-class"}
if existing == "" {
@@ -57,10 +57,10 @@ func ensureExposeETag(ctx *fiber.Ctx) {
func ApplyDefaultCORS(fallbackOrigin string) fiber.Handler {
fallbackOrigin = strings.TrimSpace(fallbackOrigin)
if fallbackOrigin == "" {
return func(ctx *fiber.Ctx) error { return nil }
return func(ctx fiber.Ctx) error { return nil }
}
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
if len(ctx.Response().Header.Peek("Access-Control-Allow-Origin")) == 0 {
ctx.Response().Header.Add("Access-Control-Allow-Origin", fallbackOrigin)
}
+4 -4
View File
@@ -18,14 +18,14 @@ import (
"net/http"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)
func TestApplyDefaultCORS_AddsHeaderWhenOriginSet(t *testing.T) {
origin := "https://example.com"
app := fiber.New()
app.Get("/admin", ApplyDefaultCORS(origin), func(c *fiber.Ctx) error {
app.Get("/admin", ApplyDefaultCORS(origin), func(c fiber.Ctx) error {
return c.SendStatus(http.StatusOK)
})
@@ -52,10 +52,10 @@ func TestApplyDefaultCORS_DoesNotOverrideExistingHeader(t *testing.T) {
origin := "https://example.com"
app := fiber.New()
app.Get("/admin", func(c *fiber.Ctx) error {
app.Get("/admin", func(c fiber.Ctx) error {
c.Response().Header.Add("Access-Control-Allow-Origin", "https://already-set.com")
return nil
}, ApplyDefaultCORS(origin), func(c *fiber.Ctx) error {
}, ApplyDefaultCORS(origin), func(c fiber.Ctx) error {
return c.SendStatus(http.StatusOK)
})
+3 -3
View File
@@ -21,7 +21,7 @@ import (
"strconv"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
@@ -41,7 +41,7 @@ type RootUserConfig struct {
func VerifyV4Signature(root RootUserConfig, iam auth.IAMService, region string, streamBody, requireContentSha256, allowDefaultRegion bool) fiber.Handler {
acct := accounts{root: root, iam: iam}
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
// The bucket is public, no need to check this signature
if utils.ContextKeyPublicBucket.IsSet(ctx) {
return nil
@@ -178,7 +178,7 @@ func VerifyV4Signature(root RootUserConfig, iam auth.IAMService, region string,
if !utils.IsSpecialPayload(hashPayload) {
// Calculate the hash of the request payload
hashedPayload := sha256.Sum256(ctx.Body())
hashedPayload := sha256.Sum256(ctx.BodyRaw())
hexPayload := hex.EncodeToString(hashedPayload[:])
// Compare the calculated hash with the hash provided
+2 -2
View File
@@ -18,7 +18,7 @@ import (
"bytes"
"io"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/s3api/utils"
)
@@ -85,7 +85,7 @@ func (rr *MockChecksumReader) Checksum() string {
var _ ChecksumReader = &MockChecksumReader{}
func wrapBodyReader(ctx *fiber.Ctx, wr func(io.Reader) io.Reader) {
func wrapBodyReader(ctx fiber.Ctx, wr func(io.Reader) io.Reader) {
rdr, ok := utils.ContextKeyBodyReader.Get(ctx).(io.Reader)
if !ok {
rdr = ctx.Request().BodyStream()
@@ -15,7 +15,7 @@
package middlewares
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
)
@@ -23,7 +23,7 @@ import (
// BucketObjectNameValidator extracts and validates
// the bucket and object names from the request URI.
func BucketObjectNameValidator() fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
bucket, object := parsePath(ctx.Path())
// check if the provided bucket name is valid
+3 -3
View File
@@ -20,7 +20,7 @@ import (
"io"
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
)
@@ -32,7 +32,7 @@ import (
// it wraps the body reader to handle Content-MD5:
// the x-amz-checksum-* headers are explicitly processed by the backend.
func VerifyChecksums(streamBody bool, requireBody bool, requireChecksum bool) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
md5sum := ctx.Get("Content-Md5")
if streamBody {
@@ -58,7 +58,7 @@ func VerifyChecksums(streamBody bool, requireBody bool, requireChecksum bool) fi
return nil
}
body := ctx.Body()
body := ctx.BodyRaw()
if requireBody && len(body) == 0 {
return s3err.GetAPIError(s3err.ErrMissingRequestBody)
}
+2 -2
View File
@@ -18,13 +18,13 @@ import (
"fmt"
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)
// HostStyleParser is a middleware which parses the bucket name
// from the 'Host' header and appends in the request URL path
func HostStyleParser(virtualDomain string) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
host := string(ctx.Request().Host())
// the host should match this pattern: '<bucket_name>.<virtual_domain>'
bucket, _, found := strings.Cut(host, "."+virtualDomain)
+2 -2
View File
@@ -15,12 +15,12 @@
package middlewares
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/debuglogger"
)
func DebugLogger() fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
debuglogger.LogFiberRequestDetails(ctx)
err := ctx.Next()
debuglogger.LogFiberResponseDetails(ctx)
+3 -3
View File
@@ -20,7 +20,7 @@ import (
"strconv"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3api/utils"
@@ -49,7 +49,7 @@ type PostObjectResult struct {
func AuthorizePostObject(root RootUserConfig, iam auth.IAMService, region string) fiber.Handler {
acct := accounts{root: root, iam: iam}
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
contentLengthStr := ctx.Get("Content-Length")
reqContentLength, err := strconv.ParseInt(contentLengthStr, 10, 64)
if err != nil {
@@ -71,7 +71,7 @@ func AuthorizePostObject(root RootUserConfig, iam auth.IAMService, region string
bodyRdr := ctx.Request().BodyStream()
if bodyRdr == nil {
bodyRdr = bytes.NewReader(ctx.Body())
bodyRdr = bytes.NewReader(ctx.BodyRaw())
}
mpParser, err := utils.NewMultipartParser(bodyRdr, boundary, reqContentLength)
+9 -9
View File
@@ -26,7 +26,7 @@ import (
"testing"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/stretchr/testify/assert"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
@@ -37,7 +37,7 @@ import (
// versitygw middlewares) returns nil without calling c.Next(), so they must
// be chained explicitly rather than relying on fiber's c.Next() mechanism.
func chainHandlers(handlers ...fiber.Handler) fiber.Handler {
return func(c *fiber.Ctx) error {
return func(c fiber.Ctx) error {
for _, h := range handlers {
if err := h(c); err != nil {
return err
@@ -51,7 +51,7 @@ func chainHandlers(handlers ...fiber.Handler) fiber.Handler {
// the provided follow-up handler on POST /:bucket.
func postObjectTestApp(root RootUserConfig, region string, next fiber.Handler) *fiber.App {
app := fiber.New(fiber.Config{
ErrorHandler: func(c *fiber.Ctx, err error) error {
ErrorHandler: func(c fiber.Ctx, err error) error {
if s3Err, ok := err.(s3err.S3Error); ok {
return c.Status(s3Err.StatusCode()).Send(s3Err.XMLBody("", ""))
}
@@ -124,7 +124,7 @@ func TestAuthorizePostObject_AnonymousRequest(t *testing.T) {
app := postObjectTestApp(
RootUserConfig{Access: "root", Secret: "rootsecret"},
"us-east-1",
func(c *fiber.Ctx) error {
func(c fiber.Ctx) error {
gotResult = utils.ContextKeyObjectPostResult.Get(c).(PostObjectResult)
gotAuthenticated = utils.ContextKeyAuthenticated.IsSet(c)
return c.SendStatus(http.StatusOK)
@@ -150,7 +150,7 @@ func TestAuthorizePostObject_AnonymousRequest_SetsPostObjectResult(t *testing.T)
app := postObjectTestApp(
RootUserConfig{Access: "root", Secret: "rootsecret"},
"us-east-1",
func(c *fiber.Ctx) error {
func(c fiber.Ctx) error {
gotResult = utils.ContextKeyObjectPostResult.Get(c).(PostObjectResult)
return c.SendStatus(http.StatusOK)
},
@@ -194,7 +194,7 @@ func TestAuthorizePostObject_SignedRequest(t *testing.T) {
app := postObjectTestApp(
RootUserConfig{Access: accessKey, Secret: secretKey},
region,
func(c *fiber.Ctx) error {
func(c fiber.Ctx) error {
gotAuthenticated = utils.ContextKeyAuthenticated.IsSet(c)
return c.SendStatus(http.StatusOK)
},
@@ -236,7 +236,7 @@ func TestAuthorizePostObject_SignedRequest_WrongSignature(t *testing.T) {
app := postObjectTestApp(
RootUserConfig{Access: accessKey, Secret: secretKey},
region,
func(c *fiber.Ctx) error { return c.SendStatus(http.StatusOK) },
func(c fiber.Ctx) error { return c.SendStatus(http.StatusOK) },
)
body, boundary := buildMultipartBody(t, map[string]string{
@@ -259,7 +259,7 @@ func TestAuthorizePostObject_PartialAuthFields_ReturnsError(t *testing.T) {
app := postObjectTestApp(
RootUserConfig{Access: "root", Secret: "rootsecret"},
"us-east-1",
func(c *fiber.Ctx) error { return c.SendStatus(http.StatusOK) },
func(c fiber.Ctx) error { return c.SendStatus(http.StatusOK) },
)
// Only algorithm is provided — credential, date, policy, signature absent.
@@ -279,7 +279,7 @@ func TestAuthorizePostObject_InvalidContentType_ReturnsError(t *testing.T) {
app := postObjectTestApp(
RootUserConfig{Access: "root", Secret: "rootsecret"},
"us-east-1",
func(c *fiber.Ctx) error { return c.SendStatus(http.StatusOK) },
func(c fiber.Ctx) error { return c.SendStatus(http.StatusOK) },
)
req, err := http.NewRequest(http.MethodPost, "/mybucket", strings.NewReader("body"))
+2 -2
View File
@@ -18,7 +18,7 @@ import (
"io"
"strconv"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
@@ -27,7 +27,7 @@ import (
func VerifyPresignedV4Signature(root RootUserConfig, iam auth.IAMService, region string, streamBody bool) fiber.Handler {
acct := accounts{root: root, iam: iam}
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
// The bucket is public, no need to check this signature
if utils.ContextKeyPublicBucket.IsSet(ctx) {
return nil
+4 -4
View File
@@ -20,7 +20,7 @@ import (
"io"
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/metrics"
@@ -31,7 +31,7 @@ import (
// AuthorizePublicBucketAccess checks if the bucket grants public
// access to anonymous requesters
func AuthorizePublicBucketAccess(be backend.Backend, s3action string, policyPermission auth.Action, permission auth.Permission, region string, streamBody bool) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
// skip for authenticated requests
if utils.IsPresignedURLAuth(ctx) || ctx.Get("Authorization") != "" || utils.ContextKeyAuthenticated.IsSet(ctx) {
return nil
@@ -57,7 +57,7 @@ func AuthorizePublicBucketAccess(be backend.Backend, s3action string, policyPerm
}
bucket, object := parsePath(ctx.Path())
err := auth.VerifyPublicAccess(ctx.Context(), be, policyPermission, permission, bucket, object)
err := auth.VerifyPublicAccess(ctx.RequestCtx(), be, policyPermission, permission, bucket, object)
if err != nil {
if s3action == metrics.ActionHeadBucket {
// add the bucket region header for HeadBucket
@@ -114,7 +114,7 @@ func AuthorizePublicBucketAccess(be backend.Backend, s3action string, policyPerm
if payloadHash != "" {
// Calculate the hash of the request payload
hashedPayload := sha256.Sum256(ctx.Body())
hashedPayload := sha256.Sum256(ctx.BodyRaw())
hexPayload := hex.EncodeToString(hashedPayload[:])
// Compare the calculated hash with the hash provided
+3 -3
View File
@@ -15,7 +15,7 @@
package middlewares
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/metrics"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
@@ -28,7 +28,7 @@ import (
func RateLimiter(limit int, mm metrics.Manager, logger s3log.AuditLogger) fiber.Handler {
sem := semaphore.NewWeighted(int64(limit))
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
requestID, hostID := utils.EnsureRequestIDs(ctx)
if !sem.TryAcquire(1) {
@@ -39,7 +39,7 @@ func RateLimiter(limit int, mm metrics.Manager, logger s3log.AuditLogger) fiber.
mm.Send(ctx, err, metrics.ActionUndetected, 0, 0)
}
if logger != nil {
logger.Log(ctx, err, ctx.Body(), s3log.LogMeta{
logger.Log(ctx, err, ctx.BodyRaw(), s3log.LogMeta{
Action: metrics.ActionUndetected,
})
}
+2 -2
View File
@@ -15,13 +15,13 @@
package middlewares
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/s3api/utils"
)
// RequestIDs sets requestID and hostID in context locals
func RequestIDs() fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
utils.EnsureRequestIDs(ctx)
return ctx.Next()
}
+3 -3
View File
@@ -20,15 +20,15 @@ import (
"regexp"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/stretchr/testify/assert"
"github.com/versity/versitygw/s3api/utils"
)
func TestRequestIDs(t *testing.T) {
app := fiber.New()
app.Use(RequestIDs())
app.Get("/", func(ctx *fiber.Ctx) error {
app.Use("*", RequestIDs())
app.Get("/", func(ctx fiber.Ctx) error {
assert.NotEmpty(t, utils.RequestID(ctx))
assert.NotEmpty(t, utils.HostID(ctx))
return ctx.SendStatus(http.StatusNoContent)
+4 -4
View File
@@ -15,13 +15,13 @@
package middlewares
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/s3api/utils"
)
// Evaluates/Matches the provided requst query params
func MatchQueryArgs(args ...string) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
if utils.ContextKeySkip.IsSet(ctx) {
return ctx.Next()
}
@@ -37,7 +37,7 @@ func MatchQueryArgs(args ...string) fiber.Handler {
// Evaluates/Matches the requst header
func MatchHeader(key string) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
if utils.ContextKeySkip.IsSet(ctx) {
return ctx.Next()
}
@@ -53,7 +53,7 @@ func MatchHeader(key string) fiber.Handler {
// Evaluates/Matches the requst query param and value
func MatchQueryArgWithValue(key, val string) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
if utils.ContextKeySkip.IsSet(ctx) {
return ctx.Next()
}
+2 -2
View File
@@ -17,13 +17,13 @@ package middlewares
import (
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
)
func SetDefaultValues(root RootUserConfig, region string) fiber.Handler {
return func(ctx *fiber.Ctx) error {
return func(ctx fiber.Ctx) error {
// These are necessary for the server access logs
utils.ContextKeyRegion.Set(ctx, region)
utils.ContextKeyStartTime.Set(ctx, time.Now())
+2 -2
View File
@@ -17,12 +17,12 @@ package middlewares
import (
"net/url"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)
// DecodeURL url path unescapes the request url for the gateway
// to handle some special characters
func DecodeURL(ctx *fiber.Ctx) error {
func DecodeURL(ctx fiber.Ctx) error {
unescp, err := url.PathUnescape(string(ctx.Request().URI().PathOriginal()))
if err != nil {
return err
+12 -12
View File
@@ -17,7 +17,7 @@ package s3api
import (
"net/http"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/metrics"
@@ -56,7 +56,7 @@ func (sa *S3ApiRouter) Init() {
// initialize global host-style parser middleware if virtual domain is specified
if sa.virtualDomain != "" {
sa.app.Use(middlewares.HostStyleParser(sa.virtualDomain))
sa.app.Use("*", middlewares.HostStyleParser(sa.virtualDomain))
}
if sa.WithAdmSrv {
@@ -158,7 +158,7 @@ func (sa *S3ApiRouter) Init() {
// copy source is not allowed on '/'
sa.app.Get("/", middlewares.MatchHeader("X-Amz-Copy-Source"),
controllers.ProcessHandlers(
func(ctx *fiber.Ctx) (*controllers.Response, error) {
func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetInvalidArgumentErr(s3err.InvalidArgCopySource, ctx.Get("X-Amz-Copy-Source"))
},
metrics.ActionUndetected,
@@ -475,7 +475,7 @@ func (sa *S3ApiRouter) Init() {
// copy source is not allowed on bucket HEAD operation
bucketRouter.Head("/", middlewares.MatchHeader("X-Amz-Copy-Source"),
controllers.ProcessHandlers(
func(ctx *fiber.Ctx) (*controllers.Response, error) {
func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetInvalidArgumentErr(s3err.InvalidArgCopySource, ctx.Get("X-Amz-Copy-Source"))
},
metrics.ActionUndetected,
@@ -501,7 +501,7 @@ func (sa *S3ApiRouter) Init() {
// copy source is not allowed on bucket DELETE operation
bucketRouter.Delete("/", middlewares.MatchHeader("X-Amz-Copy-Source"),
controllers.ProcessHandlers(
func(ctx *fiber.Ctx) (*controllers.Response, error) {
func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetInvalidArgumentErr(s3err.InvalidArgCopySource, ctx.Get("X-Amz-Copy-Source"))
},
metrics.ActionUndetected,
@@ -697,7 +697,7 @@ func (sa *S3ApiRouter) Init() {
// copy source is not allowed on bucket GET operation
bucketRouter.Get("/", middlewares.MatchHeader("X-Amz-Copy-Source"),
controllers.ProcessHandlers(
func(ctx *fiber.Ctx) (*controllers.Response, error) {
func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetInvalidArgumentErr(s3err.InvalidArgCopySource, ctx.Get("X-Amz-Copy-Source"))
},
metrics.ActionUndetected,
@@ -1102,7 +1102,7 @@ func (sa *S3ApiRouter) Init() {
middlewares.MatchHeader("X-Amz-Copy-Source"),
middlewares.MatchQueryArgs("uploadId"),
controllers.ProcessHandlers(
func(ctx *fiber.Ctx) (*controllers.Response, error) {
func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetInvalidArgumentErr(s3err.InvalidArgCopySource, ctx.Get("X-Amz-Copy-Source"))
},
metrics.ActionUndetected,
@@ -1142,7 +1142,7 @@ func (sa *S3ApiRouter) Init() {
objectRouter.Head("/",
middlewares.MatchHeader("X-Amz-Copy-Source"),
controllers.ProcessHandlers(
func(ctx *fiber.Ctx) (*controllers.Response, error) {
func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetInvalidArgumentErr(s3err.InvalidArgCopySource, ctx.Get("X-Amz-Copy-Source"))
},
metrics.ActionUndetected,
@@ -1182,7 +1182,7 @@ func (sa *S3ApiRouter) Init() {
objectRouter.Get("/",
middlewares.MatchHeader("X-Amz-Copy-Source"),
controllers.ProcessHandlers(
func(ctx *fiber.Ctx) (*controllers.Response, error) {
func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetInvalidArgumentErr(s3err.InvalidArgCopySource, ctx.Get("X-Amz-Copy-Source"))
},
metrics.ActionUndetected,
@@ -1287,7 +1287,7 @@ func (sa *S3ApiRouter) Init() {
objectRouter.Delete("/",
middlewares.MatchHeader("X-Amz-Copy-Source"),
controllers.ProcessHandlers(
func(ctx *fiber.Ctx) (*controllers.Response, error) {
func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetInvalidArgumentErr(s3err.InvalidArgCopySource, ctx.Get("X-Amz-Copy-Source"))
},
metrics.ActionUndetected,
@@ -1341,7 +1341,7 @@ func (sa *S3ApiRouter) Init() {
middlewares.MatchHeader("X-Amz-Copy-Source"),
middlewares.MatchQueryArgs("uploadId"),
controllers.ProcessHandlers(
func(ctx *fiber.Ctx) (*controllers.Response, error) {
func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetInvalidArgumentErr(s3err.InvalidArgCopySource, ctx.Get("X-Amz-Copy-Source"))
},
metrics.ActionUndetected,
@@ -1561,7 +1561,7 @@ func (sa *S3ApiRouter) Init() {
)
// Return MethodNotAllowed for all the unmatched routes
sa.app.All("*", controllers.ProcessHandlers(func(ctx *fiber.Ctx) (*controllers.Response, error) {
sa.app.All("*", controllers.ProcessHandlers(func(ctx fiber.Ctx) (*controllers.Response, error) {
return &controllers.Response{}, s3err.GetMethodNotAllowedErr(ctx.Method(), s3err.ResourceTypeService, nil)
}, metrics.ActionUndetected, services))
}
+1 -1
View File
@@ -21,7 +21,7 @@ import (
"testing"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/s3err"
+1 -1
View File
@@ -17,7 +17,7 @@ package s3api
import (
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
)
+71 -30
View File
@@ -23,9 +23,10 @@ import (
"strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/logger"
"github.com/gofiber/fiber/v3/middleware/recover"
"github.com/valyala/fasthttp"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/debuglogger"
@@ -40,7 +41,8 @@ import (
)
const (
shutDownDuration = time.Second * 10
shutDownDuration = time.Second * 10
requestHeaderMaxSize = 8 * 1024
)
type S3ApiServer struct {
@@ -102,25 +104,24 @@ func New(
}
app := fiber.New(fiber.Config{
AppName: "versitygw",
ServerHeader: "VERSITYGW",
StreamRequestBody: true,
DisableKeepalive: !server.keepAlive,
Network: fiber.NetworkTCP,
DisableStartupMessage: true,
ErrorHandler: globalErrorHandler,
Concurrency: server.maxConnections,
AppName: "versitygw",
ServerHeader: "VERSITYGW",
StreamRequestBody: true,
DisableKeepalive: !server.keepAlive,
ErrorHandler: globalErrorHandler,
Concurrency: server.maxConnections,
// Sets buffer limit to read/parse incoming requests
// if the limit is reached, fiber/fasthttp will throw an error
// in the global error handler
ReadBufferSize: 8 * 1024, // 8 KB
ReadBufferSize: requestHeaderMaxSize,
})
installRequestHeaderLimitErrorHandler(app)
server.app = app
server.Router.app = app
// initialize the panic recovery middleware
app.Use(recover.New(
app.Use("*", recover.New(
recover.Config{
EnableStackTrace: true,
StackTraceHandler: stackTraceHandler,
@@ -128,35 +129,41 @@ func New(
// Logging middlewares
if !server.quiet {
app.Use(logger.New(logger.Config{
app.Use("*", logger.New(logger.Config{
Format: "${time} | vgw | ${status} | ${latency} | ${ip} | ${method} | ${path} | ${error} | ${queryParams}\n",
}))
}
// initialize requestId middleware
app.Use(middlewares.RequestIDs())
app.Use("*", middlewares.RequestIDs())
// Set up health endpoint if specified
if server.health != "" {
app.Get(server.health, func(ctx *fiber.Ctx) error {
app.Get(server.health, func(ctx fiber.Ctx) error {
return ctx.SendStatus(http.StatusOK)
})
}
// Set up WebUI on the S3 port if configured
if server.webuiSrvCfg != nil {
webui.MountOn(app, server.webuiMountPrefix, server.webuiSrvCfg)
if err := webui.MountOn(app, server.webuiMountPrefix, server.webuiSrvCfg); err != nil {
return nil, fmt.Errorf("mount webui: %w", err)
}
}
// initialize total requests cap limiter middleware
app.Use(middlewares.RateLimiter(server.maxRequests, mm, l))
app.Use("*", middlewares.RateLimiter(server.maxRequests, mm, l))
for _, route := range server.routes {
method, err := validateRouteMount(route)
if err != nil {
return nil, err
}
app.Add(method, route.path, route.handlers...)
handlers := make([]any, len(route.handlers)-1)
for i := range handlers {
handlers[i] = route.handlers[i+1]
}
app.Add([]string{method}, route.path, route.handlers[0], handlers...)
}
for _, mount := range server.middlewares {
@@ -167,15 +174,15 @@ func New(
}
// initilaze the default value setter middleware
app.Use(middlewares.SetDefaultValues(root, region))
app.Use("*", middlewares.SetDefaultValues(root, region))
// initialize the 'DecodeURL' middleware which
// path unescapes the url
app.Use(controllers.WrapMiddleware(middlewares.DecodeURL, l, mm))
app.Use("*", controllers.WrapMiddleware(middlewares.DecodeURL, l, mm))
// initialize the debug logger in debug mode
if debuglogger.IsDebugEnabled() {
app.Use(middlewares.DebugLogger())
app.Use("*", middlewares.DebugLogger())
}
server.Router.Init()
@@ -357,9 +364,9 @@ func (sa *S3ApiServer) ServeMultiPort(ports []string) error {
var err error
if sa.CertStorage != nil {
ln, err = utils.NewMultiAddrTLSListener(sa.app.Config().Network, portSpec, sa.CertStorage.GetCertificate, utils.ListenerOptions{SocketPerm: sa.socketPerm})
ln, err = utils.NewMultiAddrTLSListener(fiber.NetworkTCP, portSpec, sa.CertStorage.GetCertificate, utils.ListenerOptions{SocketPerm: sa.socketPerm})
} else {
ln, err = utils.NewMultiAddrListener(sa.app.Config().Network, portSpec, utils.ListenerOptions{SocketPerm: sa.socketPerm})
ln, err = utils.NewMultiAddrListener(fiber.NetworkTCP, portSpec, utils.ListenerOptions{SocketPerm: sa.socketPerm})
}
if err != nil {
return fmt.Errorf("failed to bind s3 listener %s: %w", portSpec, err)
@@ -383,7 +390,9 @@ func (sa *S3ApiServer) ServeMultiPort(ports []string) error {
})
}
return sa.app.Listener(finalListener)
return sa.app.Listener(finalListener, fiber.ListenConfig{
DisableStartupMessage: true,
})
}
// ShutDown gracefully shuts down the server with a context timeout
@@ -393,13 +402,45 @@ func (sa *S3ApiServer) ShutDown() error {
// stackTraceHandler stores the system panics
// in the context locals
func stackTraceHandler(ctx *fiber.Ctx, e any) {
func stackTraceHandler(ctx fiber.Ctx, e any) {
utils.ContextKeyStack.Set(ctx, e)
}
// installRequestHeaderLimitErrorHandler converts fasthttp small-buffer errors
// into the S3 RequestHeaderSectionTooLarge response.
//
// This is a temporary solution until Fiber handles request header limit errors
// before response writes correctly. See:
// https://github.com/gofiber/fiber/issues/4423
func installRequestHeaderLimitErrorHandler(app *fiber.App) {
server := app.Server()
fiberErrorHandler := server.ErrorHandler
server.ErrorHandler = func(ctx *fasthttp.RequestCtx, err error) {
var smallBufferErr *fasthttp.ErrSmallBuffer
if errors.As(err, &smallBufferErr) {
debuglogger.Logf("total request headers size exceeds the allowed 8KB")
requestID := utils.NewS3RequestID()
hostID := utils.NewS3HostID()
apiErr := s3err.GetRequestHeaderSectionTooLargeErr(requestHeaderMaxSize)
ctx.Response.Reset()
ctx.Response.Header.SetContentType(fiber.MIMEApplicationXML)
ctx.Response.Header.Set(utils.HeaderAmzRequestID, requestID)
ctx.Response.Header.Set(utils.HeaderAmzID2, hostID)
ctx.SetStatusCode(apiErr.StatusCode())
ctx.SetConnectionClose()
ctx.SetBody(apiErr.XMLBody(requestID, hostID))
return
}
fiberErrorHandler(ctx, err)
}
}
// globalErrorHandler catches the errors before reaching to
// the handlers and any system panics
func globalErrorHandler(ctx *fiber.Ctx, er error) error {
func globalErrorHandler(ctx fiber.Ctx, er error) error {
requestID, hostID := utils.EnsureRequestIDs(ctx)
// set content type to application/xml
@@ -416,8 +457,8 @@ func globalErrorHandler(ctx *fiber.Ctx, er error) error {
if errors.As(er, &fiberErr) {
if errors.Is(fiberErr, fiber.ErrRequestHeaderFieldsTooLarge) {
debuglogger.Logf("total request headers size exceeds the allowed 8KB")
ctx.Status(http.StatusBadRequest)
return nil
err := s3err.GetRequestHeaderSectionTooLargeErr(requestHeaderMaxSize)
return ctx.Status(err.StatusCode()).Send(err.XMLBody(requestID, hostID))
}
if strings.Contains(fiberErr.Message, "cannot parse Content-Length") {
debuglogger.Logf("failed to parse Content-Length")
+8 -7
View File
@@ -20,8 +20,9 @@ import (
"strings"
"sync"
"testing"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/s3api/middlewares"
@@ -87,10 +88,10 @@ func TestWithRouteRegistersBeforeMiddleware(t *testing.T) {
middlewareCalled := false
server, err := newTestS3ApiServer(
WithRoute(http.MethodGet, routePath, func(ctx *fiber.Ctx) error {
WithRoute(http.MethodGet, routePath, func(ctx fiber.Ctx) error {
return ctx.SendStatus(http.StatusNoContent)
}),
WithMiddleware("/", func(ctx *fiber.Ctx) error {
WithMiddleware("/", func(ctx fiber.Ctx) error {
middlewareCalled = true
return ctx.SendStatus(http.StatusMisdirectedRequest)
}),
@@ -126,7 +127,7 @@ func TestWithRouteRegistersAfterRateLimiter(t *testing.T) {
server, err := newTestS3ApiServer(
WithConcurrencyLimiter(10, 1),
WithRoute(http.MethodGet, routePath, func(ctx *fiber.Ctx) error {
WithRoute(http.MethodGet, routePath, func(ctx fiber.Ctx) error {
once.Do(func() {
close(started)
})
@@ -139,7 +140,7 @@ func TestWithRouteRegistersAfterRateLimiter(t *testing.T) {
}
go func() {
resp, err := server.app.Test(httptest.NewRequest(http.MethodGet, routePath, nil), -1)
resp, err := server.app.Test(httptest.NewRequest(http.MethodGet, routePath, nil), fiber.TestConfig{Timeout: 0, FailOnTimeout: false})
if err != nil {
firstDone <- err
return
@@ -154,7 +155,7 @@ func TestWithRouteRegistersAfterRateLimiter(t *testing.T) {
<-started
resp, err := server.app.Test(httptest.NewRequest(http.MethodGet, routePath, nil), 100)
resp, err := server.app.Test(httptest.NewRequest(http.MethodGet, routePath, nil), fiber.TestConfig{Timeout: time.Duration(100) * time.Millisecond})
if err != nil {
close(release)
t.Fatalf("second app.Test() error = %v", err)
@@ -172,7 +173,7 @@ func TestWithRouteRegistersAfterRateLimiter(t *testing.T) {
}
func TestCustomMountValidation(t *testing.T) {
validHandler := func(ctx *fiber.Ctx) error {
validHandler := func(ctx fiber.Ctx) error {
return ctx.SendStatus(http.StatusNoContent)
}
+2 -2
View File
@@ -26,7 +26,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/smithy-go/logging"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
v4 "github.com/versity/versitygw/aws/signer/v4"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3err"
@@ -53,7 +53,7 @@ const (
)
// CheckValidSignature validates the ctx v4 auth signature
func CheckValidSignature(ctx *fiber.Ctx, auth AuthData, secret, checksum string, tdate time.Time, contentLen int64) (string, error) {
func CheckValidSignature(ctx fiber.Ctx, auth AuthData, secret, checksum string, tdate time.Time, contentLen int64) (string, error) {
signedHdrs := strings.Split(auth.SignedHeaders, ";")
// Create a new http request instance from fasthttp request
+18 -9
View File
@@ -20,7 +20,8 @@ import (
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/valyala/fasthttp"
"github.com/valyala/fasthttp/fasthttputil"
v4 "github.com/versity/versitygw/aws/signer/v4"
)
@@ -84,14 +85,14 @@ func Test_Client_UserAgent(t *testing.T) {
expectedSig := "37a35d96998d786113ad420c57c22c5433f6aca74f88f26566caa047fc3601c6"
dateStr := "20240206T210328Z"
app := fiber.New(fiber.Config{DisableStartupMessage: true})
app := fiber.New(fiber.Config{})
tdate, err := time.Parse(iso8601Format, dateStr)
if err != nil {
t.Fatal(err)
}
app.Get("/", func(c *fiber.Ctx) error {
app.Get("/", func(c fiber.Ctx) error {
req, err := createHttpRequestFromCtx(c, signedHdrs, int64(c.Request().Header.ContentLength()))
if err != nil {
t.Fatal(err)
@@ -135,10 +136,18 @@ func Test_Client_UserAgent(t *testing.T) {
}
}()
c := fiber.AcquireClient()
c.UserAgent = agent
a := c.Get("http://example.com")
a.HostClient.Dial = func(_ string) (net.Conn, error) { return ln.Dial() }
a.String()
fiber.ReleaseClient(c)
client := fasthttp.Client{
Dial: func(_ string) (net.Conn, error) { return ln.Dial() },
}
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
req.SetRequestURI("http://example.com")
req.Header.SetUserAgent(agent)
if err := client.Do(req, resp); err != nil {
t.Fatal(err)
}
}
+4 -4
View File
@@ -23,7 +23,7 @@ import (
"strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3err"
)
@@ -100,7 +100,7 @@ func (c checksumType) isValid() bool {
}
// Extracts and validates the checksum type from the 'X-Amz-Trailer' header
func ExtractChecksumType(ctx *fiber.Ctx) (checksumType, error) {
func ExtractChecksumType(ctx fiber.Ctx) (checksumType, error) {
trailer := ctx.Get("X-Amz-Trailer")
chType := checksumType(strings.ToLower(trailer))
if chType != "" && !chType.isValid() {
@@ -172,7 +172,7 @@ func IsStreamingPayload(str string) bool {
// ParseDecodedContentLength extracts and validates the
// 'x-amz-decoded-content-length' from fiber context
func ParseDecodedContentLength(ctx *fiber.Ctx) (int64, error) {
func ParseDecodedContentLength(ctx fiber.Ctx) (int64, error) {
decContLengthStr := ctx.Get("X-Amz-Decoded-Content-Length")
if decContLengthStr == "" {
debuglogger.Logf("missing required header 'X-Amz-Decoded-Content-Length'")
@@ -192,7 +192,7 @@ func ParseDecodedContentLength(ctx *fiber.Ctx) (int64, error) {
return decContLength, nil
}
func NewChunkReader(ctx *fiber.Ctx, r io.Reader, authdata AuthData, canonicalString, secret string, date time.Time) (io.Reader, error) {
func NewChunkReader(ctx fiber.Ctx, r io.Reader, authdata AuthData, canonicalString, secret string, date time.Time) (io.Reader, error) {
cLength, err := ParseDecodedContentLength(ctx)
if err != nil {
return nil, err
+5 -5
View File
@@ -15,7 +15,7 @@
package utils
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)
// Region, StartTime, IsRoot, Account, AccessKey context locals
@@ -43,19 +43,19 @@ const (
ContextKeyWebsiteConfig ContextKey = "website-config"
)
func (ck ContextKey) Set(ctx *fiber.Ctx, val any) {
func (ck ContextKey) Set(ctx fiber.Ctx, val any) {
ctx.Locals(string(ck), val)
}
func (ck ContextKey) IsSet(ctx *fiber.Ctx) bool {
func (ck ContextKey) IsSet(ctx fiber.Ctx) bool {
val := ctx.Locals(string(ck))
return val != nil
}
func (ck ContextKey) Delete(ctx *fiber.Ctx) {
func (ck ContextKey) Delete(ctx fiber.Ctx) {
ctx.Locals(string(ck), nil)
}
func (ck ContextKey) Get(ctx *fiber.Ctx) any {
func (ck ContextKey) Get(ctx fiber.Ctx) any {
return ctx.Locals(string(ck))
}
+5 -5
View File
@@ -18,7 +18,7 @@ import (
"strconv"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/debuglogger"
)
@@ -45,7 +45,7 @@ func WithCopySource() preconditionOpt {
// - If-None-Match
// - If-Modified-Since
// - If-Unmodified-Since
func ParsePreconditionHeaders(ctx *fiber.Ctx, opts ...preconditionOpt) ConditionalHeaders {
func ParsePreconditionHeaders(ctx fiber.Ctx, opts ...preconditionOpt) ConditionalHeaders {
ifMatch, ifNoneMatch := ParsePreconditionMatchHeaders(ctx, opts...)
ifModSince, ifUnmodeSince := ParsePreconditionDateHeaders(ctx, opts...)
@@ -58,7 +58,7 @@ func ParsePreconditionHeaders(ctx *fiber.Ctx, opts ...preconditionOpt) Condition
}
// ParsePreconditionMatchHeaders extracts "If-Match" and "If-None-Match" headers from fiber Ctx
func ParsePreconditionMatchHeaders(ctx *fiber.Ctx, opts ...preconditionOpt) (*string, *string) {
func ParsePreconditionMatchHeaders(ctx fiber.Ctx, opts ...preconditionOpt) (*string, *string) {
cfg := new(precondtionCfg)
for _, opt := range opts {
opt(cfg)
@@ -75,7 +75,7 @@ func ParsePreconditionMatchHeaders(ctx *fiber.Ctx, opts ...preconditionOpt) (*st
// ParsePreconditionDateHeaders parses the "If-Modified-Since" and "If-Unmodified-Since"
// headers from fiber context to *time.Time
func ParsePreconditionDateHeaders(ctx *fiber.Ctx, opts ...preconditionOpt) (*time.Time, *time.Time) {
func ParsePreconditionDateHeaders(ctx fiber.Ctx, opts ...preconditionOpt) (*time.Time, *time.Time) {
cfg := new(precondtionCfg)
for _, opt := range opts {
opt(cfg)
@@ -129,7 +129,7 @@ func ParsePreconditionDateHeader(date string) *time.Time {
// ParseIfMatchSize parses the 'x-amz-if-match-size' to *int64
// if parsing fails, returns nil
func ParseIfMatchSize(ctx *fiber.Ctx) *int64 {
func ParseIfMatchSize(ctx fiber.Ctx) *int64 {
ifMatchSizeHdr := ctx.Get("x-amz-if-match-size")
if ifMatchSizeHdr == "" {
return nil
+6 -6
View File
@@ -24,7 +24,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/smithy-go/logging"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
v4 "github.com/versity/versitygw/aws/signer/v4"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3err"
@@ -38,7 +38,7 @@ const (
)
// CheckPresignedSignature validates presigned request signature
func CheckPresignedSignature(ctx *fiber.Ctx, auth AuthData, secret string) error {
func CheckPresignedSignature(ctx fiber.Ctx, auth AuthData, secret string) error {
signedHdrs := strings.Split(auth.SignedHeaders, ";")
var contentLength int64
@@ -60,7 +60,7 @@ func CheckPresignedSignature(ctx *fiber.Ctx, auth AuthData, secret string) error
date, _ := time.Parse(iso8601Format, auth.Date)
signer := v4.NewSigner()
uri, _, signMeta, signErr := signer.PresignHTTP(ctx.Context(), aws.Credentials{
uri, _, signMeta, signErr := signer.PresignHTTP(ctx.RequestCtx(), aws.Credentials{
AccessKeyID: auth.Access,
SecretAccessKey: secret,
}, req, unsignedPayload, service, auth.Region, date, signedHdrs, func(options *v4.SignerOptions) {
@@ -104,7 +104,7 @@ func CheckPresignedSignature(ctx *fiber.Ctx, auth AuthData, secret string) error
// &X-Amz-Expires=86400
// &X-Amz-SignedHeaders=host
// &X-Amz-Signature=1e68ad45c1db540284a4a1eca3884c293ba1a0ff63ab9db9a15b5b29dfa02cd8
func ParsePresignedURIParts(ctx *fiber.Ctx, region string) (AuthData, error) {
func ParsePresignedURIParts(ctx fiber.Ctx, region string) (AuthData, error) {
a := AuthData{}
// Get and verify algorithm query parameter
@@ -218,7 +218,7 @@ func validateAlgorithm(algo string) error {
// IsPresignedURLAuth determines if the request is presigned:
// which is authorization with query params
func IsPresignedURLAuth(ctx *fiber.Ctx) bool {
func IsPresignedURLAuth(ctx fiber.Ctx) bool {
algo := ctx.Query("X-Amz-Algorithm")
creds := ctx.Query("X-Amz-Credential")
signature := ctx.Query("X-Amz-Signature")
@@ -230,7 +230,7 @@ func IsPresignedURLAuth(ctx *fiber.Ctx) bool {
// IsPresignedURLAuthV2 determines if the request is
// query-string signed with aws v2 signer
func IsPresignedURLAuthV2(ctx *fiber.Ctx) bool {
func IsPresignedURLAuthV2(ctx fiber.Ctx) bool {
expires := ctx.Query("Expires")
access := ctx.Query("AWSAccessKeyId")
signature := ctx.Query("Signature")
+4 -4
View File
@@ -18,7 +18,7 @@ import (
"crypto/rand"
"encoding/base64"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/debuglogger"
)
@@ -70,7 +70,7 @@ func NewS3HostID() string {
// EnsureRequestIDs makes sure the request-local IDs exist and are present
// in the response headers. Existing local values are reused so headers and XML
// bodies stay consistent throughout the request.
func EnsureRequestIDs(ctx *fiber.Ctx) (requestID, hostID string) {
func EnsureRequestIDs(ctx fiber.Ctx) (requestID, hostID string) {
requestID = RequestID(ctx)
if requestID == "" {
requestID = NewS3RequestID()
@@ -89,7 +89,7 @@ func EnsureRequestIDs(ctx *fiber.Ctx) (requestID, hostID string) {
return requestID, hostID
}
func RequestID(ctx *fiber.Ctx) string {
func RequestID(ctx fiber.Ctx) string {
requestID, _ := ContextKeyRequestID.Get(ctx).(string)
if requestID != "" {
return requestID
@@ -98,7 +98,7 @@ func RequestID(ctx *fiber.Ctx) string {
return string(ctx.Response().Header.Peek(HeaderAmzRequestID))
}
func HostID(ctx *fiber.Ctx) string {
func HostID(ctx fiber.Ctx) string {
hostID, _ := ContextKeyHostID.Get(ctx).(string)
if hostID != "" {
return hostID
+1 -1
View File
@@ -19,7 +19,7 @@ import (
"regexp"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
)
+3 -3
View File
@@ -21,7 +21,7 @@ import (
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/stretchr/testify/require"
"github.com/valyala/fasthttp"
v4 "github.com/versity/versitygw/aws/signer/v4"
@@ -151,7 +151,7 @@ func buildPresignedURL(t *testing.T, headers http.Header) string {
return signedURL
}
func signedHeaderAuthCtx(t *testing.T, signedHeaders, extraHeaders http.Header) (*fiber.Ctx, AuthData, time.Time) {
func signedHeaderAuthCtx(t *testing.T, signedHeaders, extraHeaders http.Header) (fiber.Ctx, AuthData, time.Time) {
t.Helper()
signingTime := time.Now().UTC()
@@ -192,7 +192,7 @@ func signedHeaderAuthCtx(t *testing.T, signedHeaders, extraHeaders http.Header)
return ctx, authData, signingTime
}
func fiberCtxFromURL(t *testing.T, method, rawURL string, headers http.Header) *fiber.Ctx {
func fiberCtxFromURL(t *testing.T, method, rawURL string, headers http.Header) fiber.Ctx {
t.Helper()
parsedURL, err := url.Parse(rawURL)
+19 -19
View File
@@ -32,7 +32,7 @@ import (
"time"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/valyala/fasthttp"
signerV4 "github.com/versity/versitygw/aws/signer/v4"
"github.com/versity/versitygw/debuglogger"
@@ -135,7 +135,7 @@ func ExtractMetadataFromFields(fields map[string]string) (map[string]string, err
return metadata, nil
}
func createHttpRequestFromCtx(ctx *fiber.Ctx, signedHdrs []string, contentLength int64) (*http.Request, error) {
func createHttpRequestFromCtx(ctx fiber.Ctx, signedHdrs []string, contentLength int64) (*http.Request, error) {
req := ctx.Request()
uri := ctx.OriginalURL()
@@ -180,7 +180,7 @@ var (
}
)
func createPresignedHttpRequestFromCtx(ctx *fiber.Ctx, signedHdrs []string, contentLength int64) (*http.Request, error) {
func createPresignedHttpRequestFromCtx(ctx fiber.Ctx, signedHdrs []string, contentLength int64) (*http.Request, error) {
req := ctx.Request()
uri, _, _ := strings.Cut(ctx.OriginalURL(), "?")
@@ -221,7 +221,7 @@ func createPresignedHttpRequestFromCtx(ctx *fiber.Ctx, signedHdrs []string, cont
return httpReq, nil
}
func SetMetaHeaders(ctx *fiber.Ctx, meta map[string]string) {
func SetMetaHeaders(ctx fiber.Ctx, meta map[string]string) {
ctx.Response().Header.DisableNormalizing()
for key, val := range meta {
ctx.Response().Header.Set(fmt.Sprintf("x-amz-meta-%s", key), val)
@@ -311,17 +311,17 @@ type CustomHeader struct {
Value string
}
func SetResponseHeaders(ctx *fiber.Ctx, headers []CustomHeader) {
func SetResponseHeaders(ctx fiber.Ctx, headers []CustomHeader) {
for _, header := range headers {
ctx.Set(header.Key, header.Value)
}
}
// Streams the response body by chunks
func StreamResponseBody(ctx *fiber.Ctx, rdr io.ReadCloser, bodysize int) {
func StreamResponseBody(ctx fiber.Ctx, rdr io.ReadCloser, bodysize int) {
// SetBodyStream will call Close() on the reader when the stream is done
// since rdr is a ReadCloser
ctx.Context().SetBodyStream(rdr, bodysize)
ctx.RequestCtx().SetBodyStream(rdr, bodysize)
}
func IsValidBucketName(bucket string) bool {
@@ -353,7 +353,7 @@ func includeHeader(hdr string, signedHdrs []string) bool {
})
}
func addRequestHeadersFromCtx(ctx *fiber.Ctx, httpReq *http.Request, signedHdrs []string) error {
func addRequestHeadersFromCtx(ctx fiber.Ctx, httpReq *http.Request, signedHdrs []string) error {
headersNotSigned := []string{}
for key, value := range ctx.Request().Header.All() {
keyStr := string(key)
@@ -424,7 +424,7 @@ func FilterObjectAttributes(attrs map[s3response.ObjectAttributes]struct{}, outp
return output
}
func ParseObjectAttributes(ctx *fiber.Ctx) (map[s3response.ObjectAttributes]struct{}, error) {
func ParseObjectAttributes(ctx fiber.Ctx) (map[s3response.ObjectAttributes]struct{}, error) {
attrs := map[s3response.ObjectAttributes]struct{}{}
var err error
for key, value := range ctx.Request().Header.All() {
@@ -463,7 +463,7 @@ type objLockCfg struct {
LegalHoldStatus types.ObjectLockLegalHoldStatus
}
func ParsObjectLockHdrs(ctx *fiber.Ctx) (*objLockCfg, error) {
func ParsObjectLockHdrs(ctx fiber.Ctx) (*objLockCfg, error) {
legalHoldHdr := ctx.Get("X-Amz-Object-Lock-Legal-Hold")
objLockModeHdr := ctx.Get("X-Amz-Object-Lock-Mode")
objLockDate := ctx.Get("X-Amz-Object-Lock-Retain-Until-Date")
@@ -549,7 +549,7 @@ func (cv ChecksumValues) Headers() string {
// ParseCalculatedChecksumHeaders parses and validates x-amz-checksum-x header keys
// e.g x-amz-checksum-crc32, x-amz-checksum-sha256 ...
func ParseCalculatedChecksumHeaders(ctx *fiber.Ctx) (ChecksumValues, error) {
func ParseCalculatedChecksumHeaders(ctx fiber.Ctx) (ChecksumValues, error) {
checksums := ChecksumValues{}
var hdrErr error
@@ -639,7 +639,7 @@ func ParseCalculatedChecksumFields(fields map[string]string) (ChecksumValues, er
// ParseCompleteMpChecksumHeaders parses and validates
// the 'CompleteMultipartUpload' x-amz-checksum-x headers
// by supporting both 'checksum' and 'checksum-<part_length>' formats
func ParseCompleteMpChecksumHeaders(ctx *fiber.Ctx) (ChecksumValues, error) {
func ParseCompleteMpChecksumHeaders(ctx fiber.Ctx) (ChecksumValues, error) {
// first parse/validate 'x-amz-checksum-x' headers
checksums, err := ParseCalculatedChecksumHeaders(ctx)
if err != nil {
@@ -673,7 +673,7 @@ func ParseCompleteMpChecksumHeaders(ctx *fiber.Ctx) (ChecksumValues, error) {
// ParseChecksumHeadersAndSdkAlgo parses/validates 'x-amz-sdk-checksum-algorithm' and
// 'x-amz-checksum-x' precalculated request headers
func ParseChecksumHeadersAndSdkAlgo(ctx *fiber.Ctx) (types.ChecksumAlgorithm, ChecksumValues, error) {
func ParseChecksumHeadersAndSdkAlgo(ctx fiber.Ctx) (types.ChecksumAlgorithm, ChecksumValues, error) {
sdkAlgorithm := types.ChecksumAlgorithm(strings.ToUpper(ctx.Get("X-Amz-Sdk-Checksum-Algorithm")))
err := IsChecksumAlgorithmValid(sdkAlgorithm)
if err != nil {
@@ -862,7 +862,7 @@ func checkChecksumTypeAndAlgo(algo types.ChecksumAlgorithm, t types.ChecksumType
}
// Parses and validates the x-amz-checksum-algorithm and x-amz-checksum-type headers
func ParseCreateMpChecksumHeaders(ctx *fiber.Ctx) (types.ChecksumAlgorithm, types.ChecksumType, error) {
func ParseCreateMpChecksumHeaders(ctx fiber.Ctx) (types.ChecksumAlgorithm, types.ChecksumType, error) {
algo := types.ChecksumAlgorithm(strings.ToUpper(ctx.Get("x-amz-checksum-algorithm")))
if err := IsChecksumAlgorithmValid(algo); err != nil {
return "", "", err
@@ -1071,7 +1071,7 @@ func ValidateCopySource(input string) error {
}
// GetQueryParam returns a pointer to the query parameter value if it exists
func GetQueryParam(ctx *fiber.Ctx, key string) *string {
func GetQueryParam(ctx fiber.Ctx, key string) *string {
value := ctx.Query(key)
if value == "" {
return nil
@@ -1089,9 +1089,9 @@ func ApplyOverride(original, override *string) *string {
// GenerateObjectLocation generates the object location path-styled or host-styled
// depending on the gateway configuration
func GenerateObjectLocation(ctx *fiber.Ctx, virtualDomain, bucket, object string) string {
scheme := ctx.Protocol()
host := ctx.Hostname()
func GenerateObjectLocation(ctx fiber.Ctx, virtualDomain, bucket, object string) string {
scheme := ctx.Scheme()
host := ctx.Host()
// escape the object name
obj := url.PathEscape(object)
@@ -1146,7 +1146,7 @@ func NewTLSListener(network string, address string, getCertificateFunc func(*tls
return tls.NewListener(ln, config), nil
}
func DetectResourceType(ctx *fiber.Ctx) s3err.ResourceType {
func DetectResourceType(ctx fiber.Ctx) s3err.ResourceType {
path := ctx.Path()
if path == "" || path == "/" {
return s3err.ResourceTypeService
+2 -2
View File
@@ -28,7 +28,7 @@ import (
"time"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
"github.com/versity/versitygw/backend"
@@ -38,7 +38,7 @@ import (
func TestCreateHttpRequestFromCtx(t *testing.T) {
type args struct {
ctx *fiber.Ctx
ctx fiber.Ctx
}
app := fiber.New()
@@ -0,0 +1,60 @@
// Copyright 2026 Versity Software
// This file is licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package s3err
import "encoding/xml"
// RequestHeaderSectionTooLargeError is returned when the full HTTP request
// header section exceeds the server read buffer.
// Produces a <MaxSizeAllowed> field in the XML response.
type RequestHeaderSectionTooLargeError struct {
APIError
MaxSizeAllowed int
}
func (e RequestHeaderSectionTooLargeError) XMLBody(requestID, hostID string) []byte {
return encodeResponse(struct {
XMLName xml.Name `xml:"Error"`
Code string
Message string
MaxSizeAllowed int `xml:",omitempty"`
RequestID string `xml:"RequestId,omitempty"`
HostID string `xml:"HostId,omitempty"`
}{
Code: e.Code,
Message: e.Description,
MaxSizeAllowed: e.MaxSizeAllowed,
RequestID: requestID,
HostID: hostID,
})
}
func (e RequestHeaderSectionTooLargeError) HTMLBody(requestID, hostID string) []byte {
return e.APIError.encodeHTMLResponse(requestID, hostID,
ErrorField{Name: "MaxSizeAllowed", Value: e.MaxSizeAllowed},
)
}
func (e RequestHeaderSectionTooLargeError) Is(target error) bool {
t, ok := target.(APIError)
return ok && e.APIError == t
}
func GetRequestHeaderSectionTooLargeErr(maxSizeAllowed int) RequestHeaderSectionTooLargeError {
return RequestHeaderSectionTooLargeError{
APIError: GetAPIError(ErrRequestHeaderSectionTooLarge),
MaxSizeAllowed: maxSizeAllowed,
}
}
+6
View File
@@ -182,6 +182,7 @@ const (
ErrInvalidChunkSize
ErrSlowDown
ErrMetadataTooLarge
ErrRequestHeaderSectionTooLarge
ErrUnsupportedAuthorizationMechanism
ErrNoBucketInRequest
@@ -706,6 +707,11 @@ var errorCodeResponse = map[ErrorCode]APIError{
Description: "Your metadata headers exceed the maximum allowed metadata size",
HTTPStatusCode: http.StatusBadRequest,
},
ErrRequestHeaderSectionTooLarge: {
Code: "RequestHeaderSectionTooLarge",
Description: "Your request header section exceeds the maximum allowed size.",
HTTPStatusCode: http.StatusBadRequest,
},
ErrUnsupportedAuthorizationMechanism: {
Code: "InvalidRequest",
Description: "The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.",
+3 -3
View File
@@ -20,13 +20,13 @@ import (
"strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
)
type S3EventSender interface {
SendEvent(ctx *fiber.Ctx, meta EventMeta)
SendEvent(ctx fiber.Ctx, meta EventMeta)
Close() error
}
@@ -147,7 +147,7 @@ func InitEventSender(cfg *EventConfig) (S3EventSender, error) {
return evSender, err
}
func createEventSchema(ctx *fiber.Ctx, meta EventMeta, configId ConfigurationId) EventSchema {
func createEventSchema(ctx fiber.Ctx, meta EventMeta, configId ConfigurationId) EventSchema {
path := strings.Split(ctx.Path(), "/")
var bucket, object string
+3 -3
View File
@@ -23,7 +23,7 @@ import (
"sync"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/segmentio/kafka-go"
"github.com/versity/versitygw/s3response"
)
@@ -73,7 +73,7 @@ func InitKafkaEventService(url, topic, key string, filter EventFilter) (S3EventS
}, nil
}
func (ks *Kafka) SendEvent(ctx *fiber.Ctx, meta EventMeta) {
func (ks *Kafka) SendEvent(ctx fiber.Ctx, meta EventMeta) {
ks.mu.Lock()
defer ks.mu.Unlock()
@@ -84,7 +84,7 @@ func (ks *Kafka) SendEvent(ctx *fiber.Ctx, meta EventMeta) {
if meta.EventName == EventObjectRemovedDeleteObjects {
var dObj s3response.DeleteObjects
if err := xml.Unmarshal(ctx.Body(), &dObj); err != nil {
if err := xml.Unmarshal(ctx.BodyRaw(), &dObj); err != nil {
fmt.Fprintf(os.Stderr, "failed to parse delete objects input payload: %v\n", err.Error())
return
}
+3 -3
View File
@@ -21,7 +21,7 @@ import (
"os"
"sync"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/nats-io/nats.go"
"github.com/versity/versitygw/s3response"
)
@@ -60,7 +60,7 @@ func InitNatsEventService(url, topic string, filter EventFilter) (S3EventSender,
}, nil
}
func (ns *NatsEventSender) SendEvent(ctx *fiber.Ctx, meta EventMeta) {
func (ns *NatsEventSender) SendEvent(ctx fiber.Ctx, meta EventMeta) {
ns.mu.Lock()
defer ns.mu.Unlock()
@@ -71,7 +71,7 @@ func (ns *NatsEventSender) SendEvent(ctx *fiber.Ctx, meta EventMeta) {
if meta.EventName == EventObjectRemovedDeleteObjects {
var dObj s3response.DeleteObjects
if err := xml.Unmarshal(ctx.Body(), &dObj); err != nil {
if err := xml.Unmarshal(ctx.BodyRaw(), &dObj); err != nil {
fmt.Fprintf(os.Stderr, "failed to parse delete objects input payload: %v\n", err.Error())
return
}
+3 -3
View File
@@ -22,7 +22,7 @@ import (
"sync"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/google/uuid"
amqp "github.com/rabbitmq/amqp091-go"
"github.com/versity/versitygw/s3response"
@@ -87,7 +87,7 @@ func InitRabbitmqEventService(url, exchange, routingKey string, filter EventFilt
}, nil
}
func (rs *RabbitmqEventSender) SendEvent(ctx *fiber.Ctx, meta EventMeta) {
func (rs *RabbitmqEventSender) SendEvent(ctx fiber.Ctx, meta EventMeta) {
rs.mu.Lock()
defer rs.mu.Unlock()
@@ -97,7 +97,7 @@ func (rs *RabbitmqEventSender) SendEvent(ctx *fiber.Ctx, meta EventMeta) {
if meta.EventName == EventObjectRemovedDeleteObjects {
var dObj s3response.DeleteObjects
if err := xml.Unmarshal(ctx.Body(), &dObj); err != nil {
if err := xml.Unmarshal(ctx.BodyRaw(), &dObj); err != nil {
fmt.Fprintf(os.Stderr, "failed to parse delete objects input payload: %v\n", err.Error())
return
}
+3 -3
View File
@@ -25,7 +25,7 @@ import (
"sync"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/s3response"
)
@@ -72,7 +72,7 @@ func InitWebhookEventSender(url string, filter EventFilter) (S3EventSender, erro
}, nil
}
func (w *Webhook) SendEvent(ctx *fiber.Ctx, meta EventMeta) {
func (w *Webhook) SendEvent(ctx fiber.Ctx, meta EventMeta) {
w.mu.Lock()
defer w.mu.Unlock()
@@ -83,7 +83,7 @@ func (w *Webhook) SendEvent(ctx *fiber.Ctx, meta EventMeta) {
if meta.EventName == EventObjectRemovedDeleteObjects {
var dObj s3response.DeleteObjects
if err := xml.Unmarshal(ctx.Body(), &dObj); err != nil {
if err := xml.Unmarshal(ctx.BodyRaw(), &dObj); err != nil {
fmt.Fprintf(os.Stderr, "failed to parse delete objects input payload: %v\n", err.Error())
return
}
+2 -2
View File
@@ -19,11 +19,11 @@ import (
"fmt"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)
type AuditLogger interface {
Log(ctx *fiber.Ctx, err error, body []byte, meta LogMeta)
Log(ctx fiber.Ctx, err error, body []byte, meta LogMeta)
HangUp() error
Shutdown() error
}
+3 -3
View File
@@ -22,7 +22,7 @@ import (
"sync"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
@@ -56,7 +56,7 @@ func InitFileLogger(logname string) (AuditLogger, error) {
}
// Log sends log message to file logger
func (f *FileLogger) Log(ctx *fiber.Ctx, err error, body []byte, meta LogMeta) {
func (f *FileLogger) Log(ctx fiber.Ctx, err error, body []byte, meta LogMeta) {
f.mu.Lock()
defer f.mu.Unlock()
@@ -79,7 +79,7 @@ func (f *FileLogger) Log(ctx *fiber.Ctx, err error, body []byte, meta LogMeta) {
if !ok {
startTime = time.Now()
}
tlsConnState := ctx.Context().TLSConnectionState()
tlsConnState := ctx.RequestCtx().TLSConnectionState()
if tlsConnState != nil {
lf.CipherSuite = tls.CipherSuiteName(tlsConnState.CipherSuite)
lf.TLSVersion = getTLSVersionName(tlsConnState.Version)
+3 -3
View File
@@ -20,7 +20,7 @@ import (
"os"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
)
@@ -45,7 +45,7 @@ func InitAdminFileLogger(logname string) (AuditLogger, error) {
}
// Log sends log message to file logger
func (f *AdminFileLogger) Log(ctx *fiber.Ctx, err error, body []byte, meta LogMeta) {
func (f *AdminFileLogger) Log(ctx fiber.Ctx, err error, body []byte, meta LogMeta) {
f.mu.Lock()
defer f.mu.Unlock()
@@ -62,7 +62,7 @@ func (f *AdminFileLogger) Log(ctx *fiber.Ctx, err error, body []byte, meta LogMe
if !ok {
startTime = time.Now()
}
tlsConnState := ctx.Context().TLSConnectionState()
tlsConnState := ctx.RequestCtx().TLSConnectionState()
if tlsConnState != nil {
lf.CipherSuite = tls.CipherSuiteName(tlsConnState.CipherSuite)
lf.TLSVersion = getTLSVersionName(tlsConnState.Version)
+3 -3
View File
@@ -26,7 +26,7 @@ import (
"sync"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
@@ -57,7 +57,7 @@ func InitWebhookLogger(url string) (AuditLogger, error) {
}
// Log sends log message to webhook
func (wl *WebhookLogger) Log(ctx *fiber.Ctx, err error, body []byte, meta LogMeta) {
func (wl *WebhookLogger) Log(ctx fiber.Ctx, err error, body []byte, meta LogMeta) {
wl.mu.Lock()
defer wl.mu.Unlock()
@@ -76,7 +76,7 @@ func (wl *WebhookLogger) Log(ctx *fiber.Ctx, err error, body []byte, meta LogMet
if !ok {
startTime = time.Now()
}
tlsConnState := ctx.Context().TLSConnectionState()
tlsConnState := ctx.RequestCtx().TLSConnectionState()
if tlsConnState != nil {
lf.CipherSuite = tls.CipherSuiteName(tlsConnState.CipherSuite)
lf.TLSVersion = getTLSVersionName(tlsConnState.Version)
+5 -14
View File
@@ -16,12 +16,12 @@ package integration
import (
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/versity/versitygw/s3err"
)
func Server_large_http_header(s *S3Conf) error {
@@ -39,20 +39,11 @@ func Server_large_http_header(s *S3Conf) error {
return err
}
if resp.StatusCode != http.StatusBadRequest {
return fmt.Errorf("expected the response status to be %v, instead got %v", http.StatusBadRequest, resp.StatusCode)
expectedErr := s3err.GetRequestHeaderSectionTooLargeErr(8 * 1024)
if resp.StatusCode != expectedErr.StatusCode() {
return fmt.Errorf("expected the response status to be %v, instead got %v", expectedErr.StatusCode(), resp.StatusCode)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if len(body) != 0 {
return fmt.Errorf("expected empty response body, instead got %s", body)
}
return nil
return checkHTTPResponseApiErr(resp, expectedErr)
})
}
+2
View File
@@ -693,6 +693,8 @@ func compareS3ApiErr(expected s3err.S3Error, received *APIErrorResponse) error {
compareErrField("Size", int64(err.Size), received.Size),
compareErrField("MaxSizeAllowed", int64(err.MaxSizeAllowed), received.MaxSizeAllowed),
)
case s3err.RequestHeaderSectionTooLargeError:
return compareErrField("MaxSizeAllowed", int64(err.MaxSizeAllowed), received.MaxSizeAllowed)
case s3err.MethodNotAllowedError:
return compareS3ApiErrFields(
compareErrField("Method", err.Method, received.Method),
+33 -33
View File
@@ -23,7 +23,7 @@ import (
"strings"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/debuglogger"
@@ -63,15 +63,15 @@ func newWebsiteController(be backend.Backend, domain string) *websiteController
return controller
}
func (c *websiteController) Get(ctx *fiber.Ctx) error {
func (c *websiteController) Get(ctx fiber.Ctx) error {
return c.serve(ctx, c.getObject)
}
func (c *websiteController) Head(ctx *fiber.Ctx) error {
func (c *websiteController) Head(ctx fiber.Ctx) error {
return c.serve(ctx, c.headObject)
}
func (c *websiteController) Options(ctx *fiber.Ctx) error {
func (c *websiteController) Options(ctx fiber.Ctx) error {
bucket, err := c.resolveBucket(ctx)
if err != nil {
return sendError(ctx, err)
@@ -96,7 +96,7 @@ func (c *websiteController) Options(ctx *fiber.Ctx) error {
return sendError(ctx, err)
}
cors, err := c.be.GetBucketCors(ctx.Context(), bucket)
cors, err := c.be.GetBucketCors(ctx.RequestCtx(), bucket)
if err != nil {
debuglogger.Logf("failed to get bucket cors: %v", err)
if errors.Is(err, s3err.GetAPIError(s3err.ErrNoSuchCORSConfiguration)) {
@@ -131,7 +131,7 @@ func registerWebsiteRoutes(app *fiber.App, be backend.Backend, domain string) {
app.All("*", controller.MethodNotAllowed)
}
func setCORSPreflightHeaders(ctx *fiber.Ctx, allowConfig *auth.CORSAllowanceConfig) {
func setCORSPreflightHeaders(ctx fiber.Ctx, allowConfig *auth.CORSAllowanceConfig) {
ctx.Set("Access-Control-Allow-Origin", allowConfig.Origin)
ctx.Set("Access-Control-Allow-Methods", allowConfig.Methods)
ctx.Set("Access-Control-Expose-Headers", allowConfig.ExposedHeaders)
@@ -143,7 +143,7 @@ func setCORSPreflightHeaders(ctx *fiber.Ctx, allowConfig *auth.CORSAllowanceConf
}
}
func (c *websiteController) MethodNotAllowed(ctx *fiber.Ctx) error {
func (c *websiteController) MethodNotAllowed(ctx fiber.Ctx) error {
return sendError(ctx, s3err.GetMethodNotAllowedErr(ctx.Method(), s3err.ResourceTypeObject, websiteAllowedMethods))
}
@@ -153,9 +153,9 @@ type websiteRequestInfo struct {
key string
}
type websiteObjectReader func(ctx *fiber.Ctx, bucket, key string) websiteResult
type websiteObjectReader func(ctx fiber.Ctx, bucket, key string) websiteResult
func (c *websiteController) serve(ctx *fiber.Ctx, readObject websiteObjectReader) error {
func (c *websiteController) serve(ctx fiber.Ctx, readObject websiteObjectReader) error {
req, err := c.resolveRequest(ctx)
if err != nil {
return sendError(ctx, err)
@@ -189,7 +189,7 @@ func (c *websiteController) serve(ctx *fiber.Ctx, readObject websiteObjectReader
return serveWebsiteResult(ctx, req.bucket, req.config, result, readObject)
}
func (c *websiteController) resolveRequest(ctx *fiber.Ctx) (*websiteRequestInfo, error) {
func (c *websiteController) resolveRequest(ctx fiber.Ctx) (*websiteRequestInfo, error) {
bucket, err := c.resolveBucket(ctx)
if err != nil {
return nil, err
@@ -202,7 +202,7 @@ func (c *websiteController) resolveRequest(ctx *fiber.Ctx) (*websiteRequestInfo,
return nil, err
}
data, err := c.be.GetBucketWebsite(ctx.Context(), bucket)
data, err := c.be.GetBucketWebsite(ctx.RequestCtx(), bucket)
if err != nil {
return nil, err
}
@@ -241,8 +241,8 @@ func validateWebsiteNames(bucket, key string) error {
//
// When domain is empty (catch-all mode):
// - The full hostname is used as the bucket name.
func (c *websiteController) resolveBucket(ctx *fiber.Ctx) (string, error) {
host := ctx.Hostname()
func (c *websiteController) resolveBucket(ctx fiber.Ctx) (string, error) {
host := ctx.Host()
if host == "" {
ctx.Set("Location", c.noBucketLocation(ctx, host))
return "", s3err.GetAPIError(s3err.ErrNoBucketInRequest)
@@ -269,11 +269,11 @@ func (c *websiteController) resolveBucket(ctx *fiber.Ctx) (string, error) {
}
}
ctx.Set("Location", c.noBucketLocation(ctx, ctx.Hostname()))
ctx.Set("Location", c.noBucketLocation(ctx, ctx.Host()))
return "", s3err.GetAPIError(s3err.ErrNoBucketInRequest)
}
func (c *websiteController) noBucketLocation(ctx *fiber.Ctx, host string) string {
func (c *websiteController) noBucketLocation(ctx fiber.Ctx, host string) string {
locationHost := c.domain
if locationHost == "" {
locationHost = stripHostPort(host)
@@ -287,7 +287,7 @@ func (c *websiteController) noBucketLocation(ctx *fiber.Ctx, host string) string
}
}
return fmt.Sprintf("%s://%s/", ctx.Protocol(), locationHost)
return fmt.Sprintf("%s://%s/", ctx.Scheme(), locationHost)
}
func stripHostPort(host string) string {
@@ -330,8 +330,8 @@ func resolveIndexKey(key string, config *s3response.WebsiteConfiguration) string
return key
}
func (c *websiteController) getObject(ctx *fiber.Ctx, bucket, key string) websiteResult {
if err := auth.VerifyPublicAccess(ctx.Context(), c.be, auth.GetObjectAction, auth.PermissionRead, bucket, key); err != nil {
func (c *websiteController) getObject(ctx fiber.Ctx, bucket, key string) websiteResult {
if err := auth.VerifyPublicAccess(ctx.RequestCtx(), c.be, auth.GetObjectAction, auth.PermissionRead, bucket, key); err != nil {
return websiteResult{
Key: key,
StatusCode: statusCodeFromError(err),
@@ -339,7 +339,7 @@ func (c *websiteController) getObject(ctx *fiber.Ctx, bucket, key string) websit
}
}
result, err := c.be.GetObject(ctx.Context(), &s3.GetObjectInput{
result, err := c.be.GetObject(ctx.RequestCtx(), &s3.GetObjectInput{
Bucket: &bucket,
Key: &key,
})
@@ -363,8 +363,8 @@ func (c *websiteController) getObject(ctx *fiber.Ctx, bucket, key string) websit
}
}
func (c *websiteController) headObject(ctx *fiber.Ctx, bucket, key string) websiteResult {
if err := auth.VerifyPublicAccess(ctx.Context(), c.be, auth.GetObjectAction, auth.PermissionRead, bucket, key); err != nil {
func (c *websiteController) headObject(ctx fiber.Ctx, bucket, key string) websiteResult {
if err := auth.VerifyPublicAccess(ctx.RequestCtx(), c.be, auth.GetObjectAction, auth.PermissionRead, bucket, key); err != nil {
return websiteResult{
Key: key,
StatusCode: statusCodeFromError(err),
@@ -372,7 +372,7 @@ func (c *websiteController) headObject(ctx *fiber.Ctx, bucket, key string) websi
}
}
result, err := c.be.HeadObject(ctx.Context(), &s3.HeadObjectInput{
result, err := c.be.HeadObject(ctx.RequestCtx(), &s3.HeadObjectInput{
Bucket: &bucket,
Key: &key,
})
@@ -405,10 +405,10 @@ func statusCodeFromError(err error) int {
}
// handleRedirectAll sends a 301 redirect for RedirectAllRequestsTo configuration.
func handleRedirectAll(ctx *fiber.Ctx, redirect *s3response.RedirectAllRequestsTo, key string) error {
func handleRedirectAll(ctx fiber.Ctx, redirect *s3response.RedirectAllRequestsTo, key string) error {
protocol := redirect.Protocol
if protocol == "" {
protocol = ctx.Protocol()
protocol = ctx.Scheme()
}
location := fmt.Sprintf("%s://%s/%s", protocol, redirect.HostName, key)
@@ -419,15 +419,15 @@ func handleRedirectAll(ctx *fiber.Ctx, redirect *s3response.RedirectAllRequestsT
}
// applyRedirect constructs and sends a redirect response from a routing rule.
func applyRedirect(ctx *fiber.Ctx, redirect *s3response.Redirect, condition *s3response.RoutingRuleCondition, originalKey string) error {
func applyRedirect(ctx fiber.Ctx, redirect *s3response.Redirect, condition *s3response.RoutingRuleCondition, originalKey string) error {
protocol := redirect.Protocol
if protocol == "" {
protocol = ctx.Protocol()
protocol = ctx.Scheme()
}
host := redirect.HostName
if host == "" {
host = ctx.Hostname()
host = ctx.Host()
}
key := originalKey
@@ -451,7 +451,7 @@ func applyRedirect(ctx *fiber.Ctx, redirect *s3response.Redirect, condition *s3r
return sendRedirect(ctx, httpCode, location)
}
func sendRedirect(ctx *fiber.Ctx, statusCode int, location string) error {
func sendRedirect(ctx fiber.Ctx, statusCode int, location string) error {
ctx.Set("Location", location)
_, _ = utils.EnsureRequestIDs(ctx)
ctx.Status(statusCode)
@@ -494,7 +494,7 @@ func headObjectHeaders(result *s3.HeadObjectOutput) map[string]*string {
}
}
func serveWebsiteResult(ctx *fiber.Ctx, bucket string, config *s3response.WebsiteConfiguration, result websiteResult, readObject websiteObjectReader) error {
func serveWebsiteResult(ctx fiber.Ctx, bucket string, config *s3response.WebsiteConfiguration, result websiteResult, readObject websiteObjectReader) error {
if result.Err == nil {
// Precedence: RedirectAllRequestsTo, pre-fetch routing rules, object
// redirect metadata, then post-error routing/error documents.
@@ -514,7 +514,7 @@ func serveWebsiteResult(ctx *fiber.Ctx, bucket string, config *s3response.Websit
return sendError(ctx, result.Err)
}
func serveObject(ctx *fiber.Ctx, object websiteObject, statusCode int) error {
func serveObject(ctx fiber.Ctx, object websiteObject, statusCode int) error {
ctx.Status(statusCode)
setWebsiteObjectHeaders(ctx, object)
@@ -531,7 +531,7 @@ func serveObject(ctx *fiber.Ctx, object websiteObject, statusCode int) error {
return nil
}
func setWebsiteObjectHeaders(ctx *fiber.Ctx, object websiteObject) {
func setWebsiteObjectHeaders(ctx fiber.Ctx, object websiteObject) {
utils.SetMetaHeaders(ctx, object.Metadata)
for key, value := range object.Headers {
if value != nil && *value != "" {
@@ -541,7 +541,7 @@ func setWebsiteObjectHeaders(ctx *fiber.Ctx, object websiteObject) {
}
// serveErrorDocument fetches and serves the configured error document.
func serveErrorDocument(ctx *fiber.Ctx, readObject websiteObjectReader, bucket, errorDocKey string, statusCode int) error {
func serveErrorDocument(ctx fiber.Ctx, readObject websiteObjectReader, bucket, errorDocKey string, statusCode int) error {
result := readObject(ctx, bucket, errorDocKey)
if result.Err != nil {
return sendError(ctx, result.Err)
@@ -551,7 +551,7 @@ func serveErrorDocument(ctx *fiber.Ctx, readObject websiteObjectReader, bucket,
}
// sendError sends a simple HTML error page.
func sendError(ctx *fiber.Ctx, err error) error {
func sendError(ctx fiber.Ctx, err error) error {
requestId, hostId := utils.EnsureRequestIDs(ctx)
serr, ok := err.(s3err.S3Error)
if !ok {
+3 -5
View File
@@ -26,7 +26,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/s3err"
@@ -1016,9 +1016,7 @@ func websiteRequestWithHostAndHeaders(t *testing.T, be backend.Backend, method,
func websiteRequestWithDomainHostAndHeaders(t *testing.T, be backend.Backend, domain, method, host, path string, headers map[string]string) *http.Response {
t.Helper()
app := fiber.New(fiber.Config{
ServerHeader: "VERSITYGW",
})
app := fiber.New(fiber.Config{ServerHeader: "VERSITYGW"})
registerWebsiteRoutes(app, be, domain)
req := httptest.NewRequest(method, path, nil)
@@ -1027,7 +1025,7 @@ func websiteRequestWithDomainHostAndHeaders(t *testing.T, be backend.Backend, do
for key, value := range headers {
req.Header.Set(key, value)
}
resp, err := app.Test(req, -1)
resp, err := app.Test(req, fiber.TestConfig{Timeout: 0, FailOnTimeout: false})
if err != nil {
t.Fatalf("website request failed: %v", err)
}
+13 -13
View File
@@ -19,9 +19,9 @@ import (
"net"
"os"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/logger"
"github.com/gofiber/fiber/v3/middleware/recover"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/debuglogger"
"github.com/versity/versitygw/s3api/middlewares"
@@ -63,10 +63,8 @@ func WithSocketPerm(perm os.FileMode) Option {
// - Host "<domain>" (apex, no subdomain) resolves to bucket "<domain>"
func NewServer(be backend.Backend, domain string, opts ...Option) *Server {
app := fiber.New(fiber.Config{
AppName: "versitygw-website",
ServerHeader: "VERSITYGW",
DisableStartupMessage: true,
Network: fiber.NetworkTCP,
AppName: "versitygw-website",
ServerHeader: "VERSITYGW",
})
server := &Server{
@@ -84,19 +82,19 @@ func NewServer(be backend.Backend, domain string, opts ...Option) *Server {
}
// Panic recovery
app.Use(recover.New())
app.Use("*", recover.New())
// Request logging
if !server.quiet {
fmt.Printf("initializing website endpoint (%s)\n", domainInfo)
app.Use(logger.New(logger.Config{
app.Use("*", logger.New(logger.Config{
Format: "${time} | website | ${status} | ${latency} | ${ip} | ${method} | ${path}\n",
}))
}
// initialize the debug logger in debug mode
if debuglogger.IsDebugEnabled() {
app.Use(middlewares.DebugLogger())
app.Use("*", middlewares.DebugLogger())
}
registerWebsiteRoutes(app, be, domain)
@@ -118,9 +116,9 @@ func (s *Server) ServeMultiPort(ports []string) error {
var err error
if s.CertStorage != nil {
ln, err = utils.NewMultiAddrTLSListener(s.app.Config().Network, addrSpec, s.CertStorage.GetCertificate, utils.ListenerOptions{SocketPerm: s.socketPerm})
ln, err = utils.NewMultiAddrTLSListener(fiber.NetworkTCP, addrSpec, s.CertStorage.GetCertificate, utils.ListenerOptions{SocketPerm: s.socketPerm})
} else {
ln, err = utils.NewMultiAddrListener(s.app.Config().Network, addrSpec, utils.ListenerOptions{SocketPerm: s.socketPerm})
ln, err = utils.NewMultiAddrListener(fiber.NetworkTCP, addrSpec, utils.ListenerOptions{SocketPerm: s.socketPerm})
}
if err != nil {
@@ -136,7 +134,9 @@ func (s *Server) ServeMultiPort(ports []string) error {
finalListener := utils.NewMultiListener(listeners...)
return s.app.Listener(finalListener)
return s.app.Listener(finalListener, fiber.ListenConfig{
DisableStartupMessage: true,
})
}
// Shutdown gracefully shuts down the server.
+5 -2
View File
@@ -14,7 +14,10 @@
package webui
import "embed"
import (
"embed"
"io/fs"
)
// webFiles embeds the admin GUI static files from web/.
// The "all:" prefix recursively includes all files and subdirectories.
@@ -23,4 +26,4 @@ import "embed"
var webFiles embed.FS
// webFS is an alias for webFiles for consistency with server.go
var webFS = webFiles
var webFS fs.FS = webFiles
+37 -32
View File
@@ -17,15 +17,15 @@ package webui
import (
"encoding/json"
"fmt"
"io/fs"
"net"
"net/http"
"os"
"strings"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/filesystem"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/logger"
"github.com/gofiber/fiber/v3/middleware/recover"
"github.com/gofiber/fiber/v3/middleware/static"
"github.com/versity/versitygw/s3api/utils"
)
@@ -73,12 +73,10 @@ func WithSocketPerm(perm os.FileMode) Option {
}
// NewServer creates a new GUI server instance
func NewServer(cfg *ServerConfig, opts ...Option) *Server {
func NewServer(cfg *ServerConfig, opts ...Option) (*Server, error) {
app := fiber.New(fiber.Config{
AppName: "versitygw",
ServerHeader: "VERSITYGW",
DisableStartupMessage: true,
Network: fiber.NetworkTCP,
AppName: "versitygw",
ServerHeader: "VERSITYGW",
})
server := &Server{
@@ -93,50 +91,55 @@ func NewServer(cfg *ServerConfig, opts ...Option) *Server {
fmt.Printf("initializing web dashboard\n")
server.setupMiddleware()
server.setupRoutes()
if err := server.setupRoutes(); err != nil {
return nil, err
}
return server
return server, nil
}
// setupMiddleware configures middleware
func (s *Server) setupMiddleware() {
// Panic recovery
s.app.Use(recover.New())
s.app.Use("*", recover.New())
// Request logging
if !s.quiet {
s.app.Use(logger.New(logger.Config{
s.app.Use("*", logger.New(logger.Config{
Format: "${time} | web | ${status} | ${latency} | ${ip} | ${method} | ${path}\n",
}))
}
}
// setupRoutes configures all routes
func (s *Server) setupRoutes() {
func (s *Server) setupRoutes() error {
prefix := s.pathPrefix
// Serve index.html with server-side config injection
s.app.Get(prefix+"/", s.handleIndexHTML)
s.app.Get(prefix+"/index.html", s.handleIndexHTML)
// Serve embedded static files from web/
s.app.Use(prefix+"/", filesystem.New(filesystem.Config{
Root: http.FS(webFS),
PathPrefix: "web",
Browse: false,
staticFS, err := fs.Sub(webFS, "web")
if err != nil {
return fmt.Errorf("initialize embedded web UI filesystem: %w", err)
}
// Serve embedded static files from web/.
s.app.Use(prefix+"/", static.New("", static.Config{
FS: staticFS,
Browse: false,
}))
// Catch-all: absorb any request the filesystem did not fully handle.
// The filesystem middleware calls Next() for non-GET/HEAD methods and for
// paths not found in the embedded FS, which would otherwise fall through
// to the S3 router and be interpreted as bucket/object operations.
s.app.Use(prefix+"/", func(c *fiber.Ctx) error {
return c.SendStatus(http.StatusBadRequest)
// Catch-all: absorb any request the static middleware did not fully handle.
s.app.Use(prefix+"/", func(c fiber.Ctx) error {
return c.SendStatus(fiber.StatusBadRequest)
})
return nil
}
// handleIndexHTML serves index.html with server config injected as an inline script.
func (s *Server) handleIndexHTML(c *fiber.Ctx) error {
func (s *Server) handleIndexHTML(c fiber.Ctx) error {
data, err := webFiles.ReadFile("web/index.html")
if err != nil {
return fiber.ErrInternalServerError
@@ -184,9 +187,9 @@ func (s *Server) ServeMultiPort(ports []string) error {
var err error
if s.CertStorage != nil {
ln, err = utils.NewMultiAddrTLSListener(s.app.Config().Network, addrSpec, s.CertStorage.GetCertificate, utils.ListenerOptions{SocketPerm: s.socketPerm})
ln, err = utils.NewMultiAddrTLSListener(fiber.NetworkTCP, addrSpec, s.CertStorage.GetCertificate, utils.ListenerOptions{SocketPerm: s.socketPerm})
} else {
ln, err = utils.NewMultiAddrListener(s.app.Config().Network, addrSpec, utils.ListenerOptions{SocketPerm: s.socketPerm})
ln, err = utils.NewMultiAddrListener(fiber.NetworkTCP, addrSpec, utils.ListenerOptions{SocketPerm: s.socketPerm})
}
if err != nil {
@@ -203,7 +206,9 @@ func (s *Server) ServeMultiPort(ports []string) error {
// Combine all listeners
finalListener := utils.NewMultiListener(listeners...)
return s.app.Listener(finalListener)
return s.app.Listener(finalListener, fiber.ListenConfig{
DisableStartupMessage: true,
})
}
// Shutdown gracefully shuts down the server
@@ -214,12 +219,12 @@ func (s *Server) Shutdown() error {
// MountOn registers the WebUI routes on an existing Fiber app at the given path prefix.
// This allows hosting the WebUI on the same port as another service (e.g. the S3 API server).
// The prefix must start with "/" and must not be empty or just "/".
func MountOn(app *fiber.App, prefix string, cfg *ServerConfig) {
func MountOn(app *fiber.App, prefix string, cfg *ServerConfig) error {
s := &Server{
app: app,
config: cfg,
pathPrefix: prefix,
}
fmt.Printf("initializing web dashboard\n")
s.setupRoutes()
return s.setupRoutes()
}