-
Notifications
You must be signed in to change notification settings - Fork 652
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
874 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package rest | ||
|
||
import ( | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
) | ||
|
||
// 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, rawPath, pathBuffer []byte | ||
|
||
query url.Values | ||
header http.Header | ||
} | ||
|
||
// 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: []byte(req.URL.Path), | ||
rawPath: []byte(req.URL.RawPath), | ||
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 { | ||
e.req.URL.Path, e.req.URL.RawPath = string(e.path), string(e.rawPath) | ||
e.req.URL.RawQuery = e.query.Encode() | ||
e.req.Header = e.header | ||
|
||
return e.req | ||
} | ||
|
||
func (e *Encoder) AddHeader(key string) HeaderValue { | ||
return newHeaderValue(e.header, key, true) | ||
} | ||
|
||
func (e *Encoder) SetHeader(key string) HeaderValue { | ||
return newHeaderValue(e.header, key, false) | ||
} | ||
|
||
func (e *Encoder) Headers(prefix string) Headers { | ||
return Headers{ | ||
header: e.header, | ||
prefix: strings.TrimSpace(prefix), | ||
} | ||
} | ||
|
||
func (e *Encoder) SetURI(key string) URIValue { | ||
return newURIValue(&e.path, &e.rawPath, &e.pathBuffer, key) | ||
} | ||
|
||
func (e *Encoder) SetQuery(key string) QueryValue { | ||
return newQueryValue(e.query, key, false) | ||
} | ||
|
||
func (e *Encoder) AddQuery(key string) QueryValue { | ||
return newQueryValue(e.query, key, true) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package rest | ||
|
||
import ( | ||
"net/http" | ||
"net/url" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestEncoder(t *testing.T) { | ||
actual := http.Request{ | ||
Header: http.Header{ | ||
"custom-user-header": {"someValue"}, | ||
}, | ||
URL: &url.URL{ | ||
Path: "/some/{pathKey}/path", | ||
RawQuery: "someExistingKeys=foobar", | ||
}, | ||
} | ||
|
||
expected := http.Request{ | ||
Header: map[string][]string{ | ||
"custom-user-header": {"someValue"}, | ||
"X-Amzn-Header-Foo": {"someValue"}, | ||
"X-Amzn-Meta-Foo": {"someValue"}, | ||
}, | ||
URL: &url.URL{ | ||
Path: "/some/someValue/path", | ||
RawPath: "/some/someValue/path", | ||
RawQuery: "someExistingKeys=foobar&someKey=someValue&someKey=otherValue", | ||
}, | ||
} | ||
|
||
encoder := NewEncoder(&actual) | ||
|
||
// Headers | ||
encoder.AddHeader("x-amzn-header-foo").String("someValue") | ||
encoder.Headers("x-amzn-meta-").AddHeader("foo").String("someValue") | ||
|
||
// Query | ||
encoder.SetQuery("someKey").String("someValue") | ||
encoder.AddQuery("someKey").String("otherValue") | ||
|
||
// URI | ||
if err := encoder.SetURI("pathKey").String("someValue"); err != nil { | ||
t.Errorf("expected no err, but got %v", err) | ||
} | ||
|
||
actual = *encoder.Encode() | ||
|
||
if !reflect.DeepEqual(expected, actual) { | ||
t.Errorf("expected %v, but got %v", expected, actual) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package rest | ||
|
||
import ( | ||
"encoding/base64" | ||
"net/http" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go-v2/aws" | ||
"github.com/aws/aws-sdk-go-v2/private/protocol" | ||
) | ||
|
||
type Headers struct { | ||
header http.Header | ||
prefix string | ||
} | ||
|
||
func (h Headers) AddHeader(key string) HeaderValue { | ||
return h.newHeaderValue(key, true) | ||
} | ||
|
||
func (h Headers) SetHeader(key string) HeaderValue { | ||
return h.newHeaderValue(key, false) | ||
} | ||
|
||
func (h Headers) newHeaderValue(key string, append bool) HeaderValue { | ||
return newHeaderValue(h.header, h.prefix+strings.TrimSpace(key), append) | ||
} | ||
|
||
type HeaderValue struct { | ||
header http.Header | ||
key string | ||
append bool | ||
} | ||
|
||
func newHeaderValue(header http.Header, key string, append bool) HeaderValue { | ||
return HeaderValue{header: header, key: strings.TrimSpace(key), append: append} | ||
} | ||
|
||
func (h HeaderValue) modifyHeader(value string) { | ||
if h.append { | ||
h.header.Add(h.key, value) | ||
} else { | ||
h.header.Set(h.key, value) | ||
} | ||
} | ||
|
||
func (h HeaderValue) String(v string) { | ||
h.modifyHeader(v) | ||
} | ||
|
||
func (h HeaderValue) Integer(v int64) { | ||
h.modifyHeader(strconv.FormatInt(v, 10)) | ||
} | ||
|
||
func (h HeaderValue) Boolean(v bool) { | ||
h.modifyHeader(strconv.FormatBool(v)) | ||
} | ||
|
||
func (h HeaderValue) Float(v float64) { | ||
h.modifyHeader(strconv.FormatFloat(v, 'f', -1, 64)) | ||
} | ||
|
||
func (h HeaderValue) Time(t time.Time, format string) (err error) { | ||
value, err := protocol.FormatTime(format, t) | ||
if err != nil { | ||
return err | ||
} | ||
h.modifyHeader(value) | ||
return nil | ||
} | ||
|
||
func (h HeaderValue) ByteSlice(v []byte) { | ||
encodeToString := base64.StdEncoding.EncodeToString(v) | ||
h.modifyHeader(encodeToString) | ||
} | ||
|
||
func (h HeaderValue) JSONValue(v aws.JSONValue) error { | ||
encodedValue, err := protocol.EncodeJSONValue(v, protocol.Base64Escape) | ||
if err != nil { | ||
return err | ||
} | ||
h.modifyHeader(encodedValue) | ||
return nil | ||
} |
Oops, something went wrong.