middleware.go (5027B)
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 }