0
Fork 0
mirror of https://github.com/caddyserver/caddy.git synced 2024-12-23 22:27:38 -05:00
caddy/middleware/errors/errors_test.go
Matthew Holt 2a46f2a14e Revert recent Content-Length-related changes and fix fastcgi return
fastcgi's ServeHTTP method originally returned the correct value (0) in
b51e8bc191. Later, I mistakenly suggested
we change that to return the status code because I forgot that status
codes aren't logged by the return value. So fastcgi broke due in
3966936bd6 due to my error.

We later had to try to make up for this with ugly Content-Length checks
like in c37ad7f677. Turns out that all we
had to do was fix the returned status here back to 0. The proxy
middleware behaves the same way, and returning 0 is correct. We should
only return a status code if the response has not been written, but with
upstream servers, we do write a response; they do not know about our
error handler.

Also clarifed this in the middleware.Handler documentation.
2016-03-02 11:33:40 -07:00

168 lines
4.2 KiB
Go

package errors
import (
"bytes"
"errors"
"fmt"
"log"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"github.com/mholt/caddy/middleware"
)
func TestErrors(t *testing.T) {
// create a temporary page
path := filepath.Join(os.TempDir(), "errors_test.html")
f, err := os.Create(path)
if err != nil {
t.Fatal(err)
}
defer os.Remove(path)
const content = "This is a error page"
_, err = f.WriteString(content)
if err != nil {
t.Fatal(err)
}
f.Close()
buf := bytes.Buffer{}
em := ErrorHandler{
ErrorPages: map[int]string{
http.StatusNotFound: path,
http.StatusForbidden: "not_exist_file",
},
Log: log.New(&buf, "", 0),
}
_, notExistErr := os.Open("not_exist_file")
testErr := errors.New("test error")
tests := []struct {
next middleware.Handler
expectedCode int
expectedBody string
expectedLog string
expectedErr error
}{
{
next: genErrorHandler(http.StatusOK, nil, "normal"),
expectedCode: http.StatusOK,
expectedBody: "normal",
expectedLog: "",
expectedErr: nil,
},
{
next: genErrorHandler(http.StatusMovedPermanently, testErr, ""),
expectedCode: http.StatusMovedPermanently,
expectedBody: "",
expectedLog: fmt.Sprintf("[ERROR %d %s] %v\n", http.StatusMovedPermanently, "/", testErr),
expectedErr: testErr,
},
{
next: genErrorHandler(http.StatusBadRequest, nil, ""),
expectedCode: 0,
expectedBody: fmt.Sprintf("%d %s\n", http.StatusBadRequest,
http.StatusText(http.StatusBadRequest)),
expectedLog: "",
expectedErr: nil,
},
{
next: genErrorHandler(http.StatusNotFound, nil, ""),
expectedCode: 0,
expectedBody: content,
expectedLog: "",
expectedErr: nil,
},
{
next: genErrorHandler(http.StatusForbidden, nil, ""),
expectedCode: 0,
expectedBody: fmt.Sprintf("%d %s\n", http.StatusForbidden,
http.StatusText(http.StatusForbidden)),
expectedLog: fmt.Sprintf("[NOTICE %d /] could not load error page: %v\n",
http.StatusForbidden, notExistErr),
expectedErr: nil,
},
}
req, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatal(err)
}
for i, test := range tests {
em.Next = test.next
buf.Reset()
rec := httptest.NewRecorder()
code, err := em.ServeHTTP(rec, req)
if err != test.expectedErr {
t.Errorf("Test %d: Expected error %v, but got %v",
i, test.expectedErr, err)
}
if code != test.expectedCode {
t.Errorf("Test %d: Expected status code %d, but got %d",
i, test.expectedCode, code)
}
if body := rec.Body.String(); body != test.expectedBody {
t.Errorf("Test %d: Expected body %q, but got %q",
i, test.expectedBody, body)
}
if log := buf.String(); !strings.Contains(log, test.expectedLog) {
t.Errorf("Test %d: Expected log %q, but got %q",
i, test.expectedLog, log)
}
}
}
func TestVisibleErrorWithPanic(t *testing.T) {
const panicMsg = "I'm a panic"
eh := ErrorHandler{
ErrorPages: make(map[int]string),
Debug: true,
Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
panic(panicMsg)
}),
}
req, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatal(err)
}
rec := httptest.NewRecorder()
code, err := eh.ServeHTTP(rec, req)
if code != 0 {
t.Errorf("Expected error handler to return 0 (it should write to response), got status %d", code)
}
if err != nil {
t.Errorf("Expected error handler to return nil error (it should panic!), but got '%v'", err)
}
body := rec.Body.String()
if !strings.Contains(body, "[PANIC /] middleware/errors/errors_test.go") {
t.Errorf("Expected response body to contain error log line, but it didn't:\n%s", body)
}
if !strings.Contains(body, panicMsg) {
t.Errorf("Expected response body to contain panic message, but it didn't:\n%s", body)
}
if len(body) < 500 {
t.Errorf("Expected response body to contain stack trace, but it was too short: len=%d", len(body))
}
}
func genErrorHandler(status int, err error, body string) middleware.Handler {
return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
if len(body) > 0 {
w.Header().Set("Content-Length", strconv.Itoa(len(body)))
fmt.Fprint(w, body)
}
return status, err
})
}