aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.adoc21
-rw-r--r--lib/http/server.go15
-rw-r--r--lib/http/server_options.go13
-rw-r--r--pakakeh.go2
4 files changed, 48 insertions, 3 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 85f68dd7..666dbaad 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -37,6 +37,27 @@ Legend,
* 🌼: Enhancement
* 💧: Chores
+
+[#v0_61_1]
+== pakakeh.go v0.61.1 (2026-xx-xx)
+//{{{
+
+[#v0_61_1_lib_http]
+=== 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.
+
+
+//}}}
[#v0_61_0]
== pakakeh.go v0.61.0 (2026-02-09)
//{{{
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,
diff --git a/pakakeh.go b/pakakeh.go
index 68c25910..97ad48f2 100644
--- a/pakakeh.go
+++ b/pakakeh.go
@@ -6,4 +6,4 @@
package pakakeh
// Version of this module.
-var Version = `0.61.0`
+var Version = `0.61.1`