1
0
mirror of https://github.com/labstack/echo.git synced 2025-07-13 01:30:31 +02:00

Now using sync.Pool

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana
2016-02-04 14:40:08 -08:00
parent 443a0bb48d
commit f405794a7c
18 changed files with 317 additions and 235 deletions

View File

@ -47,7 +47,7 @@ type (
Redirect(int, string) error Redirect(int, string) error
Error(err error) Error(err error)
Logger() *log.Logger Logger() *log.Logger
X() *context Context() *context
} }
context struct { context struct {
@ -307,8 +307,8 @@ func (c *context) Logger() *log.Logger {
return c.echo.logger return c.echo.logger
} }
// X returns the `context` instance. // Context returns the `context` instance.
func (c *context) X() *context { func (c *context) Context() *context {
return c return c
} }

View File

@ -51,8 +51,8 @@ func TestContext(t *testing.T) {
assert.Nil(t, c.Socket()) assert.Nil(t, c.Socket())
// Param by id // Param by id
c.X().pnames = []string{"id"} c.Context().pnames = []string{"id"}
c.X().pvalues = []string{"1"} c.Context().pvalues = []string{"1"}
assert.Equal(t, "1", c.P(0)) assert.Equal(t, "1", c.P(0))
// Param by name // Param by name
@ -68,13 +68,13 @@ func TestContext(t *testing.T) {
// JSON // JSON
testBindOk(t, c, ApplicationJSON) testBindOk(t, c, ApplicationJSON)
c.X().request = test.NewRequest(POST, "/", strings.NewReader(incorrectContent)) c.Context().request = test.NewRequest(POST, "/", strings.NewReader(incorrectContent))
testBindError(t, c, ApplicationJSON) testBindError(t, c, ApplicationJSON)
// XML // XML
c.X().request = test.NewRequest(POST, "/", strings.NewReader(userXML)) c.Context().request = test.NewRequest(POST, "/", strings.NewReader(userXML))
testBindOk(t, c, ApplicationXML) testBindOk(t, c, ApplicationXML)
c.X().request = test.NewRequest(POST, "/", strings.NewReader(incorrectContent)) c.Context().request = test.NewRequest(POST, "/", strings.NewReader(incorrectContent))
testBindError(t, c, ApplicationXML) testBindError(t, c, ApplicationXML)
// Unsupported // Unsupported
@ -87,14 +87,14 @@ func TestContext(t *testing.T) {
tpl := &Template{ tpl := &Template{
templates: template.Must(template.New("hello").Parse("Hello, {{.}}!")), templates: template.Must(template.New("hello").Parse("Hello, {{.}}!")),
} }
c.X().echo.SetRenderer(tpl) c.Context().echo.SetRenderer(tpl)
err := c.Render(http.StatusOK, "hello", "Joe") err := c.Render(http.StatusOK, "hello", "Joe")
if assert.NoError(t, err) { if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Status()) assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, "Hello, Joe!", rec.Body.String()) assert.Equal(t, "Hello, Joe!", rec.Body.String())
} }
c.X().echo.renderer = nil c.Context().echo.renderer = nil
err = c.Render(http.StatusOK, "hello", "Joe") err = c.Render(http.StatusOK, "hello", "Joe")
assert.Error(t, err) assert.Error(t, err)
@ -226,12 +226,12 @@ func TestContext(t *testing.T) {
// Error // Error
rec = test.NewResponseRecorder() rec = test.NewResponseRecorder()
c = NewContext(req, rec, e).X() c = NewContext(req, rec, e).Context()
c.Error(errors.New("error")) c.Error(errors.New("error"))
assert.Equal(t, http.StatusInternalServerError, c.Response().Status()) assert.Equal(t, http.StatusInternalServerError, c.Response().Status())
// reset // reset
c.X().reset(req, test.NewResponseRecorder(), e) c.Context().reset(req, test.NewResponseRecorder(), e)
} }
func TestContextPath(t *testing.T) { func TestContextPath(t *testing.T) {

51
echo.go
View File

@ -554,8 +554,23 @@ func (e *Echo) SetEngine(t engine.Type) {
} }
// Run runs a server. // Run runs a server.
func (e *Echo) Run(address string) { func (e *Echo) Run(addr string) {
config := &engine.Config{Address: address} c := &engine.Config{Address: addr}
e.RunWithConfig(c)
}
// RunTLS runs a server with TLS configuration.
func (e *Echo) RunTLS(addr, certfile, keyfile string) {
c := &engine.Config{
Address: addr,
TLSCertfile: certfile,
TLSKeyfile: keyfile,
}
e.RunWithConfig(c)
}
// RunWithConfig runs a server with engine configuration.
func (e *Echo) RunWithConfig(config *engine.Config) {
handler := func(req engine.Request, res engine.Response) { handler := func(req engine.Request, res engine.Response) {
if e.hook != nil { if e.hook != nil {
e.hook(req, res) e.hook(req, res)
@ -585,38 +600,6 @@ func (e *Echo) Run(address string) {
} }
e.engine.Start() e.engine.Start()
// e.run(e.Server(addr))
}
// RunTLS runs a server with TLS configuration.
func (e *Echo) RunTLS(addr, crtFile, keyFile string) {
// e.run(e.Server(addr), crtFile, keyFile)
}
// RunServer runs a custom server.
func (e *Echo) RunServer(s *http.Server) {
// e.run(s)
}
// RunTLSServer runs a custom server with TLS configuration.
func (e *Echo) RunTLSServer(s *http.Server, crtFile, keyFile string) {
// e.run(s, crtFile, keyFile)
}
func (e *Echo) run(s *http.Server, files ...string) {
// s.Handler = e
// // TODO: Remove in Go 1.6+
// if e.http2 {
// http2.ConfigureServer(s, nil)
// }
// if len(files) == 0 {
// e.logger.Fatal(s.ListenAndServe())
// } else if len(files) == 2 {
// e.logger.Fatal(s.ListenAndServeTLS(files[0], files[1]))
// } else {
// e.logger.Fatal("invalid TLS configuration")
// }
} }
func NewHTTPError(code int, msg ...string) *HTTPError { func NewHTTPError(code int, msg ...string) *HTTPError {

View File

@ -307,9 +307,9 @@ func TestEchoGroup(t *testing.T) {
func TestEchoNotFound(t *testing.T) { func TestEchoNotFound(t *testing.T) {
e := New() e := New()
req := test.NewRequest(GET, "/files", nil) req := test.NewRequest(GET, "/files", nil)
res := test.NewResponseRecorder() rec := test.NewResponseRecorder()
e.ServeHTTP(req, res) e.ServeHTTP(req, rec)
assert.Equal(t, http.StatusNotFound, res.Status()) assert.Equal(t, http.StatusNotFound, rec.Status())
} }
func TestEchoMethodNotAllowed(t *testing.T) { func TestEchoMethodNotAllowed(t *testing.T) {
@ -318,9 +318,9 @@ func TestEchoMethodNotAllowed(t *testing.T) {
return c.String(http.StatusOK, "Echo!") return c.String(http.StatusOK, "Echo!")
}) })
req := test.NewRequest(POST, "/", nil) req := test.NewRequest(POST, "/", nil)
res := test.NewResponseRecorder() rec := test.NewResponseRecorder()
e.ServeHTTP(req, res) e.ServeHTTP(req, rec)
assert.Equal(t, http.StatusMethodNotAllowed, res.Status()) assert.Equal(t, http.StatusMethodNotAllowed, rec.Status())
} }
func TestEchoHTTPError(t *testing.T) { func TestEchoHTTPError(t *testing.T) {
@ -349,8 +349,8 @@ func TestEchoHook(t *testing.T) {
} }
}) })
req := test.NewRequest(GET, "/test/", nil) req := test.NewRequest(GET, "/test/", nil)
res := test.NewResponseRecorder() rec := test.NewResponseRecorder()
e.ServeHTTP(req, res) e.ServeHTTP(req, rec)
assert.Equal(t, req.URL().Path(), "/test") assert.Equal(t, req.URL().Path(), "/test")
} }
@ -370,7 +370,7 @@ func testMethod(t *testing.T, method, path string, e *Echo) {
func request(method, path string, e *Echo) (int, string) { func request(method, path string, e *Echo) (int, string) {
req := test.NewRequest(method, path, nil) req := test.NewRequest(method, path, nil)
res := test.NewResponseRecorder() rec := test.NewResponseRecorder()
e.ServeHTTP(req, res) e.ServeHTTP(req, rec)
return res.Status(), res.Body.String() return rec.Status(), rec.Body.String()
} }

View File

@ -1,6 +1,9 @@
package engine package engine
import "io" import (
"io"
"time"
)
type ( type (
Type uint8 Type uint8
@ -31,6 +34,8 @@ type (
Status() int Status() int
Size() int64 Size() int64
Committed() bool Committed() bool
SetWriter(io.Writer)
Writer() io.Writer
} }
Header interface { Header interface {
@ -50,6 +55,10 @@ type (
Config struct { Config struct {
Address string Address string
ReadTimeout time.Duration
WriteTimeout time.Duration
TLSCertfile string
TLSKeyfile string
} }
) )

View File

@ -1,6 +1,8 @@
package fasthttp package fasthttp
import ( import (
"io"
"github.com/labstack/echo/engine" "github.com/labstack/echo/engine"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
) )
@ -12,6 +14,7 @@ type (
status int status int
size int64 size int64
committed bool committed bool
writer io.Writer
} }
) )
@ -38,3 +41,11 @@ func (r *Response) Size() int64 {
func (r *Response) Committed() bool { func (r *Response) Committed() bool {
return r.committed return r.committed
} }
func (r *Response) SetWriter(w io.Writer) {
r.writer = w
}
func (r *Response) Writer() io.Writer {
return r.writer
}

View File

@ -1,8 +1,9 @@
package fasthttp package fasthttp
import ( import (
"log"
"net/http" "net/http"
"github.com/labstack/gommon/log"
) )
import ( import (
"github.com/labstack/echo/engine" "github.com/labstack/echo/engine"
@ -27,7 +28,6 @@ func NewServer(config *engine.Config, handler engine.HandlerFunc) *Server {
func (s *Server) Start() { func (s *Server) Start() {
fasthttp.ListenAndServe(s.config.Address, func(ctx *fasthttp.RequestCtx) { fasthttp.ListenAndServe(s.config.Address, func(ctx *fasthttp.RequestCtx) {
println("FastHTTP")
req := &Request{ req := &Request{
context: ctx, context: ctx,
url: &URL{ctx.URI()}, url: &URL{ctx.URI()},

View File

@ -4,22 +4,26 @@ import "net/http"
type ( type (
Header struct { Header struct {
http.Header header http.Header
} }
) )
func (h *Header) Add(key, val string) { func (h *Header) Add(key, val string) {
h.Header.Add(key, val) h.header.Add(key, val)
} }
func (h *Header) Del(key string) { func (h *Header) Del(key string) {
h.Header.Del(key) h.header.Del(key)
} }
func (h *Header) Get(key string) string { func (h *Header) Get(key string) string {
return h.Header.Get(key) return h.header.Get(key)
} }
func (h *Header) Set(key, val string) { func (h *Header) Set(key, val string) {
h.Header.Set(key, val) h.header.Set(key, val)
}
func (h *Header) reset(hdr http.Header) {
h.header = hdr
} }

View File

@ -18,7 +18,7 @@ type (
func NewRequest(r *http.Request) *Request { func NewRequest(r *http.Request) *Request {
return &Request{ return &Request{
request: r, request: r,
url: NewURL(r.URL), url: &URL{url: r.URL},
header: &Header{r.Header}, header: &Header{r.Header},
} }
} }
@ -54,3 +54,9 @@ func (r *Request) Body() io.ReadCloser {
func (r *Request) FormValue(name string) string { func (r *Request) FormValue(name string) string {
return r.request.FormValue(name) return r.request.FormValue(name)
} }
func (r *Request) reset(req *http.Request, h engine.Header, u engine.URL) {
r.request = req
r.header = h
r.url = u
}

View File

@ -1,7 +1,11 @@
package standard package standard
import "net/http" import (
import "github.com/labstack/echo/engine" "io"
"net/http"
"github.com/labstack/echo/engine"
)
type ( type (
Response struct { Response struct {
@ -10,6 +14,7 @@ type (
status int status int
size int64 size int64
committed bool committed bool
writer io.Writer
} }
) )
@ -17,6 +22,7 @@ func NewResponse(w http.ResponseWriter) *Response {
return &Response{ return &Response{
response: w, response: w,
header: &Header{w.Header()}, header: &Header{w.Header()},
writer: w,
} }
} }
@ -35,7 +41,7 @@ func (r *Response) WriteHeader(code int) {
} }
func (r *Response) Write(b []byte) (n int, err error) { func (r *Response) Write(b []byte) (n int, err error) {
n, err = r.response.Write(b) n, err = r.writer.Write(b)
r.size += int64(n) r.size += int64(n)
return return
} }
@ -51,3 +57,20 @@ func (r *Response) Size() int64 {
func (r *Response) Committed() bool { func (r *Response) Committed() bool {
return r.committed return r.committed
} }
func (r *Response) SetWriter(w io.Writer) {
r.writer = w
}
func (r *Response) Writer() io.Writer {
return r.writer
}
func (r *Response) reset(w http.ResponseWriter, h engine.Header) {
r.response = w
r.header = h
r.status = http.StatusOK
r.size = 0
r.committed = false
r.writer = w
}

View File

@ -3,6 +3,7 @@ package standard
import ( import (
"log" "log"
"net/http" "net/http"
"sync"
"github.com/labstack/echo/engine" "github.com/labstack/echo/engine"
) )
@ -12,6 +13,14 @@ type (
*http.Server *http.Server
config *engine.Config config *engine.Config
handler engine.HandlerFunc handler engine.HandlerFunc
pool *Pool
}
Pool struct {
request sync.Pool
response sync.Pool
header sync.Pool
url sync.Pool
} }
) )
@ -20,13 +29,54 @@ func NewServer(config *engine.Config, handler engine.HandlerFunc) *Server {
Server: new(http.Server), Server: new(http.Server),
config: config, config: config,
handler: handler, handler: handler,
pool: &Pool{
request: sync.Pool{
New: func() interface{} {
return &Request{}
},
},
response: sync.Pool{
New: func() interface{} {
return &Response{}
},
},
header: sync.Pool{
New: func() interface{} {
return &Header{}
},
},
url: sync.Pool{
New: func() interface{} {
return &URL{}
},
},
},
} }
} }
func (s *Server) Start() { func (s *Server) Start() {
s.Addr = s.config.Address s.Addr = s.config.Address
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
s.handler(NewRequest(r), NewResponse(w)) // Request
req := s.pool.request.Get().(*Request)
reqHdr := s.pool.request.Get().(*Header)
reqURL := s.pool.request.Get().(*URL)
reqHdr.reset(r.Header)
reqURL.reset(r.URL)
req.reset(r, reqHdr, reqURL)
// Response
res := s.pool.request.Get().(*Response)
resHdr := s.pool.request.Get().(*Header)
res.reset(w, reqHdr)
s.handler(req, res)
s.pool.request.Put(req)
s.pool.header.Put(reqHdr)
s.pool.url.Put(reqURL)
s.pool.response.Put(res)
s.pool.header.Put(resHdr)
}) })
log.Fatal(s.ListenAndServe()) log.Fatal(s.ListenAndServe())
} }

View File

@ -9,10 +9,6 @@ type (
} }
) )
func NewURL(u *url.URL) *URL {
return &URL{url: u}
}
func (u *URL) URL() *url.URL { func (u *URL) URL() *url.URL {
return u.url return u.url
} }
@ -39,3 +35,7 @@ func (u *URL) QueryValue(name string) string {
} }
return u.query.Get(name) return u.query.Get(name)
} }
func (u *URL) reset(url *url.URL) {
u.url = url
}

