mirror of
https://github.com/labstack/echo.git
synced 2024-11-24 08:22:21 +02:00
- Static back as middleware Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
parent
2f8639b7e6
commit
130c548826
@ -238,6 +238,7 @@ Middleware | Description
|
||||
[Gzip](https://labstack.com/echo/guide/middleware/#gzip-middleware:37ab2f15ff048f67959bcac0a6032f32) | Send gzip HTTP response
|
||||
[BasicAuth](https://labstack.com/echo/guide/middleware/#basicauth-middleware:37ab2f15ff048f67959bcac0a6032f32) | HTTP basic authentication
|
||||
[CORS](https://labstack.com/echo/guide/middleware/#cors-middleware:37ab2f15ff048f67959bcac0a6032f32) | Cross-Origin Resource Sharing
|
||||
[Static](https://labstack.com/echo/guide/static-files/#using-static-middleware:123f9d1043075fe4874616541b409e4d) | Serve static files
|
||||
[AddTrailingSlash](https://labstack.com/echo/guide/middleware/#addtrailingslash-middleware:37ab2f15ff048f67959bcac0a6032f32) | Add trailing slash to the request URI
|
||||
[RemoveTrailingSlash](https://labstack.com/echo/guide/middleware/#removetrailingslash-middleware:37ab2f15ff048f67959bcac0a6032f32) | Remove trailing slash from the request URI
|
||||
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
@ -367,12 +366,14 @@ func (c *context) File(file string) error {
|
||||
|
||||
fi, _ := f.Stat()
|
||||
if fi.IsDir() {
|
||||
file = path.Join(file, "index.html")
|
||||
file = filepath.Join(file, "index.html")
|
||||
f, err = os.Open(file)
|
||||
if err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
fi, _ = f.Stat()
|
||||
if fi, err = f.Stat(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return c.ServeContent(f, fi.Name(), fi.ModTime())
|
||||
}
|
||||
|
16
echo.go
16
echo.go
@ -45,6 +45,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
@ -374,19 +375,14 @@ func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middlew
|
||||
}
|
||||
}
|
||||
|
||||
// Static serves static files from provided `root` directory for `/<path>*` URL.
|
||||
func (e *Echo) Static(path, root string) {
|
||||
e.StaticWithConfig(path, StaticConfig{
|
||||
Root: root,
|
||||
// Static serves static files from provided root directory with URL path prefix.
|
||||
func (e *Echo) Static(prefix, root string) {
|
||||
e.Get(prefix+"*", func(c Context) error {
|
||||
return c.File(path.Join(root, c.P(0)))
|
||||
})
|
||||
}
|
||||
|
||||
// StaticWithConfig serves static files with provided config for `/<path>*` URL.
|
||||
func (e *Echo) StaticWithConfig(path string, config StaticConfig) {
|
||||
e.Get(path+"*", StaticWithConfig(config))
|
||||
}
|
||||
|
||||
// File serve provided file for `/<path>` HTTP path.
|
||||
// File serves provided file for URL path.
|
||||
func (e *Echo) File(path, file string) {
|
||||
e.Get(path, func(c Context) error {
|
||||
return c.File(file)
|
||||
|
31
group.go
31
group.go
@ -5,9 +5,10 @@ type (
|
||||
// routes that share a common middlware or functionality that should be separate
|
||||
// from the parent echo instance while still inheriting from it.
|
||||
Group struct {
|
||||
prefix string
|
||||
middleware []MiddlewareFunc
|
||||
echo *Echo
|
||||
prefix string
|
||||
middleware []MiddlewareFunc
|
||||
initialized bool
|
||||
echo *Echo
|
||||
}
|
||||
)
|
||||
|
||||
@ -82,26 +83,24 @@ func (g *Group) Group(prefix string, m ...MiddlewareFunc) *Group {
|
||||
}
|
||||
|
||||
// Static implements `Echo#Static()` for sub-routes within the Group.
|
||||
func (g *Group) Static(path, root string) {
|
||||
g.StaticWithConfig(path, StaticConfig{
|
||||
Root: root,
|
||||
})
|
||||
}
|
||||
|
||||
// StaticWithConfig implements `Echo#StaticWithConfig()` for sub-routes within the
|
||||
// Group.
|
||||
func (g *Group) StaticWithConfig(path string, config StaticConfig) {
|
||||
g.Get(path+"*", StaticWithConfig(config))
|
||||
func (g *Group) Static(prefix, root string) {
|
||||
g.echo.Static(g.prefix+prefix, root)
|
||||
}
|
||||
|
||||
// File implements `Echo#File()` for sub-routes within the Group.
|
||||
func (g *Group) File(path, file string) {
|
||||
g.Get(path, func(c Context) error {
|
||||
return c.File(file)
|
||||
})
|
||||
g.echo.File(g.prefix+path, file)
|
||||
}
|
||||
|
||||
func (g *Group) add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
|
||||
middleware = append(g.middleware, middleware...)
|
||||
if !g.initialized {
|
||||
// Allow all requests to reach the group as they might get dropped if router
|
||||
// doesn't find a match, making none of the group middleware process.
|
||||
g.echo.Any(g.prefix+"*", func(c Context) error {
|
||||
return ErrNotFound
|
||||
}, middleware...)
|
||||
g.initialized = true
|
||||
}
|
||||
g.echo.add(method, g.prefix+path, handler, middleware...)
|
||||
}
|
||||
|
119
middleware/static.go
Normal file
119
middleware/static.go
Normal file
@ -0,0 +1,119 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/labstack/echo"
|
||||
)
|
||||
|
||||
type (
|
||||
// StaticConfig defines the config for static middleware.
|
||||
StaticConfig struct {
|
||||
// Root is the directory from where the static content is served.
|
||||
// Required.
|
||||
Root string `json:"root"`
|
||||
|
||||
// Index is the list of index files to be searched and used when serving
|
||||
// a directory.
|
||||
// Optional with default value as []string{"index.html"}.
|
||||
Index []string `json:"index"`
|
||||
|
||||
// Browse is a flag to enable/disable directory browsing.
|
||||
// Optional with default value as false.
|
||||
Browse bool `json:"browse"`
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultStaticConfig is the default static middleware config.
|
||||
DefaultStaticConfig = StaticConfig{
|
||||
Index: []string{"index.html"},
|
||||
Browse: false,
|
||||
}
|
||||
)
|
||||
|
||||
// Static returns a static middleware to serves static content from the provided
|
||||
// root directory.
|
||||
func Static(root string) echo.MiddlewareFunc {
|
||||
c := DefaultStaticConfig
|
||||
c.Root = root
|
||||
return StaticWithConfig(c)
|
||||
}
|
||||
|
||||
// StaticWithConfig returns a static middleware from config.
|
||||
// See `Static()`.
|
||||
func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
|
||||
// Defaults
|
||||
if config.Index == nil {
|
||||
config.Index = DefaultStaticConfig.Index
|
||||
}
|
||||
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
fs := http.Dir(config.Root)
|
||||
p := c.Request().URL().Path()
|
||||
if strings.Contains(c.Path(), "*") { // If serving from a group, e.g. `/static*`.
|
||||
p = c.P(0)
|
||||
}
|
||||
file := path.Clean(p)
|
||||
f, err := fs.Open(file)
|
||||
if err != nil {
|
||||
return next(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 different directories for the same path.
|
||||
*/
|
||||
d := f
|
||||
|
||||
// Index file
|
||||
// TODO: search all files
|
||||
file = path.Join(file, config.Index[0])
|
||||
f, err = fs.Open(file)
|
||||
if err != nil {
|
||||
return next(c)
|
||||
}
|
||||
if config.Browse {
|
||||
dirs, err := d.Readdir(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a directory index
|
||||
rs := c.Response()
|
||||
rs.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
|
||||
if _, err = fmt.Fprintf(rs, "<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(rs, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = fmt.Fprintf(rs, "</pre>\n")
|
||||
return err
|
||||
}
|
||||
if fi, err = f.Stat(); err != nil { // Index file
|
||||
return err
|
||||
}
|
||||
}
|
||||
return c.ServeContent(f, fi.Name(), fi.ModTime())
|
||||
}
|
||||
}
|
||||
}
|
110
static.go
110
static.go
@ -1,110 +0,0 @@
|
||||
package echo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
)
|
||||
|
||||
type (
|
||||
// StaticConfig defines the config for static handler.
|
||||
StaticConfig struct {
|
||||
// Root is the directory from where the static content is served.
|
||||
// Required.
|
||||
Root string `json:"root"`
|
||||
|
||||
// Index is the list of index files to be searched and used when serving
|
||||
// a directory.
|
||||
// Optional with default value as []string{"index.html"}.
|
||||
Index []string `json:"index"`
|
||||
|
||||
// Browse is a flag to enable/disable directory browsing.
|
||||
// Optional with default value as false.
|
||||
Browse bool `json:"browse"`
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultStaticConfig is the default static handler config.
|
||||
DefaultStaticConfig = StaticConfig{
|
||||
Index: []string{"index.html"},
|
||||
Browse: false,
|
||||
}
|
||||
)
|
||||
|
||||
// Static returns a static handler to serves static content from the provided
|
||||
// root directory.
|
||||
func Static(root string) HandlerFunc {
|
||||
c := DefaultStaticConfig
|
||||
c.Root = root
|
||||
return StaticWithConfig(c)
|
||||
}
|
||||
|
||||
// StaticWithConfig returns a static handler from config.
|
||||
// See `Static()`.
|
||||
func StaticWithConfig(config StaticConfig) HandlerFunc {
|
||||
// Defaults
|
||||
if config.Index == nil {
|
||||
config.Index = DefaultStaticConfig.Index
|
||||
}
|
||||
|
||||
return func(c Context) error {
|
||||
fs := http.Dir(config.Root)
|
||||
file := path.Clean(c.P(0))
|
||||
f, err := fs.Open(file)
|
||||
if err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
defer f.Close()
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
if fi.IsDir() {
|
||||
/* NOTE:
|
||||
Not checking the Last-Modified header as it caches the response `304` when
|
||||
changing different directories for the same path.
|
||||
*/
|
||||
d := f
|
||||
|
||||
// Index file
|
||||
// TODO: search all files
|
||||
file = path.Join(file, config.Index[0])
|
||||
f, err = fs.Open(file)
|
||||
if err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
if config.Browse {
|
||||
dirs, err := d.Readdir(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a directory index
|
||||
rs := c.Response()
|
||||
rs.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
|
||||
if _, err = fmt.Fprintf(rs, "<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(rs, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = fmt.Fprintf(rs, "</pre>\n")
|
||||
return err
|
||||
}
|
||||
if fi, err = f.Stat(); err != nil { // Index file
|
||||
return ErrNotFound
|
||||
}
|
||||
}
|
||||
return c.ServeContent(f, fi.Name(), fi.ModTime())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user