-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
private/protocol/restjson: Define JSONValue marshaling for body and querystring #1640
Changes from all commits
eb6a101
87a591f
a538a36
9bfcb32
809795b
f7e3b7b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -614,16 +614,30 @@ | |
"OutputShape": { | ||
"type": "structure", | ||
"members": { | ||
"Attr": { | ||
"HeaderField": { | ||
"shape": "StringType", | ||
"jsonvalue": true, | ||
"location": "header", | ||
"locationName": "X-Amz-Foo" | ||
"jsonvalue": true, | ||
"location": "header", | ||
"locationName": "X-Amz-Foo" | ||
}, | ||
"BodyField":{ | ||
"shape": "StringType", | ||
"jsonvalue": true | ||
}, | ||
"BodyListField": { | ||
"shape": "ListType" | ||
} | ||
} | ||
}, | ||
"StringType": { | ||
"type": "string" | ||
}, | ||
"ListType": { | ||
"type": "list", | ||
"member": { | ||
"shape": "StringType", | ||
"jsonvalue": true | ||
} | ||
} | ||
}, | ||
"cases": [ | ||
|
@@ -635,11 +649,43 @@ | |
"name": "OperationName" | ||
}, | ||
"result": { | ||
"Attr": {"Foo":"Bar"} | ||
"HeaderField": {"Foo":"Bar"}, | ||
"BodyField": {"Foo":"Bar"} | ||
}, | ||
"response": { | ||
"status_code": 200, | ||
"headers": {"X-Amz-Foo": "eyJGb28iOiJCYXIifQ=="}, | ||
"body": "{\"BodyField\":\"{\\\"Foo\\\":\\\"Bar\\\"}\"}" | ||
} | ||
}, | ||
{ | ||
"given": { | ||
"output": { | ||
"shape": "OutputShape" | ||
}, | ||
"name": "OperationName" | ||
}, | ||
"result": { | ||
"BodyListField": [{"Foo":"Bar"}] | ||
}, | ||
"response": { | ||
"status_code": 200, | ||
"headers": {}, | ||
"body": "{\"BodyListField\":[\"{\\\"Foo\\\":\\\"Bar\\\"}\"]}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here |
||
} | ||
}, | ||
{ | ||
"given": { | ||
"output": { | ||
"shape": "OutputShape" | ||
}, | ||
"name": "OperationName" | ||
}, | ||
"result": { | ||
}, | ||
"response": { | ||
"status_code": 200, | ||
"headers": {}, | ||
"body": "" | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ import ( | |
"strconv" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/private/protocol" | ||
) | ||
|
||
|
@@ -49,7 +50,10 @@ func buildAny(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) err | |
t = "list" | ||
} | ||
case reflect.Map: | ||
t = "map" | ||
// cannot be a JSONValue map | ||
if _, ok := value.Interface().(aws.JSONValue); !ok { | ||
t = "map" | ||
} | ||
} | ||
} | ||
|
||
|
@@ -210,14 +214,11 @@ func buildScalar(v reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) erro | |
} | ||
buf.Write(strconv.AppendFloat(scratch[:0], f, 'f', -1, 64)) | ||
default: | ||
switch value.Type() { | ||
case timeType: | ||
converted := v.Interface().(*time.Time) | ||
|
||
switch converted := value.Interface().(type) { | ||
case time.Time: | ||
buf.Write(strconv.AppendInt(scratch[:0], converted.UTC().Unix(), 10)) | ||
case byteSliceType: | ||
case []byte: | ||
if !value.IsNil() { | ||
converted := value.Interface().([]byte) | ||
buf.WriteByte('"') | ||
if len(converted) < 1024 { | ||
// for small buffers, using Encode directly is much faster. | ||
|
@@ -233,6 +234,12 @@ func buildScalar(v reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) erro | |
} | ||
buf.WriteByte('"') | ||
} | ||
case aws.JSONValue: | ||
str, err := protocol.EncodeJSONValue(converted, protocol.QuotedEscape) | ||
if err != nil { | ||
return fmt.Errorf("unable to encode JSONValue, %v", err) | ||
} | ||
buf.WriteString(str) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just realized we squash all these error. Is that something we want to do? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. definitely want to return errors from these functions. If the protocol marshaler is squashing them then those marshalers should be updated not to squash the errors. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah you mean errors on write, sorry missed that. Those should be captured... I don't think the SDK does that for any writes currently like this since the type is a bytes.buffer. |
||
default: | ||
return fmt.Errorf("unsupported JSON value %v (%s)", value.Interface(), value.Type()) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package protocol | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might want to add tests for these new functions. |
||
|
||
import ( | ||
"encoding/base64" | ||
"encoding/json" | ||
"fmt" | ||
"strconv" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
) | ||
|
||
// EscapeMode is the mode that should be use for escaping a value | ||
type EscapeMode uint | ||
|
||
// The modes for escaping a value before it is marshaled, and unmarshaled. | ||
const ( | ||
NoEscape EscapeMode = iota | ||
Base64Escape | ||
QuotedEscape | ||
) | ||
|
||
// EncodeJSONValue marshals the value into a JSON string, and optionally base64 | ||
// encodes the string before returning it. | ||
// | ||
// Will panic if the escape mode is unknown. | ||
func EncodeJSONValue(v aws.JSONValue, escape EscapeMode) (string, error) { | ||
b, err := json.Marshal(v) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
switch escape { | ||
case NoEscape: | ||
return string(b), nil | ||
case Base64Escape: | ||
return base64.StdEncoding.EncodeToString(b), nil | ||
case QuotedEscape: | ||
return strconv.Quote(string(b)), nil | ||
} | ||
|
||
panic(fmt.Sprintf("EncodeJSONValue called with unknown EscapeMode, %v", escape)) | ||
} | ||
|
||
// DecodeJSONValue will attempt to decode the string input as a JSONValue. | ||
// Optionally decoding base64 the value first before JSON unmarshaling. | ||
// | ||
// Will panic if the escape mode is unknown. | ||
func DecodeJSONValue(v string, escape EscapeMode) (aws.JSONValue, error) { | ||
var b []byte | ||
var err error | ||
|
||
switch escape { | ||
case NoEscape: | ||
b = []byte(v) | ||
case Base64Escape: | ||
b, err = base64.StdEncoding.DecodeString(v) | ||
case QuotedEscape: | ||
var u string | ||
u, err = strconv.Unquote(v) | ||
b = []byte(u) | ||
default: | ||
panic(fmt.Sprintf("DecodeJSONValue called with unknown EscapeMode, %v", escape)) | ||
} | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
m := aws.JSONValue{} | ||
err = json.Unmarshal(b, &m) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return m, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is testing for empty output, may want to have nothing in the params.