src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

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 }