middleware_header_comment.go (2306B)
1 package http 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 8 "github.com/aws/smithy-go/middleware" 9 ) 10 11 // WithHeaderComment instruments a middleware stack to append an HTTP field 12 // comment to the given header as specified in RFC 9110 13 // (https://www.rfc-editor.org/rfc/rfc9110#name-comments). 14 // 15 // The header is case-insensitive. If the provided header exists when the 16 // middleware runs, the content will be inserted as-is enclosed in parentheses. 17 // 18 // Note that per the HTTP specification, comments are only allowed in fields 19 // containing "comment" as part of their field value definition, but this API 20 // will NOT verify whether the provided header is one of them. 21 // 22 // WithHeaderComment MAY be applied more than once to a middleware stack and/or 23 // more than once per header. 24 func WithHeaderComment(header, content string) func(*middleware.Stack) error { 25 return func(s *middleware.Stack) error { 26 m, err := getOrAddHeaderComment(s) 27 if err != nil { 28 return fmt.Errorf("get or add header comment: %v", err) 29 } 30 31 m.values.Add(header, content) 32 return nil 33 } 34 } 35 36 type headerCommentMiddleware struct { 37 values http.Header // hijack case-insensitive access APIs 38 } 39 40 func (*headerCommentMiddleware) ID() string { 41 return "headerComment" 42 } 43 44 func (m *headerCommentMiddleware) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) ( 45 out middleware.BuildOutput, metadata middleware.Metadata, err error, 46 ) { 47 r, ok := in.Request.(*Request) 48 if !ok { 49 return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) 50 } 51 52 for h, contents := range m.values { 53 for _, c := range contents { 54 if existing := r.Header.Get(h); existing != "" { 55 r.Header.Set(h, fmt.Sprintf("%s (%s)", existing, c)) 56 } 57 } 58 } 59 60 return next.HandleBuild(ctx, in) 61 } 62 63 func getOrAddHeaderComment(s *middleware.Stack) (*headerCommentMiddleware, error) { 64 id := (*headerCommentMiddleware)(nil).ID() 65 m, ok := s.Build.Get(id) 66 if !ok { 67 m := &headerCommentMiddleware{values: http.Header{}} 68 if err := s.Build.Add(m, middleware.After); err != nil { 69 return nil, fmt.Errorf("add build: %v", err) 70 } 71 72 return m, nil 73 } 74 75 hc, ok := m.(*headerCommentMiddleware) 76 if !ok { 77 return nil, fmt.Errorf("existing middleware w/ id %s is not *headerCommentMiddleware", id) 78 } 79 80 return hc, nil 81 }