github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/rpc/jsonrpc/server/http_uri_handler.go (about) 1 package server 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "net/http" 7 "reflect" 8 "regexp" 9 "strings" 10 11 tmjson "github.com/tendermint/tendermint/libs/json" 12 "github.com/tendermint/tendermint/libs/log" 13 types "github.com/tendermint/tendermint/rpc/jsonrpc/types" 14 ) 15 16 /////////////////////////////////////////////////////////////////////////////// 17 // HTTP + URI handler 18 /////////////////////////////////////////////////////////////////////////////// 19 20 var reInt = regexp.MustCompile(`^-?[0-9]+$`) 21 22 // convert from a function name to the http handler 23 func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWriter, *http.Request) { 24 // Always return -1 as there's no ID here. 25 dummyID := types.JSONRPCIntID(-1) // URIClientRequestID 26 27 // Exception for websocket endpoints 28 if rpcFunc.ws { 29 return func(w http.ResponseWriter, r *http.Request) { 30 WriteRPCResponseHTTPError(w, http.StatusNotFound, 31 types.RPCMethodNotFoundError(dummyID)) 32 } 33 } 34 35 // All other endpoints 36 return func(w http.ResponseWriter, r *http.Request) { 37 logger.Debug("HTTP HANDLER", "req", r) 38 39 ctx := &types.Context{HTTPReq: r} 40 args := []reflect.Value{reflect.ValueOf(ctx)} 41 42 fnArgs, err := httpParamsToArgs(rpcFunc, r) 43 if err != nil { 44 WriteRPCResponseHTTPError( 45 w, 46 http.StatusInternalServerError, 47 types.RPCInvalidParamsError( 48 dummyID, 49 fmt.Errorf("error converting http params to arguments: %w", err), 50 ), 51 ) 52 return 53 } 54 args = append(args, fnArgs...) 55 56 returns := rpcFunc.f.Call(args) 57 58 logger.Debug("HTTPRestRPC", "method", r.URL.Path, "args", args, "returns", returns) 59 result, err := unreflectResult(returns) 60 if err != nil { 61 WriteRPCResponseHTTPError(w, http.StatusInternalServerError, 62 types.RPCInternalError(dummyID, err)) 63 return 64 } 65 WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse(dummyID, result)) 66 } 67 } 68 69 // Covert an http query to a list of properly typed values. 70 // To be properly decoded the arg must be a concrete type from tendermint (if its an interface). 71 func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error) { 72 // skip types.Context 73 const argsOffset = 1 74 75 values := make([]reflect.Value, len(rpcFunc.argNames)) 76 77 for i, name := range rpcFunc.argNames { 78 argType := rpcFunc.args[i+argsOffset] 79 80 values[i] = reflect.Zero(argType) // set default for that type 81 82 arg := getParam(r, name) 83 // log.Notice("param to arg", "argType", argType, "name", name, "arg", arg) 84 85 if arg == "" { 86 continue 87 } 88 89 v, ok, err := nonJSONStringToArg(argType, arg) 90 if err != nil { 91 return nil, err 92 } 93 if ok { 94 values[i] = v 95 continue 96 } 97 98 values[i], err = jsonStringToArg(argType, arg) 99 if err != nil { 100 return nil, err 101 } 102 } 103 104 return values, nil 105 } 106 107 func jsonStringToArg(rt reflect.Type, arg string) (reflect.Value, error) { 108 rv := reflect.New(rt) 109 err := tmjson.Unmarshal([]byte(arg), rv.Interface()) 110 if err != nil { 111 return rv, err 112 } 113 rv = rv.Elem() 114 return rv, nil 115 } 116 117 func nonJSONStringToArg(rt reflect.Type, arg string) (reflect.Value, bool, error) { 118 if rt.Kind() == reflect.Ptr { 119 rv1, ok, err := nonJSONStringToArg(rt.Elem(), arg) 120 switch { 121 case err != nil: 122 return reflect.Value{}, false, err 123 case ok: 124 rv := reflect.New(rt.Elem()) 125 rv.Elem().Set(rv1) 126 return rv, true, nil 127 default: 128 return reflect.Value{}, false, nil 129 } 130 } else { 131 return _nonJSONStringToArg(rt, arg) 132 } 133 } 134 135 // NOTE: rt.Kind() isn't a pointer. 136 func _nonJSONStringToArg(rt reflect.Type, arg string) (reflect.Value, bool, error) { 137 isIntString := reInt.Match([]byte(arg)) 138 isQuotedString := strings.HasPrefix(arg, `"`) && strings.HasSuffix(arg, `"`) 139 isHexString := strings.HasPrefix(strings.ToLower(arg), "0x") 140 141 var expectingString, expectingByteSlice, expectingInt bool 142 switch rt.Kind() { 143 case reflect.Int, 144 reflect.Uint, 145 reflect.Int8, 146 reflect.Uint8, 147 reflect.Int16, 148 reflect.Uint16, 149 reflect.Int32, 150 reflect.Uint32, 151 reflect.Int64, 152 reflect.Uint64: 153 expectingInt = true 154 case reflect.String: 155 expectingString = true 156 case reflect.Slice: 157 expectingByteSlice = rt.Elem().Kind() == reflect.Uint8 158 } 159 160 if isIntString && expectingInt { 161 qarg := `"` + arg + `"` 162 rv, err := jsonStringToArg(rt, qarg) 163 if err != nil { 164 return rv, false, err 165 } 166 167 return rv, true, nil 168 } 169 170 if isHexString { 171 if !expectingString && !expectingByteSlice { 172 err := fmt.Errorf("got a hex string arg, but expected '%s'", 173 rt.Kind().String()) 174 return reflect.ValueOf(nil), false, err 175 } 176 177 var value []byte 178 value, err := hex.DecodeString(arg[2:]) 179 if err != nil { 180 return reflect.ValueOf(nil), false, err 181 } 182 if rt.Kind() == reflect.String { 183 return reflect.ValueOf(string(value)), true, nil 184 } 185 return reflect.ValueOf(value), true, nil 186 } 187 188 if isQuotedString && expectingByteSlice { 189 v := reflect.New(reflect.TypeOf("")) 190 err := tmjson.Unmarshal([]byte(arg), v.Interface()) 191 if err != nil { 192 return reflect.ValueOf(nil), false, err 193 } 194 v = v.Elem() 195 return reflect.ValueOf([]byte(v.String())), true, nil 196 } 197 198 return reflect.ValueOf(nil), false, nil 199 } 200 201 func getParam(r *http.Request, param string) string { 202 s := r.URL.Query().Get(param) 203 if s == "" { 204 s = r.FormValue(param) 205 } 206 return s 207 }