From fd3c4f42e7a54040323e1c65d17f7e0c1cfd14a3 Mon Sep 17 00:00:00 2001 From: sneak Date: Tue, 20 Oct 2026 18:59:14 +0000 Subject: [PATCH] Serve the index page for an empty URL path instead of panicking (closes #149) setupSPA took the file name from request.URL.Path[1:], which panics when the path is empty, as it is for an absolute-form request line with no path ("GET http://host HTTP/1.1"). It now trims a leading "/" instead; an empty name fails to read, so the request gets the index page, as "/" already does. The new test in internal/server sends such a request and expects 200 and the index page. export_test.go gives it a Server whose router has only the web client route. Model: opus-5-5 --- internal/server/export_test.go | 12 ++++++++++ internal/server/routes.go | 5 ++++- internal/server/routes_test.go | 41 ++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 internal/server/export_test.go create mode 100644 internal/server/routes_test.go diff --git a/internal/server/export_test.go b/internal/server/export_test.go new file mode 100644 index 0000000..656b378 --- /dev/null +++ b/internal/server/export_test.go @@ -0,0 +1,12 @@ +package server + +import "github.com/go-chi/chi/v5" + +// NewTestSPAServer creates a Server whose router serves only +// the embedded web client. +func NewTestSPAServer() *Server { + srv := &Server{router: chi.NewRouter()} + srv.setupSPA() + + return srv +} diff --git a/internal/server/routes.go b/internal/server/routes.go index 1aa741b..f428c92 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -3,6 +3,7 @@ package server import ( "io/fs" "net/http" + "strings" "time" "sneak.berlin/go/neoirc/web" @@ -137,8 +138,10 @@ func (srv *Server) setupSPA() { return } + // The path is empty, not "/", for a request line such + // as "GET http://host HTTP/1.1". fileData, readErr := readFS.ReadFile( - request.URL.Path[1:], + strings.TrimPrefix(request.URL.Path, "/"), ) if readErr != nil || len(fileData) == 0 { indexHTML, indexErr := readFS.ReadFile( diff --git a/internal/server/routes_test.go b/internal/server/routes_test.go new file mode 100644 index 0000000..a98ff1b --- /dev/null +++ b/internal/server/routes_test.go @@ -0,0 +1,41 @@ +package server_test + +import ( + "io/fs" + "net/http" + "net/http/httptest" + "testing" + + "sneak.berlin/go/neoirc/internal/server" + "sneak.berlin/go/neoirc/web" +) + +// An absolute-form request line with no path, such as +// "GET http://example.com HTTP/1.1", leaves URL.Path empty. +func TestSPAServesIndexForEmptyPath(t *testing.T) { + t.Parallel() + + request := httptest.NewRequestWithContext( + t.Context(), http.MethodGet, "http://example.com", nil, + ) + if request.URL.Path != "" { + t.Fatalf("URL.Path is %q, want it empty", request.URL.Path) + } + + recorder := httptest.NewRecorder() + + server.NewTestSPAServer().ServeHTTP(recorder, request) + + if recorder.Code != http.StatusOK { + t.Fatalf("status %d, want %d", recorder.Code, http.StatusOK) + } + + indexHTML, err := fs.ReadFile(web.Dist, "dist/index.html") + if err != nil { + t.Fatal(err) + } + + if recorder.Body.String() != string(indexHTML) { + t.Errorf("body is not the index page") + } +} -- 2.54.0