package main import ( "context" "encoding/json" "encoding/xml" "log" "net/http" "strings" "time" ) func CreateAndStartHTTPServer(conf *Configuration) *http.Server { router := http.NewServeMux() router.HandleFunc("/processes", AreProcessesUp(&conf.Processes, conf.IndentedOutput)) srv := &http.Server{ Addr: conf.ListenAddress, Handler: router, ReadTimeout: 5 * time.Second, WriteTimeout: 5 * time.Second, IdleTimeout: 10 * time.Second, } go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("ListenAndServe: %s\n", err) } }() return srv } func ShutdownHTTPServer(srv *http.Server) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() srv.SetKeepAlivesEnabled(false) if err := srv.Shutdown(ctx); err != nil { log.Fatalf("%s\n", err) } } // AreProcessesUp handles a GET /processes request and sends back status of given // processes. func AreProcessesUp(processes *[]string, indented bool) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { proclist := make(ProcessList) for _, proc := range *processes { pids, err := GetProcessPIDs(proc) proclist[proc] = err == nil && len(pids) > 0 } switch r.Header.Get("Accept") { case "application/xml": w.Header().Add("Content-Type", "application/xml") enc := xml.NewEncoder(w) if indented { enc.Indent("", "\t") } enc.Encode(proclist) case "text/plain": w.Header().Add("Content-Type", "text/plain") var s []string for k, v := range proclist { if v { s = append(s, k) } } w.Write([]byte(strings.Join(s, ","))) default: w.Header().Add("Content-Type", "application/json") enc := json.NewEncoder(w) if indented { enc.SetIndent("", "\t") } enc.Encode(proclist) } } else { w.WriteHeader(http.StatusMethodNotAllowed) w.Header().Add("Allow", "GET") } } }