@marcel91200 / caddy Mirror · read-only / commits / afd15411
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

admin: Support config adapters at /load endpoint

Based on Content-Type

Matthew Holt committed Aug 22, 2019 at 14:52 UTC afd154119a24786be44996990028d177569f4a58
2 files changed +43 -4
admin.go
+39 -4
@@ -20,6 +20,7 @@ import (
20 "encoding/json"
21 "fmt"
22 "io"
23 + "io/ioutil"
24 "log"
25 "net"
26 "net/http"
@@ -29,6 +30,7 @@ import (
30 "sync"
31 "time"
32
33 + "github.com/caddyserver/caddy/caddyconfig"
34 "github.com/mholt/certmagic"
35 "github.com/rs/cors"
36 )
@@ -164,12 +166,45 @@ func handleLoadConfig(w http.ResponseWriter, r *http.Request) {
166 return
167 }
168
167 - if !strings.Contains(r.Header.Get("Content-Type"), "/json") {
168 - http.Error(w, "unacceptable Content-Type", http.StatusBadRequest)
169 - return
169 + var payload io.Reader = r.Body
170 +
171 + // if the config is formatted other than Caddy's native
172 + // JSON, we need to adapt it before loading it
173 + ct := r.Header.Get("Content-Type")
174 + if !strings.Contains(ct, "/json") {
175 + slashIdx := strings.Index(ct, "/")
176 + if slashIdx < 0 {
177 + http.Error(w, "Malformed Content-Type", http.StatusBadRequest)
178 + return
179 + }
180 + adapterName := ct[slashIdx+1:]
181 + cfgAdapter := caddyconfig.GetAdapter(adapterName)
182 + if cfgAdapter == nil {
183 + http.Error(w, "Unrecognized config adapter: "+adapterName, http.StatusBadRequest)
184 + return
185 + }
186 + body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, 1024*1024))
187 + if err != nil {
188 + http.Error(w, "Error reading request body: "+err.Error(), http.StatusBadRequest)
189 + return
190 + }
191 + result, warnings, err := cfgAdapter.Adapt(body, nil)
192 + if err != nil {
193 + log.Printf("[ADMIN][ERROR] adapting config from %s: %v", adapterName, err)
194 + http.Error(w, fmt.Sprintf("Adapting config from %s: %v", adapterName, err), http.StatusBadRequest)
195 + return
196 + }
197 + if len(warnings) > 0 {
198 + respBody, err := json.Marshal(warnings)
199 + if err != nil {
200 + log.Printf("[ADMIN][ERROR] marshaling warnings: %v", err)
201 + }
202 + w.Write(respBody)
203 + }
204 + payload = bytes.NewReader(result)
205 }
206
172 - err := Load(r.Body)
207 + err := Load(payload)
208 if err != nil {
209 log.Printf("[ADMIN][ERROR] loading config: %v", err)
210 http.Error(w, err.Error(), http.StatusBadRequest)
caddyconfig/configadapters.go
+4
@@ -98,6 +98,8 @@ func JSONIndent(val interface{}) ([]byte, error) {
98 return json.MarshalIndent(val, "", "\t")
99 }
100
101 +// RegisterAdapter registers a config adapter with the given name.
102 +// This should usually be done at init-time.
103 func RegisterAdapter(name string, adapter Adapter) error {
104 if _, ok := configAdapters[name]; ok {
105 return fmt.Errorf("%s: already registered", name)
@@ -106,6 +108,8 @@ func RegisterAdapter(name string, adapter Adapter) error {
108 return nil
109 }
110
111 +// GetAdapter returns the adapter with the given name,
112 +// or nil if one with that name is not registered.
113 func GetAdapter(name string) Adapter {
114 return configAdapters[name]
115 }