From 8a684c1bb5caa2ccfef25be4131c8f6164b0621f Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Mon, 31 Jan 2022 14:52:38 -0800 Subject: [PATCH] rpc: fix layout of endpoint list (#7742) * rpc: fix layout of endpoint list 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). Fixes #3618. --- rpc/jsonrpc/server/http_json_handler.go | 76 ++++++++++++++----------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/rpc/jsonrpc/server/http_json_handler.go b/rpc/jsonrpc/server/http_json_handler.go index 4d0c19c28..94da974de 100644 --- a/rpc/jsonrpc/server/http_json_handler.go +++ b/rpc/jsonrpc/server/http_json_handler.go @@ -6,11 +6,12 @@ import ( "encoding/json" "errors" "fmt" + "html/template" "io" "net/http" "reflect" - "sort" "strconv" + "strings" "github.com/tendermint/tendermint/libs/log" rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" @@ -222,40 +223,51 @@ func (z *int64String) UnmarshalText(data []byte) 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, + }) } + +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}} + +`))