diff options
| author | Shulhan <ms@kilabit.info> | 2024-03-15 14:51:48 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2024-03-15 14:53:43 +0700 |
| commit | 713d51e4792fb873d67d442553c0967e7fa0dc56 (patch) | |
| tree | 8d06441dd302c253bda3c2cac9a9e3f6694bead9 /lib/http | |
| parent | 625722e9087173d7b01acfb786de935fe09f4310 (diff) | |
| download | pakakeh.go-713d51e4792fb873d67d442553c0967e7fa0dc56.tar.xz | |
lib/http: refactoring FSHandler type to return [*memfs.Node]
Changing FSHandler type to return [*memfs.Node], allow the handler to
redirect or return custom node.
One of the use case is when service Single Page Application (SPA), where
route is handled by JavaScript.
For example, when user requested "/dashboard" but dashboard directory
does not exist, one can write the following handler to return
"/index.html",
{
node, _ = memfs.Get(`/index.html`)
return node
}
Diffstat (limited to 'lib/http')
| -rw-r--r-- | lib/http/fs_handler.go | 12 | ||||
| -rw-r--r-- | lib/http/http_test.go | 13 | ||||
| -rw-r--r-- | lib/http/server.go | 36 |
3 files changed, 35 insertions, 26 deletions
diff --git a/lib/http/fs_handler.go b/lib/http/fs_handler.go index 06d470f1..b88c13b4 100644 --- a/lib/http/fs_handler.go +++ b/lib/http/fs_handler.go @@ -12,12 +12,14 @@ import ( // FSHandler define the function to inspect each GET request to Server // [memfs.MemFS] instance. -// The node parameter contains the requested file inside the memfs. +// The node parameter contains the requested file inside the memfs or nil +// if the file does not exist. // -// If the handler return true, server will continue processing the node -// (writing the [memfs.Node] content type, body, and so on). +// If the handler return non-nil [*memfs.Node], server will continue +// processing the node, writing the [memfs.Node] content type, body, and so +// on. // -// If the handler return false, server stop processing the node and return +// 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) bool +type FSHandler func(node *memfs.Node, res http.ResponseWriter, req *http.Request) (out *memfs.Node) diff --git a/lib/http/http_test.go b/lib/http/http_test.go index c6872fe4..4cb40856 100644 --- a/lib/http/http_test.go +++ b/lib/http/http_test.go @@ -106,7 +106,12 @@ 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) bool { +func handleFS(node *memfs.Node, res http.ResponseWriter, req *http.Request) *memfs.Node { + if node == nil { + res.WriteHeader(http.StatusNotFound) + return nil + } + var ( lowerPath = strings.ToLower(node.Path) @@ -117,14 +122,14 @@ func handleFS(node *memfs.Node, res http.ResponseWriter, req *http.Request) bool cookieSid, err = req.Cookie("sid") if err != nil { http.Redirect(res, req, "/", http.StatusSeeOther) - return false + return nil } if cookieSid.Value != "authz" { http.Redirect(res, req, "/", http.StatusSeeOther) - return false + return nil } } - return true + return node } func registerEndpoints() { diff --git a/lib/http/server.go b/lib/http/server.go index 6cf8c70c..37ff71dc 100644 --- a/lib/http/server.go +++ b/lib/http/server.go @@ -419,22 +419,19 @@ func (srv *Server) HandleFS(res http.ResponseWriter, req *http.Request) { var ( logp = "HandleFS" - node *memfs.Node - responseETag string - requestETag string - size int64 - err error - isDir bool - ok bool + node *memfs.Node + err error + isDir bool ) node, isDir = srv.getFSNode(req.URL.Path) if node == nil { - res.WriteHeader(http.StatusNotFound) - return - } - - if isDir && req.URL.Path[len(req.URL.Path)-1] != '/' { + if srv.Options.HandleFS == nil { + res.WriteHeader(http.StatusNotFound) + return + } + // Fallthrough, call HandleFS below. + } else if isDir && req.URL.Path[len(req.URL.Path)-1] != '/' { // If request path is a directory and it is not end with // slash, redirect request to location with slash to allow // relative links works inside the HTML content. @@ -447,8 +444,8 @@ func (srv *Server) HandleFS(res http.ResponseWriter, req *http.Request) { } if srv.Options.HandleFS != nil { - ok = srv.Options.HandleFS(node, res, req) - if !ok { + node = srv.Options.HandleFS(node, res, req) + if node == nil { return } } @@ -457,8 +454,10 @@ func (srv *Server) HandleFS(res http.ResponseWriter, req *http.Request) { var nodeModtime = node.ModTime().Unix() - responseETag = strconv.FormatInt(nodeModtime, 10) - requestETag = req.Header.Get(HeaderIfNoneMatch) + var ( + responseETag = strconv.FormatInt(nodeModtime, 10) + requestETag = req.Header.Get(HeaderIfNoneMatch) + ) if requestETag == responseETag { res.WriteHeader(http.StatusNotModified) return @@ -477,7 +476,10 @@ func (srv *Server) HandleFS(res http.ResponseWriter, req *http.Request) { } } - var bodyReader io.ReadSeeker + var ( + bodyReader io.ReadSeeker + size int64 + ) if len(node.Content) > 0 { bodyReader = bytes.NewReader(node.Content) |
