From 55d88e9b1e884bc6876629e2b063690f2202687d Mon Sep 17 00:00:00 2001 From: gofmt Date: Tue, 8 Dec 2015 15:52:05 +0800 Subject: [PATCH 01/67] fix router.go cn.ppath = ppath --- router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/router.go b/router.go index a3bba24b2..ac47a688c 100644 --- a/router.go +++ b/router.go @@ -164,7 +164,7 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string // Node already exists if h != nil { cn.addHandler(method, h) - cn.ppath = path + cn.ppath = ppath cn.pnames = pnames cn.echo = e } From f40bf0a20a9f94b118cb1b6ab3535aaf288571c9 Mon Sep 17 00:00:00 2001 From: Walid ZIOUCHE <01walid@gmail.com> Date: Mon, 28 Dec 2015 21:59:02 +0100 Subject: [PATCH 02/67] Fix a small typo in customization docs --- website/content/guide/customization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/content/guide/customization.md b/website/content/guide/customization.md index f3ee75688..f3e019179 100644 --- a/website/content/guide/customization.md +++ b/website/content/guide/customization.md @@ -45,7 +45,7 @@ SetLogLevel sets the log level for the logger. Default value is `log.INFO`. ### HTTP2 -`echo#HTTP(on bool)` +`echo#HTTP2(on bool)` Enable/disable HTTP2 support. From 9c974279b0ea73930b0fce928000c6afaacffcc2 Mon Sep 17 00:00:00 2001 From: Alexey Palazhchenko Date: Thu, 31 Dec 2015 12:37:56 +0300 Subject: [PATCH 03/67] Fix typo --- website/content/guide/customization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/content/guide/customization.md b/website/content/guide/customization.md index f3ee75688..222ca52c4 100644 --- a/website/content/guide/customization.md +++ b/website/content/guide/customization.md @@ -60,7 +60,7 @@ Enable/disable automatically creating an index page for the directory. ```go e := echo.New() e.AutoIndex(true) -e.ServerDir("/", "/Users/vr/Projects/echo") +e.ServeDir("/", "/Users/vr/Projects/echo") e.Run(":1323") ``` From c8d77b2675004ed4add8546974928a750f0170d6 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 9 Jan 2016 09:44:18 -0800 Subject: [PATCH 04/67] Fixed #307 Signed-off-by: Vishal Rana --- recipes/crud/server.go | 75 --------- recipes/embed-resources/.gitignore | 2 - recipes/embed-resources/app/index.html | 11 -- recipes/embed-resources/app/main.js | 1 - recipes/embed-resources/rice.go | 26 ---- recipes/file-upload/public/index.html | 17 -- recipes/file-upload/server.go | 56 ------- recipes/google-app-engine/Dockerfile | 7 - recipes/google-app-engine/app-engine.go | 18 --- recipes/google-app-engine/app-engine.yaml | 36 ----- recipes/google-app-engine/app-managed.go | 29 ---- recipes/google-app-engine/app-managed.yaml | 37 ----- recipes/google-app-engine/app-standalone.go | 25 --- recipes/google-app-engine/app.go | 4 - recipes/google-app-engine/public/favicon.ico | Bin 1150 -> 0 bytes recipes/google-app-engine/public/index.html | 15 -- .../google-app-engine/public/scripts/main.js | 1 - .../google-app-engine/templates/welcome.html | 1 - recipes/google-app-engine/users.go | 54 ------- recipes/google-app-engine/welcome.go | 31 ---- recipes/graceful-shutdown/grace/server.go | 27 ---- recipes/graceful-shutdown/graceful/server.go | 19 --- recipes/hello-world/server.go | 28 ---- recipes/jsonp/public/index.html | 36 ----- recipes/jsonp/server.go | 31 ---- recipes/jwt-authentication/server.go | 76 --------- recipes/jwt-authentication/token/token.go | 24 --- recipes/middleware/server.go | 48 ------ .../streaming-file-upload/public/index.html | 17 -- recipes/streaming-file-upload/server.go | 81 ---------- recipes/streaming-response/server.go | 45 ------ recipes/subdomains/server.go | 67 -------- recipes/website/public/favicon.ico | Bin 1150 -> 0 bytes recipes/website/public/folder/index.html | 1 - recipes/website/public/index.html | 15 -- recipes/website/public/scripts/main.js | 1 - recipes/website/public/views/welcome.html | 1 - recipes/website/server.go | 146 ------------------ recipes/websocket/public/index.html | 37 ----- recipes/websocket/server.go | 34 ---- website/Dockerfile | 8 +- website/argo.json | 14 ++ website/content/recipes/crud.md | 2 +- website/content/recipes/embed-resources.md | 2 +- website/content/recipes/file-upload.md | 2 +- website/content/recipes/google-app-engine.md | 2 +- website/content/recipes/graceful-shutdown.md | 4 +- website/content/recipes/hello-world.md | 2 +- website/content/recipes/jsonp.md | 2 +- website/content/recipes/jwt-authentication.md | 2 +- website/content/recipes/middleware.md | 2 +- .../content/recipes/streaming-file-upload.md | 2 +- website/content/recipes/streaming-response.md | 2 +- website/content/recipes/subdomains.md | 2 +- website/content/recipes/website.md | 2 +- website/content/recipes/websocket.md | 2 +- website/layouts/shortcodes/embed.html | 2 +- website/package.json | 1 - website/server.go | 17 -- 59 files changed, 34 insertions(+), 1218 deletions(-) delete mode 100644 recipes/crud/server.go delete mode 100644 recipes/embed-resources/.gitignore delete mode 100644 recipes/embed-resources/app/index.html delete mode 100644 recipes/embed-resources/app/main.js delete mode 100644 recipes/embed-resources/rice.go delete mode 100644 recipes/file-upload/public/index.html delete mode 100644 recipes/file-upload/server.go delete mode 100644 recipes/google-app-engine/Dockerfile delete mode 100644 recipes/google-app-engine/app-engine.go delete mode 100644 recipes/google-app-engine/app-engine.yaml delete mode 100644 recipes/google-app-engine/app-managed.go delete mode 100644 recipes/google-app-engine/app-managed.yaml delete mode 100644 recipes/google-app-engine/app-standalone.go delete mode 100644 recipes/google-app-engine/app.go delete mode 100644 recipes/google-app-engine/public/favicon.ico delete mode 100644 recipes/google-app-engine/public/index.html delete mode 100644 recipes/google-app-engine/public/scripts/main.js delete mode 100644 recipes/google-app-engine/templates/welcome.html delete mode 100644 recipes/google-app-engine/users.go delete mode 100644 recipes/google-app-engine/welcome.go delete mode 100644 recipes/graceful-shutdown/grace/server.go delete mode 100644 recipes/graceful-shutdown/graceful/server.go delete mode 100644 recipes/hello-world/server.go delete mode 100644 recipes/jsonp/public/index.html delete mode 100644 recipes/jsonp/server.go delete mode 100644 recipes/jwt-authentication/server.go delete mode 100644 recipes/jwt-authentication/token/token.go delete mode 100644 recipes/middleware/server.go delete mode 100644 recipes/streaming-file-upload/public/index.html delete mode 100644 recipes/streaming-file-upload/server.go delete mode 100644 recipes/streaming-response/server.go delete mode 100644 recipes/subdomains/server.go delete mode 100644 recipes/website/public/favicon.ico delete mode 100644 recipes/website/public/folder/index.html delete mode 100644 recipes/website/public/index.html delete mode 100644 recipes/website/public/scripts/main.js delete mode 100644 recipes/website/public/views/welcome.html delete mode 100644 recipes/website/server.go delete mode 100644 recipes/websocket/public/index.html delete mode 100644 recipes/websocket/server.go create mode 100644 website/argo.json delete mode 100644 website/package.json delete mode 100644 website/server.go diff --git a/recipes/crud/server.go b/recipes/crud/server.go deleted file mode 100644 index 683acb8bb..000000000 --- a/recipes/crud/server.go +++ /dev/null @@ -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") -} diff --git a/recipes/embed-resources/.gitignore b/recipes/embed-resources/.gitignore deleted file mode 100644 index 9524d94fa..000000000 --- a/recipes/embed-resources/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -rice -app.rice-box.go diff --git a/recipes/embed-resources/app/index.html b/recipes/embed-resources/app/index.html deleted file mode 100644 index 66aac4465..000000000 --- a/recipes/embed-resources/app/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - go.rice Example - - - -

go.rice Example

- - diff --git a/recipes/embed-resources/app/main.js b/recipes/embed-resources/app/main.js deleted file mode 100644 index f888dc5ca..000000000 --- a/recipes/embed-resources/app/main.js +++ /dev/null @@ -1 +0,0 @@ -alert("main.js"); diff --git a/recipes/embed-resources/rice.go b/recipes/embed-resources/rice.go deleted file mode 100644 index 7dcc4b8ea..000000000 --- a/recipes/embed-resources/rice.go +++ /dev/null @@ -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") -} diff --git a/recipes/file-upload/public/index.html b/recipes/file-upload/public/index.html deleted file mode 100644 index cdbdb3e50..000000000 --- a/recipes/file-upload/public/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - File Upload - - -

Upload Files

- -
- Name:
- Email:
- Files:

- -
- - diff --git a/recipes/file-upload/server.go b/recipes/file-upload/server.go deleted file mode 100644 index 05ba9e996..000000000 --- a/recipes/file-upload/server.go +++ /dev/null @@ -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") -} diff --git a/recipes/google-app-engine/Dockerfile b/recipes/google-app-engine/Dockerfile deleted file mode 100644 index 5d1c13e53..000000000 --- a/recipes/google-app-engine/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -# Dockerfile extending the generic Go image with application files for a -# single application. -FROM gcr.io/google_appengine/golang - -COPY . /go/src/app -RUN go-wrapper download -RUN go-wrapper install -tags appenginevm \ No newline at end of file diff --git a/recipes/google-app-engine/app-engine.go b/recipes/google-app-engine/app-engine.go deleted file mode 100644 index ddbf39445..000000000 --- a/recipes/google-app-engine/app-engine.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build appengine - -package main - -import ( - "github.com/labstack/echo" - "net/http" -) - -func createMux() *echo.Echo { - e := echo.New() - - // note: we don't need to provide the middleware or static handlers, that's taken care of by the platform - // app engine has it's own "main" wrapper - we just need to hook echo into the default handler - http.Handle("/", e) - - return e -} diff --git a/recipes/google-app-engine/app-engine.yaml b/recipes/google-app-engine/app-engine.yaml deleted file mode 100644 index e8f5bf050..000000000 --- a/recipes/google-app-engine/app-engine.yaml +++ /dev/null @@ -1,36 +0,0 @@ -application: my-application-id # defined when you create your app using google dev console -module: default # see https://cloud.google.com/appengine/docs/go/ -version: alpha # you can run multiple versions of an app and A/B test -runtime: go # see https://cloud.google.com/appengine/docs/go/ -api_version: go1 # used when appengine supports different go versions - -default_expiration: "1d" # for CDN serving of static files (use url versioning if long!) - -handlers: -# all the static files that we normally serve ourselves are defined here and Google will handle -# serving them for us from it's own CDN / edge locations. For all the configuration options see: -# https://cloud.google.com/appengine/docs/go/config/appconfig#Go_app_yaml_Static_file_handlers -- url: / - mime_type: text/html - static_files: public/index.html - upload: public/index.html - -- url: /favicon.ico - mime_type: image/x-icon - static_files: public/favicon.ico - upload: public/favicon.ico - -- url: /scripts - mime_type: text/javascript - static_dir: public/scripts - -# static files normally don't touch the server that the app runs on but server-side template files -# needs to be readable by the app. The application_readable option makes sure they are available as -# part of the app deployment onto the instance. -- url: /templates - static_dir: /templates - application_readable: true - -# finally, we route all other requests to our application. The script name just means "the go app" -- url: /.* - script: _go_app \ No newline at end of file diff --git a/recipes/google-app-engine/app-managed.go b/recipes/google-app-engine/app-managed.go deleted file mode 100644 index cc5adfbf8..000000000 --- a/recipes/google-app-engine/app-managed.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build appenginevm - -package main - -import ( - "github.com/labstack/echo" - "google.golang.org/appengine" - "net/http" - "runtime" -) - -func createMux() *echo.Echo { - // we're in a container on a Google Compute Engine instance so are not sandboxed anymore ... - runtime.GOMAXPROCS(runtime.NumCPU()) - - e := echo.New() - - // note: we don't need to provide the middleware or static handlers - // for the appengine vm version - that's taken care of by the platform - - return e -} - -func main() { - // the appengine package provides a convenient method to handle the health-check requests - // and also run the app on the correct port. We just need to add Echo to the default handler - http.Handle("/", e) - appengine.Main() -} diff --git a/recipes/google-app-engine/app-managed.yaml b/recipes/google-app-engine/app-managed.yaml deleted file mode 100644 index d5da4cd94..000000000 --- a/recipes/google-app-engine/app-managed.yaml +++ /dev/null @@ -1,37 +0,0 @@ -application: my-application-id # defined when you create your app using google dev console -module: default # see https://cloud.google.com/appengine/docs/go/ -version: alpha # you can run multiple versions of an app and A/B test -runtime: go # see https://cloud.google.com/appengine/docs/go/ -api_version: go1 # used when appengine supports different go versions -vm: true # for managed VMs only, remove for appengine classic - -default_expiration: "1d" # for CDN serving of static files (use url versioning if long!) - -handlers: -# all the static files that we normally serve ourselves are defined here and Google will handle -# serving them for us from it's own CDN / edge locations. For all the configuration options see: -# https://cloud.google.com/appengine/docs/go/config/appconfig#Go_app_yaml_Static_file_handlers -- url: / - mime_type: text/html - static_files: public/index.html - upload: public/index.html - -- url: /favicon.ico - mime_type: image/x-icon - static_files: public/favicon.ico - upload: public/favicon.ico - -- url: /scripts - mime_type: text/javascript - static_dir: public/scripts - -# static files normally don't touch the server that the app runs on but server-side template files -# needs to be readable by the app. The application_readable option makes sure they are available as -# part of the app deployment onto the instance. -- url: /templates - static_dir: /templates - application_readable: true - -# finally, we route all other requests to our application. The script name just means "the go app" -- url: /.* - script: _go_app \ No newline at end of file diff --git a/recipes/google-app-engine/app-standalone.go b/recipes/google-app-engine/app-standalone.go deleted file mode 100644 index 0a6881fa8..000000000 --- a/recipes/google-app-engine/app-standalone.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build !appengine,!appenginevm - -package main - -import ( - "github.com/labstack/echo" - "github.com/labstack/echo/middleware" -) - -func createMux() *echo.Echo { - e := echo.New() - - e.Use(middleware.Recover()) - e.Use(middleware.Logger()) - e.Use(middleware.Gzip()) - - e.Index("public/index.html") - e.Static("/public", "public") - - return e -} - -func main() { - e.Run(":8080") -} diff --git a/recipes/google-app-engine/app.go b/recipes/google-app-engine/app.go deleted file mode 100644 index 442ed8863..000000000 --- a/recipes/google-app-engine/app.go +++ /dev/null @@ -1,4 +0,0 @@ -package main - -// referecnce our echo instance and create it early -var e = createMux() diff --git a/recipes/google-app-engine/public/favicon.ico b/recipes/google-app-engine/public/favicon.ico deleted file mode 100644 index d939ddca12aa14a2fa691e082b14436f18719f6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmZQzU<5(|0R|wcz>vYhz#zuJz@P!dKp~(AL>x#lFaYI*xgi+L$0S%eIXJ|4d3e=$ zc=$9q*f})W*w{3AxVg1?dHFTCxVU71TG%nQ!9^s*C1e}r6xHtm@dI&j$+JSjqKD-a z)E)x)52d8#mN7Cgr~_3q!*xIzLZXr&7N@L&MvuI*?teKY?f(+eioe7p3-i zipeOb?_p!-lme;)8iNY#y}}th{6lyR9m5aFStkFNx6S&mWS;@V>Hn3T^ZqMa;8qR43_WoB7nfzbbr}e*9NZ)^>jyEcB5D~<+3`sc1>sGYKwp`v5j zgo^Gt|D*C+{(Hxj{P#>K{U4Ck^gq98>i?R)d1sp^&J}2!I2S|z%ALmmsy{F`jln-ARk5h5aYt9* zj16{yc^j0iVpbHkPBBa^s?yiCa9}le@x`haBp8{T%@C22>snl1`#mEv>3=|I+E;tu z_=n{M)i2vSC%z1cPj!k)%D|~VFfN0^CoYq}ptP - - - - - Echo - - - - - -

Echo!

- - - diff --git a/recipes/google-app-engine/public/scripts/main.js b/recipes/google-app-engine/public/scripts/main.js deleted file mode 100644 index 62a4c8f1f..000000000 --- a/recipes/google-app-engine/public/scripts/main.js +++ /dev/null @@ -1 +0,0 @@ -console.log("Echo!"); diff --git a/recipes/google-app-engine/templates/welcome.html b/recipes/google-app-engine/templates/welcome.html deleted file mode 100644 index 5dc667c36..000000000 --- a/recipes/google-app-engine/templates/welcome.html +++ /dev/null @@ -1 +0,0 @@ -{{define "welcome"}}Hello, {{.}}!{{end}} diff --git a/recipes/google-app-engine/users.go b/recipes/google-app-engine/users.go deleted file mode 100644 index 8b1bf019d..000000000 --- a/recipes/google-app-engine/users.go +++ /dev/null @@ -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)]) -} diff --git a/recipes/google-app-engine/welcome.go b/recipes/google-app-engine/welcome.go deleted file mode 100644 index 2599a4d93..000000000 --- a/recipes/google-app-engine/welcome.go +++ /dev/null @@ -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") -} diff --git a/recipes/graceful-shutdown/grace/server.go b/recipes/graceful-shutdown/grace/server.go deleted file mode 100644 index 3a19c9b1a..000000000 --- a/recipes/graceful-shutdown/grace/server.go +++ /dev/null @@ -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) -} diff --git a/recipes/graceful-shutdown/graceful/server.go b/recipes/graceful-shutdown/graceful/server.go deleted file mode 100644 index 5f6b46a86..000000000 --- a/recipes/graceful-shutdown/graceful/server.go +++ /dev/null @@ -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) -} diff --git a/recipes/hello-world/server.go b/recipes/hello-world/server.go deleted file mode 100644 index 88883d074..000000000 --- a/recipes/hello-world/server.go +++ /dev/null @@ -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") -} diff --git a/recipes/jsonp/public/index.html b/recipes/jsonp/public/index.html deleted file mode 100644 index 033632e91..000000000 --- a/recipes/jsonp/public/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - JSONP - - - - - - -
- -

-


-        