View File

@ -1,74 +1,74 @@
package middleware package middleware
// import (
// import ( "bufio"
// "bufio" "compress/gzip"
// "compress/gzip" "io"
// "io" "io/ioutil"
// "io/ioutil" "net"
// "net" "net/http"
// "net/http" "strings"
// "strings" "sync"
// "sync"
// "github.com/labstack/echo"
// "github.com/labstack/echo" "github.com/labstack/echo/engine"
// ) )
//
// type ( type (
// gzipWriter struct { gzipWriter struct {
// io.Writer io.Writer
// http.ResponseWriter engine.Response
// } }
// ) )
//
// func (w gzipWriter) Write(b []byte) (int, error) { func (w gzipWriter) Write(b []byte) (int, error) {
// if w.Header().Get(echo.ContentType) == "" { if w.Header().Get(echo.ContentType) == "" {
// w.Header().Set(echo.ContentType, http.DetectContentType(b)) w.Header().Set(echo.ContentType, http.DetectContentType(b))
// } }
// return w.Writer.Write(b) return w.Writer.Write(b)
// } }
//
// func (w gzipWriter) Flush() error { func (w gzipWriter) Flush() error {
// return w.Writer.(*gzip.Writer).Flush() return w.Writer.(*gzip.Writer).Flush()
// } }
//
// func (w gzipWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { func (w gzipWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
// return w.ResponseWriter.(http.Hijacker).Hijack() return w.Response.(http.Hijacker).Hijack()
// } }
//
// func (w *gzipWriter) CloseNotify() <-chan bool { func (w *gzipWriter) CloseNotify() <-chan bool {
// return w.ResponseWriter.(http.CloseNotifier).CloseNotify() return w.Response.(http.CloseNotifier).CloseNotify()
// } }
//
// var writerPool = sync.Pool{ var writerPool = sync.Pool{
// New: func() interface{} { New: func() interface{} {
// return gzip.NewWriter(ioutil.Discard) return gzip.NewWriter(ioutil.Discard)
// }, },
// } }
//
// // Gzip returns a middleware which compresses HTTP response using gzip compression // Gzip returns a middleware which compresses HTTP response using gzip compression
// // scheme. // scheme.
// func Gzip() echo.MiddlewareFunc { func Gzip() echo.MiddlewareFunc {
// scheme := "gzip" scheme := "gzip"
//
// return func(h echo.HandlerFunc) echo.HandlerFunc { return func(h echo.HandlerFunc) echo.HandlerFunc {
// return func(c echo.Context) error { return func(c echo.Context) error {
// c.Response().Header().Add(echo.Vary, echo.AcceptEncoding) c.Response().Header().Add(echo.Vary, echo.AcceptEncoding)
// if strings.Contains(c.Request().Header().Get(echo.AcceptEncoding), scheme) { if strings.Contains(c.Request().Header().Get(echo.AcceptEncoding), scheme) {
// w := writerPool.Get().(*gzip.Writer) w := writerPool.Get().(*gzip.Writer)
// w.Reset(c.Response().Writer()) w.Reset(c.Response().Writer())
// defer func() { defer func() {
// w.Close() w.Close()
// writerPool.Put(w) writerPool.Put(w)
// }() }()
// gw := gzipWriter{Writer: w, ResponseWriter: c.Response().Writer()} gw := gzipWriter{Writer: w, Response: c.Response()}
// c.Response().Header().Set(echo.ContentEncoding, scheme) c.Response().Header().Set(echo.ContentEncoding, scheme)
// c.Response().SetWriter(gw) c.Response().SetWriter(gw)
// } }
// if err := h(c); err != nil { if err := h(c); err != nil {
// c.Error(err) c.Error(err)
// } }
// return nil return nil
// } }
// } }
// } }

