httpserve

simple static HTTP server
git clone git://git.rr3.xyz/httpserve
Log | Files | Refs | README | LICENSE

commit d01fea585574b78ffdfbfe5ae667d6612116aeb3
Author: Robert Russell <robertrussell.72001@gmail.com>
Date:   Tue, 16 Jul 2024 22:19:26 -0700

Initial commit

Diffstat:
A.gitignore | 1+
Ago.mod | 5+++++
Ago.sum | 2++
Ahttpserve.1 | 15+++++++++++++++
Ahttpserve.go | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +httpserve diff --git a/go.mod b/go.mod @@ -0,0 +1,5 @@ +module rr3.xyz/httpserve + +go 1.22.5 + +require golang.org/x/sys v0.22.0 // indirect diff --git a/go.sum b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/httpserve.1 b/httpserve.1 @@ -0,0 +1,15 @@ +.TH "HTTPSERVE" "1" "2024-07-16" "httpserve" "User Commands" +.SH NAME +httpserve \- Simple static HTTP server +.SH SYNOPSIS +.nf +\fBtlsrp\fR \fBtcp\fR [\fIhost\fR]\fB:\fR[\fIport\fR] \fIroot\fR +.fi +.nf +\fBtlsrp\fR \fBunix\fR \fIpath\fR \fIroot\fR +.fi +.SH DESCRIPTION +httpserve serves static content on the indicated TCP or Unix address. For TCP, +\fIhost\fR defaults to all available unicast and anycast IP addresses of the +local system, and \fIport\fR defaults to being automatically chosen (and +logged to stderr). diff --git a/httpserve.go b/httpserve.go @@ -0,0 +1,57 @@ +package main + +import ( + "flag" + "fmt" + "golang.org/x/sys/unix" + "log" + "net" + "net/http" + "os" + "os/signal" +) + +func main() { + flag.Usage = func() { + format := `Usage: %[1]s tcp [HOST]:[PORT] ROOT_DIR + %[1]s unix PATH ROOT_DIR +` + fmt.Fprintf(os.Stderr, format, os.Args[0]) + os.Exit(1) + } + + flag.Parse() + if flag.NArg() != 3 { + flag.Usage() + } + args := flag.Args() + + network := args[0] + address := args[1] + root := args[2] + + // We catch termination signals so that we can properly close the socket. + // We must register the signal channel before calling net.Listen to avoid + // a race condition. + sigs := make(chan os.Signal, 3) + signal.Notify(sigs, unix.SIGINT, unix.SIGQUIT, unix.SIGTERM) + + listener, err := net.Listen(network, address) + if err != nil { + log.Fatal(err) + } + defer listener.Close() + + serveErr := make(chan error, 1) + go func () { + log.Printf("serving %s on %s\n", root, listener.Addr()) + serveErr <- http.Serve(listener, http.FileServer(http.Dir(root))) + }() + + select { + case err := <-serveErr: + log.Print(err) + case sig := <-sigs: + log.Printf("received signal %s; terminating\n", sig) + } +}