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