Browse Source

When using JSONRPC, do not double-encode JSON.

pull/43/merge
Jae Kwon 10 years ago
parent
commit
1a4aab4c35
6 changed files with 39 additions and 88 deletions
  1. +8
    -4
      binary/binary.go
  2. +1
    -1
      p2p/pex_reactor.go
  3. +23
    -72
      rpc/http_handlers.go
  4. +3
    -0
      rpc/test/http_rpc_test.go
  5. +2
    -2
      rpc/test/json_rpc_test.go
  6. +2
    -9
      rpc/test/test.go

+ 8
- 4
binary/binary.go View File

@ -25,19 +25,23 @@ func WriteBinary(o interface{}, w io.Writer, n *int64, err *error) {
}
func ReadJSON(o interface{}, bytes []byte, err *error) interface{} {
var parsed interface{}
*err = json.Unmarshal(bytes, &parsed)
var object interface{}
*err = json.Unmarshal(bytes, &object)
if *err != nil {
return o
}
return ReadJSONFromObject(o, object, err)
}
func ReadJSONFromObject(o interface{}, object interface{}, err *error) interface{} {
rv, rt := reflect.ValueOf(o), reflect.TypeOf(o)
if rv.Kind() == reflect.Ptr {
readReflectJSON(rv.Elem(), rt.Elem(), parsed, err)
readReflectJSON(rv.Elem(), rt.Elem(), object, err)
return o
} else {
ptrRv := reflect.New(rt)
readReflectJSON(ptrRv.Elem(), rt, parsed, err)
readReflectJSON(ptrRv.Elem(), rt, object, err)
return ptrRv.Elem().Interface()
}
}


+ 1
- 1
p2p/pex_reactor.go View File

