summaryrefslogtreecommitdiff
path: root/caddy.go
diff options
context:
space:
mode:
authorTom Barrett <tom@tombarrett.xyz>2023-11-01 17:57:48 +0100
committerTom Barrett <tom@tombarrett.xyz>2023-11-01 18:11:33 +0100
commit240c3d1338415e5d82ef7ca0e52c4284be6441bd (patch)
tree4b0ee5d208c2cdffa78d65f1b0abe0ec85f15652 /caddy.go
parent73e78ab226f21e6c6c68961af88c4ab9c746f4f4 (diff)
parent0e204b730aa2b1fa0835336b1117eff8c420f713 (diff)
vbump to v2.7.5HEADcaddy-cgi
Diffstat (limited to 'caddy.go')
-rw-r--r--caddy.go58
1 files changed, 38 insertions, 20 deletions
diff --git a/caddy.go b/caddy.go
index 5d0152a..8e7dce5 100644
--- a/caddy.go
+++ b/caddy.go
@@ -34,10 +34,11 @@ import (
"sync/atomic"
"time"
- "github.com/caddyserver/caddy/v2/notify"
"github.com/caddyserver/certmagic"
"github.com/google/uuid"
"go.uber.org/zap"
+
+ "github.com/caddyserver/caddy/v2/notify"
)
// Config is the top (or beginning) of the Caddy configuration structure.
@@ -156,8 +157,8 @@ func changeConfig(method, path string, input []byte, ifMatchHeader string, force
return fmt.Errorf("method not allowed")
}
- currentCtxMu.Lock()
- defer currentCtxMu.Unlock()
+ rawCfgMu.Lock()
+ defer rawCfgMu.Unlock()
if ifMatchHeader != "" {
// expect the first and last character to be quotes
@@ -257,8 +258,8 @@ func changeConfig(method, path string, input []byte, ifMatchHeader string, force
// readConfig traverses the current config to path
// and writes its JSON encoding to out.
func readConfig(path string, out io.Writer) error {
- currentCtxMu.RLock()
- defer currentCtxMu.RUnlock()
+ rawCfgMu.RLock()
+ defer rawCfgMu.RUnlock()
return unsyncedConfigAccess(http.MethodGet, path, nil, out)
}
@@ -305,7 +306,7 @@ func indexConfigObjects(ptr any, configPath string, index map[string]string) err
// it as the new config, replacing any other current config.
// It does NOT update the raw config state, as this is a
// lower-level function; most callers will want to use Load
-// instead. A write lock on currentCtxMu is required! If
+// instead. A write lock on rawCfgMu is required! If
// allowPersist is false, it will not be persisted to disk,
// even if it is configured to.
func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
@@ -314,7 +315,7 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
strippedCfgJSON := RemoveMetaFields(cfgJSON)
var newCfg *Config
- err := strictUnmarshalJSON(strippedCfgJSON, &newCfg)
+ err := StrictUnmarshalJSON(strippedCfgJSON, &newCfg)
if err != nil {
return err
}
@@ -340,8 +341,10 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
}
// swap old context (including its config) with the new one
+ currentCtxMu.Lock()
oldCtx := currentCtx
currentCtx = ctx
+ currentCtxMu.Unlock()
// Stop, Cleanup each old app
unsyncedStop(oldCtx)
@@ -354,13 +357,13 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
newCfg.Admin.Config.Persist == nil ||
*newCfg.Admin.Config.Persist) {
dir := filepath.Dir(ConfigAutosavePath)
- err := os.MkdirAll(dir, 0700)
+ err := os.MkdirAll(dir, 0o700)
if err != nil {
Log().Error("unable to create folder for config autosave",
zap.String("dir", dir),
zap.Error(err))
} else {
- err := os.WriteFile(ConfigAutosavePath, cfgJSON, 0600)
+ err := os.WriteFile(ConfigAutosavePath, cfgJSON, 0o600)
if err == nil {
Log().Info("autosaved config (load with --resume flag)", zap.String("file", ConfigAutosavePath))
} else {
@@ -627,22 +630,35 @@ type ConfigLoader interface {
// stop the others. Stop should only be called
// if not replacing with a new config.
func Stop() error {
+ currentCtxMu.RLock()
+ ctx := currentCtx
+ currentCtxMu.RUnlock()
+
+ rawCfgMu.Lock()
+ unsyncedStop(ctx)
+
currentCtxMu.Lock()
- defer currentCtxMu.Unlock()
- unsyncedStop(currentCtx)
currentCtx = Context{}
+ currentCtxMu.Unlock()
+
rawCfgJSON = nil
rawCfgIndex = nil
rawCfg[rawConfigKey] = nil
+ rawCfgMu.Unlock()
+
return nil
}
-// unsyncedStop stops cfg from running, but has
-// no locking around cfg. It is a no-op if cfg is
-// nil. If any app returns an error when stopping,
+// unsyncedStop stops ctx from running, but has
+// no locking around ctx. It is a no-op if ctx has a
+// nil cfg. If any app returns an error when stopping,
// it is logged and the function continues stopping
// the next app. This function assumes all apps in
-// cfg were successfully started first.
+// ctx were successfully started first.
+//
+// A lock on rawCfgMu is required, even though this
+// function does not access rawCfg, that lock
+// synchronizes the stop/start of apps.
func unsyncedStop(ctx Context) {
if ctx.cfg == nil {
return
@@ -816,7 +832,7 @@ func InstanceID() (uuid.UUID, error) {
if err != nil {
return uuid, err
}
- err = os.WriteFile(uuidFilePath, []byte(uuid.String()), 0600)
+ err = os.WriteFile(uuidFilePath, []byte(uuid.String()), 0o600)
return uuid, err
} else if err != nil {
return [16]byte{}, err
@@ -969,14 +985,12 @@ type CtxKey string
// This group of variables pertains to the current configuration.
var (
- // currentCtxMu protects everything in this var block.
- currentCtxMu sync.RWMutex
-
// currentCtx is the root context for the currently-running
// configuration, which can be accessed through this value.
// If the Config contained in this value is not nil, then
// a config is currently active/running.
- currentCtx Context
+ currentCtx Context
+ currentCtxMu sync.RWMutex
// rawCfg is the current, generic-decoded configuration;
// we initialize it as a map with one field ("config")
@@ -994,6 +1008,10 @@ var (
// rawCfgIndex is the map of user-assigned ID to expanded
// path, for converting /id/ paths to /config/ paths.
rawCfgIndex map[string]string
+
+ // rawCfgMu protects all the rawCfg fields and also
+ // essentially synchronizes config changes/reloads.
+ rawCfgMu sync.RWMutex
)
// errSameConfig is returned if the new config is the same