1
0
mirror of https://github.com/labstack/echo.git synced 2024-12-24 20:14:31 +02:00

Static as middleware

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2016-02-18 22:50:40 -08:00
parent 91ae93ebfc
commit 19d51dad4c
8 changed files with 121 additions and 121 deletions

18
glide.lock generated
View File

@ -1,18 +1,20 @@
hash: c9f84c389c3133ad9adf26b374f5b7970f26f3d185ec13e1d6824254478beb76 hash: f220137e9ccd9aaf3051be33c3c23ea8abd2c40df6cf96175c3994d482b5e007
updated: 2016-02-18T14:02:34.556933487-08:00 updated: 2016-02-18T22:26:06.777493855-08:00
imports: imports:
- name: github.com/klauspost/compress - name: github.com/klauspost/compress
version: 3dcfad3351d86b2c07406ac93e92f03edd98c707 version: 3dcfad3351d86b2c07406ac93e92f03edd98c707
repo: https://github.com/klauspost/compress subpackages:
- flate
- gzip
- zlib
- name: github.com/klauspost/cpuid - name: github.com/klauspost/cpuid
version: 349c675778172472f5e8f3a3e0fe187e302e5a10 version: 349c675778172472f5e8f3a3e0fe187e302e5a10
repo: https://github.com/klauspost/cpuid
- name: github.com/klauspost/crc32 - name: github.com/klauspost/crc32
version: 81ac41837f877bc6a7f81321c2c29d88d69c108a version: 81ac41837f877bc6a7f81321c2c29d88d69c108a
- name: github.com/labstack/gommon - name: github.com/labstack/gommon
version: bfff5bf04688a4048a5cb4dd3b3f0697caaad19c version: bfff5bf04688a4048a5cb4dd3b3f0697caaad19c
subpackages: subpackages:
- /color - color
- log - log
- name: github.com/mattn/go-colorable - name: github.com/mattn/go-colorable
version: 9fdad7c47650b7d2e1da50644c1f4ba7f172f252 version: 9fdad7c47650b7d2e1da50644c1f4ba7f172f252
@ -20,13 +22,9 @@ imports:
version: 56b76bdf51f7708750eac80fa38b952bb9f32639 version: 56b76bdf51f7708750eac80fa38b952bb9f32639
- name: github.com/valyala/fasthttp - name: github.com/valyala/fasthttp
version: 14b2ff3d2b38a596b037541c94f43718d9da215f version: 14b2ff3d2b38a596b037541c94f43718d9da215f
- name: golang.org/x/crypto
version: 1f22c0103821b9390939b6776727195525381532
- name: golang.org/x/net - name: golang.org/x/net
version: b6d7b1396ec874c3b00f6c84cd4301a17c56c8ed version: b6d7b1396ec874c3b00f6c84cd4301a17c56c8ed
subpackages: subpackages:
- /context - context
- websocket - websocket
- name: golang.org/x/text
version: 07b9a78963006a15c538ec5175243979025fa7a8
devImports: [] devImports: []

View File

@ -1,95 +0,0 @@
package handler
import (
"fmt"
"io"
"net/http"
"path"
"github.com/labstack/echo"
)
type (
StaticOptions struct {
Root string `json:"root"`
Index string `json:"index"`
Browse bool `json:"browse"`
}
)
func Static(root string, options ...*StaticOptions) echo.HandlerFunc {
// Default options
opts := &StaticOptions{Index: "index.html"}
if len(options) > 0 {
opts = options[0]
}
return func(c echo.Context) error {
fs := http.Dir(root)
file := c.P(0)
f, err := fs.Open(file)
if err != nil {
return echo.ErrNotFound
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return err
}
if fi.IsDir() {
/* NOTE:
Not checking the Last-Modified header as it caches the response `304` when
changing differnt directories for the same path.
*/
d := f
// Index file
file = path.Join(file, opts.Index)
f, err = fs.Open(file)
if err != nil {
if opts.Browse {
dirs, err := d.Readdir(-1)
if err != nil {
return err
}
// Create a directory index
res := c.Response()
res.Header().Set(echo.ContentType, echo.TextHTMLCharsetUTF8)
if _, err = fmt.Fprintf(res, "<pre>\n"); err != nil {
return err
}
for _, d := range dirs {
name := d.Name()
color := "#212121"
if d.IsDir() {
color = "#e91e63"
name += "/"
}
if _, err = fmt.Fprintf(res, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
return err
}
}
_, err = fmt.Fprintf(res, "</pre>\n")
return err
}
return echo.ErrNotFound
}
fi, _ = f.Stat() // Index file stat
}
c.Response().WriteHeader(http.StatusOK)
io.Copy(c.Response(), f)
return nil
// TODO:
// http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
}
}
// Favicon serves the default favicon - GET /favicon.ico.
func Favicon() echo.HandlerFunc {
return func(c echo.Context) error {
return nil
}
}

