| 179 | } |
| 180 | |
| 181 | func (s StaticResponse) ServeHTTP(w http.ResponseWriter, r *http.Request, next Handler) error { |
| 182 | // close the connection immediately |
| 183 | if s.Abort { |
| 184 | panic(http.ErrAbortHandler) |
| 185 | } |
| 186 | |
| 187 | // close the connection after responding |
| 188 | if s.Close { |
| 189 | r.Close = true |
| 190 | w.Header().Set("Connection", "close") |
| 191 | } |
| 192 | |
| 193 | repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) |
| 194 | |
| 195 | // set all headers |
| 196 | for field, vals := range s.Headers { |
| 197 | field = textproto.CanonicalMIMEHeaderKey(repl.ReplaceAll(field, "")) |
| 198 | newVals := make([]string, len(vals)) |
| 199 | for i := range vals { |
| 200 | newVals[i] = repl.ReplaceAll(vals[i], "") |
| 201 | } |
| 202 | w.Header()[field] = newVals |
| 203 | } |
| 204 | |
| 205 | // implicitly set Content-Type header if we can do so safely |
| 206 | // (this allows templates handler to eval templates successfully |
| 207 | // or for clients to render JSON properly which is very common) |
| 208 | body := repl.ReplaceKnown(s.Body, "") |
| 209 | if body != "" && w.Header().Get("Content-Type") == "" { |
| 210 | content := strings.TrimSpace(body) |
| 211 | if len(content) > 2 && |
| 212 | (content[0] == '{' && content[len(content)-1] == '}' || |
| 213 | (content[0] == '[' && content[len(content)-1] == ']')) && |
| 214 | json.Valid([]byte(content)) { |
| 215 | w.Header().Set("Content-Type", "application/json") |
| 216 | } else { |
| 217 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | // do not allow Go to sniff the content-type, for safety |
| 222 | if w.Header().Get("Content-Type") == "" { |
| 223 | w.Header()["Content-Type"] = nil |
| 224 | } |
| 225 | |
| 226 | // get the status code; if this handler exists in an error route, |
| 227 | // use the recommended status code as the default; otherwise 200 |
| 228 | statusCode := http.StatusOK |
| 229 | if reqErr, ok := r.Context().Value(ErrorCtxKey).(error); ok { |
| 230 | if handlerErr, ok := reqErr.(HandlerError); ok { |
| 231 | if handlerErr.StatusCode > 0 { |
| 232 | statusCode = handlerErr.StatusCode |
| 233 | } |
| 234 | } |
| 235 | } |
| 236 | if codeStr := s.StatusCode.String(); codeStr != "" { |
| 237 | intVal, err := strconv.Atoi(repl.ReplaceAll(codeStr, "")) |
| 238 | if err != nil { |