mirror of
https://github.com/labstack/echo.git
synced 2025-01-26 03:20:08 +02:00
v2 is compiling now
Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
parent
dbd1e8e230
commit
688293b5ed
10
context.go
10
context.go
@ -135,18 +135,12 @@ func (c *context) Param(name string) (value string) {
|
|||||||
|
|
||||||
// Query returns query parameter by name.
|
// Query returns query parameter by name.
|
||||||
func (c *context) Query(name string) string {
|
func (c *context) Query(name string) string {
|
||||||
if c.query == nil {
|
return c.request.URL().QueryValue(name)
|
||||||
// TODO: v2
|
|
||||||
// c.query = c.request.URL.Query()
|
|
||||||
}
|
|
||||||
return c.query.Get(name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Form returns form parameter by name.
|
// Form returns form parameter by name.
|
||||||
func (c *context) Form(name string) string {
|
func (c *context) Form(name string) string {
|
||||||
// TODO: v2
|
return c.request.FormValue(name)
|
||||||
// return c.request.FormValue(name)
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get retrieves data from the context.
|
// Get retrieves data from the context.
|
||||||
|
@ -192,7 +192,7 @@ func TestContext(t *testing.T) {
|
|||||||
// File
|
// File
|
||||||
rec = test.NewResponseRecorder()
|
rec = test.NewResponseRecorder()
|
||||||
c = NewContext(req, rec, e)
|
c = NewContext(req, rec, e)
|
||||||
err = c.File("testing/fixture/walle.png", "", false)
|
err = c.File("_fixture/images/walle.png", "", false)
|
||||||
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, 219885, rec.Body.Len())
|
assert.Equal(t, 219885, rec.Body.Len())
|
||||||
@ -201,7 +201,7 @@ func TestContext(t *testing.T) {
|
|||||||
// File as attachment
|
// File as attachment
|
||||||
rec = test.NewResponseRecorder()
|
rec = test.NewResponseRecorder()
|
||||||
c = NewContext(req, rec, e)
|
c = NewContext(req, rec, e)
|
||||||
err = c.File("testing/fixture/walle.png", "WALLE.PNG", true)
|
err = c.File("_fixture/images/walle.png", "WALLE.PNG", true)
|
||||||
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, rec.Header().Get(ContentDisposition), "attachment; filename=WALLE.PNG")
|
assert.Equal(t, rec.Header().Get(ContentDisposition), "attachment; filename=WALLE.PNG")
|
||||||
|
145
echo.go
145
echo.go
@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/labstack/echo/engine/fasthttp"
|
"github.com/labstack/echo/engine/fasthttp"
|
||||||
"github.com/labstack/echo/engine/standard"
|
"github.com/labstack/echo/engine/standard"
|
||||||
"github.com/labstack/gommon/log"
|
"github.com/labstack/gommon/log"
|
||||||
"golang.org/x/net/http2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -237,7 +236,7 @@ func (e *Echo) SetLogPrefix(prefix string) {
|
|||||||
e.logger.SetPrefix(prefix)
|
e.logger.SetPrefix(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLogOutput sets the output destination for the logger. Default value is `os.Std*`
|
// SetLogOutput sets the output destination for the logger. Default value is `os.Stdout`
|
||||||
func (e *Echo) SetLogOutput(w io.Writer) {
|
func (e *Echo) SetLogOutput(w io.Writer) {
|
||||||
e.logger.SetOutput(w)
|
e.logger.SetOutput(w)
|
||||||
}
|
}
|
||||||
@ -408,33 +407,36 @@ func (e *Echo) ServeFile(path, file string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Echo) serveFile(dir, file string, c Context) (err error) {
|
func (e *Echo) serveFile(dir, file string, c Context) (err error) {
|
||||||
// fs := http.Dir(dir)
|
fs := http.Dir(dir)
|
||||||
// f, err := fs.Open(file)
|
f, err := fs.Open(file)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return NewHTTPError(http.StatusNotFound)
|
return NewHTTPError(http.StatusNotFound)
|
||||||
// }
|
}
|
||||||
// defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
// fi, _ := f.Stat()
|
fi, _ := f.Stat()
|
||||||
// if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
// /* NOTE:
|
/* NOTE:
|
||||||
// Not checking the Last-Modified header as it caches the response `304` when
|
Not checking the Last-Modified header as it caches the response `304` when
|
||||||
// changing differnt directories for the same path.
|
changing differnt directories for the same path.
|
||||||
// */
|
*/
|
||||||
// d := f
|
d := f
|
||||||
|
|
||||||
// // Index file
|
// Index file
|
||||||
// file = filepath.Join(file, indexPage)
|
file = filepath.Join(file, indexPage)
|
||||||
// f, err = fs.Open(file)
|
f, err = fs.Open(file)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// if e.autoIndex {
|
if e.autoIndex {
|
||||||
// // Auto index
|
// Auto index
|
||||||
// return listDir(d, c)
|
return listDir(d, c)
|
||||||
// }
|
}
|
||||||
// return NewHTTPError(http.StatusForbidden)
|
return NewHTTPError(http.StatusForbidden)
|
||||||
// }
|
}
|
||||||
// fi, _ = f.Stat() // Index file stat
|
fi, _ = f.Stat() // Index file stat
|
||||||
// }
|
}
|
||||||
|
c.Response().WriteHeader(http.StatusOK)
|
||||||
|
io.Copy(c.Response(), f)
|
||||||
|
// TODO:
|
||||||
// http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
|
// http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -513,39 +515,38 @@ func (e *Echo) Routes() []Route {
|
|||||||
return e.router.routes
|
return e.router.routes
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
|
// ServeHTTP serves HTTP requests.
|
||||||
func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (e *Echo) ServeHTTP(req engine.Request, res engine.Response) {
|
||||||
// TODO: v2
|
if e.hook != nil {
|
||||||
// if e.hook != nil {
|
e.hook(req, res)
|
||||||
// e.hook(w, r)
|
}
|
||||||
// }
|
|
||||||
//
|
c := e.pool.Get().(*context)
|
||||||
// c := e.pool.Get().(*context)
|
h, e := e.router.Find(req.Method(), req.URL().Path(), c)
|
||||||
// h, e := e.router.Find(r.Method, r.URL.Path, c)
|
c.reset(req, res, e)
|
||||||
// c.reset(r, w, e)
|
|
||||||
//
|
// Chain middleware with handler in the end
|
||||||
// // Chain middleware with handler in the end
|
for i := len(e.middleware) - 1; i >= 0; i-- {
|
||||||
// for i := len(e.middleware) - 1; i >= 0; i-- {
|
h = e.middleware[i](h)
|
||||||
// h = e.middleware[i](h)
|
}
|
||||||
// }
|
|
||||||
//
|
// Execute chain
|
||||||
// // Execute chain
|
if err := h(c); err != nil {
|
||||||
// if err := h(c); err != nil {
|
e.httpErrorHandler(err, c)
|
||||||
// e.httpErrorHandler(err, c)
|
}
|
||||||
// }
|
|
||||||
//
|
e.pool.Put(c)
|
||||||
// e.pool.Put(c)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server returns the internal *http.Server.
|
// Server returns the internal *http.Server.
|
||||||
func (e *Echo) Server(addr string) *http.Server {
|
// func (e *Echo) Server(addr string) *http.Server {
|
||||||
s := &http.Server{Addr: addr, Handler: e}
|
// s := &http.Server{Addr: addr, Handler: e}
|
||||||
// TODO: Remove in Go 1.6+
|
// // TODO: Remove in Go 1.6+
|
||||||
if e.http2 {
|
// if e.http2 {
|
||||||
http2.ConfigureServer(s, nil)
|
// http2.ConfigureServer(s, nil)
|
||||||
}
|
// }
|
||||||
return s
|
// return s
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (e *Echo) SetEngine(t engine.Type) {
|
func (e *Echo) SetEngine(t engine.Type) {
|
||||||
e.engineType = t
|
e.engineType = t
|
||||||
@ -589,32 +590,32 @@ func (e *Echo) Run(address string) {
|
|||||||
|
|
||||||
// RunTLS runs a server with TLS configuration.
|
// RunTLS runs a server with TLS configuration.
|
||||||
func (e *Echo) RunTLS(addr, crtFile, keyFile string) {
|
func (e *Echo) RunTLS(addr, crtFile, keyFile string) {
|
||||||
e.run(e.Server(addr), crtFile, keyFile)
|
// e.run(e.Server(addr), crtFile, keyFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunServer runs a custom server.
|
// RunServer runs a custom server.
|
||||||
func (e *Echo) RunServer(s *http.Server) {
|
func (e *Echo) RunServer(s *http.Server) {
|
||||||
e.run(s)
|
// e.run(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunTLSServer runs a custom server with TLS configuration.
|
// RunTLSServer runs a custom server with TLS configuration.
|
||||||
func (e *Echo) RunTLSServer(s *http.Server, crtFile, keyFile string) {
|
func (e *Echo) RunTLSServer(s *http.Server, crtFile, keyFile string) {
|
||||||
e.run(s, crtFile, keyFile)
|
// e.run(s, crtFile, keyFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Echo) run(s *http.Server, files ...string) {
|
func (e *Echo) run(s *http.Server, files ...string) {
|
||||||
s.Handler = e
|
// s.Handler = e
|
||||||
// TODO: Remove in Go 1.6+
|
// // TODO: Remove in Go 1.6+
|
||||||
if e.http2 {
|
// if e.http2 {
|
||||||
http2.ConfigureServer(s, nil)
|
// http2.ConfigureServer(s, nil)
|
||||||
}
|
// }
|
||||||
if len(files) == 0 {
|
// if len(files) == 0 {
|
||||||
e.logger.Fatal(s.ListenAndServe())
|
// e.logger.Fatal(s.ListenAndServe())
|
||||||
} else if len(files) == 2 {
|
// } else if len(files) == 2 {
|
||||||
e.logger.Fatal(s.ListenAndServeTLS(files[0], files[1]))
|
// e.logger.Fatal(s.ListenAndServeTLS(files[0], files[1]))
|
||||||
} else {
|
// } else {
|
||||||
e.logger.Fatal("invalid TLS configuration")
|
// e.logger.Fatal("invalid TLS configuration")
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPError(code int, msg ...string) *HTTPError {
|
func NewHTTPError(code int, msg ...string) *HTTPError {
|
||||||
|
75
echo_test.go
75
echo_test.go
@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -44,7 +43,7 @@ func TestEcho(t *testing.T) {
|
|||||||
|
|
||||||
func TestEchoIndex(t *testing.T) {
|
func TestEchoIndex(t *testing.T) {
|
||||||
e := New()
|
e := New()
|
||||||
e.Index("recipes/website/public/index.html")
|
e.Index("_fixture/index.html")
|
||||||
c, b := request(GET, "/", e)
|
c, b := request(GET, "/", e)
|
||||||
assert.Equal(t, http.StatusOK, c)
|
assert.Equal(t, http.StatusOK, c)
|
||||||
assert.NotEmpty(t, b)
|
assert.NotEmpty(t, b)
|
||||||
@ -52,7 +51,7 @@ func TestEchoIndex(t *testing.T) {
|
|||||||
|
|
||||||
func TestEchoFavicon(t *testing.T) {
|
func TestEchoFavicon(t *testing.T) {
|
||||||
e := New()
|
e := New()
|
||||||
e.Favicon("recipes/website/public/favicon.ico")
|
e.Favicon("_fixture/favicon.ico")
|
||||||
c, b := request(GET, "/favicon.ico", e)
|
c, b := request(GET, "/favicon.ico", e)
|
||||||
assert.Equal(t, http.StatusOK, c)
|
assert.Equal(t, http.StatusOK, c)
|
||||||
assert.NotEmpty(t, b)
|
assert.NotEmpty(t, b)
|
||||||
@ -62,23 +61,23 @@ func TestEchoStatic(t *testing.T) {
|
|||||||
e := New()
|
e := New()
|
||||||
|
|
||||||
// OK
|
// OK
|
||||||
e.Static("/scripts", "recipes/website/public/scripts")
|
e.Static("/images", "_fixture/images")
|
||||||
c, b := request(GET, "/scripts/main.js", e)
|
c, b := request(GET, "/images/walle.png", e)
|
||||||
assert.Equal(t, http.StatusOK, c)
|
assert.Equal(t, http.StatusOK, c)
|
||||||
assert.NotEmpty(t, b)
|
assert.NotEmpty(t, b)
|
||||||
|
|
||||||
// No file
|
// No file
|
||||||
e.Static("/scripts", "recipes/website/public/scripts")
|
e.Static("/images", "_fixture/scripts")
|
||||||
c, _ = request(GET, "/scripts/index.js", e)
|
c, _ = request(GET, "/images/bolt.png", e)
|
||||||
assert.Equal(t, http.StatusNotFound, c)
|
assert.Equal(t, http.StatusNotFound, c)
|
||||||
|
|
||||||
// Directory
|
// Directory
|
||||||
e.Static("/scripts", "recipes/website/public/scripts")
|
e.Static("/images", "_fixture/images")
|
||||||
c, _ = request(GET, "/scripts", e)
|
c, _ = request(GET, "/images", e)
|
||||||
assert.Equal(t, http.StatusForbidden, c)
|
assert.Equal(t, http.StatusForbidden, c)
|
||||||
|
|
||||||
// Directory with index.html
|
// Directory with index.html
|
||||||
e.Static("/", "recipes/website/public")
|
e.Static("/", "_fixture")
|
||||||
c, r := request(GET, "/", e)
|
c, r := request(GET, "/", e)
|
||||||
assert.Equal(t, http.StatusOK, c)
|
assert.Equal(t, http.StatusOK, c)
|
||||||
assert.Equal(t, true, strings.HasPrefix(r, "<!doctype html>"))
|
assert.Equal(t, true, strings.HasPrefix(r, "<!doctype html>"))
|
||||||
@ -86,7 +85,8 @@ func TestEchoStatic(t *testing.T) {
|
|||||||
// Sub-directory with index.html
|
// Sub-directory with index.html
|
||||||
c, r = request(GET, "/folder", e)
|
c, r = request(GET, "/folder", e)
|
||||||
assert.Equal(t, http.StatusOK, c)
|
assert.Equal(t, http.StatusOK, c)
|
||||||
assert.Equal(t, "sub directory", r)
|
assert.Equal(t, true, strings.HasPrefix(r, "<!doctype html>"))
|
||||||
|
// assert.Equal(t, "sub directory", r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEchoMiddleware(t *testing.T) {
|
func TestEchoMiddleware(t *testing.T) {
|
||||||
@ -250,11 +250,13 @@ func TestEchoGroup(t *testing.T) {
|
|||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
e.Use(func(h HandlerFunc) HandlerFunc {
|
e.Use(func(h HandlerFunc) HandlerFunc {
|
||||||
return func(c Context) error {
|
return func(c Context) error {
|
||||||
buf.WriteString("a")
|
buf.WriteString("0")
|
||||||
return h(c)
|
return h(c)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
h := func(Context) error { return nil }
|
h := func(c Context) error {
|
||||||
|
return c.NoContent(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
//--------
|
//--------
|
||||||
// Routes
|
// Routes
|
||||||
@ -284,18 +286,13 @@ func TestEchoGroup(t *testing.T) {
|
|||||||
// Nested groups
|
// Nested groups
|
||||||
g3 := e.Group("/group3")
|
g3 := e.Group("/group3")
|
||||||
g4 := g3.Group("/group4")
|
g4 := g3.Group("/group4")
|
||||||
g4.Use(func(h HandlerFunc) HandlerFunc {
|
g4.Get("/", h)
|
||||||
return func(c Context) error {
|
|
||||||
return c.NoContent(http.StatusOK)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
request(GET, "/users", e)
|
request(GET, "/users", e)
|
||||||
assert.Equal(t, "0", buf.String())
|
assert.Equal(t, "0", buf.String())
|
||||||
|
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
request(GET, "/group1/", e)
|
request(GET, "/group1/", e)
|
||||||
// println(len(g1.echo.middleware))
|
|
||||||
assert.Equal(t, "01", buf.String())
|
assert.Equal(t, "01", buf.String())
|
||||||
|
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
@ -309,10 +306,10 @@ func TestEchoGroup(t *testing.T) {
|
|||||||
|
|
||||||
func TestEchoNotFound(t *testing.T) {
|
func TestEchoNotFound(t *testing.T) {
|
||||||
e := New()
|
e := New()
|
||||||
r, _ := http.NewRequest(GET, "/files", nil)
|
req := test.NewRequest(GET, "/files", nil)
|
||||||
w := httptest.NewRecorder()
|
res := test.NewResponseRecorder()
|
||||||
e.ServeHTTP(w, r)
|
e.ServeHTTP(req, res)
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, res.Status())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEchoMethodNotAllowed(t *testing.T) {
|
func TestEchoMethodNotAllowed(t *testing.T) {
|
||||||
@ -320,10 +317,10 @@ func TestEchoMethodNotAllowed(t *testing.T) {
|
|||||||
e.Get("/", func(c Context) error {
|
e.Get("/", func(c Context) error {
|
||||||
return c.String(http.StatusOK, "Echo!")
|
return c.String(http.StatusOK, "Echo!")
|
||||||
})
|
})
|
||||||
r, _ := http.NewRequest(POST, "/", nil)
|
req := test.NewRequest(POST, "/", nil)
|
||||||
w := httptest.NewRecorder()
|
res := test.NewResponseRecorder()
|
||||||
e.ServeHTTP(w, r)
|
e.ServeHTTP(req, res)
|
||||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
assert.Equal(t, http.StatusMethodNotAllowed, res.Status())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEchoHTTPError(t *testing.T) {
|
func TestEchoHTTPError(t *testing.T) {
|
||||||
@ -334,9 +331,9 @@ func TestEchoHTTPError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEchoServer(t *testing.T) {
|
func TestEchoServer(t *testing.T) {
|
||||||
e := New()
|
// e := New()
|
||||||
s := e.Server(":1323")
|
// s := e.Server(":1323")
|
||||||
assert.IsType(t, &http.Server{}, s)
|
// assert.IsType(t, &http.Server{}, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEchoHook(t *testing.T) {
|
func TestEchoHook(t *testing.T) {
|
||||||
@ -348,13 +345,13 @@ func TestEchoHook(t *testing.T) {
|
|||||||
path := req.URL().Path()
|
path := req.URL().Path()
|
||||||
l := len(path) - 1
|
l := len(path) - 1
|
||||||
if path != "/" && path[l] == '/' {
|
if path != "/" && path[l] == '/' {
|
||||||
// req.URL().Path() = path[:l]
|
req.URL().SetPath(path[:l])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
r, _ := http.NewRequest(GET, "/test/", nil)
|
req := test.NewRequest(GET, "/test/", nil)
|
||||||
w := httptest.NewRecorder()
|
res := test.NewResponseRecorder()
|
||||||
e.ServeHTTP(w, r)
|
e.ServeHTTP(req, res)
|
||||||
assert.Equal(t, r.URL.Path, "/test")
|
assert.Equal(t, req.URL().Path(), "/test")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMethod(t *testing.T, method, path string, e *Echo) {
|
func testMethod(t *testing.T, method, path string, e *Echo) {
|
||||||
@ -372,8 +369,8 @@ 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) {
|
||||||
r, _ := http.NewRequest(method, path, nil)
|
req := test.NewRequest(method, path, nil)
|
||||||
w := httptest.NewRecorder()
|
res := test.NewResponseRecorder()
|
||||||
e.ServeHTTP(w, r)
|
e.ServeHTTP(req, res)
|
||||||
return w.Code, w.Body.String()
|
return res.Status(), res.Body.String()
|
||||||
}
|
}
|
||||||
|
59
engine/engine.go
Normal file
59
engine/engine.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package engine
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
type (
|
||||||
|
Type uint8
|
||||||
|
|
||||||
|
HandlerFunc func(Request, Response)
|
||||||
|
|
||||||
|
Engine interface {
|
||||||
|
Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
Request interface {
|
||||||
|
Header() Header
|
||||||
|
// Proto() string
|
||||||
|
// ProtoMajor() int
|
||||||
|
// ProtoMinor() int
|
||||||
|
RemoteAddress() string
|
||||||
|
Method() string
|
||||||
|
URI() string
|
||||||
|
URL() URL
|
||||||
|
Body() io.ReadCloser
|
||||||
|
FormValue(string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
Response interface {
|
||||||
|
Header() Header
|
||||||
|
WriteHeader(int)
|
||||||
|
Write(b []byte) (int, error)
|
||||||
|
Status() int
|
||||||
|
Size() int64
|
||||||
|
Committed() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
Header interface {
|
||||||
|
Add(string, string)
|
||||||
|
Del(string)
|
||||||
|
Get(string) string
|
||||||
|
Set(string, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
URL interface {
|
||||||
|
Scheme() string
|
||||||
|
SetPath(string)
|
||||||
|
Path() string
|
||||||
|
Host() string
|
||||||
|
QueryValue(string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
Config struct {
|
||||||
|
Address string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Standard Type = iota
|
||||||
|
FastHTTP
|
||||||
|
)
|
46
engine/fasthttp/header.go
Normal file
46
engine/fasthttp/header.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package fasthttp
|
||||||
|
|
||||||
|
import "github.com/valyala/fasthttp"
|
||||||
|
|
||||||
|
type (
|
||||||
|
RequestHeader struct {
|
||||||
|
fasthttp.RequestHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseHeader struct {
|
||||||
|
fasthttp.ResponseHeader
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *RequestHeader) Add(key, val string) {
|
||||||
|
// h.RequestHeader.Add(key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) Del(key string) {
|
||||||
|
h.RequestHeader.Del(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) Get(key string) string {
|
||||||
|
return string(h.RequestHeader.Peek(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHeader) Set(key, val string) {
|
||||||
|
h.RequestHeader.Set(key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ResponseHeader) Add(key, val string) {
|
||||||
|
// h.ResponseHeader.Add(key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ResponseHeader) Del(key string) {
|
||||||
|
h.ResponseHeader.Del(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ResponseHeader) Get(key string) string {
|
||||||
|
// return h.ResponseHeader.Get(key)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ResponseHeader) Set(key, val string) {
|
||||||
|
h.ResponseHeader.Set(key, val)
|
||||||
|
}
|
45
engine/fasthttp/request.go
Normal file
45
engine/fasthttp/request.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package fasthttp
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo/engine"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Request struct {
|
||||||
|
context *fasthttp.RequestCtx
|
||||||
|
url engine.URL
|
||||||
|
header engine.Header
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *Request) Header() engine.Header {
|
||||||
|
return r.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) RemoteAddress() string {
|
||||||
|
return r.context.RemoteAddr().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Method() string {
|
||||||
|
return string(r.context.Method())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) URI() string {
|
||||||
|
return string(r.context.RequestURI())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) URL() engine.URL {
|
||||||
|
return r.url
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Body() io.ReadCloser {
|
||||||
|
// return r.context.PostBody()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) FormValue(name string) string {
|
||||||
|
return ""
|
||||||
|
}
|
40
engine/fasthttp/response.go
Normal file
40
engine/fasthttp/response.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package fasthttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo/engine"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Response struct {
|
||||||
|
context *fasthttp.RequestCtx
|
||||||
|
header engine.Header
|
||||||
|
status int
|
||||||
|
size int64
|
||||||
|
committed bool
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *Response) Header() engine.Header {
|
||||||
|
return r.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) WriteHeader(code int) {
|
||||||
|
r.context.SetStatusCode(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Write(b []byte) (int, error) {
|
||||||
|
return r.context.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Status() int {
|
||||||
|
return r.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Size() int64 {
|
||||||
|
return r.size
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Committed() bool {
|
||||||
|
return r.committed
|
||||||
|
}
|
43
engine/fasthttp/server.go
Normal file
43
engine/fasthttp/server.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package fasthttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo/engine"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Server struct {
|
||||||
|
*http.Server
|
||||||
|
config *engine.Config
|
||||||
|
handler engine.HandlerFunc
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewServer(config *engine.Config, handler engine.HandlerFunc) *Server {
|
||||||
|
return &Server{
|
||||||
|
Server: new(http.Server),
|
||||||
|
config: config,
|
||||||
|
handler: handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start() {
|
||||||
|
fasthttp.ListenAndServe(s.config.Address, func(ctx *fasthttp.RequestCtx) {
|
||||||
|
println("FastHTTP")
|
||||||
|
req := &Request{
|
||||||
|
context: ctx,
|
||||||
|
url: &URL{ctx.URI()},
|
||||||
|
header: &RequestHeader{ctx.Request.Header},
|
||||||
|
}
|
||||||
|
res := &Response{
|
||||||
|
context: ctx,
|
||||||
|
header: &ResponseHeader{ctx.Response.Header},
|
||||||
|
}
|
||||||
|
s.handler(req, res)
|
||||||
|
})
|
||||||
|
log.Fatal(s.ListenAndServe())
|
||||||
|
}
|
29
engine/fasthttp/url.go
Normal file
29
engine/fasthttp/url.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package fasthttp
|
||||||
|
|
||||||
|
import "github.com/valyala/fasthttp"
|
||||||
|
|
||||||
|
type (
|
||||||
|
URL struct {
|
||||||
|
*fasthttp.URI
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (u *URL) Scheme() string {
|
||||||
|
return string(u.URI.Scheme())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) Host() string {
|
||||||
|
return string(u.URI.Host())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) SetPath(path string) {
|
||||||
|
// return string(u.URI.Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) Path() string {
|
||||||
|
return string(u.URI.Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) QueryValue(name string) string {
|
||||||
|
return ""
|
||||||
|
}
|
25
engine/standard/header.go
Normal file
25
engine/standard/header.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package standard
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
type (
|
||||||
|
Header struct {
|
||||||
|
http.Header
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Header) Add(key, val string) {
|
||||||
|
h.Header.Add(key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Header) Del(key string) {
|
||||||
|
h.Header.Del(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Header) Get(key string) string {
|
||||||
|
return h.Header.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Header) Set(key, val string) {
|
||||||
|
h.Header.Set(key, val)
|
||||||
|
}
|
56
engine/standard/request.go
Normal file
56
engine/standard/request.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package standard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/engine"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Request struct {
|
||||||
|
request *http.Request
|
||||||
|
url engine.URL
|
||||||
|
header engine.Header
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewRequest(r *http.Request) *Request {
|
||||||
|
return &Request{
|
||||||
|
request: r,
|
||||||
|
url: NewURL(r.URL),
|
||||||
|
header: &Header{r.Header},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Request() *http.Request {
|
||||||
|
return r.request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Header() engine.Header {
|
||||||
|
return r.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) URL() engine.URL {
|
||||||
|
return r.url
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) RemoteAddress() string {
|
||||||
|
return r.request.RemoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Method() string {
|
||||||
|
return r.request.Method
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) URI() string {
|
||||||
|
return r.request.RequestURI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Body() io.ReadCloser {
|
||||||
|
return r.request.Body
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) FormValue(name string) string {
|
||||||
|
return r.request.FormValue(name)
|
||||||
|
}
|
53
engine/standard/response.go
Normal file
53
engine/standard/response.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package standard
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
import "github.com/labstack/echo/engine"
|
||||||
|
|
||||||
|
type (
|
||||||
|
Response struct {
|
||||||
|
response http.ResponseWriter
|
||||||
|
header engine.Header
|
||||||
|
status int
|
||||||
|
size int64
|
||||||
|
committed bool
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewResponse(w http.ResponseWriter) *Response {
|
||||||
|
return &Response{
|
||||||
|
response: w,
|
||||||
|
header: &Header{w.Header()},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Header() engine.Header {
|
||||||
|
return r.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) WriteHeader(code int) {
|
||||||
|
if r.committed {
|
||||||
|
// r.echo.Logger().Warn("response already committed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.status = code
|
||||||
|
r.response.WriteHeader(code)
|
||||||
|
r.committed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Write(b []byte) (n int, err error) {
|
||||||
|
n, err = r.response.Write(b)
|
||||||
|
r.size += int64(n)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Status() int {
|
||||||
|
return r.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Size() int64 {
|
||||||
|
return r.size
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) Committed() bool {
|
||||||
|
return r.committed
|
||||||
|
}
|
32
engine/standard/server.go
Normal file
32
engine/standard/server.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package standard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/engine"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Server struct {
|
||||||
|
*http.Server
|
||||||
|
config *engine.Config
|
||||||
|
handler engine.HandlerFunc
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewServer(config *engine.Config, handler engine.HandlerFunc) *Server {
|
||||||
|
return &Server{
|
||||||
|
Server: new(http.Server),
|
||||||
|
config: config,
|
||||||
|
handler: handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start() {
|
||||||
|
s.Addr = s.config.Address
|
||||||
|
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
s.handler(NewRequest(r), NewResponse(w))
|
||||||
|
})
|
||||||
|
log.Fatal(s.ListenAndServe())
|
||||||
|
}
|
41
engine/standard/url.go
Normal file
41
engine/standard/url.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package standard
|
||||||
|
|
||||||
|
import "net/url"
|
||||||
|
|
||||||
|
type (
|
||||||
|
URL struct {
|
||||||
|
url *url.URL
|
||||||
|
query url.Values
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewURL(u *url.URL) *URL {
|
||||||
|
return &URL{url: u}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) URL() *url.URL {
|
||||||
|
return u.url
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) Scheme() string {
|
||||||
|
return u.url.Scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) Host() string {
|
||||||
|
return u.url.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) SetPath(path string) {
|
||||||
|
u.url.Path = path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) Path() string {
|
||||||
|
return u.url.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) QueryValue(name string) string {
|
||||||
|
if u.query == nil {
|
||||||
|
u.query = u.url.Query()
|
||||||
|
}
|
||||||
|
return u.query.Get(name)
|
||||||
|
}
|
@ -3,18 +3,18 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
|
"github.com/labstack/echo/test"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBasicAuth(t *testing.T) {
|
func TestBasicAuth(t *testing.T) {
|
||||||
e := echo.New()
|
e := echo.New()
|
||||||
req, _ := http.NewRequest(echo.GET, "/", nil)
|
req := test.NewRequest(echo.GET, "/", nil)
|
||||||
rec := httptest.NewRecorder()
|
res := test.NewResponseRecorder()
|
||||||
c := echo.NewContext(req, echo.NewResponse(rec, e), e)
|
c := echo.NewContext(req, res, e)
|
||||||
fn := func(u, p string) bool {
|
fn := func(u, p string) bool {
|
||||||
if u == "joe" && p == "secret" {
|
if u == "joe" && p == "secret" {
|
||||||
return true
|
return true
|
||||||
@ -37,22 +37,22 @@ func TestBasicAuth(t *testing.T) {
|
|||||||
req.Header().Set(echo.Authorization, auth)
|
req.Header().Set(echo.Authorization, auth)
|
||||||
he := ba(c).(*echo.HTTPError)
|
he := ba(c).(*echo.HTTPError)
|
||||||
assert.Equal(t, http.StatusUnauthorized, he.Code())
|
assert.Equal(t, http.StatusUnauthorized, he.Code())
|
||||||
assert.Equal(t, Basic+" realm=Restricted", rec.Header().Get(echo.WWWAuthenticate))
|
assert.Equal(t, Basic+" realm=Restricted", res.Header().Get(echo.WWWAuthenticate))
|
||||||
|
|
||||||
// Empty Authorization header
|
// Empty Authorization header
|
||||||
req.Header.Set(echo.Authorization, "")
|
req.Header().Set(echo.Authorization, "")
|
||||||
he = ba(c).(*echo.HTTPError)
|
he = ba(c).(*echo.HTTPError)
|
||||||
assert.Equal(t, http.StatusUnauthorized, he.Code())
|
assert.Equal(t, http.StatusUnauthorized, he.Code())
|
||||||
assert.Equal(t, Basic+" realm=Restricted", rec.Header().Get(echo.WWWAuthenticate))
|
assert.Equal(t, Basic+" realm=Restricted", res.Header().Get(echo.WWWAuthenticate))
|
||||||
|
|
||||||
// Invalid Authorization header
|
// Invalid Authorization header
|
||||||
auth = base64.StdEncoding.EncodeToString([]byte("invalid"))
|
auth = base64.StdEncoding.EncodeToString([]byte("invalid"))
|
||||||
req.Header.Set(echo.Authorization, auth)
|
req.Header().Set(echo.Authorization, auth)
|
||||||
he = ba(c).(*echo.HTTPError)
|
he = ba(c).(*echo.HTTPError)
|
||||||
assert.Equal(t, http.StatusUnauthorized, he.Code())
|
assert.Equal(t, http.StatusUnauthorized, he.Code())
|
||||||
assert.Equal(t, Basic+" realm=Restricted", rec.Header().Get(echo.WWWAuthenticate))
|
assert.Equal(t, Basic+" realm=Restricted", res.Header().Get(echo.WWWAuthenticate))
|
||||||
|
|
||||||
// WebSocket
|
// WebSocket
|
||||||
c.Request().Header.Set(echo.Upgrade, echo.WebSocket)
|
c.Request().Header().Set(echo.Upgrade, echo.WebSocket)
|
||||||
assert.NoError(t, ba(c))
|
assert.NoError(t, ba(c))
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,74 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
//
|
||||||
"bufio"
|
// import (
|
||||||
"compress/gzip"
|
// "bufio"
|
||||||
"io"
|
// "compress/gzip"
|
||||||
"io/ioutil"
|
// "io"
|
||||||
"net"
|
// "io/ioutil"
|
||||||
"net/http"
|
// "net"
|
||||||
"strings"
|
// "net/http"
|
||||||
"sync"
|
// "strings"
|
||||||
|
// "sync"
|
||||||
"github.com/labstack/echo"
|
//
|
||||||
)
|
// "github.com/labstack/echo"
|
||||||
|
// )
|
||||||
type (
|
//
|
||||||
gzipWriter struct {
|
// type (
|
||||||
io.Writer
|
// gzipWriter struct {
|
||||||
http.ResponseWriter
|
// io.Writer
|
||||||
}
|
// http.ResponseWriter
|
||||||
)
|
// }
|
||||||
|
// )
|
||||||
func (w gzipWriter) Write(b []byte) (int, error) {
|
//
|
||||||
if w.Header().Get(echo.ContentType) == "" {
|
// func (w gzipWriter) Write(b []byte) (int, error) {
|
||||||
w.Header().Set(echo.ContentType, http.DetectContentType(b))
|
// if w.Header().Get(echo.ContentType) == "" {
|
||||||
}
|
// w.Header().Set(echo.ContentType, http.DetectContentType(b))
|
||||||
return w.Writer.Write(b)
|
// }
|
||||||
}
|
// return w.Writer.Write(b)
|
||||||
|
// }
|
||||||
func (w gzipWriter) Flush() error {
|
//
|
||||||
return w.Writer.(*gzip.Writer).Flush()
|
// func (w gzipWriter) Flush() error {
|
||||||
}
|
// return w.Writer.(*gzip.Writer).Flush()
|
||||||
|
// }
|
||||||
func (w gzipWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
//
|
||||||
return w.ResponseWriter.(http.Hijacker).Hijack()
|
// func (w gzipWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
}
|
// return w.ResponseWriter.(http.Hijacker).Hijack()
|
||||||
|
// }
|
||||||
func (w *gzipWriter) CloseNotify() <-chan bool {
|
//
|
||||||
return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
// func (w *gzipWriter) CloseNotify() <-chan bool {
|
||||||
}
|
// return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||||
|
// }
|
||||||
var writerPool = sync.Pool{
|
//
|
||||||
New: func() interface{} {
|
// var writerPool = sync.Pool{
|
||||||
return gzip.NewWriter(ioutil.Discard)
|
// New: func() interface{} {
|
||||||
},
|
// return gzip.NewWriter(ioutil.Discard)
|
||||||
}
|
// },
|
||||||
|
// }
|
||||||
// Gzip returns a middleware which compresses HTTP response using gzip compression
|
//
|
||||||
// scheme.
|
// // Gzip returns a middleware which compresses HTTP response using gzip compression
|
||||||
func Gzip() echo.MiddlewareFunc {
|
// // scheme.
|
||||||
scheme := "gzip"
|
// func Gzip() echo.MiddlewareFunc {
|
||||||
|
// scheme := "gzip"
|
||||||
return func(h echo.HandlerFunc) echo.HandlerFunc {
|
//
|
||||||
return func(c echo.Context) error {
|
// return func(h echo.HandlerFunc) echo.HandlerFunc {
|
||||||
c.Response().Header().Add(echo.Vary, echo.AcceptEncoding)
|
// return func(c echo.Context) error {
|
||||||
if strings.Contains(c.Request().Header().Get(echo.AcceptEncoding), scheme) {
|
// c.Response().Header().Add(echo.Vary, echo.AcceptEncoding)
|
||||||
w := writerPool.Get().(*gzip.Writer)
|
// if strings.Contains(c.Request().Header().Get(echo.AcceptEncoding), scheme) {
|
||||||
w.Reset(c.Response().Writer())
|
// w := writerPool.Get().(*gzip.Writer)
|
||||||
defer func() {
|
// w.Reset(c.Response().Writer())
|
||||||
w.Close()
|
// defer func() {
|
||||||
writerPool.Put(w)
|
// w.Close()
|
||||||
}()
|
// writerPool.Put(w)
|
||||||
gw := gzipWriter{Writer: w, ResponseWriter: c.Response().Writer()}
|
// }()
|
||||||
c.Response().Header().Set(echo.ContentEncoding, scheme)
|
// gw := gzipWriter{Writer: w, ResponseWriter: c.Response().Writer()}
|
||||||
c.Response().SetWriter(gw)
|
// c.Response().Header().Set(echo.ContentEncoding, scheme)
|
||||||
}
|
// c.Response().SetWriter(gw)
|
||||||
if err := h(c); err != nil {
|
// }
|
||||||
c.Error(err)
|
// if err := h(c); err != nil {
|
||||||
}
|
// c.Error(err)
|
||||||
return nil
|
// }
|
||||||
}
|
// return nil
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
@ -1,144 +1,146 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
//
|
||||||
"bytes"
|
// import (
|
||||||
"compress/gzip"
|
// "bytes"
|
||||||
"net/http"
|
// "compress/gzip"
|
||||||
"net/http/httptest"
|
// "net/http"
|
||||||
"testing"
|
// "net/http/httptest"
|
||||||
"time"
|
// "testing"
|
||||||
|
// "time"
|
||||||
"github.com/labstack/echo"
|
//
|
||||||
"github.com/stretchr/testify/assert"
|
// "github.com/labstack/echo"
|
||||||
)
|
// "github.com/labstack/echo/test"
|
||||||
|
// "github.com/stretchr/testify/assert"
|
||||||
type closeNotifyingRecorder struct {
|
// )
|
||||||
*httptest.ResponseRecorder
|
//
|
||||||
closed chan bool
|
// type closeNotifyingRecorder struct {
|
||||||
}
|
// *httptest.ResponseRecorder
|
||||||
|
// closed chan bool
|
||||||
func newCloseNotifyingRecorder() *closeNotifyingRecorder {
|
// }
|
||||||
return &closeNotifyingRecorder{
|
//
|
||||||
httptest.NewRecorder(),
|
// func newCloseNotifyingRecorder() *closeNotifyingRecorder {
|
||||||
make(chan bool, 1),
|
// return &closeNotifyingRecorder{
|
||||||
}
|
// test.NewResponseRecorder(),
|
||||||
}
|
// make(chan bool, 1),
|
||||||
|
// }
|
||||||
func (c *closeNotifyingRecorder) close() {
|
// }
|
||||||
c.closed <- true
|
//
|
||||||
}
|
// func (c *closeNotifyingRecorder) close() {
|
||||||
|
// c.closed <- true
|
||||||
func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
|
// }
|
||||||
return c.closed
|
//
|
||||||
}
|
// func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
|
||||||
|
// return c.closed
|
||||||
func TestGzip(t *testing.T) {
|
// }
|
||||||
e := echo.New()
|
//
|
||||||
req, _ := http.NewRequest(echo.GET, "/", nil)
|
// func TestGzip(t *testing.T) {
|
||||||
rec := httptest.NewRecorder()
|
// e := echo.New()
|
||||||
c := echo.NewContext(req, echo.NewResponse(rec, e), e)
|
// req := test.NewRequest(echo.GET, "/", nil)
|
||||||
h := func(c echo.Context) error {
|
// res := test.NewResponseRecorder()
|
||||||
c.Response().Write([]byte("test")) // For Content-Type sniffing
|
// c := echo.NewContext(req, res, e)
|
||||||
return nil
|
// h := func(c echo.Context) error {
|
||||||
}
|
// c.Response().Write([]byte("test")) // For Content-Type sniffing
|
||||||
|
// return nil
|
||||||
// Skip if no Accept-Encoding header
|
// }
|
||||||
Gzip()(h)(c)
|
//
|
||||||
assert.Equal(t, http.StatusOK, rec.Code)
|
// // Skip if no Accept-Encoding header
|
||||||
assert.Equal(t, "test", rec.Body.String())
|
// Gzip()(h)(c)
|
||||||
|
// assert.Equal(t, http.StatusOK, res.Status())
|
||||||
req, _ = http.NewRequest(echo.GET, "/", nil)
|
// assert.Equal(t, "test", res.Body().String())
|
||||||
req.Header.Set(echo.AcceptEncoding, "gzip")
|
//
|
||||||
rec = httptest.NewRecorder()
|
// req = test.NewRequest(echo.GET, "/", nil)
|
||||||
c = echo.NewContext(req, echo.NewResponse(rec, e), e)
|
// req.Header.Set(echo.AcceptEncoding, "gzip")
|
||||||
|
// res = test.NewResponseRecorder()
|
||||||
// Gzip
|
// c = echo.NewContext(req, res, e)
|
||||||
Gzip()(h)(c)
|
//
|
||||||
assert.Equal(t, http.StatusOK, rec.Code)
|
// // Gzip
|
||||||
assert.Equal(t, "gzip", rec.Header().Get(echo.ContentEncoding))
|
// Gzip()(h)(c)
|
||||||
assert.Contains(t, rec.Header().Get(echo.ContentType), echo.TextPlain)
|
// assert.Equal(t, http.StatusOK, res.Status())
|
||||||
r, err := gzip.NewReader(rec.Body)
|
// assert.Equal(t, "gzip", res.Header().Get(echo.ContentEncoding))
|
||||||
defer r.Close()
|
// assert.Contains(t, res.Header().Get(echo.ContentType), echo.TextPlain)
|
||||||
if assert.NoError(t, err) {
|
// r, err := gzip.NewReader(res.Body())
|
||||||
buf := new(bytes.Buffer)
|
// defer r.Close()
|
||||||
buf.ReadFrom(r)
|
// if assert.NoError(t, err) {
|
||||||
assert.Equal(t, "test", buf.String())
|
// buf := new(bytes.Buffer)
|
||||||
}
|
// buf.ReadFrom(r)
|
||||||
}
|
// assert.Equal(t, "test", buf.String())
|
||||||
|
// }
|
||||||
func TestGzipFlush(t *testing.T) {
|
// }
|
||||||
rec := httptest.NewRecorder()
|
//
|
||||||
buf := new(bytes.Buffer)
|
// func TestGzipFlush(t *testing.T) {
|
||||||
w := gzip.NewWriter(buf)
|
// res := test.NewResponseRecorder()
|
||||||
gw := gzipWriter{Writer: w, ResponseWriter: rec}
|
// buf := new(bytes.Buffer)
|
||||||
|
// w := gzip.NewWriter(buf)
|
||||||
n0 := buf.Len()
|
// gw := gzipWriter{Writer: w, ResponseWriter: res}
|
||||||
if n0 != 0 {
|
//
|
||||||
t.Fatalf("buffer size = %d before writes; want 0", n0)
|
// n0 := buf.Len()
|
||||||
}
|
// if n0 != 0 {
|
||||||
|
// t.Fatalf("buffer size = %d before writes; want 0", n0)
|
||||||
if err := gw.Flush(); err != nil {
|
// }
|
||||||
t.Fatal(err)
|
//
|
||||||
}
|
// if err := gw.Flush(); err != nil {
|
||||||
|
// t.Fatal(err)
|
||||||
n1 := buf.Len()
|
// }
|
||||||
if n1 == 0 {
|
//
|
||||||
t.Fatal("no data after first flush")
|
// n1 := buf.Len()
|
||||||
}
|
// if n1 == 0 {
|
||||||
|
// t.Fatal("no data after first flush")
|
||||||
gw.Write([]byte("x"))
|
// }
|
||||||
|
//
|
||||||
n2 := buf.Len()
|
// gw.Write([]byte("x"))
|
||||||
if n1 != n2 {
|
//
|
||||||
t.Fatalf("after writing a single byte, size changed from %d to %d; want no change", n1, n2)
|
// n2 := buf.Len()
|
||||||
}
|
// if n1 != n2 {
|
||||||
|
// t.Fatalf("after writing a single byte, size changed from %d to %d; want no change", n1, n2)
|
||||||
if err := gw.Flush(); err != nil {
|
// }
|
||||||
t.Fatal(err)
|
//
|
||||||
}
|
// if err := gw.Flush(); err != nil {
|
||||||
|
// t.Fatal(err)
|
||||||
n3 := buf.Len()
|
// }
|
||||||
if n2 == n3 {
|
//
|
||||||
t.Fatal("Flush didn't flush any data")
|
// n3 := buf.Len()
|
||||||
}
|
// if n2 == n3 {
|
||||||
}
|
// t.Fatal("Flush didn't flush any data")
|
||||||
|
// }
|
||||||
func TestGzipCloseNotify(t *testing.T) {
|
// }
|
||||||
rec := newCloseNotifyingRecorder()
|
//
|
||||||
buf := new(bytes.Buffer)
|
// func TestGzipCloseNotify(t *testing.T) {
|
||||||
w := gzip.NewWriter(buf)
|
// rec := newCloseNotifyingRecorder()
|
||||||
gw := gzipWriter{Writer: w, ResponseWriter: rec}
|
// buf := new(bytes.Buffer)
|
||||||
closed := false
|
// w := gzip.NewWriter(buf)
|
||||||
notifier := gw.CloseNotify()
|
// gw := gzipWriter{Writer: w, ResponseWriter: rec}
|
||||||
rec.close()
|
// closed := false
|
||||||
|
// notifier := gw.CloseNotify()
|
||||||
select {
|
// rec.close()
|
||||||
case <-notifier:
|
//
|
||||||
closed = true
|
// select {
|
||||||
case <-time.After(time.Second):
|
// case <-notifier:
|
||||||
}
|
// closed = true
|
||||||
|
// case <-time.After(time.Second):
|
||||||
assert.Equal(t, closed, true)
|
// }
|
||||||
}
|
//
|
||||||
|
// assert.Equal(t, closed, true)
|
||||||
func BenchmarkGzip(b *testing.B) {
|
// }
|
||||||
b.StopTimer()
|
//
|
||||||
b.ReportAllocs()
|
// func BenchmarkGzip(b *testing.B) {
|
||||||
|
// b.StopTimer()
|
||||||
h := func(c echo.Context) error {
|
// b.ReportAllocs()
|
||||||
c.Response().Write([]byte("test")) // For Content-Type sniffing
|
//
|
||||||
return nil
|
// h := func(c echo.Context) error {
|
||||||
}
|
// c.Response().Write([]byte("test")) // For Content-Type sniffing
|
||||||
req, _ := http.NewRequest(echo.GET, "/", nil)
|
// return nil
|
||||||
req.Header.Set(echo.AcceptEncoding, "gzip")
|
// }
|
||||||
|
// req, _ := http.NewRequest(echo.GET, "/", nil)
|
||||||
b.StartTimer()
|
// req.Header().Set(echo.AcceptEncoding, "gzip")
|
||||||
|
//
|
||||||
for i := 0; i < b.N; i++ {
|
// b.StartTimer()
|
||||||
e := echo.New()
|
//
|
||||||
rec := httptest.NewRecorder()
|
// for i := 0; i < b.N; i++ {
|
||||||
c := echo.NewContext(req, echo.NewResponse(rec, e), e)
|
// e := echo.New()
|
||||||
Gzip()(h)(c)
|
// res := test.NewResponseRecorder()
|
||||||
}
|
// c := echo.NewContext(req, res, e)
|
||||||
|
// Gzip()(h)(c)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
@ -4,19 +4,19 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
|
"github.com/labstack/echo/test"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLogger(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, _ := http.NewRequest(echo.GET, "/", nil)
|
req := test.NewRequest(echo.GET, "/", nil)
|
||||||
rec := httptest.NewRecorder()
|
res := test.NewResponseRecorder()
|
||||||
c := echo.NewContext(req, echo.NewResponse(rec, e), e)
|
c := echo.NewContext(req, res, e)
|
||||||
|
|
||||||
// Status 2xx
|
// Status 2xx
|
||||||
h := func(c echo.Context) error {
|
h := func(c echo.Context) error {
|
||||||
@ -25,25 +25,25 @@ func TestLogger(t *testing.T) {
|
|||||||
Logger()(h)(c)
|
Logger()(h)(c)
|
||||||
|
|
||||||
// Status 3xx
|
// Status 3xx
|
||||||
rec = httptest.NewRecorder()
|
res = test.NewResponseRecorder()
|
||||||
c = echo.NewContext(req, echo.NewResponse(rec, e), e)
|
c = echo.NewContext(req, res, 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
|
||||||
rec = httptest.NewRecorder()
|
res = test.NewResponseRecorder()
|
||||||
c = echo.NewContext(req, echo.NewResponse(rec, e), e)
|
c = echo.NewContext(req, res, 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")
|
||||||
}
|
}
|
||||||
Logger()(h)(c)
|
Logger()(h)(c)
|
||||||
|
|
||||||
// Status 5xx with empty path
|
// Status 5xx with empty path
|
||||||
req, _ = http.NewRequest(echo.GET, "", nil)
|
req = test.NewRequest(echo.GET, "", nil)
|
||||||
rec = httptest.NewRecorder()
|
res = test.NewResponseRecorder()
|
||||||
c = echo.NewContext(req, echo.NewResponse(rec, e), e)
|
c = echo.NewContext(req, res, e)
|
||||||
h = func(c echo.Context) error {
|
h = func(c echo.Context) error {
|
||||||
return errors.New("error")
|
return errors.New("error")
|
||||||
}
|
}
|
||||||
@ -52,9 +52,9 @@ func TestLogger(t *testing.T) {
|
|||||||
|
|
||||||
func TestLoggerIPAddress(t *testing.T) {
|
func TestLoggerIPAddress(t *testing.T) {
|
||||||
e := echo.New()
|
e := echo.New()
|
||||||
req, _ := http.NewRequest(echo.GET, "/", nil)
|
req := test.NewRequest(echo.GET, "/", nil)
|
||||||
rec := httptest.NewRecorder()
|
res := test.NewResponseRecorder()
|
||||||
c := echo.NewContext(req, echo.NewResponse(rec, e), e)
|
c := echo.NewContext(req, res, 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"
|
||||||
@ -65,14 +65,14 @@ func TestLoggerIPAddress(t *testing.T) {
|
|||||||
mw := Logger()
|
mw := Logger()
|
||||||
|
|
||||||
// With X-Real-IP
|
// With X-Real-IP
|
||||||
req.Header.Add(echo.XRealIP, ip)
|
req.Header().Add(echo.XRealIP, ip)
|
||||||
mw(h)(c)
|
mw(h)(c)
|
||||||
assert.Contains(t, buf.String(), ip)
|
assert.Contains(t, buf.String(), ip)
|
||||||
|
|
||||||
// With X-Forwarded-For
|
// With X-Forwarded-For
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
req.Header.Del(echo.XRealIP)
|
req.Header().Del(echo.XRealIP)
|
||||||
req.Header.Add(echo.XForwardedFor, ip)
|
req.Header().Add(echo.XForwardedFor, ip)
|
||||||
mw(h)(c)
|
mw(h)(c)
|
||||||
assert.Contains(t, buf.String(), ip)
|
assert.Contains(t, buf.String(), ip)
|
||||||
|
|
||||||
|
@ -2,23 +2,23 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
|
"github.com/labstack/echo/test"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRecover(t *testing.T) {
|
func TestRecover(t *testing.T) {
|
||||||
e := echo.New()
|
e := echo.New()
|
||||||
e.SetDebug(true)
|
e.SetDebug(true)
|
||||||
req, _ := http.NewRequest(echo.GET, "/", nil)
|
req := test.NewRequest(echo.GET, "/", nil)
|
||||||
rec := httptest.NewRecorder()
|
res := test.NewResponseRecorder()
|
||||||
c := echo.NewContext(req, echo.NewResponse(rec, e), e)
|
c := echo.NewContext(req, res, 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, rec.Code)
|
assert.Equal(t, http.StatusInternalServerError, res.Status())
|
||||||
assert.Contains(t, rec.Body.String(), "panic recover")
|
assert.Contains(t, res.Body.String(), "panic recover")
|
||||||
}
|
}
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
mw "github.com/labstack/echo/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
user struct {
|
|
||||||
ID int
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
users = map[int]*user{}
|
|
||||||
seq = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
//----------
|
|
||||||
// Handlers
|
|
||||||
//----------
|
|
||||||
|
|
||||||
func createUser(c echo.Context) error {
|
|
||||||
u := &user{
|
|
||||||
ID: seq,
|
|
||||||
}
|
|
||||||
if err := c.Bind(u); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
users[u.ID] = u
|
|
||||||
seq++
|
|
||||||
return c.JSON(http.StatusCreated, u)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUser(c echo.Context) error {
|
|
||||||
id, _ := strconv.Atoi(c.Param("id"))
|
|
||||||
return c.JSON(http.StatusOK, users[id])
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUser(c echo.Context) error {
|
|
||||||
u := new(user)
|
|
||||||
if err := c.Bind(u); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
id, _ := strconv.Atoi(c.Param("id"))
|
|
||||||
users[id].Name = u.Name
|
|
||||||
return c.JSON(http.StatusOK, users[id])
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteUser(c echo.Context) error {
|
|
||||||
id, _ := strconv.Atoi(c.Param("id"))
|
|
||||||
delete(users, id)
|
|
||||||
return c.NoContent(http.StatusNoContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
e := echo.New()
|
|
||||||
|
|
||||||
// Middleware
|
|
||||||
e.Use(mw.Logger())
|
|
||||||
e.Use(mw.Recover())
|
|
||||||
|
|
||||||
// Routes
|
|
||||||
e.Post("/users", createUser)
|
|
||||||
e.Get("/users/:id", getUser)
|
|
||||||
e.Patch("/users/:id", updateUser)
|
|
||||||
e.Delete("/users/:id", deleteUser)
|
|
||||||
|
|
||||||
// Start server
|
|
||||||
e.Run(":1323")
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/GeertJohan/go.rice"
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
e := echo.New()
|
|
||||||
// the file server for rice. "app" is the folder where the files come from.
|
|
||||||
assetHandler := http.FileServer(rice.MustFindBox("app").HTTPBox())
|
|
||||||
// serves the index.html from rice
|
|
||||||
e.Get("/", func(c echo.Context) error {
|
|
||||||
assetHandler.ServeHTTP(c.Response().Writer(), c.Request())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
// servers other static files
|
|
||||||
e.Get("/static/*", func(c echo.Context) error {
|
|
||||||
http.StripPrefix("/static/", assetHandler).
|
|
||||||
ServeHTTP(c.Response().Writer(), c.Request())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
e.Run(":3000")
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
mw "github.com/labstack/echo/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
func upload(c echo.Context) error {
|
|
||||||
req := c.Request()
|
|
||||||
req.ParseMultipartForm(16 << 20) // Max memory 16 MiB
|
|
||||||
|
|
||||||
// Read form fields
|
|
||||||
name := c.Form("name")
|
|
||||||
email := c.Form("email")
|
|
||||||
|
|
||||||
// Read files
|
|
||||||
files := req.MultipartForm.File["files"]
|
|
||||||
for _, f := range files {
|
|
||||||
// Source file
|
|
||||||
src, err := f.Open()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer src.Close()
|
|
||||||
|
|
||||||
// Destination file
|
|
||||||
dst, err := os.Create(f.Filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer dst.Close()
|
|
||||||
|
|
||||||
if _, err = io.Copy(dst, src); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.String(http.StatusOK, fmt.Sprintf("Thank You! %s <%s>, %d files uploaded successfully.",
|
|
||||||
name, email, len(files)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
e := echo.New()
|
|
||||||
e.Use(mw.Logger())
|
|
||||||
e.Use(mw.Recover())
|
|
||||||
|
|
||||||
e.Static("/", "public")
|
|
||||||
e.Post("/upload", upload)
|
|
||||||
|
|
||||||
e.Run(":1323")
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
"github.com/rs/cors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
user struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
users map[string]user
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
users = map[string]user{
|
|
||||||
"1": user{
|
|
||||||
ID: "1",
|
|
||||||
Name: "Wreck-It Ralph",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// hook into the echo instance to create an endpoint group
|
|
||||||
// and add specific middleware to it plus handlers
|
|
||||||
g := e.Group("/users")
|
|
||||||
g.Use(cors.Default().Handler)
|
|
||||||
|
|
||||||
g.Post("", createUser)
|
|
||||||
g.Get("", getUsers)
|
|
||||||
g.Get("/:id", getUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createUser(c echo.Context) error {
|
|
||||||
u := new(user)
|
|
||||||
if err := c.Bind(u); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
users[u.ID] = *u
|
|
||||||
return c.JSON(http.StatusCreated, u)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUsers(c echo.Context) error {
|
|
||||||
return c.JSON(http.StatusOK, users)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUser(c echo.Context) error {
|
|
||||||
return c.JSON(http.StatusOK, users[c.P(0)])
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
Template struct {
|
|
||||||
templates *template.Template
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
t := &Template{
|
|
||||||
templates: template.Must(template.ParseFiles("templates/welcome.html")),
|
|
||||||
}
|
|
||||||
e.SetRenderer(t)
|
|
||||||
e.Get("/welcome", welcome)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
|
|
||||||
return t.templates.ExecuteTemplate(w, name, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func welcome(c echo.Context) error {
|
|
||||||
return c.Render(http.StatusOK, "welcome", "Joe")
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/facebookgo/grace/gracehttp"
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Setup
|
|
||||||
e := echo.New()
|
|
||||||
e.Get("/", func(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "Six sick bricks tick")
|
|
||||||
})
|
|
||||||
|
|
||||||
// Get the http.Server
|
|
||||||
s := e.Server(":1323")
|
|
||||||
|
|
||||||
// HTTP2 is currently enabled by default in echo.New(). To override TLS handshake errors
|
|
||||||
// you will need to override the TLSConfig for the server so it does not attempt to validate
|
|
||||||
// the connection using TLS as required by HTTP2
|
|
||||||
s.TLSConfig = nil
|
|
||||||
|
|
||||||
// Serve it like a boss
|
|
||||||
gracehttp.Serve(s)
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
"github.com/tylerb/graceful"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Setup
|
|
||||||
e := echo.New()
|
|
||||||
e.Get("/", func(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "Sue sews rose on slow joe crows nose")
|
|
||||||
})
|
|
||||||
|
|
||||||
graceful.ListenAndServe(e.Server(":1323"), 5*time.Second)
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
mw "github.com/labstack/echo/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Handler
|
|
||||||
func hello(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "Hello, World!\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Echo instance
|
|
||||||
e := echo.New()
|
|
||||||
|
|
||||||
// Middleware
|
|
||||||
e.Use(mw.Logger())
|
|
||||||
e.Use(mw.Recover())
|
|
||||||
|
|
||||||
// Routes
|
|
||||||
e.Get("/", hello)
|
|
||||||
|
|
||||||
// Start server
|
|
||||||
e.Run(":1323")
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Setup
|
|
||||||
e := echo.New()
|
|
||||||
e.ServeDir("/", "public")
|
|
||||||
|
|
||||||
e.Get("/jsonp", func(c echo.Context) error {
|
|
||||||
callback := c.Query("callback")
|
|
||||||
var content struct {
|
|
||||||
Response string `json:"response"`
|
|
||||||
Timestamp time.Time `json:"timestamp"`
|
|
||||||
Random int `json:"random"`
|
|
||||||
}
|
|
||||||
content.Response = "Sent via JSONP"
|
|
||||||
content.Timestamp = time.Now().UTC()
|
|
||||||
content.Random = rand.Intn(1000)
|
|
||||||
return c.JSONP(http.StatusOK, callback, &content)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Start server
|
|
||||||
e.Run(":3999")
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
mw "github.com/labstack/echo/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
Bearer = "Bearer"
|
|
||||||
SigningKey = "somethingsupersecret"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A JSON Web Token middleware
|
|
||||||
func JWTAuth(key string) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
|
|
||||||
// Skip WebSocket
|
|
||||||
if (c.Request().Header.Get(echo.Upgrade)) == echo.WebSocket {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
auth := c.Request().Header.Get("Authorization")
|
|
||||||
l := len(Bearer)
|
|
||||||
he := echo.NewHTTPError(http.StatusUnauthorized)
|
|
||||||
|
|
||||||
if len(auth) > l+1 && auth[:l] == Bearer {
|
|
||||||
t, err := jwt.Parse(auth[l+1:], func(token *jwt.Token) (interface{}, error) {
|
|
||||||
|
|
||||||
// Always check the signing method
|
|
||||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
||||||
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the key for validation
|
|
||||||
return []byte(key), nil
|
|
||||||
})
|
|
||||||
if err == nil && t.Valid {
|
|
||||||
// Store token claims in echo.Context
|
|
||||||
c.Set("claims", t.Claims)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return he
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func accessible(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "No auth required for this route.\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func restricted(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "Access granted with JWT.\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Echo instance
|
|
||||||
e := echo.New()
|
|
||||||
|
|
||||||
// Logger
|
|
||||||
e.Use(mw.Logger())
|
|
||||||
|
|
||||||
// Unauthenticated route
|
|
||||||
e.Get("/", accessible)
|
|
||||||
|
|
||||||
// Restricted group
|
|
||||||
r := e.Group("/restricted")
|
|
||||||
r.Use(JWTAuth(SigningKey))
|
|
||||||
r.Get("", restricted)
|
|
||||||
|
|
||||||
// Start server
|
|
||||||
e.Run(":1323")
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
mw "github.com/labstack/echo/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Handler
|
|
||||||
func hello(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "Hello, World!\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Echo instance
|
|
||||||
e := echo.New()
|
|
||||||
|
|
||||||
// Debug mode
|
|
||||||
e.Debug()
|
|
||||||
|
|
||||||
//------------
|
|
||||||
// Middleware
|
|
||||||
//------------
|
|
||||||
|
|
||||||
// Logger
|
|
||||||
e.Use(mw.Logger())
|
|
||||||
|
|
||||||
// Recover
|
|
||||||
e.Use(mw.Recover())
|
|
||||||
|
|
||||||
// Basic auth
|
|
||||||
e.Use(mw.BasicAuth(func(usr, pwd string) bool {
|
|
||||||
if usr == "joe" && pwd == "secret" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Gzip
|
|
||||||
e.Use(mw.Gzip())
|
|
||||||
|
|
||||||
// Routes
|
|
||||||
e.Get("/", hello)
|
|
||||||
|
|
||||||
// Start server
|
|
||||||
e.Run(":1323")
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
mw "github.com/labstack/echo/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
func upload(c echo.Context) error {
|
|
||||||
mr, err := c.Request().MultipartReader()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read form field `name`
|
|
||||||
part, err := mr.NextPart()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer part.Close()
|
|
||||||
b, err := ioutil.ReadAll(part)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
name := string(b)
|
|
||||||
|
|
||||||
// Read form field `email`
|
|
||||||
part, err = mr.NextPart()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer part.Close()
|
|
||||||
b, err = ioutil.ReadAll(part)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
email := string(b)
|
|
||||||
|
|
||||||
// Read files
|
|
||||||
i := 0
|
|
||||||
for {
|
|
||||||
part, err := mr.NextPart()
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer part.Close()
|
|
||||||
|
|
||||||
file, err := os.Create(part.FileName())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
if _, err := io.Copy(file, part); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return c.String(http.StatusOK, fmt.Sprintf("Thank You! %s <%s>, %d files uploaded successfully.",
|
|
||||||
name, email, i))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
e := echo.New()
|
|
||||||
e.Use(mw.Logger())
|
|
||||||
e.Use(mw.Recover())
|
|
||||||
|
|
||||||
e.Static("/", "public")
|
|
||||||
e.Post("/upload", upload)
|
|
||||||
|
|
||||||
e.Run(":1323")
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
Geolocation struct {
|
|
||||||
Altitude float64
|
|
||||||
Latitude float64
|
|
||||||
Longitude float64
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
locations = []Geolocation{
|
|
||||||
{-97, 37.819929, -122.478255},
|
|
||||||
{1899, 39.096849, -120.032351},
|
|
||||||
{2619, 37.865101, -119.538329},
|
|
||||||
{42, 33.812092, -117.918974},
|
|
||||||
{15, 37.77493, -122.419416},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
e := echo.New()
|
|
||||||
e.Get("/", func(c echo.Context) error {
|
|
||||||
c.Response().Header().Set(echo.ContentType, echo.ApplicationJSON)
|
|
||||||
c.Response().WriteHeader(http.StatusOK)
|
|
||||||
for _, l := range locations {
|
|
||||||
if err := json.NewEncoder(c.Response()).Encode(l); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.Response().Flush()
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
e.Run(":1323")
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
mw "github.com/labstack/echo/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Hosts map[string]http.Handler
|
|
||||||
|
|
||||||
func (h Hosts) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if handler := h[r.Host]; handler != nil {
|
|
||||||
handler.ServeHTTP(w, r)
|
|
||||||
} else {
|
|
||||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Host map
|
|
||||||
hosts := make(Hosts)
|
|
||||||
|
|
||||||
//-----
|
|
||||||
// API
|
|
||||||
//-----
|
|
||||||
|
|
||||||
api := echo.New()
|
|
||||||
api.Use(mw.Logger())
|
|
||||||
api.Use(mw.Recover())
|
|
||||||
|
|
||||||
hosts["api.localhost:1323"] = api
|
|
||||||
|
|
||||||
api.Get("/", func(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "API")
|
|
||||||
})
|
|
||||||
|
|
||||||
//------
|
|
||||||
// Blog
|
|
||||||
//------
|
|
||||||
|
|
||||||
blog := echo.New()
|
|
||||||
blog.Use(mw.Logger())
|
|
||||||
blog.Use(mw.Recover())
|
|
||||||
|
|
||||||
hosts["blog.localhost:1323"] = blog
|
|
||||||
|
|
||||||
blog.Get("/", func(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "Blog")
|
|
||||||
})
|
|
||||||
|
|
||||||
//---------
|
|
||||||
// Website
|
|
||||||
//---------
|
|
||||||
|
|
||||||
site := echo.New()
|
|
||||||
site.Use(mw.Logger())
|
|
||||||
site.Use(mw.Recover())
|
|
||||||
|
|
||||||
hosts["localhost:1323"] = site
|
|
||||||
|
|
||||||
site.Get("/", func(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "Welcome!")
|
|
||||||
})
|
|
||||||
|
|
||||||
http.ListenAndServe(":1323", hosts)
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"html/template"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
mw "github.com/labstack/echo/middleware"
|
|
||||||
"github.com/rs/cors"
|
|
||||||
"github.com/thoas/stats"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Template provides HTML template rendering
|
|
||||||
Template struct {
|
|
||||||
templates *template.Template
|
|
||||||
}
|
|
||||||
|
|
||||||
user struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
users map[string]user
|
|
||||||
)
|
|
||||||
|
|
||||||
// Render HTML
|
|
||||||
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
|
|
||||||
return t.templates.ExecuteTemplate(w, name, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------
|
|
||||||
// Handlers
|
|
||||||
//----------
|
|
||||||
|
|
||||||
func welcome(c echo.Context) error {
|
|
||||||
return c.Render(http.StatusOK, "welcome", "Joe")
|
|
||||||
}
|
|
||||||
|
|
||||||
func createUser(c echo.Context) error {
|
|
||||||
u := new(user)
|
|
||||||
if err := c.Bind(u); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
users[u.ID] = *u
|
|
||||||
return c.JSON(http.StatusCreated, u)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUsers(c echo.Context) error {
|
|
||||||
return c.JSON(http.StatusOK, users)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUser(c echo.Context) error {
|
|
||||||
return c.JSON(http.StatusOK, users[c.P(0)])
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
e := echo.New()
|
|
||||||
|
|
||||||
// Middleware
|
|
||||||
e.Use(mw.Logger())
|
|
||||||
e.Use(mw.Recover())
|
|
||||||
e.Use(mw.Gzip())
|
|
||||||
|
|
||||||
//------------------------
|
|
||||||
// Third-party middleware
|
|
||||||
//------------------------
|
|
||||||
|
|
||||||
// https://github.com/rs/cors
|
|
||||||
e.Use(cors.Default().Handler)
|
|
||||||
|
|
||||||
// https://github.com/thoas/stats
|
|
||||||
s := stats.New()
|
|
||||||
e.Use(s.Handler)
|
|
||||||
// Route
|
|
||||||
e.Get("/stats", func(c echo.Context) error {
|
|
||||||
return c.JSON(http.StatusOK, s.Data())
|
|
||||||
})
|
|
||||||
|
|
||||||
// Serve index file
|
|
||||||
e.Index("public/index.html")
|
|
||||||
|
|
||||||
// Serve favicon
|
|
||||||
e.Favicon("public/favicon.ico")
|
|
||||||
|
|
||||||
// Serve static files
|
|
||||||
e.Static("/scripts", "public/scripts")
|
|
||||||
|
|
||||||
//--------
|
|
||||||
// Routes
|
|
||||||
//--------
|
|
||||||
|
|
||||||
e.Post("/users", createUser)
|
|
||||||
e.Get("/users", getUsers)
|
|
||||||
e.Get("/users/:id", getUser)
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
// Templates
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
t := &Template{
|
|
||||||
// Cached templates
|
|
||||||
templates: template.Must(template.ParseFiles("public/views/welcome.html")),
|
|
||||||
}
|
|
||||||
e.SetRenderer(t)
|
|
||||||
e.Get("/welcome", welcome)
|
|
||||||
|
|
||||||
//-------
|
|
||||||
// Group
|
|
||||||
//-------
|
|
||||||
|
|
||||||
// Group with parent middleware
|
|
||||||
a := e.Group("/admin")
|
|
||||||
a.Use(func(c echo.Context) error {
|
|
||||||
// Security middleware
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
a.Get("", func(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "Welcome admin!")
|
|
||||||
})
|
|
||||||
|
|
||||||
// Group with no parent middleware
|
|
||||||
g := e.Group("/files", func(c echo.Context) error {
|
|
||||||
// Security middleware
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
g.Get("", func(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "Your files!")
|
|
||||||
})
|
|
||||||
|
|
||||||
// Start server
|
|
||||||
e.Run(":1323")
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
users = map[string]user{
|
|
||||||
"1": user{
|
|
||||||
ID: "1",
|
|
||||||
Name: "Wreck-It Ralph",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
|
||||||
mw "github.com/labstack/echo/middleware"
|
|
||||||
"golang.org/x/net/websocket"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
e := echo.New()
|
|
||||||
|
|
||||||
e.Use(mw.Logger())
|
|
||||||
e.Use(mw.Recover())
|
|
||||||
|
|
||||||
e.Static("/", "public")
|
|
||||||
e.WebSocket("/ws", func(c echo.Context) (err error) {
|
|
||||||
ws := c.Socket()
|
|
||||||
msg := ""
|
|
||||||
|
|
||||||
for {
|
|
||||||
if err = websocket.Message.Send(ws, "Hello, Client!"); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = websocket.Message.Receive(ws, &msg); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
e.Run(":1323")
|
|
||||||
}
|
|
@ -35,7 +35,7 @@ SetLogPrefix sets the prefix for the logger. Default value is `echo`.
|
|||||||
|
|
||||||
`echo#SetLogOutput(w io.Writer)`
|
`echo#SetLogOutput(w io.Writer)`
|
||||||
|
|
||||||
SetLogOutput sets the output destination for the logger. Default value is `os.Std*`
|
SetLogOutput sets the output destination for the logger. Default value is `os.Stdout`
|
||||||
|
|
||||||
### Log level
|
### Log level
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user