View File

@ -23,7 +23,7 @@ const (
// For valid credentials it calls the next handler. // For valid credentials it calls the next handler.
// For invalid credentials, it sends "401 - Unauthorized" response. // For invalid credentials, it sends "401 - Unauthorized" response.
func BasicAuth(fn BasicAuthFunc, options ...*BasicAuthOptions) echo.MiddlewareFunc { func BasicAuth(fn BasicAuthFunc, options ...*BasicAuthOptions) echo.MiddlewareFunc {
return func(h echo.Handler) echo.Handler { return func(next echo.Handler) echo.Handler {
return echo.HandlerFunc(func(c echo.Context) error { return echo.HandlerFunc(func(c echo.Context) error {
// Skip WebSocket // Skip WebSocket
if (c.Request().Header().Get(echo.Upgrade)) == echo.WebSocket { if (c.Request().Header().Get(echo.Upgrade)) == echo.WebSocket {

View File

@ -28,7 +28,7 @@ type (
// 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(options ...*GzipOptions) echo.MiddlewareFunc { func Gzip(options ...*GzipOptions) echo.MiddlewareFunc {
return func(h echo.Handler) echo.Handler { return func(next echo.Handler) echo.Handler {
scheme := "gzip" scheme := "gzip"
return echo.HandlerFunc(func(c echo.Context) error { return echo.HandlerFunc(func(c echo.Context) error {
c.Response().Header().Add(echo.Vary, echo.AcceptEncoding) c.Response().Header().Add(echo.Vary, echo.AcceptEncoding)
@ -43,7 +43,7 @@ func Gzip(options ...*GzipOptions) echo.MiddlewareFunc {
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.Handle(c); err != nil { if err := next.Handle(c); err != nil {
c.Error(err) c.Error(err)
} }
return nil return nil

View File

@ -12,13 +12,13 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestLog(t *testing.T) { 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)
rec := test.NewResponseRecorder() rec := test.NewResponseRecorder()
c := echo.NewContext(req, rec, e) c := echo.NewContext(req, rec, e)
h := Log()(echo.HandlerFunc(func(c echo.Context) error { h := Logger()(echo.HandlerFunc(func(c echo.Context) error {
return c.String(http.StatusOK, "test") return c.String(http.StatusOK, "test")
})) }))
@ -28,7 +28,7 @@ func TestLog(t *testing.T) {
// Status 3xx // Status 3xx
rec = test.NewResponseRecorder() rec = test.NewResponseRecorder()
c = echo.NewContext(req, rec, e) c = echo.NewContext(req, rec, e)
h = Log()(echo.HandlerFunc(func(c echo.Context) error { h = Logger()(echo.HandlerFunc(func(c echo.Context) error {
return c.String(http.StatusTemporaryRedirect, "test") return c.String(http.StatusTemporaryRedirect, "test")
})) }))
h.Handle(c) h.Handle(c)
@ -36,7 +36,7 @@ func TestLog(t *testing.T) {
// Status 4xx // Status 4xx
rec = test.NewResponseRecorder() rec = test.NewResponseRecorder()
c = echo.NewContext(req, rec, e) c = echo.NewContext(req, rec, e)
h = Log()(echo.HandlerFunc(func(c echo.Context) error { h = Logger()(echo.HandlerFunc(func(c echo.Context) error {
return c.String(http.StatusNotFound, "test") return c.String(http.StatusNotFound, "test")
})) }))
h.Handle(c) h.Handle(c)
@ -45,13 +45,13 @@ func TestLog(t *testing.T) {
req = test.NewRequest(echo.GET, "", nil) req = test.NewRequest(echo.GET, "", nil)
rec = test.NewResponseRecorder() rec = test.NewResponseRecorder()
c = echo.NewContext(req, rec, e) c = echo.NewContext(req, rec, e)
h = Log()(echo.HandlerFunc(func(c echo.Context) error { h = Logger()(echo.HandlerFunc(func(c echo.Context) error {
return errors.New("error") return errors.New("error")
})) }))
h.Handle(c) h.Handle(c)
} }
func TestLogIPAddress(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)
rec := test.NewResponseRecorder() rec := test.NewResponseRecorder()
@ -59,7 +59,7 @@ func TestLogIPAddress(t *testing.T) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
e.Logger().(*log.Logger).SetOutput(buf) e.Logger().(*log.Logger).SetOutput(buf)
ip := "127.0.0.1" ip := "127.0.0.1"
h := Log()(echo.HandlerFunc(func(c echo.Context) error { h := Logger()(echo.HandlerFunc(func(c echo.Context) error {
return c.String(http.StatusOK, "test") return c.String(http.StatusOK, "test")
})) }))

View File

@ -9,12 +9,12 @@ import (
) )
type ( type (
LogOptions struct { LoggerOptions struct {
} }
) )
func Log(options ...*LogOptions) echo.MiddlewareFunc { func Logger(options ...*LoggerOptions) echo.MiddlewareFunc {
return func(h echo.Handler) echo.Handler { return func(next echo.Handler) echo.Handler {
return echo.HandlerFunc(func(c echo.Context) error { return echo.HandlerFunc(func(c echo.Context) error {
req := c.Request() req := c.Request()
res := c.Response() res := c.Response()
@ -30,7 +30,7 @@ func Log(options ...*LogOptions) echo.MiddlewareFunc {
} }
start := time.Now() start := time.Now()
if err := h.Handle(c); err != nil { if err := next.Handle(c); err != nil {
c.Error(err) c.Error(err)
} }
stop := time.Now() stop := time.Now()

View File

@ -16,7 +16,7 @@ type (
// Recover returns a middleware which recovers from panics anywhere in the chain // Recover returns a middleware which recovers from panics anywhere in the chain
// and handles the control to the centralized HTTPErrorHandler. // and handles the control to the centralized HTTPErrorHandler.
func Recover(options ...*RecoverOptions) echo.MiddlewareFunc { func Recover(options ...*RecoverOptions) echo.MiddlewareFunc {
return func(h echo.Handler) echo.Handler { return func(next echo.Handler) echo.Handler {
// TODO: Provide better stack trace `https://github.com/go-errors/errors` `https://github.com/docker/libcontainer/tree/master/stacktrace` // TODO: Provide better stack trace `https://github.com/go-errors/errors` `https://github.com/docker/libcontainer/tree/master/stacktrace`
return echo.HandlerFunc(func(c echo.Context) error { return echo.HandlerFunc(func(c echo.Context) error {
defer func() { defer func() {
@ -27,7 +27,7 @@ func Recover(options ...*RecoverOptions) echo.MiddlewareFunc {
err, n, trace[:n])) err, n, trace[:n]))
} }
}() }()
return h.Handle(c) return next.Handle(c)
}) })
} }
} }

97
middleware/static.go Normal file
View File

@ -0,0 +1,97 @@
package middleware
import (
"fmt"
"io"
"net/http"
"path"
"github.com/labstack/echo"
)
type (
StaticOptions struct {
Root string `json:"root"`
Index string `json:"index"`
Browse bool `json:"browse"`
}
)
func Static(root string, options ...*StaticOptions) echo.MiddlewareFunc {
return func(next echo.Handler) echo.Handler {
// Default options
opts := &StaticOptions{Index: "index.html"}
if len(options) > 0 {
opts = options[0]
}
return echo.HandlerFunc(func(c echo.Context) error {
fs := http.Dir(root)
file := c.Request().URI()
f, err := fs.Open(file)
if err != nil {
return next.Handle(c)
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return err
}
if fi.IsDir() {
/* NOTE:
Not checking the Last-Modified header as it caches the response `304` when
changing differnt directories for the same path.
*/
d := f
// Index file
file = path.Join(file, opts.Index)
f, err = fs.Open(file)
if err != nil {
if opts.Browse {
dirs, err := d.Readdir(-1)
if err != nil {
return err
}
// Create a directory index
res := c.Response()
res.Header().Set(echo.ContentType, echo.TextHTMLCharsetUTF8)
if _, err = fmt.Fprintf(res, "<pre>\n"); err != nil {
return err
}
for _, d := range dirs {
name := d.Name()
color := "#212121"
if d.IsDir() {
color = "#e91e63"
name += "/"
}
if _, err = fmt.Fprintf(res, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
return err
}
}
_, err = fmt.Fprintf(res, "</pre>\n")
return err
}
return next.Handle(c)
}
fi, _ = f.Stat() // Index file stat
}
c.Response().WriteHeader(http.StatusOK)
io.Copy(c.Response(), f)
return nil
// TODO:
// http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
})
}
}
// Favicon serves the default favicon - GET /favicon.ico.
func Favicon() echo.HandlerFunc {
return func(c echo.Context) error {
return nil
}
}