From e91954b5a65847970903e0d8294e54d918c8bc0b Mon Sep 17 00:00:00 2001 From: Shulhan Date: Tue, 6 Jan 2026 23:00:07 +0700 Subject: lib/http: add second return value, statusCode, to FSHandler Non-zero status code indicates that the function already response to the request, and the server will return immediately. Zero status code indicates that the function did not process the request, it is up to server to process the returned node `out`. --- CHANGELOG.adoc | 20 ++++++++++++++++++++ lib/http/fs_handler.go | 19 ++++++++++++------- lib/http/http_test.go | 29 ++++++++++++++++------------- lib/http/server.go | 14 +++++++++++--- lib/http/server_test.go | 6 +++++- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 13b03410..5d9c003d 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -27,6 +27,26 @@ This is changelog for `pakakeh.go` module since v0.12.0 until v0.21.0. link:CHANGELOG_2018-2019.html[Changelog from 2018 to 2019^]. This is changelog for `pakakeh.go` module since v0.1.0 until v0.11.0. +Legend, + +* 🪵: Breaking changes +* 🌱: New feature +* 🌼: Enhancement +* 💧: Chores + +//{{{ +[#v0_61_0] +== pakakeh.go v0.61.0 (2026-xx-xx) + +**🪵 lib/http: add second return value, statusCode, to FSHandler** + +Non-zero status code indicates that the function already response +to the request, and the server will return immediately. + +Zero status code indicates that the function did not process the request, +it is up to server to process the returned node `out`. + +//}}} //{{{ [#v0_60_2] == pakakeh.go v0.60.2 (2025-12-27) diff --git a/lib/http/fs_handler.go b/lib/http/fs_handler.go index b88c13b4..7dfca198 100644 --- a/lib/http/fs_handler.go +++ b/lib/http/fs_handler.go @@ -15,11 +15,16 @@ import ( // The node parameter contains the requested file inside the memfs or nil // if the file does not exist. // -// If the handler return non-nil [*memfs.Node], server will continue -// processing the node, writing the [memfs.Node] content type, body, and so -// on. +// This function return two values: the node `out` that is used to process the +// request and response; and the HTTP status code `statusCode` returned in +// response. // -// If the handler return nil, server stop processing the node and return -// immediately, which means the function should have already handle writing -// the header, status code, and/or body. -type FSHandler func(node *memfs.Node, res http.ResponseWriter, req *http.Request) (out *memfs.Node) +// Non-zero status code indicates that the function already response +// to the request, and the server will return immediately. +// +// Zero status code indicates that the function did not process the request, +// it is up to server to process the returned node `out`. +// The returned node `out` may be the same as `node`, modified, of completely +// new. +type FSHandler func(node *memfs.Node, res http.ResponseWriter, req *http.Request) ( + out *memfs.Node, statusCode int) diff --git a/lib/http/http_test.go b/lib/http/http_test.go index 4cb40856..fa0c9975 100644 --- a/lib/http/http_test.go +++ b/lib/http/http_test.go @@ -106,30 +106,33 @@ var ( // If the node path is start with "/auth/" and cookie name "sid" exist // with value "authz" it will return true; // otherwise it will redirect to "/" and return false. -func handleFS(node *memfs.Node, res http.ResponseWriter, req *http.Request) *memfs.Node { - if node == nil { - res.WriteHeader(http.StatusNotFound) - return nil - } - +func handleFS(node *memfs.Node, res http.ResponseWriter, req *http.Request) ( + out *memfs.Node, statusCode int, +) { var ( - lowerPath = strings.ToLower(node.Path) - + lowerPath string cookieSid *http.Cookie err error ) + if node == nil { + lowerPath = strings.ToLower(req.URL.Path) + } else { + lowerPath = strings.ToLower(node.Path) + } if strings.HasPrefix(lowerPath, "/auth/") { cookieSid, err = req.Cookie("sid") if err != nil { - http.Redirect(res, req, "/", http.StatusSeeOther) - return nil + statusCode = http.StatusSeeOther + http.Redirect(res, req, "/", statusCode) + return nil, statusCode } if cookieSid.Value != "authz" { - http.Redirect(res, req, "/", http.StatusSeeOther) - return nil + statusCode = http.StatusSeeOther + http.Redirect(res, req, "/", statusCode) + return nil, statusCode } } - return node + return node, 0 } func registerEndpoints() { diff --git a/lib/http/server.go b/lib/http/server.go index 5801832f..4c89032b 100644 --- a/lib/http/server.go +++ b/lib/http/server.go @@ -449,11 +449,13 @@ func (srv *Server) handleDelete(res http.ResponseWriter, req *http.Request) { // This method only works if the [ServerOptions.Memfs] is not nil. // // If the request Path exists and [ServerOptions.HandleFS] is set and -// returning false, it will return immediately. +// returning [*memfs.Node] with non-zero HTTP `statusCode`, server will return +// immediately. // // If the request Path exists in file system, it will return 200 OK with the // header Content-Type set accordingly to the detected file type and the // response body set to the content of file. +// // If the request Method is HEAD, only the header will be sent back to client. // // If the request Path is not exist it will return 404 Not Found. @@ -485,11 +487,17 @@ func (srv *Server) HandleFS(res http.ResponseWriter, req *http.Request) { } if srv.Options.HandleFS != nil { - node = srv.Options.HandleFS(node, res, req) - if node == nil { + var statusCode int + node, statusCode = srv.Options.HandleFS(node, res, req) + if statusCode != 0 { + // HandleFS already response to the request. return } } + if node == nil { + res.WriteHeader(http.StatusNotFound) + return + } res.Header().Set(HeaderContentType, node.ContentType) diff --git a/lib/http/server_test.go b/lib/http/server_test.go index a3a82d9e..6542d833 100644 --- a/lib/http/server_test.go +++ b/lib/http/server_test.go @@ -995,6 +995,10 @@ func TestServer_Options_HandleFS(t *testing.T) { }, expStatusCode: http.StatusOK, expResBody: "Hello, /auth/sub!\n", + }, { + desc: `With public path not exists`, + reqPath: `/index.php`, + expStatusCode: http.StatusNotFound, }} for _, c = range cases { @@ -1025,7 +1029,7 @@ func TestServer_Options_HandleFS(t *testing.T) { t.Fatalf("%s: %s", c.desc, err) } - test.Assert(t, "response body", c.expResBody, string(gotBody)) + test.Assert(t, c.desc+`: response body`, c.expResBody, string(gotBody)) } } -- cgit v1.3