Documentation
¶
Overview ¶
Example ¶
package main
import (
"context"
"flag"
"log/slog"
"net/http"
"os"
"github.com/linkdata/webserv"
)
var (
flagAddress = flag.String("address", os.Getenv("WEBSERV_ADDRESS"), "serve HTTP requests on given [address][:port]")
flagCertDir = flag.String("certdir", os.Getenv("WEBSERV_CERTDIR"), "where to find fullchain.pem and privkey.pem")
flagUser = flag.String("user", envOrDefault("WEBSERV_USER", "www-data"), "switch to this user after startup (*nix only)")
flagDataDir = flag.String("datadir", envOrDefault("WEBSERV_DATADIR", "$HOME"), "where to store data files after startup")
flagListenURL = flag.String("listenurl", os.Getenv("WEBSERV_LISTENURL"), "specify the external URL clients can reach us at")
)
func envOrDefault(envvar, defval string) (s string) {
if s = os.Getenv(envvar); s == "" {
s = defval
}
return
}
func main() {
flag.Parse()
cfg := webserv.Config{
Address: *flagAddress,
CertDir: *flagCertDir,
User: *flagUser,
DataDir: *flagDataDir,
ListenURL: *flagListenURL,
Logger: slog.Default(),
}
http.DefaultServeMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("<html><body>Hello world!</body></html>"))
})
l, err := cfg.Listen()
if err == nil {
if err = cfg.Serve(context.Background(), l, nil); err == nil {
return
}
}
slog.Error(err.Error())
}
Index ¶
- Constants
- Variables
- func BecomeUser(userName string) error
- func DefaultDataDir(dataDir, defaultSuffix string) (result string, err error)
- func Listener(listenAddr, certDir, fullchainPem, privkeyPem, overrideUrl string) (l net.Listener, listenUrl, absCertDir string, err error)
- func LoadCert(certDir, fullchainPem, privkeyPem string) (cert *tls.Certificate, absCertDir string, err error)
- func UseDataDir(dataDir string, mode fs.FileMode) (string, error)
- type Config
- func (cfg *Config) Listen() (l net.Listener, err error)
- func (cfg *Config) ListenAndServe(ctx context.Context, handler http.Handler) (err error)
- func (cfg *Config) Serve(ctx context.Context, l net.Listener, handler http.Handler) error
- func (cfg *Config) ServeWith(ctx context.Context, srv *http.Server, l net.Listener) (err error)
- type Logger
Examples ¶
Constants ¶
const ( FullchainPem = "fullchain.pem" PrivkeyPem = "privkey.pem" )
Variables ¶
var ErrBecomeUser = errBecomeUser{}
var ShutdownTimeLimit = time.Second
Functions ¶
func BecomeUser ¶
BecomeUser switches to the given userName if not empty.
It sets the GID, UID and changes the USER and HOME environment variables accordingly. It unsets XDG_CONFIG_HOME.
Returns ErrBecomeUserNotImplemented if the current OS is not supported.
func DefaultDataDir ¶
DefaultDataDir returns the absolute path to dataDir if not empty, otherwise if defaultSuffix is not empty it returns the absolute joined path of os.UserConfigDir() and defaultSuffix.
It will expand environment variables in the path before evaluating the absolute path.
dataDir and defaultSuffix may contain paths, ".." segments and symlinks. They are not confined to UserConfigDir, so they may resolve outside of it. Caller is responsible for validating or sandboxing untrusted path input.
func Listener ¶
func Listener(listenAddr, certDir, fullchainPem, privkeyPem, overrideUrl string) (l net.Listener, listenUrl, absCertDir string, err error)
Listener creates a net.Listener given an optional preferred address or port and an optional directory containing certificate files.
If certDir is not empty, it calls LoadCert to load fullchain.pem and privkey.pem.
The listener will default to all addresses and standard port depending on privileges and if a certificate was loaded or not.
These defaults can be overridden with the listenAddr argument.
Returns the net.Listener and listenURL if there was no error. If certificates were successfully loaded, absCertDir will be the absolute path to that directory.
func LoadCert ¶
func LoadCert(certDir, fullchainPem, privkeyPem string) (cert *tls.Certificate, absCertDir string, err error)
LoadCert does nothing if certDir is empty, otherwise it expands environment variables and transforms it into an absolute path. It then tries to load a X509 key pair from the files named fullchainPem and privkeyPem from the resulting directory.
The filenames may contain paths, ".." segments and symlinks. They are not confined to certDir, so they may resolve outside of it. Caller is responsible for validating or sandboxing untrusted path input.
If fullchainPem is empty, it defaults to "fullchain.pem". If privkeyPem is empty, it defaults to "privkey.pem".
Return a non-nil cert and absolute path to certDir if there are no errors.
func UseDataDir ¶
UseDataDir transforms dataDir into an absolute path. Then, if mode is not zero, it creates the path if it does not exist. Does nothing if dataDir is empty. Does not expand environment variables in the path.
Returns the final path or an empty string if dataDir was empty.
Types ¶
type Config ¶
type Config struct {
Address string // optional specific address (and/or port) to listen on
CertDir string // if set, directory to look for fullchain.pem and privkey.pem
FullchainPem string // set to override filename for "fullchain.pem"
PrivkeyPem string // set to override filename for "privkey.pem"
User string // if set, user to switch to after opening listening port
DataDir string // if set, create this directory, if unset will be filled in after Listen
DefaultDataDirSuffix string // if set and DataDir is not set, set DataDir to the user's default data dir plus this suffix
DataDirMode fs.FileMode // if nonzero, create DataDir if it does not exist using this mode
ListenURL string // if set, the external URL clients can reach us at. If unset, Listen may fill this in (e.g. "https://localhost:8443"), even when Listen later returns an error after binding.
Logger Logger // logger to use, if nil logs nothing
}
func (*Config) Listen ¶
Listen performs initial setup for a simple web server and returns a net.Listener if successful.
First it loads certificates if cfg.CertDir is set, and then starts a net.Listener (TLS or normal). The listener will default to all addresses and standard port depending on privileges and if a certificate was loaded or not.
If cfg.Address was set, any address or port given there overrides these defaults.
If cfg.User is set it then switches to that user and the users primary group. Note that this is not supported on Windows.
If cfg.DataDir or cfg.DefaultDataDirSuffix is set, calculates the absolute data directory path and sets cfg.DataDir. If cfg.DataDirMode is nonzero, the directory will be created if necessary.
On return, cfg.CertDir and cfg.DataDir will be absolute paths or be empty. If cfg.ListenURL was empty it may be set to a best-guess printable and connectable URL like "http://localhost:80" as soon as the socket is opened. Therefore cfg.ListenURL can be non-empty even if Listen returns an error from a later step, such as user switching or data directory setup.
func (*Config) ListenAndServe ¶ added in v0.9.0
ListenAndServe calls Listen followed by Serve.
func (*Config) Serve ¶ added in v0.9.0
Serve creates a http.Server with reasonable defaults and calls ServeWith.
func (*Config) ServeWith ¶ added in v0.9.1
ServeWith sets up a signal handler to catch SIGINT and SIGTERM and then calls srv.Serve(l). If ctx is canceled, the server will be shut down and this function returns with ctx.Err().
Returns nil if the server started successfully and then cleanly shut down.
Panics if any of the arguments are nil.