summaryrefslogtreecommitdiff
path: root/modules/caddyhttp
diff options
context:
space:
mode:
authorMatt Holt <mholt@users.noreply.github.com>2022-08-31 09:43:46 -0600
committerGitHub <noreply@github.com>2022-08-31 09:43:46 -0600
commit2d5a30b908d022d76c246a09154d1fc611695a17 (patch)
tree3ffc8f2393aff0bde39a7cd8b6ab33d36ed0bf10 /modules/caddyhttp
parent687a4b9e81c7b0b08c760ec33808c721d6775e0e (diff)
caddyhttp: Set Content-Type for static response (#4999)
Diffstat (limited to 'modules/caddyhttp')
-rw-r--r--modules/caddyhttp/staticresp.go42
1 files changed, 33 insertions, 9 deletions
diff --git a/modules/caddyhttp/staticresp.go b/modules/caddyhttp/staticresp.go
index f0aea03..f429692 100644
--- a/modules/caddyhttp/staticresp.go
+++ b/modules/caddyhttp/staticresp.go
@@ -88,10 +88,18 @@ type StaticResponse struct {
// if needing to use a placeholder, a string.
StatusCode WeakString `json:"status_code,omitempty"`
- // Header fields to set on the response.
+ // Header fields to set on the response; overwrites any existing
+ // header fields of the same names after normalization.
Headers http.Header `json:"headers,omitempty"`
- // The response body.
+ // The response body. If non-empty, the Content-Type header may
+ // be added automatically if it is not explicitly configured nor
+ // already set on the response; the default value is
+ // "text/plain; charset=utf-8" unless the body is a valid JSON object
+ // or array, in which case the value will be "application/json".
+ // Other than those common special cases the Content-Type header
+ // should be set explicitly if it is desired because MIME sniffing
+ // is disabled for safety.
Body string `json:"body,omitempty"`
// If true, the server will close the client's connection
@@ -114,10 +122,10 @@ func (StaticResponse) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the handler from Caddyfile tokens. Syntax:
//
-// respond [<matcher>] <status>|<body> [<status>] {
-// body <text>
-// close
-// }
+// respond [<matcher>] <status>|<body> [<status>] {
+// body <text>
+// close
+// }
//
// If there is just one argument (other than the matcher), it is considered
// to be a status code if it's a valid positive integer of 3 digits.
@@ -186,7 +194,23 @@ func (s StaticResponse) ServeHTTP(w http.ResponseWriter, r *http.Request, _ Hand
w.Header()[field] = newVals
}
- // do not allow Go to sniff the content-type
+ // implicitly set Content-Type header if we can do so safely
+ // (this allows templates handler to eval templates successfully
+ // or for clients to render JSON properly which is very common)
+ body := repl.ReplaceKnown(s.Body, "")
+ if body != "" && w.Header().Get("Content-Type") == "" {
+ content := strings.TrimSpace(s.Body)
+ if len(content) > 2 &&
+ (content[0] == '{' && content[len(content)-1] == '}' ||
+ (content[0] == '[' && content[len(content)-1] == ']')) &&
+ json.Valid([]byte(content)) {
+ w.Header().Set("Content-Type", "application/json")
+ } else {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ }
+ }
+
+ // do not allow Go to sniff the content-type, for safety
if w.Header().Get("Content-Type") == "" {
w.Header()["Content-Type"] = nil
}
@@ -213,8 +237,8 @@ func (s StaticResponse) ServeHTTP(w http.ResponseWriter, r *http.Request, _ Hand
w.WriteHeader(statusCode)
// write response body
- if s.Body != "" {
- fmt.Fprint(w, repl.ReplaceKnown(s.Body, ""))
+ if body != "" {
+ fmt.Fprint(w, body)
}
return nil