View File

@ -1,73 +1,69 @@
package middleware package middleware
// import (
// import ( "bytes"
// "bytes" "compress/gzip"
// "compress/gzip" "testing"
// "net/http"
// "net/http/httptest" "github.com/labstack/echo"
// "testing" "github.com/labstack/echo/test"
// "time" "github.com/stretchr/testify/assert"
// )
// "github.com/labstack/echo"
// "github.com/labstack/echo/test" type closeNotifyingRecorder struct {
// "github.com/stretchr/testify/assert" *test.ResponseRecorder
// ) closed chan bool
// }
// type closeNotifyingRecorder struct {
// *httptest.ResponseRecorder func newCloseNotifyingRecorder() *closeNotifyingRecorder {
// closed chan bool return &closeNotifyingRecorder{
// } test.NewResponseRecorder(),
// make(chan bool, 1),
// func newCloseNotifyingRecorder() *closeNotifyingRecorder { }
// return &closeNotifyingRecorder{ }
// test.NewResponseRecorder(),
// make(chan bool, 1), func (c *closeNotifyingRecorder) close() {
// } c.closed <- true
// } }
//
// func (c *closeNotifyingRecorder) close() { func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
// c.closed <- true return c.closed
// } }
//
// func (c *closeNotifyingRecorder) CloseNotify() <-chan bool { func TestGzip(t *testing.T) {
// return c.closed e := echo.New()
// } req := test.NewRequest(echo.GET, "/", nil)
// rec := test.NewResponseRecorder()
// func TestGzip(t *testing.T) { c := echo.NewContext(req, rec, e)
// e := echo.New() h := func(c echo.Context) error {
// req := test.NewRequest(echo.GET, "/", nil) c.Response().Write([]byte("test")) // For Content-Type sniffing
// res := test.NewResponseRecorder() return nil
// c := echo.NewContext(req, res, e) }
// h := func(c echo.Context) error {
// c.Response().Write([]byte("test")) // For Content-Type sniffing // Skip if no Accept-Encoding header
// return nil Gzip()(h)(c)
// } // assert.Equal(t, http.StatusOK, rec.Status())
// assert.Equal(t, "test", rec.Body.String())
// // Skip if no Accept-Encoding header
// Gzip()(h)(c) req = test.NewRequest(echo.GET, "/", nil)
// assert.Equal(t, http.StatusOK, res.Status()) req.Header().Set(echo.AcceptEncoding, "gzip")
// assert.Equal(t, "test", res.Body().String()) rec = test.NewResponseRecorder()
// c = echo.NewContext(req, rec, e)
// req = test.NewRequest(echo.GET, "/", nil)
// req.Header.Set(echo.AcceptEncoding, "gzip") // Gzip
// res = test.NewResponseRecorder() Gzip()(h)(c)
// c = echo.NewContext(req, res, e) // assert.Equal(t, http.StatusOK, rec.Status())
// assert.Equal(t, "gzip", rec.Header().Get(echo.ContentEncoding))
// // Gzip assert.Contains(t, rec.Header().Get(echo.ContentType), echo.TextPlain)
// Gzip()(h)(c) r, err := gzip.NewReader(rec.Body)
// assert.Equal(t, http.StatusOK, res.Status()) defer r.Close()
// assert.Equal(t, "gzip", res.Header().Get(echo.ContentEncoding)) if assert.NoError(t, err) {
// assert.Contains(t, res.Header().Get(echo.ContentType), echo.TextPlain) buf := new(bytes.Buffer)
// r, err := gzip.NewReader(res.Body()) buf.ReadFrom(r)
// defer r.Close() assert.Equal(t, "test", buf.String())
// if assert.NoError(t, err) { }
// buf := new(bytes.Buffer) }
// buf.ReadFrom(r)
// assert.Equal(t, "test", buf.String())
// }
// }
//
// func TestGzipFlush(t *testing.T) { // func TestGzipFlush(t *testing.T) {
// res := test.NewResponseRecorder() // res := test.NewResponseRecorder()
// buf := new(bytes.Buffer) // buf := new(bytes.Buffer)
@ -104,7 +100,7 @@ package middleware
// t.Fatal("Flush didn't flush any data") // t.Fatal("Flush didn't flush any data")
// } // }
// } // }
//
// func TestGzipCloseNotify(t *testing.T) { // func TestGzipCloseNotify(t *testing.T) {
// rec := newCloseNotifyingRecorder() // rec := newCloseNotifyingRecorder()
// buf := new(bytes.Buffer) // buf := new(bytes.Buffer)

