mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-25 04:48:22 +08:00
admin: Preserve "@id" fields through partial changes (fixes #2902)
This commit is contained in:
parent
8de1a76227
commit
6e10586303
7
admin.go
7
admin.go
|
@ -27,6 +27,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -764,6 +765,12 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// idRegexp is used to match ID fields and their associated values
|
||||||
|
// in the config. It also matches adjacent commas so that syntax
|
||||||
|
// can be preserved no matter where in the object the field appears.
|
||||||
|
// It supports string and most numeric values.
|
||||||
|
var idRegexp = regexp.MustCompile(`(?m),?\s*"` + idKey + `":\s?(-?[0-9]+(\.[0-9]+)?|(?U)".*")\s*,?`)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
rawConfigKey = "config"
|
rawConfigKey = "config"
|
||||||
idKey = "@id"
|
idKey = "@id"
|
||||||
|
|
37
caddy.go
37
caddy.go
|
@ -102,16 +102,6 @@ func changeConfig(method, path string, input []byte, forceReload bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// find any IDs in this config and index them
|
|
||||||
idx := make(map[string]string)
|
|
||||||
err = indexConfigObjects(rawCfg[rawConfigKey], "/"+rawConfigKey, idx)
|
|
||||||
if err != nil {
|
|
||||||
return APIError{
|
|
||||||
Code: http.StatusInternalServerError,
|
|
||||||
Err: fmt.Errorf("indexing config: %v", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// the mutation is complete, so encode the entire config as JSON
|
// the mutation is complete, so encode the entire config as JSON
|
||||||
newCfg, err := json.Marshal(rawCfg[rawConfigKey])
|
newCfg, err := json.Marshal(rawCfg[rawConfigKey])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -127,6 +117,32 @@ func changeConfig(method, path string, input []byte, forceReload bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find any IDs in this config and index them
|
||||||
|
idx := make(map[string]string)
|
||||||
|
err = indexConfigObjects(rawCfg[rawConfigKey], "/"+rawConfigKey, idx)
|
||||||
|
if err != nil {
|
||||||
|
return APIError{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
Err: fmt.Errorf("indexing config: %v", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove any @id fields from the JSON, which would cause
|
||||||
|
// loading to break since the field wouldn't be recognized
|
||||||
|
// (an alternate way to do this would be to delete them from
|
||||||
|
// rawCfg as they are indexed, then iterate the index we made
|
||||||
|
// and add them back after encoding as JSON)
|
||||||
|
newCfg = idRegexp.ReplaceAllFunc(newCfg, func(in []byte) []byte {
|
||||||
|
// matches with a comma on both sides (when "@id" property is
|
||||||
|
// not the first or last in the object) need to keep exactly
|
||||||
|
// one comma for correct JSON syntax
|
||||||
|
comma := []byte{','}
|
||||||
|
if bytes.HasPrefix(in, comma) && bytes.HasSuffix(in, comma) {
|
||||||
|
return comma
|
||||||
|
}
|
||||||
|
return []byte{}
|
||||||
|
})
|
||||||
|
|
||||||
// load this new config; if it fails, we need to revert to
|
// load this new config; if it fails, we need to revert to
|
||||||
// our old representation of caddy's actual config
|
// our old representation of caddy's actual config
|
||||||
err = unsyncedDecodeAndRun(newCfg)
|
err = unsyncedDecodeAndRun(newCfg)
|
||||||
|
@ -183,7 +199,6 @@ func indexConfigObjects(ptr interface{}, configPath string, index map[string]str
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%s: %s field must be a string or number", configPath, idKey)
|
return fmt.Errorf("%s: %s field must be a string or number", configPath, idKey)
|
||||||
}
|
}
|
||||||
delete(val, idKey) // field is no longer needed, and will break config if not removed
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// traverse this object property recursively
|
// traverse this object property recursively
|
||||||
|
|
Loading…
Reference in New Issue
Block a user