signoz/pkg/web/routerweb/provider.go

92 lines
2.3 KiB
Go

package routerweb
import (
"context"
"fmt"
"net/http"
"os"
"path/filepath"
"github.com/gorilla/mux"
"go.signoz.io/signoz/pkg/factory"
"go.signoz.io/signoz/pkg/http/middleware"
"go.signoz.io/signoz/pkg/web"
)
const (
indexFileName string = "index.html"
)
type provider struct {
config web.Config
}
func NewFactory() factory.ProviderFactory[web.Web, web.Config] {
return factory.NewProviderFactory(factory.MustNewName("router"), New)
}
func New(ctx context.Context, settings factory.ProviderSettings, config web.Config) (web.Web, error) {
fi, err := os.Stat(config.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(config.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 &provider{
config: config,
}, nil
}
func (provider *provider) AddToRouter(router *mux.Router) error {
cache := middleware.NewCache(0)
err := router.PathPrefix(provider.config.Prefix).
Handler(
http.StripPrefix(
provider.config.Prefix,
cache.Wrap(http.HandlerFunc(provider.ServeHTTP)),
),
).GetError()
if err != nil {
return fmt.Errorf("unable to add web to router: %w", err)
}
return nil
}
func (provider *provider) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// Join internally call path.Clean to prevent directory traversal
path := filepath.Join(provider.config.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(provider.config.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(provider.config.Directory)).ServeHTTP(rw, req)
}