aboutsummaryrefslogtreecommitdiff
path: root/lib/http
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2026-02-11 20:52:42 +0700
committerShulhan <ms@kilabit.info>2026-02-11 20:53:23 +0700
commit37c0e3f259204842c1ac82a04effb6c12e76078d (patch)
tree37533f2f6e351bc7e5b3158b539ad948526706ce /lib/http
parent9569814020e7122b61d88fa4afd39989e2bfcfb2 (diff)
downloadpakakeh.go-37c0e3f259204842c1ac82a04effb6c12e76078d.tar.xz
lib/http: add BasePath to the ServerOptions
The BasePath allow server to serve HTTP from custom prefix, other than "/". Each request that server received will remove the BasePath first from the [http.Request.URL.Path] before passing to the handler. Each redirect that server sent will add the BasePath as the prefix to redirect URL. Any trailing slash in the BasePath will be removed.
Diffstat (limited to 'lib/http')
-rw-r--r--lib/http/server.go15
-rw-r--r--lib/http/server_options.go13
2 files changed, 26 insertions, 2 deletions
diff --git a/lib/http/server.go b/lib/http/server.go
index 64ac5c14..4501cb9f 100644
--- a/lib/http/server.go
+++ b/lib/http/server.go
@@ -1,6 +1,5 @@
-// SPDX-FileCopyrightText: 2018 M. Shulhan <ms@kilabit.info>
-//
// SPDX-License-Identifier: BSD-3-Clause
+// SPDX-FileCopyrightText: 2018 M. Shulhan <ms@kilabit.info>
package http
@@ -83,6 +82,11 @@ func (srv *Server) RedirectTemp(res http.ResponseWriter, redirectURL string) {
if len(redirectURL) == 0 {
redirectURL = "/"
}
+ endWithSlash := redirectURL[len(redirectURL)-1] == '/'
+ redirectURL = path.Join(srv.Options.BasePath, redirectURL)
+ if endWithSlash {
+ redirectURL += `/`
+ }
res.Header().Set(HeaderLocation, redirectURL)
res.WriteHeader(http.StatusTemporaryRedirect)
}
@@ -319,6 +323,8 @@ func (srv *Server) registerPut(ep *Endpoint) (err error) {
// ServeHTTP handle mapping of client request to registered endpoints.
func (srv *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) {
+ req.URL.Path = strings.TrimPrefix(req.URL.Path, srv.Options.BasePath)
+
switch req.Method {
case http.MethodDelete:
srv.handleDelete(res, req)
@@ -481,6 +487,11 @@ func (srv *Server) HandleFS(res http.ResponseWriter, req *http.Request) {
// 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.
+ endWithSlash := redirectURL.Path[len(redirectURL.Path)-1] == '/'
+ redirectURL.Path = path.Join(srv.Options.BasePath, redirectURL.Path)
+ if endWithSlash {
+ redirectURL.Path += `/`
+ }
http.Redirect(res, req, redirectURL.String(), http.StatusMovedPermanently)
return
}
diff --git a/lib/http/server_options.go b/lib/http/server_options.go
index d51fe381..8e168885 100644
--- a/lib/http/server_options.go
+++ b/lib/http/server_options.go
@@ -8,6 +8,7 @@ import (
"log"
"net"
"net/http"
+ "strings"
"git.sr.ht/~shulhan/pakakeh.go/lib/memfs"
)
@@ -38,6 +39,16 @@ type ServerOptions struct {
// This field is optional, default to ":80".
Address string
+ // BasePath define the base path or prefix to serve the HTTP request
+ // and response.
+ // Each request that server received will remove the BasePath first
+ // from the [http.Request.URL.Path] before passing to the handler.
+ // Each redirect that server sent will add the BasePath as the prefix
+ // to redirect URL.
+ //
+ // Any trailing slash in the BasePath will be removed.
+ BasePath string
+
// Conn contains custom HTTP server connection.
// This fields is optional.
Conn *http.Server
@@ -64,6 +75,8 @@ func (opts *ServerOptions) init() {
opts.Address = ":80"
}
+ opts.BasePath = strings.TrimRight(opts.BasePath, `/`)
+
if opts.Conn == nil {
opts.Conn = &http.Server{
ReadTimeout: defRWTimeout,