github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/endpoint.go (about)

     1  package s3
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/aavshr/aws-sdk-go/aws/awserr"
     6  	"net/url"
     7  	"strings"
     8  
     9  	"github.com/aavshr/aws-sdk-go/aws"
    10  	awsarn "github.com/aavshr/aws-sdk-go/aws/arn"
    11  	"github.com/aavshr/aws-sdk-go/aws/request"
    12  	"github.com/aavshr/aws-sdk-go/internal/s3shared"
    13  	"github.com/aavshr/aws-sdk-go/internal/s3shared/arn"
    14  )
    15  
    16  const (
    17  	s3Namespace              = "s3"
    18  	s3AccessPointNamespace   = "s3-accesspoint"
    19  	s3ObjectsLambdaNamespace = "s3-object-lambda"
    20  	s3OutpostsNamespace      = "s3-outposts"
    21  )
    22  
    23  // Used by shapes with members decorated as endpoint ARN.
    24  func parseEndpointARN(v string) (arn.Resource, error) {
    25  	return arn.ParseResource(v, accessPointResourceParser)
    26  }
    27  
    28  func accessPointResourceParser(a awsarn.ARN) (arn.Resource, error) {
    29  	resParts := arn.SplitResource(a.Resource)
    30  	switch resParts[0] {
    31  	case "accesspoint":
    32  		switch a.Service {
    33  		case s3Namespace:
    34  			return arn.ParseAccessPointResource(a, resParts[1:])
    35  		case s3ObjectsLambdaNamespace:
    36  			return parseS3ObjectLambdaAccessPointResource(a, resParts)
    37  		default:
    38  			return arn.AccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: fmt.Sprintf("service is not %s or %s", s3Namespace, s3ObjectsLambdaNamespace)}
    39  		}
    40  	case "outpost":
    41  		if a.Service != "s3-outposts" {
    42  			return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "service is not s3-outposts"}
    43  		}
    44  		return parseOutpostAccessPointResource(a, resParts[1:])
    45  	default:
    46  		return nil, arn.InvalidARNError{ARN: a, Reason: "unknown resource type"}
    47  	}
    48  }
    49  
    50  // parseOutpostAccessPointResource attempts to parse the ARNs resource as an
    51  // outpost access-point resource.
    52  //
    53  // Supported Outpost AccessPoint ARN format:
    54  //	- ARN format: arn:{partition}:s3-outposts:{region}:{accountId}:outpost/{outpostId}/accesspoint/{accesspointName}
    55  //	- example: arn:aws:s3-outposts:us-west-2:012345678901:outpost/op-1234567890123456/accesspoint/myaccesspoint
    56  //
    57  func parseOutpostAccessPointResource(a awsarn.ARN, resParts []string) (arn.OutpostAccessPointARN, error) {
    58  	// outpost accesspoint arn is only valid if service is s3-outposts
    59  	if a.Service != "s3-outposts" {
    60  		return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "service is not s3-outposts"}
    61  	}
    62  
    63  	if len(resParts) == 0 {
    64  		return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "outpost resource-id not set"}
    65  	}
    66  
    67  	if len(resParts) < 3 {
    68  		return arn.OutpostAccessPointARN{}, arn.InvalidARNError{
    69  			ARN: a, Reason: "access-point resource not set in Outpost ARN",
    70  		}
    71  	}
    72  
    73  	resID := strings.TrimSpace(resParts[0])
    74  	if len(resID) == 0 {
    75  		return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "outpost resource-id not set"}
    76  	}
    77  
    78  	var outpostAccessPointARN = arn.OutpostAccessPointARN{}
    79  	switch resParts[1] {
    80  	case "accesspoint":
    81  		accessPointARN, err := arn.ParseAccessPointResource(a, resParts[2:])
    82  		if err != nil {
    83  			return arn.OutpostAccessPointARN{}, err
    84  		}
    85  		// set access-point arn
    86  		outpostAccessPointARN.AccessPointARN = accessPointARN
    87  	default:
    88  		return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "access-point resource not set in Outpost ARN"}
    89  	}
    90  
    91  	// set outpost id
    92  	outpostAccessPointARN.OutpostID = resID
    93  	return outpostAccessPointARN, nil
    94  }
    95  
    96  func parseS3ObjectLambdaAccessPointResource(a awsarn.ARN, resParts []string) (arn.S3ObjectLambdaAccessPointARN, error) {
    97  	if a.Service != s3ObjectsLambdaNamespace {
    98  		return arn.S3ObjectLambdaAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: fmt.Sprintf("service is not %s", s3ObjectsLambdaNamespace)}
    99  	}
   100  
   101  	accessPointARN, err := arn.ParseAccessPointResource(a, resParts[1:])
   102  	if err != nil {
   103  		return arn.S3ObjectLambdaAccessPointARN{}, err
   104  	}
   105  
   106  	if len(accessPointARN.Region) == 0 {
   107  		return arn.S3ObjectLambdaAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: fmt.Sprintf("%s region not set", s3ObjectsLambdaNamespace)}
   108  	}
   109  
   110  	return arn.S3ObjectLambdaAccessPointARN{
   111  		AccessPointARN: accessPointARN,
   112  	}, nil
   113  }
   114  
   115  func endpointHandler(req *request.Request) {
   116  	endpoint, ok := req.Params.(endpointARNGetter)
   117  	if !ok || !endpoint.hasEndpointARN() {
   118  		updateBucketEndpointFromParams(req)
   119  		return
   120  	}
   121  
   122  	resource, err := endpoint.getEndpointARN()
   123  	if err != nil {
   124  		req.Error = s3shared.NewInvalidARNError(nil, err)
   125  		return
   126  	}
   127  
   128  	resReq := s3shared.ResourceRequest{
   129  		Resource: resource,
   130  		Request:  req,
   131  	}
   132  
   133  	if len(resReq.Request.ClientInfo.PartitionID) != 0 && resReq.IsCrossPartition() {
   134  		req.Error = s3shared.NewClientPartitionMismatchError(resource,
   135  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   136  		return
   137  	}
   138  
   139  	if !resReq.AllowCrossRegion() && resReq.IsCrossRegion() {
   140  		req.Error = s3shared.NewClientRegionMismatchError(resource,
   141  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   142  		return
   143  	}
   144  
   145  	switch tv := resource.(type) {
   146  	case arn.AccessPointARN:
   147  		err = updateRequestAccessPointEndpoint(req, tv)
   148  		if err != nil {
   149  			req.Error = err
   150  		}
   151  	case arn.S3ObjectLambdaAccessPointARN:
   152  		err = updateRequestS3ObjectLambdaAccessPointEndpoint(req, tv)
   153  		if err != nil {
   154  			req.Error = err
   155  		}
   156  	case arn.OutpostAccessPointARN:
   157  		// outposts does not support FIPS regions
   158  		if resReq.UseFIPS() {
   159  			req.Error = s3shared.NewFIPSConfigurationError(resource, req.ClientInfo.PartitionID,
   160  				aws.StringValue(req.Config.Region), nil)
   161  			return
   162  		}
   163  
   164  		err = updateRequestOutpostAccessPointEndpoint(req, tv)
   165  		if err != nil {
   166  			req.Error = err
   167  		}
   168  	default:
   169  		req.Error = s3shared.NewInvalidARNError(resource, nil)
   170  	}
   171  }
   172  
   173  func updateBucketEndpointFromParams(r *request.Request) {
   174  	bucket, ok := bucketNameFromReqParams(r.Params)
   175  	if !ok {
   176  		// Ignore operation requests if the bucket name was not provided
   177  		// if this is an input validation error the validation handler
   178  		// will report it.
   179  		return
   180  	}
   181  	updateEndpointForS3Config(r, bucket)
   182  }
   183  
   184  func updateRequestAccessPointEndpoint(req *request.Request, accessPoint arn.AccessPointARN) error {
   185  	// Accelerate not supported
   186  	if aws.BoolValue(req.Config.S3UseAccelerate) {
   187  		return s3shared.NewClientConfiguredForAccelerateError(accessPoint,
   188  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   189  	}
   190  
   191  	// Ignore the disable host prefix for access points
   192  	req.Config.DisableEndpointHostPrefix = aws.Bool(false)
   193  
   194  	if err := accessPointEndpointBuilder(accessPoint).build(req); err != nil {
   195  		return err
   196  	}
   197  
   198  	removeBucketFromPath(req.HTTPRequest.URL)
   199  
   200  	return nil
   201  }
   202  
   203  func updateRequestS3ObjectLambdaAccessPointEndpoint(req *request.Request, accessPoint arn.S3ObjectLambdaAccessPointARN) error {
   204  	// DualStack not supported
   205  	if aws.BoolValue(req.Config.UseDualStack) {
   206  		return s3shared.NewClientConfiguredForDualStackError(accessPoint,
   207  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   208  	}
   209  
   210  	// Accelerate not supported
   211  	if aws.BoolValue(req.Config.S3UseAccelerate) {
   212  		return s3shared.NewClientConfiguredForAccelerateError(accessPoint,
   213  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   214  	}
   215  
   216  	// Ignore the disable host prefix for access points
   217  	req.Config.DisableEndpointHostPrefix = aws.Bool(false)
   218  
   219  	if err := s3ObjectLambdaAccessPointEndpointBuilder(accessPoint).build(req); err != nil {
   220  		return err
   221  	}
   222  
   223  	removeBucketFromPath(req.HTTPRequest.URL)
   224  
   225  	return nil
   226  }
   227  
   228  func updateRequestOutpostAccessPointEndpoint(req *request.Request, accessPoint arn.OutpostAccessPointARN) error {
   229  	// Accelerate not supported
   230  	if aws.BoolValue(req.Config.S3UseAccelerate) {
   231  		return s3shared.NewClientConfiguredForAccelerateError(accessPoint,
   232  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   233  	}
   234  
   235  	// Dualstack not supported
   236  	if aws.BoolValue(req.Config.UseDualStack) {
   237  		return s3shared.NewClientConfiguredForDualStackError(accessPoint,
   238  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   239  	}
   240  
   241  	// Ignore the disable host prefix for access points
   242  	req.Config.DisableEndpointHostPrefix = aws.Bool(false)
   243  
   244  	if err := outpostAccessPointEndpointBuilder(accessPoint).build(req); err != nil {
   245  		return err
   246  	}
   247  
   248  	removeBucketFromPath(req.HTTPRequest.URL)
   249  	return nil
   250  }
   251  
   252  func removeBucketFromPath(u *url.URL) {
   253  	u.Path = strings.Replace(u.Path, "/{Bucket}", "", -1)
   254  	if u.Path == "" {
   255  		u.Path = "/"
   256  	}
   257  }
   258  
   259  func buildWriteGetObjectResponseEndpoint(req *request.Request) {
   260  	// DualStack not supported
   261  	if aws.BoolValue(req.Config.UseDualStack) {
   262  		req.Error = awserr.New("ConfigurationError", "client configured for dualstack but not supported for operation", nil)
   263  		return
   264  	}
   265  
   266  	// Accelerate not supported
   267  	if aws.BoolValue(req.Config.S3UseAccelerate) {
   268  		req.Error = awserr.New("ConfigurationError", "client configured for accelerate but not supported for operation", nil)
   269  		return
   270  	}
   271  
   272  	signingName := s3ObjectsLambdaNamespace
   273  	signingRegion := req.ClientInfo.SigningRegion
   274  
   275  	if !hasCustomEndpoint(req) {
   276  		endpoint, err := resolveRegionalEndpoint(req, aws.StringValue(req.Config.Region), EndpointsID)
   277  		if err != nil {
   278  			req.Error = awserr.New(request.ErrCodeSerialization, "failed to resolve endpoint", err)
   279  			return
   280  		}
   281  		signingRegion = endpoint.SigningRegion
   282  
   283  		if err = updateRequestEndpoint(req, endpoint.URL); err != nil {
   284  			req.Error = err
   285  			return
   286  		}
   287  		updateS3HostPrefixForS3ObjectLambda(req)
   288  	}
   289  
   290  	redirectSigner(req, signingName, signingRegion)
   291  }