summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-08-22 14:52:39 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2019-08-22 14:52:39 -0600
commitafd154119a24786be44996990028d177569f4a58 (patch)
treef3ef4899af6b684676f2969ebd91bbff2633c919
parente34ff21a7183969afb4150f1f7a1f71b9a1dd0d6 (diff)
admin: Support config adapters at /load endpoint
Based on Content-Type
-rw-r--r--admin.go43
-rw-r--r--caddyconfig/configadapters.go4
2 files changed, 43 insertions, 4 deletions
diff --git a/admin.go b/admin.go
index 7799913..95a3276 100644
--- a/admin.go
+++ b/admin.go
@@ -20,6 +20,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/ioutil"
"log"
"net"
"net/http"
@@ -29,6 +30,7 @@ import (
"sync"
"time"
+ "github.com/caddyserver/caddy/caddyconfig"
"github.com/mholt/certmagic"
"github.com/rs/cors"
)
@@ -164,12 +166,45 @@ func handleLoadConfig(w http.ResponseWriter, r *http.Request) {
return
}
- if !strings.Contains(r.Header.Get("Content-Type"), "/json") {
- http.Error(w, "unacceptable Content-Type", http.StatusBadRequest)
- return
+ var payload io.Reader = r.Body
+
+ // if the config is formatted other than Caddy's native
+ // JSON, we need to adapt it before loading it
+ ct := r.Header.Get("Content-Type")
+ if !strings.Contains(ct, "/json") {
+ slashIdx := strings.Index(ct, "/")
+ if slashIdx < 0 {
+ http.Error(w, "Malformed Content-Type", http.StatusBadRequest)
+ return
+ }
+ adapterName := ct[slashIdx+1:]
+ cfgAdapter := caddyconfig.GetAdapter(adapterName)
+ if cfgAdapter == nil {
+ http.Error(w, "Unrecognized config adapter: "+adapterName, http.StatusBadRequest)
+ return
+ }
+ body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, 1024*1024))
+ if err != nil {
+ http.Error(w, "Error reading request body: "+err.Error(), http.StatusBadRequest)
+ return
+ }
+ result, warnings, err := cfgAdapter.Adapt(body, nil)
+ if err != nil {
+ log.Printf("[ADMIN][ERROR] adapting config from %s: %v", adapterName, err)
+ http.Error(w, fmt.Sprintf("Adapting config from %s: %v", adapterName, err), http.StatusBadRequest)
+ return
+ }
+ if len(warnings) > 0 {
+ respBody, err := json.Marshal(warnings)
+ if err != nil {
+ log.Printf("[ADMIN][ERROR] marshaling warnings: %v", err)
+ }
+ w.Write(respBody)
+ }
+ payload = bytes.NewReader(result)
}
- err := Load(r.Body)
+ err := Load(payload)
if err != nil {
log.Printf("[ADMIN][ERROR] loading config: %v", err)
http.Error(w, err.Error(), http.StatusBadRequest)
diff --git a/caddyconfig/configadapters.go b/caddyconfig/configadapters.go
index c539176..1a0801f 100644
--- a/caddyconfig/configadapters.go
+++ b/caddyconfig/configadapters.go
@@ -98,6 +98,8 @@ func JSONIndent(val interface{}) ([]byte, error) {
return json.MarshalIndent(val, "", "\t")
}
+// RegisterAdapter registers a config adapter with the given name.
+// This should usually be done at init-time.
func RegisterAdapter(name string, adapter Adapter) error {
if _, ok := configAdapters[name]; ok {
return fmt.Errorf("%s: already registered", name)
@@ -106,6 +108,8 @@ func RegisterAdapter(name string, adapter Adapter) error {
return nil
}
+// GetAdapter returns the adapter with the given name,
+// or nil if one with that name is not registered.
func GetAdapter(name string) Adapter {
return configAdapters[name]
}