mirror of
https://github.com/labstack/echo.git
synced 2024-12-18 16:20:53 +02:00
6d9e043284
This reintroduces support for Go modules, as v4. CloseNotifier() is removed as it has been obsoleted, see https://golang.org/doc/go1.11#net/http It was already NOT working (not sending signals) as of 1.11 the functionality was gone, we merely deleted the functions that exposed it. If anyone still relies on it they should migrate to using `c.Request().Context().Done()` instead. Closes #1268, #1255
174 lines
5.2 KiB
Go
174 lines
5.2 KiB
Go
package middleware
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
"unsafe"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestLogger(t *testing.T) {
|
|
// Note: Just for the test coverage, not a real test.
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
h := Logger()(func(c echo.Context) error {
|
|
return c.String(http.StatusOK, "test")
|
|
})
|
|
|
|
// Status 2xx
|
|
h(c)
|
|
|
|
// Status 3xx
|
|
rec = httptest.NewRecorder()
|
|
c = e.NewContext(req, rec)
|
|
h = Logger()(func(c echo.Context) error {
|
|
return c.String(http.StatusTemporaryRedirect, "test")
|
|
})
|
|
h(c)
|
|
|
|
// Status 4xx
|
|
rec = httptest.NewRecorder()
|
|
c = e.NewContext(req, rec)
|
|
h = Logger()(func(c echo.Context) error {
|
|
return c.String(http.StatusNotFound, "test")
|
|
})
|
|
h(c)
|
|
|
|
// Status 5xx with empty path
|
|
req = httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec = httptest.NewRecorder()
|
|
c = e.NewContext(req, rec)
|
|
h = Logger()(func(c echo.Context) error {
|
|
return errors.New("error")
|
|
})
|
|
h(c)
|
|
}
|
|
|
|
func TestLoggerIPAddress(t *testing.T) {
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
buf := new(bytes.Buffer)
|
|
e.Logger.SetOutput(buf)
|
|
ip := "127.0.0.1"
|
|
h := Logger()(func(c echo.Context) error {
|
|
return c.String(http.StatusOK, "test")
|
|
})
|
|
|
|
// With X-Real-IP
|
|
req.Header.Add(echo.HeaderXRealIP, ip)
|
|
h(c)
|
|
assert.Contains(t, ip, buf.String())
|
|
|
|
// With X-Forwarded-For
|
|
buf.Reset()
|
|
req.Header.Del(echo.HeaderXRealIP)
|
|
req.Header.Add(echo.HeaderXForwardedFor, ip)
|
|
h(c)
|
|
assert.Contains(t, ip, buf.String())
|
|
|
|
buf.Reset()
|
|
h(c)
|
|
assert.Contains(t, ip, buf.String())
|
|
}
|
|
|
|
func TestLoggerTemplate(t *testing.T) {
|
|
buf := new(bytes.Buffer)
|
|
|
|
e := echo.New()
|
|
e.Use(LoggerWithConfig(LoggerConfig{
|
|
Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}","host":"${host}","user_agent":"${user_agent}",` +
|
|
`"method":"${method}","uri":"${uri}","status":${status}, "latency":${latency},` +
|
|
`"latency_human":"${latency_human}","bytes_in":${bytes_in}, "path":"${path}", "referer":"${referer}",` +
|
|
`"bytes_out":${bytes_out},"ch":"${header:X-Custom-Header}", "protocol":"${protocol}"` +
|
|
`"us":"${query:username}", "cf":"${form:username}", "session":"${cookie:session}"}` + "\n",
|
|
Output: buf,
|
|
}))
|
|
|
|
e.GET("/", func(c echo.Context) error {
|
|
return c.String(http.StatusOK, "Header Logged")
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/?username=apagano-param&password=secret", nil)
|
|
req.RequestURI = "/"
|
|
req.Header.Add(echo.HeaderXRealIP, "127.0.0.1")
|
|
req.Header.Add("Referer", "google.com")
|
|
req.Header.Add("User-Agent", "echo-tests-agent")
|
|
req.Header.Add("X-Custom-Header", "AAA-CUSTOM-VALUE")
|
|
req.Header.Add("X-Request-ID", "6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
|
req.Header.Add("Cookie", "_ga=GA1.2.000000000.0000000000; session=ac08034cd216a647fc2eb62f2bcf7b810")
|
|
req.Form = url.Values{
|
|
"username": []string{"apagano-form"},
|
|
"password": []string{"secret-form"},
|
|
}
|
|
|
|
rec := httptest.NewRecorder()
|
|
e.ServeHTTP(rec, req)
|
|
|
|
cases := map[string]bool{
|
|
"apagano-param": true,
|
|
"apagano-form": true,
|
|
"AAA-CUSTOM-VALUE": true,
|
|
"BBB-CUSTOM-VALUE": false,
|
|
"secret-form": false,
|
|
"hexvalue": false,
|
|
"GET": true,
|
|
"127.0.0.1": true,
|
|
"\"path\":\"/\"": true,
|
|
"\"uri\":\"/\"": true,
|
|
"\"status\":200": true,
|
|
"\"bytes_in\":0": true,
|
|
"google.com": true,
|
|
"echo-tests-agent": true,
|
|
"6ba7b810-9dad-11d1-80b4-00c04fd430c8": true,
|
|
"ac08034cd216a647fc2eb62f2bcf7b810": true,
|
|
}
|
|
|
|
for token, present := range cases {
|
|
assert.True(t, strings.Contains(buf.String(), token) == present, "Case: "+token)
|
|
}
|
|
}
|
|
|
|
func TestLoggerCustomTimestamp(t *testing.T) {
|
|
buf := new(bytes.Buffer)
|
|
customTimeFormat := "2006-01-02 15:04:05.00000"
|
|
e := echo.New()
|
|
e.Use(LoggerWithConfig(LoggerConfig{
|
|
Format: `{"time":"${time_custom}","id":"${id}","remote_ip":"${remote_ip}","host":"${host}","user_agent":"${user_agent}",` +
|
|
`"method":"${method}","uri":"${uri}","status":${status}, "latency":${latency},` +
|
|
`"latency_human":"${latency_human}","bytes_in":${bytes_in}, "path":"${path}", "referer":"${referer}",` +
|
|
`"bytes_out":${bytes_out},"ch":"${header:X-Custom-Header}",` +
|
|
`"us":"${query:username}", "cf":"${form:username}", "session":"${cookie:session}"}` + "\n",
|
|
CustomTimeFormat: customTimeFormat,
|
|
Output: buf,
|
|
}))
|
|
|
|
e.GET("/", func(c echo.Context) error {
|
|
return c.String(http.StatusOK, "custom time stamp test")
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
e.ServeHTTP(rec, req)
|
|
|
|
var objs map[string]*json.RawMessage
|
|
if err := json.Unmarshal([]byte(buf.String()), &objs); err != nil {
|
|
panic(err)
|
|
}
|
|
loggedTime := *(*string)(unsafe.Pointer(objs["time"]))
|
|
_, err := time.Parse(customTimeFormat, loggedTime)
|
|
assert.Error(t, err)
|
|
}
|