diff --git a/admin.go b/admin.go index 6ccec41e78c..8074cffe5cb 100644 --- a/admin.go +++ b/admin.go @@ -40,6 +40,7 @@ import ( "sync" "time" + "github.com/caddyserver/caddy/v2/caddyconfig/warning" "github.com/caddyserver/certmagic" "github.com/cespare/xxhash/v2" "github.com/prometheus/client_golang/prometheus" @@ -1314,9 +1315,10 @@ func (f AdminHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) erro // and client responses. If Message is unset, then // Err.Error() will be serialized in its place. type APIError struct { - HTTPStatus int `json:"-"` - Err error `json:"-"` - Message string `json:"error"` + HTTPStatus int `json:"-"` + Err error `json:"-"` + Message string `json:"error"` + Warnings []warning.Warning `json:"warnings,omitempty"` } func (e APIError) Error() string { diff --git a/caddyconfig/configadapters.go b/caddyconfig/configadapters.go index 0ca3c3af13f..9a73f00d1cc 100644 --- a/caddyconfig/configadapters.go +++ b/caddyconfig/configadapters.go @@ -19,6 +19,7 @@ import ( "fmt" "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig/warning" ) // Adapter is a type which can adapt a configuration to Caddy JSON. @@ -28,20 +29,7 @@ type Adapter interface { } // Warning represents a warning or notice related to conversion. -type Warning struct { - File string `json:"file,omitempty"` - Line int `json:"line,omitempty"` - Directive string `json:"directive,omitempty"` - Message string `json:"message,omitempty"` -} - -func (w Warning) String() string { - var directive string - if w.Directive != "" { - directive = fmt.Sprintf(" (%s)", w.Directive) - } - return fmt.Sprintf("%s:%d%s: %s", w.File, w.Line, directive, w.Message) -} +type Warning = warning.Warning // JSON encodes val as JSON, returning it as a json.RawMessage. Any // marshaling errors (which are highly unlikely with correct code) diff --git a/caddyconfig/load.go b/caddyconfig/load.go index 9422d2fbb03..d53132ae1b7 100644 --- a/caddyconfig/load.go +++ b/caddyconfig/load.go @@ -91,23 +91,19 @@ func (adminLoad) handleLoad(w http.ResponseWriter, r *http.Request) error { } body := buf.Bytes() + var warnings []Warning // if the config is formatted other than Caddy's native // JSON, we need to adapt it before loading it if ctHeader := r.Header.Get("Content-Type"); ctHeader != "" { - result, warnings, err := adaptByContentType(ctHeader, body) + result, wns, err := adaptByContentType(ctHeader, body) if err != nil { return caddy.APIError{ HTTPStatus: http.StatusBadRequest, Err: err, + Warnings: wns, } } - if len(warnings) > 0 { - respBody, err := json.Marshal(warnings) - if err != nil { - caddy.Log().Named("admin.api.load").Error(err.Error()) - } - _, _ = w.Write(respBody) - } + warnings = wns body = result } @@ -118,6 +114,7 @@ func (adminLoad) handleLoad(w http.ResponseWriter, r *http.Request) error { return caddy.APIError{ HTTPStatus: http.StatusBadRequest, Err: fmt.Errorf("loading config: %v", err), + Warnings: warnings, } } @@ -130,6 +127,16 @@ func (adminLoad) handleLoad(w http.ResponseWriter, r *http.Request) error { caddy.Log().Named("admin.api").Info("load complete") + // Send any warnings back even if there were no errors + if len(warnings) > 0 { + out := struct { + Warnings []Warning `json:"warnings"` + }{ + Warnings: warnings, + } + return json.NewEncoder(w).Encode(out) + } + return nil } diff --git a/caddyconfig/warning/warning.go b/caddyconfig/warning/warning.go new file mode 100644 index 00000000000..c97794fe31e --- /dev/null +++ b/caddyconfig/warning/warning.go @@ -0,0 +1,19 @@ +package warning + +import "fmt" + +// Warning represents a warning or notice related to conversion. +type Warning struct { + File string `json:"file,omitempty"` + Line int `json:"line,omitempty"` + Directive string `json:"directive,omitempty"` + Message string `json:"message,omitempty"` +} + +func (w Warning) String() string { + var directive string + if w.Directive != "" { + directive = fmt.Sprintf(" (%s)", w.Directive) + } + return fmt.Sprintf("%s:%d%s: %s", w.File, w.Line, directive, w.Message) +}