middleware_headers.go (5259B)
1 package http 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/aws/smithy-go/middleware" 8 ) 9 10 type isContentTypeAutoSet struct{} 11 12 // SetIsContentTypeDefaultValue returns a Context specifying if the request's 13 // content-type header was set to a default value. 14 func SetIsContentTypeDefaultValue(ctx context.Context, isDefault bool) context.Context { 15 return context.WithValue(ctx, isContentTypeAutoSet{}, isDefault) 16 } 17 18 // GetIsContentTypeDefaultValue returns if the content-type HTTP header on the 19 // request is a default value that was auto assigned by an operation 20 // serializer. Allows middleware post serialization to know if the content-type 21 // was auto set to a default value or not. 22 // 23 // Also returns false if the Context value was never updated to include if 24 // content-type was set to a default value. 25 func GetIsContentTypeDefaultValue(ctx context.Context) bool { 26 v, _ := ctx.Value(isContentTypeAutoSet{}).(bool) 27 return v 28 } 29 30 // AddNoPayloadDefaultContentTypeRemover Adds the DefaultContentTypeRemover 31 // middleware to the stack after the operation serializer. This middleware will 32 // remove the content-type header from the request if it was set as a default 33 // value, and no request payload is present. 34 // 35 // Returns error if unable to add the middleware. 36 func AddNoPayloadDefaultContentTypeRemover(stack *middleware.Stack) (err error) { 37 err = stack.Serialize.Insert(removeDefaultContentType{}, 38 "OperationSerializer", middleware.After) 39 if err != nil { 40 return fmt.Errorf("failed to add %s serialize middleware, %w", 41 removeDefaultContentType{}.ID(), err) 42 } 43 44 return nil 45 } 46 47 // RemoveNoPayloadDefaultContentTypeRemover removes the 48 // DefaultContentTypeRemover middleware from the stack. Returns an error if 49 // unable to remove the middleware. 50 func RemoveNoPayloadDefaultContentTypeRemover(stack *middleware.Stack) (err error) { 51 _, err = stack.Serialize.Remove(removeDefaultContentType{}.ID()) 52 if err != nil { 53 return fmt.Errorf("failed to remove %s serialize middleware, %w", 54 removeDefaultContentType{}.ID(), err) 55 56 } 57 return nil 58 } 59 60 // removeDefaultContentType provides after serialization middleware that will 61 // remove the content-type header from an HTTP request if the header was set as 62 // a default value by the operation serializer, and there is no request payload. 63 type removeDefaultContentType struct{} 64 65 // ID returns the middleware ID 66 func (removeDefaultContentType) ID() string { return "RemoveDefaultContentType" } 67 68 // HandleSerialize implements the serialization middleware. 69 func (removeDefaultContentType) HandleSerialize( 70 ctx context.Context, input middleware.SerializeInput, next middleware.SerializeHandler, 71 ) ( 72 out middleware.SerializeOutput, meta middleware.Metadata, err error, 73 ) { 74 req, ok := input.Request.(*Request) 75 if !ok { 76 return out, meta, fmt.Errorf( 77 "unexpected request type %T for removeDefaultContentType middleware", 78 input.Request) 79 } 80 81 if GetIsContentTypeDefaultValue(ctx) && req.GetStream() == nil { 82 req.Header.Del("Content-Type") 83 input.Request = req 84 } 85 86 return next.HandleSerialize(ctx, input) 87 } 88 89 type headerValue struct { 90 header string 91 value string 92 append bool 93 } 94 95 type headerValueHelper struct { 96 headerValues []headerValue 97 } 98 99 func (h *headerValueHelper) addHeaderValue(value headerValue) { 100 h.headerValues = append(h.headerValues, value) 101 } 102 103 func (h *headerValueHelper) ID() string { 104 return "HTTPHeaderHelper" 105 } 106 107 func (h *headerValueHelper) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (out middleware.BuildOutput, metadata middleware.Metadata, err error) { 108 req, ok := in.Request.(*Request) 109 if !ok { 110 return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) 111 } 112 113 for _, value := range h.headerValues { 114 if value.append { 115 req.Header.Add(value.header, value.value) 116 } else { 117 req.Header.Set(value.header, value.value) 118 } 119 } 120 121 return next.HandleBuild(ctx, in) 122 } 123 124 func getOrAddHeaderValueHelper(stack *middleware.Stack) (*headerValueHelper, error) { 125 id := (*headerValueHelper)(nil).ID() 126 m, ok := stack.Build.Get(id) 127 if !ok { 128 m = &headerValueHelper{} 129 err := stack.Build.Add(m, middleware.After) 130 if err != nil { 131 return nil, err 132 } 133 } 134 135 requestUserAgent, ok := m.(*headerValueHelper) 136 if !ok { 137 return nil, fmt.Errorf("%T for %s middleware did not match expected type", m, id) 138 } 139 140 return requestUserAgent, nil 141 } 142 143 // AddHeaderValue returns a stack mutator that adds the header value pair to header. 144 // Appends to any existing values if present. 145 func AddHeaderValue(header string, value string) func(stack *middleware.Stack) error { 146 return func(stack *middleware.Stack) error { 147 helper, err := getOrAddHeaderValueHelper(stack) 148 if err != nil { 149 return err 150 } 151 helper.addHeaderValue(headerValue{header: header, value: value, append: true}) 152 return nil 153 } 154 } 155 156 // SetHeaderValue returns a stack mutator that adds the header value pair to header. 157 // Replaces any existing values if present. 158 func SetHeaderValue(header string, value string) func(stack *middleware.Stack) error { 159 return func(stack *middleware.Stack) error { 160 helper, err := getOrAddHeaderValueHelper(stack) 161 if err != nil { 162 return err 163 } 164 helper.addHeaderValue(headerValue{header: header, value: value, append: false}) 165 return nil 166 } 167 }