MCPcopy
hub / github.com/caddyserver/caddy / unsyncedConfigAccess

Function unsyncedConfigAccess

admin.go:1159–1336  ·  view source on GitHub ↗

unsyncedConfigAccess traverses into the current config and performs the operation at path according to method, using body and out as needed. This is a low-level, unsynchronized function; most callers will want to use changeConfig or readConfig instead. This requires a read or write lock on currentCt

(method, path string, body []byte, out io.Writer)

Source from the content-addressed store, hash-verified

1157// read or write lock on currentCtxMu, depending on method (GET needs
1158// only a read lock; all others need a write lock).
1159func unsyncedConfigAccess(method, path string, body []byte, out io.Writer) error {
1160 var err error
1161 var val any
1162
1163 // if there is a request body, decode it into the
1164 // variable that will be set in the config according
1165 // to method and path
1166 if len(body) > 0 {
1167 err = json.Unmarshal(body, &val)
1168 if err != nil {
1169 if jsonErr, ok := err.(*json.SyntaxError); ok {
1170 return fmt.Errorf("decoding request body: %w, at offset %d", jsonErr, jsonErr.Offset)
1171 }
1172 return fmt.Errorf("decoding request body: %w", err)
1173 }
1174 }
1175
1176 enc := json.NewEncoder(out)
1177
1178 cleanPath := strings.Trim(path, "/")
1179 if cleanPath == "" {
1180 return fmt.Errorf("no traversable path")
1181 }
1182
1183 parts := strings.Split(cleanPath, "/")
1184 if len(parts) == 0 {
1185 return fmt.Errorf("path missing")
1186 }
1187
1188 // A path that ends with "..." implies:
1189 // 1) the part before it is an array
1190 // 2) the payload is an array
1191 // and means that the user wants to expand the elements
1192 // in the payload array and append each one into the
1193 // destination array, like so:
1194 // array = append(array, elems...)
1195 // This special case is handled below.
1196 ellipses := parts[len(parts)-1] == "..."
1197 if ellipses {
1198 parts = parts[:len(parts)-1]
1199 }
1200
1201 var ptr any = rawCfg
1202
1203traverseLoop:
1204 for i, part := range parts {
1205 switch v := ptr.(type) {
1206 case map[string]any:
1207 // if the next part enters a slice, and the slice is our destination,
1208 // handle it specially (because appending to the slice copies the slice
1209 // header, which does not replace the original one like we want)
1210 if arr, ok := v[part].([]any); ok && i == len(parts)-2 {
1211 var idx int
1212 if method != http.MethodPost {
1213 idxStr := parts[len(parts)-1]
1214 idx, err = parseCanonicalArrayIndex(idxStr)
1215 if err != nil {
1216 return fmt.Errorf("[%s] invalid array index '%s': %v",

Callers 4

TestUnsyncedConfigAccessFunction · 0.85
changeConfigFunction · 0.85
readConfigFunction · 0.85

Calls 2

parseCanonicalArrayIndexFunction · 0.85
NewEncoderMethod · 0.65