aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2016-12-12 19:20:30 +0800
committerFelix Lange <fjl@twurst.com>2016-12-20 21:35:26 +0800
commita3e3235d97cd85e13609f61a9268ad06aa9843c2 (patch)
tree87a9b74989d96f8bc0b4beb43b90ec3c1d1ae28e
parent2be3c4b0e3a3a89594109f0b8e6b79c93cb9afba (diff)
downloaddexon-a3e3235d97cd85e13609f61a9268ad06aa9843c2.tar.gz
dexon-a3e3235d97cd85e13609f61a9268ad06aa9843c2.tar.zst
dexon-a3e3235d97cd85e13609f61a9268ad06aa9843c2.zip
rpc: improve error messages for invalid arguments
The message now includes the index of the invalid arg.
-rw-r--r--rpc/json.go63
1 files changed, 32 insertions, 31 deletions
diff --git a/rpc/json.go b/rpc/json.go
index a7053e3f5..5a89c1a69 100644
--- a/rpc/json.go
+++ b/rpc/json.go
@@ -17,6 +17,7 @@
package rpc
import (
+ "bytes"
"encoding/json"
"fmt"
"io"
@@ -266,42 +267,42 @@ func (c *jsonCodec) ParseRequestArguments(argTypes []reflect.Type, params interf
}
}
-// parsePositionalArguments tries to parse the given args to an array of values with the given types.
-// It returns the parsed values or an error when the args could not be parsed. Missing optional arguments
-// are returned as reflect.Zero values.
-func parsePositionalArguments(args json.RawMessage, callbackArgs []reflect.Type) ([]reflect.Value, Error) {
- params := make([]interface{}, 0, len(callbackArgs))
- for _, t := range callbackArgs {
- params = append(params, reflect.New(t).Interface())
+// parsePositionalArguments tries to parse the given args to an array of values with the
+// given types. It returns the parsed values or an error when the args could not be
+// parsed. Missing optional arguments are returned as reflect.Zero values.
+func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, Error) {
+ // Read beginning of the args array.
+ dec := json.NewDecoder(bytes.NewReader(rawArgs))
+ if tok, _ := dec.Token(); tok != json.Delim('[') {
+ return nil, &invalidParamsError{"non-array args"}
}
-
- if err := json.Unmarshal(args, &params); err != nil {
- return nil, &invalidParamsError{err.Error()}
- }
-
- if len(params) > len(callbackArgs) {
- return nil, &invalidParamsError{fmt.Sprintf("too many params, want %d got %d", len(callbackArgs), len(params))}
+ // Read args.
+ args := make([]reflect.Value, 0, len(types))
+ for i := 0; dec.More(); i++ {
+ if i >= len(types) {
+ return nil, &invalidParamsError{fmt.Sprintf("too many arguments, want at most %d", len(types))}
+ }
+ argval := reflect.New(types[i])
+ if err := dec.Decode(argval.Interface()); err != nil {
+ return nil, &invalidParamsError{fmt.Sprintf("invalid argument %d: %v", i, err)}
+ }
+ if argval.IsNil() && types[i].Kind() != reflect.Ptr {
+ return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)}
+ }
+ args = append(args, argval.Elem())
}
-
- // assume missing params are null values
- for i := len(params); i < len(callbackArgs); i++ {
- params = append(params, nil)
+ // Read end of args array.
+ if _, err := dec.Token(); err != nil {
+ return nil, &invalidParamsError{err.Error()}
}
-
- argValues := make([]reflect.Value, len(params))
- for i, p := range params {
- // verify that JSON null values are only supplied for optional arguments (ptr types)
- if p == nil && callbackArgs[i].Kind() != reflect.Ptr {
- return nil, &invalidParamsError{fmt.Sprintf("invalid or missing value for params[%d]", i)}
- }
- if p == nil {
- argValues[i] = reflect.Zero(callbackArgs[i])
- } else { // deref pointers values creates previously with reflect.New
- argValues[i] = reflect.ValueOf(p).Elem()
+ // Set any missing args to nil.
+ for i := len(args); i < len(types); i++ {
+ if types[i].Kind() != reflect.Ptr {
+ return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)}
}
+ args = append(args, reflect.Zero(types[i]))
}
-
- return argValues, nil
+ return args, nil
}
// CreateResponse will create a JSON-RPC success response with the given id and reply as result.