...

Source file src/github.com/aws/smithy-go/encoding/httpbinding/encode.go

Documentation: github.com/aws/smithy-go/encoding/httpbinding

     1  package httpbinding
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"net/url"
     7  	"strconv"
     8  	"strings"
     9  )
    10  
    11  const (
    12  	contentLengthHeader = "Content-Length"
    13  	floatNaN            = "NaN"
    14  	floatInfinity       = "Infinity"
    15  	floatNegInfinity    = "-Infinity"
    16  )
    17  
    18  // An Encoder provides encoding of REST URI path, query, and header components
    19  // of an HTTP request. Can also encode a stream as the payload.
    20  //
    21  // Does not support SetFields.
    22  type Encoder struct {
    23  	path, rawPath, pathBuffer []byte
    24  
    25  	query  url.Values
    26  	header http.Header
    27  }
    28  
    29  // NewEncoder creates a new encoder from the passed in request. It assumes that
    30  // raw path contains no valuable information at this point, so it passes in path
    31  // as path and raw path for subsequent trans
    32  func NewEncoder(path, query string, headers http.Header) (*Encoder, error) {
    33  	return NewEncoderWithRawPath(path, path, query, headers)
    34  }
    35  
    36  // NewHTTPBindingEncoder creates a new encoder from the passed in request. All query and
    37  // header values will be added on top of the request's existing values. Overwriting
    38  // duplicate values.
    39  func NewEncoderWithRawPath(path, rawPath, query string, headers http.Header) (*Encoder, error) {
    40  	parseQuery, err := url.ParseQuery(query)
    41  	if err != nil {
    42  		return nil, fmt.Errorf("failed to parse query string: %w", err)
    43  	}
    44  
    45  	e := &Encoder{
    46  		path:    []byte(path),
    47  		rawPath: []byte(rawPath),
    48  		query:   parseQuery,
    49  		header:  headers.Clone(),
    50  	}
    51  
    52  	return e, nil
    53  }
    54  
    55  // Encode returns a REST protocol encoder for encoding HTTP bindings.
    56  //
    57  // Due net/http requiring `Content-Length` to be specified on the http.Request#ContentLength directly. Encode
    58  // will look for whether the header is present, and if so will remove it and set the respective value on http.Request.
    59  //
    60  // Returns any error occurring during encoding.
    61  func (e *Encoder) Encode(req *http.Request) (*http.Request, error) {
    62  	req.URL.Path, req.URL.RawPath = string(e.path), string(e.rawPath)
    63  	req.URL.RawQuery = e.query.Encode()
    64  
    65  	// net/http ignores Content-Length header and requires it to be set on http.Request
    66  	if v := e.header.Get(contentLengthHeader); len(v) > 0 {
    67  		iv, err := strconv.ParseInt(v, 10, 64)
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  		req.ContentLength = iv
    72  		e.header.Del(contentLengthHeader)
    73  	}
    74  
    75  	req.Header = e.header
    76  
    77  	return req, nil
    78  }
    79  
    80  // AddHeader returns a HeaderValue for appending to the given header name
    81  func (e *Encoder) AddHeader(key string) HeaderValue {
    82  	return newHeaderValue(e.header, key, true)
    83  }
    84  
    85  // SetHeader returns a HeaderValue for setting the given header name
    86  func (e *Encoder) SetHeader(key string) HeaderValue {
    87  	return newHeaderValue(e.header, key, false)
    88  }
    89  
    90  // Headers returns a Header used for encoding headers with the given prefix
    91  func (e *Encoder) Headers(prefix string) Headers {
    92  	return Headers{
    93  		header: e.header,
    94  		prefix: strings.TrimSpace(prefix),
    95  	}
    96  }
    97  
    98  // HasHeader returns if a header with the key specified exists with one or
    99  // more value.
   100  func (e Encoder) HasHeader(key string) bool {
   101  	return len(e.header[key]) != 0
   102  }
   103  
   104  // SetURI returns a URIValue used for setting the given path key
   105  func (e *Encoder) SetURI(key string) URIValue {
   106  	return newURIValue(&e.path, &e.rawPath, &e.pathBuffer, key)
   107  }
   108  
   109  // SetQuery returns a QueryValue used for setting the given query key
   110  func (e *Encoder) SetQuery(key string) QueryValue {
   111  	return NewQueryValue(e.query, key, false)
   112  }
   113  
   114  // AddQuery returns a QueryValue used for appending the given query key
   115  func (e *Encoder) AddQuery(key string) QueryValue {
   116  	return NewQueryValue(e.query, key, true)
   117  }
   118  
   119  // HasQuery returns if a query with the key specified exists with one or
   120  // more values.
   121  func (e *Encoder) HasQuery(key string) bool {
   122  	return len(e.query.Get(key)) != 0
   123  }
   124  

View as plain text