@marcel91200 / caddy Mirror · read-only / commits / 2d5a30b9
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 13, 14:15 UTC

caddyhttp: Set Content-Type for static response (#4999)

Matt Holt committed Aug 31, 2022 at 09:43 UTC 2d5a30b908d022d76c246a09154d1fc611695a17
1 file changed +33 -9
modules/caddyhttp/staticresp.go
+33 -9
@@ -88,10 +88,18 @@ type StaticResponse struct {
88 // if needing to use a placeholder, a string.
89 StatusCode WeakString `json:"status_code,omitempty"`
90
91 - // Header fields to set on the response.
91 + // Header fields to set on the response; overwrites any existing
92 + // header fields of the same names after normalization.
93 Headers http.Header `json:"headers,omitempty"`
94
94 - // The response body.
95 + // The response body. If non-empty, the Content-Type header may
96 + // be added automatically if it is not explicitly configured nor
97 + // already set on the response; the default value is
98 + // "text/plain; charset=utf-8" unless the body is a valid JSON object
99 + // or array, in which case the value will be "application/json".
100 + // Other than those common special cases the Content-Type header
101 + // should be set explicitly if it is desired because MIME sniffing
102 + // is disabled for safety.
103 Body string `json:"body,omitempty"`
104
105 // If true, the server will close the client's connection
@@ -114,10 +122,10 @@ func (StaticResponse) CaddyModule() caddy.ModuleInfo {
122
123 // UnmarshalCaddyfile sets up the handler from Caddyfile tokens. Syntax:
124 //
117 -// respond [<matcher>] <status>|<body> [<status>] {
118 -// body <text>
119 -// close
120 -// }
125 +// respond [<matcher>] <status>|<body> [<status>] {
126 +// body <text>
127 +// close
128 +// }
129 //
130 // If there is just one argument (other than the matcher), it is considered
131 // 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
194 w.Header()[field] = newVals
195 }
196
189 - // do not allow Go to sniff the content-type
197 + // implicitly set Content-Type header if we can do so safely
198 + // (this allows templates handler to eval templates successfully
199 + // or for clients to render JSON properly which is very common)
200 + body := repl.ReplaceKnown(s.Body, "")
201 + if body != "" && w.Header().Get("Content-Type") == "" {
202 + content := strings.TrimSpace(s.Body)
203 + if len(content) > 2 &&
204 + (content[0] == '{' && content[len(content)-1] == '}' ||
205 + (content[0] == '[' && content[len(content)-1] == ']')) &&
206 + json.Valid([]byte(content)) {
207 + w.Header().Set("Content-Type", "application/json")
208 + } else {
209 + w.Header().Set("Content-Type", "text/plain; charset=utf-8")
210 + }
211 + }
212 +
213 + // do not allow Go to sniff the content-type, for safety
214 if w.Header().Get("Content-Type") == "" {
215 w.Header()["Content-Type"] = nil
216 }
@@ -213,8 +237,8 @@ func (s StaticResponse) ServeHTTP(w http.ResponseWriter, r *http.Request, _ Hand
237 w.WriteHeader(statusCode)
238
239 // write response body
216 - if s.Body != "" {
217 - fmt.Fprint(w, repl.ReplaceKnown(s.Body, ""))
240 + if body != "" {
241 + fmt.Fprint(w, body)
242 }
243
244 return nil