From b64ccc00f01202f67e02ce11665e6dcdf01ebe16 Mon Sep 17 00:00:00 2001 From: Naveen Sreeramachandra Date: Fri, 20 Jun 2025 08:38:04 +0000 Subject: [PATCH 1/2] add input validation to support to support gorouter log level changes at runtime --- server.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/server.go b/server.go index e1fbd4e..714db9f 100644 --- a/server.go +++ b/server.go @@ -1,6 +1,7 @@ package debugserver import ( + "errors" "flag" "io" "net/http" @@ -42,6 +43,24 @@ func DebugAddress(flags *flag.FlagSet) string { return dbgFlag.Value.String() } +func validateloglevelrequest(w http.ResponseWriter, r *http.Request, level []byte) error { + // Only POST method is allowed for setting log level. + if r.Method != http.MethodPost { + return errors.New("method not allowed, use POST") + } + + // Only http is allowed for setting log level. + if r.TLS != nil { + return errors.New("invalid scheme, https is not allowed") + } + + // Ensure the log level is not empty. + if len(level) == 0 { + return errors.New("log level cannot be empty") + } + return nil +} + func Runner(address string, sink ReconfigurableSinkInterface) ifrit.Runner { return http_server.New(address, Handler(sink)) } @@ -64,21 +83,42 @@ func Handler(sink ReconfigurableSinkInterface) http.Handler { mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile)) mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol)) mux.Handle("/log-level", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Read the log level from the request body. level, err := io.ReadAll(r.Body) if err != nil { + http.Error(w, "Failed to read body", http.StatusBadRequest) return } - + // Validate the log level request. + if err = validateloglevelrequest(w, r, level); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + // Set the logLevel based on the input. + // Accepts: debug, info, error, fatal, or their short forms (d, i, e, f) or numeric values. + // If the input is not recognized, return a 400 Bad Request. + var logLevel lager.LogLevel switch string(level) { - case "debug", "DEBUG", "d", strconv.Itoa(int(lager.DEBUG)): - sink.SetMinLevel(lager.DEBUG) - case "info", "INFO", "i", strconv.Itoa(int(lager.INFO)): - sink.SetMinLevel(lager.INFO) - case "error", "ERROR", "e", strconv.Itoa(int(lager.ERROR)): - sink.SetMinLevel(lager.ERROR) - case "fatal", "FATAL", "f", strconv.Itoa(int(lager.FATAL)): - sink.SetMinLevel(lager.FATAL) + case "debug", "d", strconv.Itoa(int(lager.DEBUG)): + logLevel = lager.DEBUG + case "info", "i", strconv.Itoa(int(lager.INFO)): + logLevel = lager.INFO + case "error", "e", strconv.Itoa(int(lager.ERROR)): + logLevel = lager.ERROR + case "fatal", "f", strconv.Itoa(int(lager.FATAL)): + logLevel = lager.FATAL + default: + http.Error(w, "Invalid log level provided: "+string(level), http.StatusBadRequest) + return } + // Set the log level in the sink. + // The SetMinLevel sets the global zapcore conf.level for the logger. + sink.SetMinLevel(logLevel) + + // Respond with a success message. + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "text/plain") + w.Write([]byte("✅ /log-level was invoked with Level: " + string(level) + "\n")) })) mux.Handle("/block-profile-rate", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _rate, err := io.ReadAll(r.Body) From f20ee4a57e3f49b11b29b3f3a3f9d80ecf1ccb5b Mon Sep 17 00:00:00 2001 From: Naveen Sreeramachandra Date: Fri, 20 Jun 2025 09:08:59 +0000 Subject: [PATCH 2/2] add uppercase log levels --- server.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server.go b/server.go index 714db9f..116312b 100644 --- a/server.go +++ b/server.go @@ -99,13 +99,13 @@ func Handler(sink ReconfigurableSinkInterface) http.Handler { // If the input is not recognized, return a 400 Bad Request. var logLevel lager.LogLevel switch string(level) { - case "debug", "d", strconv.Itoa(int(lager.DEBUG)): + case "debug", "DEBUG", "d", strconv.Itoa(int(lager.DEBUG)): logLevel = lager.DEBUG - case "info", "i", strconv.Itoa(int(lager.INFO)): + case "info", "INFO", "i", strconv.Itoa(int(lager.INFO)): logLevel = lager.INFO - case "error", "e", strconv.Itoa(int(lager.ERROR)): + case "error", "ERROR", "e", strconv.Itoa(int(lager.ERROR)): logLevel = lager.ERROR - case "fatal", "f", strconv.Itoa(int(lager.FATAL)): + case "fatal", "FATAL", "f", strconv.Itoa(int(lager.FATAL)): logLevel = lager.FATAL default: http.Error(w, "Invalid log level provided: "+string(level), http.StatusBadRequest)