src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

middleware.go (4020B)


      1 package presignedurl
      2 
      3 import (
      4 	"context"
      5 	"fmt"
      6 
      7 	awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
      8 	v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
      9 
     10 	"github.com/aws/smithy-go/middleware"
     11 )
     12 
     13 // URLPresigner provides the interface to presign the input parameters in to a
     14 // presigned URL.
     15 type URLPresigner interface {
     16 	// PresignURL presigns a URL.
     17 	PresignURL(ctx context.Context, srcRegion string, params interface{}) (*v4.PresignedHTTPRequest, error)
     18 }
     19 
     20 // ParameterAccessor provides an collection of accessor to for retrieving and
     21 // setting the values needed to PresignedURL generation
     22 type ParameterAccessor struct {
     23 	// GetPresignedURL accessor points to a function that retrieves a presigned url if present
     24 	GetPresignedURL func(interface{}) (string, bool, error)
     25 
     26 	// GetSourceRegion accessor points to a function that retrieves source region for presigned url
     27 	GetSourceRegion func(interface{}) (string, bool, error)
     28 
     29 	// CopyInput accessor points to a function that takes in an input, and returns a copy.
     30 	CopyInput func(interface{}) (interface{}, error)
     31 
     32 	// SetDestinationRegion accessor points to a function that sets destination region on api input struct
     33 	SetDestinationRegion func(interface{}, string) error
     34 
     35 	// SetPresignedURL accessor points to a function that sets presigned url on api input struct
     36 	SetPresignedURL func(interface{}, string) error
     37 }
     38 
     39 // Options provides the set of options needed by the presigned URL middleware.
     40 type Options struct {
     41 	// Accessor are the parameter accessors used by this middleware
     42 	Accessor ParameterAccessor
     43 
     44 	// Presigner is the URLPresigner used by the middleware
     45 	Presigner URLPresigner
     46 }
     47 
     48 // AddMiddleware adds the Presign URL middleware to the middleware stack.
     49 func AddMiddleware(stack *middleware.Stack, opts Options) error {
     50 	return stack.Initialize.Add(&presign{options: opts}, middleware.Before)
     51 }
     52 
     53 // RemoveMiddleware removes the Presign URL middleware from the stack.
     54 func RemoveMiddleware(stack *middleware.Stack) error {
     55 	_, err := stack.Initialize.Remove((*presign)(nil).ID())
     56 	return err
     57 }
     58 
     59 type presign struct {
     60 	options Options
     61 }
     62 
     63 func (m *presign) ID() string { return "Presign" }
     64 
     65 func (m *presign) HandleInitialize(
     66 	ctx context.Context, input middleware.InitializeInput, next middleware.InitializeHandler,
     67 ) (
     68 	out middleware.InitializeOutput, metadata middleware.Metadata, err error,
     69 ) {
     70 	// If PresignedURL is already set ignore middleware.
     71 	if _, ok, err := m.options.Accessor.GetPresignedURL(input.Parameters); err != nil {
     72 		return out, metadata, fmt.Errorf("presign middleware failed, %w", err)
     73 	} else if ok {
     74 		return next.HandleInitialize(ctx, input)
     75 	}
     76 
     77 	// If have source region is not set ignore middleware.
     78 	srcRegion, ok, err := m.options.Accessor.GetSourceRegion(input.Parameters)
     79 	if err != nil {
     80 		return out, metadata, fmt.Errorf("presign middleware failed, %w", err)
     81 	} else if !ok || len(srcRegion) == 0 {
     82 		return next.HandleInitialize(ctx, input)
     83 	}
     84 
     85 	// Create a copy of the original input so the destination region value can
     86 	// be added. This ensures that value does not leak into the original
     87 	// request parameters.
     88 	paramCpy, err := m.options.Accessor.CopyInput(input.Parameters)
     89 	if err != nil {
     90 		return out, metadata, fmt.Errorf("unable to create presigned URL, %w", err)
     91 	}
     92 
     93 	// Destination region is the API client's configured region.
     94 	dstRegion := awsmiddleware.GetRegion(ctx)
     95 	if err = m.options.Accessor.SetDestinationRegion(paramCpy, dstRegion); err != nil {
     96 		return out, metadata, fmt.Errorf("presign middleware failed, %w", err)
     97 	}
     98 
     99 	presignedReq, err := m.options.Presigner.PresignURL(ctx, srcRegion, paramCpy)
    100 	if err != nil {
    101 		return out, metadata, fmt.Errorf("unable to create presigned URL, %w", err)
    102 	}
    103 
    104 	// Update the original input with the presigned URL value.
    105 	if err = m.options.Accessor.SetPresignedURL(input.Parameters, presignedReq.URL); err != nil {
    106 		return out, metadata, fmt.Errorf("presign middleware failed, %w", err)
    107 	}
    108 
    109 	return next.HandleInitialize(ctx, input)
    110 }