Handle hex strings and quoted strings in HTTP params

Use 0x-prefixed hex strings in client

server: Decode hex string args

Encode all string args as 0x<hex> without trying to encode as JSON

Added tests for special string arguments

Fix server handling quoted string args

Added string arg handling test cases to bash test script
This commit is contained in:
Matt Bell 2017-01-02 09:50:20 -08:00
parent 161e36fd56
commit 34a806578a
4 changed files with 111 additions and 10 deletions

View File

@ -4,10 +4,12 @@ import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"reflect"
"strings"
. "github.com/tendermint/go-common"
@ -119,7 +121,7 @@ func (c *ClientURI) call(method string, params map[string]interface{}, result in
if err != nil {
return nil, err
}
//log.Info(Fmt("URI request to %v (%v): %v", c.address, method, values))
log.Info(Fmt("URI request to %v (%v): %v", c.address, method, values))
resp, err := c.client.PostForm(c.address+"/"+method, values)
if err != nil {
return nil, err
@ -176,6 +178,21 @@ func argsToJson(args map[string]interface{}) error {
var n int
var err error
for k, v := range args {
// Convert strings to "0x"-prefixed hex
str, isString := reflect.ValueOf(v).Interface().(string)
if isString {
args[k] = fmt.Sprintf("0x%X", str)
continue
}
// Convert byte slices to "0x"-prefixed hex
byteSlice, isByteSlice := reflect.ValueOf(v).Interface().([]byte)
if isByteSlice {
args[k] = fmt.Sprintf("0x%X", byteSlice)
continue
}
// Pass everything else to go-wire
buf := new(bytes.Buffer)
wire.WriteJSON(v, buf, &n, &err)
if err != nil {

View File

@ -164,3 +164,39 @@ func TestWS_UNIX(t *testing.T) {
}
testWS(t, cl)
}
func TestHexStringArg(t *testing.T) {
cl := rpcclient.NewClientURI(tcpAddr)
// should NOT be handled as hex
val := "0xabc"
params := map[string]interface{}{
"arg": val,
}
var result Result
_, err := cl.Call("status", params, &result)
if err != nil {
t.Fatal(err)
}
got := result.(*ResultStatus).Value
if got != val {
t.Fatalf("Got: %v .... Expected: %v \n", got, val)
}
}
func TestQuotedStringArg(t *testing.T) {
cl := rpcclient.NewClientURI(tcpAddr)
// should NOT be unquoted
val := "\"abc\""
params := map[string]interface{}{
"arg": val,
}
var result Result
_, err := cl.Call("status", params, &result)
if err != nil {
t.Fatal(err)
}
got := result.(*ResultStatus).Value
if got != val {
t.Fatalf("Got: %v .... Expected: %v \n", got, val)
}
}

View File

@ -2,6 +2,7 @@ package rpcserver
import (
"bytes"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
@ -229,7 +230,35 @@ func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error
for i, name := range argNames {
ty := argTypes[i]
arg := GetParam(r, name)
//log.Notice("param to arg", "ty", ty, "name", name, "arg", arg)
// log.Notice("param to arg", "ty", ty, "name", name, "arg", arg)
// Handle quoted strings
if strings.HasPrefix(arg, "\"") && strings.HasSuffix(arg, "\"") {
data := arg[1 : len(arg)-1]
if ty.Kind() == reflect.String {
values[i] = reflect.ValueOf(string(data))
} else {
values[i] = reflect.ValueOf(data)
}
continue
}
// Handle hex strings
if strings.HasPrefix(strings.ToLower(arg), "0x") {
var value []byte
value, err = hex.DecodeString(arg[2:])
if err != nil {
return nil, err
}
if ty.Kind() == reflect.String {
values[i] = reflect.ValueOf(string(value))
} else {
values[i] = reflect.ValueOf(value)
}
continue
}
// Pass values to go-wire
values[i], err = _jsonStringToArg(ty, arg)
if err != nil {
return nil, err

35
test/test.sh Normal file → Executable file
View File

@ -6,18 +6,37 @@ go build -o server main.go
PID=$!
sleep 2
# simple JSONRPC request
R1=`curl -s 'http://localhost:8008/hello_world?name="my_world"&num=5'`
R2=`curl -s --data @data.json http://localhost:8008`
kill -9 $PID
if [[ "$R1" != "$R2" ]]; then
echo "responses are not identical:"
echo "R1: $R1"
echo "R2: $R2"
exit 1
else
echo "Success"
fi
echo "Success"
# request with 0x-prefixed hex string arg
R1=`curl -s 'http://localhost:8008/hello_world?name=0x41424344&num=123'`
R2='{"jsonrpc":"2.0","id":"","result":{"Result":"hi ABCD 123"},"error":""}'
if [[ "$R1" != "$R2" ]]; then
echo "responses are not identical:"
echo "R1: $R1"
echo "R2: $R2"
else
echo "Success"
fi
# request with unquoted string arg
R1=`curl -s 'http://localhost:8008/hello_world?name=abcd&num=123'`
R2="{\"jsonrpc\":\"2.0\",\"id\":\"\",\"result\":null,\"error\":\"Error converting http params to args: invalid character 'a' looking for beginning of value\"}"
if [[ "$R1" != "$R2" ]]; then
echo "responses are not identical:"
echo "R1: $R1"
echo "R2: $R2"
else
echo "Success"
fi
kill -9 $PID