diff --git a/README.md b/README.md index 7fa446f73..2d42d2e6c 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,12 @@ Caddy binaries have no dependencies and are available for every platform. Get Ca customize your build in the browser - **[Latest release](https://github.com/mholt/caddy/releases/latest)** for pre-built, vanilla binaries -- **go get** to build from source: `go get github.com/mholt/caddy/caddy` (requires Go 1.8 or newer) - to build with proper version information (required when filing issues), `cd` to the `caddy` folder and use `go get github.com/caddyserver/builds` followed by `go run build.go`. + +## Build +To build from source you need **[Git](https://git-scm.com/downloads)** and **[Go](https://golang.org/doc/install)** (1.8 or newer). Follow these instruction for fast building: + +- Get source `go get github.com/mholt/caddy/caddy` and then run `go get github.com/caddyserver/builds` +- Now `cd` to `$GOPATH/src/github.com/mholt/caddy/caddy` and run `go run build.go` Then make sure the `caddy` binary is in your PATH. diff --git a/assets_test.go b/assets_test.go index b0cee3b18..fa7931100 100644 --- a/assets_test.go +++ b/assets_test.go @@ -25,9 +25,15 @@ func TestAssetsPath(t *testing.T) { t.Errorf("Expected path to be a .caddy folder, got: %v", actual) } - os.Setenv("CADDYPATH", "testpath") + err := os.Setenv("CADDYPATH", "testpath") + if err != nil { + t.Error("Could not set CADDYPATH") + } if actual, expected := AssetsPath(), "testpath"; actual != expected { t.Errorf("Expected path to be %v, got: %v", expected, actual) } - os.Setenv("CADDYPATH", "") + err = os.Setenv("CADDYPATH", "") + if err != nil { + t.Error("Could not set CADDYPATH") + } } diff --git a/caddy.go b/caddy.go index 902a1a394..032d8721c 100644 --- a/caddy.go +++ b/caddy.go @@ -206,12 +206,15 @@ func (i *Instance) Restart(newCaddyfile Input) (*Instance, error) { // success! stop the old instance for _, shutdownFunc := range i.onShutdown { - err := shutdownFunc() + err = shutdownFunc() if err != nil { return i, err } } - i.Stop() + err = i.Stop() + if err != nil { + return i, err + } // Execute instantiation events EmitEvent(InstanceStartupEvent, newInst) @@ -483,14 +486,14 @@ func startWithListenerFds(cdyfile Input, inst *Instance, restartFds map[string]r if !IsUpgrade() && restartFds == nil { // first startup means not a restart or upgrade for _, firstStartupFunc := range inst.onFirstStartup { - err := firstStartupFunc() + err = firstStartupFunc() if err != nil { return err } } } for _, startupFunc := range inst.onStartup { - err := startupFunc() + err = startupFunc() if err != nil { return err } @@ -565,12 +568,7 @@ func ValidateAndExecuteDirectives(cdyfile Input, inst *Instance, justValidate bo return err } - err = executeDirectives(inst, cdyfile.Path(), stype.Directives(), sblocks, justValidate) - if err != nil { - return err - } - - return nil + return executeDirectives(inst, cdyfile.Path(), stype.Directives(), sblocks, justValidate) } func executeDirectives(inst *Instance, filename string, @@ -658,7 +656,10 @@ func startServers(serverList []Server, inst *Instance, restartFds map[string]res if fdIndex, ok := loadedGob.ListenerFds["tcp"+addr]; ok { file := os.NewFile(fdIndex, "") ln, err = net.FileListener(file) - file.Close() + if err != nil { + return err + } + err = file.Close() if err != nil { return err } @@ -666,7 +667,10 @@ func startServers(serverList []Server, inst *Instance, restartFds map[string]res if fdIndex, ok := loadedGob.ListenerFds["udp"+addr]; ok { file := os.NewFile(fdIndex, "") pc, err = net.FilePacketConn(file) - file.Close() + if err != nil { + return err + } + err = file.Close() if err != nil { return err } @@ -689,7 +693,10 @@ func startServers(serverList []Server, inst *Instance, restartFds map[string]res if err != nil { return err } - file.Close() + err = file.Close() + if err != nil { + return err + } } // packetconn if old.packet != nil { @@ -701,7 +708,10 @@ func startServers(serverList []Server, inst *Instance, restartFds map[string]res if err != nil { return err } - file.Close() + err = file.Close() + if err != nil { + return err + } } } } diff --git a/caddyhttp/browse/browse.go b/caddyhttp/browse/browse.go index 2ac72c031..f265710e0 100644 --- a/caddyhttp/browse/browse.go +++ b/caddyhttp/browse/browse.go @@ -252,7 +252,7 @@ func directoryListing(files []os.FileInfo, canGoUp bool, urlPath string, config for _, f := range files { name := f.Name() - for _, indexName := range staticfiles.IndexPages { + for _, indexName := range config.Fs.IndexPages { if name == indexName { hasIndexFile = true break diff --git a/caddyhttp/browse/setup.go b/caddyhttp/browse/setup.go index 949f414ab..6979308ba 100644 --- a/caddyhttp/browse/setup.go +++ b/caddyhttp/browse/setup.go @@ -78,8 +78,9 @@ func browseParse(c *caddy.Controller) ([]Config, error) { } bc.Fs = staticfiles.FileServer{ - Root: http.Dir(cfg.Root), - Hide: cfg.HiddenFiles, + Root: http.Dir(cfg.Root), + Hide: cfg.HiddenFiles, + IndexPages: cfg.IndexPages, } // Second argument would be the template file to use diff --git a/caddyhttp/httpserver/plugin.go b/caddyhttp/httpserver/plugin.go index ca8f0c334..643eea7f7 100644 --- a/caddyhttp/httpserver/plugin.go +++ b/caddyhttp/httpserver/plugin.go @@ -27,6 +27,7 @@ import ( "github.com/mholt/caddy" "github.com/mholt/caddy/caddyfile" + "github.com/mholt/caddy/caddyhttp/staticfiles" "github.com/mholt/caddy/caddytls" ) @@ -155,6 +156,7 @@ func (h *httpContext) InspectServerBlocks(sourceFile string, serverBlocks []cadd AltTLSSNIPort: altTLSSNIPort, }, originCaddyfile: sourceFile, + IndexPages: staticfiles.DefaultIndexPages, } h.saveConfig(key, cfg) } @@ -234,7 +236,7 @@ func GetConfig(c *caddy.Controller) *SiteConfig { // we should only get here during tests because directive // actions typically skip the server blocks where we make // the configs - cfg := &SiteConfig{Root: Root, TLS: new(caddytls.Config)} + cfg := &SiteConfig{Root: Root, TLS: new(caddytls.Config), IndexPages: staticfiles.DefaultIndexPages} ctx.saveConfig(key, cfg) return cfg } diff --git a/caddyhttp/httpserver/server.go b/caddyhttp/httpserver/server.go index eb854d726..b0f85a056 100644 --- a/caddyhttp/httpserver/server.go +++ b/caddyhttp/httpserver/server.go @@ -142,7 +142,7 @@ func NewServer(addr string, group []*SiteConfig) (*Server, error) { // Compile custom middleware for every site (enables virtual hosting) for _, site := range group { - stack := Handler(staticfiles.FileServer{Root: http.Dir(site.Root), Hide: site.HiddenFiles}) + stack := Handler(staticfiles.FileServer{Root: http.Dir(site.Root), Hide: site.HiddenFiles, IndexPages: site.IndexPages}) for i := len(site.middleware) - 1; i >= 0; i-- { stack = site.middleware[i](stack) } diff --git a/caddyhttp/httpserver/siteconfig.go b/caddyhttp/httpserver/siteconfig.go index bd444c75b..1cd9a0504 100644 --- a/caddyhttp/httpserver/siteconfig.go +++ b/caddyhttp/httpserver/siteconfig.go @@ -26,6 +26,9 @@ type SiteConfig struct { // The address of the site Addr Address + // The list of viable index page names of the site + IndexPages []string + // The hostname to bind listener to; // defaults to Addr.Host ListenHost string diff --git a/caddyhttp/index/index.go b/caddyhttp/index/index.go index 760245c9c..fefc0ff73 100644 --- a/caddyhttp/index/index.go +++ b/caddyhttp/index/index.go @@ -16,7 +16,7 @@ package index import ( "github.com/mholt/caddy" - "github.com/mholt/caddy/caddyhttp/staticfiles" + "github.com/mholt/caddy/caddyhttp/httpserver" ) func init() { @@ -29,6 +29,8 @@ func init() { func setupIndex(c *caddy.Controller) error { var index []string + cfg := httpserver.GetConfig(c) + for c.Next() { args := c.RemainingArgs() @@ -40,7 +42,7 @@ func setupIndex(c *caddy.Controller) error { index = append(index, in) } - staticfiles.IndexPages = index + cfg.IndexPages = index } return nil diff --git a/caddyhttp/index/index_test.go b/caddyhttp/index/index_test.go index bedb29628..f0b3f41d5 100644 --- a/caddyhttp/index/index_test.go +++ b/caddyhttp/index/index_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/mholt/caddy" + "github.com/mholt/caddy/caddyhttp/httpserver" "github.com/mholt/caddy/caddyhttp/staticfiles" ) @@ -31,7 +32,7 @@ func TestIndexIncompleteParams(t *testing.T) { } func TestIndex(t *testing.T) { - c := caddy.NewTestController("", "index a.html b.html c.html") + c := caddy.NewTestController("http", "index a.html b.html c.html") err := setupIndex(c) if err != nil { @@ -40,14 +41,85 @@ func TestIndex(t *testing.T) { expectedIndex := []string{"a.html", "b.html", "c.html"} - if len(staticfiles.IndexPages) != 3 { - t.Errorf("Expected 3 values, got %v", len(staticfiles.IndexPages)) + siteConfig := httpserver.GetConfig(c) + + if len(siteConfig.IndexPages) != len(expectedIndex) { + t.Errorf("Expected 3 values, got %v", len(siteConfig.IndexPages)) } // Ensure ordering is correct - for i, actual := range staticfiles.IndexPages { + for i, actual := range siteConfig.IndexPages { if actual != expectedIndex[i] { t.Errorf("Expected value in position %d to be %v, got %v", i, expectedIndex[i], actual) } } } + +func TestMultiSiteIndexWithEitherHasDefault(t *testing.T) { + // TestIndex already covers the correctness of the directive + // when used on a single controller, so no need to verify test setupIndex again. + // This sets the stage for the actual verification. + customIndex := caddy.NewTestController("http", "index a.html b.html") + + // setupIndex against customIdx should not pollute the + // index list for other controllers. + err := setupIndex(customIndex) + if err != nil { + t.Errorf("Expected no errors, got: %v", err) + } + + // Represents a virtual host with no index directive. + defaultIndex := caddy.NewTestController("http", "") + + // Not calling setupIndex because it guards against lack of arguments, + // and we need to ensure the site gets the default set of index pages. + + siteConfig := httpserver.GetConfig(defaultIndex) + + // In case the index directive is not used, the virtual host + // should receive staticfiles.DefaultIndexPages slice. The length, as checked here, + // and the values, as checked in the upcoming loop, should match. + if len(siteConfig.IndexPages) != len(staticfiles.DefaultIndexPages) { + t.Errorf("Expected %d values, got %d", len(staticfiles.DefaultIndexPages), len(siteConfig.IndexPages)) + } + + // Ensure values match the expected default index pages + for i, actual := range siteConfig.IndexPages { + if actual != staticfiles.DefaultIndexPages[i] { + t.Errorf("Expected value in position %d to be %v, got %v", i, staticfiles.DefaultIndexPages[i], actual) + } + } +} + +func TestPerSiteIndexPageIsolation(t *testing.T) { + firstIndex := "first.html" + secondIndex := "second.html" + + // Create two sites with different index page configurations + firstSite := caddy.NewTestController("http", "index first.html") + err := setupIndex(firstSite) + if err != nil { + t.Errorf("Expected no errors, got: %v", err) + } + + secondSite := caddy.NewTestController("http", "index second.html") + err = setupIndex(secondSite) + if err != nil { + t.Errorf("Expected no errors, got: %v", err) + } + + firstSiteConfig := httpserver.GetConfig(firstSite) + if firstSiteConfig.IndexPages[0] != firstIndex { + t.Errorf("Expected index for first site as %s, received %s", firstIndex, firstSiteConfig.IndexPages[0]) + } + + secondSiteConfig := httpserver.GetConfig(secondSite) + if secondSiteConfig.IndexPages[0] != secondIndex { + t.Errorf("Expected index for second site as %s, received %s", secondIndex, secondSiteConfig.IndexPages[0]) + } + + // They should have different index pages, as per the provided config. + if firstSiteConfig.IndexPages[0] == secondSiteConfig.IndexPages[0] { + t.Errorf("Expected different index pages for both sites, got %s for first and %s for second", firstSiteConfig.IndexPages[0], secondSiteConfig.IndexPages[0]) + } +} diff --git a/caddyhttp/push/handler.go b/caddyhttp/push/handler.go index 36d414ffb..4a676c272 100644 --- a/caddyhttp/push/handler.go +++ b/caddyhttp/push/handler.go @@ -19,7 +19,6 @@ import ( "strings" "github.com/mholt/caddy/caddyhttp/httpserver" - "github.com/mholt/caddy/caddyhttp/staticfiles" ) func (h Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { @@ -44,7 +43,7 @@ outer: matches := httpserver.Path(urlPath).Matches(rule.Path) // Also check IndexPages when requesting a directory if !matches { - indexFile, isIndexFile := httpserver.IndexFile(h.Root, urlPath, staticfiles.IndexPages) + indexFile, isIndexFile := httpserver.IndexFile(h.Root, urlPath, h.indexPages) if isIndexFile { matches = httpserver.Path(indexFile).Matches(rule.Path) } diff --git a/caddyhttp/push/handler_test.go b/caddyhttp/push/handler_test.go index 0055ae793..99bba4165 100644 --- a/caddyhttp/push/handler_test.go +++ b/caddyhttp/push/handler_test.go @@ -393,7 +393,8 @@ func TestMiddlewareShouldPushIndexFile(t *testing.T) { {Path: "/index.css", Method: http.MethodGet}, }}, }, - Root: http.Dir(root), + Root: http.Dir(root), + indexPages: []string{indexFile}, } indexFilePath := filepath.Join(root, indexFile) diff --git a/caddyhttp/push/push.go b/caddyhttp/push/push.go index 9fdd48b8c..5dc75c113 100644 --- a/caddyhttp/push/push.go +++ b/caddyhttp/push/push.go @@ -36,9 +36,10 @@ type ( // Middleware supports pushing resources to clients Middleware struct { - Next httpserver.Handler - Rules []Rule - Root http.FileSystem + Next httpserver.Handler + Rules []Rule + Root http.FileSystem + indexPages []string // will be injected from SiteConfig on setup } ruleOp func([]Resource) diff --git a/caddyhttp/push/setup.go b/caddyhttp/push/setup.go index bda4935a2..a5037df3f 100644 --- a/caddyhttp/push/setup.go +++ b/caddyhttp/push/setup.go @@ -50,7 +50,7 @@ func setup(c *caddy.Controller) error { cfg := httpserver.GetConfig(c) cfg.AddMiddleware(func(next httpserver.Handler) httpserver.Handler { - return Middleware{Next: next, Rules: rules, Root: http.Dir(cfg.Root)} + return Middleware{Next: next, Rules: rules, Root: http.Dir(cfg.Root), indexPages: cfg.IndexPages} }) return nil diff --git a/caddyhttp/staticfiles/fileserver.go b/caddyhttp/staticfiles/fileserver.go index 4f77f1db0..2b38212ea 100644 --- a/caddyhttp/staticfiles/fileserver.go +++ b/caddyhttp/staticfiles/fileserver.go @@ -45,6 +45,10 @@ import ( type FileServer struct { Root http.FileSystem // jailed access to the file system Hide []string // list of files for which to respond with "Not Found" + + // A list of pages that may be understood as the "index" files to directories. + // Injected from *SiteConfig. + IndexPages []string } // ServeHTTP serves static files for r according to fs's configuration. @@ -118,7 +122,7 @@ func (fs FileServer) serveFile(w http.ResponseWriter, r *http.Request) (int, err // if an index file was explicitly requested, strip file name from the request // ("/foo/index.html" -> "/foo/") var requestPage = path.Base(urlCopy.Path) - for _, indexPage := range IndexPages { + for _, indexPage := range fs.IndexPages { if requestPage == indexPage { urlCopy.Path = urlCopy.Path[:len(urlCopy.Path)-len(indexPage)] redir = true @@ -134,7 +138,7 @@ func (fs FileServer) serveFile(w http.ResponseWriter, r *http.Request) (int, err // use contents of an index file, if present, for directory requests if d.IsDir() { - for _, indexPage := range IndexPages { + for _, indexPage := range fs.IndexPages { indexPath := path.Join(reqPath, indexPage) indexFile, err := fs.Root.Open(indexPath) if err != nil { @@ -253,9 +257,9 @@ func calculateEtag(d os.FileInfo) string { return `"` + t + s + `"` } -// IndexPages is a list of pages that may be understood as +// DefaultIndexPages is a list of pages that may be understood as // the "index" files to directories. -var IndexPages = []string{ +var DefaultIndexPages = []string{ "index.html", "index.htm", "index.txt", diff --git a/caddyhttp/staticfiles/fileserver_test.go b/caddyhttp/staticfiles/fileserver_test.go index 95d315d3b..9cce77057 100644 --- a/caddyhttp/staticfiles/fileserver_test.go +++ b/caddyhttp/staticfiles/fileserver_test.go @@ -36,8 +36,9 @@ func TestServeHTTP(t *testing.T) { defer afterServeHTTPTest(t, tmpWebRootDir) fileserver := FileServer{ - Root: http.Dir(filepath.Join(tmpWebRootDir, webrootName)), - Hide: []string{"dir/hidden.html"}, + Root: http.Dir(filepath.Join(tmpWebRootDir, webrootName)), + Hide: []string{"dir/hidden.html"}, + IndexPages: DefaultIndexPages, } movedPermanently := "Moved Permanently" diff --git a/caddytls/config.go b/caddytls/config.go index 4654c0644..d3468e348 100644 --- a/caddytls/config.go +++ b/caddytls/config.go @@ -148,6 +148,11 @@ type OnDemandState struct { // Set from max_certs in tls config, it specifies the // maximum number of certificates that can be issued. MaxObtain int32 + + // The url to call to check if an on-demand tls certificate should + // be issued. If a request to the URL fails or returns a non 2xx + // status on-demand issuances must fail. + AskURL *url.URL } // ObtainCert obtains a certificate for name using c, as long diff --git a/caddytls/handshake.go b/caddytls/handshake.go index 31fc67e06..c50e8ab63 100644 --- a/caddytls/handshake.go +++ b/caddytls/handshake.go @@ -19,6 +19,8 @@ import ( "errors" "fmt" "log" + "net/http" + "net/url" "strings" "sync" "sync/atomic" @@ -135,8 +137,8 @@ func (cfg *Config) getCertDuringHandshake(name string, loadIfNecessary, obtainIf name = strings.ToLower(name) - // Make sure aren't over any applicable limits - err := cfg.checkLimitsForObtainingNewCerts(name) + // Make sure the certificate should be obtained based on config + err := cfg.checkIfCertShouldBeObtained(name) if err != nil { return Certificate{}, err } @@ -159,10 +161,52 @@ func (cfg *Config) getCertDuringHandshake(name string, loadIfNecessary, obtainIf return Certificate{}, fmt.Errorf("no certificate available for %s", name) } +// checkIfCertShouldBeObtained checks to see if an on-demand tls certificate +// should be obtained for a given domain based upon the config settings. If +// a non-nil error is returned, do not issue a new certificate for name. +func (cfg *Config) checkIfCertShouldBeObtained(name string) error { + // If the "ask" URL is defined in the config, use to determine if a + // cert should obtained + if cfg.OnDemandState.AskURL != nil { + return cfg.checkURLForObtainingNewCerts(name) + } + + // Otherwise use the limit defined by the "max_certs" setting + return cfg.checkLimitsForObtainingNewCerts(name) +} + +func (cfg *Config) checkURLForObtainingNewCerts(name string) error { + client := http.Client{ + Timeout: 10 * time.Second, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return errors.New("following http redirects is not allowed") + }, + } + + // Copy the URL from the config in order to modify it for this request + askURL := new(url.URL) + *askURL = *cfg.OnDemandState.AskURL + + query := askURL.Query() + query.Set("domain", name) + askURL.RawQuery = query.Encode() + + resp, err := client.Get(askURL.String()) + if err != nil { + return fmt.Errorf("error checking %v to deterine if certificate for hostname '%s' should be allowed: %v", cfg.OnDemandState.AskURL, name, err) + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode > 299 { + return fmt.Errorf("certificate for hostname '%s' not allowed, non-2xx status code %d returned from %v", name, resp.StatusCode, cfg.OnDemandState.AskURL) + } + + return nil +} + // checkLimitsForObtainingNewCerts checks to see if name can be issued right -// now according to mitigating factors we keep track of and preferences the -// user has set. If a non-nil error is returned, do not issue a new certificate -// for name. +// now according the maximum count defined in the configuration. If a non-nil +// error is returned, do not issue a new certificate for name. func (cfg *Config) checkLimitsForObtainingNewCerts(name string) error { // User can set hard limit for number of certs for the process to issue if cfg.OnDemandState.MaxObtain > 0 && diff --git a/caddytls/setup.go b/caddytls/setup.go index 6a16cbf33..cbc2baca1 100644 --- a/caddytls/setup.go +++ b/caddytls/setup.go @@ -21,6 +21,7 @@ import ( "fmt" "io/ioutil" "log" + "net/url" "os" "path/filepath" "strconv" @@ -49,7 +50,7 @@ func setupTLS(c *caddy.Controller) error { config.Enabled = true for c.Next() { - var certificateFile, keyFile, loadDir, maxCerts string + var certificateFile, keyFile, loadDir, maxCerts, askURL string args := c.RemainingArgs() switch len(args) { @@ -164,6 +165,9 @@ func setupTLS(c *caddy.Controller) error { case "max_certs": c.Args(&maxCerts) config.OnDemand = true + case "ask": + c.Args(&askURL) + config.OnDemand = true case "dns": args := c.RemainingArgs() if len(args) != 1 { @@ -213,6 +217,19 @@ func setupTLS(c *caddy.Controller) error { config.OnDemandState.MaxObtain = int32(maxCertsNum) } + if askURL != "" { + parsedURL, err := url.Parse(askURL) + if err != nil { + return c.Err("ask must be a valid url") + } + + if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" { + return c.Err("ask URL must use http or https") + } + + config.OnDemandState.AskURL = parsedURL + } + // don't try to load certificates unless we're supposed to if !config.Enabled || !config.Manual { continue diff --git a/dist/init/freebsd/caddy b/dist/init/freebsd/caddy index 5499f7c54..3f6f00e84 100755 --- a/dist/init/freebsd/caddy +++ b/dist/init/freebsd/caddy @@ -62,7 +62,7 @@ fi pidfile="/var/run/${name}.pid" procname="${caddy_bin_path}" #enabled builtin pid checking for start / stop command="/usr/sbin/daemon" -command_args="-u ${caddy_user} -p ${pidfile} /usr/bin/env ${caddy_env} ${procname} -cpu ${caddy_cpu} -log stdout -conf ${caddy_config_path} -agree -email ${caddy_cert_email} < /dev/null >> ${caddy_logfile} 2>&1" +command_args="-p ${pidfile} /usr/bin/env ${caddy_env} ${procname} -cpu ${caddy_cpu} -log stdout -conf ${caddy_config_path} -agree -email ${caddy_cert_email} < /dev/null >> ${caddy_logfile} 2>&1" start_precmd="caddy_startprecmd" diff --git a/onevent/hook/hook.go b/onevent/hook/hook.go index 57a67f16a..9d2c4d0b5 100644 --- a/onevent/hook/hook.go +++ b/onevent/hook/hook.go @@ -28,10 +28,10 @@ func (cfg *Config) Hook(event caddy.EventName, info interface{}) error { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if nonblock { - log.Printf("[INFO] Nonblocking Command with ID %s: \"%s %s\"", cfg.ID, cfg.Command, strings.Join(cfg.Args, " ")) + log.Printf("[INFO] Nonblocking Command \"%s %s\" with ID %s", cfg.Command, strings.Join(cfg.Args, " "), cfg.ID) return cmd.Start() } - log.Printf("[INFO] Blocking Command with ID %s: \"%s %s\"", cfg.ID, cfg.Command, strings.Join(cfg.Args, " ")) + log.Printf("[INFO] Blocking Command \"%s %s\" with ID %s", cfg.Command, strings.Join(cfg.Args, " "), cfg.ID) err := cmd.Run() if err != nil { return err diff --git a/onevent/on.go b/onevent/on.go index 2b0d3e6af..2e291052b 100644 --- a/onevent/on.go +++ b/onevent/on.go @@ -20,9 +20,12 @@ func setup(c *caddy.Controller) error { } // Register Event Hooks. - for _, cfg := range config { - caddy.RegisterEventHook("on-"+cfg.ID, cfg.Hook) - } + c.OncePerServerBlock(func() error { + for _, cfg := range config { + caddy.RegisterEventHook("on-"+cfg.ID, cfg.Hook) + } + return nil + }) return nil } diff --git a/sigtrap_posix.go b/sigtrap_posix.go index 0715b3280..71b6969af 100644 --- a/sigtrap_posix.go +++ b/sigtrap_posix.go @@ -84,7 +84,7 @@ func trapSignalsPosix() { } // Kick off the restart; our work is done - inst, err = inst.Restart(caddyfileToUse) + _, err = inst.Restart(caddyfileToUse) if err != nil { log.Printf("[ERROR] SIGUSR1: %v", err) } diff --git a/startupshutdown/startupshutdown.go b/startupshutdown/startupshutdown.go index cb7e7119d..72fe9225c 100644 --- a/startupshutdown/startupshutdown.go +++ b/startupshutdown/startupshutdown.go @@ -36,9 +36,12 @@ func Startup(c *caddy.Controller) error { } // Register Event Hooks. - for _, cfg := range config { - caddy.RegisterEventHook("on-"+cfg.ID, cfg.Hook) - } + c.OncePerServerBlock(func() error { + for _, cfg := range config { + caddy.RegisterEventHook("on-"+cfg.ID, cfg.Hook) + } + return nil + }) fmt.Println("NOTICE: Startup directive will be removed in a later version. Please migrate to 'on startup'") diff --git a/upgrade.go b/upgrade.go index 9a607ef21..8214937b9 100644 --- a/upgrade.go +++ b/upgrade.go @@ -136,7 +136,10 @@ func Upgrade() error { // immediately close our dup'ed fds and the write end of our signal pipe for _, f := range extraFiles { - f.Close() + err = f.Close() + if err != nil { + return err + } } // feed Caddyfile to the child @@ -144,11 +147,14 @@ func Upgrade() error { if err != nil { return err } - wpipe.Close() + err = wpipe.Close() + if err != nil { + return err + } // determine whether child startup succeeded answer, readErr := ioutil.ReadAll(sigrpipe) - if answer == nil || len(answer) == 0 { + if len(answer) == 0 { cmdErr := cmd.Wait() // get exit status errStr := fmt.Sprintf("child failed to initialize: %v", cmdErr) if readErr != nil {