made authentiaction work made install with makefile added login page (if auth required) added comments to default conf file
sophuwu sophie@sophuwu.com
Thu, 17 Jul 2025 01:13:40 +0200
12 files changed,
381 insertions(+),
61 deletions(-)
M
CFG/CFG.go
→
CFG/CFG.go
@@ -4,9 +4,9 @@ import (
"context" "errors" "fmt" + "git.sophuwu.com/gophuwu/flags" "git.sophuwu.com/manhttpd/neterr" "golang.org/x/sys/unix" - "log" "net/http" "os" "os/exec"@@ -86,11 +86,15 @@
func ParseConfig() { checkCmds() - if len(os.Args) > 1 && strings.HasSuffix(os.Args[1], ".conf") { - ConfFile = os.Args[1] + s, err := flags.GetStringFlag("conf") + if err != nil { + neterr.Fatal("Failed to get configuration file flag:", err) + } + if s != "" { + ConfFile = s } - err := parse() + err = parse() if err != nil { if !errors.Is(err, NoConfError) { neterr.Fatal("Failed to parse configuration file:", err)@@ -120,27 +124,29 @@ return ""
} func ListenAndServe(h http.Handler) { + var err error server := http.Server{ Addr: Addr + ":" + Port, Handler: h, } - var err error + sigchan := make(chan os.Signal) go func() { - if UseTLS && TLSCertFile != "" && TLSKeyFile != "" { - err = server.ListenAndServeTLS(TLSCertFile, TLSKeyFile) - } else { - err = server.ListenAndServe() - } - if err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Fatalf("Error starting server: %v", err) + signal.Notify(sigchan, unix.SIGINT, unix.SIGTERM, unix.SIGQUIT, unix.SIGKILL, unix.SIGSTOP) + <-sigchan + fmt.Println("Stopping server...") + err = server.Shutdown(context.Background()) + if err != nil { + fmt.Println("Error stopping server: %v", err) } }() - sigchan := make(chan os.Signal) - signal.Notify(sigchan, unix.SIGINT, unix.SIGTERM, unix.SIGQUIT, unix.SIGKILL, unix.SIGSTOP) - s := <-sigchan - println("stopping: got signal", s.String()) - err = server.Shutdown(context.Background()) - if err != nil { - log.Println("Error stopping server: %v", err) + fmt.Println("Starting server on", server.Addr) + if UseTLS && TLSCertFile != "" && TLSKeyFile != "" { + err = server.ListenAndServeTLS(TLSCertFile, TLSKeyFile) + } else { + err = server.ListenAndServe() + } + if err != nil && !errors.Is(err, http.ErrServerClosed) { + fmt.Println("Error starting server:", err) } + fmt.Println("Server stopped.") }
A
Makefile
@@ -0,0 +1,19 @@
+default: build +build: + go build -ldflags="-w -s" -trimpath -o build/manhttpd + +build_deb: ./build/manhttpd + cd extras && nfpm pkg --packager deb --config nfpm.yaml --target ../build/manhttpd.deb + +install_deb: ./build/manhttpd.deb + sudo apt-get install -y ./build/manhttpd.deb + +install_bin: ./build/manhttpd + sudo apt-get install -y mandoc + sudo sh ./extras/preinst.sh + sudo install ./build/manhttpd /usr/bin/manhttpd + sudo install ./extras/manhttpd-passwd /usr/bin/manhttpd-passwd + sudo install ./extras/manhttpd.service /etc/manhttpd/manhttpd.service + sudo install ./extras/manhttpd.conf /etc/manhttpd/manhttpd.conf + sudo sh ./extras/postinstall.sh +
M
README.md
→
README.md
@@ -27,8 +27,7 @@ This will also make the server available as a systemd service, and start it automatically. You may still want to configure a user for the service as some manuals may be in user home directories.
This isn't common on most systems, so the default configuration should work out of the box in most cases. ```bash -curl https://cdn.sophuwu.site/deb/addrepo.sh | sudo sh -sudo apt update +curl https://cdn.sophuwu.com/deb/addrepo.sh | sudo sh sudo apt install manhttpd ```@@ -44,15 +43,17 @@
## Compiling The Binary - ```sh -# download the source code -git clone "https://git.sophuwu.com/manhttpd" && cd manhttpd - -# build the binary with go -go build -ldflags="-s -w" -trimpath -o build/manhttpd + ```bash +git clone "https://git.sophuwu.com/manhttpd" +cd manhttpd -# install the binary into the system -sudo install ./build/manhttpd /usr/local/bin/manhttpd +# build binary +make build +make install_bin + +# build a debian package and install it +make build_deb +make install_deb ``` # Using As Systemd Service:@@ -128,5 +129,5 @@
I don't know how this git pull thing works. I will try if I see any issues. I've never collaborated on code before. If you have any suggestions, or questions about anything I've written, I would be happy to hear your thoughts.\ contant info: * discord: [@sophuwu](https://discord.com/users/sophuwu) -* email: [sophie@sophuwu.site](mailto:sophie@sophuwu.site) +* email: [sophie@sophuwu.com](mailto:sophie@sophuwu.com)
M
embeds/embeds.go
→
embeds/embeds.go
@@ -10,6 +10,7 @@ "html/template"
"io/fs" "net/http" "path/filepath" + "strings" ) //go:embed template/index.html@@ -17,6 +18,9 @@ var index string
//go:embed template/help.html var help string + +//go:embed template/login.html +var LoginPage string //go:embed static/* var static embed.FS@@ -82,6 +86,12 @@ t, e = template.New("index.html").Parse(index)
if e != nil { neterr.Fatal("Failed to parse index template:", e) } + LoginPage = strings.ReplaceAll(LoginPage, "{{ HostName }}", func() string { + if CFG.Hostname != "" { + return "@" + CFG.Hostname + } + return "" + }()) } func StaticFile(name string) (*StaticFS, bool) {
A
embeds/template/login.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>Login</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="?static=css" type="text/css"> + <script src="?static=js"></script> + <link rel="icon" href="?static=ico" type="image/x-icon"> + <style> + form { + width: fit-content!important; + margin: 0!important; + transform: translate(-50%,-50%) !important; + top: 50% !important; + position: absolute !important; + left: 50% !important; + } + h3 { + margin: 0 auto!important; + } + .inin { + width: 30ch!important; + } + .rounded { + margin-bottom: 0.5lh!important; + + } + .subbutt { + cursor: pointer!important; + border-radius: 1ch!important; + padding: 0.5ch 0.5lh!important; + display: block!important; + } + .subbutt:hover { + background-color: #0004!important; + } + </style> + <style id="styleCss"></style> + </head> + <body> + <header class="menu" id="search"> + <h3 style="cursor: pointer;" onclick="GoToRawQuery('');">ManWeb Login {{ HostName }}</h3> + </header> + <main id="main-content"> + <form method="POST" action="?authuwu:login"> + <div class="rounded"> + <label for="username">Username</label><input type="text" class="inin" autocomplete="off" id="username" name="username" required> + </div> + <div class="rounded"> + <label for="password">Password</label><input type="password" class="inin" autocomplete="off" id="password" name="password" required> + </div> + <div class="rounded"> + <input class="subbutt" type="submit" value="Login"> + </div> + </form> + </main> + </body> +</html>
A
extra/manhttpd-passwd
@@ -0,0 +1,28 @@
+#!/bin/bash + +# This script is used change the users and passwords for manhttpd +# This script must be run as root or with sudo +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root or with sudo" 1>&2 + exit 1 +fi + +if [[ "$1" == "" ]]; then + echo 'usage: manhttpd-passwd <username>' + exit 1 +fi +if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "-?" || "$1" == "help" ]]; then + sudo -u manhttpd /usr/bin/manhttpd --help + exit 0 +fi +declare runing="no" +systemctl is-active manhttpd >/dev/null 2>&1 +if [[ "$?" == "0" ]]; then + runing="yes" + systemctl stop manhttpd +fi +sudo -u manhttpd /usr/bin/manhttpd -pu $@ +if [[ "$runing" == "yes" ]]; then + systemctl start manhttpd +fi +
M
extra/manhttpd.conf
→
extra/manhttpd.conf
@@ -1,8 +1,51 @@
-#hostname -port 8082 -addr 0.0.0.0 -require_auth no -passwd_file /var/lib/manhttpd/authuwu -tldr_pages no -enable_stats no -statistic_db /var/lib/manhttpd/stats.db+## manhttpd.conf - Configuration file for the manhttpd server + +## manhttpd will read this file to configure its behavior +## The default location for this file is /etc/manhttpd/manhttpd.conf +## You can also specify a custom configuration file by using the -c option +## Example: manhttpd -c /path/to/custom/manhttpd.conf + + +## By default, the hostname in set from /etc/hostname +## Uncomment the line below to set a custom hostname +#hostname = myserver + +## By default, the port is set to 8082 +## Uncomment the line below to set a custom port +#port = 8082 + +## By default, the address is set to all interfaces +## Uncomment the line below to set a custom address +#addr = 0.0.0.0 + + +## By default, tldr_pages is set to no +## and tldr_dir is set to /var/lib/manhttpd/tldr +## Uncomment the line below to enable tldr_pages +#tldr_pages = yes +#tldr_dir = /var/lib/manhttpd/tldr + + +## manhttpd supports basic authentication. to edit auth credentials: +## sudo manhttpd-passwd <username> +## this will prompt you to enter a password for the user +## By default, require_auth is set to no, this disables authentication +## the default passwd_file is set to /var/lib/manhttpd/authuwu.db +## Uncomment the line below to enable tldr_pages +#require_auth = yes +#passwd_file = /var/lib/manhttpd/authuwu.db + + +## By default, enable_stats is set to no +## and statistic_db is set to /var/lib/manhttpd/stats.db +## Uncomment the line below to enable statistics collection +#enable_stats = yes +#statistic_db = /var/lib/manhttpd/stats.db + + +## By default, use_tls is set to no +## tls_cert and tls_key have no default values +## Uncomment the lines below to enable TLS +#use_tls = yes +#tls_cert = +#tls_key =
M
extra/nfpm.yaml
→
extra/nfpm.yaml
@@ -15,7 +15,7 @@ - mandoc
recommends: suggests: conflicts: -maintainer: "sophuwu <sophie@skisiel.com>" +maintainer: "sophuwu <sophie@sophuwu.com>" description: | manhttpd is a frontend for the linux man pages. Offering a functional, minimalistic interface for viewing and finding pages.@@ -25,13 +25,15 @@ - Search by section number
- Full regex name and description search It is useful for serving manpages over a network, or for browsing them in a web browser. -vendor: "sophuwu.site" +vendor: "sophuwu.com" homepage: "https://git.sophuwu.com/manhttpd" license: "MIT" changelog: "" contents: - src: ../build/manhttpd dst: /usr/bin/manhttpd +- src: ./manhttpd-passwd + dst: /usr/bin/manhttpd-passwd - src: ./manhttpd.service dst: /etc/manhttpd/manhttpd.service type: config
M
go.mod
→
go.mod
@@ -1,7 +1,15 @@
module git.sophuwu.com/manhttpd -go 1.23.0 +go 1.24.4 -toolchain go1.24.4 +require ( + git.sophuwu.com/authuwu v0.0.0-20250716222415-8755549e8fed + git.sophuwu.com/gophuwu v0.0.0-20250711231123-1d1d6daa6d8f + golang.org/x/sys v0.34.0 + golang.org/x/term v0.33.0 +) -require golang.org/x/sys v0.34.0 +require ( + github.com/asdine/storm/v3 v3.2.1 // indirect + go.etcd.io/bbolt v1.4.2 // indirect +)
M
go.sum
→
go.sum
@@ -1,2 +1,56 @@
+git.sophuwu.com/authuwu v0.0.0-20250716185239-acc2ef94bd9e h1:LeE1q3UoucDZf+O6xF6fUizBXo5e7Q9Hav5/SO+n34A= +git.sophuwu.com/authuwu v0.0.0-20250716185239-acc2ef94bd9e/go.mod h1:8Iwgnydo+Zud59xPW1HZKflqjVfXslLr0isASGRhj+M= +git.sophuwu.com/authuwu v0.0.0-20250716202553-43ab0ab7e160 h1:2Oy4q8J0cKHzFuSn/wW39KQqitDgsoErqLpUAfpRo8I= +git.sophuwu.com/authuwu v0.0.0-20250716202553-43ab0ab7e160/go.mod h1:8Iwgnydo+Zud59xPW1HZKflqjVfXslLr0isASGRhj+M= +git.sophuwu.com/authuwu v0.0.0-20250716210115-86d1e146d409 h1:AjJx1CpjN81WoHqt0Ar7P0Huuh3MX7BIGMQf9l2YEx8= +git.sophuwu.com/authuwu v0.0.0-20250716210115-86d1e146d409/go.mod h1:8Iwgnydo+Zud59xPW1HZKflqjVfXslLr0isASGRhj+M= +git.sophuwu.com/authuwu v0.0.0-20250716222415-8755549e8fed h1:ixaJKErKg3l5+1i5ArQtzEPemqMLPRybwpgOQ8ZWu6A= +git.sophuwu.com/authuwu v0.0.0-20250716222415-8755549e8fed/go.mod h1:8Iwgnydo+Zud59xPW1HZKflqjVfXslLr0isASGRhj+M= +git.sophuwu.com/gophuwu v0.0.0-20250711231123-1d1d6daa6d8f h1:xtZI73NLnlKbNoVtJiyIgp8s7exmyGCuNkcGZiFXc1Y= +git.sophuwu.com/gophuwu v0.0.0-20250711231123-1d1d6daa6d8f/go.mod h1:2j1SAWD5STcFV5oKUm4vChACQ1peXCKpfJLbgE/sD00= +github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863 h1:BRrxwOZBolJN4gIwvZMJY1tzqBvQgpaZiQRuIDD40jM= +github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM= +github.com/asdine/storm/v3 v3.2.1 h1:I5AqhkPK6nBZ/qJXySdI7ot5BlXSZ7qvDY1zAn5ZJac= +github.com/asdine/storm/v3 v3.2.1/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I= +go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20191105084925-a882066a44e0 h1:QPlSTtPE2k6PZPasQUbzuK3p9JbS+vMXYVto8g/yrsg= +golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
M
main.go
→
main.go
@@ -2,23 +2,94 @@ package main
import ( "fmt" + "git.sophuwu.com/authuwu" + "git.sophuwu.com/authuwu/userpass" + "git.sophuwu.com/gophuwu/flags" "git.sophuwu.com/manhttpd/CFG" "git.sophuwu.com/manhttpd/embeds" "git.sophuwu.com/manhttpd/manpage" "git.sophuwu.com/manhttpd/neterr" + "golang.org/x/term" "net/http" + "os" "os/exec" "regexp" "strings" + "time" ) func init() { + err := flags.NewFlag("conf", "c", "configuration file to use", "/etc/manhttpd/manhttpd.conf") + neterr.ChkFtl("creating conf flag:", err) + err = flags.NewFlag("passwd", "p", "open the program in password edit mode", false) + neterr.ChkFtl("creating passwd flag:", err) + err = flags.NewFlag("user", "u", "choose a username to set/change/delete password for", "") + neterr.ChkFtl("creating user flag:", err) + err = flags.ParseArgs() + neterr.ChkFtl("parsing flags:", err) CFG.ParseConfig() embeds.OpenAndParse() } +func setPasswd() { + u, err := flags.GetStringFlag("user") + if err != nil { + fmt.Println("getting user flag:", err) + return + } + if u == "" { + fmt.Println("no user specified, use -u <username> to set a password for a user") + return + } + var in []byte + fmt.Printf("Enter password for user %s (leave empty to delete user): \n", u) + in, err = term.ReadPassword(0) + if err != nil { + fmt.Println("could not read password:", err) + return + } + password := string(in) + if password == "" { + fmt.Printf("delete user %s? (y/N): ", u) + in = make([]byte, 1) + os.Stdin.Read(in) + if in[0] != 'y' && in[0] != 'Y' { + userpass.DeleteUser(u) + fmt.Printf("User %s deleted.\n", u) + return + } + fmt.Printf("exiting with no changes\n") + return + } + fmt.Println("Enter password again: ") + in, err = term.ReadPassword(0) + if err != nil { + fmt.Println("could not read password:", err) + return + } + if string(in) != password { + fmt.Println("Passwords do not match, please try again.") + return + } + err = userpass.NewUser(u, password) +} + func main() { - CFG.ListenAndServe(ManHandler{}) + b, err := flags.GetBoolFlag("passwd") + neterr.ChkFtl("getting passwd flag:", err) + if b { + err = authuwu.OpenDB(CFG.PasswdFile) + neterr.ChkFtl("opening password database:", err) + setPasswd() + authuwu.CloseDB() + return + } + if CFG.RequireAuth { + err = authuwu.OpenDB(CFG.PasswdFile) + neterr.ChkFtl("error opening password database:", err) + PageHandler = authuwu.NewAuthuwuHandler(PageHandler, time.Hour*24*3, embeds.LoginPage) + } + CFG.ListenAndServe(Handler) } var RxWords = regexp.MustCompile(`("[^"]+")|([^ ]+)`).FindAllString@@ -72,20 +143,7 @@ }
embeds.WriteHtml(w, r, "Search", output, q) } -type ManHandle interface { - ServeHTTP(http.ResponseWriter, *http.Request) -} - -type ManHandler struct { -} - -func (m ManHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // func IndexHandler(w http.ResponseWriter, r *http.Request) { - if r.URL.Query().Has("static") { - StaticHandler(w, r) - return - } - +var PageHandler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { SearchHandler(w, r) return@@ -109,7 +167,26 @@ }
title = man.Name } embeds.WriteHtml(w, r, title, html, name) - return +}) + +var Handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Query().Has("static") { + StaticHandler(w, r) + return + } + PageHandler.ServeHTTP(w, r) +}) + +type ManHandler struct { + h http.Handler +} + +func (m ManHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.URL.Query().Has("static") { + StaticHandler(w, r) + return + } + m.h.ServeHTTP(w, r) } func StaticHandler(w http.ResponseWriter, r *http.Request) {
M
neterr/neterr.go
→
neterr/neterr.go
@@ -5,9 +5,22 @@ "fmt"
"os" ) -func Fatal(v ...interface{}) { +func ChkFtl(str string, e error) { + if e == nil { + return + } + Fatal(str, e) +} + +func Fatal(v ...any) { fmt.Fprintln(os.Stderr, "manhttpd exited due to an error it could not recover from.") - fmt.Fprintf(os.Stderr, "Error: %s\n", fmt.Sprint(v...)) + fmt.Fprintf(os.Stderr, "Error: %s\n", func() string { + s := "" + for _, i := range v { + s += fmt.Sprintf("%v ", i) + } + return s + }()) os.Exit(1) }