-
- - - diff --git a/recipes/jsonp/server.go b/recipes/jsonp/server.go deleted file mode 100644 index 8d74d4808..000000000 --- a/recipes/jsonp/server.go +++ /dev/null @@ -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") -} diff --git a/recipes/jwt-authentication/server.go b/recipes/jwt-authentication/server.go deleted file mode 100644 index 96db0bf87..000000000 --- a/recipes/jwt-authentication/server.go +++ /dev/null @@ -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") -} diff --git a/recipes/jwt-authentication/token/token.go b/recipes/jwt-authentication/token/token.go deleted file mode 100644 index 0e309ab12..000000000 --- a/recipes/jwt-authentication/token/token.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "fmt" - "time" - - "github.com/dgrijalva/jwt-go" -) - -const SigningKey = "somethingsupersecret" - -func main() { - - // New web token. - token := jwt.New(jwt.SigningMethodHS256) - - // Set a header and a claim - token.Header["typ"] = "JWT" - token.Claims["exp"] = time.Now().Add(time.Hour * 96).Unix() - - // Generate encoded token - t, _ := token.SignedString([]byte(SigningKey)) - fmt.Println(t) -} diff --git a/recipes/middleware/server.go b/recipes/middleware/server.go deleted file mode 100644 index 98fa0d75a..000000000 --- a/recipes/middleware/server.go +++ /dev/null @@ -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") -} diff --git a/recipes/streaming-file-upload/public/index.html b/recipes/streaming-file-upload/public/index.html deleted file mode 100644 index cdbdb3e50..000000000 --- a/recipes/streaming-file-upload/public/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - File Upload - - -

Upload Files

- -
- Name:
- Email:
- Files:

- -
- - diff --git a/recipes/streaming-file-upload/server.go b/recipes/streaming-file-upload/server.go deleted file mode 100644 index 98778eece..000000000 --- a/recipes/streaming-file-upload/server.go +++ /dev/null @@ -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") -} diff --git a/recipes/streaming-response/server.go b/recipes/streaming-response/server.go deleted file mode 100644 index 0dbb18085..000000000 --- a/recipes/streaming-response/server.go +++ /dev/null @@ -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") -} diff --git a/recipes/subdomains/server.go b/recipes/subdomains/server.go deleted file mode 100644 index 2da3cf261..000000000 --- a/recipes/subdomains/server.go +++ /dev/null @@ -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) -} diff --git a/recipes/website/public/favicon.ico b/recipes/website/public/favicon.ico deleted file mode 100644 index d939ddca12aa14a2fa691e082b14436f18719f6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmZQzU<5(|0R|wcz>vYhz#zuJz@P!dKp~(AL>x#lFaYI*xgi+L$0S%eIXJ|4d3e=$ zc=$9q*f})W*w{3AxVg1?dHFTCxVU71TG%nQ!9^s*C1e}r6xHtm@dI&j$+JSjqKD-a z)E)x)52d8#mN7Cgr~_3q!*xIzLZXr&7N@L&MvuI*?teKY?f(+eioe7p3-i zipeOb?_p!-lme;)8iNY#y}}th{6lyR9m5aFStkFNx6S&mWS;@V>Hn3T^ZqMa;8qR43_WoB7nfzbbr}e*9NZ)^>jyEcB5D~<+3`sc1>sGYKwp`v5j zgo^Gt|D*C+{(Hxj{P#>K{U4Ck^gq98>i?R)d1sp^&J}2!I2S|z%ALmmsy{F`jln-ARk5h5aYt9* zj16{yc^j0iVpbHkPBBa^s?yiCa9}le@x`haBp8{T%@C22>snl1`#mEv>3=|I+E;tu z_=n{M)i2vSC%z1cPj!k)%D|~VFfN0^CoYq}ptP - - - - - Echo - - - - - -

Echo!

- - - diff --git a/recipes/website/public/scripts/main.js b/recipes/website/public/scripts/main.js deleted file mode 100644 index c3b96d214..000000000 --- a/recipes/website/public/scripts/main.js +++ /dev/null @@ -1 +0,0 @@ -console.log("Echo!") diff --git a/recipes/website/public/views/welcome.html b/recipes/website/public/views/welcome.html deleted file mode 100644 index 5dc667c36..000000000 --- a/recipes/website/public/views/welcome.html +++ /dev/null @@ -1 +0,0 @@ -{{define "welcome"}}Hello, {{.}}!{{end}} diff --git a/recipes/website/server.go b/recipes/website/server.go deleted file mode 100644 index 38886b92f..000000000 --- a/recipes/website/server.go +++ /dev/null @@ -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", - }, - } -} diff --git a/recipes/websocket/public/index.html b/recipes/websocket/public/index.html deleted file mode 100644 index 859bd55d8..000000000 --- a/recipes/websocket/public/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - WebSocket - - -

- - - - diff --git a/recipes/websocket/server.go b/recipes/websocket/server.go deleted file mode 100644 index 52d074fa7..000000000 --- a/recipes/websocket/server.go +++ /dev/null @@ -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") -} diff --git a/website/Dockerfile b/website/Dockerfile index c3a6614a2..e8306fd78 100644 --- a/website/Dockerfile +++ b/website/Dockerfile @@ -1,7 +1,7 @@ -FROM busybox +FROM reg.lab.st/argo MAINTAINER Vishal Rana -COPY server /server -COPY public /public +ADD argo.json /etc +ADD public /www -CMD ["/server"] +CMD ["-c", "/etc/argo.json"] diff --git a/website/argo.json b/website/argo.json new file mode 100644 index 000000000..8bc8ad384 --- /dev/null +++ b/website/argo.json @@ -0,0 +1,14 @@ +{ + "www": { + "listen": ":80", + "hosts": { + "*": { + "paths": { + "/*": { + "dir": "/www" + } + } + } + } + } +} diff --git a/website/content/recipes/crud.md b/website/content/recipes/crud.md index 5b1d81b21..65b1a0997 100644 --- a/website/content/recipes/crud.md +++ b/website/content/recipes/crud.md @@ -16,4 +16,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/crud) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/crud) diff --git a/website/content/recipes/embed-resources.md b/website/content/recipes/embed-resources.md index 275aec1a8..2b8ad44ac 100644 --- a/website/content/recipes/embed-resources.md +++ b/website/content/recipes/embed-resources.md @@ -17,4 +17,4 @@ menu: - [caarlos0](https://github.com/caarlos0) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/rice) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/rice) diff --git a/website/content/recipes/file-upload.md b/website/content/recipes/file-upload.md index 9919b0580..36582e63a 100644 --- a/website/content/recipes/file-upload.md +++ b/website/content/recipes/file-upload.md @@ -50,4 +50,4 @@ if _, err = io.Copy(dst, file); err != nil { - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/file-upload) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/file-upload) diff --git a/website/content/recipes/google-app-engine.md b/website/content/recipes/google-app-engine.md index ecc1c9b2a..bbfe35725 100644 --- a/website/content/recipes/google-app-engine.md +++ b/website/content/recipes/google-app-engine.md @@ -132,4 +132,4 @@ but is outside the scope of this recipe. - [CaptainCodeman](https://github.com/CaptainCodeman) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/google-app-engine) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/google-app-engine) diff --git a/website/content/recipes/graceful-shutdown.md b/website/content/recipes/graceful-shutdown.md index 1d2cc3e0c..f2516138c 100644 --- a/website/content/recipes/graceful-shutdown.md +++ b/website/content/recipes/graceful-shutdown.md @@ -24,6 +24,6 @@ menu: ### Source Code -[graceful](https://github.com/labstack/echo/blob/master/recipes/graceful-shutdown/graceful) +[graceful](https://github.com/vishr/recipes/blob/master/echo/recipes/graceful-shutdown/graceful) -[grace](https://github.com/labstack/echo/blob/master/recipes/graceful-shutdown/grace) +[grace](https://github.com/vishr/recipes/blob/master/echo/recipes/graceful-shutdown/grace) diff --git a/website/content/recipes/hello-world.md b/website/content/recipes/hello-world.md index f774f9d5a..94fa555f0 100644 --- a/website/content/recipes/hello-world.md +++ b/website/content/recipes/hello-world.md @@ -16,4 +16,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/hello-world) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/hello-world) diff --git a/website/content/recipes/jsonp.md b/website/content/recipes/jsonp.md index c04c6c353..07ad7c7d4 100644 --- a/website/content/recipes/jsonp.md +++ b/website/content/recipes/jsonp.md @@ -24,4 +24,4 @@ JSONP is a method that allows cross-domain server calls. You can read more about - [willf](https://github.com/willf) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/jsonp) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/jsonp) diff --git a/website/content/recipes/jwt-authentication.md b/website/content/recipes/jwt-authentication.md index df75f1840..938c119ec 100644 --- a/website/content/recipes/jwt-authentication.md +++ b/website/content/recipes/jwt-authentication.md @@ -55,4 +55,4 @@ $ curl localhost:1323/restricted -H "Authorization: Bearer " => Access g - [axdg](https://github.com/axdg) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/jwt-authentication) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/jwt-authentication) diff --git a/website/content/recipes/middleware.md b/website/content/recipes/middleware.md index bab02b002..6e0000585 100644 --- a/website/content/recipes/middleware.md +++ b/website/content/recipes/middleware.md @@ -17,4 +17,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/middleware) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/middleware) diff --git a/website/content/recipes/streaming-file-upload.md b/website/content/recipes/streaming-file-upload.md index 3e1f91469..ea02aa48f 100644 --- a/website/content/recipes/streaming-file-upload.md +++ b/website/content/recipes/streaming-file-upload.md @@ -25,4 +25,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/streaming-file-upload) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/streaming-file-upload) diff --git a/website/content/recipes/streaming-response.md b/website/content/recipes/streaming-response.md index 898c9b198..e9533526c 100644 --- a/website/content/recipes/streaming-response.md +++ b/website/content/recipes/streaming-response.md @@ -35,4 +35,4 @@ $ curl localhost:1323 - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/streaming-response) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/streaming-response) diff --git a/website/content/recipes/subdomains.md b/website/content/recipes/subdomains.md index f4647b0af..50b2a956a 100644 --- a/website/content/recipes/subdomains.md +++ b/website/content/recipes/subdomains.md @@ -15,4 +15,4 @@ menu: - [axdg](https://github.com/axdg) - [vishr](https://github.com/axdg) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/subdomains) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/subdomains) diff --git a/website/content/recipes/website.md b/website/content/recipes/website.md index b9894e1d8..2ea3e5b9f 100644 --- a/website/content/recipes/website.md +++ b/website/content/recipes/website.md @@ -22,4 +22,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/website) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/website) diff --git a/website/content/recipes/websocket.md b/website/content/recipes/websocket.md index bdd084bbe..03fa7a3d2 100644 --- a/website/content/recipes/websocket.md +++ b/website/content/recipes/websocket.md @@ -44,4 +44,4 @@ Hello, Server! - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/labstack/echo/blob/master/recipes/websocket) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/websocket) diff --git a/website/layouts/shortcodes/embed.html b/website/layouts/shortcodes/embed.html index 1c88e121f..9de428b2d 100644 --- a/website/layouts/shortcodes/embed.html +++ b/website/layouts/shortcodes/embed.html @@ -1,2 +1,2 @@ -
+
 
diff --git a/website/package.json b/website/package.json deleted file mode 100644 index 0967ef424..000000000 --- a/website/package.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/website/server.go b/website/server.go deleted file mode 100644 index 9327d3e6e..000000000 --- a/website/server.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "github.com/labstack/echo" - mw "github.com/labstack/echo/middleware" -) - -func main() { - e := echo.New() - e.Use(mw.Logger()) - e.Use(mw.Recover()) - e.Use(mw.Gzip()) - - e.Static("/", "public") - - e.Run(":80") -} From 4255f4bd4411f541ebcc76d6575af6ed35b3db1a Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 9 Jan 2016 10:34:34 -0800 Subject: [PATCH 05/67] Fixed test Signed-off-by: Vishal Rana --- _fixture/favicon.ico | Bin 0 -> 1150 bytes _fixture/folder/index.html | 9 +++++++++ {test/fixture => _fixture/images}/walle.png | Bin _fixture/index.html | 9 +++++++++ context_test.go | 4 ++-- echo_test.go | 21 ++++++++++---------- 6 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 _fixture/favicon.ico create mode 100644 _fixture/folder/index.html rename {test/fixture => _fixture/images}/walle.png (100%) create mode 100644 _fixture/index.html diff --git a/_fixture/favicon.ico b/_fixture/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d939ddca12aa14a2fa691e082b14436f18719f6b GIT binary patch literal 1150 zcmZQzU<5(|0R|wcz>vYhz#zuJz@P!dKp~(AL>x#lFaYI*xgi+L$0S%eIXJ|4d3e=$ zc=$9q*f})W*w{3AxVg1?dHFTCxVU71TG%nQ!9^s*C1e}r6xHtm@dI&j$+JSjqKD-a z)E)x)52d8#mN7Cgr~_3q!*xIzLZXr&7N@L&MvuI*?teKY?f(+eioe7p3-i zipeOb?_p!-lme;)8iNY#y}}th{6lyR9m5aFStkFNx6S&mWS;@V>Hn3T^ZqMa;8qR43_WoB7nfzbbr}e*9NZ)^>jyEcB5D~<+3`sc1>sGYKwp`v5j zgo^Gt|D*C+{(Hxj{P#>K{U4Ck^gq98>i?R)d1sp^&J}2!I2S|z%ALmmsy{F`jln-ARk5h5aYt9* zj16{yc^j0iVpbHkPBBa^s?yiCa9}le@x`haBp8{T%@C22>snl1`#mEv>3=|I+E;tu z_=n{M)i2vSC%z1cPj!k)%D|~VFfN0^CoYq}ptP + + + + Echo + + + + diff --git a/test/fixture/walle.png b/_fixture/images/walle.png similarity index 100% rename from test/fixture/walle.png rename to _fixture/images/walle.png diff --git a/_fixture/index.html b/_fixture/index.html new file mode 100644 index 000000000..9b07a7588 --- /dev/null +++ b/_fixture/index.html @@ -0,0 +1,9 @@ + + + + + Echo + + + + diff --git a/context_test.go b/context_test.go index 460c0d364..04f4ea8f9 100644 --- a/context_test.go +++ b/context_test.go @@ -194,7 +194,7 @@ func TestContext(t *testing.T) { // File rec = httptest.NewRecorder() c = NewContext(req, NewResponse(rec, e), e) - err = c.File("test/fixture/walle.png", "", false) + err = c.File("_fixture/images/walle.png", "", false) if assert.NoError(t, err) { assert.Equal(t, http.StatusOK, rec.Code) assert.Equal(t, 219885, rec.Body.Len()) @@ -203,7 +203,7 @@ func TestContext(t *testing.T) { // File as attachment rec = httptest.NewRecorder() c = NewContext(req, NewResponse(rec, e), e) - err = c.File("test/fixture/walle.png", "WALLE.PNG", true) + err = c.File("_fixture/images/walle.png", "WALLE.PNG", true) if assert.NoError(t, err) { assert.Equal(t, http.StatusOK, rec.Code) assert.Equal(t, rec.Header().Get(ContentDisposition), "attachment; filename=WALLE.PNG") diff --git a/echo_test.go b/echo_test.go index 7bba3d7a9..626e24d44 100644 --- a/echo_test.go +++ b/echo_test.go @@ -43,7 +43,7 @@ func TestEcho(t *testing.T) { func TestEchoIndex(t *testing.T) { e := New() - e.Index("recipes/website/public/index.html") + e.Index("_fixture/index.html") c, b := request(GET, "/", e) assert.Equal(t, http.StatusOK, c) assert.NotEmpty(t, b) @@ -51,7 +51,7 @@ func TestEchoIndex(t *testing.T) { func TestEchoFavicon(t *testing.T) { e := New() - e.Favicon("recipes/website/public/favicon.ico") + e.Favicon("_fixture/favicon.ico") c, b := request(GET, "/favicon.ico", e) assert.Equal(t, http.StatusOK, c) assert.NotEmpty(t, b) @@ -61,23 +61,23 @@ func TestEchoStatic(t *testing.T) { e := New() // OK - e.Static("/scripts", "recipes/website/public/scripts") - c, b := request(GET, "/scripts/main.js", e) + e.Static("/images", "_fixture/images") + c, b := request(GET, "/images/walle.png", e) assert.Equal(t, http.StatusOK, c) assert.NotEmpty(t, b) // No file - e.Static("/scripts", "recipes/website/public/scripts") - c, _ = request(GET, "/scripts/index.js", e) + e.Static("/images", "_fixture/scripts") + c, _ = request(GET, "/images/bolt.png", e) assert.Equal(t, http.StatusNotFound, c) // Directory - e.Static("/scripts", "recipes/website/public/scripts") - c, _ = request(GET, "/scripts", e) + e.Static("/images", "_fixture/images") + c, _ = request(GET, "/images", e) assert.Equal(t, http.StatusForbidden, c) // Directory with index.html - e.Static("/", "recipes/website/public") + e.Static("/", "_fixture") c, r := request(GET, "/", e) assert.Equal(t, http.StatusOK, c) assert.Equal(t, true, strings.HasPrefix(r, "")) @@ -85,7 +85,8 @@ func TestEchoStatic(t *testing.T) { // Sub-directory with index.html c, r = request(GET, "/folder", e) assert.Equal(t, http.StatusOK, c) - assert.Equal(t, "sub directory", r) + assert.Equal(t, true, strings.HasPrefix(r, "")) + // assert.Equal(t, "sub directory", r) } func TestEchoMiddleware(t *testing.T) { From ec83e2407f257c0fa7b5ee17727d175d9d6e9f1a Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 9 Jan 2016 10:34:34 -0800 Subject: [PATCH 06/67] Closed #319 Signed-off-by: Vishal Rana --- _fixture/favicon.ico | Bin 0 -> 1150 bytes _fixture/folder/index.html | 9 +++++++++ {test/fixture => _fixture/images}/walle.png | Bin _fixture/index.html | 9 +++++++++ context_test.go | 4 ++-- echo_test.go | 21 ++++++++++---------- group.go | 12 +++++++++++ group_test.go | 2 ++ 8 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 _fixture/favicon.ico create mode 100644 _fixture/folder/index.html rename {test/fixture => _fixture/images}/walle.png (100%) create mode 100644 _fixture/index.html diff --git a/_fixture/favicon.ico b/_fixture/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d939ddca12aa14a2fa691e082b14436f18719f6b GIT binary patch literal 1150 zcmZQzU<5(|0R|wcz>vYhz#zuJz@P!dKp~(AL>x#lFaYI*xgi+L$0S%eIXJ|4d3e=$ zc=$9q*f})W*w{3AxVg1?dHFTCxVU71TG%nQ!9^s*C1e}r6xHtm@dI&j$+JSjqKD-a z)E)x)52d8#mN7Cgr~_3q!*xIzLZXr&7N@L&MvuI*?teKY?f(+eioe7p3-i zipeOb?_p!-lme;)8iNY#y}}th{6lyR9m5aFStkFNx6S&mWS;@V>Hn3T^ZqMa;8qR43_WoB7nfzbbr}e*9NZ)^>jyEcB5D~<+3`sc1>sGYKwp`v5j zgo^Gt|D*C+{(Hxj{P#>K{U4Ck^gq98>i?R)d1sp^&J}2!I2S|z%ALmmsy{F`jln-ARk5h5aYt9* zj16{yc^j0iVpbHkPBBa^s?yiCa9}le@x`haBp8{T%@C22>snl1`#mEv>3=|I+E;tu z_=n{M)i2vSC%z1cPj!k)%D|~VFfN0^CoYq}ptP + + + + Echo + + + + diff --git a/test/fixture/walle.png b/_fixture/images/walle.png similarity index 100% rename from test/fixture/walle.png rename to _fixture/images/walle.png diff --git a/_fixture/index.html b/_fixture/index.html new file mode 100644 index 000000000..9b07a7588 --- /dev/null +++ b/_fixture/index.html @@ -0,0 +1,9 @@ + + + + + Echo + + + + diff --git a/context_test.go b/context_test.go index 460c0d364..04f4ea8f9 100644 --- a/context_test.go +++ b/context_test.go @@ -194,7 +194,7 @@ func TestContext(t *testing.T) { // File rec = httptest.NewRecorder() c = NewContext(req, NewResponse(rec, e), e) - err = c.File("test/fixture/walle.png", "", false) + err = c.File("_fixture/images/walle.png", "", false) if assert.NoError(t, err) { assert.Equal(t, http.StatusOK, rec.Code) assert.Equal(t, 219885, rec.Body.Len()) @@ -203,7 +203,7 @@ func TestContext(t *testing.T) { // File as attachment rec = httptest.NewRecorder() c = NewContext(req, NewResponse(rec, e), e) - err = c.File("test/fixture/walle.png", "WALLE.PNG", true) + err = c.File("_fixture/images/walle.png", "WALLE.PNG", true) if assert.NoError(t, err) { assert.Equal(t, http.StatusOK, rec.Code) assert.Equal(t, rec.Header().Get(ContentDisposition), "attachment; filename=WALLE.PNG") diff --git a/echo_test.go b/echo_test.go index 7bba3d7a9..626e24d44 100644 --- a/echo_test.go +++ b/echo_test.go @@ -43,7 +43,7 @@ func TestEcho(t *testing.T) { func TestEchoIndex(t *testing.T) { e := New() - e.Index("recipes/website/public/index.html") + e.Index("_fixture/index.html") c, b := request(GET, "/", e) assert.Equal(t, http.StatusOK, c) assert.NotEmpty(t, b) @@ -51,7 +51,7 @@ func TestEchoIndex(t *testing.T) { func TestEchoFavicon(t *testing.T) { e := New() - e.Favicon("recipes/website/public/favicon.ico") + e.Favicon("_fixture/favicon.ico") c, b := request(GET, "/favicon.ico", e) assert.Equal(t, http.StatusOK, c) assert.NotEmpty(t, b) @@ -61,23 +61,23 @@ func TestEchoStatic(t *testing.T) { e := New() // OK - e.Static("/scripts", "recipes/website/public/scripts") - c, b := request(GET, "/scripts/main.js", e) + e.Static("/images", "_fixture/images") + c, b := request(GET, "/images/walle.png", e) assert.Equal(t, http.StatusOK, c) assert.NotEmpty(t, b) // No file - e.Static("/scripts", "recipes/website/public/scripts") - c, _ = request(GET, "/scripts/index.js", e) + e.Static("/images", "_fixture/scripts") + c, _ = request(GET, "/images/bolt.png", e) assert.Equal(t, http.StatusNotFound, c) // Directory - e.Static("/scripts", "recipes/website/public/scripts") - c, _ = request(GET, "/scripts", e) + e.Static("/images", "_fixture/images") + c, _ = request(GET, "/images", e) assert.Equal(t, http.StatusForbidden, c) // Directory with index.html - e.Static("/", "recipes/website/public") + e.Static("/", "_fixture") c, r := request(GET, "/", e) assert.Equal(t, http.StatusOK, c) assert.Equal(t, true, strings.HasPrefix(r, "")) @@ -85,7 +85,8 @@ func TestEchoStatic(t *testing.T) { // Sub-directory with index.html c, r = request(GET, "/folder", e) assert.Equal(t, http.StatusOK, c) - assert.Equal(t, "sub directory", r) + assert.Equal(t, true, strings.HasPrefix(r, "")) + // assert.Equal(t, "sub directory", r) } func TestEchoMiddleware(t *testing.T) { diff --git a/group.go b/group.go index 856a33651..56effb9c8 100644 --- a/group.go +++ b/group.go @@ -48,6 +48,18 @@ func (g *Group) Trace(path string, h Handler) { g.echo.Trace(path, h) } +func (g *Group) Any(path string, h Handler) { + for _, m := range methods { + g.echo.add(m, path, h) + } +} + +func (g *Group) Match(methods []string, path string, h Handler) { + for _, m := range methods { + g.echo.add(m, path, h) + } +} + func (g *Group) WebSocket(path string, h HandlerFunc) { g.echo.WebSocket(path, h) } diff --git a/group_test.go b/group_test.go index f605993cc..d4eebb3fa 100644 --- a/group_test.go +++ b/group_test.go @@ -14,6 +14,8 @@ func TestGroup(t *testing.T) { g.Post("/", h) g.Put("/", h) g.Trace("/", h) + g.Any("/", h) + g.Match([]string{GET, POST}, "/", h) g.WebSocket("/ws", h) g.Static("/scripts", "scripts") g.ServeDir("/scripts", "scripts") From c67300bb30fb7e38d6aa734224348a68cc229f04 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Fri, 22 Jan 2016 13:19:34 -0800 Subject: [PATCH 07/67] Updated docs Signed-off-by: Vishal Rana --- echo.go | 2 +- website/content/guide/customization.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/echo.go b/echo.go index be6896953..ce4bb676d 100644 --- a/echo.go +++ b/echo.go @@ -232,7 +232,7 @@ func (e *Echo) SetLogPrefix(prefix string) { 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) { e.logger.SetOutput(w) } diff --git a/website/content/guide/customization.md b/website/content/guide/customization.md index f3ee75688..879d038d5 100644 --- a/website/content/guide/customization.md +++ b/website/content/guide/customization.md @@ -35,7 +35,7 @@ SetLogPrefix sets the prefix for the logger. Default value is `echo`. `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 From 106272e201241f4da16a73f0879439d4dc10d189 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Fri, 22 Jan 2016 13:37:18 -0800 Subject: [PATCH 08/67] Cleaned up http error handler #325 Signed-off-by: Vishal Rana --- echo.go | 40 +++++++++++++++------------------------- echo_test.go | 7 ------- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/echo.go b/echo.go index ce4bb676d..cc6827076 100644 --- a/echo.go +++ b/echo.go @@ -12,7 +12,6 @@ import ( "runtime" "strings" "sync" - "time" "encoding/xml" @@ -23,21 +22,19 @@ import ( type ( Echo struct { - prefix string - middleware []MiddlewareFunc - http2 bool - maxParam *int - notFoundHandler HandlerFunc - defaultHTTPErrorHandler HTTPErrorHandler - httpErrorHandler HTTPErrorHandler - binder Binder - renderer Renderer - pool sync.Pool - debug bool - hook http.HandlerFunc - autoIndex bool - logger *log.Logger - router *Router + prefix string + middleware []MiddlewareFunc + http2 bool + maxParam *int + httpErrorHandler HTTPErrorHandler + binder Binder + renderer Renderer + pool sync.Pool + debug bool + hook http.HandlerFunc + autoIndex bool + logger *log.Logger + router *Router } Route struct { @@ -180,8 +177,6 @@ var ( methodNotAllowedHandler = func(c *Context) error { return NewHTTPError(http.StatusMethodNotAllowed) } - - unixEpochTime = time.Unix(0, 0) ) // New creates an instance of Echo. @@ -197,7 +192,7 @@ func New() (e *Echo) { //---------- e.HTTP2(true) - e.defaultHTTPErrorHandler = func(err error, c *Context) { + defaultHTTPErrorHandler := func(err error, c *Context) { code := http.StatusInternalServerError msg := http.StatusText(code) if he, ok := err.(*HTTPError); ok { @@ -212,7 +207,7 @@ func New() (e *Echo) { } e.logger.Error(err) } - e.SetHTTPErrorHandler(e.defaultHTTPErrorHandler) + e.SetHTTPErrorHandler(defaultHTTPErrorHandler) e.SetBinder(&binder{}) // Logger @@ -252,11 +247,6 @@ func (e *Echo) HTTP2(on bool) { e.http2 = on } -// DefaultHTTPErrorHandler invokes the default HTTP error handler. -func (e *Echo) DefaultHTTPErrorHandler(err error, c *Context) { - e.defaultHTTPErrorHandler(err, c) -} - // SetHTTPErrorHandler registers a custom Echo.HTTPErrorHandler. func (e *Echo) SetHTTPErrorHandler(h HTTPErrorHandler) { e.httpErrorHandler = h diff --git a/echo_test.go b/echo_test.go index 626e24d44..4e44320c1 100644 --- a/echo_test.go +++ b/echo_test.go @@ -25,9 +25,6 @@ type ( func TestEcho(t *testing.T) { e := New() - req, _ := http.NewRequest(GET, "/", nil) - rec := httptest.NewRecorder() - c := NewContext(req, NewResponse(rec, e), e) // Router assert.NotNil(t, e.Router()) @@ -35,10 +32,6 @@ func TestEcho(t *testing.T) { // Debug e.SetDebug(true) assert.True(t, e.debug) - - // DefaultHTTPErrorHandler - e.DefaultHTTPErrorHandler(errors.New("error"), c) - assert.Equal(t, http.StatusInternalServerError, rec.Code) } func TestEchoIndex(t *testing.T) { From 5d70ff42fc19fcd063429f40ce047dd4f21d1d5b Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sun, 24 Jan 2016 19:45:53 -0800 Subject: [PATCH 09/67] Putting back DefaultHTTPErrorHandler Signed-off-by: Vishal Rana --- echo.go | 36 +++++++++++++++++++++--------------- echo_test.go | 7 +++++++ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/echo.go b/echo.go index cc6827076..63e27a58e 100644 --- a/echo.go +++ b/echo.go @@ -22,19 +22,20 @@ import ( type ( Echo struct { - prefix string - middleware []MiddlewareFunc - http2 bool - maxParam *int - httpErrorHandler HTTPErrorHandler - binder Binder - renderer Renderer - pool sync.Pool - debug bool - hook http.HandlerFunc - autoIndex bool - logger *log.Logger - router *Router + prefix string + middleware []MiddlewareFunc + http2 bool + maxParam *int + defaultHTTPErrorHandler HTTPErrorHandler + httpErrorHandler HTTPErrorHandler + binder Binder + renderer Renderer + pool sync.Pool + debug bool + hook http.HandlerFunc + autoIndex bool + logger *log.Logger + router *Router } Route struct { @@ -192,7 +193,7 @@ func New() (e *Echo) { //---------- e.HTTP2(true) - defaultHTTPErrorHandler := func(err error, c *Context) { + e.defaultHTTPErrorHandler = func(err error, c *Context) { code := http.StatusInternalServerError msg := http.StatusText(code) if he, ok := err.(*HTTPError); ok { @@ -207,7 +208,7 @@ func New() (e *Echo) { } e.logger.Error(err) } - e.SetHTTPErrorHandler(defaultHTTPErrorHandler) + e.SetHTTPErrorHandler(e.defaultHTTPErrorHandler) e.SetBinder(&binder{}) // Logger @@ -247,6 +248,11 @@ func (e *Echo) HTTP2(on bool) { e.http2 = on } +// DefaultHTTPErrorHandler invokes the default HTTP error handler. +func (e *Echo) DefaultHTTPErrorHandler(err error, c *Context) { + e.defaultHTTPErrorHandler(err, c) +} + // SetHTTPErrorHandler registers a custom Echo.HTTPErrorHandler. func (e *Echo) SetHTTPErrorHandler(h HTTPErrorHandler) { e.httpErrorHandler = h diff --git a/echo_test.go b/echo_test.go index 4e44320c1..626e24d44 100644 --- a/echo_test.go +++ b/echo_test.go @@ -25,6 +25,9 @@ type ( func TestEcho(t *testing.T) { e := New() + req, _ := http.NewRequest(GET, "/", nil) + rec := httptest.NewRecorder() + c := NewContext(req, NewResponse(rec, e), e) // Router assert.NotNil(t, e.Router()) @@ -32,6 +35,10 @@ func TestEcho(t *testing.T) { // Debug e.SetDebug(true) assert.True(t, e.debug) + + // DefaultHTTPErrorHandler + e.DefaultHTTPErrorHandler(errors.New("error"), c) + assert.Equal(t, http.StatusInternalServerError, rec.Code) } func TestEchoIndex(t *testing.T) { From a81670211f64a31cee96c177e799780a25fc6d5a Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Tue, 26 Jan 2016 22:03:01 +0400 Subject: [PATCH 10/67] Fix serving static files on windows. See https://golang.org/pkg/net/http/#Dir.Open --- echo.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/echo.go b/echo.go index 63e27a58e..51d209f69 100644 --- a/echo.go +++ b/echo.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net/http" + "path" "path/filepath" "reflect" "runtime" @@ -429,7 +430,7 @@ func (e *Echo) serveFile(dir, file string, c *Context) (err error) { d := f // Index file - file = filepath.Join(file, indexPage) + file = path.Join(file, indexPage) f, err = fs.Open(file) if err != nil { if e.autoIndex { From d8e3467827d9952918f8095834952e9c5efa1761 Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Tue, 26 Jan 2016 22:58:17 +0400 Subject: [PATCH 11/67] fix websocket test on windows --- echo_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/echo_test.go b/echo_test.go index 626e24d44..fe4344d76 100644 --- a/echo_test.go +++ b/echo_test.go @@ -274,7 +274,7 @@ func TestEchoWebSocket(t *testing.T) { url := fmt.Sprintf("ws://%s/ws", addr) ws, err := websocket.Dial(url, "", origin) if assert.NoError(t, err) { - ws.Write([]byte("test")) + ws.Write([]byte("test\n")) defer ws.Close() buf := new(bytes.Buffer) buf.ReadFrom(ws) From 4cb8421b734ff62438fa5002cd5a829871c664da Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Fri, 29 Jan 2016 14:22:18 +0400 Subject: [PATCH 12/67] Change context.Bind() return type to HTTPError #344 --- context_test.go | 35 ++++++++++++++++++++++++++++------- echo.go | 11 ++++++++--- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/context_test.go b/context_test.go index 04f4ea8f9..622ca62da 100644 --- a/context_test.go +++ b/context_test.go @@ -34,6 +34,7 @@ func TestContext(t *testing.T) { userJSONIndent := "{\n_?\"id\": \"1\",\n_?\"name\": \"Joe\"\n_}" userXML := `1Joe` userXMLIndent := "_\n_?1\n_?Joe\n_" + incorrectContent := "this is incorrect content" var nonMarshallableChannel chan bool @@ -68,14 +69,18 @@ func TestContext(t *testing.T) { //------ // JSON - testBind(t, c, "application/json") + testBindOk(t, c, ApplicationJSON) + c.request, _ = http.NewRequest(POST, "/", strings.NewReader(incorrectContent)) + testBindError(t, c, ApplicationJSON) // XML c.request, _ = http.NewRequest(POST, "/", strings.NewReader(userXML)) - testBind(t, c, ApplicationXML) + testBindOk(t, c, ApplicationXML) + c.request, _ = http.NewRequest(POST, "/", strings.NewReader(incorrectContent)) + testBindError(t, c, ApplicationXML) // Unsupported - testBind(t, c, "") + testBindError(t, c, "") //-------- // Render @@ -280,14 +285,30 @@ func TestContextNetContext(t *testing.T) { assert.Equal(t, "val", c.Value("key")) } -func testBind(t *testing.T, c *Context, ct string) { +func testBindOk(t *testing.T, c *Context, ct string) { c.request.Header.Set(ContentType, ct) u := new(user) err := c.Bind(u) - if ct == "" { - assert.Error(t, UnsupportedMediaType) - } else if assert.NoError(t, err) { + if assert.NoError(t, err) { assert.Equal(t, "1", u.ID) assert.Equal(t, "Joe", u.Name) } } + +func testBindError(t *testing.T, c *Context, ct string) { + c.request.Header.Set(ContentType, ct) + u := new(user) + err := c.Bind(u) + + switch ct { + case ApplicationJSON, ApplicationXML: + if assert.IsType(t, new(HTTPError), err) { + assert.Equal(t, http.StatusBadRequest, err.(*HTTPError).code) + } + default: + if assert.IsType(t, new(HTTPError), err) { + assert.Equal(t, UnsupportedMediaType, err) + } + + } +} diff --git a/echo.go b/echo.go index 51d209f69..fa512796b 100644 --- a/echo.go +++ b/echo.go @@ -164,7 +164,7 @@ var ( // Errors //-------- - UnsupportedMediaType = errors.New("unsupported media type") + UnsupportedMediaType = NewHTTPError(http.StatusUnsupportedMediaType) RendererNotRegistered = errors.New("renderer not registered") InvalidRedirectCode = errors.New("invalid redirect status code") @@ -693,9 +693,14 @@ func (binder) Bind(r *http.Request, i interface{}) (err error) { ct := r.Header.Get(ContentType) err = UnsupportedMediaType if strings.HasPrefix(ct, ApplicationJSON) { - err = json.NewDecoder(r.Body).Decode(i) + if err = json.NewDecoder(r.Body).Decode(i); err != nil { + err = NewHTTPError(http.StatusBadRequest, err.Error()) + } } else if strings.HasPrefix(ct, ApplicationXML) { - err = xml.NewDecoder(r.Body).Decode(i) + if err = xml.NewDecoder(r.Body).Decode(i); err != nil { + err = NewHTTPError(http.StatusBadRequest, err.Error()) + } + } return } From e9808b69b4ef3e3188eb6085fa578efb7f152354 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:06:20 -0800 Subject: [PATCH 13/67] license update, some .gitattributes and .gitignore expansion, .travis.yml expansion, golint fixes and .godir for heroku --- .gitattributes | 16 ++++++------ .gitignore | 41 +++++++++++++++++++++++++----- .godir | 1 + .travis.yml | 44 +++++++++++++++++++++++++------- LICENSE | 2 +- echo.go | 28 ++++++++++++++------- group.go | 31 +++++++++++++++++++---- middleware/auth.go | 10 +++++--- middleware/logger.go | 5 +++- response.go | 60 ++++++++++++++++++++++++++++++++------------ router.go | 13 ++++++++++ 11 files changed, 193 insertions(+), 58 deletions(-) create mode 100644 .godir diff --git a/.gitattributes b/.gitattributes index 178af8637..591a6897c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,19 +2,21 @@ # http://git-scm.com/docs/gitattributes#_end_of_line_conversion * text=auto -# For the following file types, normalize line endings to LF on checking and +# For the following file types, normalize line endings to LF on checkin and # prevent conversion to CRLF when they are checked out (this is required in -# order to prevent newline related issues) -.* text eol=lf +# order) to prevent newline related issues) +.* text eolf=lf +*.css text eol=lf *.go text eol=lf -*.yml text eol=lf *.html text eol=lf -*.css text eol=lf *.js text eol=lf *.json text eol=lf +*.md text eol=lf +*.yml text eol=lf +*.yaml text eol=lf LICENSE text eol=lf -# Exclude `website` and `recipes` from Github's language statistics +# Exclude documentation-related directories from Github's language statistics # https://github.com/github/linguist#using-gitattributes -recipes/* linguist-documentation +_fixture/* linguist-documentation website/* linguist-documentation diff --git a/.gitignore b/.gitignore index a66a5e3b5..d9fd17d0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,42 @@ -# Website +# gitignore - Specifies intentionally untracked files to ignore +# http://git-scm.com/docs/gitignore + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +# submodule properties +.gitmodules + +# compiled web files website/public website/make website/Makefile website/marathon* -.gitmodules -# Node.js +# node.js web dependencies node_modules -# IntelliJ -.idea -*.iml +# code coverage output files +*.coverprofile diff --git a/.godir b/.godir new file mode 100644 index 000000000..37aac7c12 --- /dev/null +++ b/.godir @@ -0,0 +1 @@ +github.com/labstack/echo diff --git a/.travis.yml b/.travis.yml index 084ec7918..7b70c96b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,39 @@ language: go +sudo: false + go: - - 1.4 - - tip + - 1.4 + - 1.5 + - 1.6rc1 + - tip +env: + global: + - GO15VENDOREXPERIMENT=1 + before_install: - - go get github.com/modocache/gover - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover + - export $PATH = $PATH:$GOPATH/bin + - go get golang.org/x/tools/cmd/vet + - go get golang.org/x/tools/cmd/cover + - go get github.com/modocache/gover + - go get github.com/mattn/goveralls + +install: + - go get -t -v ./... + script: - - go test -coverprofile=echo.coverprofile - - go test -coverprofile=middleware.coverprofile ./middleware - - $HOME/gopath/bin/gover - - $HOME/gopath/bin/goveralls -coverprofile=gover.coverprofile -service=travis-ci + - go vet ./... + - go test -v -race ./... + - diff -u <(echo -n) <(gofmt -d -s .) + - go test -v -coverprofile=echo.coverprofile + - go test -v -coverprofile=middleware.coverprofile ./middleware + - gover + - goveralls -coverprofile=gover.coverprofile -service=travis-ci + +notifications: + email: + on_success: change + on_failure: always + +matrix: + allow_failures: + - go: tip diff --git a/LICENSE b/LICENSE index a14f926e5..00d0c1812 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 LabStack +Copyright (c) 2016 LabStack Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/echo.go b/echo.go index 51d209f69..b67e5449a 100644 --- a/echo.go +++ b/echo.go @@ -3,6 +3,7 @@ package echo import ( "bytes" "encoding/json" + "encoding/xml" "errors" "fmt" "io" @@ -14,14 +15,13 @@ import ( "strings" "sync" - "encoding/xml" - "github.com/labstack/gommon/log" "golang.org/x/net/http2" "golang.org/x/net/websocket" ) type ( + // Echo is the top-level framework instance. Echo struct { prefix string middleware []MiddlewareFunc @@ -39,21 +39,30 @@ type ( router *Router } + // Route contains a handler and information for matching against requests. Route struct { Method string Path string Handler Handler } + // HTTPError represents an error that occured while handling a request. HTTPError struct { code int message string } - Middleware interface{} + // Middleware ... + Middleware interface{} + + // MiddlewareFunc ... MiddlewareFunc func(HandlerFunc) HandlerFunc - Handler interface{} - HandlerFunc func(*Context) error + + // Handler ... + Handler interface{} + + // HandlerFunc ... + HandlerFunc func(*Context) error // HTTPErrorHandler is a centralized HTTP error handler. HTTPErrorHandler func(error, *Context) @@ -164,9 +173,9 @@ var ( // Errors //-------- - UnsupportedMediaType = errors.New("unsupported media type") - RendererNotRegistered = errors.New("renderer not registered") - InvalidRedirectCode = errors.New("invalid redirect status code") + ErrUnsupportedMediaType = errors.New("unsupported media type") + ErrRendererNotRegistered = errors.New("renderer not registered") + ErrInvalidRedirectCode = errors.New("invalid redirect status code") //---------------- // Error handlers @@ -588,6 +597,7 @@ func (e *Echo) run(s *http.Server, files ...string) { } } +// NewHTTPError creates a new HTTPError instance. func NewHTTPError(code int, msg ...string) *HTTPError { he := &HTTPError{code: code, message: http.StatusText(code)} if len(msg) > 0 { @@ -691,7 +701,7 @@ func wrapHandler(h Handler) HandlerFunc { func (binder) Bind(r *http.Request, i interface{}) (err error) { ct := r.Header.Get(ContentType) - err = UnsupportedMediaType + err = ErrUnsupportedMediaType if strings.HasPrefix(ct, ApplicationJSON) { err = json.NewDecoder(r.Body).Decode(i) } else if strings.HasPrefix(ct, ApplicationXML) { diff --git a/group.go b/group.go index 56effb9c8..2d5240b80 100644 --- a/group.go +++ b/group.go @@ -1,81 +1,102 @@ package echo -type ( - Group struct { - echo Echo - } -) +// Group is a set of subroutes for a specified route. It can be used for inner +// routes that share a common middlware or functionality that should be separate +// from the parent echo instance while still inheriting from it. +type Group struct { + echo Echo +} +// Use implements the echo.Use interface for subroutes within the Group. func (g *Group) Use(m ...Middleware) { for _, h := range m { g.echo.middleware = append(g.echo.middleware, wrapMiddleware(h)) } } +// Connect implements the echo.Connect interface for subroutes within the Group. func (g *Group) Connect(path string, h Handler) { g.echo.Connect(path, h) } +// Delete implements the echo.Delete interface for subroutes within the Group. func (g *Group) Delete(path string, h Handler) { g.echo.Delete(path, h) } +// Get implements the echo.Get interface for subroutes within the Group. func (g *Group) Get(path string, h Handler) { g.echo.Get(path, h) } +// Head implements the echo.Head interface for subroutes within the Group. func (g *Group) Head(path string, h Handler) { g.echo.Head(path, h) } +// Options implements the echo.Options interface for subroutes within the Group. func (g *Group) Options(path string, h Handler) { g.echo.Options(path, h) } +// Patch implements the echo.Patch interface for subroutes within the Group. func (g *Group) Patch(path string, h Handler) { g.echo.Patch(path, h) } +// Post implements the echo.Post interface for subroutes within the Group. func (g *Group) Post(path string, h Handler) { g.echo.Post(path, h) } +// Put implements the echo.Put interface for subroutes within the Group. func (g *Group) Put(path string, h Handler) { g.echo.Put(path, h) } +// Trace implements the echo.Trace interface for subroutes within the Group. func (g *Group) Trace(path string, h Handler) { g.echo.Trace(path, h) } +// Any implements the echo.Any interface for subroutes within the Group. func (g *Group) Any(path string, h Handler) { for _, m := range methods { g.echo.add(m, path, h) } } +// Match implements the echo.Match interface for subroutes within the Group. func (g *Group) Match(methods []string, path string, h Handler) { for _, m := range methods { g.echo.add(m, path, h) } } +// WebSocket implements the echo.WebSocket interface for subroutes within the +// Group. func (g *Group) WebSocket(path string, h HandlerFunc) { g.echo.WebSocket(path, h) } +// Static implements the echo.Static interface for subroutes within the Group. func (g *Group) Static(path, root string) { g.echo.Static(path, root) } +// ServeDir implements the echo.ServeDir interface for subroutes within the +// Group. func (g *Group) ServeDir(path, root string) { g.echo.ServeDir(path, root) } +// ServeFile implements the echo.ServeFile interface for subroutes within the +// Group. func (g *Group) ServeFile(path, file string) { g.echo.ServeFile(path, file) } +// Group implements the echo.Group interface for subroutes within the Group. func (g *Group) Group(prefix string, m ...Middleware) *Group { return g.echo.Group(prefix, m...) } diff --git a/middleware/auth.go b/middleware/auth.go index 23c494c57..1b864df36 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -8,17 +8,19 @@ import ( ) type ( + // BasicValidateFunc is the expected format a BasicAuth fn argument is + // expected to implement. BasicValidateFunc func(string, string) bool ) const ( + // Basic is the authentication scheme implemented by the middleware. Basic = "Basic" ) -// BasicAuth returns an HTTP basic authentication middleware. -// -// For valid credentials it calls the next handler. -// For invalid credentials, it sends "401 - Unauthorized" response. +// BasicAuth returns a HTTP basic authentication middleware. +// For valid credentials, it calls the next handler. +// For invalid credentials, it returns a "401 Unauthorized" HTTP error. func BasicAuth(fn BasicValidateFunc) echo.HandlerFunc { return func(c *echo.Context) error { // Skip WebSocket diff --git a/middleware/logger.go b/middleware/logger.go index 9b88980cf..88c1d0a78 100644 --- a/middleware/logger.go +++ b/middleware/logger.go @@ -8,6 +8,9 @@ import ( "github.com/labstack/gommon/color" ) +const loggerFormat = "%s %s %s %s %s %d" + +// Logger returns a Middleware that logs requests. func Logger() echo.MiddlewareFunc { return func(h echo.HandlerFunc) echo.HandlerFunc { return func(c *echo.Context) error { @@ -47,7 +50,7 @@ func Logger() echo.MiddlewareFunc { code = color.Cyan(n) } - logger.Info("%s %s %s %s %s %d", remoteAddr, method, path, code, stop.Sub(start), size) + logger.Info(loggerFormat, remoteAddr, method, path, code, stop.Sub(start), size) return nil } } diff --git a/response.go b/response.go index 1e43df9e3..a40bd48e7 100644 --- a/response.go +++ b/response.go @@ -6,32 +6,46 @@ import ( "net/http" ) -type ( - Response struct { - writer http.ResponseWriter - status int - size int64 - committed bool - echo *Echo - } -) +// Response wraps an http.ResponseWriter and implements its interface to be used +// by an HTTP handler to construct an HTTP response. +// See [http.ResponseWriter](https://golang.org/pkg/net/http/#ResponseWriter) +type Response struct { + writer http.ResponseWriter + status int + size int64 + committed bool + echo *Echo +} +// NewResponse creates a new instance of Response. func NewResponse(w http.ResponseWriter, e *Echo) *Response { return &Response{writer: w, echo: e} } +// SetWriter sets the http.ResponseWriter instance for this Response. func (r *Response) SetWriter(w http.ResponseWriter) { r.writer = w } -func (r *Response) Header() http.Header { - return r.writer.Header() -} - +// Writer returns the http.ResponseWriter instance for this Response. func (r *Response) Writer() http.ResponseWriter { return r.writer } +// Header returns the header map for the writer that will be sent by +// WriteHeader. Changing the header after a call to WriteHeader (or Write) has +// no effect unless the modified headers were declared as trailers by setting +// the "Trailer" header before the call to WriteHeader (see example) +// To suppress implicit response headers, set their value to nil. +// Example [ResponseWriter.Trailers](https://golang.org/pkg/net/http/#example_ResponseWriter_trailers) +func (r *Response) Header() http.Header { + return r.writer.Header() +} + +// WriteHeader sends an HTTP response header with status code. If WriteHeader is +// not called explicitly, the first call to Write will trigger an implicit +// WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly +// used to send error codes. func (r *Response) WriteHeader(code int) { if r.committed { r.echo.Logger().Warn("response already committed") @@ -42,35 +56,49 @@ func (r *Response) WriteHeader(code int) { r.committed = true } +// Write wraps and implements the http.Response.Write specification. +// Additionally, Write will increment the size of the current response. +// See [http.Response.Write](https://golang.org/pkg/net/http/#Response.Write) func (r *Response) Write(b []byte) (n int, err error) { n, err = r.writer.Write(b) r.size += int64(n) return n, err } -// Flush wraps response writer's Flush function. +// Flush implements the http.Flusher interface to allow an HTTP handler to flush +// buffered data to the client. +// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher) func (r *Response) Flush() { r.writer.(http.Flusher).Flush() } -// Hijack wraps response writer's Hijack function. +// Hijack implements the http.Hijacker interface to allow an HTTP handler to +// take over the connection. +// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker) func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) { return r.writer.(http.Hijacker).Hijack() } -// CloseNotify wraps response writer's CloseNotify function. +// CloseNotify implements the http.CloseNotifier interface to allow detecting +// when the underlying connection has gone away. +// This mechanism can be used to cancel long operations on the server if the +// client has disconnected before the response is ready. +// See [http.CloseNotifier](https://golang.org/pkg/net/http/#CloseNotifier) func (r *Response) CloseNotify() <-chan bool { return r.writer.(http.CloseNotifier).CloseNotify() } +// Status returns the HTTP status code of the response. func (r *Response) Status() int { return r.status } +// Size returns the current size, in bytes, of the response. func (r *Response) Size() int64 { return r.size } +// Committed asserts whether or not the response has been committed to. func (r *Response) Committed() bool { return r.committed } diff --git a/router.go b/router.go index a3bba24b2..42a056631 100644 --- a/router.go +++ b/router.go @@ -3,6 +3,12 @@ package echo import "net/http" type ( + + // Router is the registry of all registered routes for an Echo instance for + // request matching and handler dispatching. + // + // Router implements the http.Handler specification and can be registered + // to serve requests. Router struct { tree *node routes []Route @@ -40,6 +46,7 @@ const ( mkind ) +// NewRouter returns a new Router instance. func NewRouter(e *Echo) *Router { return &Router{ tree: &node{ @@ -50,6 +57,7 @@ func NewRouter(e *Echo) *Router { } } +// Add registers a new route with a matcher for the URL path. func (r *Router) Add(method, path string, h HandlerFunc, e *Echo) { ppath := path // Pristine path pnames := []string{} // Param names @@ -275,6 +283,8 @@ func (n *node) check405() HandlerFunc { return notFoundHandler } +// Find dispatches the request to the handler whos route is matched with the +// specified request path. func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo) { h = notFoundHandler e = r.echo @@ -400,6 +410,9 @@ End: return } +// ServeHTTP implements the Handler interface and can be registered to serve a +// particular path or subtree in an HTTP server. +// See Router.Find() func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { c := r.echo.pool.Get().(*Context) h, _ := r.Find(req.Method, req.URL.Path, c) From 9799f5fb80792a1c338ef7c7a6114a5eed96acd0 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:08:29 -0800 Subject: [PATCH 14/67] typo --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 591a6897c..2a7bb5c15 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,7 +5,7 @@ # For the following file types, normalize line endings to LF on checkin and # prevent conversion to CRLF when they are checked out (this is required in # order) to prevent newline related issues) -.* text eolf=lf +.* text eol=lf *.css text eol=lf *.go text eol=lf *.html text eol=lf From 46fd0365f661308f40183dc79a5f256309aae424 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:17:39 -0800 Subject: [PATCH 15/67] fixing typo for path export --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7b70c96b8..c9be89477 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ env: - GO15VENDOREXPERIMENT=1 before_install: - - export $PATH = $PATH:$GOPATH/bin + - export PATH=$PATH:$GOPATH/bin - go get golang.org/x/tools/cmd/vet - go get golang.org/x/tools/cmd/cover - go get github.com/modocache/gover From 58edee2270b838272e885c10353d8c6c927c9c3c Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:19:07 -0800 Subject: [PATCH 16/67] adding uncommitted context changes --- context.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/context.go b/context.go index b1ded8931..b49623739 100644 --- a/context.go +++ b/context.go @@ -120,7 +120,7 @@ func (c *Context) Bind(i interface{}) error { // code. Templates can be registered using `Echo.SetRenderer()`. func (c *Context) Render(code int, name string, data interface{}) (err error) { if c.echo.renderer == nil { - return RendererNotRegistered + return ErrRendererNotRegistered } buf := new(bytes.Buffer) if err = c.echo.renderer.Render(buf, name, data); err != nil { @@ -244,7 +244,7 @@ func (c *Context) NoContent(code int) error { // Redirect redirects the request using http.Redirect with status code. func (c *Context) Redirect(code int, url string) error { if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect { - return InvalidRedirectCode + return ErrInvalidRedirectCode } http.Redirect(c.response, c.request, url, code) return nil From 4ad737c418bea86590248cb62c2b46b97e6f5cc5 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:19:44 -0800 Subject: [PATCH 17/67] additional missing file save --- context_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context_test.go b/context_test.go index 04f4ea8f9..1185496fe 100644 --- a/context_test.go +++ b/context_test.go @@ -285,7 +285,7 @@ func testBind(t *testing.T, c *Context, ct string) { u := new(user) err := c.Bind(u) if ct == "" { - assert.Error(t, UnsupportedMediaType) + assert.Error(t, ErrUnsupportedMediaType) } else if assert.NoError(t, err) { assert.Equal(t, "1", u.ID) assert.Equal(t, "Joe", u.Name) From be8a2212d88dac5e16ee69d81918eaed31b06ae4 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:31:34 -0800 Subject: [PATCH 18/67] adding tests for setting log output and prefix to make coveralls happy --- echo_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/echo_test.go b/echo_test.go index fe4344d76..84d523098 100644 --- a/echo_test.go +++ b/echo_test.go @@ -1,6 +1,7 @@ package echo import ( + "bufio" "bytes" "fmt" "net/http" @@ -41,6 +42,20 @@ func TestEcho(t *testing.T) { assert.Equal(t, http.StatusInternalServerError, rec.Code) } +func TestLogger(t *testing.T) { + prefix := "extremely-long-prefix-string-that-wont-exist" + e := New() + + var b bytes.Buffer + out := bufio.NewWriter(&b) + + e.logger.SetPrefix(prefix) + e.logger.SetOutput(out) + e.logger.Print("test") + + assert.Contains(t, "extremely-long-prefix-string", b.String()) +} + func TestEchoIndex(t *testing.T) { e := New() e.Index("_fixture/index.html") From 857fb3761d06f3f0813eb1bf43501335c9fb44c2 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:34:40 -0800 Subject: [PATCH 19/67] reusing variables to retry travis due to failure of coveralls from a travis bug --- echo_test.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/echo_test.go b/echo_test.go index 84d523098..8a95cc06c 100644 --- a/echo_test.go +++ b/echo_test.go @@ -44,16 +44,21 @@ func TestEcho(t *testing.T) { func TestLogger(t *testing.T) { prefix := "extremely-long-prefix-string-that-wont-exist" + logmsg := "test-log-message" + e := New() var b bytes.Buffer - out := bufio.NewWriter(&b) + writer := bufio.NewWriter(&b) e.logger.SetPrefix(prefix) - e.logger.SetOutput(out) - e.logger.Print("test") + e.logger.SetOutput(writer) + e.logger.Print(logmsg) + + output := b.String() - assert.Contains(t, "extremely-long-prefix-string", b.String()) + assert.Contains(t, prefix, output) + assert.Contains(t, logmsg, output) } func TestEchoIndex(t *testing.T) { From ad525c22a0a4fe5606535241cbc21e7904d01363 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:40:24 -0800 Subject: [PATCH 20/67] removing test logger as it actually doesnt help us at all --- echo_test.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/echo_test.go b/echo_test.go index 8a95cc06c..fe4344d76 100644 --- a/echo_test.go +++ b/echo_test.go @@ -1,7 +1,6 @@ package echo import ( - "bufio" "bytes" "fmt" "net/http" @@ -42,25 +41,6 @@ func TestEcho(t *testing.T) { assert.Equal(t, http.StatusInternalServerError, rec.Code) } -func TestLogger(t *testing.T) { - prefix := "extremely-long-prefix-string-that-wont-exist" - logmsg := "test-log-message" - - e := New() - - var b bytes.Buffer - writer := bufio.NewWriter(&b) - - e.logger.SetPrefix(prefix) - e.logger.SetOutput(writer) - e.logger.Print(logmsg) - - output := b.String() - - assert.Contains(t, prefix, output) - assert.Contains(t, logmsg, output) -} - func TestEchoIndex(t *testing.T) { e := New() e.Index("_fixture/index.html") From 6c296681684608aad04fd1a68314c0467fa27674 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:42:16 -0800 Subject: [PATCH 21/67] adding testing for c.store nil --- context_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/context_test.go b/context_test.go index 1185496fe..157f09452 100644 --- a/context_test.go +++ b/context_test.go @@ -229,6 +229,10 @@ func TestContext(t *testing.T) { // reset c.reset(req, NewResponse(httptest.NewRecorder(), e), e) + + // after reset (nil store) set test + c.Set("user", "Joe") + assert.Equal(t, "Joe", c.Get("user")) } func TestContextPath(t *testing.T) { From 46c74807088aa599f4d78107530180857c0a36da Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:43:55 -0800 Subject: [PATCH 22/67] adding nil context.Echo testing --- context_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/context_test.go b/context_test.go index 157f09452..9ce16e377 100644 --- a/context_test.go +++ b/context_test.go @@ -284,6 +284,13 @@ func TestContextNetContext(t *testing.T) { assert.Equal(t, "val", c.Value("key")) } +func TestContextEcho(t *testing.T) { + c := new(Context) + + // Should be null when initialized without one + assert.Nil(t, c.Echo()) +} + func testBind(t *testing.T, c *Context, ct string) { c.request.Header.Set(ContentType, ct) u := new(user) From 7c5c9c30d6ab9e9fe2d05caad2fa189f5397fc9c Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 04:57:47 -0800 Subject: [PATCH 23/67] fixing typo in gitattributes --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 2a7bb5c15..c840c5a65 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,7 +4,7 @@ # For the following file types, normalize line endings to LF on checkin and # prevent conversion to CRLF when they are checked out (this is required in -# order) to prevent newline related issues) +# order to prevent newline related issues) .* text eol=lf *.css text eol=lf *.go text eol=lf From 5940691448d402c6647fd9a3c0c941cb38dc7439 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 06:10:39 -0800 Subject: [PATCH 24/67] removing extra newline --- LICENSE | 1 - 1 file changed, 1 deletion(-) diff --git a/LICENSE b/LICENSE index 00d0c1812..f36474939 100644 --- a/LICENSE +++ b/LICENSE @@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - From ad46da8f772de3a45b8f30fb3df5bf51080893dd Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Fri, 29 Jan 2016 06:42:28 -0800 Subject: [PATCH 25/67] adding godoc introduction --- echo.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/echo.go b/echo.go index b67e5449a..1f21863b2 100644 --- a/echo.go +++ b/echo.go @@ -1,3 +1,34 @@ +/* +Package echo implements a fast and unfancy micro web framework for Go. + +Example: + + package main + + import ( + "net/http" + + "github.com/labstack/echo" + mw "github.com/labstack/echo/middleware" + ) + + func hello(c *echo.Context) error { + return c.String(http.StatusOK, "Hello, World!\n") + } + + func main() { + e := echo.New() + + e.Use(mw.Logger()) + e.Use(mw.Recover()) + + e.Get("/", hello) + + e.Run(":1323") + } + +Learn more at https://labstack.com/echo +*/ package echo import ( From 6c320ca50bce63a167763e19f2515331e39cd4c5 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 30 Jan 2016 10:05:17 -0800 Subject: [PATCH 26/67] Glide for dependency mgmt Signed-off-by: Vishal Rana --- .gitignore | 4 +++- middleware/logger.go | 6 ++++-- website/config.json | 2 +- website/content/index.md | 2 +- website/layouts/partials/header.html | 6 +++--- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index d9fd17d0d..0890611cb 100644 --- a/.gitignore +++ b/.gitignore @@ -33,10 +33,12 @@ _testmain.go website/public website/make website/Makefile -website/marathon* # node.js web dependencies node_modules # code coverage output files *.coverprofile + +# glide +vendor diff --git a/middleware/logger.go b/middleware/logger.go index 88c1d0a78..8aa6f52cd 100644 --- a/middleware/logger.go +++ b/middleware/logger.go @@ -8,7 +8,9 @@ import ( "github.com/labstack/gommon/color" ) -const loggerFormat = "%s %s %s %s %s %d" +const ( + format = "%s %s %s %s %s %d" +) // Logger returns a Middleware that logs requests. func Logger() echo.MiddlewareFunc { @@ -50,7 +52,7 @@ func Logger() echo.MiddlewareFunc { code = color.Cyan(n) } - logger.Info(loggerFormat, remoteAddr, method, path, code, stop.Sub(start), size) + logger.Infof(format, remoteAddr, method, path, code, stop.Sub(start), size) return nil } } diff --git a/website/config.json b/website/config.json index 17a1302f5..ab6d64eee 100644 --- a/website/config.json +++ b/website/config.json @@ -1,5 +1,5 @@ { - "baseurl": "http://labstack.com/echo", + "baseurl": "https://labstack.com/echo", "languageCode": "en-us", "title": "Echo", "canonifyurls": true, diff --git a/website/content/index.md b/website/content/index.md index e9d0b229f..e8b1c64d5 100644 --- a/website/content/index.md +++ b/website/content/index.md @@ -2,7 +2,7 @@ title: Index --- -# Echo +# ![Echo](/images/echo.svg) Echo A fast and unfancy micro web framework for Go. diff --git a/website/layouts/partials/header.html b/website/layouts/partials/header.html index 66789ac03..82169092a 100644 --- a/website/layouts/partials/header.html +++ b/website/layouts/partials/header.html @@ -1,12 +1,12 @@
From 96c6f17ed6e15041b0c2d8c4d0c5ce601da53511 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 30 Jan 2016 11:26:45 -0800 Subject: [PATCH 27/67] Update README.md --- README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c44ab7a7..b6000c570 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,23 @@ $ go get github.com/labstack/echo ## Echo System -Community created packages for Echo +### Who's using Echo? + +- [ShowChampions](https://showchampions.photoserve.co) +- [deferpanic](https://deferpanic.com) +- [Center for Open Science](https://cos.io) +- [SeeSaw Labs](http://www.seesawlabs.com) +- [Kyäni](http://www.kyani.net) +- [Carrot Creative](http://carrot.is) +- [EurekaMetrics](http://eurekametrics.com) +- [Coursella](https://www.coursella.com) +- [blue Vanilla](https://www.bleuvanille.fr) +- [ImPlaces](http://www.implaces.com) +- [Gomoku](http://gomoku.thoughtsfromplac.es) +- [DrinkIn](https://drinkin.com) +- [PodBaby](https://podbaby.me) + +### Community created packages around Echo - [echo-logrus](https://github.com/deoxxa/echo-logrus) - [go_middleware](https://github.com/rightscale/go_middleware) @@ -102,6 +118,9 @@ Community created packages for Echo - [echo-middleware](https://github.com/syntaqx/echo-middleware) - [dpecho](https://github.com/deferpanic/dpecho) - [echosentry](https://github.com/01walid/echosentry) +- [go-starter-kit](https://github.com/olebedev/go-starter-kit) + +[Want to get listed?](https://github.com/labstack/echo/issues/295) ## Contribute From f18418cf32acea54d6728160a28a1f9b9285e1ae Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 30 Jan 2016 11:31:19 -0800 Subject: [PATCH 28/67] Update index.md --- website/content/index.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/website/content/index.md b/website/content/index.md index e8b1c64d5..bf95bb96a 100644 --- a/website/content/index.md +++ b/website/content/index.md @@ -51,6 +51,37 @@ A fast and unfancy micro web framework for Go. +## Echo System + +### Who's using Echo? + +- [ShowChampions](https://showchampions.photoserve.co) +- [deferpanic](https://deferpanic.com) +- [Center for Open Science](https://cos.io) +- [SeeSaw Labs](http://www.seesawlabs.com) +- [Kyäni](http://www.kyani.net) +- [Carrot Creative](http://carrot.is) +- [EurekaMetrics](http://eurekametrics.com) +- [Coursella](https://www.coursella.com) +- [blue Vanilla](https://www.bleuvanille.fr) +- [ImPlaces](http://www.implaces.com) +- [Gomoku](http://gomoku.thoughtsfromplac.es) +- [DrinkIn](https://drinkin.com) +- [PodBaby](https://podbaby.me) + +### Community created packages around Echo + +- [echo-logrus](https://github.com/deoxxa/echo-logrus) +- [go_middleware](https://github.com/rightscale/go_middleware) +- [permissions2](https://github.com/xyproto/permissions2) +- [permissionbolt](https://github.com/xyproto/permissionbolt) +- [echo-middleware](https://github.com/syntaqx/echo-middleware) +- [dpecho](https://github.com/deferpanic/dpecho) +- [echosentry](https://github.com/01walid/echosentry) +- [go-starter-kit](https://github.com/olebedev/go-starter-kit) + +[Want to get listed?](https://github.com/labstack/echo/issues/295) + ## Getting Started ### Installation From fb926922bf6c2aac2bd90d26f341090e6c6103e8 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 30 Jan 2016 11:32:56 -0800 Subject: [PATCH 29/67] Update README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b6000c570..1e9196975 100644 --- a/README.md +++ b/README.md @@ -81,16 +81,6 @@ BenchmarkVulcan_GithubAll 5000 271682 ns/op 1989 BenchmarkZeus_GithubAll 2000 748827 ns/op 300688 B/op 2648 allocs/op ``` -## Installation - -```sh -$ go get github.com/labstack/echo -``` - -## [Recipes](http://labstack.com/echo/recipes/hello-world) - -## [Guide](http://labstack.com/echo/guide/installation) - ## Echo System ### Who's using Echo? @@ -122,6 +112,16 @@ $ go get github.com/labstack/echo [Want to get listed?](https://github.com/labstack/echo/issues/295) +## Installation + +```sh +$ go get github.com/labstack/echo +``` + +## [Recipes](http://labstack.com/echo/recipes/hello-world) + +## [Guide](http://labstack.com/echo/guide/installation) + ## Contribute **Use issues for everything** From 96988cb4de446474d6f7c9186399e4d0d73eca51 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 30 Jan 2016 22:50:30 -0800 Subject: [PATCH 30/67] Glide for dependency mgmt Signed-off-by: Vishal Rana --- glide.lock | 27 +++++++++++++++++++++++++++ glide.yaml | 12 ++++++++++++ website/static/images/echo.svg | 17 +++++++++++++++++ website/static/images/logo.svg | 1 + 4 files changed, 57 insertions(+) create mode 100644 glide.lock create mode 100644 glide.yaml create mode 100644 website/static/images/echo.svg create mode 100644 website/static/images/logo.svg diff --git a/glide.lock b/glide.lock new file mode 100644 index 000000000..a7f4c7407 --- /dev/null +++ b/glide.lock @@ -0,0 +1,27 @@ +hash: fc82f692d0964f55086fbff3572309a4dc9ffef356a2fa27687b997b761e345f +updated: 2016-01-30T10:01:06.631964896-08:00 +imports: +- name: github.com/labstack/echo + version: 28b1b9d57b8a7b0b79ae05530b27244e27ba4bff +- name: github.com/labstack/gommon + version: 43358a791be603db7175670d78abf544245f9941 + subpackages: + - /color + - log +- name: github.com/mattn/go-colorable + version: 4af63d73f5bea08b682ad2cd198b1e607afd6be0 +- name: github.com/mattn/go-isatty + version: 56b76bdf51f7708750eac80fa38b952bb9f32639 +- name: golang.org/x/crypto + version: 1f22c0103821b9390939b6776727195525381532 + repo: https://golang.org/x/crypto +- name: golang.org/x/net + version: 04b9de9b512f58addf28c9853d50ebef61c3953e + subpackages: + - /context + - http2 + - websocket +- name: golang.org/x/text + version: 6fc2e00a0d64b1f7fc1212dae5b0c939cf6d9ac4 + repo: https://golang.org/x/text +devImports: [] diff --git a/glide.yaml b/glide.yaml new file mode 100644 index 000000000..c65faaeb7 --- /dev/null +++ b/glide.yaml @@ -0,0 +1,12 @@ +package: . +import: +- package: github.com/labstack/echo +- package: github.com/labstack/gommon + subpackages: + - /color + - log +- package: golang.org/x/net + subpackages: + - /context + - http2 + - websocket diff --git a/website/static/images/echo.svg b/website/static/images/echo.svg new file mode 100644 index 000000000..009846729 --- /dev/null +++ b/website/static/images/echo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/website/static/images/logo.svg b/website/static/images/logo.svg new file mode 100644 index 000000000..bc527fb3d --- /dev/null +++ b/website/static/images/logo.svg @@ -0,0 +1 @@ +LabStack \ No newline at end of file From 4a09f90bf1a9038527493be82be6be024e526530 Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Sun, 31 Jan 2016 11:51:12 +0400 Subject: [PATCH 31/67] Replace real object logger with interface. --- echo.go | 39 +++++++++++++++++++++++---------------- middleware/logger_test.go | 7 +++++-- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/echo.go b/echo.go index 6859bab50..9654a6ffd 100644 --- a/echo.go +++ b/echo.go @@ -66,10 +66,28 @@ type ( debug bool hook http.HandlerFunc autoIndex bool - logger *log.Logger + logger Logger router *Router } + // Logger is the interface that declares echo's logging system. + Logger interface { + Debug(...interface{}) + Debugf(string, ...interface{}) + + Info(...interface{}) + Infof(string, ...interface{}) + + Warn(...interface{}) + Warnf(string, ...interface{}) + + Error(...interface{}) + Errorf(string, ...interface{}) + + Fatal(...interface{}) + Fatalf(string, ...interface{}) + } + // Route contains a handler and information for matching against requests. Route struct { Method string @@ -254,7 +272,6 @@ func New() (e *Echo) { // Logger e.logger = log.New("echo") - e.logger.SetLevel(log.INFO) return } @@ -264,23 +281,13 @@ func (e *Echo) Router() *Router { return e.router } -// SetLogPrefix sets the prefix for the logger. Default value is `echo`. -func (e *Echo) SetLogPrefix(prefix string) { - e.logger.SetPrefix(prefix) -} - -// SetLogOutput sets the output destination for the logger. Default value is `os.Stdout` -func (e *Echo) SetLogOutput(w io.Writer) { - e.logger.SetOutput(w) -} - -// SetLogLevel sets the log level for the logger. Default value is `log.INFO`. -func (e *Echo) SetLogLevel(l log.Level) { - e.logger.SetLevel(l) +// SetLogger sets the logger instance. +func (e *Echo) SetLogger(logger Logger) { + e.logger = logger } // Logger returns the logger instance. -func (e *Echo) Logger() *log.Logger { +func (e *Echo) Logger() Logger { return e.logger } diff --git a/middleware/logger_test.go b/middleware/logger_test.go index 298154b4e..3ae4970be 100644 --- a/middleware/logger_test.go +++ b/middleware/logger_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/labstack/echo" + "github.com/labstack/gommon/log" "github.com/stretchr/testify/assert" ) @@ -52,11 +53,13 @@ func TestLogger(t *testing.T) { func TestLoggerIPAddress(t *testing.T) { e := echo.New() + l := log.New("echo") + buf := new(bytes.Buffer) + l.SetOutput(buf) + e.SetLogger(l) req, _ := http.NewRequest(echo.GET, "/", nil) rec := httptest.NewRecorder() c := echo.NewContext(req, echo.NewResponse(rec, e), e) - buf := new(bytes.Buffer) - e.Logger().SetOutput(buf) ip := "127.0.0.1" h := func(c *echo.Context) error { return c.String(http.StatusOK, "test") From 3ba82ac1ec909764cc9abae5b16b89dce40041ae Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sun, 31 Jan 2016 08:55:43 -0800 Subject: [PATCH 32/67] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1e9196975..6bcf2e9ca 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ BenchmarkZeus_GithubAll 2000 748827 ns/op 30068 - [Gomoku](http://gomoku.thoughtsfromplac.es) - [DrinkIn](https://drinkin.com) - [PodBaby](https://podbaby.me) +- [gifs](https://gifs.com) ### Community created packages around Echo From 7af4376e7fe9646af809c7912517eda9916316d5 Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Mon, 1 Feb 2016 19:40:03 +0400 Subject: [PATCH 33/67] Add form binding. --- binder.go | 207 ++++++++++++++++++++++++++++++++++++++++++++++++ binder_test.go | 96 ++++++++++++++++++++++ context_test.go | 47 ----------- echo.go | 27 ------- 4 files changed, 303 insertions(+), 74 deletions(-) create mode 100644 binder.go create mode 100644 binder_test.go diff --git a/binder.go b/binder.go new file mode 100644 index 000000000..e91d1dea6 --- /dev/null +++ b/binder.go @@ -0,0 +1,207 @@ +package echo + +import ( + "encoding/json" + "encoding/xml" + "errors" + "net/http" + "reflect" + "strconv" + "strings" +) + +type ( + // Binder is the interface that wraps the Bind method. + Binder interface { + Bind(*http.Request, interface{}) error + } + + binder struct { + maxMemory int64 + } +) + +const ( + defaultMaxMemory = 32 << 20 // 32 MB +) + +// SetMaxBodySize sets multipart forms max body size +func (b *binder) SetMaxMemory(size int64) { + b.maxMemory = size +} + +// MaxBodySize return multipart forms max body size +func (b *binder) MaxMemory() int64 { + return b.maxMemory +} + +func (b *binder) Bind(r *http.Request, i interface{}) (err error) { + ct := r.Header.Get(ContentType) + err = ErrUnsupportedMediaType + switch { + case strings.HasPrefix(ct, ApplicationJSON): + if err = json.NewDecoder(r.Body).Decode(i); err != nil { + err = NewHTTPError(http.StatusBadRequest, err.Error()) + } + case strings.HasPrefix(ct, ApplicationXML): + if err = xml.NewDecoder(r.Body).Decode(i); err != nil { + err = NewHTTPError(http.StatusBadRequest, err.Error()) + } + case strings.HasPrefix(ct, ApplicationForm): + if err = b.bindForm(r, i); err != nil { + err = NewHTTPError(http.StatusBadRequest, err.Error()) + } + case strings.HasPrefix(ct, MultipartForm): + if err = b.bindMultiPartForm(r, i); err != nil { + err = NewHTTPError(http.StatusBadRequest, err.Error()) + } + } + return +} + +func (binder) bindForm(r *http.Request, i interface{}) error { + if err := r.ParseForm(); err != nil { + return err + } + return mapForm(i, r.Form) +} + +func (b binder) bindMultiPartForm(r *http.Request, i interface{}) error { + if b.maxMemory == 0 { + b.maxMemory = defaultMaxMemory + } + if err := r.ParseMultipartForm(b.maxMemory); err != nil { + return err + } + return mapForm(i, r.Form) +} + +func mapForm(ptr interface{}, form map[string][]string) error { + typ := reflect.TypeOf(ptr).Elem() + val := reflect.ValueOf(ptr).Elem() + for i := 0; i < typ.NumField(); i++ { + typeField := typ.Field(i) + structField := val.Field(i) + if !structField.CanSet() { + continue + } + + structFieldKind := structField.Kind() + inputFieldName := typeField.Tag.Get("form") + if inputFieldName == "" { + inputFieldName = typeField.Name + + // if "form" tag is nil, we inspect if the field is a struct. + // this would not make sense for JSON parsing but it does for a form + // since data is flatten + if structFieldKind == reflect.Struct { + err := mapForm(structField.Addr().Interface(), form) + if err != nil { + return err + } + continue + } + } + inputValue, exists := form[inputFieldName] + if !exists { + continue + } + + numElems := len(inputValue) + if structFieldKind == reflect.Slice && numElems > 0 { + sliceOf := structField.Type().Elem().Kind() + slice := reflect.MakeSlice(structField.Type(), numElems, numElems) + for i := 0; i < numElems; i++ { + if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil { + return err + } + } + val.Field(i).Set(slice) + } else { + if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil { + return err + } + } + } + return nil +} + +func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error { + switch valueKind { + case reflect.Int: + return setIntField(val, 0, structField) + case reflect.Int8: + return setIntField(val, 8, structField) + case reflect.Int16: + return setIntField(val, 16, structField) + case reflect.Int32: + return setIntField(val, 32, structField) + case reflect.Int64: + return setIntField(val, 64, structField) + case reflect.Uint: + return setUintField(val, 0, structField) + case reflect.Uint8: + return setUintField(val, 8, structField) + case reflect.Uint16: + return setUintField(val, 16, structField) + case reflect.Uint32: + return setUintField(val, 32, structField) + case reflect.Uint64: + return setUintField(val, 64, structField) + case reflect.Bool: + return setBoolField(val, structField) + case reflect.Float32: + return setFloatField(val, 32, structField) + case reflect.Float64: + return setFloatField(val, 64, structField) + case reflect.String: + structField.SetString(val) + default: + return errors.New("Unknown type") + } + return nil +} + +func setIntField(val string, bitSize int, field reflect.Value) error { + if val == "" { + val = "0" + } + intVal, err := strconv.ParseInt(val, 10, bitSize) + if err == nil { + field.SetInt(intVal) + } + return err +} + +func setUintField(val string, bitSize int, field reflect.Value) error { + if val == "" { + val = "0" + } + uintVal, err := strconv.ParseUint(val, 10, bitSize) + if err == nil { + field.SetUint(uintVal) + } + return err +} + +func setBoolField(val string, field reflect.Value) error { + if val == "" { + val = "false" + } + boolVal, err := strconv.ParseBool(val) + if err == nil { + field.SetBool(boolVal) + } + return err +} + +func setFloatField(val string, bitSize int, field reflect.Value) error { + if val == "" { + val = "0.0" + } + floatVal, err := strconv.ParseFloat(val, bitSize) + if err == nil { + field.SetFloat(floatVal) + } + return err +} diff --git a/binder_test.go b/binder_test.go new file mode 100644 index 000000000..7ee2ca785 --- /dev/null +++ b/binder_test.go @@ -0,0 +1,96 @@ +package echo + +import ( + "bytes" + "github.com/stretchr/testify/assert" + "mime/multipart" + "net/http" + "strings" + "testing" +) + +type ( + customer struct { + ID string `json:"id" xml:"id" form:"id"` + Name string `json:"name" xml:"name" form:"name"` + } +) + +const ( + customerJSON = `{"id":"1","name":"Joe"}` + customerXML = `1Joe` + customerForm = `id=1&name=Joe` + incorrectContent = "this is incorrect content" +) + +func TestMaxMemory(t *testing.T) { + b := new(binder) + b.SetMaxMemory(20) + assert.Equal(t, int64(20), b.MaxMemory()) +} + +func TestJSONBinding(t *testing.T) { + r, _ := http.NewRequest(POST, "/", strings.NewReader(customerJSON)) + testBindOk(t, r, ApplicationJSON) + r, _ = http.NewRequest(POST, "/", strings.NewReader(incorrectContent)) + testBindError(t, r, ApplicationJSON) +} + +func TestXMLBinding(t *testing.T) { + r, _ := http.NewRequest(POST, "/", strings.NewReader(customerXML)) + testBindOk(t, r, ApplicationXML) + r, _ = http.NewRequest(POST, "/", strings.NewReader(incorrectContent)) + testBindError(t, r, ApplicationXML) +} + +func TestFormBinding(t *testing.T) { + r, _ := http.NewRequest(POST, "/", strings.NewReader(customerForm)) + testBindOk(t, r, ApplicationForm) +} + +func TestMultipartFormBinding(t *testing.T) { + body := new(bytes.Buffer) + mw := multipart.NewWriter(body) + mw.WriteField("id", "1") + mw.WriteField("name", "Joe") + mw.Close() + r, _ := http.NewRequest(POST, "/", body) + testBindOk(t, r, mw.FormDataContentType()) + r, _ = http.NewRequest(POST, "/", strings.NewReader(incorrectContent)) + testBindError(t, r, mw.FormDataContentType()) +} + +func TestUnsupportedMediaTypeBinding(t *testing.T) { + r, _ := http.NewRequest(POST, "/", strings.NewReader(customerJSON)) + + // Unsupported + testBindError(t, r, "") +} + +func testBindOk(t *testing.T, r *http.Request, ct string) { + r.Header.Set(ContentType, ct) + u := new(customer) + err := new(binder).Bind(r, u) + if assert.NoError(t, err) { + assert.Equal(t, "1", u.ID) + assert.Equal(t, "Joe", u.Name) + } +} + +func testBindError(t *testing.T, r *http.Request, ct string) { + r.Header.Set(ContentType, ct) + u := new(customer) + err := new(binder).Bind(r, u) + + switch { + case strings.HasPrefix(ct, ApplicationJSON), strings.HasPrefix(ct, ApplicationXML), strings.HasPrefix(ct, ApplicationForm), strings.HasPrefix(ct, MultipartForm): + if assert.IsType(t, new(HTTPError), err) { + assert.Equal(t, http.StatusBadRequest, err.(*HTTPError).code) + } + default: + if assert.IsType(t, new(HTTPError), err) { + assert.Equal(t, ErrUnsupportedMediaType, err) + } + + } +} diff --git a/context_test.go b/context_test.go index c65738c26..fb57cc62b 100644 --- a/context_test.go +++ b/context_test.go @@ -34,7 +34,6 @@ func TestContext(t *testing.T) { userJSONIndent := "{\n_?\"id\": \"1\",\n_?\"name\": \"Joe\"\n_}" userXML := `1Joe` userXMLIndent := "_\n_?1\n_?Joe\n_" - incorrectContent := "this is incorrect content" var nonMarshallableChannel chan bool @@ -64,24 +63,6 @@ func TestContext(t *testing.T) { c.Set("user", "Joe") assert.Equal(t, "Joe", c.Get("user")) - //------ - // Bind - //------ - - // JSON - testBindOk(t, c, ApplicationJSON) - c.request, _ = http.NewRequest(POST, "/", strings.NewReader(incorrectContent)) - testBindError(t, c, ApplicationJSON) - - // XML - c.request, _ = http.NewRequest(POST, "/", strings.NewReader(userXML)) - testBindOk(t, c, ApplicationXML) - c.request, _ = http.NewRequest(POST, "/", strings.NewReader(incorrectContent)) - testBindError(t, c, ApplicationXML) - - // Unsupported - testBindError(t, c, "") - //-------- // Render //-------- @@ -295,31 +276,3 @@ func TestContextEcho(t *testing.T) { // Should be null when initialized without one assert.Nil(t, c.Echo()) } - -func testBindOk(t *testing.T, c *Context, ct string) { - c.request.Header.Set(ContentType, ct) - u := new(user) - err := c.Bind(u) - if assert.NoError(t, err) { - assert.Equal(t, "1", u.ID) - assert.Equal(t, "Joe", u.Name) - } -} - -func testBindError(t *testing.T, c *Context, ct string) { - c.request.Header.Set(ContentType, ct) - u := new(user) - err := c.Bind(u) - - switch ct { - case ApplicationJSON, ApplicationXML: - if assert.IsType(t, new(HTTPError), err) { - assert.Equal(t, http.StatusBadRequest, err.(*HTTPError).code) - } - default: - if assert.IsType(t, new(HTTPError), err) { - assert.Equal(t, ErrUnsupportedMediaType, err) - } - - } -} diff --git a/echo.go b/echo.go index 9654a6ffd..7819c1625 100644 --- a/echo.go +++ b/echo.go @@ -33,8 +33,6 @@ package echo import ( "bytes" - "encoding/json" - "encoding/xml" "errors" "fmt" "io" @@ -43,7 +41,6 @@ import ( "path/filepath" "reflect" "runtime" - "strings" "sync" "github.com/labstack/gommon/log" @@ -116,14 +113,6 @@ type ( // HTTPErrorHandler is a centralized HTTP error handler. HTTPErrorHandler func(error, *Context) - // Binder is the interface that wraps the Bind method. - Binder interface { - Bind(*http.Request, interface{}) error - } - - binder struct { - } - // Validator is the interface that wraps the Validate method. Validator interface { Validate() error @@ -736,19 +725,3 @@ func wrapHandler(h Handler) HandlerFunc { panic("unknown handler") } } - -func (binder) Bind(r *http.Request, i interface{}) (err error) { - ct := r.Header.Get(ContentType) - err = ErrUnsupportedMediaType - if strings.HasPrefix(ct, ApplicationJSON) { - if err = json.NewDecoder(r.Body).Decode(i); err != nil { - err = NewHTTPError(http.StatusBadRequest, err.Error()) - } - } else if strings.HasPrefix(ct, ApplicationXML) { - if err = xml.NewDecoder(r.Body).Decode(i); err != nil { - err = NewHTTPError(http.StatusBadRequest, err.Error()) - } - - } - return -} From 68c86e3f9060ddf8452e85b8dbe3770348c76e72 Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Mon, 1 Feb 2016 23:22:33 +0400 Subject: [PATCH 34/67] Improve tests coverage --- binder_test.go | 179 +++++++++++++++++++++++++++++++++++++++++++++--- context_test.go | 12 +++- echo_test.go | 26 +++++++ 3 files changed, 207 insertions(+), 10 deletions(-) diff --git a/binder_test.go b/binder_test.go index 7ee2ca785..b7f05d803 100644 --- a/binder_test.go +++ b/binder_test.go @@ -5,19 +5,61 @@ import ( "github.com/stretchr/testify/assert" "mime/multipart" "net/http" + "reflect" "strings" "testing" ) type ( customer struct { - ID string `json:"id" xml:"id" form:"id"` + ID int `json:"id" xml:"id" form:"id"` Name string `json:"name" xml:"name" form:"name"` } + + testStruct struct { + I int + I8 int8 + I16 int16 + I32 int32 + I64 int64 + UI uint + UI8 uint8 + UI16 uint16 + UI32 uint32 + UI64 uint64 + B bool + F32 float32 + F64 float64 + S string + cantSet string + DoesntExist string + } ) +func (t testStruct) GetCantSet() string { + return t.cantSet +} + +var values = map[string][]string{ + "I": {"0"}, + "I8": {"8"}, + "I16": {"16"}, + "I32": {"32"}, + "I64": {"64"}, + "UI": {"0"}, + "UI8": {"8"}, + "UI16": {"16"}, + "UI32": {"32"}, + "UI64": {"64"}, + "B": {"true"}, + "F32": {"32.5"}, + "F64": {"64.5"}, + "S": {"test"}, + "cantSet": {"test"}, +} + const ( - customerJSON = `{"id":"1","name":"Joe"}` + customerJSON = `{"id":1,"name":"Joe"}` customerXML = `1Joe` customerForm = `id=1&name=Joe` incorrectContent = "this is incorrect content" @@ -46,6 +88,8 @@ func TestXMLBinding(t *testing.T) { func TestFormBinding(t *testing.T) { r, _ := http.NewRequest(POST, "/", strings.NewReader(customerForm)) testBindOk(t, r, ApplicationForm) + r, _ = http.NewRequest(POST, "/", nil) + testBindError(t, r, ApplicationForm) } func TestMultipartFormBinding(t *testing.T) { @@ -62,18 +106,134 @@ func TestMultipartFormBinding(t *testing.T) { func TestUnsupportedMediaTypeBinding(t *testing.T) { r, _ := http.NewRequest(POST, "/", strings.NewReader(customerJSON)) - - // Unsupported testBindError(t, r, "") } +func TestBindFormFunc(t *testing.T) { + r, _ := http.NewRequest(POST, "/", strings.NewReader(customerForm)) + r.Header.Set(ContentType, ApplicationForm) + b := new(binder) + c := new(customer) + if assert.NoError(t, b.bindForm(r, c)) { + assertCustomer(t, c) + } +} + +func TestBindMultiPartFormFunc(t *testing.T) { + body := new(bytes.Buffer) + mw := multipart.NewWriter(body) + mw.WriteField("id", "1") + mw.WriteField("name", "Joe") + mw.Close() + r, _ := http.NewRequest(POST, "/", body) + r.Header.Set(ContentType, mw.FormDataContentType()) + b := new(binder) + c := new(customer) + if assert.NoError(t, b.bindMultiPartForm(r, c)) { + assertCustomer(t, c) + } +} + +func assertCustomer(t *testing.T, c *customer) { + assert.Equal(t, 1, c.ID) + assert.Equal(t, "Joe", c.Name) +} + +func TestMapForm(t *testing.T) { + ts := new(testStruct) + mapForm(ts, values) + assertTestStruct(t, ts) +} + +func TestSetWithProperType(t *testing.T) { + ts := new(testStruct) + typ := reflect.TypeOf(ts).Elem() + val := reflect.ValueOf(ts).Elem() + for i := 0; i < typ.NumField(); i++ { + typeField := typ.Field(i) + structField := val.Field(i) + if !structField.CanSet() { + continue + } + if len(values[typeField.Name]) == 0 { + continue + } + val := values[typeField.Name][0] + err := setWithProperType(typeField.Type.Kind(), val, structField) + assert.NoError(t, err) + } + assertTestStruct(t, ts) + + type foo struct { + Bar bytes.Buffer + } + v := &foo{} + typ = reflect.TypeOf(v).Elem() + val = reflect.ValueOf(v).Elem() + assert.Error(t, setWithProperType(typ.Field(0).Type.Kind(), "5", val.Field(0))) +} + +func TestSetFields(t *testing.T) { + ts := new(testStruct) + val := reflect.ValueOf(ts).Elem() + // Int + if assert.NoError(t, setIntField("5", 0, val.FieldByName("I"))) { + assert.Equal(t, 5, ts.I) + } + if assert.NoError(t, setIntField("", 0, val.FieldByName("I"))) { + assert.Equal(t, 0, ts.I) + } + + // Uint + if assert.NoError(t, setUintField("10", 0, val.FieldByName("UI"))) { + assert.Equal(t, uint(10), ts.UI) + } + if assert.NoError(t, setUintField("", 0, val.FieldByName("UI"))) { + assert.Equal(t, uint(0), ts.UI) + } + + // Float + if assert.NoError(t, setFloatField("15.5", 0, val.FieldByName("F32"))) { + assert.Equal(t, float32(15.5), ts.F32) + } + if assert.NoError(t, setFloatField("", 0, val.FieldByName("F32"))) { + assert.Equal(t, float32(0.0), ts.F32) + } + + // Bool + if assert.NoError(t, setBoolField("true", val.FieldByName("B"))) { + assert.Equal(t, true, ts.B) + } + if assert.NoError(t, setBoolField("", val.FieldByName("B"))) { + assert.Equal(t, false, ts.B) + } +} + +func assertTestStruct(t *testing.T, ts *testStruct) { + assert.Equal(t, 0, ts.I) + assert.Equal(t, int8(8), ts.I8) + assert.Equal(t, int16(16), ts.I16) + assert.Equal(t, int32(32), ts.I32) + assert.Equal(t, int64(64), ts.I64) + assert.Equal(t, uint(0), ts.UI) + assert.Equal(t, uint8(8), ts.UI8) + assert.Equal(t, uint16(16), ts.UI16) + assert.Equal(t, uint32(32), ts.UI32) + assert.Equal(t, uint64(64), ts.UI64) + assert.Equal(t, true, ts.B) + assert.Equal(t, float32(32.5), ts.F32) + assert.Equal(t, float64(64.5), ts.F64) + assert.Equal(t, "test", ts.S) + assert.Equal(t, "", ts.GetCantSet()) +} + func testBindOk(t *testing.T, r *http.Request, ct string) { r.Header.Set(ContentType, ct) - u := new(customer) - err := new(binder).Bind(r, u) + c := new(customer) + err := new(binder).Bind(r, c) if assert.NoError(t, err) { - assert.Equal(t, "1", u.ID) - assert.Equal(t, "Joe", u.Name) + assert.Equal(t, 1, c.ID) + assert.Equal(t, "Joe", c.Name) } } @@ -83,7 +243,8 @@ func testBindError(t *testing.T, r *http.Request, ct string) { err := new(binder).Bind(r, u) switch { - case strings.HasPrefix(ct, ApplicationJSON), strings.HasPrefix(ct, ApplicationXML), strings.HasPrefix(ct, ApplicationForm), strings.HasPrefix(ct, MultipartForm): + case strings.HasPrefix(ct, ApplicationJSON), strings.HasPrefix(ct, ApplicationXML), + strings.HasPrefix(ct, ApplicationForm), strings.HasPrefix(ct, MultipartForm): if assert.IsType(t, new(HTTPError), err) { assert.Equal(t, http.StatusBadRequest, err.(*HTTPError).code) } diff --git a/context_test.go b/context_test.go index fb57cc62b..62b440449 100644 --- a/context_test.go +++ b/context_test.go @@ -63,6 +63,16 @@ func TestContext(t *testing.T) { c.Set("user", "Joe") assert.Equal(t, "Joe", c.Get("user")) + // Bind + c.request, _ = http.NewRequest(POST, "/", strings.NewReader(userJSON)) + c.request.Header.Set(ContentType, ApplicationJSON) + u := new(user) + err := c.Bind(u) + if assert.NoError(t, err) { + assert.Equal(t, "1", u.ID) + assert.Equal(t, "Joe", u.Name) + } + //-------- // Render //-------- @@ -71,7 +81,7 @@ func TestContext(t *testing.T) { templates: template.Must(template.New("hello").Parse("Hello, {{.}}!")), } c.echo.SetRenderer(tpl) - err := c.Render(http.StatusOK, "hello", "Joe") + err = c.Render(http.StatusOK, "hello", "Joe") if assert.NoError(t, err) { assert.Equal(t, http.StatusOK, rec.Code) assert.Equal(t, "Hello, Joe!", rec.Body.String()) diff --git a/echo_test.go b/echo_test.go index fe4344d76..a6d9040aa 100644 --- a/echo_test.go +++ b/echo_test.go @@ -12,6 +12,7 @@ import ( "errors" + "github.com/labstack/gommon/log" "github.com/stretchr/testify/assert" "golang.org/x/net/websocket" ) @@ -39,6 +40,29 @@ func TestEcho(t *testing.T) { // DefaultHTTPErrorHandler e.DefaultHTTPErrorHandler(errors.New("error"), c) assert.Equal(t, http.StatusInternalServerError, rec.Code) + + // Logger + l := log.New("test") + e.SetLogger(l) + assert.Equal(t, l, e.Logger()) + + // Autoindex + e.AutoIndex(true) + assert.True(t, e.autoIndex) +} + +func TestListDir(t *testing.T) { + e := New() + req, _ := http.NewRequest(GET, "/", nil) + rec := httptest.NewRecorder() + c := NewContext(req, NewResponse(rec, e), e) + fs := http.Dir("_fixture") + f, err := fs.Open("images") + assert.NoError(t, err) + if assert.NoError(t, listDir(f, c)) { + assert.Equal(t, TextHTMLCharsetUTF8, rec.Header().Get(ContentType)) + assert.Equal(t, "
\nwalle.png\n
\n", rec.Body.String()) + } } func TestEchoIndex(t *testing.T) { @@ -399,6 +423,8 @@ func TestEchoHTTPError(t *testing.T) { he := NewHTTPError(http.StatusBadRequest, m) assert.Equal(t, http.StatusBadRequest, he.Code()) assert.Equal(t, m, he.Error()) + he.SetCode(http.StatusOK) + assert.Equal(t, http.StatusOK, he.Code()) } func TestEchoServer(t *testing.T) { From ce5e89302aa5c64b8b4b878037f3da70b8bec8f8 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Mon, 1 Feb 2016 15:10:15 -0800 Subject: [PATCH 35/67] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6bcf2e9ca..e1bebc14e 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ BenchmarkZeus_GithubAll 2000 748827 ns/op 30068 ### Who's using Echo? +- [LabStack](https://labstack.com) - [ShowChampions](https://showchampions.photoserve.co) - [deferpanic](https://deferpanic.com) - [Center for Open Science](https://cos.io) From feac46afa9051536eda79a50f7870eaafcb032f0 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Mon, 1 Feb 2016 15:10:50 -0800 Subject: [PATCH 36/67] Update index.md --- website/content/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/content/index.md b/website/content/index.md index bf95bb96a..5332729ca 100644 --- a/website/content/index.md +++ b/website/content/index.md @@ -55,6 +55,7 @@ A fast and unfancy micro web framework for Go. ### Who's using Echo? +- [LabStack](https://labstack.com) - [ShowChampions](https://showchampions.photoserve.co) - [deferpanic](https://deferpanic.com) - [Center for Open Science](https://cos.io) From 1c6658e48aed7577a002583a94dd7b6509f51cac Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Fri, 5 Feb 2016 15:40:39 +0400 Subject: [PATCH 37/67] fix memory leaks #356 --- binder.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/binder.go b/binder.go index e91d1dea6..cb1f6a2d4 100644 --- a/binder.go +++ b/binder.go @@ -36,6 +36,11 @@ func (b *binder) MaxMemory() int64 { } func (b *binder) Bind(r *http.Request, i interface{}) (err error) { + if r.Body == nil { + err = NewHTTPError(http.StatusBadRequest, "Requesr body can't be nil") + return + } + defer r.Body.Close() ct := r.Header.Get(ContentType) err = ErrUnsupportedMediaType switch { From 9831b9087a47f0af18c142f5d41b54103741dde3 Mon Sep 17 00:00:00 2001 From: Florian Bertholin Date: Thu, 4 Feb 2016 12:37:21 +0100 Subject: [PATCH 38/67] Add a ParamNames method on Context --- context.go | 5 +++++ context_test.go | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/context.go b/context.go index b49623739..5cb07e059 100644 --- a/context.go +++ b/context.go @@ -58,6 +58,11 @@ func (c *Context) Socket() *websocket.Conn { return c.socket } +// ParamNames returns path parameter names. +func (c *Context) ParamNames() []string { + return c.pnames +} + // Path returns the registered path for the handler. func (c *Context) Path() string { return c.path diff --git a/context_test.go b/context_test.go index 62b440449..4b9f7ca30 100644 --- a/context_test.go +++ b/context_test.go @@ -51,6 +51,10 @@ func TestContext(t *testing.T) { // Socket assert.Nil(t, c.Socket()) + // ParamNames + c.pnames = []string{"user_id", "id"} + assert.EqualValues(t, []string{"user_id", "id"}, c.ParamNames()) + // Param by id c.pnames = []string{"id"} c.pvalues = []string{"1"} From 631f7f1534496496c02ad1a24f52a2dd24e2938a Mon Sep 17 00:00:00 2001 From: Oleg Lobanov Date: Fri, 5 Feb 2016 20:44:47 +0400 Subject: [PATCH 39/67] fix typo --- binder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binder.go b/binder.go index cb1f6a2d4..eaf364a4b 100644 --- a/binder.go +++ b/binder.go @@ -37,7 +37,7 @@ func (b *binder) MaxMemory() int64 { func (b *binder) Bind(r *http.Request, i interface{}) (err error) { if r.Body == nil { - err = NewHTTPError(http.StatusBadRequest, "Requesr body can't be nil") + err = NewHTTPError(http.StatusBadRequest, "Request body can't be nil") return } defer r.Body.Close() From fd5f48a884249faa4960e42168ce2d1cb36742f7 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Mon, 8 Feb 2016 22:15:38 -0800 Subject: [PATCH 40/67] Fixed default http handler Signed-off-by: Vishal Rana --- echo.go | 62 +++++++++++++++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/echo.go b/echo.go index 7819c1625..111173cf3 100644 --- a/echo.go +++ b/echo.go @@ -51,20 +51,19 @@ import ( type ( // Echo is the top-level framework instance. Echo struct { - prefix string - middleware []MiddlewareFunc - http2 bool - maxParam *int - defaultHTTPErrorHandler HTTPErrorHandler - httpErrorHandler HTTPErrorHandler - binder Binder - renderer Renderer - pool sync.Pool - debug bool - hook http.HandlerFunc - autoIndex bool - logger Logger - router *Router + prefix string + middleware []MiddlewareFunc + http2 bool + maxParam *int + httpErrorHandler HTTPErrorHandler + binder Binder + renderer Renderer + pool sync.Pool + debug bool + hook http.HandlerFunc + autoIndex bool + logger Logger + router *Router } // Logger is the interface that declares echo's logging system. @@ -241,22 +240,7 @@ func New() (e *Echo) { //---------- e.HTTP2(true) - e.defaultHTTPErrorHandler = func(err error, c *Context) { - code := http.StatusInternalServerError - msg := http.StatusText(code) - if he, ok := err.(*HTTPError); ok { - code = he.code - msg = he.message - } - if e.debug { - msg = err.Error() - } - if !c.response.committed { - http.Error(c.response, msg, code) - } - e.logger.Error(err) - } - e.SetHTTPErrorHandler(e.defaultHTTPErrorHandler) + e.SetHTTPErrorHandler(e.DefaultHTTPErrorHandler) e.SetBinder(&binder{}) // Logger @@ -287,7 +271,19 @@ func (e *Echo) HTTP2(on bool) { // DefaultHTTPErrorHandler invokes the default HTTP error handler. func (e *Echo) DefaultHTTPErrorHandler(err error, c *Context) { - e.defaultHTTPErrorHandler(err, c) + code := http.StatusInternalServerError + msg := http.StatusText(code) + if he, ok := err.(*HTTPError); ok { + code = he.code + msg = he.message + } + if e.debug { + msg = err.Error() + } + if !c.response.committed { + http.Error(c.response, msg, code) + } + e.logger.Error(err) } // SetHTTPErrorHandler registers a custom Echo.HTTPErrorHandler. @@ -595,8 +591,8 @@ func (e *Echo) Run(addr string) { } // RunTLS runs a server with TLS configuration. -func (e *Echo) RunTLS(addr, crtFile, keyFile string) { - e.run(e.Server(addr), crtFile, keyFile) +func (e *Echo) RunTLS(addr, certfile, keyfile string) { + e.run(e.Server(addr), certfile, keyfile) } // RunServer runs a custom server. From 4e57fa0557593aea5f1b8fdd26d64c09e81a108c Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Tue, 9 Feb 2016 19:26:31 -0800 Subject: [PATCH 41/67] Fixed #360 Signed-off-by: Vishal Rana --- context.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/context.go b/context.go index 5cb07e059..c68ff4bd6 100644 --- a/context.go +++ b/context.go @@ -159,10 +159,7 @@ func (c *Context) JSON(code int, i interface{}) (err error) { if err != nil { return err } - c.response.Header().Set(ContentType, ApplicationJSONCharsetUTF8) - c.response.WriteHeader(code) - c.response.Write(b) - return + return c.JSONBlob(code, b) } // JSONIndent sends a JSON response with status code, but it applies prefix and indent to format the output. @@ -171,14 +168,15 @@ func (c *Context) JSONIndent(code int, i interface{}, prefix string, indent stri if err != nil { return err } - c.json(code, b) - return + return c.JSONBlob(code, b) } -func (c *Context) json(code int, b []byte) { +// JSONBlob sends a JSON blob response with status code. +func (c *Context) JSONBlob(code int, b []byte) (err error) { c.response.Header().Set(ContentType, ApplicationJSONCharsetUTF8) c.response.WriteHeader(code) c.response.Write(b) + return } // JSONP sends a JSONP response with status code. It uses `callback` to construct From f42af6ea9fae26b64fafd30d648b0ffbe880fb11 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Wed, 10 Feb 2016 09:28:49 -0800 Subject: [PATCH 42/67] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e1bebc14e..f2060e5cd 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ A fast and unfancy micro web framework for Go. +[![Donate](https://www.paypalobjects.com/webstatic/en_US/btn/btn_donate_92x26.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=JD5R56K84A8G4&lc=US&item_name=LabStack&item_number=echo¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted) + ## Features - Fast HTTP router which smartly prioritize routes. From 849000076287d6fdda4096792d188e704d22526e Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Fri, 12 Feb 2016 19:00:10 -0800 Subject: [PATCH 43/67] echo#Use method to chain middleware #353 Signed-off-by: Vishal Rana --- echo.go | 11 +++++++++++ echo_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/echo.go b/echo.go index 111173cf3..679ac7a90 100644 --- a/echo.go +++ b/echo.go @@ -645,6 +645,17 @@ func (e *HTTPError) Error() string { return e.message } +// Use chains all middleware with handler in the end and returns head of the chain. +// The head can be used as handler in any route. +func Use(handler Handler, middleware ...Middleware) (h HandlerFunc) { + h = wrapHandler(handler) + for i := len(middleware) - 1; i >= 0; i-- { + m := wrapMiddleware(middleware[i]) + h = m(h) + } + return +} + // wrapMiddleware wraps middleware. func wrapMiddleware(m Middleware) MiddlewareFunc { switch m := m.(type) { diff --git a/echo_test.go b/echo_test.go index a6d9040aa..72e37ceb7 100644 --- a/echo_test.go +++ b/echo_test.go @@ -451,6 +451,31 @@ func TestEchoHook(t *testing.T) { assert.Equal(t, r.URL.Path, "/test") } +func TestEchoUse(t *testing.T) { + e := New() + buf := new(bytes.Buffer) + mw1 := MiddlewareFunc(func(h HandlerFunc) HandlerFunc { + return func(c *Context) error { + buf.WriteString("mw1") + return h(c) + } + }) + mw2 := MiddlewareFunc(func(h HandlerFunc) HandlerFunc { + return func(c *Context) error { + buf.WriteString("mw2") + return h(c) + } + }) + e.Get("/", Use(func(c *Context) error { + return c.String(http.StatusOK, "Okay") + }, mw1, mw2)) + + r, _ := http.NewRequest(GET, "/", nil) + w := httptest.NewRecorder() + e.ServeHTTP(w, r) + assert.Equal(t, "mw1mw2", buf.String()) +} + func testMethod(t *testing.T, method, path string, e *Echo) { m := fmt.Sprintf("%c%s", method[0], strings.ToLower(method[1:])) p := reflect.ValueOf(path) From 6914162d64dd26ccd90d7c8b00290364337c134c Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Thu, 18 Feb 2016 14:05:40 -0800 Subject: [PATCH 44/67] Removed HTTP2 option Signed-off-by: Vishal Rana --- echo.go | 16 ---------------- glide.lock | 1 - glide.yaml | 1 - 3 files changed, 18 deletions(-) diff --git a/echo.go b/echo.go index 679ac7a90..c069f350b 100644 --- a/echo.go +++ b/echo.go @@ -44,7 +44,6 @@ import ( "sync" "github.com/labstack/gommon/log" - "golang.org/x/net/http2" "golang.org/x/net/websocket" ) @@ -53,7 +52,6 @@ type ( Echo struct { prefix string middleware []MiddlewareFunc - http2 bool maxParam *int httpErrorHandler HTTPErrorHandler binder Binder @@ -239,7 +237,6 @@ func New() (e *Echo) { // Defaults //---------- - e.HTTP2(true) e.SetHTTPErrorHandler(e.DefaultHTTPErrorHandler) e.SetBinder(&binder{}) @@ -264,11 +261,6 @@ func (e *Echo) Logger() Logger { return e.logger } -// HTTP2 enable/disable HTTP2 support. -func (e *Echo) HTTP2(on bool) { - e.http2 = on -} - // DefaultHTTPErrorHandler invokes the default HTTP error handler. func (e *Echo) DefaultHTTPErrorHandler(err error, c *Context) { code := http.StatusInternalServerError @@ -578,10 +570,6 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Server returns the internal *http.Server. func (e *Echo) Server(addr string) *http.Server { s := &http.Server{Addr: addr, Handler: e} - // TODO: Remove in Go 1.6+ - if e.http2 { - http2.ConfigureServer(s, nil) - } return s } @@ -607,10 +595,6 @@ func (e *Echo) RunTLSServer(s *http.Server, crtFile, keyFile string) { func (e *Echo) run(s *http.Server, files ...string) { s.Handler = e - // TODO: Remove in Go 1.6+ - if e.http2 { - http2.ConfigureServer(s, nil) - } if len(files) == 0 { e.logger.Fatal(s.ListenAndServe()) } else if len(files) == 2 { diff --git a/glide.lock b/glide.lock index a7f4c7407..cc9fc02d7 100644 --- a/glide.lock +++ b/glide.lock @@ -19,7 +19,6 @@ imports: version: 04b9de9b512f58addf28c9853d50ebef61c3953e subpackages: - /context - - http2 - websocket - name: golang.org/x/text version: 6fc2e00a0d64b1f7fc1212dae5b0c939cf6d9ac4 diff --git a/glide.yaml b/glide.yaml index c65faaeb7..d7b681241 100644 --- a/glide.yaml +++ b/glide.yaml @@ -8,5 +8,4 @@ import: - package: golang.org/x/net subpackages: - /context - - http2 - websocket From c782b3fc755dd875907c832ca9402808091b726c Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sun, 21 Feb 2016 21:45:11 -0800 Subject: [PATCH 45/67] Fixed #217 Signed-off-by: Vishal Rana --- router.go | 4 ++++ router_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/router.go b/router.go index 42a056631..b447a2ad7 100644 --- a/router.go +++ b/router.go @@ -379,6 +379,10 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo // c = cn.getChild() if cn = cn.findChildByKind(mkind); cn == nil { // Not found + if nn != nil { // Issue #217 + cn = nn + continue + } return } ctx.pvalues[len(cn.pnames)-1] = search diff --git a/router_test.go b/router_test.go index c33572234..7876e9cf7 100644 --- a/router_test.go +++ b/router_test.go @@ -503,6 +503,48 @@ func TestRouterPriority(t *testing.T) { } } +// Issue #217 +func TestRouterPriorityWithMatchAny(t *testing.T) { + e := New() + r := e.router + + // Routes + r.Add(GET, "/aa", func(c *Context) error { + c.Set("a", 1) + return nil + }, e) + r.Add(GET, "/ab", func(c *Context) error { + c.Set("b", 2) + return nil + }, e) + r.Add(GET, "/*", func(c *Context) error { + c.Set("c", 3) + return nil + }, e) + c := NewContext(nil, nil, e) + + // Route > /aa + h, _ := r.Find(GET, "/aa", c) + if assert.NotNil(t, h) { + h(c) + assert.Equal(t, 1, c.Get("a")) + } + + // Route > /ab + h, _ = r.Find(GET, "/ab", c) + if assert.NotNil(t, h) { + h(c) + assert.Equal(t, 2, c.Get("b")) + } + + // Route > /* + h, _ = r.Find(GET, "/abc", c) + if assert.NotNil(t, h) { + h(c) + assert.Equal(t, 3, c.Get("c")) + } +} + func TestRouterParamNames(t *testing.T) { e := New() r := e.router From 33c227045acc469295302b5aeb79c930cf5ecf33 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Tue, 23 Feb 2016 13:35:41 -0800 Subject: [PATCH 46/67] Revert "Fixed #217" This reverts commit c782b3fc755dd875907c832ca9402808091b726c. --- router.go | 4 ---- router_test.go | 42 ------------------------------------------ 2 files changed, 46 deletions(-) diff --git a/router.go b/router.go index b447a2ad7..42a056631 100644 --- a/router.go +++ b/router.go @@ -379,10 +379,6 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo // c = cn.getChild() if cn = cn.findChildByKind(mkind); cn == nil { // Not found - if nn != nil { // Issue #217 - cn = nn - continue - } return } ctx.pvalues[len(cn.pnames)-1] = search diff --git a/router_test.go b/router_test.go index 7876e9cf7..c33572234 100644 --- a/router_test.go +++ b/router_test.go @@ -503,48 +503,6 @@ func TestRouterPriority(t *testing.T) { } } -// Issue #217 -func TestRouterPriorityWithMatchAny(t *testing.T) { - e := New() - r := e.router - - // Routes - r.Add(GET, "/aa", func(c *Context) error { - c.Set("a", 1) - return nil - }, e) - r.Add(GET, "/ab", func(c *Context) error { - c.Set("b", 2) - return nil - }, e) - r.Add(GET, "/*", func(c *Context) error { - c.Set("c", 3) - return nil - }, e) - c := NewContext(nil, nil, e) - - // Route > /aa - h, _ := r.Find(GET, "/aa", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 1, c.Get("a")) - } - - // Route > /ab - h, _ = r.Find(GET, "/ab", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 2, c.Get("b")) - } - - // Route > /* - h, _ = r.Find(GET, "/abc", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 3, c.Get("c")) - } -} - func TestRouterParamNames(t *testing.T) { e := New() r := e.router From d105270d58157b18d45ca7d80158c1243f92f83a Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Tue, 23 Feb 2016 16:27:55 -0800 Subject: [PATCH 47/67] Fixed Router#Find #217 Signed-off-by: Vishal Rana --- router.go | 42 ++++++++++++++++++--------------- router_test.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/router.go b/router.go index 42a056631..b0bbed20c 100644 --- a/router.go +++ b/router.go @@ -43,7 +43,7 @@ type ( const ( skind kind = iota pkind - mkind + akind ) // NewRouter returns a new Router instance. @@ -82,7 +82,7 @@ func (r *Router) Add(method, path string, h HandlerFunc, e *Echo) { } else if path[i] == '*' { r.insert(method, path[:i], nil, skind, "", nil, e) pnames = append(pnames, "_*") - r.insert(method, path[:i+1], h, mkind, ppath, pnames, e) + r.insert(method, path[:i+1], h, akind, ppath, pnames, e) return } } @@ -286,6 +286,7 @@ func (n *node) check405() HandlerFunc { // Find dispatches the request to the handler whos route is matched with the // specified request path. func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo) { + // r.tree.printTree("", true) h = notFoundHandler e = r.echo cn := r.tree // Current node as root @@ -299,7 +300,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo ns string // Next search ) - // Search order static > param > match-any + // Search order static > param > any for { if search == "" { goto End @@ -329,12 +330,11 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo search = ns if nk == pkind { goto Param - } else if nk == mkind { - goto MatchAny - } else { - // Not found - return + } else if nk == akind { + goto Any } + // Not found + return } if search == "" { @@ -342,8 +342,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo } // Static node - c = cn.findChild(search[0], skind) - if c != nil { + if c = cn.findChild(search[0], skind); c != nil { // Save next if cn.label == '/' { nk = pkind @@ -356,11 +355,10 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo // Param node Param: - c = cn.findChildByKind(pkind) - if c != nil { + if c = cn.findChildByKind(pkind); c != nil { // Save next if cn.label == '/' { - nk = mkind + nk = akind nn = cn ns = search } @@ -374,10 +372,16 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo continue } - // Match-any node - MatchAny: - // c = cn.getChild() - if cn = cn.findChildByKind(mkind); cn == nil { + // Any node + Any: + if cn = cn.findChildByKind(akind); cn == nil { + cn = nn + search = ns + if nk == pkind { + goto Param + } else if nk == akind { + goto Any + } // Not found return } @@ -397,9 +401,9 @@ End: if h == nil { h = cn.check405() - // Dig further for match-any, might have an empty value for *, e.g. + // Dig further for any, might have an empty value for *, e.g. // serving a directory. Issue #207. - if cn = cn.findChildByKind(mkind); cn == nil { + if cn = cn.findChildByKind(akind); cn == nil { return } ctx.pvalues[len(cn.pnames)-1] = "" diff --git a/router_test.go b/router_test.go index c33572234..c0ffc6b6b 100644 --- a/router_test.go +++ b/router_test.go @@ -503,6 +503,70 @@ func TestRouterPriority(t *testing.T) { } } +// Issue #217 +func TestRouterPriorityNext(t *testing.T) { + e := New() + r := e.router + + // Routes + r.Add(GET, "/aa", func(c *Context) error { + c.Set("a", 1) + return nil + }, e) + r.Add(GET, "/ab", func(c *Context) error { + c.Set("b", 2) + return nil + }, e) + r.Add(GET, "/abc", func(c *Context) error { + c.Set("c", 3) + return nil + }, e) + r.Add(GET, "/abd", func(c *Context) error { + c.Set("d", 4) + return nil + }, e) + r.Add(GET, "/*", func(c *Context) error { + c.Set("e", 5) + return nil + }, e) + c := NewContext(nil, nil, e) + + // Route > /aa + h, _ := r.Find(GET, "/aa", c) + if assert.NotNil(t, h) { + h(c) + assert.Equal(t, 1, c.Get("a")) + } + + // Route > /ab + h, _ = r.Find(GET, "/ab", c) + if assert.NotNil(t, h) { + h(c) + assert.Equal(t, 2, c.Get("b")) + } + + // Route > /abc + h, _ = r.Find(GET, "/abc", c) + if assert.NotNil(t, h) { + h(c) + assert.Equal(t, 3, c.Get("c")) + } + + // Route > /abd + h, _ = r.Find(GET, "/abd", c) + if assert.NotNil(t, h) { + h(c) + assert.Equal(t, 4, c.Get("d")) + } + + // Route > /* + h, _ = r.Find(GET, "/abc.html", c) + if assert.NotNil(t, h) { + h(c) + assert.Equal(t, 5, c.Get("e")) + } +} + func TestRouterParamNames(t *testing.T) { e := New() r := e.router From feef0c0b8f928fa361f288b0ea1ea6a754a78b9d Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Wed, 24 Feb 2016 08:55:08 -0800 Subject: [PATCH 48/67] Fixed #372 Signed-off-by: Vishal Rana --- router.go | 15 ++++++---- router_test.go | 75 +++++++++++++++++--------------------------------- 2 files changed, 35 insertions(+), 55 deletions(-) diff --git a/router.go b/router.go index b0bbed20c..9da3cee3c 100644 --- a/router.go +++ b/router.go @@ -375,12 +375,15 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo // Any node Any: if cn = cn.findChildByKind(akind); cn == nil { - cn = nn - search = ns - if nk == pkind { - goto Param - } else if nk == akind { - goto Any + if nn != nil { + cn = nn + nn = nil // Next + search = ns + if nk == pkind { + goto Param + } else if nk == akind { + goto Any + } } // Not found return diff --git a/router_test.go b/router_test.go index c0ffc6b6b..c3c6207a3 100644 --- a/router_test.go +++ b/router_test.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "net/http/httptest" + "strconv" "testing" "github.com/stretchr/testify/assert" @@ -503,67 +504,43 @@ func TestRouterPriority(t *testing.T) { } } -// Issue #217 +// Issue #217, #372 func TestRouterPriorityNext(t *testing.T) { e := New() r := e.router - // Routes - r.Add(GET, "/aa", func(c *Context) error { - c.Set("a", 1) - return nil - }, e) - r.Add(GET, "/ab", func(c *Context) error { - c.Set("b", 2) - return nil - }, e) - r.Add(GET, "/abc", func(c *Context) error { - c.Set("c", 3) - return nil - }, e) - r.Add(GET, "/abd", func(c *Context) error { - c.Set("d", 4) - return nil - }, e) - r.Add(GET, "/*", func(c *Context) error { - c.Set("e", 5) - return nil - }, e) - c := NewContext(nil, nil, e) - - // Route > /aa - h, _ := r.Find(GET, "/aa", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 1, c.Get("a")) + routes := []Route{ + {"GET", "/aa", nil}, + {"GET", "/ab", nil}, + {"GET", "/abc", nil}, + {"GET", "/abd", nil}, + {"GET", "/a/foo", nil}, + {"GET", "/a/bar", nil}, + {"GET", "/*", nil}, } - // Route > /ab - h, _ = r.Find(GET, "/ab", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 2, c.Get("b")) - } - - // Route > /abc - h, _ = r.Find(GET, "/abc", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 3, c.Get("c")) + for i, route := range routes { + a := strconv.Itoa(i) + r.Add(route.Method, route.Path, func(c *Context) error { + c.Set(a, a) + return nil + }, e) } - - // Route > /abd - h, _ = r.Find(GET, "/abd", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 4, c.Get("d")) + c := NewContext(nil, nil, e) + for i, route := range routes { + a := strconv.Itoa(i) + h, _ := r.Find(route.Method, route.Path, c) + if assert.NotNil(t, h) { + h(c) + assert.Equal(t, a, c.Get(a)) + } } // Route > /* - h, _ = r.Find(GET, "/abc.html", c) + h, _ := r.Find(GET, "/abc.html", c) if assert.NotNil(t, h) { h(c) - assert.Equal(t, 5, c.Get("e")) + assert.Equal(t, "abc.html", c.P(0)) } } From 30ee5fbb95aa1fc1c09f101fc7f9a1022a78da38 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Wed, 24 Feb 2016 11:50:28 -0800 Subject: [PATCH 49/67] Enhanced router tests Signed-off-by: Vishal Rana --- router_test.go | 293 ++++++++++++++++++++++++------------------------- 1 file changed, 146 insertions(+), 147 deletions(-) diff --git a/router_test.go b/router_test.go index c3c6207a3..2750198ef 100644 --- a/router_test.go +++ b/router_test.go @@ -4,7 +4,6 @@ import ( "fmt" "net/http" "net/http/httptest" - "strconv" "testing" "github.com/stretchr/testify/assert" @@ -285,10 +284,8 @@ func TestRouterStatic(t *testing.T) { }, e) c := NewContext(nil, nil, e) h, _ := r.Find(GET, path, c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, path, c.Get("path")) - } + h(c) + assert.Equal(t, path, c.Get("path")) } func TestRouterParam(t *testing.T) { @@ -298,10 +295,8 @@ func TestRouterParam(t *testing.T) { return nil }, e) c := NewContext(nil, nil, e) - h, _ := r.Find(GET, "/users/1", c) - if assert.NotNil(t, h) { - assert.Equal(t, "1", c.P(0)) - } + r.Find(GET, "/users/1", c) + assert.Equal(t, "1", c.P(0)) } func TestRouterTwoParam(t *testing.T) { @@ -311,44 +306,39 @@ func TestRouterTwoParam(t *testing.T) { return nil }, e) c := NewContext(nil, nil, e) - - h, _ := r.Find(GET, "/users/1/files/1", c) - if assert.NotNil(t, h) { - assert.Equal(t, "1", c.P(0)) - assert.Equal(t, "1", c.P(1)) - } + r.Find(GET, "/users/1/files/1", c) + assert.Equal(t, "1", c.P(0)) + assert.Equal(t, "1", c.P(1)) } func TestRouterMatchAny(t *testing.T) { e := New() r := e.router - // Routes + // Add r.Add(GET, "/", func(*Context) error { return nil }, e) + r.Add(GET, "/*", func(*Context) error { return nil }, e) + r.Add(GET, "/users/*", func(*Context) error { return nil }, e) + c := NewContext(nil, nil, e) - h, _ := r.Find(GET, "/", c) - if assert.NotNil(t, h) { - assert.Equal(t, "", c.P(0)) - } + // Find + r.Find(GET, "/", c) + assert.Equal(t, "", c.P(0)) - h, _ = r.Find(GET, "/download", c) - if assert.NotNil(t, h) { - assert.Equal(t, "download", c.P(0)) - } + r.Find(GET, "/download", c) + assert.Equal(t, "download", c.P(0)) - h, _ = r.Find(GET, "/users/joe", c) - if assert.NotNil(t, h) { - assert.Equal(t, "joe", c.P(0)) - } + r.Find(GET, "/users/joe", c) + assert.Equal(t, "joe", c.P(0)) } func TestRouterMicroParam(t *testing.T) { @@ -358,12 +348,10 @@ func TestRouterMicroParam(t *testing.T) { return nil }, e) c := NewContext(nil, nil, e) - h, _ := r.Find(GET, "/1/2/3", c) - if assert.NotNil(t, h) { - assert.Equal(t, "1", c.P(0)) - assert.Equal(t, "2", c.P(1)) - assert.Equal(t, "3", c.P(2)) - } + r.Find(GET, "/1/2/3", c) + assert.Equal(t, "1", c.P(0)) + assert.Equal(t, "2", c.P(1)) + assert.Equal(t, "3", c.P(2)) } func TestRouterMixParamMatchAny(t *testing.T) { @@ -377,40 +365,33 @@ func TestRouterMixParamMatchAny(t *testing.T) { c := NewContext(nil, nil, e) h, _ := r.Find(GET, "/users/joe/comments", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, "joe", c.P(0)) - } + h(c) + assert.Equal(t, "joe", c.P(0)) } func TestRouterMultiRoute(t *testing.T) { e := New() r := e.router - // Routes + // Add r.Add(GET, "/users", func(c *Context) error { c.Set("path", "/users") return nil }, e) + r.Add(GET, "/users/:id", func(c *Context) error { return nil }, e) c := NewContext(nil, nil, e) - // Route > /users + // Find h, _ := r.Find(GET, "/users", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, "/users", c.Get("path")) - } + h(c) + assert.Equal(t, "/users", c.Get("path")) - // Route > /users/:id h, _ = r.Find(GET, "/users/1", c) - if assert.NotNil(t, h) { - assert.Equal(t, "1", c.P(0)) - } + assert.Equal(t, "1", c.P(0)) - // Route > /user h, _ = r.Find(GET, "/user", c) if assert.IsType(t, new(HTTPError), h(c)) { he := h(c).(*HTTPError) @@ -422,167 +403,188 @@ func TestRouterPriority(t *testing.T) { e := New() r := e.router - // Routes + // Add r.Add(GET, "/users", func(c *Context) error { c.Set("a", 1) return nil }, e) + r.Add(GET, "/users/new", func(c *Context) error { c.Set("b", 2) return nil }, e) + r.Add(GET, "/users/:id", func(c *Context) error { c.Set("c", 3) return nil }, e) + r.Add(GET, "/users/dew", func(c *Context) error { c.Set("d", 4) return nil }, e) + r.Add(GET, "/users/:id/files", func(c *Context) error { c.Set("e", 5) return nil }, e) + r.Add(GET, "/users/newsee", func(c *Context) error { c.Set("f", 6) return nil }, e) + r.Add(GET, "/users/*", func(c *Context) error { c.Set("g", 7) return nil }, e) + c := NewContext(nil, nil, e) - // Route > /users + // Find h, _ := r.Find(GET, "/users", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 1, c.Get("a")) - } + h(c) + assert.Equal(t, 1, c.Get("a")) - // Route > /users/new h, _ = r.Find(GET, "/users/new", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 2, c.Get("b")) - } + h(c) + assert.Equal(t, 2, c.Get("b")) - // Route > /users/:id h, _ = r.Find(GET, "/users/1", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 3, c.Get("c")) - } + h(c) + assert.Equal(t, 3, c.Get("c")) - // Route > /users/dew h, _ = r.Find(GET, "/users/dew", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 4, c.Get("d")) - } + h(c) + assert.Equal(t, 4, c.Get("d")) - // Route > /users/:id/files h, _ = r.Find(GET, "/users/1/files", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 5, c.Get("e")) - } + h(c) + assert.Equal(t, 5, c.Get("e")) - // Route > /users/:id h, _ = r.Find(GET, "/users/news", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 3, c.Get("c")) - } + h(c) + assert.Equal(t, 3, c.Get("c")) - // Route > /users/* h, _ = r.Find(GET, "/users/joe/books", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, 7, c.Get("g")) - assert.Equal(t, "joe/books", c.Param("_*")) - } + h(c) + assert.Equal(t, 7, c.Get("g")) + assert.Equal(t, "joe/books", c.Param("_*")) } -// Issue #217, #372 -func TestRouterPriorityNext(t *testing.T) { +// Issue #217 +func TestRouterPriorityParamAny(t *testing.T) { e := New() r := e.router - routes := []Route{ - {"GET", "/aa", nil}, - {"GET", "/ab", nil}, - {"GET", "/abc", nil}, - {"GET", "/abd", nil}, - {"GET", "/a/foo", nil}, - {"GET", "/a/bar", nil}, - {"GET", "/*", nil}, - } + // Add + r.Add(GET, "/aa", func(c *Context) error { + c.Set("a", 1) + return nil + }, e) + + r.Add(GET, "/ab", func(c *Context) error { + c.Set("b", 2) + return nil + }, e) + + r.Add(GET, "/ab/:name", func(c *Context) error { + c.Set("c", 3) + return nil + }, e) + + r.Add(GET, "/ab/*", func(c *Context) error { + c.Set("d", 4) + return nil + }, e) + + r.Add(GET, "/*", func(c *Context) error { + c.Set("e", 5) + return nil + }, e) - for i, route := range routes { - a := strconv.Itoa(i) - r.Add(route.Method, route.Path, func(c *Context) error { - c.Set(a, a) - return nil - }, e) - } c := NewContext(nil, nil, e) - for i, route := range routes { - a := strconv.Itoa(i) - h, _ := r.Find(route.Method, route.Path, c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, a, c.Get(a)) - } - } - // Route > /* - h, _ := r.Find(GET, "/abc.html", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, "abc.html", c.P(0)) - } + // Find + h, _ := r.Find(GET, "/aa", c) + h(c) + assert.Equal(t, 1, c.Get("a")) + + h, _ = r.Find(GET, "/ab", c) + h(c) + assert.Equal(t, 2, c.Get("b")) + + h, _ = r.Find(GET, "/ab/joe", c) + h(c) + assert.Equal(t, 3, c.Get("c")) + + h, _ = r.Find(GET, "/abc.html", c) + h(c) + assert.Equal(t, 5, c.Get("e")) +} + +// Issue #372 +func TestRouterPriorityNotFound(t *testing.T) { + e := New() + r := e.router + c := NewContext(nil, nil, e) + + // Add + r.Add(GET, "/a/foo", func(c *Context) error { + c.Set("a", 1) + return nil + }, e) + r.Add(GET, "/a/bar", func(c *Context) error { + c.Set("b", 2) + return nil + }, e) + + // Find + h, _ := r.Find(GET, "/a/foo", c) + h(c) + assert.Equal(t, 1, c.Get("a")) + h, _ = r.Find(GET, "/a/bar", c) + h(c) + assert.Equal(t, 2, c.Get("b")) + h, _ = r.Find(GET, "/abc/def", c) + he := h(c).(*HTTPError) + assert.Equal(t, http.StatusNotFound, he.Code()) } func TestRouterParamNames(t *testing.T) { e := New() r := e.router - // Routes + // Add r.Add(GET, "/users", func(c *Context) error { c.Set("path", "/users") return nil }, e) + r.Add(GET, "/users/:id", func(c *Context) error { return nil }, e) + r.Add(GET, "/users/:uid/files/:fid", func(c *Context) error { return nil }, e) + c := NewContext(nil, nil, e) - // Route > /users + // Find h, _ := r.Find(GET, "/users", c) - if assert.NotNil(t, h) { - h(c) - assert.Equal(t, "/users", c.Get("path")) - } - - // Route > /users/:id - h, _ = r.Find(GET, "/users/1", c) - if assert.NotNil(t, h) { - assert.Equal(t, "id", c.pnames[0]) - assert.Equal(t, "1", c.P(0)) - } - - // Route > /users/:uid/files/:fid - h, _ = r.Find(GET, "/users/1/files/1", c) - if assert.NotNil(t, h) { - assert.Equal(t, "uid", c.pnames[0]) - assert.Equal(t, "1", c.P(0)) - assert.Equal(t, "fid", c.pnames[1]) - assert.Equal(t, "1", c.P(1)) - } + h(c) + assert.Equal(t, "/users", c.Get("path")) + + r.Find(GET, "/users/1", c) + assert.Equal(t, "id", c.pnames[0]) + assert.Equal(t, "1", c.P(0)) + + r.Find(GET, "/users/1/files/1", c) + assert.Equal(t, "uid", c.pnames[0]) + assert.Equal(t, "1", c.P(0)) + assert.Equal(t, "fid", c.pnames[1]) + assert.Equal(t, "1", c.P(1)) } func TestRouterAPI(t *testing.T) { @@ -596,14 +598,11 @@ func TestRouterAPI(t *testing.T) { } c := NewContext(nil, nil, e) for _, route := range api { - h, _ := r.Find(route.Method, route.Path, c) - if assert.NotNil(t, h) { - for i, n := range c.pnames { - if assert.NotEmpty(t, n) { - assert.Equal(t, ":"+n, c.P(i)) - } + r.Find(route.Method, route.Path, c) + for i, n := range c.pnames { + if assert.NotEmpty(t, n) { + assert.Equal(t, ":"+n, c.P(i)) } - h(c) } } } From 2f091ad5448fdd6ac613b1d6ee9d5eb085db9ec5 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Thu, 3 Mar 2016 22:48:42 -0800 Subject: [PATCH 50/67] Updated website Signed-off-by: Vishal Rana --- website/config.json | 1 + website/layouts/partials/head.html | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/website/config.json b/website/config.json index ab6d64eee..45d4e310c 100644 --- a/website/config.json +++ b/website/config.json @@ -21,6 +21,7 @@ }, "params": { + "description": "Golang micro web framework, High performance, Minimalistic and Fast.", "googleAnayticsId": "UA-51208124-3" } } diff --git a/website/layouts/partials/head.html b/website/layouts/partials/head.html index 1566178df..581a029bc 100644 --- a/website/layouts/partials/head.html +++ b/website/layouts/partials/head.html @@ -5,9 +5,9 @@ - {{ if ne .URL "/" }}{{ .Title }} | {{ end }}{{ .Site.Title }} + {{ .Site.Title }} - {{ .Site.Params.description }}{{ if ne .URL "/" }} - {{ .Title }} {{ end }} - + From 4686b25efcae07b7e31174299add14cdce48995b Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 5 Mar 2016 11:13:24 -0800 Subject: [PATCH 51/67] Updated website Signed-off-by: Vishal Rana --- website/content/recipes/crud.md | 2 +- website/content/recipes/embed-resources.md | 2 +- website/content/recipes/file-upload.md | 2 +- website/content/recipes/google-app-engine.md | 2 +- website/content/recipes/graceful-shutdown.md | 4 ++-- website/content/recipes/hello-world.md | 2 +- website/content/recipes/jsonp.md | 2 +- website/content/recipes/jwt-authentication.md | 2 +- website/content/recipes/middleware.md | 2 +- website/content/recipes/streaming-file-upload.md | 2 +- website/content/recipes/streaming-response.md | 2 +- website/content/recipes/subdomains.md | 2 +- website/content/recipes/website.md | 2 +- website/content/recipes/websocket.md | 2 +- website/static/styles/echo.css | 2 +- 15 files changed, 16 insertions(+), 16 deletions(-) diff --git a/website/content/recipes/crud.md b/website/content/recipes/crud.md index 65b1a0997..c4afe762a 100644 --- a/website/content/recipes/crud.md +++ b/website/content/recipes/crud.md @@ -16,4 +16,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/crud) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/crud) diff --git a/website/content/recipes/embed-resources.md b/website/content/recipes/embed-resources.md index 2b8ad44ac..ddbd9073b 100644 --- a/website/content/recipes/embed-resources.md +++ b/website/content/recipes/embed-resources.md @@ -17,4 +17,4 @@ menu: - [caarlos0](https://github.com/caarlos0) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/rice) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/rice) diff --git a/website/content/recipes/file-upload.md b/website/content/recipes/file-upload.md index 36582e63a..ac0e185e3 100644 --- a/website/content/recipes/file-upload.md +++ b/website/content/recipes/file-upload.md @@ -50,4 +50,4 @@ if _, err = io.Copy(dst, file); err != nil { - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/file-upload) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/file-upload) diff --git a/website/content/recipes/google-app-engine.md b/website/content/recipes/google-app-engine.md index bbfe35725..934d30b22 100644 --- a/website/content/recipes/google-app-engine.md +++ b/website/content/recipes/google-app-engine.md @@ -132,4 +132,4 @@ but is outside the scope of this recipe. - [CaptainCodeman](https://github.com/CaptainCodeman) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/google-app-engine) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/google-app-engine) diff --git a/website/content/recipes/graceful-shutdown.md b/website/content/recipes/graceful-shutdown.md index f2516138c..dbd6a3b3f 100644 --- a/website/content/recipes/graceful-shutdown.md +++ b/website/content/recipes/graceful-shutdown.md @@ -24,6 +24,6 @@ menu: ### Source Code -[graceful](https://github.com/vishr/recipes/blob/master/echo/recipes/graceful-shutdown/graceful) +[graceful](https://github.com/vishr/recipes/blob/master/echo.v1/graceful-shutdown/graceful) -[grace](https://github.com/vishr/recipes/blob/master/echo/recipes/graceful-shutdown/grace) +[grace](https://github.com/vishr/recipes/blob/master/echo.v1/graceful-shutdown/grace) diff --git a/website/content/recipes/hello-world.md b/website/content/recipes/hello-world.md index 94fa555f0..3dd6659b1 100644 --- a/website/content/recipes/hello-world.md +++ b/website/content/recipes/hello-world.md @@ -16,4 +16,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/hello-world) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/hello-world) diff --git a/website/content/recipes/jsonp.md b/website/content/recipes/jsonp.md index 07ad7c7d4..628383333 100644 --- a/website/content/recipes/jsonp.md +++ b/website/content/recipes/jsonp.md @@ -24,4 +24,4 @@ JSONP is a method that allows cross-domain server calls. You can read more about - [willf](https://github.com/willf) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/jsonp) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/jsonp) diff --git a/website/content/recipes/jwt-authentication.md b/website/content/recipes/jwt-authentication.md index 938c119ec..32a10ce5e 100644 --- a/website/content/recipes/jwt-authentication.md +++ b/website/content/recipes/jwt-authentication.md @@ -55,4 +55,4 @@ $ curl localhost:1323/restricted -H "Authorization: Bearer " => Access g - [axdg](https://github.com/axdg) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/jwt-authentication) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/jwt-authentication) diff --git a/website/content/recipes/middleware.md b/website/content/recipes/middleware.md index 6e0000585..8c25e96da 100644 --- a/website/content/recipes/middleware.md +++ b/website/content/recipes/middleware.md @@ -17,4 +17,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/middleware) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/middleware) diff --git a/website/content/recipes/streaming-file-upload.md b/website/content/recipes/streaming-file-upload.md index ea02aa48f..2c28f0095 100644 --- a/website/content/recipes/streaming-file-upload.md +++ b/website/content/recipes/streaming-file-upload.md @@ -25,4 +25,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/streaming-file-upload) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/streaming-file-upload) diff --git a/website/content/recipes/streaming-response.md b/website/content/recipes/streaming-response.md index e9533526c..274826c5e 100644 --- a/website/content/recipes/streaming-response.md +++ b/website/content/recipes/streaming-response.md @@ -35,4 +35,4 @@ $ curl localhost:1323 - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/streaming-response) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/streaming-response) diff --git a/website/content/recipes/subdomains.md b/website/content/recipes/subdomains.md index 50b2a956a..e22c16fe3 100644 --- a/website/content/recipes/subdomains.md +++ b/website/content/recipes/subdomains.md @@ -15,4 +15,4 @@ menu: - [axdg](https://github.com/axdg) - [vishr](https://github.com/axdg) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/subdomains) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/subdomains) diff --git a/website/content/recipes/website.md b/website/content/recipes/website.md index 2ea3e5b9f..5029e39ca 100644 --- a/website/content/recipes/website.md +++ b/website/content/recipes/website.md @@ -22,4 +22,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/website) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/website) diff --git a/website/content/recipes/websocket.md b/website/content/recipes/websocket.md index 03fa7a3d2..f43ce115f 100644 --- a/website/content/recipes/websocket.md +++ b/website/content/recipes/websocket.md @@ -44,4 +44,4 @@ Hello, Server! - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo/recipes/websocket) +### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/websocket) diff --git a/website/static/styles/echo.css b/website/static/styles/echo.css index 97191d687..6b4377723 100644 --- a/website/static/styles/echo.css +++ b/website/static/styles/echo.css @@ -15,7 +15,7 @@ footer { color: #333; } :not(pre) > code { - padding: 2px 4px; + padding: 0 4px; background: #EEE; color: #424242; font-size: .95em; From e4f3900c40121e003de983998aafb388e8142586 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 5 Mar 2016 14:34:34 -0800 Subject: [PATCH 52/67] Updated website Signed-off-by: Vishal Rana --- website/content/recipes/crud.md | 2 +- website/content/recipes/embed-resources.md | 2 +- website/content/recipes/file-upload.md | 2 +- website/content/recipes/google-app-engine.md | 2 +- website/content/recipes/graceful-shutdown.md | 4 ++-- website/content/recipes/hello-world.md | 2 +- website/content/recipes/jsonp.md | 2 +- website/content/recipes/jwt-authentication.md | 2 +- website/content/recipes/middleware.md | 2 +- website/content/recipes/streaming-file-upload.md | 2 +- website/content/recipes/streaming-response.md | 2 +- website/content/recipes/subdomains.md | 2 +- website/content/recipes/website.md | 2 +- website/content/recipes/websocket.md | 2 +- website/layouts/shortcodes/embed.html | 2 +- 15 files changed, 16 insertions(+), 16 deletions(-) diff --git a/website/content/recipes/crud.md b/website/content/recipes/crud.md index c4afe762a..eea4a4969 100644 --- a/website/content/recipes/crud.md +++ b/website/content/recipes/crud.md @@ -16,4 +16,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/crud) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/crud) diff --git a/website/content/recipes/embed-resources.md b/website/content/recipes/embed-resources.md index ddbd9073b..e66e525a2 100644 --- a/website/content/recipes/embed-resources.md +++ b/website/content/recipes/embed-resources.md @@ -17,4 +17,4 @@ menu: - [caarlos0](https://github.com/caarlos0) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/rice) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/rice) diff --git a/website/content/recipes/file-upload.md b/website/content/recipes/file-upload.md index ac0e185e3..907e201c0 100644 --- a/website/content/recipes/file-upload.md +++ b/website/content/recipes/file-upload.md @@ -50,4 +50,4 @@ if _, err = io.Copy(dst, file); err != nil { - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/file-upload) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/file-upload) diff --git a/website/content/recipes/google-app-engine.md b/website/content/recipes/google-app-engine.md index 934d30b22..df9b8bb4f 100644 --- a/website/content/recipes/google-app-engine.md +++ b/website/content/recipes/google-app-engine.md @@ -132,4 +132,4 @@ but is outside the scope of this recipe. - [CaptainCodeman](https://github.com/CaptainCodeman) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/google-app-engine) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/google-app-engine) diff --git a/website/content/recipes/graceful-shutdown.md b/website/content/recipes/graceful-shutdown.md index dbd6a3b3f..98b94be0b 100644 --- a/website/content/recipes/graceful-shutdown.md +++ b/website/content/recipes/graceful-shutdown.md @@ -24,6 +24,6 @@ menu: ### Source Code -[graceful](https://github.com/vishr/recipes/blob/master/echo.v1/graceful-shutdown/graceful) +[graceful](https://github.com/vishr/echo-recipes/blob/master/v1/graceful-shutdown/graceful) -[grace](https://github.com/vishr/recipes/blob/master/echo.v1/graceful-shutdown/grace) +[grace](https://github.com/vishr/echo-recipes/blob/master/v1/graceful-shutdown/grace) diff --git a/website/content/recipes/hello-world.md b/website/content/recipes/hello-world.md index 3dd6659b1..b71a8ff53 100644 --- a/website/content/recipes/hello-world.md +++ b/website/content/recipes/hello-world.md @@ -16,4 +16,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/hello-world) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/hello-world) diff --git a/website/content/recipes/jsonp.md b/website/content/recipes/jsonp.md index 628383333..821a684e6 100644 --- a/website/content/recipes/jsonp.md +++ b/website/content/recipes/jsonp.md @@ -24,4 +24,4 @@ JSONP is a method that allows cross-domain server calls. You can read more about - [willf](https://github.com/willf) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/jsonp) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/jsonp) diff --git a/website/content/recipes/jwt-authentication.md b/website/content/recipes/jwt-authentication.md index 32a10ce5e..e92bf30ce 100644 --- a/website/content/recipes/jwt-authentication.md +++ b/website/content/recipes/jwt-authentication.md @@ -55,4 +55,4 @@ $ curl localhost:1323/restricted -H "Authorization: Bearer " => Access g - [axdg](https://github.com/axdg) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/jwt-authentication) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/jwt-authentication) diff --git a/website/content/recipes/middleware.md b/website/content/recipes/middleware.md index 8c25e96da..7ea7f05c4 100644 --- a/website/content/recipes/middleware.md +++ b/website/content/recipes/middleware.md @@ -17,4 +17,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/middleware) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/middleware) diff --git a/website/content/recipes/streaming-file-upload.md b/website/content/recipes/streaming-file-upload.md index 2c28f0095..43d2ccdd5 100644 --- a/website/content/recipes/streaming-file-upload.md +++ b/website/content/recipes/streaming-file-upload.md @@ -25,4 +25,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/streaming-file-upload) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/streaming-file-upload) diff --git a/website/content/recipes/streaming-response.md b/website/content/recipes/streaming-response.md index 274826c5e..5949a370f 100644 --- a/website/content/recipes/streaming-response.md +++ b/website/content/recipes/streaming-response.md @@ -35,4 +35,4 @@ $ curl localhost:1323 - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/streaming-response) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/streaming-response) diff --git a/website/content/recipes/subdomains.md b/website/content/recipes/subdomains.md index e22c16fe3..e0e5c8011 100644 --- a/website/content/recipes/subdomains.md +++ b/website/content/recipes/subdomains.md @@ -15,4 +15,4 @@ menu: - [axdg](https://github.com/axdg) - [vishr](https://github.com/axdg) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/subdomains) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/subdomains) diff --git a/website/content/recipes/website.md b/website/content/recipes/website.md index 5029e39ca..69196422e 100644 --- a/website/content/recipes/website.md +++ b/website/content/recipes/website.md @@ -22,4 +22,4 @@ menu: - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/website) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/website) diff --git a/website/content/recipes/websocket.md b/website/content/recipes/websocket.md index f43ce115f..7cb428947 100644 --- a/website/content/recipes/websocket.md +++ b/website/content/recipes/websocket.md @@ -44,4 +44,4 @@ Hello, Server! - [vishr](https://github.com/vishr) -### [Source Code](https://github.com/vishr/recipes/blob/master/echo.v1/websocket) +### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/websocket) diff --git a/website/layouts/shortcodes/embed.html b/website/layouts/shortcodes/embed.html index 9de428b2d..201236036 100644 --- a/website/layouts/shortcodes/embed.html +++ b/website/layouts/shortcodes/embed.html @@ -1,2 +1,2 @@ -
+
 
From d6af11ec08fa66ae397bdb7578fab4ff28403228 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sun, 6 Mar 2016 09:04:04 -0800 Subject: [PATCH 53/67] Fixed #364 & #377 Signed-off-by: Vishal Rana --- echo.go | 42 +++++++++++--------------- website/content/guide/customization.md | 8 +---- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/echo.go b/echo.go index c069f350b..4bbedf83c 100644 --- a/echo.go +++ b/echo.go @@ -60,28 +60,10 @@ type ( debug bool hook http.HandlerFunc autoIndex bool - logger Logger + logger *log.Logger router *Router } - // Logger is the interface that declares echo's logging system. - Logger interface { - Debug(...interface{}) - Debugf(string, ...interface{}) - - Info(...interface{}) - Infof(string, ...interface{}) - - Warn(...interface{}) - Warnf(string, ...interface{}) - - Error(...interface{}) - Errorf(string, ...interface{}) - - Fatal(...interface{}) - Fatalf(string, ...interface{}) - } - // Route contains a handler and information for matching against requests. Route struct { Method string @@ -242,6 +224,7 @@ func New() (e *Echo) { // Logger e.logger = log.New("echo") + e.SetLogLevel(log.FATAL) return } @@ -251,13 +234,23 @@ func (e *Echo) Router() *Router { return e.router } -// SetLogger sets the logger instance. -func (e *Echo) SetLogger(logger Logger) { - e.logger = logger +// SetLogPrefix sets the prefix for the logger. Default value is `echo`. +func (e *Echo) SetLogPrefix(prefix string) { + e.logger.SetPrefix(prefix) +} + +// SetLogOutput sets the output destination for the logger. Default value is `os.Std*` +func (e *Echo) SetLogOutput(w io.Writer) { + e.logger.SetOutput(w) +} + +// SetLogLevel sets the log level for the logger. Default value is `log.FATAL`. +func (e *Echo) SetLogLevel(l log.Level) { + e.logger.SetLevel(l) } // Logger returns the logger instance. -func (e *Echo) Logger() Logger { +func (e *Echo) Logger() *log.Logger { return e.logger } @@ -275,7 +268,7 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c *Context) { if !c.response.committed { http.Error(c.response, msg, code) } - e.logger.Error(err) + e.logger.Debug(err) } // SetHTTPErrorHandler registers a custom Echo.HTTPErrorHandler. @@ -296,6 +289,7 @@ func (e *Echo) SetRenderer(r Renderer) { // SetDebug enable/disable debug mode. func (e *Echo) SetDebug(on bool) { e.debug = on + e.SetLogLevel(log.FATAL) } // Debug returns debug mode (enabled or disabled). diff --git a/website/content/guide/customization.md b/website/content/guide/customization.md index 4897e3ff9..eecedce81 100644 --- a/website/content/guide/customization.md +++ b/website/content/guide/customization.md @@ -41,13 +41,7 @@ SetLogOutput sets the output destination for the logger. Default value is `os.St `echo#SetLogLevel(l log.Level)` -SetLogLevel sets the log level for the logger. Default value is `log.INFO`. - -### HTTP2 - -`echo#HTTP2(on bool)` - -Enable/disable HTTP2 support. +SetLogLevel sets the log level for the logger. Default value is `log.FATAL`. ### Auto index From 56e678ff4dec78fdd27dc2dc57cc4ce5d016e86f Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sun, 6 Mar 2016 09:10:42 -0800 Subject: [PATCH 54/67] Logger test cases Signed-off-by: Vishal Rana --- echo_test.go | 6 ------ middleware/logger.go | 2 +- middleware/logger_test.go | 7 ++----- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/echo_test.go b/echo_test.go index 72e37ceb7..ceb9b0c70 100644 --- a/echo_test.go +++ b/echo_test.go @@ -12,7 +12,6 @@ import ( "errors" - "github.com/labstack/gommon/log" "github.com/stretchr/testify/assert" "golang.org/x/net/websocket" ) @@ -41,11 +40,6 @@ func TestEcho(t *testing.T) { e.DefaultHTTPErrorHandler(errors.New("error"), c) assert.Equal(t, http.StatusInternalServerError, rec.Code) - // Logger - l := log.New("test") - e.SetLogger(l) - assert.Equal(t, l, e.Logger()) - // Autoindex e.AutoIndex(true) assert.True(t, e.autoIndex) diff --git a/middleware/logger.go b/middleware/logger.go index 8aa6f52cd..a28b9e2cc 100644 --- a/middleware/logger.go +++ b/middleware/logger.go @@ -52,7 +52,7 @@ func Logger() echo.MiddlewareFunc { code = color.Cyan(n) } - logger.Infof(format, remoteAddr, method, path, code, stop.Sub(start), size) + logger.Printf(format, remoteAddr, method, path, code, stop.Sub(start), size) return nil } } diff --git a/middleware/logger_test.go b/middleware/logger_test.go index 3ae4970be..298154b4e 100644 --- a/middleware/logger_test.go +++ b/middleware/logger_test.go @@ -8,7 +8,6 @@ import ( "testing" "github.com/labstack/echo" - "github.com/labstack/gommon/log" "github.com/stretchr/testify/assert" ) @@ -53,13 +52,11 @@ func TestLogger(t *testing.T) { func TestLoggerIPAddress(t *testing.T) { e := echo.New() - l := log.New("echo") - buf := new(bytes.Buffer) - l.SetOutput(buf) - e.SetLogger(l) req, _ := http.NewRequest(echo.GET, "/", nil) rec := httptest.NewRecorder() c := echo.NewContext(req, echo.NewResponse(rec, e), e) + buf := new(bytes.Buffer) + e.Logger().SetOutput(buf) ip := "127.0.0.1" h := func(c *echo.Context) error { return c.String(http.StatusOK, "test") From dba674adf20af34a09c51b05adfda4ae020620c6 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sun, 6 Mar 2016 23:26:36 -0800 Subject: [PATCH 55/67] Closes #378 Signed-off-by: Vishal Rana --- router.go | 6 ++++++ router_test.go | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/router.go b/router.go index 9da3cee3c..644eceec7 100644 --- a/router.go +++ b/router.go @@ -356,6 +356,11 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo // Param node Param: if c = cn.findChildByKind(pkind); c != nil { + // Issue #378 + if len(ctx.pvalues) == n { + continue + } + // Save next if cn.label == '/' { nk = akind @@ -363,6 +368,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo ns = search } cn = c + i, l := 0, len(search) for ; i < l && search[i] != '/'; i++ { } diff --git a/router_test.go b/router_test.go index 2750198ef..867a32cfc 100644 --- a/router_test.go +++ b/router_test.go @@ -311,6 +311,25 @@ func TestRouterTwoParam(t *testing.T) { assert.Equal(t, "1", c.P(1)) } +// Issue #378 +func TestRouterParamWithSlash(t *testing.T) { + e := New() + r := e.router + + r.Add(GET, "/a/:b/c/d/:e", func(c *Context) error { + return nil + }, e) + + r.Add(GET, "/a/:b/c/:d/:f", func(c *Context) error { + return nil + }, e) + + c := NewContext(nil, nil, e) + assert.NotPanics(t, func() { + r.Find(GET, "/a/1/c/d/2/3", c) + }) +} + func TestRouterMatchAny(t *testing.T) { e := New() r := e.router From 52922ecd62fbc6dbdc1e24b1d3148301497e48a4 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Wed, 9 Mar 2016 20:37:30 -0800 Subject: [PATCH 56/67] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f2060e5cd..673606978 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +# *NOTICE* + +#### Soon master branch, website/docs and godoc will pointing to v2 branch, if you want to continue using v1, use a package manager to get a stable v1 release or latest commit, you can use https://github.com/Masterminds/glide, it's nice. You can also use `http://labix.org/gopkg.in` like `go get gopkg.in/labstack/echo.v1`. It is advisable to migrate to v2. + # [Echo](http://labstack.com/echo) [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/labstack/echo) [![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE) [![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo) [![Coverage Status](http://img.shields.io/coveralls/labstack/echo.svg?style=flat-square)](https://coveralls.io/r/labstack/echo) [![Join the chat at https://gitter.im/labstack/echo](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg?style=flat-square)](https://gitter.im/labstack/echo) A fast and unfancy micro web framework for Go. From ff0aaf378c08900176a997aac21893462956bc07 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Wed, 9 Mar 2016 20:38:20 -0800 Subject: [PATCH 57/67] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 673606978..8f322bb6f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # *NOTICE* -#### Soon master branch, website/docs and godoc will pointing to v2 branch, if you want to continue using v1, use a package manager to get a stable v1 release or latest commit, you can use https://github.com/Masterminds/glide, it's nice. You can also use `http://labix.org/gopkg.in` like `go get gopkg.in/labstack/echo.v1`. It is advisable to migrate to v2. +#### Soon master branch, website/docs and godoc will be pointing to v2 branch, if you want to continue using v1, use a package manager to get a stable v1 release or latest commit, you can use https://github.com/Masterminds/glide, it's nice. You can also use `http://labix.org/gopkg.in` like `go get gopkg.in/labstack/echo.v1`. It is advisable to migrate to v2. # [Echo](http://labstack.com/echo) [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/labstack/echo) [![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE) [![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo) [![Coverage Status](http://img.shields.io/coveralls/labstack/echo.svg?style=flat-square)](https://coveralls.io/r/labstack/echo) [![Join the chat at https://gitter.im/labstack/echo](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg?style=flat-square)](https://gitter.im/labstack/echo) From 46eefcb0b95d6d041b7234ce3b7bd45de1216537 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Wed, 9 Mar 2016 20:39:45 -0800 Subject: [PATCH 58/67] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f322bb6f..f2814417e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # *NOTICE* -#### Soon master branch, website/docs and godoc will be pointing to v2 branch, if you want to continue using v1, use a package manager to get a stable v1 release or latest commit, you can use https://github.com/Masterminds/glide, it's nice. You can also use `http://labix.org/gopkg.in` like `go get gopkg.in/labstack/echo.v1`. It is advisable to migrate to v2. +#### Soon master branch, website/docs and godoc will be pointing to v2 branch, if you want to continue using v1, use a package manager (https://github.com/Masterminds/glide, it's nice!) to get a stable v1 release or latest commit or you can use `https://gopkg.in` like `go get gopkg.in/labstack/echo.v1`. It is advisable to migrate to v2. # [Echo](http://labstack.com/echo) [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/labstack/echo) [![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE) [![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo) [![Coverage Status](http://img.shields.io/coveralls/labstack/echo.svg?style=flat-square)](https://coveralls.io/r/labstack/echo) [![Join the chat at https://gitter.im/labstack/echo](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg?style=flat-square)](https://gitter.im/labstack/echo) From b676ad11cf0d2c928012c0438df67a04b7c2c37f Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Wed, 9 Mar 2016 21:14:44 -0800 Subject: [PATCH 59/67] Updated website Signed-off-by: Vishal Rana --- website/content/recipes/subdomains.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/content/recipes/subdomains.md b/website/content/recipes/subdomains.md index e0e5c8011..3129ec6c9 100644 --- a/website/content/recipes/subdomains.md +++ b/website/content/recipes/subdomains.md @@ -3,7 +3,7 @@ title: Subdomains menu: side: parent: recipes - weight: 10 + weight: 10 --- `server.go` @@ -13,6 +13,6 @@ menu: ### Maintainers - [axdg](https://github.com/axdg) -- [vishr](https://github.com/axdg) +- [vishr](https://github.com/vishr) ### [Source Code](https://github.com/vishr/echo-recipes/blob/master/v1/subdomains) From 04c3a0269de492482ec5d69b90da5cef3072a78c Mon Sep 17 00:00:00 2001 From: William Riancho Date: Fri, 11 Mar 2016 11:06:06 +0100 Subject: [PATCH 60/67] Reference echo.v1 for every imports --- echo.go | 4 ++-- middleware/auth.go | 2 +- middleware/auth_test.go | 2 +- middleware/compress.go | 2 +- middleware/compress_test.go | 2 +- middleware/logger.go | 2 +- middleware/logger_test.go | 2 +- middleware/recover.go | 2 +- middleware/recover_test.go | 2 +- website/content/index.md | 6 +++--- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/echo.go b/echo.go index 4bbedf83c..15f9c5b0b 100644 --- a/echo.go +++ b/echo.go @@ -8,8 +8,8 @@ Example: import ( "net/http" - "github.com/labstack/echo" - mw "github.com/labstack/echo/middleware" + echo "gopkg.in/labstack/echo.v1" + mw "gopkg.in/labstack/echo.v1/middleware" ) func hello(c *echo.Context) error { diff --git a/middleware/auth.go b/middleware/auth.go index 1b864df36..c1488178a 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -4,7 +4,7 @@ import ( "encoding/base64" "net/http" - "github.com/labstack/echo" + echo "gopkg.in/labstack/echo.v1" ) type ( diff --git a/middleware/auth_test.go b/middleware/auth_test.go index d8b80c978..42e3c9d10 100644 --- a/middleware/auth_test.go +++ b/middleware/auth_test.go @@ -6,8 +6,8 @@ import ( "net/http/httptest" "testing" - "github.com/labstack/echo" "github.com/stretchr/testify/assert" + echo "gopkg.in/labstack/echo.v1" ) func TestBasicAuth(t *testing.T) { diff --git a/middleware/compress.go b/middleware/compress.go index 8c0095556..302229644 100644 --- a/middleware/compress.go +++ b/middleware/compress.go @@ -10,7 +10,7 @@ import ( "strings" "sync" - "github.com/labstack/echo" + echo "gopkg.in/labstack/echo.v1" ) type ( diff --git a/middleware/compress_test.go b/middleware/compress_test.go index dc8b2a46e..af468612b 100644 --- a/middleware/compress_test.go +++ b/middleware/compress_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/labstack/echo" "github.com/stretchr/testify/assert" + echo "gopkg.in/labstack/echo.v1" ) type closeNotifyingRecorder struct { diff --git a/middleware/logger.go b/middleware/logger.go index a28b9e2cc..37193793c 100644 --- a/middleware/logger.go +++ b/middleware/logger.go @@ -4,8 +4,8 @@ import ( "net" "time" - "github.com/labstack/echo" "github.com/labstack/gommon/color" + echo "gopkg.in/labstack/echo.v1" ) const ( diff --git a/middleware/logger_test.go b/middleware/logger_test.go index 298154b4e..51dc85723 100644 --- a/middleware/logger_test.go +++ b/middleware/logger_test.go @@ -7,8 +7,8 @@ import ( "net/http/httptest" "testing" - "github.com/labstack/echo" "github.com/stretchr/testify/assert" + echo "gopkg.in/labstack/echo.v1" ) func TestLogger(t *testing.T) { diff --git a/middleware/recover.go b/middleware/recover.go index 9bc266ce2..c6e18765d 100644 --- a/middleware/recover.go +++ b/middleware/recover.go @@ -5,7 +5,7 @@ import ( "runtime" - "github.com/labstack/echo" + echo "gopkg.in/labstack/echo.v1" ) // Recover returns a middleware which recovers from panics anywhere in the chain diff --git a/middleware/recover_test.go b/middleware/recover_test.go index 3adedebbc..4f0de8fcd 100644 --- a/middleware/recover_test.go +++ b/middleware/recover_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/labstack/echo" "github.com/stretchr/testify/assert" + echo "gopkg.in/labstack/echo.v1" ) func TestRecover(t *testing.T) { diff --git a/website/content/index.md b/website/content/index.md index 5332729ca..53e176118 100644 --- a/website/content/index.md +++ b/website/content/index.md @@ -88,7 +88,7 @@ A fast and unfancy micro web framework for Go. ### Installation ```sh -$ go get github.com/labstack/echo +$ go get gopkg.in/labstack/echo.v1 ``` ### Hello, World! @@ -101,8 +101,8 @@ package main import ( "net/http" - "github.com/labstack/echo" - mw "github.com/labstack/echo/middleware" + echo "gopkg.in/labstack/echo.v1" + mw "gopkg.in/labstack/echo.v1/middleware" ) // Handler From 18a78a34eb4481722eef1ac9034eada58e3cf909 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Sat, 19 Mar 2016 21:11:20 -0700 Subject: [PATCH 61/67] Fixed gommon changes Signed-off-by: Vishal Rana --- echo.go | 2 +- glide.lock | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/echo.go b/echo.go index 15f9c5b0b..05905ea00 100644 --- a/echo.go +++ b/echo.go @@ -245,7 +245,7 @@ func (e *Echo) SetLogOutput(w io.Writer) { } // SetLogLevel sets the log level for the logger. Default value is `log.FATAL`. -func (e *Echo) SetLogLevel(l log.Level) { +func (e *Echo) SetLogLevel(l uint8) { e.logger.SetLevel(l) } diff --git a/glide.lock b/glide.lock index cc9fc02d7..008b9f1a8 100644 --- a/glide.lock +++ b/glide.lock @@ -1,26 +1,28 @@ -hash: fc82f692d0964f55086fbff3572309a4dc9ffef356a2fa27687b997b761e345f -updated: 2016-01-30T10:01:06.631964896-08:00 +hash: 8b57b20e89ff74be22c696521d2c6f9bd11fb1521ac56d9ef0b0b9ef0352ad7e +updated: 2016-03-19T21:08:56.443543993-07:00 imports: - name: github.com/labstack/echo - version: 28b1b9d57b8a7b0b79ae05530b27244e27ba4bff + version: 576dfeb71d257a11e14bf637073b8c64576d2628 - name: github.com/labstack/gommon - version: 43358a791be603db7175670d78abf544245f9941 + version: 9c0a60557b6840125c331d8c8075119770aa2805 subpackages: - - /color + - color - log - name: github.com/mattn/go-colorable - version: 4af63d73f5bea08b682ad2cd198b1e607afd6be0 + version: 9cbef7c35391cca05f15f8181dc0b18bc9736dbb - name: github.com/mattn/go-isatty version: 56b76bdf51f7708750eac80fa38b952bb9f32639 -- name: golang.org/x/crypto - version: 1f22c0103821b9390939b6776727195525381532 - repo: https://golang.org/x/crypto +- name: github.com/valyala/fasttemplate + version: 3b874956e03f1636d171bda64b130f9135f42cff - name: golang.org/x/net - version: 04b9de9b512f58addf28c9853d50ebef61c3953e + version: 35b06af0720201bc2f326773a80767387544f8c4 subpackages: - - /context + - context - websocket -- name: golang.org/x/text - version: 6fc2e00a0d64b1f7fc1212dae5b0c939cf6d9ac4 - repo: https://golang.org/x/text +- name: golang.org/x/sys + version: 9d4e42a20653790449273b3c85e67d6d8bae6e2e + subpackages: + - unix +- name: gopkg.in/labstack/echo.v1 + version: 982498ca223e754d658ca18e07d1161e26186173 devImports: [] From f12d77f9cf7a374fa39e2e029a439c55e59dbc91 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Thu, 7 Apr 2016 17:01:42 -0700 Subject: [PATCH 62/67] Log level to debug in debug mode Signed-off-by: Vishal Rana --- echo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/echo.go b/echo.go index 05905ea00..fa2b9b21b 100644 --- a/echo.go +++ b/echo.go @@ -289,7 +289,7 @@ func (e *Echo) SetRenderer(r Renderer) { // SetDebug enable/disable debug mode. func (e *Echo) SetDebug(on bool) { e.debug = on - e.SetLogLevel(log.FATAL) + e.SetLogLevel(log.DEBUG) } // Debug returns debug mode (enabled or disabled). From 5d3ea7014b8661f376d41fc28580a43fe5cd0e99 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Fri, 3 Jun 2016 07:37:20 -0700 Subject: [PATCH 63/67] Closes #275 Signed-off-by: Vishal Rana --- response.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/response.go b/response.go index a40bd48e7..10c6d0866 100644 --- a/response.go +++ b/response.go @@ -60,6 +60,9 @@ func (r *Response) WriteHeader(code int) { // Additionally, Write will increment the size of the current response. // See [http.Response.Write](https://golang.org/pkg/net/http/#Response.Write) func (r *Response) Write(b []byte) (n int, err error) { + if !r.committed { + r.WriteHeader(http.StatusOK) + } n, err = r.writer.Write(b) r.size += int64(n) return n, err From be5efe5927206c132948c096ad3da6357d922b56 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Fri, 3 Jun 2016 07:50:24 -0700 Subject: [PATCH 64/67] Test for #275 Signed-off-by: Vishal Rana --- .travis.yml | 2 +- response_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c9be89477..609ac1651 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ env: before_install: - export PATH=$PATH:$GOPATH/bin - - go get golang.org/x/tools/cmd/vet + # - go get golang.org/x/tools/cmd/vet - go get golang.org/x/tools/cmd/cover - go get github.com/modocache/gover - go get github.com/mattn/goveralls diff --git a/response_test.go b/response_test.go index 266436371..e6389f54d 100644 --- a/response_test.go +++ b/response_test.go @@ -64,3 +64,27 @@ func TestResponse(t *testing.T) { // reset r.reset(httptest.NewRecorder(), New()) } + +func TestResponseWriteCommit(t *testing.T) { + e := New() + w := httptest.NewRecorder() + r := NewResponse(w, e) + + // Write body, it writes header if not committed yet + s := "echo" + r.Write([]byte(s)) + + assert.Equal(t, w.Code, 200) + assert.Equal(t, w.Body.String(), s) + + assert.Equal(t, r.Status(), 200) + assert.Equal(t, r.Size(), int64(4)) + assert.True(t, r.Committed()) + + // This is ignored with warning + r.WriteHeader(400) + + assert.Equal(t, r.Status(), 200) + assert.Equal(t, r.Size(), int64(4)) + assert.True(t, r.Committed()) +} From 5789bde991cc5c41536e4fd82cc0107e7cd3d0eb Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Thu, 9 Jun 2016 12:34:10 -0700 Subject: [PATCH 65/67] Fixed log level api changes Signed-off-by: Vishal Rana Updated deps Signed-off-by: Vishal Rana --- echo.go | 4 ++-- glide.lock | 20 +++++++++++--------- glide.yaml | 11 +++++++---- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/echo.go b/echo.go index fa2b9b21b..698706a4b 100644 --- a/echo.go +++ b/echo.go @@ -244,8 +244,8 @@ func (e *Echo) SetLogOutput(w io.Writer) { e.logger.SetOutput(w) } -// SetLogLevel sets the log level for the logger. Default value is `log.FATAL`. -func (e *Echo) SetLogLevel(l uint8) { +// SetLogLevel sets the log level for the logger. Default value FATAL. +func (e *Echo) SetLogLevel(l log.Lvl) { e.logger.SetLevel(l) } diff --git a/glide.lock b/glide.lock index 008b9f1a8..f731e12e3 100644 --- a/glide.lock +++ b/glide.lock @@ -1,28 +1,30 @@ -hash: 8b57b20e89ff74be22c696521d2c6f9bd11fb1521ac56d9ef0b0b9ef0352ad7e -updated: 2016-03-19T21:08:56.443543993-07:00 +hash: e300b5e8680ee0ce02a89f7b931687fb248b57516e959cbb9a889c824957e727 +updated: 2016-06-09T13:25:18.242243375-07:00 imports: -- name: github.com/labstack/echo - version: 576dfeb71d257a11e14bf637073b8c64576d2628 - name: github.com/labstack/gommon - version: 9c0a60557b6840125c331d8c8075119770aa2805 + version: 722aa12d41c236ce78ff48eac1cafe0107ecdc9d subpackages: - color - log - name: github.com/mattn/go-colorable - version: 9cbef7c35391cca05f15f8181dc0b18bc9736dbb + version: 9056b7a9f2d1f2d96498d6d146acd1f9d5ed3d59 - name: github.com/mattn/go-isatty version: 56b76bdf51f7708750eac80fa38b952bb9f32639 +- name: github.com/stretchr/testify + version: 8d64eb7173c7753d6419fd4a9caf057398611364 + subpackages: + - assert - name: github.com/valyala/fasttemplate version: 3b874956e03f1636d171bda64b130f9135f42cff - name: golang.org/x/net - version: 35b06af0720201bc2f326773a80767387544f8c4 + version: 3f122ce3dbbe488b7e6a8bdb26f41edec852a40b subpackages: - context - websocket - name: golang.org/x/sys - version: 9d4e42a20653790449273b3c85e67d6d8bae6e2e + version: 076b546753157f758b316e59bcb51e6807c04057 subpackages: - unix - name: gopkg.in/labstack/echo.v1 - version: 982498ca223e754d658ca18e07d1161e26186173 + version: be5efe5927206c132948c096ad3da6357d922b56 devImports: [] diff --git a/glide.yaml b/glide.yaml index d7b681241..3a0590134 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,11 +1,14 @@ -package: . +package: github.com/labstack/echo import: -- package: github.com/labstack/echo - package: github.com/labstack/gommon subpackages: - - /color + - color - log - package: golang.org/x/net subpackages: - - /context + - context - websocket +- package: gopkg.in/labstack/echo.v1 +- package: github.com/stretchr/testify + subpackages: + - assert From 49c099c3b3ad8aac1a5ea76cef1a70a119d09190 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Fri, 28 Oct 2016 17:09:07 -0700 Subject: [PATCH 66/67] fixed #697 Signed-off-by: Vishal Rana --- echo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/echo.go b/echo.go index 698706a4b..12de3ad70 100644 --- a/echo.go +++ b/echo.go @@ -224,7 +224,7 @@ func New() (e *Echo) { // Logger e.logger = log.New("echo") - e.SetLogLevel(log.FATAL) + e.SetLogLevel(log.OFF) return } From 1659348a67f499ff74f6dbf386375c95b5433ded Mon Sep 17 00:00:00 2001 From: Konstantin Kulikov Date: Thu, 3 Nov 2016 20:41:43 +0300 Subject: [PATCH 67/67] backport fix for #623 from v3 (#709) --- group.go | 2 ++ router.go | 4 ++-- router_test.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/group.go b/group.go index 2d5240b80..d6190bd20 100644 --- a/group.go +++ b/group.go @@ -12,6 +12,8 @@ func (g *Group) Use(m ...Middleware) { for _, h := range m { g.echo.middleware = append(g.echo.middleware, wrapMiddleware(h)) } + + g.echo.Any(g.echo.prefix+"*", notFoundHandler) } // Connect implements the echo.Connect interface for subroutes within the Group. diff --git a/router.go b/router.go index 2e3338dee..2e46fe379 100644 --- a/router.go +++ b/router.go @@ -344,7 +344,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo // Static node if c = cn.findChild(search[0], skind); c != nil { // Save next - if cn.label == '/' { + if cn.prefix[len(cn.prefix)-1] == '/' { nk = pkind nn = cn ns = search @@ -362,7 +362,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo } // Save next - if cn.label == '/' { + if cn.prefix[len(cn.prefix)-1] == '/' { nk = akind nn = cn ns = search diff --git a/router_test.go b/router_test.go index 867a32cfc..0b5335186 100644 --- a/router_test.go +++ b/router_test.go @@ -606,6 +606,37 @@ func TestRouterParamNames(t *testing.T) { assert.Equal(t, "1", c.P(1)) } +func TestRouterStaticDynamicConflict(t *testing.T) { + e := New() + r := e.router + c := NewContext(nil, nil, e) + + r.Add(GET, "/dictionary/skills", func(c *Context) error { + c.Set("a", 1) + return nil + }, e) + r.Add(GET, "/dictionary/:name", func(c *Context) error { + c.Set("b", 2) + return nil + }, e) + r.Add(GET, "/server", func(c *Context) error { + c.Set("c", 3) + return nil + }, e) + + h, _ := r.Find(GET, "/dictionary/skills", c) + h(c) + assert.Equal(t, 1, c.Get("a")) + c = NewContext(nil, nil, e) + h, _ = r.Find(GET, "/dictionary/type", c) + h(c) + assert.Equal(t, 2, c.Get("b")) + c = NewContext(nil, nil, e) + h, _ = r.Find(GET, "/server", c) + h(c) + assert.Equal(t, 3, c.Get("c")) +} + func TestRouterAPI(t *testing.T) { e := New() r := e.router