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
}