Repository: gobuffalo/buffalo
Pull request #1535 (2019-01-15 19:34:31)

Default error page content-type to text/html
This replaces PR #1534 (based on master) with a patch based on the development branch. It looks like this branch already covers the common case of a form submission, but it may not make sense to reflect the client's content type for any other non-xml/json responses. 

The error handler only supports html, xml, and json responses; this PR ensures that the content-type will be correct in those three situations. 

hdm:  I updated the two variable names; let me know if you would like to see any further changes around this.
hdm: @senorprogrammer thanks! fixed in 8fb2459

Patch:
diff --git a/errors.go b/errors.go
index 010495b9..92c3ace5 100644
--- a/errors.go
+++ b/errors.go
@@ -140,7 +140,7 @@ type ErrorResponse struct {
 	Code    int      `json:"code" xml:"code,attr"`
 }
 
-const defErrorCT = "text/html; charset=utf-8"
+const defaultErrorCT = "text/html; charset=utf-8"
 
 type stackTracer interface {
 	StackTrace() errors.StackTrace
@@ -148,16 +148,13 @@ type stackTracer interface {
 
 func defaultErrorHandler(status int, origErr error, c Context) error {
 	env := c.Value("env")
-	ct := defaults.String(httpx.ContentType(c.Request()), defErrorCT)
-	if strings.Contains(ct, "form") {
-		ct = defErrorCT
-	}
-	c.Response().Header().Set("content-type", ct)
+	requestCT := defaults.String(httpx.ContentType(c.Request()), defaultErrorCT)
 
 	c.Logger().Error(origErr)
 	c.Response().WriteHeader(status)
 
 	if env != nil && env.(string) == "production" {
+		c.Response().Header().Set("content-type", defaultErrorCT)
 		responseBody := productionErrorResponseFor(status)
 		c.Response().Write(responseBody)
 		return nil
@@ -171,8 +168,9 @@ func defaultErrorHandler(status int, origErr error, c Context) error {
 		}
 		trace = fmt.Sprintf("%s\n%s", origErr, strings.Join(log, "\n"))
 	}
-	switch strings.ToLower(ct) {
+	switch strings.ToLower(requestCT) {
 	case "application/json", "text/json", "json":
+		c.Response().Header().Set("content-type", "application/json")
 		err := json.NewEncoder(c.Response()).Encode(&ErrorResponse{
 			Error: errors.Cause(origErr).Error(),
 			Trace: trace,
@@ -182,6 +180,7 @@ func defaultErrorHandler(status int, origErr error, c Context) error {
 			return errors.WithStack(err)
 		}
 	case "application/xml", "text/xml", "xml":
+		c.Response().Header().Set("content-type", "text/xml")
 		err := xml.NewEncoder(c.Response()).Encode(&ErrorResponse{
 			Error: errors.Cause(origErr).Error(),
 			Trace: trace,
@@ -191,7 +190,7 @@ func defaultErrorHandler(status int, origErr error, c Context) error {
 			return errors.WithStack(err)
 		}
 	default:
-		c.Response().Header().Set("content-type", "text/html; charset=utf-8")
+		c.Response().Header().Set("content-type", defaultErrorCT)
 		if err := c.Request().ParseForm(); err != nil {
 			trace = fmt.Sprintf("%s\n%s", err.Error(), trace)
 		}


Test patch:
diff --git a/errors_test.go b/errors_test.go
index 0b778201..bb2c8d04 100644
--- a/errors_test.go
+++ b/errors_test.go
@@ -52,7 +52,7 @@ func Test_defaultErrorHandler_XML(t *testing.T) {
 	res := w.XML("/").Get()
 	r.Equal(401, res.Code)
 	ct := res.Header().Get("content-type")
-	r.Equal("application/xml", ct)
+	r.Equal("text/xml", ct)
 	b := res.Body.String()
 	r.Contains(b, `<response code="401">`)
 	r.Contains(b, `<error>boom</error>`)