From 0d208fe2f832a8be0f5eacaafcd4a4b3caf051d2 Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Mon, 14 Oct 2024 23:27:38 -0700 Subject: [PATCH 1/3] Added support for path style in presigned Post --- service/s3/presign_post.go | 29 +++++++++++++-- service/s3/presign_post_test.go | 63 +++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/service/s3/presign_post.go b/service/s3/presign_post.go index 6bdbcde6687..3f4ab42bb7e 100644 --- a/service/s3/presign_post.go +++ b/service/s3/presign_post.go @@ -8,6 +8,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "log" "net/url" "strings" "time" @@ -166,6 +167,9 @@ type PresignPostOptions struct { // // [here]https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html#sigv4-PolicyConditions Conditions []interface{} + + // BaseURLOverride provides an override for the presigner + BaseURLOverride *string } type presignPostConverter PresignPostOptions @@ -177,6 +181,7 @@ type presignPostRequestMiddlewareOptions struct { LogSigning bool ExpiresIn time.Duration Conditions []interface{} + BaseURLOverride *string } type presignPostRequestMiddleware struct { @@ -185,6 +190,7 @@ type presignPostRequestMiddleware struct { logSigning bool expiresIn time.Duration conditions []interface{} + BaseURLOverride *string } // newPresignPostRequestMiddleware returns a new presignPostRequestMiddleware @@ -196,6 +202,7 @@ func newPresignPostRequestMiddleware(options presignPostRequestMiddlewareOptions logSigning: options.LogSigning, expiresIn: options.ExpiresIn, conditions: options.Conditions, + BaseURLOverride: options.BaseURLOverride, } } @@ -267,6 +274,9 @@ func (s *presignPostRequestMiddleware) HandleFinalize( // Other middlewares may set default values on the URL on the path or as query params. Remove them baseURL := toBaseURL(u) + if s.BaseURLOverride != nil { + baseURL = *s.BaseURLOverride + } out.Result = &PresignedPostRequest{ URL: baseURL, @@ -277,8 +287,22 @@ func (s *presignPostRequestMiddleware) HandleFinalize( } func toBaseURL(fullURL string) string { - a, _ := url.Parse(fullURL) - return a.Scheme + "://" + a.Host + parsedURL, err := url.Parse(fullURL) + if err != nil { + log.Printf("Invalid URL format: %v", err) + return "" + } + pathSegments := strings.Split(parsedURL.Path, "/") + + if len(pathSegments) > 0 && pathSegments[0] == "" { + pathSegments = pathSegments[1:] + } + + if len(pathSegments) > 1 { + return fmt.Sprintf("%s://%s/%s", parsedURL.Scheme, parsedURL.Host, pathSegments[0]) + } else { + return fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host) + } } // Adapted from existing PresignConverter middleware @@ -305,6 +329,7 @@ func (c presignPostConverter) ConvertToPresignMiddleware(stack *middleware.Stack LogSigning: options.ClientLogMode.IsSigning(), ExpiresIn: expiresIn, Conditions: c.Conditions, + BaseURLOverride: c.BaseURLOverride, }) if _, err := stack.Finalize.Swap("Signing", pmw); err != nil { return err diff --git a/service/s3/presign_post_test.go b/service/s3/presign_post_test.go index baf50a2aaf8..77cab0157a5 100644 --- a/service/s3/presign_post_test.go +++ b/service/s3/presign_post_test.go @@ -19,11 +19,13 @@ func TestPresignPutObject(t *testing.T) { defer mockTime(fixedTime)() cases := map[string]struct { - input PutObjectInput - options []func(*PresignPostOptions) - expectedExpires time.Time - expectedURL string - region string + input PutObjectInput + options []func(*PresignPostOptions) + expectedExpires time.Time + expectedURL string + region string + pathStyleEnabled bool + BaseEndpoint string }{ "sample": { input: PutObjectInput{ @@ -66,6 +68,49 @@ func TestPresignPutObject(t *testing.T) { }, expectedURL: "https://mfzwi23gnjvgw.mrap.accesspoint.s3-global.amazonaws.com", }, + "override base url": { + input: PutObjectInput{ + Bucket: aws.String("bucket"), + Key: aws.String("key"), + }, + options: []func(o *PresignPostOptions){ + func(o *PresignPostOptions) { + o.BaseURLOverride = aws.String("https://s3.custom-domain.com") + }, + }, + expectedURL: "https://s3.custom-domain.com", + }, + "use path style bucket hosting pattern": { + input: PutObjectInput{ + Bucket: aws.String("bucket"), + Key: aws.String("key"), + }, + expectedURL: "https://s3.us-west-2.amazonaws.com/bucket", + pathStyleEnabled: true, + }, + "use path style bucket with custom baseEndpoint": { + input: PutObjectInput{ + Bucket: aws.String("bucket"), + Key: aws.String("key"), + }, + expectedURL: "https://s3.custom-domain.com/bucket", + pathStyleEnabled: true, + BaseEndpoint: "https://s3.custom-domain.com", + }, + "path style with baseEndpoint with url override option": { + input: PutObjectInput{ + Bucket: aws.String("bucket"), + Key: aws.String("key"), + }, + options: []func(o *PresignPostOptions){ + func(o *PresignPostOptions) { + o.BaseURLOverride = aws.String("https://different-url.com") + }, + }, + expectedURL: "https://different-url.com", + pathStyleEnabled: true, + BaseEndpoint: "https://s3.custom-domain.com", + }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { @@ -81,8 +126,12 @@ func TestPresignPutObject(t *testing.T) { return aws.NopRetryer{} }, } - - presignClient := NewPresignClient(NewFromConfig(cfg)) + presignClient := NewPresignClient(NewFromConfig(cfg, func(options *Options) { + options.UsePathStyle = tc.pathStyleEnabled + if tc.BaseEndpoint != "" { + options.BaseEndpoint = aws.String(tc.BaseEndpoint) + } + })) postObject, err := presignClient.PresignPostObject(ctx, &tc.input, tc.options...) if err != nil { t.Error(err) From de630f5d5ea27317fc249c81b13db87cc60d6b8d Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Mon, 14 Oct 2024 23:29:49 -0700 Subject: [PATCH 2/3] Added changelog --- .changelog/7762e0d93d3e4d549a85c7174feaff94.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changelog/7762e0d93d3e4d549a85c7174feaff94.json diff --git a/.changelog/7762e0d93d3e4d549a85c7174feaff94.json b/.changelog/7762e0d93d3e4d549a85c7174feaff94.json new file mode 100644 index 00000000000..d2c387b4ae3 --- /dev/null +++ b/.changelog/7762e0d93d3e4d549a85c7174feaff94.json @@ -0,0 +1,8 @@ +{ + "id": "7762e0d9-3d3e-4d54-9a85-c7174feaff94", + "type": "bugfix", + "description": "Added support for path style urls and overrides in presigned post", + "modules": [ + "service/s3" + ] +} \ No newline at end of file From 926a6bce7b9f12481870c262a82411d4340d2850 Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Tue, 15 Oct 2024 10:56:20 -0700 Subject: [PATCH 3/3] fixing lint error --- service/s3/presign_post.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/service/s3/presign_post.go b/service/s3/presign_post.go index 3f4ab42bb7e..72fc097a9d6 100644 --- a/service/s3/presign_post.go +++ b/service/s3/presign_post.go @@ -300,9 +300,8 @@ func toBaseURL(fullURL string) string { if len(pathSegments) > 1 { return fmt.Sprintf("%s://%s/%s", parsedURL.Scheme, parsedURL.Host, pathSegments[0]) - } else { - return fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host) } + return fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host) } // Adapted from existing PresignConverter middleware