Skip to content

Commit

Permalink
lib/http: refactoring FSHandler type to return [*memfs.Node]
Browse files Browse the repository at this point in the history
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
  }
  • Loading branch information
shuLhan committed Mar 15, 2024
1 parent 625722e commit 713d51e
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 26 deletions.
12 changes: 7 additions & 5 deletions lib/http/fs_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
13 changes: 9 additions & 4 deletions lib/http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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() {
Expand Down
36 changes: 19 additions & 17 deletions lib/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
}
}
Expand All @@ -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
Expand All @@ -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)
Expand Down

0 comments on commit 713d51e

Please sign in to comment.