1
0
mirror of https://github.com/labstack/echo.git synced 2024-11-28 08:38:39 +02:00

Added gzip middleware

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2015-05-15 12:29:14 -07:00
parent 4f45cd1517
commit 1ee3bc23e3
15 changed files with 138 additions and 42 deletions

View File

@ -91,7 +91,7 @@ func main() {
e := echo.New()
// Middleware
e.Use(mw.Logger)
e.Use(mw.Logger())
// Routes
e.Get("/", hello)

View File

@ -53,8 +53,8 @@ func (c *Context) Param(name string) (value string) {
// Bind binds the request body into specified type v. Default binder does it
// based on Content-Type header.
func (c *Context) Bind(v interface{}) *HTTPError {
return c.echo.binder(c.Request, v)
func (c *Context) Bind(i interface{}) *HTTPError {
return c.echo.binder(c.Request, i)
}
// Render invokes the registered HTML template renderer and sends a text/html
@ -69,10 +69,10 @@ func (c *Context) Render(code int, name string, data interface{}) *HTTPError {
}
// JSON sends an application/json response with status code.
func (c *Context) JSON(code int, v interface{}) *HTTPError {
func (c *Context) JSON(code int, i interface{}) *HTTPError {
c.Response.Header().Set(ContentType, ApplicationJSON+"; charset=utf-8")
c.Response.WriteHeader(code)
if err := json.NewEncoder(c.Response).Encode(v); err != nil {
if err := json.NewEncoder(c.Response).Encode(i); err != nil {
return &HTTPError{Error: err}
}
return nil

View File

@ -90,7 +90,9 @@ const (
//---------
Accept = "Accept"
AcceptEncoding = "Accept-Encoding"
ContentDisposition = "Content-Disposition"
ContentEncoding = "Content-Encoding"
ContentLength = "Content-Length"
ContentType = "Content-Type"
Authorization = "Authorization"

View File

@ -61,7 +61,7 @@ func main() {
e := echo.New()
// Middleware
e.Use(mw.Logger)
e.Use(mw.Logger())
// Routes
e.Post("/users", createUser)

View File

@ -17,7 +17,7 @@ func main() {
e := echo.New()
// Middleware
e.Use(mw.Logger)
e.Use(mw.Logger())
// Routes
e.Get("/", hello)

View File

@ -21,7 +21,7 @@ func main() {
//------------
// Logger
e.Use(mw.Logger)
e.Use(mw.Logger())
// Basic auth
e.Use(mw.BasicAuth(func(u, p string) bool {
@ -41,6 +41,9 @@ func main() {
// e.Use(mw.RedirectToSlash())
// Gzip
e.Use(mw.Gzip())
// Routes
e.Get("/", hello)

View File

@ -65,7 +65,7 @@ func main() {
e := echo.New()
// Middleware
e.Use(mw.Logger)
e.Use(mw.Logger())
//------------------------
// Third-party middleware

View File

@ -14,7 +14,7 @@ const (
Basic = "Basic"
)
// BasicAuth provides HTTP basic authentication middleware.
// BasicAuth provides HTTP basic authentication.
func BasicAuth(fn AuthFunc) echo.HandlerFunc {
return func(c *echo.Context) (he *echo.HTTPError) {
auth := c.Request.Header.Get(echo.Authorization)

43
middleware/compress.go Normal file
View File

@ -0,0 +1,43 @@
package middleware
import (
"compress/gzip"
"io"
"strings"
"github.com/labstack/echo"
)
type (
gzipResponseWriter struct {
io.Writer
*echo.Response
}
)
func (g gzipResponseWriter) Write(b []byte) (int, error) {
return g.Writer.Write(b)
}
// Gzip compresses HTTP response using gzip compression scheme.
func Gzip() echo.MiddlewareFunc {
scheme := "gzip"
return func(h echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) *echo.HTTPError {
if !strings.Contains(c.Request.Header.Get(echo.AcceptEncoding), scheme) {
return nil
}
w := gzip.NewWriter(c.Response.Writer)
defer w.Close()
gw := gzipResponseWriter{Writer: w, Response: c.Response}
c.Response.Header().Set(echo.ContentEncoding, scheme)
c.Response = &echo.Response{Writer: gw}
if he := h(c); he != nil {
c.Error(he)
}
return nil
}
}
}

View File

@ -0,0 +1,42 @@
package middleware
import (
"net/http"
"net/http/httptest"
"testing"
"compress/gzip"
"github.com/labstack/echo"
"io/ioutil"
)
func TestGzip(t *testing.T) {
req, _ := http.NewRequest(echo.GET, "/", nil)
req.Header.Set(echo.AcceptEncoding, "gzip")
w := httptest.NewRecorder()
res := &echo.Response{Writer: w}
c := echo.NewContext(req, res, echo.New())
Gzip()(func(c *echo.Context) *echo.HTTPError {
return c.String(http.StatusOK, "test")
})(c)
if w.Header().Get(echo.ContentEncoding) != "gzip" {
t.Errorf("expected Content-Encoding: gzip, got %d", w.Header().Get(echo.ContentEncoding))
}
r, err := gzip.NewReader(w.Body)
defer r.Close()
if err != nil {
t.Error(err)
}
b, err := ioutil.ReadAll(r)
if err != nil {
t.Error(err)
}
s := string(b)
if s != "test" {
t.Errorf(`expected "test", got "%s"`, s)
}
}

View File

@ -8,28 +8,34 @@ import (
"github.com/labstack/gommon/color"
)
func Logger(h echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) *echo.HTTPError {
start := time.Now()
if he := h(c); he != nil {
c.Error(he)
}
end := time.Now()
m := c.Request.Method
p := c.Request.URL.Path
n := c.Response.Status()
col := color.Green
func Logger() echo.MiddlewareFunc {
return func(h echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) *echo.HTTPError {
start := time.Now()
if he := h(c); he != nil {
c.Error(he)
}
end := time.Now()
method := c.Request.Method
path := c.Request.URL.Path
if path == "" {
path = "/"
}
size := c.Response.Size()
switch {
case n >= 500:
col = color.Red
case n >= 400:
col = color.Yellow
case n >= 300:
col = color.Cyan
}
n := c.Response.Status()
code := color.Green(n)
switch {
case n >= 500:
code = color.Red(n)
case n >= 400:
code = color.Yellow(n)
case n >= 300:
code = color.Cyan(n)
}
log.Printf("%s %s %s %s", m, p, col(n), end.Sub(start))
return nil
log.Printf("%s %s %s %s %d", method, path, code, end.Sub(start), size)
return nil
}
}
}

View File

@ -10,8 +10,8 @@ import (
type (
Response struct {
Writer http.ResponseWriter
status int
size int
status int
size uint64
committed bool
}
)
@ -20,20 +20,20 @@ func (r *Response) Header() http.Header {
return r.Writer.Header()
}
func (r *Response) WriteHeader(n int) {
func (r *Response) WriteHeader(code int) {
if r.committed {
// TODO: Warning
log.Printf("echo: %s", color.Yellow("response already committed"))
return
}
r.status = n
r.Writer.WriteHeader(n)
r.status = code
r.Writer.WriteHeader(code)
r.committed = true
}
func (r *Response) Write(b []byte) (n int, err error) {
n, err = r.Writer.Write(b)
r.size += n
r.size += uint64(n)
return n, err
}
@ -41,7 +41,7 @@ func (r *Response) Status() int {
return r.status
}
func (r *Response) Size() int {
func (r *Response) Size() uint64 {
return r.size
}

View File

@ -163,9 +163,9 @@ h := func(*echo.Context) *HTTPError {
e.Get("/users/:id", h)
```
## (Middleware)[https://github.com/labstack/echo/tree/master/examples/middleware]
## Middleware
*WIP*
[*WIP*](https://github.com/labstack/echo/tree/master/examples/middleware)
## Response

View File

@ -66,7 +66,7 @@ func main() {
e := echo.New()
// Middleware
e.Use(mw.Logger)
e.Use(mw.Logger())
// Routes
e.Get("/", hello)
@ -78,7 +78,7 @@ func main() {
`echo.New()` returns a new instance of Echo.
`e.Use(mw.Logger)` adds logging middleware to the chain. It logs every HTTP request
`e.Use(mw.Logger())` adds logging middleware to the chain. It logs every HTTP request
made to the server, producing output
```sh