@ -237,7 +237,7 @@ func DecodeMessage(bz []byte) (msg interface{}, err error) {
}
/*
A pexHandshakeMessage contains the peer's chainId
A pexHandshakeMessage contains the network identifier.
*/
type pexHandshakeMessage struct {
Network string


+ 23
- 72
rpc/http_handlers.go View File

@ -1,7 +1,6 @@
package rpc
import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/tendermint/tendermint/binary"
@ -9,7 +8,6 @@ import (
"io/ioutil"
"net/http"
"reflect"
"strconv"
)
// cache all type information about each function up front
@ -66,71 +64,24 @@ func toHandler(funcName string) func(http.ResponseWriter, *http.Request) {
// convert a (json) string to a given type
func jsonToArg(ty reflect.Type, arg string) (reflect.Value, error) {
v := reflect.New(ty).Elem()
kind := v.Kind()
var err error
switch kind {
case reflect.Interface:
v = reflect.New(ty)
binary.ReadJSON(v.Interface(), []byte(arg), &err)
if err != nil {
return v, err
}
v = v.Elem()
case reflect.Struct:
binary.ReadJSON(v.Interface(), []byte(arg), &err)
if err != nil {
return v, err
}
case reflect.Slice:
rt := ty.Elem()
if rt.Kind() == reflect.Uint8 {
// if hex, decode
if len(arg) > 2 && arg[:2] == "0x" {
arg = arg[2:]
b, err := hex.DecodeString(arg)
if err != nil {
return v, err
}
v = reflect.ValueOf(b)
} else {
v = reflect.ValueOf([]byte(arg))
}
} else {
v = reflect.New(ty)
binary.ReadJSON(v.Interface(), []byte(arg), &err)
if err != nil {
return v, err
}
v = v.Elem()
}
case reflect.Int64:
u, err := strconv.ParseInt(arg, 10, 64)
if err != nil {
return v, err
}
v = reflect.ValueOf(u)
case reflect.Int32:
u, err := strconv.ParseInt(arg, 10, 32)
if err != nil {
return v, err
}
v = reflect.ValueOf(u)
case reflect.Uint64:
u, err := strconv.ParseUint(arg, 10, 64)
if err != nil {
return v, err
}
v = reflect.ValueOf(u)
case reflect.Uint:
u, err := strconv.ParseUint(arg, 10, 32)
if err != nil {
return v, err
}
v = reflect.ValueOf(u)
default:
v = reflect.ValueOf(arg)
v := reflect.New(ty)
binary.ReadJSON(v.Interface(), []byte(arg), &err)
if err != nil {
return v, err
}
v = v.Elem()
return v, nil
}
func jsonObjectToArg(ty reflect.Type, object interface{}) (reflect.Value, error) {
var err error
v := reflect.New(ty)
binary.ReadJSONFromObject(v.Interface(), object, &err)
if err != nil {
return v, err
}
v = v.Elem()
return v, nil
}
@ -145,6 +96,7 @@ func queryToValues(funcInfo *FuncWrapper, r *http.Request) ([]reflect.Value, err
for i, name := range argNames {
ty := argTypes[i]
arg := GetParam(r, name)
//fmt.Println("GetParam()", r, name, arg)
values[i], err = jsonToArg(ty, arg)
if err != nil {
return nil, err
@ -154,12 +106,11 @@ func queryToValues(funcInfo *FuncWrapper, r *http.Request) ([]reflect.Value, err
}
// covert a list of interfaces to properly typed values
// TODO!
func paramsToValues(funcInfo *FuncWrapper, params []string) ([]reflect.Value, error) {
func paramsToValues(funcInfo *FuncWrapper, params []interface{}) ([]reflect.Value, error) {
values := make([]reflect.Value, len(params))
for i, p := range params {
ty := funcInfo.args[i]
v, err := jsonToArg(ty, p)
v, err := jsonObjectToArg(ty, p)
if err != nil {
return nil, err
}
@ -249,10 +200,10 @@ func initHandlers() {
}
type JsonRpc struct {
JsonRpc string `json:"jsonrpc"`
Method string `json:"method"`
Params []string `json:"params"`
Id int `json:"id"`
JsonRpc string `json:"jsonrpc"`
Method string `json:"method"`
Params []interface{} `json:"params"`
Id int `json:"id"`
}
// this will panic if not passed a function


+ 3
- 0
rpc/test/http_rpc_test.go View File

@ -71,6 +71,9 @@ func TestHTTPGenPriv(t *testing.T) {
func TestHTTPGetAccount(t *testing.T) {
byteAddr, _ := hex.DecodeString(userAddr)
acc := getAccount(t, "HTTP", byteAddr)
if acc == nil {
t.Fatalf("Account was nil")
}
if bytes.Compare(acc.Address, byteAddr) != 0 {
t.Fatalf("Failed to get correct account. Got %x, expected %x", acc.Address, byteAddr)
}


+ 2
- 2
rpc/test/json_rpc_test.go View File

@ -21,7 +21,7 @@ func TestJSONStatus(t *testing.T) {
s := rpc.JsonRpc{
JsonRpc: "2.0",
Method: "status",
Params: []string{},
Params: []interface{}{},
Id: 0,
}
b, err := json.Marshal(s)
@ -56,7 +56,7 @@ func TestJSONGenPriv(t *testing.T) {
s := rpc.JsonRpc{
JsonRpc: "2.0",
Method: "unsafe/gen_priv_account",
Params: []string{},
Params: []interface{}{},
Id: 0,
}
b, err := json.Marshal(s)


+ 2
- 9
rpc/test/test.go View File

@ -4,7 +4,6 @@ import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/tendermint/tendermint/account"
"github.com/tendermint/tendermint/binary"
"github.com/tendermint/tendermint/config"
@ -24,8 +23,6 @@ var (
rpcAddr = "127.0.0.1:8089"
requestAddr = "http://" + rpcAddr + "/"
chainId string
node *daemon.Node
mempoolCount = 0
@ -78,7 +75,7 @@ func getAccount(t *testing.T, typ string, addr []byte) *account.Account {
s := rpc.JsonRpc{
JsonRpc: "2.0",
Method: "get_account",
Params: []string{"0x" + hex.EncodeToString(addr)},
Params: []interface{}{hex.EncodeToString(addr)},
Id: 0,
}
b, err := json.Marshal(s)
@ -89,9 +86,8 @@ func getAccount(t *testing.T, typ string, addr []byte) *account.Account {
resp, err = http.Post(requestAddr, "text/json", buf)
case "HTTP":
resp, err = http.PostForm(requestAddr+"get_account",
url.Values{"address": {string(addr)}})
url.Values{"address": {"\"" + (hex.EncodeToString(addr)) + "\""}})
}
fmt.Println("RESPONSE:", resp)
if err != nil {
t.Fatal(err)
}
@ -105,7 +101,6 @@ func getAccount(t *testing.T, typ string, addr []byte) *account.Account {
Data core.ResponseGetAccount
Error string
}
fmt.Println(string(body))
binary.ReadJSON(&status, body, &err)
if err != nil {
t.Fatal(err)
@ -153,7 +148,6 @@ func requestResponse(t *testing.T, method string, values url.Values, status inte
if err != nil {
t.Fatal(err)
}
fmt.Println(string(body))
binary.ReadJSON(status, body, &err)
if err != nil {
t.Fatal(err)
@ -206,7 +200,6 @@ func checkTx(t *testing.T, fromAddr []byte, priv *account.PrivAccount, tx *types
if err := in.ValidateBasic(); err != nil {
t.Fatal(err)
}
fmt.Println(priv.PubKey, in.PubKey)
// Check signatures
// acc := getAccount(t, byteAddr)
// NOTE: using the acc here instead of the in fails; its PubKeyNil ... ?


Loading…
Cancel
Save