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

     1  package s3control
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/aavshr/aws-sdk-go/aws"
     8  	awsarn "github.com/aavshr/aws-sdk-go/aws/arn"
     9  	"github.com/aavshr/aws-sdk-go/aws/request"
    10  	"github.com/aavshr/aws-sdk-go/internal/s3shared"
    11  	"github.com/aavshr/aws-sdk-go/internal/s3shared/arn"
    12  )
    13  
    14  const (
    15  	// outpost id header
    16  	outpostIDHeader = "x-amz-outpost-id"
    17  
    18  	// account id header
    19  	accountIDHeader = "x-amz-account-id"
    20  )
    21  
    22  // Used by shapes with members decorated as endpoint ARN.
    23  func parseEndpointARN(v string) (arn.Resource, error) {
    24  	return arn.ParseResource(v, resourceParser)
    25  }
    26  
    27  func resourceParser(a awsarn.ARN) (arn.Resource, error) {
    28  	resParts := arn.SplitResource(a.Resource)
    29  	switch resParts[0] {
    30  	case "outpost":
    31  		return arn.ParseOutpostARNResource(a, resParts[1:])
    32  	default:
    33  		return nil, arn.InvalidARNError{ARN: a, Reason: "unknown resource type"}
    34  	}
    35  }
    36  
    37  func endpointHandler(req *request.Request) {
    38  	// For special case "CreateBucket" and "ListRegionalBuckets" operation
    39  	outpostIDEndpoint, ok := req.Params.(endpointOutpostIDGetter)
    40  	if ok && outpostIDEndpoint.hasOutpostID() {
    41  		outpostID, err := outpostIDEndpoint.getOutpostID()
    42  		if err != nil {
    43  			req.Error = fmt.Errorf("expected outpost ID to be supported, %v", err)
    44  		}
    45  		if len(strings.TrimSpace(outpostID)) == 0 {
    46  			return
    47  		}
    48  		updateRequestOutpostIDEndpoint(req)
    49  		return
    50  	}
    51  
    52  	endpoint, ok := req.Params.(endpointARNGetter)
    53  	if !ok || !endpoint.hasEndpointARN() {
    54  		return
    55  	}
    56  
    57  	resource, err := endpoint.getEndpointARN()
    58  	if err != nil {
    59  		req.Error = s3shared.NewInvalidARNError(nil, err)
    60  		return
    61  	}
    62  
    63  	// Add account-id header for the request if not present.
    64  	// SDK must always send the x-amz-account-id header for all requests
    65  	// where an accountId has been extracted from an ARN or the accountId field modeled as a header.
    66  	if h := req.HTTPRequest.Header.Get(accountIDHeader); len(h) == 0 {
    67  		req.HTTPRequest.Header.Add(accountIDHeader, resource.GetARN().AccountID)
    68  	}
    69  
    70  	switch tv := resource.(type) {
    71  	case arn.OutpostAccessPointARN:
    72  		// Add outpostID header
    73  		req.HTTPRequest.Header.Add(outpostIDHeader, tv.OutpostID)
    74  
    75  		// update arnable field to resource value
    76  		updatedInput, err := endpoint.updateArnableField(tv.AccessPointName)
    77  		if err != nil {
    78  			req.Error = err
    79  			return
    80  		}
    81  
    82  		// update request params to use modified ARN field value, if not nil
    83  		if updatedInput != nil {
    84  			req.Params = updatedInput
    85  		}
    86  
    87  		// update request for outpost access point endpoint
    88  		err = updateRequestOutpostAccessPointEndpoint(req, tv)
    89  		if err != nil {
    90  			req.Error = err
    91  		}
    92  	case arn.OutpostBucketARN:
    93  		// Add outpostID header
    94  		req.HTTPRequest.Header.Add(outpostIDHeader, tv.OutpostID)
    95  
    96  		// update arnable field to resource value
    97  		updatedInput, err := endpoint.updateArnableField(tv.BucketName)
    98  		if err != nil {
    99  			req.Error = err
   100  			return
   101  		}
   102  
   103  		// update request params to use modified ARN field value, if not nil
   104  		if updatedInput != nil {
   105  			req.Params = updatedInput
   106  		}
   107  
   108  		// update request for outpost bucket endpoint
   109  		err = updateRequestOutpostBucketEndpoint(req, tv)
   110  		if err != nil {
   111  			req.Error = err
   112  		}
   113  	default:
   114  		req.Error = s3shared.NewInvalidARNError(resource, nil)
   115  	}
   116  }
   117  
   118  // updateRequestOutpostIDEndpoint is special customization to be applied for operations
   119  // CreateBucket, ListRegionalBuckets which must resolve endpoint to s3-outposts.{region}.amazonaws.com
   120  // with region as client region and signed by s3-control if an outpost id is provided.
   121  func updateRequestOutpostIDEndpoint(request *request.Request) {
   122  	cfgRegion := aws.StringValue(request.Config.Region)
   123  
   124  	if !hasCustomEndpoint(request) {
   125  		serviceEndpointLabel := "s3-outposts."
   126  
   127  		// request url
   128  		request.HTTPRequest.URL.Host = serviceEndpointLabel + cfgRegion + ".amazonaws.com"
   129  
   130  		// disable the host prefix for outpost access points
   131  		request.Config.DisableEndpointHostPrefix = aws.Bool(true)
   132  	}
   133  
   134  	// signer redirection
   135  	request.ClientInfo.SigningName = "s3-outposts"
   136  	request.ClientInfo.SigningRegion = cfgRegion
   137  }
   138  
   139  func updateRequestOutpostAccessPointEndpoint(req *request.Request, accessPoint arn.OutpostAccessPointARN) error {
   140  	// validate Outpost endpoint
   141  	if err := validateOutpostEndpoint(req, accessPoint); err != nil {
   142  		return err
   143  	}
   144  
   145  	// disable the host prefix for outpost access points
   146  	req.Config.DisableEndpointHostPrefix = aws.Bool(true)
   147  
   148  	if err := outpostAccessPointEndpointBuilder(accessPoint).build(req); err != nil {
   149  		return err
   150  	}
   151  
   152  	return nil
   153  }
   154  
   155  func updateRequestOutpostBucketEndpoint(req *request.Request, bucketResource arn.OutpostBucketARN) error {
   156  	// validate Outpost endpoint
   157  	if err := validateOutpostEndpoint(req, bucketResource); err != nil {
   158  		return err
   159  	}
   160  
   161  	// disable the host prefix for outpost bucket.
   162  	req.Config.DisableEndpointHostPrefix = aws.Bool(true)
   163  
   164  	if err := outpostBucketResourceEndpointBuilder(bucketResource).build(req); err != nil {
   165  		return err
   166  	}
   167  
   168  	return nil
   169  }
   170  
   171  // validate request resource for retrieving endpoint
   172  func validateEndpointRequestResource(req *request.Request, resource arn.Resource) error {
   173  	resReq := s3shared.ResourceRequest{Request: req, Resource: resource}
   174  
   175  	if len(resReq.Request.ClientInfo.PartitionID) != 0 && resReq.IsCrossPartition() {
   176  		return s3shared.NewClientPartitionMismatchError(resource,
   177  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   178  	}
   179  
   180  	if !resReq.AllowCrossRegion() && resReq.IsCrossRegion() {
   181  		return s3shared.NewClientRegionMismatchError(resource,
   182  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   183  	}
   184  
   185  	// Accelerate not supported
   186  	if aws.BoolValue(req.Config.S3UseAccelerate) {
   187  		return s3shared.NewClientConfiguredForAccelerateError(resource,
   188  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   189  	}
   190  	return nil
   191  }
   192  
   193  // validations for fetching outpost endpoint
   194  func validateOutpostEndpoint(req *request.Request, resource arn.Resource) error {
   195  	resReq := s3shared.ResourceRequest{
   196  		Request:  req,
   197  		Resource: resource,
   198  	}
   199  
   200  	if err := validateEndpointRequestResource(req, resource); err != nil {
   201  		return err
   202  	}
   203  
   204  	// resource configured with FIPS as region is not supported by outposts
   205  	if resReq.UseFIPS() {
   206  		return s3shared.NewFIPSConfigurationError(resource, req.ClientInfo.PartitionID,
   207  			aws.StringValue(req.Config.Region), nil)
   208  	}
   209  
   210  	// DualStack not supported
   211  	if aws.BoolValue(req.Config.UseDualStack) {
   212  		return s3shared.NewClientConfiguredForDualStackError(resource,
   213  			req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
   214  	}
   215  	return nil
   216  }