Skip to content

Commit

Permalink
client: Switch to case sensitive unmarshalling to be compatible with …
Browse files Browse the repository at this point in the history
…ugorji

Using lessons learned from k8s changes:
kubernetes/kubernetes#65034

Change-Id: Ia17a8f94ae6ed00c5af2595c2b48d3c9a0344427
  • Loading branch information
dims authored and MartinWeindel committed Jun 12, 2019
1 parent ca6bc59 commit 96a254f
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 5 deletions.
72 changes: 72 additions & 0 deletions client/json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2019 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package client

import (
"github.com/json-iterator/go"
"github.com/modern-go/reflect2"
"strconv"
"unsafe"
)

type customNumberExtension struct {
jsoniter.DummyExtension
}

func (cne *customNumberExtension) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder {
if typ.String() == "interface {}" {
return customNumberDecoder{}
}
return nil
}

type customNumberDecoder struct {
}

func (customNumberDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
switch iter.WhatIsNext() {
case jsoniter.NumberValue:
var number jsoniter.Number
iter.ReadVal(&number)
i64, err := strconv.ParseInt(string(number), 10, 64)
if err == nil {
*(*interface{})(ptr) = i64
return
}
f64, err := strconv.ParseFloat(string(number), 64)
if err == nil {
*(*interface{})(ptr) = f64
return
}
iter.ReportError("DecodeNumber", err.Error())
default:
*(*interface{})(ptr) = iter.Read()
}
}

// caseSensitiveJsonIterator returns a jsoniterator API that's configured to be
// case-sensitive when unmarshalling, and otherwise compatible with
// the encoding/json standard library.
func caseSensitiveJsonIterator() jsoniter.API {
config := jsoniter.Config{
EscapeHTML: true,
SortMapKeys: true,
ValidateJsonRawMessage: true,
CaseSensitive: true,
}.Froze()
// Force jsoniter to decode number to interface{} via int64/float64, if possible.
config.RegisterExtension(&customNumberExtension{})
return config
}
9 changes: 4 additions & 5 deletions client/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@ import (
"encoding/json"
"errors"
"fmt"
"go.etcd.io/etcd/pkg/pathutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"

jsoniter "github.com/json-iterator/go"
"go.etcd.io/etcd/pkg/pathutil"
)

const (
Expand Down Expand Up @@ -654,10 +652,11 @@ func unmarshalHTTPResponse(code int, header http.Header, body []byte) (res *Resp
return res, err
}

var jsonIterator = caseSensitiveJsonIterator()

func unmarshalSuccessfulKeysResponse(header http.Header, body []byte) (*Response, error) {
var res Response
var json = jsoniter.ConfigCompatibleWithStandardLibrary
err := json.Unmarshal(body, &res)
err := jsonIterator.Unmarshal(body, &res)
if err != nil {
return nil, ErrInvalidJSON
}
Expand Down

0 comments on commit 96a254f

Please sign in to comment.