From 60d0304aa05500fe4971a04d3d78f8e875b796a2 Mon Sep 17 00:00:00 2001 From: Maxim Lebedev Date: Wed, 14 Feb 2024 22:42:49 +0600 Subject: [PATCH] :recycle: Refactored static HTTP delivery --- internal/cmd/home/home.go | 17 +++++++++----- internal/static/delivery/http/static_http.go | 22 +++++++------------ .../static/delivery/http/static_http_test.go | 14 ++++++++---- ...TP.golden => TestHandler_ServeHTTP.golden} | 0 4 files changed, 29 insertions(+), 24 deletions(-) rename internal/static/delivery/http/testdata/{Handler_ServeHTTP.golden => TestHandler_ServeHTTP.golden} (100%) diff --git a/internal/cmd/home/home.go b/internal/cmd/home/home.go index b664a19..bad5aa9 100644 --- a/internal/cmd/home/home.go +++ b/internal/cmd/home/home.go @@ -27,6 +27,7 @@ import ( servercase "source.toby3d.me/toby3d/home/internal/server/usecase" sitefsrepo "source.toby3d.me/toby3d/home/internal/site/repository/fs" siteucase "source.toby3d.me/toby3d/home/internal/site/usecase" + statichttpdelivery "source.toby3d.me/toby3d/home/internal/static/delivery/http" staticfsrepo "source.toby3d.me/toby3d/home/internal/static/repository/fs" staticucase "source.toby3d.me/toby3d/home/internal/static/usecase" themefsrepo "source.toby3d.me/toby3d/home/internal/theme/repository/fs" @@ -63,13 +64,17 @@ func NewApp(logger *log.Logger, config *domain.Config) (*App, error) { webfingerer := webfingerucase.NewWebFingerUseCase(sites) webfingerHandler := webfingerhttpdelivery.NewHandler(webfingerer) entryHandler := entryhttpdelivery.NewHandler(siter, entrier, themer) + staticHandler := statichttpdelivery.NewHandler(staticer) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // NOTE(toby3d): any static file is public and unprotected by - // design, so it's safe to search it first before deep down to - // any page or it's resource which might be protected by - // middleware or something else. - if static, err := staticer.Do(r.Context(), r.URL.Path); err == nil { - http.ServeContent(w, r, static.Name(), static.ModTime(), static) + // NOTE(toby3d): any file in $HOME_STATIC_DIR is public and + // unprotected by design, so it's safe to search it first before + // deep down to any page or it's resource which might be + // protected by middleware or something else. + if handler, err := staticHandler.Handle(r.Context(), r.URL.Path); err == nil { + handler.ServeHTTP(w, r) + + return + } return } diff --git a/internal/static/delivery/http/static_http.go b/internal/static/delivery/http/static_http.go index 01206e0..ce6c489 100644 --- a/internal/static/delivery/http/static_http.go +++ b/internal/static/delivery/http/static_http.go @@ -1,11 +1,9 @@ package http import ( - "errors" - "io/fs" + "context" + "fmt" "net/http" - "path" - "strings" "source.toby3d.me/toby3d/home/internal/static" ) @@ -18,17 +16,13 @@ func NewHandler(static static.UseCase) *Handler { return &Handler{static: static} } -func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - s, err := h.static.Do(r.Context(), strings.TrimPrefix(path.Clean(r.URL.Path), "/")) +func (h *Handler) Handle(ctx context.Context, path string) (http.Handler, error) { + static, err := h.static.Do(ctx, path) if err != nil { - if errors.Is(err, fs.ErrNotExist) { - http.NotFound(w, r) - } else { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - - return + return nil, fmt.Errorf("cannot handle static: %w", err) } - http.ServeContent(w, r, s.Name(), s.ModTime(), s) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.ServeContent(w, r, static.Name(), static.ModTime(), static) + }), nil } diff --git a/internal/static/delivery/http/static_http_test.go b/internal/static/delivery/http/static_http_test.go index 85443a8..897a6c4 100644 --- a/internal/static/delivery/http/static_http_test.go +++ b/internal/static/delivery/http/static_http_test.go @@ -1,6 +1,7 @@ package http_test import ( + "context" "net/http" "net/http/httptest" "strings" @@ -18,11 +19,16 @@ func TestHandler_ServeHTTP(t *testing.T) { t.Parallel() req := httptest.NewRequest(http.MethodGet, "/robots.txt", nil) - w := httptest.NewRecorder() - testStatic := domain.NewStatic(strings.NewReader("User-agent: *\nAllow: /"), time.Now().UTC(), "robots.txt") - delivery.NewHandler(usecase.NewStaticUseCase(repository.NewStubStaticRepository(nil, testStatic, false))). - ServeHTTP(w, req) + staticService := usecase.NewStaticUseCase(repository.NewStubStaticRepository(nil, testStatic, false)) + + handler, err := delivery.NewHandler(staticService).Handle(context.Background(), req.URL.Path) + if err != nil { + t.Fatal(err) + } + + w := httptest.NewRecorder() + handler.ServeHTTP(w, req) resp := w.Result() if expect := http.StatusOK; resp.StatusCode != expect { diff --git a/internal/static/delivery/http/testdata/Handler_ServeHTTP.golden b/internal/static/delivery/http/testdata/TestHandler_ServeHTTP.golden similarity index 100% rename from internal/static/delivery/http/testdata/Handler_ServeHTTP.golden rename to internal/static/delivery/http/testdata/TestHandler_ServeHTTP.golden