Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update presign post URL resolution to use the exact result from EndpointResolverV2 #2842

Merged
merged 4 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changelog/5702f383099a47a5860f5ab25cda67a1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": "5702f383-099a-47a5-860f-5ab25cda67a1",
"type": "bugfix",
"description": "Update presign post URL resolution to use the exact result from EndpointResolverV2",
"modules": [
"service/s3"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 software.amazon.smithy.aws.go.codegen.customization.s3;

import software.amazon.smithy.aws.go.codegen.AwsGoDependency;
import software.amazon.smithy.aws.go.codegen.customization.S3ModelUtils;
import software.amazon.smithy.go.codegen.GoSettings;
import software.amazon.smithy.go.codegen.GoWriter;
import software.amazon.smithy.go.codegen.integration.GoIntegration;
import software.amazon.smithy.model.Model;

import java.util.Map;

/**
* Stores the endpoint resolved by EndpointResolverV2
*/
public class StoreResolvedUri implements GoIntegration {
@Override
public void renderPostEndpointResolutionHook(GoSettings settings, GoWriter writer, Model model) {
if (!S3ModelUtils.isServiceS3(model, settings.getService(model))) return;
writer.writeGoTemplate(
"""
ctx = $setFunc:L(ctx, endpt.URI.String())
""",
Map.of(
"setFunc", "setS3ResolvedURI")
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ software.amazon.smithy.aws.go.codegen.customization.RemoveDefaults
software.amazon.smithy.aws.go.codegen.customization.auth.S3ExpressAuthScheme
software.amazon.smithy.aws.go.codegen.customization.S3BucketContext
software.amazon.smithy.aws.go.codegen.customization.s3.ExpressDefaultChecksum
software.amazon.smithy.aws.go.codegen.customization.s3.StoreResolvedUri
software.amazon.smithy.aws.go.codegen.customization.auth.GlobalAnonymousOption
software.amazon.smithy.aws.go.codegen.customization.CloudFrontKVSSigV4a
software.amazon.smithy.aws.go.codegen.customization.BackfillProtocolTestServiceTrait
Expand Down
2 changes: 2 additions & 0 deletions service/s3/endpoints.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 2 additions & 16 deletions service/s3/presign_post.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"net/url"
"strings"
"time"

Expand Down Expand Up @@ -211,10 +210,6 @@ func (s *presignPostRequestMiddleware) HandleFinalize(
) (
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
) {
req, ok := in.Request.(*smithyhttp.Request)
if !ok {
return out, metadata, fmt.Errorf("unexpected request middleware type %T", in.Request)
}

input := getOperationInput(ctx)
asS3Put, ok := input.(*PutObjectInput)
Expand All @@ -230,8 +225,7 @@ func (s *presignPostRequestMiddleware) HandleFinalize(
return out, metadata, fmt.Errorf("PutObject input does not have a key input")
}

httpReq := req.Build(ctx)
u := httpReq.URL.String()
uri := getS3ResolvedURI(ctx)

signingName := awsmiddleware.GetSigningName(ctx)
signingRegion := awsmiddleware.GetSigningRegion(ctx)
Expand Down Expand Up @@ -265,22 +259,14 @@ 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)

out.Result = &PresignedPostRequest{
URL: baseURL,
URL: uri,
Values: fields,
}

return out, metadata, nil
}

func toBaseURL(fullURL string) string {
a, _ := url.Parse(fullURL)
return a.Scheme + "://" + a.Host
}

// Adapted from existing PresignConverter middleware
func (c presignPostConverter) ConvertToPresignMiddleware(stack *middleware.Stack, options Options) (err error) {
stack.Build.Remove("UserAgent")
Expand Down
60 changes: 53 additions & 7 deletions service/s3/presign_post_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,26 @@ 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{
Bucket: aws.String("bucket"),
Key: aws.String("key"),
},
},
"bucket and key have the same value": {
input: PutObjectInput{
Bucket: aws.String("bucket"),
Key: aws.String("bucket"),
},
},
"expires override": {
input: PutObjectInput{
Bucket: aws.String("bucket"),
Expand Down Expand Up @@ -66,6 +74,40 @@ func TestPresignPutObject(t *testing.T) {
},
expectedURL: "https://mfzwi23gnjvgw.mrap.accesspoint.s3-global.amazonaws.com",
},
"use path style bucket hosting pattern": {
Madrigal marked this conversation as resolved.
Show resolved Hide resolved
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 and key have the same value ": {
input: PutObjectInput{
Bucket: aws.String("value"),
Key: aws.String("value"),
},
expectedURL: "https://s3.us-west-2.amazonaws.com/value",
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",
},
"use path style bucket with custom baseEndpoint with path": {
input: PutObjectInput{
Bucket: aws.String("bucket"),
Key: aws.String("key"),
},
BaseEndpoint: "https://my-custom-domain.com/path_my_path",
pathStyleEnabled: true,
expectedURL: "https://my-custom-domain.com/path_my_path/bucket",
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
Expand All @@ -81,8 +123,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)
Expand Down
23 changes: 23 additions & 0 deletions service/s3/uri_context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package s3

// This contains helper methods to set resolver URI into the context object. If they are ever used for
// something other than S3, they should be moved to internal/context/context.go

import (
"context"

"github.com/aws/smithy-go/middleware"
)

type s3resolvedURI struct{}

// setS3ResolvedURI sets the URI as resolved by the EndpointResolverV2
func setS3ResolvedURI(ctx context.Context, value string) context.Context {
return middleware.WithStackValue(ctx, s3resolvedURI{}, value)
}

// getS3ResolvedURI gets the URI as resolved by EndpointResolverV2
func getS3ResolvedURI(ctx context.Context) string {
v, _ := middleware.GetStackValue(ctx, s3resolvedURI{}).(string)
return v
}
Loading