14287: Avoid converting integer params to float and back.
authorTom Clegg <tclegg@veritasgenetics.com>
Thu, 9 May 2019 19:29:47 +0000 (15:29 -0400)
committerTom Clegg <tclegg@veritasgenetics.com>
Mon, 17 Jun 2019 13:54:39 +0000 (09:54 -0400)
Turns out int64(float64(MaxInt64)) was MinInt64, which is quite
different.

Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg@veritasgenetics.com>

sdk/go/arvados/client.go

index 8625e7adef79c82cd2c3afba48be9e0f17437dd2..e55cb82f2a353f95c1f57bfe168de48a852f619f 100644 (file)
@@ -13,7 +13,6 @@ import (
        "io"
        "io/ioutil"
        "log"
-       "math"
        "net/http"
        "net/url"
        "os"
@@ -188,7 +187,9 @@ func anythingToValues(params interface{}) (url.Values, error) {
                return nil, err
        }
        var generic map[string]interface{}
-       err = json.Unmarshal(j, &generic)
+       dec := json.NewDecoder(bytes.NewBuffer(j))
+       dec.UseNumber()
+       err = dec.Decode(&generic)
        if err != nil {
                return nil, err
        }
@@ -198,22 +199,16 @@ func anythingToValues(params interface{}) (url.Values, error) {
                        urlValues.Set(k, v)
                        continue
                }
-               if v, ok := v.(float64); ok {
-                       // Unmarshal decodes all numbers as float64,
-                       // which can be written as 1.2345e4 in JSON,
-                       // but this form is not accepted for ints in
-                       // url params. If a number fits in an int64,
-                       // encode it as int64 rather than float64.
-                       if v, frac := math.Modf(v); frac == 0 && v <= math.MaxInt64 && v >= math.MinInt64 {
-                               urlValues.Set(k, fmt.Sprintf("%d", int64(v)))
-                               continue
-                       }
+               if v, ok := v.(json.Number); ok {
+                       urlValues.Set(k, v.String())
+                       continue
                }
                j, err := json.Marshal(v)
                if err != nil {
                        return nil, err
                }
-               if string(j) == "null" {
+               if bytes.Equal(j, []byte("null")) {
+                       // don't add it to urlValues at all
                        continue
                }
                urlValues.Set(k, string(j))