From 31faa6d43d3d518398d9ff587bab62f642d28426 Mon Sep 17 00:00:00 2001 From: Andrey Triumfov Date: Mon, 15 Aug 2022 18:19:28 +0300 Subject: [PATCH] Remove duplicate slashes in object path to prevent 500 errors (#3442) --- weed/s3api/s3api_object_handlers.go | 23 +++++++++++- weed/s3api/s3api_object_handlers_test.go | 48 ++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 weed/s3api/s3api_object_handlers_test.go diff --git a/weed/s3api/s3api_object_handlers.go b/weed/s3api/s3api_object_handlers.go index 75abd0e4d..f3b34fa4d 100644 --- a/weed/s3api/s3api_object_handlers.go +++ b/weed/s3api/s3api_object_handlers.go @@ -130,9 +130,30 @@ func urlPathEscape(object string) string { return strings.Join(escapedParts, "/") } +func removeDuplicateSlashes(object string) string { + result := strings.Builder{} + result.Grow(len(object)) + + isLastSlash := false + for _, r := range object { + switch r { + case '/': + if !isLastSlash { + result.WriteRune(r) + } + isLastSlash = true + default: + result.WriteRune(r) + isLastSlash = false + } + } + return result.String() +} + func (s3a *S3ApiServer) toFilerUrl(bucket, object string) string { + object = urlPathEscape(removeDuplicateSlashes(object)) destUrl := fmt.Sprintf("http://%s%s/%s%s", - s3a.option.Filer.ToHttpAddress(), s3a.option.BucketsPath, bucket, urlPathEscape(object)) + s3a.option.Filer.ToHttpAddress(), s3a.option.BucketsPath, bucket, object) return destUrl } diff --git a/weed/s3api/s3api_object_handlers_test.go b/weed/s3api/s3api_object_handlers_test.go new file mode 100644 index 000000000..d1043451d --- /dev/null +++ b/weed/s3api/s3api_object_handlers_test.go @@ -0,0 +1,48 @@ +package s3api + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRemoveDuplicateSlashes(t *testing.T) { + tests := []struct { + name string + path string + expectedResult string + }{ + { + name: "empty", + path: "", + expectedResult: "", + }, + { + name: "slash", + path: "/", + expectedResult: "/", + }, + { + name: "object", + path: "object", + expectedResult: "object", + }, + { + name: "correct path", + path: "/path/to/object", + expectedResult: "/path/to/object", + }, + { + name: "path with duplicates", + path: "///path//to/object//", + expectedResult: "/path/to/object/", + }, + } + + for _, tst := range tests { + t.Run(tst.name, func(t *testing.T) { + obj := removeDuplicateSlashes(tst.path) + assert.Equal(t, tst.expectedResult, obj) + }) + } +}