Commit 8e8e2f59 authored by Carter's avatar Carter Committed by GitHub

Merge branch 'master' into log-request-body

parents 532ab661 68be4a91
...@@ -50,6 +50,14 @@ var ( ...@@ -50,6 +50,14 @@ var (
// was started as part of an upgrade, where a parent // was started as part of an upgrade, where a parent
// Caddy process started this one. // Caddy process started this one.
isUpgrade bool isUpgrade bool
// started will be set to true when the first
// instance is started; it never gets set to
// false after that.
started bool
// mu protects the variables 'isUpgrade' and 'started'.
mu sync.Mutex
) )
// Instance contains the state of servers created as a result of // Instance contains the state of servers created as a result of
...@@ -497,6 +505,10 @@ func startWithListenerFds(cdyfile Input, inst *Instance, restartFds map[string]r ...@@ -497,6 +505,10 @@ func startWithListenerFds(cdyfile Input, inst *Instance, restartFds map[string]r
} }
} }
mu.Lock()
started = true
mu.Unlock()
return nil return nil
} }
...@@ -737,9 +749,20 @@ func Upgrade() error { ...@@ -737,9 +749,20 @@ func Upgrade() error {
// where a parent caddy process spawned this one to ugprade // where a parent caddy process spawned this one to ugprade
// the binary. // the binary.
func IsUpgrade() bool { func IsUpgrade() bool {
mu.Lock()
defer mu.Unlock()
return isUpgrade return isUpgrade
} }
// Started returns true if at least one instance has been
// started by this package. It never gets reset to false
// once it is set to true.
func Started() bool {
mu.Lock()
defer mu.Unlock()
return started
}
// CaddyfileInput represents a Caddyfile as input // CaddyfileInput represents a Caddyfile as input
// and is simply a convenient way to implement // and is simply a convenient way to implement
// the Input interface. // the Input interface.
......
...@@ -10,7 +10,9 @@ import ( ...@@ -10,7 +10,9 @@ import (
) )
func activateHTTPS(cctx caddy.Context) error { func activateHTTPS(cctx caddy.Context) error {
if !caddy.Quiet { operatorPresent := !caddy.Started()
if !caddy.Quiet && operatorPresent {
fmt.Print("Activating privacy features...") fmt.Print("Activating privacy features...")
} }
...@@ -21,7 +23,7 @@ func activateHTTPS(cctx caddy.Context) error { ...@@ -21,7 +23,7 @@ func activateHTTPS(cctx caddy.Context) error {
// place certificates and keys on disk // place certificates and keys on disk
for _, c := range ctx.siteConfigs { for _, c := range ctx.siteConfigs {
err := c.TLS.ObtainCert(true) err := c.TLS.ObtainCert(operatorPresent)
if err != nil { if err != nil {
return err return err
} }
...@@ -44,9 +46,10 @@ func activateHTTPS(cctx caddy.Context) error { ...@@ -44,9 +46,10 @@ func activateHTTPS(cctx caddy.Context) error {
return err return err
} }
if !caddy.Quiet { if !caddy.Quiet && operatorPresent {
fmt.Println(" done.") fmt.Println(" done.")
} }
return nil return nil
} }
......
...@@ -144,9 +144,11 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error) ...@@ -144,9 +144,11 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error)
func (c *ACMEClient) Obtain(names []string) error { func (c *ACMEClient) Obtain(names []string) error {
Attempts: Attempts:
for attempts := 0; attempts < 2; attempts++ { for attempts := 0; attempts < 2; attempts++ {
namesObtaining.Add(names)
acmeMu.Lock() acmeMu.Lock()
certificate, failures := c.ObtainCertificate(names, true, nil) certificate, failures := c.ObtainCertificate(names, true, nil)
acmeMu.Unlock() acmeMu.Unlock()
namesObtaining.Remove(names)
if len(failures) > 0 { if len(failures) > 0 {
// Error - try to fix it or report it to the user and abort // Error - try to fix it or report it to the user and abort
var errMsg string // we'll combine all the failures into a single error message var errMsg string // we'll combine all the failures into a single error message
...@@ -234,9 +236,11 @@ func (c *ACMEClient) Renew(name string) error { ...@@ -234,9 +236,11 @@ func (c *ACMEClient) Renew(name string) error {
var newCertMeta acme.CertificateResource var newCertMeta acme.CertificateResource
var success bool var success bool
for attempts := 0; attempts < 2; attempts++ { for attempts := 0; attempts < 2; attempts++ {
namesObtaining.Add([]string{name})
acmeMu.Lock() acmeMu.Lock()
newCertMeta, err = c.RenewCertificate(certMeta, true) newCertMeta, err = c.RenewCertificate(certMeta, true)
acmeMu.Unlock() acmeMu.Unlock()
namesObtaining.Remove([]string{name})
if err == nil { if err == nil {
success = true success = true
break break
...@@ -294,3 +298,47 @@ func (c *ACMEClient) Revoke(name string) error { ...@@ -294,3 +298,47 @@ func (c *ACMEClient) Revoke(name string) error {
return nil return nil
} }
// namesObtaining is a set of hostnames with thread-safe
// methods. A name should be in this set only while this
// package is in the process of obtaining a certificate
// for the name. ACME challenges that are received for
// names which are not in this set were not initiated by
// this package and probably should not be handled by
// this package.
var namesObtaining = nameCoordinator{names: make(map[string]struct{})}
type nameCoordinator struct {
names map[string]struct{}
mu sync.RWMutex
}
// Add adds names to c. It is safe for concurrent use.
func (c *nameCoordinator) Add(names []string) {
c.mu.Lock()
for _, name := range names {
c.names[strings.ToLower(name)] = struct{}{}
}
c.mu.Unlock()
}
// Remove removes names from c. It is safe for concurrent use.
func (c *nameCoordinator) Remove(names []string) {
c.mu.Lock()
for _, name := range names {
delete(c.names, strings.ToLower(name))
}
c.mu.Unlock()
}
// Has returns true if c has name. It is safe for concurrent use.
func (c *nameCoordinator) Has(name string) bool {
hostname, _, err := net.SplitHostPort(name)
if err != nil {
hostname = name
}
c.mu.RLock()
_, ok := c.names[strings.ToLower(hostname)]
c.mu.RUnlock()
return ok
}
...@@ -214,9 +214,11 @@ func (c *Config) renewCertName(name string, allowPrompts bool) error { ...@@ -214,9 +214,11 @@ func (c *Config) renewCertName(name string, allowPrompts bool) error {
var newCertMeta acme.CertificateResource var newCertMeta acme.CertificateResource
var success bool var success bool
for attempts := 0; attempts < 2; attempts++ { for attempts := 0; attempts < 2; attempts++ {
namesObtaining.Add([]string{name})
acmeMu.Lock() acmeMu.Lock()
newCertMeta, err = client.RenewCertificate(certMeta, true) newCertMeta, err = client.RenewCertificate(certMeta, true)
acmeMu.Unlock() acmeMu.Unlock()
namesObtaining.Remove([]string{name})
if err == nil { if err == nil {
success = true success = true
break break
......
...@@ -19,6 +19,9 @@ func HTTPChallengeHandler(w http.ResponseWriter, r *http.Request, altPort string ...@@ -19,6 +19,9 @@ func HTTPChallengeHandler(w http.ResponseWriter, r *http.Request, altPort string
if !strings.HasPrefix(r.URL.Path, challengeBasePath) { if !strings.HasPrefix(r.URL.Path, challengeBasePath) {
return false return false
} }
if !namesObtaining.Has(r.Host) {
return false
}
scheme := "http" scheme := "http"
if r.TLS != nil { if r.TLS != nil {
......
...@@ -8,13 +8,17 @@ import ( ...@@ -8,13 +8,17 @@ import (
) )
func TestHTTPChallengeHandlerNoOp(t *testing.T) { func TestHTTPChallengeHandlerNoOp(t *testing.T) {
// try base paths that aren't handled by this handler namesObtaining.Add([]string{"localhost"})
// try base paths and host names that aren't
// handled by this handler
for _, url := range []string{ for _, url := range []string{
"http://localhost/", "http://localhost/",
"http://localhost/foo.html", "http://localhost/foo.html",
"http://localhost/.git", "http://localhost/.git",
"http://localhost/.well-known/", "http://localhost/.well-known/",
"http://localhost/.well-known/acme-challenging", "http://localhost/.well-known/acme-challenging",
"http://other/.well-known/acme-challenge/foo",
} { } {
req, err := http.NewRequest("GET", url, nil) req, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
...@@ -46,6 +50,9 @@ func TestHTTPChallengeHandlerSuccess(t *testing.T) { ...@@ -46,6 +50,9 @@ func TestHTTPChallengeHandlerSuccess(t *testing.T) {
} }
ts.Listener = ln ts.Listener = ln
// Tell this package that we are handling a challenge for 127.0.0.1
namesObtaining.Add([]string{"127.0.0.1"})
// Start our engines and run the test // Start our engines and run the test
ts.Start() ts.Start()
defer ts.Close() defer ts.Close()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment