middleware.go 4.9 KB

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