summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest')
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/build.go215
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/payload.go43
-rw-r--r--Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/unmarshal.go174
3 files changed, 432 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/build.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/build.go
new file mode 100644
index 000000000..3ff667d94
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/build.go
@@ -0,0 +1,215 @@
+package rest
+
+import (
+ "bytes"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "net/url"
+ "path"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/awslabs/aws-sdk-go/aws"
+)
+
+// RFC822 returns an RFC822 formatted timestamp for AWS protocols
+const RFC822 = "Mon, 2 Jan 2006 15:04:05 GMT"
+
+func Build(r *aws.Request) {
+ if r.ParamsFilled() {
+ v := reflect.ValueOf(r.Params).Elem()
+ buildLocationElements(r, v)
+ buildBody(r, v)
+ }
+}
+
+func buildLocationElements(r *aws.Request, v reflect.Value) {
+ query := r.HTTPRequest.URL.Query()
+
+ for i := 0; i < v.NumField(); i++ {
+ m := v.Field(i)
+ if n := v.Type().Field(i).Name; n[0:1] == strings.ToLower(n[0:1]) {
+ continue
+ }
+
+ if m.IsValid() {
+ field := v.Type().Field(i)
+ name := field.Tag.Get("locationName")
+ if name == "" {
+ name = field.Name
+ }
+ if m.Kind() == reflect.Ptr {
+ m = m.Elem()
+ }
+ if !m.IsValid() {
+ continue
+ }
+
+ switch field.Tag.Get("location") {
+ case "headers": // header maps
+ buildHeaderMap(r, m, field.Tag.Get("locationName"))
+ case "header":
+ buildHeader(r, m, name)
+ case "uri":
+ buildURI(r, m, name)
+ case "querystring":
+ buildQueryString(r, m, name, query)
+ }
+ }
+ if r.Error != nil {
+ return
+ }
+ }
+
+ r.HTTPRequest.URL.RawQuery = query.Encode()
+ updatePath(r.HTTPRequest.URL, r.HTTPRequest.URL.Path)
+}
+
+func buildBody(r *aws.Request, v reflect.Value) {
+ if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
+ if payloadName := field.Tag.Get("payload"); payloadName != "" {
+ pfield, _ := v.Type().FieldByName(payloadName)
+ if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" {
+ payload := reflect.Indirect(v.FieldByName(payloadName))
+ if payload.IsValid() && payload.Interface() != nil {
+ switch reader := payload.Interface().(type) {
+ case io.ReadSeeker:
+ r.SetReaderBody(reader)
+ case []byte:
+ r.SetBufferBody(reader)
+ case string:
+ r.SetBufferBody([]byte(reader))
+ default:
+ r.Error = fmt.Errorf("unknown payload type %s", payload.Type())
+ }
+ }
+ }
+ }
+ }
+}
+
+func buildHeader(r *aws.Request, v reflect.Value, name string) {
+ str, err := convertType(v)
+ if err != nil {
+ r.Error = err
+ } else if str != nil {
+ r.HTTPRequest.Header.Add(name, *str)
+ }
+}
+
+func buildHeaderMap(r *aws.Request, v reflect.Value, prefix string) {
+ for _, key := range v.MapKeys() {
+ str, err := convertType(v.MapIndex(key))
+
+ if err != nil {
+ r.Error = err
+ } else if str != nil {
+ r.HTTPRequest.Header.Add(prefix+key.String(), *str)
+ }
+ }
+}
+
+func buildURI(r *aws.Request, v reflect.Value, name string) {
+ value, err := convertType(v)
+ if err != nil {
+ r.Error = err
+ } else if value != nil {
+ uri := r.HTTPRequest.URL.Path
+ uri = strings.Replace(uri, "{"+name+"}", escapePath(*value, true), -1)
+ uri = strings.Replace(uri, "{"+name+"+}", escapePath(*value, false), -1)
+ r.HTTPRequest.URL.Path = uri
+ }
+}
+
+func buildQueryString(r *aws.Request, v reflect.Value, name string, query url.Values) {
+ str, err := convertType(v)
+ if err != nil {
+ r.Error = err
+ } else if str != nil {
+ query.Set(name, *str)
+ }
+}
+
+func updatePath(url *url.URL, urlPath string) {
+ scheme, query := url.Scheme, url.RawQuery
+
+ // clean up path
+ urlPath = path.Clean(urlPath)
+
+ // get formatted URL minus scheme so we can build this into Opaque
+ url.Scheme, url.Path, url.RawQuery = "", "", ""
+ s := url.String()
+ url.Scheme = scheme
+ url.RawQuery = query
+
+ // build opaque URI
+ url.Opaque = s + urlPath
+}
+
+// Whether the byte value can be sent without escaping in AWS URLs
+var noEscape [256]bool
+var noEscapeInitialized = false
+
+// initialise noEscape
+func initNoEscape() {
+ for i := range noEscape {
+ // Amazon expects every character except these escaped
+ noEscape[i] = (i >= 'A' && i <= 'Z') ||
+ (i >= 'a' && i <= 'z') ||
+ (i >= '0' && i <= '9') ||
+ i == '-' ||
+ i == '.' ||
+ i == '_' ||
+ i == '~'
+ }
+}
+
+// escapePath escapes part of a URL path in Amazon style
+func escapePath(path string, encodeSep bool) string {
+ if !noEscapeInitialized {
+ initNoEscape()
+ noEscapeInitialized = true
+ }
+
+ var buf bytes.Buffer
+ for i := 0; i < len(path); i++ {
+ c := path[i]
+ if noEscape[c] || (c == '/' && !encodeSep) {
+ buf.WriteByte(c)
+ } else {
+ buf.WriteByte('%')
+ buf.WriteString(strings.ToUpper(strconv.FormatUint(uint64(c), 16)))
+ }
+ }
+ return buf.String()
+}
+
+func convertType(v reflect.Value) (*string, error) {
+ v = reflect.Indirect(v)
+ if !v.IsValid() {
+ return nil, nil
+ }
+
+ var str string
+ switch value := v.Interface().(type) {
+ case string:
+ str = value
+ case []byte:
+ str = base64.StdEncoding.EncodeToString(value)
+ case bool:
+ str = strconv.FormatBool(value)
+ case int64:
+ str = strconv.FormatInt(value, 10)
+ case float64:
+ str = strconv.FormatFloat(value, 'f', -1, 64)
+ case time.Time:
+ str = value.UTC().Format(RFC822)
+ default:
+ err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
+ return nil, err
+ }
+ return &str, nil
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/payload.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/payload.go
new file mode 100644
index 000000000..1e15f66f7
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/payload.go
@@ -0,0 +1,43 @@
+package rest
+
+import "reflect"
+
+func PayloadMember(i interface{}) interface{} {
+ if i == nil {
+ return nil
+ }
+
+ v := reflect.ValueOf(i).Elem()
+ if !v.IsValid() {
+ return nil
+ }
+ if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
+ if payloadName := field.Tag.Get("payload"); payloadName != "" {
+ field, _ := v.Type().FieldByName(payloadName)
+ if field.Tag.Get("type") != "structure" {
+ return nil
+ }
+
+ payload := v.FieldByName(payloadName)
+ if payload.IsValid() || (payload.Kind() == reflect.Ptr && !payload.IsNil()) {
+ return payload.Interface()
+ }
+ }
+ }
+ return nil
+}
+
+func PayloadType(i interface{}) string {
+ v := reflect.Indirect(reflect.ValueOf(i))
+ if !v.IsValid() {
+ return ""
+ }
+ if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
+ if payloadName := field.Tag.Get("payload"); payloadName != "" {
+ if member, ok := v.Type().FieldByName(payloadName); ok {
+ return member.Tag.Get("type")
+ }
+ }
+ }
+ return ""
+}
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/unmarshal.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/unmarshal.go
new file mode 100644
index 000000000..d0e216c1e
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/internal/protocol/rest/unmarshal.go
@@ -0,0 +1,174 @@
+package rest
+
+import (
+ "encoding/base64"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/awslabs/aws-sdk-go/aws"
+)
+
+func Unmarshal(r *aws.Request) {
+ if r.DataFilled() {
+ v := reflect.Indirect(reflect.ValueOf(r.Data))
+ unmarshalBody(r, v)
+ unmarshalLocationElements(r, v)
+ }
+}
+
+func unmarshalBody(r *aws.Request, v reflect.Value) {
+ if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
+ if payloadName := field.Tag.Get("payload"); payloadName != "" {
+ pfield, _ := v.Type().FieldByName(payloadName)
+ if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" {
+ payload := reflect.Indirect(v.FieldByName(payloadName))
+ if payload.IsValid() {
+ switch payload.Interface().(type) {
+ case []byte:
+ b, err := ioutil.ReadAll(r.HTTPResponse.Body)
+ if err != nil {
+ r.Error = err
+ } else {
+ payload.Set(reflect.ValueOf(b))
+ }
+ case string:
+ b, err := ioutil.ReadAll(r.HTTPResponse.Body)
+ if err != nil {
+ r.Error = err
+ } else {
+ payload.Set(reflect.ValueOf(string(b)))
+ }
+ default:
+ switch payload.Type().String() {
+ case "io.ReadSeeker":
+ payload.Set(reflect.ValueOf(aws.ReadSeekCloser(r.HTTPResponse.Body)))
+ case "aws.ReadSeekCloser", "io.ReadCloser":
+ payload.Set(reflect.ValueOf(r.HTTPResponse.Body))
+ default:
+ r.Error = fmt.Errorf("unknown payload type %s", payload.Type())
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+func unmarshalLocationElements(r *aws.Request, v reflect.Value) {
+ for i := 0; i < v.NumField(); i++ {
+ m, field := v.Field(i), v.Type().Field(i)
+ if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) {
+ continue
+ }
+
+ if m.IsValid() {
+ name := field.Tag.Get("locationName")
+ if name == "" {
+ name = field.Name
+ }
+
+ switch field.Tag.Get("location") {
+ case "statusCode":
+ unmarshalStatusCode(m, r.HTTPResponse.StatusCode)
+ case "header":
+ err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name))
+ if err != nil {
+ r.Error = err
+ break
+ }
+ case "headers":
+ prefix := field.Tag.Get("locationName")
+ err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix)
+ if err != nil {
+ r.Error = err
+ break
+ }
+ }
+ }
+ if r.Error != nil {
+ return
+ }
+ }
+}
+
+func unmarshalStatusCode(v reflect.Value, statusCode int) {
+ if !v.IsValid() {
+ return
+ }
+
+ switch v.Interface().(type) {
+ case *int64:
+ s := int64(statusCode)
+ v.Set(reflect.ValueOf(&s))
+ }
+}
+
+func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) error {
+ switch r.Interface().(type) {
+ case *map[string]*string: // we only support string map value types
+ out := map[string]*string{}
+ for k, v := range headers {
+ k = http.CanonicalHeaderKey(k)
+ if strings.HasPrefix(strings.ToLower(k), strings.ToLower(prefix)) {
+ out[k[len(prefix):]] = &v[0]
+ }
+ }
+ r.Set(reflect.ValueOf(&out))
+ }
+ return nil
+}
+
+func unmarshalHeader(v reflect.Value, header string) error {
+ if !v.IsValid() || (header == "" && v.Elem().Kind() != reflect.String) {
+ return nil
+ }
+
+ switch v.Interface().(type) {
+ case *string:
+ v.Set(reflect.ValueOf(&header))
+ case []byte:
+ b, err := base64.StdEncoding.DecodeString(header)
+ if err != nil {
+ return err
+ } else {
+ v.Set(reflect.ValueOf(&b))
+ }
+ case *bool:
+ b, err := strconv.ParseBool(header)
+ if err != nil {
+ return err
+ } else {
+ v.Set(reflect.ValueOf(&b))
+ }
+ case *int64:
+ i, err := strconv.ParseInt(header, 10, 64)
+ if err != nil {
+ return err
+ } else {
+ v.Set(reflect.ValueOf(&i))
+ }
+ case *float64:
+ f, err := strconv.ParseFloat(header, 64)
+ if err != nil {
+ return err
+ } else {
+ v.Set(reflect.ValueOf(&f))
+ }
+ case *time.Time:
+ t, err := time.Parse(RFC822, header)
+ if err != nil {
+ return err
+ } else {
+ v.Set(reflect.ValueOf(&t))
+ }
+ default:
+ err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
+ return err
+ }
+ return nil
+}