diff options
| author | Shulhan <ms@kilabit.info> | 2022-03-31 01:34:37 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2022-03-31 01:34:37 +0700 |
| commit | d8057042e6c707e28a57508b6bfad0a6c4f3bd01 (patch) | |
| tree | 9dddfc19febf0bfe32b454a15aade88cae6b430d | |
| parent | 8a8de54d66fd14d1fbdb7e8598c597f871230980 (diff) | |
| download | pakakeh.go-d8057042e6c707e28a57508b6bfad0a6c4f3bd01.tar.xz | |
lib/http: rewrite ServerOptions FSHandler to handle request in general
This changes rename ServerOptions field FSAuthHandler to FSHandler and
rewrite their usage.
The FSHandler define the function to inspect each GET request to Server
MemFS instance.
The node parameter contains the requested file inside the memfs.
If the handler return true, server will continue processing the node
(writing the Node content type, body, and so on).
If the handler return false, server stop processing the node and return
immediately, which means the function should have already handle writing
the header, status code, and/or body.
| -rw-r--r-- | lib/http/fs_auth_handler.go | 16 | ||||
| -rw-r--r-- | lib/http/fs_handler.go | 25 | ||||
| -rw-r--r-- | lib/http/http_test.go | 40 | ||||
| -rw-r--r-- | lib/http/server.go | 16 | ||||
| -rw-r--r-- | lib/http/server_test.go | 21 | ||||
| -rw-r--r-- | lib/http/serveroptions.go | 9 |
6 files changed, 78 insertions, 49 deletions
diff --git a/lib/http/fs_auth_handler.go b/lib/http/fs_auth_handler.go deleted file mode 100644 index 9a793d64..00000000 --- a/lib/http/fs_auth_handler.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2022, Shulhan <ms@kilabit.info>. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package http - -import "net/http" - -// -// FSAuthHandler define the function to authorized each GET request to -// Server MemFS using value from the HTTP Request instance. -// -// If request is not authorized it must return false and the HTTP response -// will be set to 401 Unauthorized with empty body. -// -type FSAuthHandler func(req *http.Request) (ok bool) diff --git a/lib/http/fs_handler.go b/lib/http/fs_handler.go new file mode 100644 index 00000000..254dc782 --- /dev/null +++ b/lib/http/fs_handler.go @@ -0,0 +1,25 @@ +// Copyright 2022, Shulhan <ms@kilabit.info>. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http + +import ( + "net/http" + + "github.com/shuLhan/share/lib/memfs" +) + +// +// FSHandler define the function to inspect each GET request to Server MemFS +// instance. +// The node parameter contains the requested file inside the memfs. +// +// If the handler return true, server will continue processing the node +// (writing the Node content type, body, and so on). +// +// If the handler return false, 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 diff --git a/lib/http/http_test.go b/lib/http/http_test.go index d5eb2c44..33b8d017 100644 --- a/lib/http/http_test.go +++ b/lib/http/http_test.go @@ -58,8 +58,8 @@ func TestMain(m *testing.M) { Development: true, }, }, - HandleFSAuth: handleFSAuth, - Address: serverAddress, + HandleFS: handleFS, + Address: serverAddress, } testServerUrl = fmt.Sprintf("http://" + serverAddress) @@ -94,26 +94,32 @@ var ( testDownloadBody []byte ) -// handleFSAuth authenticate the request to Memfs using cookie. -// It will return true if request path is "/auth/" and cookie name "sid" exist -// with value "authz". -func handleFSAuth(req *http.Request) bool { +// +// handleFS authenticate the request to Memfs using cookie. +// +// If the node does not start with "/auth/" it will return true. +// +// 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 { var ( - lowerPath = strings.ToLower(req.URL.Path) + lowerPath = strings.ToLower(node.Path) cookieSid *http.Cookie err error ) - log.Printf("handleFSAuth: %s", lowerPath) - if !strings.HasPrefix(lowerPath, "/auth/") { - return true - } - cookieSid, err = req.Cookie("sid") - if err != nil { - return false - } - if cookieSid.Value != "authz" { - return false + if strings.HasPrefix(lowerPath, "/auth/") { + cookieSid, err = req.Cookie("sid") + if err != nil { + http.Redirect(res, req, "/", http.StatusSeeOther) + return false + } + if cookieSid.Value != "authz" { + http.Redirect(res, req, "/", http.StatusSeeOther) + return false + } } return true } diff --git a/lib/http/server.go b/lib/http/server.go index e6ef66b1..572edaee 100644 --- a/lib/http/server.go +++ b/lib/http/server.go @@ -484,14 +484,14 @@ func (srv *Server) handleDelete(res http.ResponseWriter, req *http.Request) { // HandleFS handle the request as resource in the memory file system. // This method only works if the Server.Options.Memfs is not nil. // +// If the request Path exists and Server Options FSHandler is set and +// returning false, it 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 exists and Server Options FSAuthHandler is set and -// returning false, it will return 401 Unauthorized. -// // If the request Path is not exist it will return 404 Not Found. // func (srv *Server) HandleFS(res http.ResponseWriter, req *http.Request) { @@ -504,7 +504,7 @@ func (srv *Server) HandleFS(res http.ResponseWriter, req *http.Request) { body []byte size int64 err error - isAuthorized bool + ok bool ) node = srv.getFSNode(req.URL.Path) @@ -513,11 +513,9 @@ func (srv *Server) HandleFS(res http.ResponseWriter, req *http.Request) { return } - if srv.Options.HandleFSAuth != nil { - req.URL.Path = node.Path - isAuthorized = srv.Options.HandleFSAuth(req) - if !isAuthorized { - res.WriteHeader(http.StatusUnauthorized) + if srv.Options.HandleFS != nil { + ok = srv.Options.HandleFS(node, res, req) + if !ok { return } } diff --git a/lib/http/server_test.go b/lib/http/server_test.go index a63bdb92..d613d2a8 100644 --- a/lib/http/server_test.go +++ b/lib/http/server_test.go @@ -788,12 +788,13 @@ func TestStatusError(t *testing.T) { } } -// TestServer_HandleFS_Auth test GET on memfs with authorization. -func TestServer_HandleFS_Auth(t *testing.T) { +// TestServer_Options_HandleFS test GET on memfs with authorization. +func TestServer_Options_HandleFS(t *testing.T) { type testCase struct { cookieSid *http.Cookie desc string reqPath string + expResBody string expStatusCode int } @@ -808,14 +809,17 @@ func TestServer_HandleFS_Auth(t *testing.T) { desc: "With public path", reqPath: "/index.html", expStatusCode: http.StatusOK, + expResBody: "<html><body>Hello, world!</body></html>\n", }, { desc: "With /auth.txt", reqPath: "/auth.txt", expStatusCode: http.StatusOK, + expResBody: "Hello, auth.txt!\n", }, { - desc: "With /auth path no cookie", + desc: "With /auth path no cookie, redirected to /", reqPath: "/auth", - expStatusCode: http.StatusUnauthorized, + expStatusCode: http.StatusOK, + expResBody: "<html><body>Hello, world!</body></html>\n", }, { desc: "With /auth path and cookie", reqPath: "/auth", @@ -824,6 +828,7 @@ func TestServer_HandleFS_Auth(t *testing.T) { Value: "authz", }, expStatusCode: http.StatusOK, + expResBody: "<html><body>Hello, authorized world!</body></html>\n", }, { desc: "With invalid /auth path and cookie", reqPath: "/auth/notexist", @@ -840,6 +845,7 @@ func TestServer_HandleFS_Auth(t *testing.T) { Value: "authz", }, expStatusCode: http.StatusOK, + expResBody: "<html><body>Hello, /auth/sub!</body></html>\n", }} for _, c = range cases { @@ -858,5 +864,12 @@ func TestServer_HandleFS_Auth(t *testing.T) { } test.Assert(t, c.desc, c.expStatusCode, res.StatusCode) + + gotBody, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatalf("%s: %s", c.desc, err) + } + + test.Assert(t, "response body", c.expResBody, string(gotBody)) } } diff --git a/lib/http/serveroptions.go b/lib/http/serveroptions.go index b548d09c..968659b2 100644 --- a/lib/http/serveroptions.go +++ b/lib/http/serveroptions.go @@ -26,9 +26,12 @@ type ServerOptions struct { // See https://pkg.go.dev/github.com/shuLhan/share/lib/memfs#hdr-Go_embed Memfs *memfs.MemFS - // HandleFSAuth handle authorization to GET request on Memfs. - // If null it means all request is allowed. - HandleFSAuth FSAuthHandler + // HandleFS inspect each GET request to Memfs. + // Some usage of this handler is to check for authorization on + // specific path, handling redirect, and so on. + // If nil it means all request are allowed. + // See FSHandler for more information. + HandleFS FSHandler // Address define listen address, using ip:port format. // This field is optional, default to ":80". |
