diff --git a/CHANGELOG.md b/CHANGELOG.md index e971eb17..fdb4bce5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 7.20.7 (unreleased) ### Implementation changes and bug fixes - [PR #1309](https://github.com/rqlite/rqlite/pull/1309): Factor Snapshot creation into own module. +- [PR #1311](https://github.com/rqlite/rqlite/pull/1311): Support 'key' param on /status endpoint. ## 7.20.6 (June 16th 2023) ### Implementation changes and bug fixes diff --git a/http/service.go b/http/service.go index 5046ed9c..56ea6cce 100644 --- a/http/service.go +++ b/http/service.go @@ -1062,6 +1062,15 @@ func (s *Service) handleStatus(w http.ResponseWriter, r *http.Request) { http.StatusInternalServerError) return } + + key := keyParam(r) + b, err = getSubJSON(b, key) + if err != nil { + http.Error(w, fmt.Sprintf("JSON subkey: %s", err.Error()), + http.StatusInternalServerError) + return + } + _, err = w.Write(b) if err != nil { http.Error(w, fmt.Sprintf("write: %s", err.Error()), @@ -1981,6 +1990,44 @@ func keyParam(req *http.Request) string { return strings.TrimSpace(q.Get("key")) } +func getSubJSON(jsonBlob []byte, keyString string) (json.RawMessage, error) { + if keyString == "" { + return jsonBlob, nil + } + + keys := strings.Split(keyString, ".") + var obj interface{} + if err := json.Unmarshal(jsonBlob, &obj); err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + + for _, key := range keys { + switch val := obj.(type) { + case map[string]interface{}: + if value, ok := val[key]; ok { + obj = value + } else { + emptyObj := json.RawMessage("{}") + return emptyObj, nil + } + default: + // If a value is not a map, marshal and return this value + finalObjBytes, err := json.Marshal(obj) + if err != nil { + return nil, fmt.Errorf("failed to marshal final object: %w", err) + } + return finalObjBytes, nil + } + } + + finalObjBytes, err := json.Marshal(obj) + if err != nil { + return nil, fmt.Errorf("failed to marshal final object: %w", err) + } + + return finalObjBytes, nil +} + // timeoutParam returns the value, if any, set for timeout. If not set, it // returns the value passed in as a default. func timeoutParam(req *http.Request, def time.Duration) (time.Duration, error) {