aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/middleware.go
blob: 1e2f5c8122a03c573726e49ad10476a6859e1ef5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package presignedurl

import (
	"context"
	"fmt"

	awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
	v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"

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

// URLPresigner provides the interface to presign the input parameters in to a
// presigned URL.
type URLPresigner interface {
	// PresignURL presigns a URL.
	PresignURL(ctx context.Context, srcRegion string, params interface{}) (*v4.PresignedHTTPRequest, error)
}

// ParameterAccessor provides an collection of accessor to for retrieving and
// setting the values needed to PresignedURL generation
type ParameterAccessor struct {
	// GetPresignedURL accessor points to a function that retrieves a presigned url if present
	GetPresignedURL func(interface{}) (string, bool, error)

	// GetSourceRegion accessor points to a function that retrieves source region for presigned url
	GetSourceRegion func(interface{}) (string, bool, error)

	// CopyInput accessor points to a function that takes in an input, and returns a copy.
	CopyInput func(interface{}) (interface{}, error)

	// SetDestinationRegion accessor points to a function that sets destination region on api input struct
	SetDestinationRegion func(interface{}, string) error

	// SetPresignedURL accessor points to a function that sets presigned url on api input struct
	SetPresignedURL func(interface{}, string) error
}

// Options provides the set of options needed by the presigned URL middleware.
type Options struct {
	// Accessor are the parameter accessors used by this middleware
	Accessor ParameterAccessor

	// Presigner is the URLPresigner used by the middleware
	Presigner URLPresigner
}

// AddMiddleware adds the Presign URL middleware to the middleware stack.
func AddMiddleware(stack *middleware.Stack, opts Options) error {
	return stack.Initialize.Add(&presign{options: opts}, middleware.Before)
}

// RemoveMiddleware removes the Presign URL middleware from the stack.
func RemoveMiddleware(stack *middleware.Stack) error {
	_, err := stack.Initialize.Remove((*presign)(nil).ID())
	return err
}

type presign struct {
	options Options
}

func (m *presign) ID() string { return "Presign" }

func (m *presign) HandleInitialize(
	ctx context.Context, input middleware.InitializeInput, next middleware.InitializeHandler,
) (
	out middleware.InitializeOutput, metadata middleware.Metadata, err error,
) {
	// If PresignedURL is already set ignore middleware.
	if _, ok, err := m.options.Accessor.GetPresignedURL(input.Parameters); err != nil {
		return out, metadata, fmt.Errorf("presign middleware failed, %w", err)
	} else if ok {
		return next.HandleInitialize(ctx, input)
	}

	// If have source region is not set ignore middleware.
	srcRegion, ok, err := m.options.Accessor.GetSourceRegion(input.Parameters)
	if err != nil {
		return out, metadata, fmt.Errorf("presign middleware failed, %w", err)
	} else if !ok || len(srcRegion) == 0 {
		return next.HandleInitialize(ctx, input)
	}

	// Create a copy of the original input so the destination region value can
	// be added. This ensures that value does not leak into the original
	// request parameters.
	paramCpy, err := m.options.Accessor.CopyInput(input.Parameters)
	if err != nil {
		return out, metadata, fmt.Errorf("unable to create presigned URL, %w", err)
	}

	// Destination region is the API client's configured region.
	dstRegion := awsmiddleware.GetRegion(ctx)
	if err = m.options.Accessor.SetDestinationRegion(paramCpy, dstRegion); err != nil {
		return out, metadata, fmt.Errorf("presign middleware failed, %w", err)
	}

	presignedReq, err := m.options.Presigner.PresignURL(ctx, srcRegion, paramCpy)
	if err != nil {
		return out, metadata, fmt.Errorf("unable to create presigned URL, %w", err)
	}

	// Update the original input with the presigned URL value.
	if err = m.options.Accessor.SetPresignedURL(input.Parameters, presignedReq.URL); err != nil {
		return out, metadata, fmt.Errorf("presign middleware failed, %w", err)
	}

	return next.HandleInitialize(ctx, input)
}