From 2dbd14b6dc771ced66777b8acfc6e6e421f9689e Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Mon, 4 May 2015 16:23:16 -0600 Subject: [PATCH] Consistent app name/version info; pipe config data through stdin --- config/config.go | 21 +++++--- config/parse/dispenser.go | 2 +- config/setup/fastcgi.go | 7 +-- config/setup/websocket.go | 9 +--- main.go | 81 ++++++++++++++++++------------ middleware/websockets/websocket.go | 2 +- server/config.go | 6 +++ 7 files changed, 78 insertions(+), 50 deletions(-) diff --git a/config/config.go b/config/config.go index bde7854eb..bb363c53f 100644 --- a/config/config.go +++ b/config/config.go @@ -19,13 +19,6 @@ const ( DefaultConfigFile = "Caddyfile" ) -// These three defaults are configurable through the command line -var ( - Root = DefaultRoot - Host = DefaultHost - Port = DefaultPort -) - func Load(filename string, input io.Reader) ([]server.Config, error) { var configs []server.Config @@ -46,6 +39,9 @@ func Load(filename string, input io.Reader) ([]server.Config, error) { Host: sb.Host, Port: sb.Port, Middleware: make(map[string][]middleware.Middleware), + ConfigFile: filename, + AppName: AppName, + AppVersion: AppVersion, } // It is crucial that directives are executed in the proper order. @@ -105,3 +101,14 @@ func Default() server.Config { Port: Port, } } + +// These three defaults are configurable through the command line +var ( + Root = DefaultRoot + Host = DefaultHost + Port = DefaultPort +) + +// The application should set these so that various middlewares +// can access the proper information for their own needs. +var AppName, AppVersion string diff --git a/config/parse/dispenser.go b/config/parse/dispenser.go index 0f5c19415..13789f12f 100644 --- a/config/parse/dispenser.go +++ b/config/parse/dispenser.go @@ -199,7 +199,7 @@ func (d *Dispenser) Err(msg string) error { // Errf is like Err, but for formatted error messages func (d *Dispenser) Errf(format string, args ...interface{}) error { - return d.Err(fmt.Sprintf(format, args...)) // TODO: I think args needs to be args... + return d.Err(fmt.Sprintf(format, args...)) } // numLineBreaks counts how many line breaks are in the token diff --git a/config/setup/fastcgi.go b/config/setup/fastcgi.go index 657affd53..fe5e734a9 100644 --- a/config/setup/fastcgi.go +++ b/config/setup/fastcgi.go @@ -25,9 +25,10 @@ func FastCGI(c *Controller) (middleware.Middleware, error) { Next: next, Rules: rules, Root: root, - SoftwareName: "Caddy", // TODO: Once generators are not in the same pkg as handler, obtain this from some global const - SoftwareVersion: "", // TODO: Get this from some global const too - // TODO: Set ServerName and ServerPort to correct values... (as user defined in config) + SoftwareName: c.AppName, + SoftwareVersion: c.AppVersion, + ServerName: c.Host, + ServerPort: c.Port, } }, nil } diff --git a/config/setup/websocket.go b/config/setup/websocket.go index d3ad2df8a..33f0a27db 100644 --- a/config/setup/websocket.go +++ b/config/setup/websocket.go @@ -68,15 +68,10 @@ func WebSocket(c *Controller) (middleware.Middleware, error) { }) } - websockets.GatewayInterface = envGatewayInterface - websockets.ServerSoftware = envServerSoftware + websockets.GatewayInterface = c.AppName + "-CGI/1.1" + websockets.ServerSoftware = c.AppName + "/" + c.AppVersion return func(next middleware.Handler) middleware.Handler { return websockets.WebSockets{Next: next, Sockets: websocks} }, nil } - -const ( - envGatewayInterface = "caddy-CGI/1.1" - envServerSoftware = "caddy/" // TODO: Version -) diff --git a/main.go b/main.go index 7d14fdaf6..e1fcb098d 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,11 @@ package main import ( + "bytes" "errors" "flag" "fmt" + "io/ioutil" "log" "net" "os" @@ -18,14 +20,15 @@ import ( ) var ( - conf string - http2 bool // TODO: temporary flag until http2 is standard - quiet bool - cpu string + conf string + http2 bool // TODO: temporary flag until http2 is standard + quiet bool + cpu string + confBody []byte // configuration data to use, piped from stdin ) func init() { - flag.StringVar(&conf, "conf", config.DefaultConfigFile, "The configuration file to use") + flag.StringVar(&conf, "conf", "", "Configuration file to use") flag.BoolVar(&http2, "http2", true, "Enable HTTP/2 support") // TODO: temporary flag until http2 merged into std lib flag.BoolVar(&quiet, "quiet", false, "Quiet mode (no initialization output)") flag.StringVar(&cpu, "cpu", "100%", "CPU cap") @@ -33,6 +36,21 @@ func init() { flag.StringVar(&config.Host, "host", config.DefaultHost, "Default host") flag.StringVar(&config.Port, "port", config.DefaultPort, "Default port") flag.Parse() + + config.AppName = "Caddy" + config.AppVersion = "0.6.0" + + // Load piped configuration data, if any + fi, err := os.Stdin.Stat() + if err != nil { + log.Fatal(err) + } + if fi.Mode()&os.ModeCharDevice == 0 { + confBody, err = ioutil.ReadAll(os.Stdin) + if err != nil { + log.Fatal(err) + } + } } func main() { @@ -45,7 +63,7 @@ func main() { } // Load config from file - allConfigs, err := loadConfigs(conf) + allConfigs, err := loadConfigs() if err != nil { log.Fatal(err) } @@ -82,36 +100,37 @@ func main() { wg.Wait() } -// loadConfigs loads configuration from a file. -func loadConfigs(confPath string) ([]server.Config, error) { - var allConfigs []server.Config - - file, err := os.Open(confPath) - if err == nil { - defer file.Close() - allConfigs, err = config.Load(path.Base(confPath), file) +// loadConfigs loads configuration from a file or stdin (piped). +// Configuration is obtained from one of three sources, tried +// in this order: 1. -conf flag, 2. stdin, 3. Caddyfile. +// If none of those are available, a default configuration is +// loaded. +func loadConfigs() ([]server.Config, error) { + // -conf flag + if conf != "" { + file, err := os.Open(conf) if err != nil { - return allConfigs, err + return []server.Config{}, err } - } else { + defer file.Close() + return config.Load(path.Base(conf), file) + } + + // stdin + if len(confBody) > 0 { + return config.Load("stdin", bytes.NewReader(confBody)) + } + + // Caddyfile + file, err := os.Open(config.DefaultConfigFile) + if err != nil { if os.IsNotExist(err) { - // This is only a problem if the user - // explicitly specified a config file - if confPath != config.DefaultConfigFile { - return allConfigs, err - } - } else { - // ... but anything else is always a problem - return allConfigs, err + return []server.Config{config.Default()}, nil } + return []server.Config{}, err } - - // If config file was empty or didn't exist, use default - if len(allConfigs) == 0 { - allConfigs = []server.Config{config.Default()} - } - - return allConfigs, nil + defer file.Close() + return config.Load(config.DefaultConfigFile, file) } // arrangeBindings groups configurations by their bind address. For example, diff --git a/middleware/websockets/websocket.go b/middleware/websockets/websocket.go index fa213c4ec..4c843f052 100644 --- a/middleware/websockets/websocket.go +++ b/middleware/websockets/websocket.go @@ -63,7 +63,7 @@ func (ws WebSocket) buildEnv(cmdPath string) (metavars []string, err error) { `PATH_TRANSLATED=`, // TODO `QUERY_STRING=` + ws.URL.RawQuery, `REMOTE_ADDR=` + remoteHost, - `REMOTE_HOST=` + remoteHost, // TODO (Host lookups are slow; make this configurable) + `REMOTE_HOST=` + remoteHost, // Host lookups are slow - don't do them `REMOTE_IDENT=`, // Not used `REMOTE_PORT=` + remotePort, `REMOTE_USER=`, // Not used, diff --git a/server/config.go b/server/config.go index 40ba55e98..591f9a48c 100644 --- a/server/config.go +++ b/server/config.go @@ -34,6 +34,12 @@ type Config struct { // The path to the configuration file from which this was loaded ConfigFile string + + // The name of the application + AppName string + + // The application's version + AppVersion string } // Address returns the host:port of c as a string.