From 32d51cc696e4927ff6275310e0ecff7122ada286 Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Mon, 31 Jan 2022 15:40:03 -0800 Subject: [PATCH] rpc: fix layout of endpoint list (#7742) (#7744) (backport of #7744) The output of the default endpoint-list query was not correctly segregating methods with and without arguments. Fix this, and also clean up the output to be easier to read (both in code and in generated source). --- rpc/jsonrpc/server/http_json_handler.go | 77 ++++++++++++++----------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/rpc/jsonrpc/server/http_json_handler.go b/rpc/jsonrpc/server/http_json_handler.go index fbc0cca79..b2ccf8694 100644 --- a/rpc/jsonrpc/server/http_json_handler.go +++ b/rpc/jsonrpc/server/http_json_handler.go @@ -1,14 +1,14 @@ package server import ( - "bytes" "encoding/json" "errors" "fmt" + "html/template" "io/ioutil" "net/http" "reflect" - "sort" + "strings" tmjson "github.com/tendermint/tendermint/libs/json" "github.com/tendermint/tendermint/libs/log" @@ -239,42 +239,27 @@ func jsonParamsToArgs(rpcFunc *RPCFunc, raw []byte) ([]reflect.Value, error) { // writes a list of available rpc endpoints as an html page func writeListOfEndpoints(w http.ResponseWriter, r *http.Request, funcMap map[string]*RPCFunc) { - noArgNames := []string{} - argNames := []string{} - for name, funcData := range funcMap { - if len(funcData.args) == 0 { - noArgNames = append(noArgNames, name) + hasArgs := make(map[string]string) + noArgs := make(map[string]string) + for name, rf := range funcMap { + base := fmt.Sprintf("//%s/%s", r.Host, name) + // N.B. Check argNames, not args, since the type list includes the type + // of the leading context argument. + if len(rf.argNames) == 0 { + noArgs[name] = base } else { - argNames = append(argNames, name) - } - } - sort.Strings(noArgNames) - sort.Strings(argNames) - buf := new(bytes.Buffer) - buf.WriteString("") - buf.WriteString("
Available endpoints:
") - - for _, name := range noArgNames { - link := fmt.Sprintf("//%s/%s", r.Host, name) - buf.WriteString(fmt.Sprintf("%s
", link, link)) - } - - buf.WriteString("
Endpoints that require arguments:
") - for _, name := range argNames { - link := fmt.Sprintf("//%s/%s?", r.Host, name) - funcData := funcMap[name] - for i, argName := range funcData.argNames { - link += argName + "=_" - if i < len(funcData.argNames)-1 { - link += "&" + query := append([]string(nil), rf.argNames...) + for i, arg := range query { + query[i] = arg + "=_" } + hasArgs[name] = base + "?" + strings.Join(query, "&") } - buf.WriteString(fmt.Sprintf("%s
", link, link)) } - buf.WriteString("") w.Header().Set("Content-Type", "text/html") - w.WriteHeader(200) - w.Write(buf.Bytes()) // nolint: errcheck + _ = listOfEndpoints.Execute(w, map[string]map[string]string{ + "NoArgs": noArgs, + "HasArgs": hasArgs, + }) } func hasDefaultHeight(r rpctypes.RPCRequest, h []reflect.Value) bool { @@ -285,3 +270,29 @@ func hasDefaultHeight(r rpctypes.RPCRequest, h []reflect.Value) bool { return false } } + +var listOfEndpoints = template.Must(template.New("list").Parse(` +List of RPC Endpoints + + +

Available RPC endpoints:

+ +{{if .NoArgs}} +
+

Endpoints with no arguments:

+ +{{end}} + +{{if .HasArgs}} +
+

Endpoints that require arguments:

+ +{{end}} + +`))