From c970c3642761536942d3544941c7100467cf31a7 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Fri, 19 Jan 2018 21:29:57 -0700 Subject: [PATCH] fix json float parsing --- parse/read_input.go | 10 +++------- types/convert/convert.go | 19 +++++++++++++++++-- types/convert/convert_test.go | 26 ++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 types/convert/convert_test.go diff --git a/parse/read_input.go b/parse/read_input.go index 03fb45455..386f365a1 100644 --- a/parse/read_input.go +++ b/parse/read_input.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "github.com/rancher/norman/httperror" @@ -22,14 +21,11 @@ func ReadBody(req *http.Request) (map[string]interface{}, error) { return nil, nil } - content, err := ioutil.ReadAll(io.LimitReader(req.Body, reqMaxSize)) - if err != nil { - return nil, httperror.NewAPIError(httperror.InvalidBodyContent, - fmt.Sprintf("Body content longer than %d bytes", reqMaxSize-1)) - } + dec := json.NewDecoder(io.LimitReader(req.Body, reqMaxSize)) + dec.UseNumber() data := map[string]interface{}{} - if err := json.Unmarshal(content, &data); err != nil { + if err := dec.Decode(&data); err != nil { return nil, httperror.NewAPIError(httperror.InvalidBodyContent, fmt.Sprintf("Failed to parse body: %v", err)) } diff --git a/types/convert/convert.go b/types/convert/convert.go index 2fb14d3ba..8801e81f3 100644 --- a/types/convert/convert.go +++ b/types/convert/convert.go @@ -1,6 +1,7 @@ package convert import ( + "bytes" "encoding/json" "errors" "fmt" @@ -85,6 +86,18 @@ func ToNumber(value interface{}) (int64, error) { if ok { return i, nil } + f, ok := value.(float64) + if ok { + return int64(f), nil + } + if n, ok := value.(json.Number); ok { + i, err := n.Int64() + if err == nil { + return i, nil + } + f, err := n.Float64() + return int64(f), err + } return strconv.ParseInt(ToString(value), 10, 64) } @@ -185,10 +198,12 @@ func ToObj(data interface{}, into interface{}) error { } func EncodeToMap(obj interface{}) (map[string]interface{}, error) { - bytes, err := json.Marshal(obj) + b, err := json.Marshal(obj) if err != nil { return nil, err } result := map[string]interface{}{} - return result, json.Unmarshal(bytes, &result) + dec := json.NewDecoder(bytes.NewBuffer(b)) + dec.UseNumber() + return result, dec.Decode(&result) } diff --git a/types/convert/convert_test.go b/types/convert/convert_test.go new file mode 100644 index 000000000..c0ef60949 --- /dev/null +++ b/types/convert/convert_test.go @@ -0,0 +1,26 @@ +package convert + +import ( + "testing" +) + +type data struct { + TTLMillis int `json:"ttl"` +} + +func TestJSON(t *testing.T) { + d := &data{ + TTLMillis: 57600000, + } + + m, err := EncodeToMap(d) + if err != nil { + t.Fatal(err) + } + + i, _ := ToNumber(m["ttl"]) + if i != 57600000 { + t.Fatal("not", 57600000, "got", m["ttl"]) + } + +}