summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-09-02 12:21:41 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2019-09-02 12:21:41 -0600
commit8e821b5039bd6983814a6b1d11894a649c44f74a (patch)
treeb2bb642a5c8168e1da767936ddc31d1d485056ff
parent9d8bff28c2ba0560d98b545c85ddc7504813dca7 (diff)
caddyconfig: Add JSON5 and JSON-C adapters (closes #2735)
-rw-r--r--admin.go59
-rw-r--r--caddyconfig/json5/json5.go43
-rw-r--r--caddyconfig/jsonc/jsonc.go49
-rw-r--r--go.mod2
-rw-r--r--go.sum4
5 files changed, 131 insertions, 26 deletions
diff --git a/admin.go b/admin.go
index c87ef95..b2894be 100644
--- a/admin.go
+++ b/admin.go
@@ -22,6 +22,7 @@ import (
"io"
"io/ioutil"
"log"
+ "mime"
"net"
"net/http"
"net/http/pprof"
@@ -170,38 +171,44 @@ func handleLoadConfig(w http.ResponseWriter, r *http.Request) {
// 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 ctHeader := r.Header.Get("Content-Type"); ctHeader != "" {
+ ct, _, err := mime.ParseMediaType(ctHeader)
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)
+ http.Error(w, "Invalid Content-Type: "+err.Error(), http.StatusBadRequest)
return
}
- if len(warnings) > 0 {
- respBody, err := json.Marshal(warnings)
+ if !strings.HasSuffix(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 {
- log.Printf("[ADMIN][ERROR] marshaling warnings: %v", err)
+ 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)
}
- w.Write(respBody)
+ payload = bytes.NewReader(result)
}
- payload = bytes.NewReader(result)
}
err := Load(payload)
diff --git a/caddyconfig/json5/json5.go b/caddyconfig/json5/json5.go
new file mode 100644
index 0000000..2c86301
--- /dev/null
+++ b/caddyconfig/json5/json5.go
@@ -0,0 +1,43 @@
+// Copyright 2015 Matthew Holt and The Caddy Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package json5adapter
+
+import (
+ "encoding/json"
+
+ "github.com/caddyserver/caddy/v2/caddyconfig"
+ "github.com/ilibs/json5"
+)
+
+func init() {
+ caddyconfig.RegisterAdapter("json5", Adapter{})
+}
+
+// Adapter adapts JSON5 to Caddy JSON.
+type Adapter struct{}
+
+// Adapt converts the JSON5 config in body to Caddy JSON.
+func (a Adapter) Adapt(body []byte, options map[string]interface{}) (result []byte, warnings []caddyconfig.Warning, err error) {
+ var decoded interface{}
+ err = json5.Unmarshal(body, &decoded)
+ if err != nil {
+ return
+ }
+ result, err = json.Marshal(decoded)
+ return
+}
+
+// Interface guard
+var _ caddyconfig.Adapter = (*Adapter)(nil)
diff --git a/caddyconfig/jsonc/jsonc.go b/caddyconfig/jsonc/jsonc.go
new file mode 100644
index 0000000..4f72c05
--- /dev/null
+++ b/caddyconfig/jsonc/jsonc.go
@@ -0,0 +1,49 @@
+// Copyright 2015 Matthew Holt and The Caddy Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jsoncadapter
+
+import (
+ "encoding/json"
+
+ "github.com/caddyserver/caddy/v2/caddyconfig"
+ "github.com/muhammadmuzzammil1998/jsonc"
+)
+
+func init() {
+ caddyconfig.RegisterAdapter("jsonc", Adapter{})
+}
+
+// Adapter adapts JSON-C to Caddy JSON.
+type Adapter struct{}
+
+// Adapt converts the JSON-C config in body to Caddy JSON.
+func (a Adapter) Adapt(body []byte, options map[string]interface{}) (result []byte, warnings []caddyconfig.Warning, err error) {
+ result = jsonc.ToJSON(body)
+
+ // any errors in the JSON will be
+ // reported during config load, but
+ // we can at least warn here that
+ // it is not valid JSON
+ if !json.Valid(result) {
+ warnings = append(warnings, caddyconfig.Warning{
+ Message: "Resulting JSON is invalid.",
+ })
+ }
+
+ return
+}
+
+// Interface guard
+var _ caddyconfig.Adapter = (*Adapter)(nil)
diff --git a/go.mod b/go.mod
index d63097a..d647344 100644
--- a/go.mod
+++ b/go.mod
@@ -14,12 +14,14 @@ require (
github.com/google/go-cmp v0.3.1 // indirect
github.com/google/uuid v1.1.1 // indirect
github.com/huandu/xstrings v1.2.0 // indirect
+ github.com/ilibs/json5 v1.0.1
github.com/imdario/mergo v0.3.7 // indirect
github.com/klauspost/compress v1.7.1-0.20190613161414-0b31f265a57b
github.com/klauspost/cpuid v1.2.1
github.com/kr/pretty v0.1.0 // indirect
github.com/mholt/certmagic v0.6.2
github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936
+ github.com/muhammadmuzzammil1998/jsonc v0.0.0-20190902132743-e4903c4dea48
github.com/rs/cors v1.6.0
github.com/russross/blackfriday/v2 v2.0.1
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index 4180648..dfe572f 100644
--- a/go.sum
+++ b/go.sum
@@ -27,6 +27,8 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
+github.com/ilibs/json5 v1.0.1 h1:3e14wUQM8PyK6Hf1bM+zAQFxfG+N5oZj35x5vCNeQ58=
+github.com/ilibs/json5 v1.0.1/go.mod h1:kXsGuzHMPuZZTN15l0IQzy5PR8DrDhPB24tFgwpdKME=
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/klauspost/compress v1.7.1-0.20190613161414-0b31f265a57b h1:LHpBANNM/cw1PAXJtKV9dgfp6ztOKfdGXcltGmqU9aE=
@@ -45,6 +47,8 @@ github.com/miekg/dns v1.1.3 h1:1g0r1IvskvgL8rR+AcHzUA+oFmGcQlaIm4IqakufeMM=
github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936 h1:kw1v0NlnN+GZcU8Ma8CLF2Zzgjfx95gs3/GN3vYAPpo=
github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
+github.com/muhammadmuzzammil1998/jsonc v0.0.0-20190902132743-e4903c4dea48 h1:BM/fjd7MfvZuyoHXLv3YlWNIuNb47PLp6EyFBL1KIMg=
+github.com/muhammadmuzzammil1998/jsonc v0.0.0-20190902132743-e4903c4dea48/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI=