package rest import ( "fmt" "io" "net/http" "net/url" "github.com/aws/aws-sdk-go-v2/private/protocol" ) // An Encoder provides encoding of REST URI path, query, and header components // of an HTTP request. Can also encode a stream as the payload. // // Does not support SetFields. type Encoder struct { req *http.Request path protocol.PathReplace query url.Values header http.Header payload io.ReadSeeker err error } // NewEncoder creates a new encoder from the passed in request. All query and // header values will be added on top of the request's existing values. Overwriting // duplicate values. func NewEncoder(req *http.Request) *Encoder { e := &Encoder{ req: req, path: protocol.NewPathReplace(req.URL.Path), query: req.URL.Query(), header: req.Header, } return e } // Encode will return the request and body if one was set. If the body // payload was not set the io.ReadSeeker will be nil. // // returns any error if one occured while encoding the API's parameters. func (e *Encoder) Encode() (*http.Request, io.ReadSeeker, error) { if e.err != nil { return nil, nil, e.err } e.req.URL.Path, e.req.URL.RawPath = e.path.Encode() e.req.URL.RawQuery = e.query.Encode() e.req.Header = e.header return e.req, e.payload, nil } // SetValue will set a value to the header, path, query. // // If the request's method is GET all BodyTarget values will be written to // the query string. func (e *Encoder) SetValue(t protocol.Target, k string, v protocol.ValueMarshaler, meta protocol.Metadata) { if e.err != nil { return } var str string str, e.err = v.MarshalValue() if e.err != nil { return } switch t { case protocol.HeaderTarget: e.header.Set(k, str) case protocol.PathTarget: e.path.ReplaceElement(k, str) case protocol.QueryTarget: e.query.Set(k, str) case protocol.BodyTarget: if e.req.Method != "GET" { e.err = fmt.Errorf("body target not supported for rest non-GET methods %s, %s", t, k) return } e.query.Set(k, str) default: e.err = fmt.Errorf("unknown SetValue rest encode target, %s, %s", t, k) } } // SetStream will set the stream to the payload of the request. func (e *Encoder) SetStream(t protocol.Target, k string, v protocol.StreamMarshaler, meta protocol.Metadata) { if e.err != nil { return } switch t { case protocol.PayloadTarget: e.payload, e.err = v.MarshalStream() default: e.err = fmt.Errorf("unknown SetStream rest encode target, %s, %s", t, k) } } // List will set the nested list values to the header or query. func (e *Encoder) List(t protocol.Target, k string, meta protocol.Metadata) protocol.ListEncoder { if e.err != nil { return nil } switch t { case protocol.QueryTarget: return &protocol.QueryListEncoder{Key: k, Query: e.query} case protocol.HeaderTarget: return &protocol.HeaderListEncoder{Key: k, Header: e.header} default: e.err = fmt.Errorf("unknown SetList rest encode target, %s, %s", t, k) return nil } } // Map will set the nested map values to the header or query. func (e *Encoder) Map(t protocol.Target, k string, meta protocol.Metadata) protocol.MapEncoder { if e.err != nil { return nil } switch t { case protocol.QueryTarget: return &protocol.QueryMapEncoder{Query: e.query} case protocol.HeadersTarget: return &protocol.HeaderMapEncoder{Prefix: k, Header: e.header} default: e.err = fmt.Errorf("unknown SetMap rest encode target, %s, %s", t, k) return nil } } // SetFields is not supported for REST encoder. func (e *Encoder) SetFields(t protocol.Target, k string, m protocol.FieldMarshaler, meta protocol.Metadata) { e.err = fmt.Errorf("rest encoder SetFields not supported, %s, %s", t, k) }