View File

@ -15,8 +15,8 @@ func TestLogger(t *testing.T) {
// Note: Just for the test coverage, not a real test. // Note: Just for the test coverage, not a real test.
e := echo.New() e := echo.New()
req := test.NewRequest(echo.GET, "/", nil) req := test.NewRequest(echo.GET, "/", nil)
res := test.NewResponseRecorder() rec := test.NewResponseRecorder()
c := echo.NewContext(req, res, e) c := echo.NewContext(req, rec, e)
// Status 2xx // Status 2xx
h := func(c echo.Context) error { h := func(c echo.Context) error {
@ -25,16 +25,16 @@ func TestLogger(t *testing.T) {
Logger()(h)(c) Logger()(h)(c)
// Status 3xx // Status 3xx
res = test.NewResponseRecorder() rec = test.NewResponseRecorder()
c = echo.NewContext(req, res, e) c = echo.NewContext(req, rec, e)
h = func(c echo.Context) error { h = func(c echo.Context) error {
return c.String(http.StatusTemporaryRedirect, "test") return c.String(http.StatusTemporaryRedirect, "test")
} }
Logger()(h)(c) Logger()(h)(c)
// Status 4xx // Status 4xx
res = test.NewResponseRecorder() rec = test.NewResponseRecorder()
c = echo.NewContext(req, res, e) c = echo.NewContext(req, rec, e)
h = func(c echo.Context) error { h = func(c echo.Context) error {
return c.String(http.StatusNotFound, "test") return c.String(http.StatusNotFound, "test")
} }
@ -42,8 +42,8 @@ func TestLogger(t *testing.T) {
// Status 5xx with empty path // Status 5xx with empty path
req = test.NewRequest(echo.GET, "", nil) req = test.NewRequest(echo.GET, "", nil)
res = test.NewResponseRecorder() rec = test.NewResponseRecorder()
c = echo.NewContext(req, res, e) c = echo.NewContext(req, rec, e)
h = func(c echo.Context) error { h = func(c echo.Context) error {
return errors.New("error") return errors.New("error")
} }
@ -53,8 +53,8 @@ func TestLogger(t *testing.T) {
func TestLoggerIPAddress(t *testing.T) { func TestLoggerIPAddress(t *testing.T) {
e := echo.New() e := echo.New()
req := test.NewRequest(echo.GET, "/", nil) req := test.NewRequest(echo.GET, "/", nil)
res := test.NewResponseRecorder() rec := test.NewResponseRecorder()
c := echo.NewContext(req, res, e) c := echo.NewContext(req, rec, e)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
e.Logger().SetOutput(buf) e.Logger().SetOutput(buf)
ip := "127.0.0.1" ip := "127.0.0.1"

View File

@ -13,12 +13,12 @@ func TestRecover(t *testing.T) {
e := echo.New() e := echo.New()
e.SetDebug(true) e.SetDebug(true)
req := test.NewRequest(echo.GET, "/", nil) req := test.NewRequest(echo.GET, "/", nil)
res := test.NewResponseRecorder() rec := test.NewResponseRecorder()
c := echo.NewContext(req, res, e) c := echo.NewContext(req, rec, e)
h := func(c echo.Context) error { h := func(c echo.Context) error {
panic("test") panic("test")
} }
Recover()(h)(c) Recover()(h)(c)
assert.Equal(t, http.StatusInternalServerError, res.Status()) assert.Equal(t, http.StatusInternalServerError, rec.Status())
assert.Contains(t, res.Body.String(), "panic recover") assert.Contains(t, rec.Body.String(), "panic recover")
} }

View File

@ -274,7 +274,7 @@ func (n *node) check405() HandlerFunc {
} }
func (r *Router) Find(method, path string, context Context) (h HandlerFunc, e *Echo) { func (r *Router) Find(method, path string, context Context) (h HandlerFunc, e *Echo) {
x := context.X() x := context.Context()
h = notFoundHandler h = notFoundHandler
e = r.echo e = r.echo
cn := r.tree // Current node as root cn := r.tree // Current node as root

View File

@ -529,16 +529,16 @@ func TestRouterParamNames(t *testing.T) {
// Route > /users/:id // Route > /users/:id
h, _ = r.Find(GET, "/users/1", c) h, _ = r.Find(GET, "/users/1", c)
if assert.NotNil(t, h) { if assert.NotNil(t, h) {
assert.Equal(t, "id", c.X().pnames[0]) assert.Equal(t, "id", c.Context().pnames[0])
assert.Equal(t, "1", c.P(0)) assert.Equal(t, "1", c.P(0))
} }
// Route > /users/:uid/files/:fid // Route > /users/:uid/files/:fid
h, _ = r.Find(GET, "/users/1/files/1", c) h, _ = r.Find(GET, "/users/1/files/1", c)
if assert.NotNil(t, h) { if assert.NotNil(t, h) {
assert.Equal(t, "uid", c.X().pnames[0]) assert.Equal(t, "uid", c.Context().pnames[0])
assert.Equal(t, "1", c.P(0)) assert.Equal(t, "1", c.P(0))
assert.Equal(t, "fid", c.X().pnames[1]) assert.Equal(t, "fid", c.Context().pnames[1])
assert.Equal(t, "1", c.P(1)) assert.Equal(t, "1", c.P(1))
} }
} }
@ -556,7 +556,7 @@ func TestRouterAPI(t *testing.T) {
for _, route := range api { for _, route := range api {
h, _ := r.Find(route.Method, route.Path, c) h, _ := r.Find(route.Method, route.Path, c)
if assert.NotNil(t, h) { if assert.NotNil(t, h) {
for i, n := range c.X().pnames { for i, n := range c.Context().pnames {
if assert.NotEmpty(t, n) { if assert.NotEmpty(t, n) {
assert.Equal(t, ":"+n, c.P(i)) assert.Equal(t, ":"+n, c.P(i))
} }