middleware.go raw
1 package client
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "io"
8 "net/url"
9
10 "github.com/aws/smithy-go"
11 smithymiddleware "github.com/aws/smithy-go/middleware"
12 smithyhttp "github.com/aws/smithy-go/transport/http"
13 )
14
15 type buildEndpoint struct {
16 Endpoint string
17 }
18
19 func (b *buildEndpoint) ID() string {
20 return "BuildEndpoint"
21 }
22
23 func (b *buildEndpoint) HandleBuild(ctx context.Context, in smithymiddleware.BuildInput, next smithymiddleware.BuildHandler) (
24 out smithymiddleware.BuildOutput, metadata smithymiddleware.Metadata, err error,
25 ) {
26 request, ok := in.Request.(*smithyhttp.Request)
27 if !ok {
28 return out, metadata, fmt.Errorf("unknown transport, %T", in.Request)
29 }
30
31 if len(b.Endpoint) == 0 {
32 return out, metadata, fmt.Errorf("endpoint not provided")
33 }
34
35 parsed, err := url.Parse(b.Endpoint)
36 if err != nil {
37 return out, metadata, fmt.Errorf("failed to parse endpoint, %w", err)
38 }
39
40 request.URL = parsed
41
42 return next.HandleBuild(ctx, in)
43 }
44
45 type serializeOpGetCredential struct{}
46
47 func (s *serializeOpGetCredential) ID() string {
48 return "OperationSerializer"
49 }
50
51 func (s *serializeOpGetCredential) HandleSerialize(ctx context.Context, in smithymiddleware.SerializeInput, next smithymiddleware.SerializeHandler) (
52 out smithymiddleware.SerializeOutput, metadata smithymiddleware.Metadata, err error,
53 ) {
54 request, ok := in.Request.(*smithyhttp.Request)
55 if !ok {
56 return out, metadata, fmt.Errorf("unknown transport type, %T", in.Request)
57 }
58
59 params, ok := in.Parameters.(*GetCredentialsInput)
60 if !ok {
61 return out, metadata, fmt.Errorf("unknown input parameters, %T", in.Parameters)
62 }
63
64 const acceptHeader = "Accept"
65 request.Header[acceptHeader] = append(request.Header[acceptHeader][:0], "application/json")
66
67 if len(params.AuthorizationToken) > 0 {
68 const authHeader = "Authorization"
69 request.Header[authHeader] = append(request.Header[authHeader][:0], params.AuthorizationToken)
70 }
71
72 return next.HandleSerialize(ctx, in)
73 }
74
75 type deserializeOpGetCredential struct{}
76
77 func (d *deserializeOpGetCredential) ID() string {
78 return "OperationDeserializer"
79 }
80
81 func (d *deserializeOpGetCredential) HandleDeserialize(ctx context.Context, in smithymiddleware.DeserializeInput, next smithymiddleware.DeserializeHandler) (
82 out smithymiddleware.DeserializeOutput, metadata smithymiddleware.Metadata, err error,
83 ) {
84 out, metadata, err = next.HandleDeserialize(ctx, in)
85 if err != nil {
86 return out, metadata, err
87 }
88
89 response, ok := out.RawResponse.(*smithyhttp.Response)
90 if !ok {
91 return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)}
92 }
93
94 if response.StatusCode < 200 || response.StatusCode >= 300 {
95 return out, metadata, deserializeError(response)
96 }
97
98 var shape *GetCredentialsOutput
99 if err = json.NewDecoder(response.Body).Decode(&shape); err != nil {
100 return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("failed to deserialize json response, %w", err)}
101 }
102
103 out.Result = shape
104 return out, metadata, err
105 }
106
107 func deserializeError(response *smithyhttp.Response) error {
108 // we could be talking to anything, json isn't guaranteed
109 // see https://github.com/aws/aws-sdk-go-v2/issues/2316
110 if response.Header.Get("Content-Type") == "application/json" {
111 return deserializeJSONError(response)
112 }
113
114 msg, err := io.ReadAll(response.Body)
115 if err != nil {
116 return &smithy.DeserializationError{
117 Err: fmt.Errorf("read response, %w", err),
118 }
119 }
120
121 return &EndpointError{
122 // no sensible value for Code
123 Message: string(msg),
124 Fault: stof(response.StatusCode),
125 statusCode: response.StatusCode,
126 }
127 }
128
129 func deserializeJSONError(response *smithyhttp.Response) error {
130 var errShape *EndpointError
131 if err := json.NewDecoder(response.Body).Decode(&errShape); err != nil {
132 return &smithy.DeserializationError{
133 Err: fmt.Errorf("failed to decode error message, %w", err),
134 }
135 }
136
137 errShape.Fault = stof(response.StatusCode)
138 errShape.statusCode = response.StatusCode
139 return errShape
140 }
141
142 // maps HTTP status code to smithy ErrorFault
143 func stof(code int) smithy.ErrorFault {
144 if code >= 500 {
145 return smithy.FaultServer
146 }
147 return smithy.FaultClient
148 }
149
150 func addProtocolFinalizerMiddlewares(stack *smithymiddleware.Stack, options Options, operation string) error {
151 if err := stack.Finalize.Add(&resolveAuthSchemeMiddleware{operation: operation, options: options}, smithymiddleware.Before); err != nil {
152 return fmt.Errorf("add ResolveAuthScheme: %w", err)
153 }
154 if err := stack.Finalize.Insert(&getIdentityMiddleware{options: options}, "ResolveAuthScheme", smithymiddleware.After); err != nil {
155 return fmt.Errorf("add GetIdentity: %w", err)
156 }
157 if err := stack.Finalize.Insert(&resolveEndpointV2Middleware{options: options}, "GetIdentity", smithymiddleware.After); err != nil {
158 return fmt.Errorf("add ResolveEndpointV2: %w", err)
159 }
160 if err := stack.Finalize.Insert(&signRequestMiddleware{}, "ResolveEndpointV2", smithymiddleware.After); err != nil {
161 return fmt.Errorf("add Signing: %w", err)
162 }
163 return nil
164 }
165