From 3db629e2ca3757f1c7d415cc9fe0b0584b6ed8b3 Mon Sep 17 00:00:00 2001 From: Michael Hohn Date: Wed, 27 Nov 2024 22:56:47 -0800 Subject: [PATCH] A go version of hepc-serve --- client/qldbtools/bin/hepc-serve.go | 104 +++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100755 client/qldbtools/bin/hepc-serve.go diff --git a/client/qldbtools/bin/hepc-serve.go b/client/qldbtools/bin/hepc-serve.go new file mode 100755 index 0000000..9f5b38b --- /dev/null +++ b/client/qldbtools/bin/hepc-serve.go @@ -0,0 +1,104 @@ +/* + dependencies + go get -u golang.org/x/exp/slog + + on-the-fly + go run bin/hepc-serve.go --codeql-db-dir db-collection-py-1 + + compiled + cd ~/work-gh/mrva/mrvacommander/client/qldbtools/ + go build -o ./bin/hepc-serve.bin ./bin/hepc-serve.go + + test + curl http://127.0.0.1:8080/api/v1/latest_results/codeql-all -o foo + curl $(head -1 foo | jq -r ".result_url" |sed 's|hepc|127.0.0.1:8080/db|g;') -o foo.zip + +*/ +package main + +import ( + "flag" + "fmt" + "net/http" + "os" + "path/filepath" + + "golang.org/x/exp/slog" +) + +var dbDir string + +func serveFile(w http.ResponseWriter, r *http.Request) { + fullPath := r.URL.Path[len("/db/"):] + + resolvedPath, err := filepath.EvalSymlinks(fullPath) + if err != nil { + slog.Warn("failed to resolve symlink", slog.String("fullPath", fullPath), + slog.String("error", err.Error())) + http.Error(w, "File not found", http.StatusNotFound) + return + } + + if fileInfo, err := os.Stat(resolvedPath); err != nil || fileInfo.IsDir() { + slog.Warn("file not found or is a directory", slog.String("resolvedPath", resolvedPath)) + http.Error(w, "File not found", http.StatusNotFound) + return + } + + slog.Info("serving file", slog.String("resolvedPath", resolvedPath)) + http.ServeFile(w, r, resolvedPath) +} + +func serveMetadata(w http.ResponseWriter, r *http.Request) { + metadataPath := filepath.Join(dbDir, "metadata.json") + if fileInfo, err := os.Stat(metadataPath); err != nil || fileInfo.IsDir() { + slog.Warn("metadata.json not found", slog.String("metadataPath", metadataPath)) + http.Error(w, "metadata.json not found", http.StatusNotFound) + return + } + + slog.Info("serving metadata.json", slog.String("metadataPath", metadataPath)) + http.ServeFile(w, r, metadataPath) +} + +func logMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + slog.Info("incoming request", slog.String("method", r.Method), slog.String("url", r.URL.Path)) + next.ServeHTTP(w, r) + }) +} + +func main() { + var host string + var port int + + flag.StringVar(&dbDir, "codeql-db-dir", "", "Directory containing CodeQL database files (required)") + flag.StringVar(&host, "host", "127.0.0.1", "Host address for the HTTP server") + flag.IntVar(&port, "port", 8080, "Port for the HTTP server") + flag.Parse() + + if dbDir == "" { + slog.Error("missing required flag", slog.String("flag", "--codeql-db-dir")) + os.Exit(1) + } + + if _, err := os.Stat(dbDir); os.IsNotExist(err) { + slog.Error("invalid directory", slog.String("dbDir", dbDir)) + os.Exit(1) + } + + slog.Info("starting server", slog.String("host", host), slog.Int("port", port), slog.String("dbDir", dbDir)) + + mux := http.NewServeMux() + mux.HandleFunc("/db/", serveFile) + mux.HandleFunc("/index", serveMetadata) + mux.HandleFunc("/api/v1/latest_results/codeql-all", serveMetadata) + + loggedHandler := logMiddleware(mux) + + addr := fmt.Sprintf("%s:%d", host, port) + slog.Info("server listening", slog.String("address", addr)) + if err := http.ListenAndServe(addr, loggedHandler); err != nil { + slog.Error("server error", slog.String("error", err.Error())) + } +}