diff --git a/ee/query-service/app/server.go b/ee/query-service/app/server.go index 98193d6eed..e93c09fb68 100644 --- a/ee/query-service/app/server.go +++ b/ee/query-service/app/server.go @@ -351,7 +351,7 @@ func (s *Server) createPrivateServer(apiHandler *api.APIHandler) (*http.Server, }, nil } -func (s *Server) createPublicServer(apiHandler *api.APIHandler, web *web.Web) (*http.Server, error) { +func (s *Server) createPublicServer(apiHandler *api.APIHandler, web web.Web) (*http.Server, error) { r := baseapp.NewRouter() diff --git a/pkg/signoz/signoz.go b/pkg/signoz/signoz.go index eaf13be2d6..6273dd5eab 100644 --- a/pkg/signoz/signoz.go +++ b/pkg/signoz/signoz.go @@ -6,12 +6,13 @@ import ( "go.signoz.io/signoz/pkg/cache/rediscache" "go.signoz.io/signoz/pkg/config" "go.signoz.io/signoz/pkg/web" + "go.signoz.io/signoz/pkg/web/routerweb" "go.uber.org/zap" ) type SigNoz struct { Cache cache.Cache - Web *web.Web + Web web.Web } func New(config *config.Config, skipWebFrontend bool) (*SigNoz, error) { @@ -25,7 +26,7 @@ func New(config *config.Config, skipWebFrontend bool) (*SigNoz, error) { cache = rediscache.New(&config.Cache.Redis) } - web, err := web.New(zap.L(), config.Web) + web, err := routerweb.New(zap.L(), config.Web) if err != nil && !skipWebFrontend { return nil, err } diff --git a/pkg/web/noopweb/provider.go b/pkg/web/noopweb/provider.go new file mode 100644 index 0000000000..3b7af16b9a --- /dev/null +++ b/pkg/web/noopweb/provider.go @@ -0,0 +1,22 @@ +package noopweb + +import ( + "context" + "net/http" + + "github.com/gorilla/mux" + "go.signoz.io/signoz/pkg/factory" + "go.signoz.io/signoz/pkg/web" +) + +type provider struct{} + +func New(ctx context.Context, settings factory.ProviderSettings, config web.Config) (web.Web, error) { + return &provider{}, nil +} + +func (provider *provider) AddToRouter(router *mux.Router) error { + return nil +} + +func (provider *provider) ServeHTTP(w http.ResponseWriter, r *http.Request) {} diff --git a/pkg/web/routerweb/provider.go b/pkg/web/routerweb/provider.go new file mode 100644 index 0000000000..f4cc644b0c --- /dev/null +++ b/pkg/web/routerweb/provider.go @@ -0,0 +1,93 @@ +package routerweb + +import ( + "fmt" + "net/http" + "os" + "path/filepath" + "time" + + "github.com/gorilla/mux" + "go.signoz.io/signoz/pkg/http/middleware" + "go.signoz.io/signoz/pkg/web" + "go.uber.org/zap" +) + +const ( + indexFileName string = "index.html" +) + +type Web struct { + logger *zap.Logger + cfg web.Config +} + +func New(logger *zap.Logger, cfg web.Config) (*Web, error) { + if logger == nil { + return nil, fmt.Errorf("cannot build web, logger is required") + } + + fi, err := os.Stat(cfg.Directory) + if err != nil { + return nil, fmt.Errorf("cannot access web directory: %w", err) + } + + ok := fi.IsDir() + if !ok { + return nil, fmt.Errorf("web directory is not a directory") + } + + fi, err = os.Stat(filepath.Join(cfg.Directory, indexFileName)) + if err != nil { + return nil, fmt.Errorf("cannot access %q in web directory: %w", indexFileName, err) + } + + if os.IsNotExist(err) || fi.IsDir() { + return nil, fmt.Errorf("%q does not exist", indexFileName) + } + + return &Web{ + logger: logger.Named("go.signoz.io/pkg/web"), + cfg: cfg, + }, nil +} + +func (web *Web) AddToRouter(router *mux.Router) error { + cache := middleware.NewCache(7 * 24 * time.Hour) + err := router.PathPrefix(web.cfg.Prefix). + Handler( + http.StripPrefix( + web.cfg.Prefix, + cache.Wrap(http.HandlerFunc(web.ServeHTTP)), + ), + ).GetError() + if err != nil { + return fmt.Errorf("unable to add web to router: %w", err) + } + + return nil +} + +func (web *Web) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + // Join internally call path.Clean to prevent directory traversal + path := filepath.Join(web.cfg.Directory, req.URL.Path) + + // check whether a file exists or is a directory at the given path + fi, err := os.Stat(path) + if os.IsNotExist(err) || fi.IsDir() { + // file does not exist or path is a directory, serve index.html + http.ServeFile(rw, req, filepath.Join(web.cfg.Directory, indexFileName)) + return + } + + if err != nil { + // if we got an error (that wasn't that the file doesn't exist) stating the + // file, return a 500 internal server error and stop + // TODO: Put down a crash html page here + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + // otherwise, use http.FileServer to serve the static file + http.FileServer(http.Dir(web.cfg.Directory)).ServeHTTP(rw, req) +} diff --git a/pkg/web/web_test.go b/pkg/web/routerweb/provider_test.go similarity index 91% rename from pkg/web/web_test.go rename to pkg/web/routerweb/provider_test.go index d5111cf747..a63c3e90c3 100644 --- a/pkg/web/web_test.go +++ b/pkg/web/routerweb/provider_test.go @@ -1,4 +1,4 @@ -package web +package routerweb import ( "io" @@ -11,6 +11,7 @@ import ( "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.signoz.io/signoz/pkg/web" "go.uber.org/zap" ) @@ -22,7 +23,7 @@ func TestServeHttpWithoutPrefix(t *testing.T) { expected, err := io.ReadAll(fi) require.NoError(t, err) - web, err := New(zap.NewNop(), Config{Prefix: "/", Directory: filepath.Join("testdata")}) + web, err := New(zap.NewNop(), web.Config{Prefix: "/", Directory: filepath.Join("testdata")}) require.NoError(t, err) router := mux.NewRouter() @@ -87,7 +88,7 @@ func TestServeHttpWithPrefix(t *testing.T) { expected, err := io.ReadAll(fi) require.NoError(t, err) - web, err := New(zap.NewNop(), Config{Prefix: "/web", Directory: filepath.Join("testdata")}) + web, err := New(zap.NewNop(), web.Config{Prefix: "/web", Directory: filepath.Join("testdata")}) require.NoError(t, err) router := mux.NewRouter() diff --git a/pkg/web/testdata/index.html b/pkg/web/routerweb/testdata/index.html similarity index 100% rename from pkg/web/testdata/index.html rename to pkg/web/routerweb/testdata/index.html diff --git a/pkg/web/web.go b/pkg/web/web.go index 2e29b000f9..ace1005506 100644 --- a/pkg/web/web.go +++ b/pkg/web/web.go @@ -1,94 +1,15 @@ package web import ( - "fmt" "net/http" - "os" - "path/filepath" - "time" "github.com/gorilla/mux" - "go.signoz.io/signoz/pkg/http/middleware" - "go.uber.org/zap" ) -var _ http.Handler = (*Web)(nil) - -const ( - indexFileName string = "index.html" -) - -type Web struct { - logger *zap.Logger - cfg Config -} - -func New(logger *zap.Logger, cfg Config) (*Web, error) { - if logger == nil { - return nil, fmt.Errorf("cannot build web, logger is required") - } - - fi, err := os.Stat(cfg.Directory) - if err != nil { - return nil, fmt.Errorf("cannot access web directory: %w", err) - } - - ok := fi.IsDir() - if !ok { - return nil, fmt.Errorf("web directory is not a directory") - } - - fi, err = os.Stat(filepath.Join(cfg.Directory, indexFileName)) - if err != nil { - return nil, fmt.Errorf("cannot access %q in web directory: %w", indexFileName, err) - } - - if os.IsNotExist(err) || fi.IsDir() { - return nil, fmt.Errorf("%q does not exist", indexFileName) - } - - return &Web{ - logger: logger.Named("go.signoz.io/pkg/web"), - cfg: cfg, - }, nil -} - -func (web *Web) AddToRouter(router *mux.Router) error { - cache := middleware.NewCache(7 * 24 * time.Hour) - err := router.PathPrefix(web.cfg.Prefix). - Handler( - http.StripPrefix( - web.cfg.Prefix, - cache.Wrap(http.HandlerFunc(web.ServeHTTP)), - ), - ).GetError() - if err != nil { - return fmt.Errorf("unable to add web to router: %w", err) - } - - return nil -} - -func (web *Web) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - // Join internally call path.Clean to prevent directory traversal - path := filepath.Join(web.cfg.Directory, req.URL.Path) - - // check whether a file exists or is a directory at the given path - fi, err := os.Stat(path) - if os.IsNotExist(err) || fi.IsDir() { - // file does not exist or path is a directory, serve index.html - http.ServeFile(rw, req, filepath.Join(web.cfg.Directory, indexFileName)) - return - } - - if err != nil { - // if we got an error (that wasn't that the file doesn't exist) stating the - // file, return a 500 internal server error and stop - // TODO: Put down a crash html page here - http.Error(rw, err.Error(), http.StatusInternalServerError) - return - } - - // otherwise, use http.FileServer to serve the static file - http.FileServer(http.Dir(web.cfg.Directory)).ServeHTTP(rw, req) +// Web is the interface that wraps the methods of the web package. +type Web interface { + // AddToRouter adds the web routes to an existing router. + AddToRouter(router *mux.Router) error + // ServeHTTP serves the web routes. + http.Handler }