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}} + +`))