mirror of
https://github.com/labstack/echo.git
synced 2025-07-13 01:30:31 +02:00
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
51
echo.go
@ -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 {
|
||||||
|
22
echo_test.go
22
echo_test.go
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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()},
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user