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

Separated recipes from the main repo

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2016-01-09 09:44:18 -08:00
parent 33d8813eb5
commit dbd1e8e230
52 changed files with 424 additions and 877 deletions

View File

@ -4,7 +4,6 @@ import (
"errors"
"io"
"net/http"
"net/http/httptest"
"testing"
"text/template"
@ -14,6 +13,7 @@ import (
"encoding/xml"
"github.com/labstack/echo/test"
"github.com/stretchr/testify/assert"
)
@ -36,9 +36,9 @@ func TestContext(t *testing.T) {
var nonMarshallableChannel chan bool
e := New()
req, _ := http.NewRequest(POST, "/", strings.NewReader(userJSON))
rec := httptest.NewRecorder()
c := NewContext(req, NewResponse(rec, e), e).X()
req := test.NewRequest(POST, "/", strings.NewReader(userJSON))
rec := test.NewResponseRecorder()
c := NewContext(req, rec, e)
// Request
assert.NotNil(t, c.Request())
@ -50,8 +50,8 @@ func TestContext(t *testing.T) {
assert.Nil(t, c.Socket())
// Param by id
c.pnames = []string{"id"}
c.pvalues = []string{"1"}
c.X().pnames = []string{"id"}
c.X().pvalues = []string{"1"}
assert.Equal(t, "1", c.P(0))
// Param by name
@ -69,7 +69,7 @@ func TestContext(t *testing.T) {
testBind(t, c, "application/json")
// XML
c.request, _ = http.NewRequest(POST, "/", strings.NewReader(userXML))
c.X().request = test.NewRequest(POST, "/", strings.NewReader(userXML))
testBind(t, c, ApplicationXML)
// Unsupported
@ -82,151 +82,151 @@ func TestContext(t *testing.T) {
tpl := &Template{
templates: template.Must(template.New("hello").Parse("Hello, {{.}}!")),
}
c.echo.SetRenderer(tpl)
c.X().echo.SetRenderer(tpl)
err := c.Render(http.StatusOK, "hello", "Joe")
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, "Hello, Joe!", rec.Body.String())
}
c.echo.renderer = nil
c.X().echo.renderer = nil
err = c.Render(http.StatusOK, "hello", "Joe")
assert.Error(t, err)
// JSON
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.JSON(http.StatusOK, user{"1", "Joe"})
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, ApplicationJSONCharsetUTF8, rec.Header().Get(ContentType))
assert.Equal(t, userJSON, rec.Body.String())
}
// JSON (error)
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
val := make(chan bool)
err = c.JSON(http.StatusOK, val)
assert.Error(t, err)
// JSONIndent
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.JSONIndent(http.StatusOK, user{"1", "Joe"}, "_", "?")
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, ApplicationJSONCharsetUTF8, rec.Header().Get(ContentType))
assert.Equal(t, userJSONIndent, rec.Body.String())
}
// JSONIndent (error)
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.JSONIndent(http.StatusOK, nonMarshallableChannel, "_", "?")
assert.Error(t, err)
// JSONP
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
callback := "callback"
err = c.JSONP(http.StatusOK, callback, user{"1", "Joe"})
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, ApplicationJavaScriptCharsetUTF8, rec.Header().Get(ContentType))
assert.Equal(t, callback+"("+userJSON+");", rec.Body.String())
}
// XML
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.XML(http.StatusOK, user{"1", "Joe"})
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, ApplicationXMLCharsetUTF8, rec.Header().Get(ContentType))
assert.Equal(t, xml.Header+userXML, rec.Body.String())
}
// XML (error)
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.XML(http.StatusOK, nonMarshallableChannel)
assert.Error(t, err)
// XMLIndent
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.XMLIndent(http.StatusOK, user{"1", "Joe"}, "_", "?")
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, ApplicationXMLCharsetUTF8, rec.Header().Get(ContentType))
assert.Equal(t, xml.Header+userXMLIndent, rec.Body.String())
}
// XMLIndent (error)
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.XMLIndent(http.StatusOK, nonMarshallableChannel, "_", "?")
assert.Error(t, err)
// String
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.String(http.StatusOK, "Hello, World!")
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, TextPlainCharsetUTF8, rec.Header().Get(ContentType))
assert.Equal(t, "Hello, World!", rec.Body.String())
}
// HTML
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.HTML(http.StatusOK, "Hello, <strong>World!</strong>")
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, TextHTMLCharsetUTF8, rec.Header().Get(ContentType))
assert.Equal(t, "Hello, <strong>World!</strong>", rec.Body.String())
}
// File
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
err = c.File("test/fixture/walle.png", "", false)
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.File("testing/fixture/walle.png", "", false)
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, 219885, rec.Body.Len())
}
// File as attachment
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
err = c.File("test/fixture/walle.png", "WALLE.PNG", true)
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
err = c.File("testing/fixture/walle.png", "WALLE.PNG", true)
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, http.StatusOK, rec.Status())
assert.Equal(t, rec.Header().Get(ContentDisposition), "attachment; filename=WALLE.PNG")
assert.Equal(t, 219885, rec.Body.Len())
}
// NoContent
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
c.NoContent(http.StatusOK)
assert.Equal(t, http.StatusOK, c.response.status)
assert.Equal(t, http.StatusOK, c.Response().Status())
// Redirect
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e)
assert.Equal(t, nil, c.Redirect(http.StatusMovedPermanently, "http://labstack.github.io/echo"))
// Error
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec, e), e).X()
rec = test.NewResponseRecorder()
c = NewContext(req, rec, e).X()
c.Error(errors.New("error"))
assert.Equal(t, http.StatusInternalServerError, c.response.status)
assert.Equal(t, http.StatusInternalServerError, c.Response().Status())
// reset
c.reset(req, NewResponse(httptest.NewRecorder(), e), e)
c.X().reset(req, test.NewResponseRecorder(), e)
}
func TestContextPath(t *testing.T) {
@ -234,12 +234,12 @@ func TestContextPath(t *testing.T) {
r := e.Router()
r.Add(GET, "/users/:id", nil, e)
c := NewContext(nil, nil, e).X()
c := NewContext(nil, nil, e)
r.Find(GET, "/users/1", c)
assert.Equal(t, c.Path(), "/users/:id")
r.Add(GET, "/users/:uid/files/:fid", nil, e)
c = NewContext(nil, nil, e).X()
c = NewContext(nil, nil, e)
r.Find(GET, "/users/1/files/1", c)
assert.Equal(t, c.Path(), "/users/:uid/files/:fid")
}
@ -248,11 +248,7 @@ func TestContextQuery(t *testing.T) {
q := make(url.Values)
q.Set("name", "joe")
q.Set("email", "joe@labstack.com")
req, err := http.NewRequest(GET, "/", nil)
assert.NoError(t, err)
req.URL.RawQuery = q.Encode()
req := test.NewRequest(GET, "/?"+q.Encode(), nil)
c := NewContext(req, nil, New())
assert.Equal(t, "joe", c.Query("name"))
assert.Equal(t, "joe@labstack.com", c.Query("email"))
@ -263,9 +259,8 @@ func TestContextForm(t *testing.T) {
f.Set("name", "joe")
f.Set("email", "joe@labstack.com")
req, err := http.NewRequest(POST, "/", strings.NewReader(f.Encode()))
assert.NoError(t, err)
req.Header.Add(ContentType, ApplicationForm)
req := test.NewRequest(POST, "/", strings.NewReader(f.Encode()))
req.Header().Add(ContentType, ApplicationForm)
c := NewContext(req, nil, New())
assert.Equal(t, "joe", c.Form("name"))
@ -278,8 +273,8 @@ func TestContextNetContext(t *testing.T) {
// assert.Equal(t, "val", c.Value("key"))
}
func testBind(t *testing.T, c *context, ct string) {
c.request.Header.Set(ContentType, ct)
func testBind(t *testing.T, c Context, ct string) {
c.Request().Header().Set(ContentType, ct)
u := new(user)
err := c.Bind(u)
if ct == "" {

36
echo.go
View File

@ -203,21 +203,19 @@ func New() (e *Echo) {
e.HTTP2(true)
e.defaultHTTPErrorHandler = func(err error, c Context) {
// TODO: v2
// x := c.X()
// 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 !x.response.Committed() {
// http.Error(x.response, msg, code)
// }
// e.logger.Error(err)
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() {
c.String(code, msg)
}
e.logger.Error(err)
}
e.SetHTTPErrorHandler(e.defaultHTTPErrorHandler)
e.SetBinder(&binder{})
@ -410,15 +408,13 @@ func (e *Echo) ServeFile(path, file string) {
}
func (e *Echo) serveFile(dir, file string, c Context) (err error) {
// TODO: v2
// x := c.X()
// fs := http.Dir(dir)
// f, err := fs.Open(file)
// if err != nil {
// return NewHTTPError(http.StatusNotFound)
// }
// defer f.Close()
//
// fi, _ := f.Stat()
// if fi.IsDir() {
// /* NOTE:
@ -426,7 +422,7 @@ func (e *Echo) serveFile(dir, file string, c Context) (err error) {
// changing differnt directories for the same path.
// */
// d := f
//
// // Index file
// file = filepath.Join(file, indexPage)
// f, err = fs.Open(file)
@ -439,7 +435,7 @@ func (e *Echo) serveFile(dir, file string, c Context) (err error) {
// }
// fi, _ = f.Stat() // Index file stat
// }
// http.ServeContent(x.response, x.request, fi.Name(), fi.ModTime(), f)
// http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
return
}

View File

@ -12,8 +12,9 @@ import (
"errors"
"github.com/labstack/echo/engine"
"github.com/labstack/echo/test"
"github.com/stretchr/testify/assert"
"golang.org/x/net/websocket"
)
type (
@ -25,9 +26,9 @@ type (
func TestEcho(t *testing.T) {
e := New()
req, _ := http.NewRequest(GET, "/", nil)
rec := httptest.NewRecorder()
c := NewContext(req, NewResponse(rec, e), e)
req := test.NewRequest(GET, "/", nil)
rec := test.NewResponseRecorder()
c := NewContext(req, rec, e)
// Router
assert.NotNil(t, e.Router())
@ -38,7 +39,7 @@ func TestEcho(t *testing.T) {
// DefaultHTTPErrorHandler
e.DefaultHTTPErrorHandler(errors.New("error"), c)
assert.Equal(t, http.StatusInternalServerError, rec.Code)
assert.Equal(t, http.StatusInternalServerError, rec.Status())
}
func TestEchoIndex(t *testing.T) {
@ -92,15 +93,13 @@ func TestEchoMiddleware(t *testing.T) {
e := New()
buf := new(bytes.Buffer)
// echo.MiddlewareFunc
e.Use(MiddlewareFunc(func(h HandlerFunc) HandlerFunc {
e.Use(func(h HandlerFunc) HandlerFunc {
return func(c Context) error {
buf.WriteString("a")
return h(c)
}
}))
})
// func(echo.HandlerFunc) echo.HandlerFunc
e.Use(func(h HandlerFunc) HandlerFunc {
return func(c Context) error {
buf.WriteString("b")
@ -108,59 +107,28 @@ func TestEchoMiddleware(t *testing.T) {
}
})
// echo.HandlerFunc
e.Use(HandlerFunc(func(c Context) error {
e.Use(func(h HandlerFunc) HandlerFunc {
return func(c Context) error {
buf.WriteString("c")
return nil
}))
// func(*echo.Context) error
e.Use(func(c Context) error {
buf.WriteString("d")
return nil
})
// func(http.Handler) http.Handler
e.Use(func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
buf.WriteString("e")
h.ServeHTTP(w, r)
})
})
// http.Handler
e.Use(http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
buf.WriteString("f")
})))
// http.HandlerFunc
e.Use(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
buf.WriteString("g")
}))
// func(http.ResponseWriter, *http.Request)
e.Use(func(w http.ResponseWriter, r *http.Request) {
buf.WriteString("h")
})
// Unknown
assert.Panics(t, func() {
e.Use(nil)
return h(c)
}
})
// Route
e.Get("/", func(c Context) error {
return c.String(http.StatusOK, "Hello!")
return c.String(http.StatusOK, "OK")
})
c, b := request(GET, "/", e)
assert.Equal(t, "abcdefgh", buf.String())
assert.Equal(t, "abc", buf.String())
assert.Equal(t, http.StatusOK, c)
assert.Equal(t, "Hello!", b)
assert.Equal(t, "OK", b)
// Error
e.Use(func(Context) error {
e.Use(func(h HandlerFunc) HandlerFunc {
return func(c Context) error {
return errors.New("error")
}
})
c, b = request(GET, "/", e)
assert.Equal(t, http.StatusInternalServerError, c)
@ -170,35 +138,13 @@ func TestEchoHandler(t *testing.T) {
e := New()
// HandlerFunc
e.Get("/1", HandlerFunc(func(c Context) error {
return c.String(http.StatusOK, "1")
e.Get("/ok", HandlerFunc(func(c Context) error {
return c.String(http.StatusOK, "OK")
}))
// func(*echo.Context) error
e.Get("/2", func(c Context) error {
return c.String(http.StatusOK, "2")
})
// http.Handler/http.HandlerFunc
e.Get("/3", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("3"))
}))
// func(http.ResponseWriter, *http.Request)
e.Get("/4", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("4"))
})
for _, p := range []string{"1", "2", "3", "4"} {
c, b := request(GET, "/"+p, e)
c, b := request(GET, "/ok", e)
assert.Equal(t, http.StatusOK, c)
assert.Equal(t, p, b)
}
// Unknown
assert.Panics(t, func() {
e.Get("/5", nil)
})
assert.Equal(t, "OK", b)
}
func TestEchoConnect(t *testing.T) {
@ -260,28 +206,6 @@ func TestEchoMatch(t *testing.T) { // JFC
})
}
func TestEchoWebSocket(t *testing.T) {
e := New()
e.WebSocket("/ws", func(c Context) error {
x := c.X()
x.socket.Write([]byte("test"))
return nil
})
srv := httptest.NewServer(e)
defer srv.Close()
addr := srv.Listener.Addr().String()
origin := "http://localhost"
url := fmt.Sprintf("ws://%s/ws", addr)
ws, err := websocket.Dial(url, "", origin)
if assert.NoError(t, err) {
ws.Write([]byte("test"))
defer ws.Close()
buf := new(bytes.Buffer)
buf.ReadFrom(ws)
assert.Equal(t, "test", buf.String())
}
}
func TestEchoURL(t *testing.T) {
e := New()
@ -303,15 +227,16 @@ func TestEchoURL(t *testing.T) {
func TestEchoRoutes(t *testing.T) {
e := New()
h := func(Context) error { return nil }
routes := []Route{
{GET, "/users/:user/events", h},
{GET, "/users/:user/events/public", h},
{POST, "/repos/:owner/:repo/git/refs", h},
{POST, "/repos/:owner/:repo/git/tags", h},
{GET, "/users/:user/events", ""},
{GET, "/users/:user/events/public", ""},
{POST, "/repos/:owner/:repo/git/refs", ""},
{POST, "/repos/:owner/:repo/git/tags", ""},
}
for _, r := range routes {
e.add(r.Method, r.Path, h)
e.add(r.Method, r.Path, func(c Context) error {
return c.String(http.StatusOK, "OK")
})
}
for i, r := range e.Routes() {
@ -323,9 +248,11 @@ func TestEchoRoutes(t *testing.T) {
func TestEchoGroup(t *testing.T) {
e := New()
buf := new(bytes.Buffer)
e.Use(func(Context) error {
buf.WriteString("0")
return nil
e.Use(func(h HandlerFunc) HandlerFunc {
return func(c Context) error {
buf.WriteString("a")
return h(c)
}
})
h := func(Context) error { return nil }
@ -337,28 +264,33 @@ func TestEchoGroup(t *testing.T) {
// Group
g1 := e.Group("/group1")
g1.Use(func(Context) error {
g1.Use(func(h HandlerFunc) HandlerFunc {
return func(c Context) error {
buf.WriteString("1")
return nil
return h(c)
}
})
g1.Get("/", h)
// Group with no parent middleware
g2 := e.Group("/group2", func(Context) error {
g2 := e.Group("/group2", func(h HandlerFunc) HandlerFunc {
return func(c Context) error {
buf.WriteString("2")
return nil
return h(c)
}
})
g2.Get("/", h)
// Nested groups
g3 := e.Group("/group3")
g4 := g3.Group("/group4")
g4.Get("/", func(c Context) error {
g4.Use(func(h HandlerFunc) HandlerFunc {
return func(c Context) error {
return c.NoContent(http.StatusOK)
}
})
request(GET, "/users", e)
// println(len(e.middleware))
assert.Equal(t, "0", buf.String())
buf.Reset()
@ -412,11 +344,11 @@ func TestEchoHook(t *testing.T) {
e.Get("/test", func(c Context) error {
return c.NoContent(http.StatusNoContent)
})
e.Hook(func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
e.Hook(func(req engine.Request, res engine.Response) {
path := req.URL().Path()
l := len(path) - 1
if path != "/" && path[l] == '/' {
r.URL.Path = path[:l]
// req.URL().Path() = path[:l]
}
})
r, _ := http.NewRequest(GET, "/test/", nil)

View File

@ -14,7 +14,6 @@ func TestGroup(t *testing.T) {
g.Post("/", h)
g.Put("/", h)
g.Trace("/", h)
g.WebSocket("/ws", h)
g.Static("/scripts", "scripts")
g.ServeDir("/scripts", "scripts")
g.ServeFile("/scripts/main.js", "scripts/main.js")

View File

@ -25,7 +25,7 @@ func TestBasicAuth(t *testing.T) {
// Valid credentials
auth := Basic + " " + base64.StdEncoding.EncodeToString([]byte("joe:secret"))
req.Header.Set(echo.Authorization, auth)
req.Header().Set(echo.Authorization, auth)
assert.NoError(t, ba(c))
//---------------------
@ -34,7 +34,7 @@ func TestBasicAuth(t *testing.T) {
// Incorrect password
auth = Basic + " " + base64.StdEncoding.EncodeToString([]byte("joe:password"))
req.Header.Set(echo.Authorization, auth)
req.Header().Set(echo.Authorization, auth)
he := ba(c).(*echo.HTTPError)
assert.Equal(t, http.StatusUnauthorized, he.Code())
assert.Equal(t, Basic+" realm=Restricted", rec.Header().Get(echo.WWWAuthenticate))

View File

@ -15,7 +15,7 @@ func Logger() echo.MiddlewareFunc {
res := c.Response()
logger := c.Logger()
remoteAddr := req.RemoteAddr
remoteAddr := req.RemoteAddress()
if ip := req.Header().Get(echo.XRealIP); ip != "" {
remoteAddr = ip
} else if ip = req.Header().Get(echo.XForwardedFor); ip != "" {
@ -30,7 +30,7 @@ func Logger() echo.MiddlewareFunc {
}
stop := time.Now()
method := req.Method
path := req.URL.Path
path := req.URL().Path()
if path == "" {
path = "/"
}

View File

@ -1,2 +0,0 @@
rice
app.rice-box.go

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>go.rice Example</title>
<script src="/static/main.js" charset="utf-8"></script>
</head>
<body>
<h1>go.rice Example</h1>
</body>
</html>

View File

@ -1 +0,0 @@
alert("main.js");

View File

@ -1,17 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>File Upload</title>
</head>
<body>
<h1>Upload Files</h1>
<form action="/upload" method=post enctype="multipart/form-data">
Name: <input type="text" name="name"><br>
Email: <input type="email" name="email"><br>
Files: <input type="file" name="files" multiple><br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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()
}

View File

@ -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

View File

@ -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")
}

View File

@ -1,4 +0,0 @@
package main
// referecnce our echo instance and create it early
var e = createMux()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,15 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Echo</title>
<link rel="shortcut icon" href="favicon.ico" />
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Echo!</h1>
<script src="/scripts/main.js"></script>
</body>
</html>

View File

@ -1 +0,0 @@
console.log("Echo!");

View File

@ -1 +0,0 @@
{{define "welcome"}}Hello, {{.}}!{{end}}

View File

@ -1,36 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<title>JSONP</title>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript">
var host_prefix = 'http://localhost:3999';
$(document).ready(function() {
// JSONP version - add 'callback=?' to the URL - fetch the JSONP response to the request
$("#jsonp-button").click(function(e) {
e.preventDefault();
// The only difference on the client end is the addition of 'callback=?' to the URL
var url = host_prefix + '/jsonp?callback=?';
$.getJSON(url, function(jsonp) {
console.log(jsonp);
$("#jsonp-response").html(JSON.stringify(jsonp, null, 2));
});
});
});
</script>
</head>
<body>
<div class="container" style="margin-top: 50px;">
<input type="button" class="btn btn-primary btn-lg" id="jsonp-button" value="Get JSONP response">
<p>
<pre id="jsonp-response"></pre>
</p>
</div>
</body>
</html>

View File

@ -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)
}

View File

@ -1,17 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>File Upload</title>
</head>
<body>
<h1>Upload Files</h1>
<form action="/upload" method=post enctype="multipart/form-data">
Name: <input type="text" name="name"><br>
Email: <input type="email" name="email"><br>
Files: <input type="file" name="files" multiple><br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1 +0,0 @@
sub directory

View File

@ -1,15 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Echo</title>
<link rel="shortcut icon" href="favicon.ico"/>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Echo!</h1>
<script src="/scripts/main.js"></script>
</body>
</html>

View File

@ -1 +0,0 @@
console.log("Echo!")

View File

@ -1 +0,0 @@
{{define "welcome"}}Hello, {{.}}!{{end}}

View File

@ -1,37 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WebSocket</title>
</head>
<body>
<p id="output"></p>
<script>
var loc = window.location;
var uri = 'ws:';
if (loc.protocol === 'https:') {
uri = 'wss:';
}
uri += '//' + loc.host;
uri += loc.pathname + 'ws';
ws = new WebSocket(uri)
ws.onopen = function() {
console.log('Connected')
}
ws.onmessage = function(evt) {
var out = document.getElementById('output');
out.innerHTML += evt.data + '<br>';
}
setInterval(function() {
ws.send('Hello, Server!');
}, 1000);
</script>
</body>
</html>

View File

@ -1,7 +1,5 @@
package echo
import "net/http"
type (
Router struct {
tree *node
@ -400,14 +398,3 @@ End:
}
return
}
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: v2
// c := r.echo.pool.Get().(*context)
// h, _ := r.Find(req.Method, req.URL.Path, c)
// c.reset(req, w, r.echo)
// if err := h(c); err != nil {
// r.echo.httpErrorHandler(err, c)
// }
// r.echo.pool.Put(c)
}

View File

@ -3,7 +3,6 @@ package echo
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
@ -12,265 +11,265 @@ import (
var (
api = []Route{
// OAuth Authorizations
{"GET", "/authorizations", nil},
{"GET", "/authorizations/:id", nil},
{"POST", "/authorizations", nil},
//{"PUT", "/authorizations/clients/:client_id", nil},
//{"PATCH", "/authorizations/:id", nil},
{"DELETE", "/authorizations/:id", nil},
{"GET", "/applications/:client_id/tokens/:access_token", nil},
{"DELETE", "/applications/:client_id/tokens", nil},
{"DELETE", "/applications/:client_id/tokens/:access_token", nil},
{"GET", "/authorizations", ""},
{"GET", "/authorizations/:id", ""},
{"POST", "/authorizations", ""},
//{"PUT", "/authorizations/clients/:client_id", ""},
//{"PATCH", "/authorizations/:id", ""},
{"DELETE", "/authorizations/:id", ""},
{"GET", "/applications/:client_id/tokens/:access_token", ""},
{"DELETE", "/applications/:client_id/tokens", ""},
{"DELETE", "/applications/:client_id/tokens/:access_token", ""},
// Activity
{"GET", "/events", nil},
{"GET", "/repos/:owner/:repo/events", nil},
{"GET", "/networks/:owner/:repo/events", nil},
{"GET", "/orgs/:org/events", nil},
{"GET", "/users/:user/received_events", nil},
{"GET", "/users/:user/received_events/public", nil},
{"GET", "/users/:user/events", nil},
{"GET", "/users/:user/events/public", nil},
{"GET", "/users/:user/events/orgs/:org", nil},
{"GET", "/feeds", nil},
{"GET", "/notifications", nil},
{"GET", "/repos/:owner/:repo/notifications", nil},
{"PUT", "/notifications", nil},
{"PUT", "/repos/:owner/:repo/notifications", nil},
{"GET", "/notifications/threads/:id", nil},
//{"PATCH", "/notifications/threads/:id", nil},
{"GET", "/notifications/threads/:id/subscription", nil},
{"PUT", "/notifications/threads/:id/subscription", nil},
{"DELETE", "/notifications/threads/:id/subscription", nil},
{"GET", "/repos/:owner/:repo/stargazers", nil},
{"GET", "/users/:user/starred", nil},
{"GET", "/user/starred", nil},
{"GET", "/user/starred/:owner/:repo", nil},
{"PUT", "/user/starred/:owner/:repo", nil},
{"DELETE", "/user/starred/:owner/:repo", nil},
{"GET", "/repos/:owner/:repo/subscribers", nil},
{"GET", "/users/:user/subscriptions", nil},
{"GET", "/user/subscriptions", nil},
{"GET", "/repos/:owner/:repo/subscription", nil},
{"PUT", "/repos/:owner/:repo/subscription", nil},
{"DELETE", "/repos/:owner/:repo/subscription", nil},
{"GET", "/user/subscriptions/:owner/:repo", nil},
{"PUT", "/user/subscriptions/:owner/:repo", nil},
{"DELETE", "/user/subscriptions/:owner/:repo", nil},
{"GET", "/events", ""},
{"GET", "/repos/:owner/:repo/events", ""},
{"GET", "/networks/:owner/:repo/events", ""},
{"GET", "/orgs/:org/events", ""},
{"GET", "/users/:user/received_events", ""},
{"GET", "/users/:user/received_events/public", ""},
{"GET", "/users/:user/events", ""},
{"GET", "/users/:user/events/public", ""},
{"GET", "/users/:user/events/orgs/:org", ""},
{"GET", "/feeds", ""},
{"GET", "/notifications", ""},
{"GET", "/repos/:owner/:repo/notifications", ""},
{"PUT", "/notifications", ""},
{"PUT", "/repos/:owner/:repo/notifications", ""},
{"GET", "/notifications/threads/:id", ""},
//{"PATCH", "/notifications/threads/:id", ""},
{"GET", "/notifications/threads/:id/subscription", ""},
{"PUT", "/notifications/threads/:id/subscription", ""},
{"DELETE", "/notifications/threads/:id/subscription", ""},
{"GET", "/repos/:owner/:repo/stargazers", ""},
{"GET", "/users/:user/starred", ""},
{"GET", "/user/starred", ""},
{"GET", "/user/starred/:owner/:repo", ""},
{"PUT", "/user/starred/:owner/:repo", ""},
{"DELETE", "/user/starred/:owner/:repo", ""},
{"GET", "/repos/:owner/:repo/subscribers", ""},
{"GET", "/users/:user/subscriptions", ""},
{"GET", "/user/subscriptions", ""},
{"GET", "/repos/:owner/:repo/subscription", ""},
{"PUT", "/repos/:owner/:repo/subscription", ""},
{"DELETE", "/repos/:owner/:repo/subscription", ""},
{"GET", "/user/subscriptions/:owner/:repo", ""},
{"PUT", "/user/subscriptions/:owner/:repo", ""},
{"DELETE", "/user/subscriptions/:owner/:repo", ""},
// Gists
{"GET", "/users/:user/gists", nil},
{"GET", "/gists", nil},
//{"GET", "/gists/public", nil},
//{"GET", "/gists/starred", nil},
{"GET", "/gists/:id", nil},
{"POST", "/gists", nil},
//{"PATCH", "/gists/:id", nil},
{"PUT", "/gists/:id/star", nil},
{"DELETE", "/gists/:id/star", nil},
{"GET", "/gists/:id/star", nil},
{"POST", "/gists/:id/forks", nil},
{"DELETE", "/gists/:id", nil},
{"GET", "/users/:user/gists", ""},
{"GET", "/gists", ""},
//{"GET", "/gists/public", ""},
//{"GET", "/gists/starred", ""},
{"GET", "/gists/:id", ""},
{"POST", "/gists", ""},
//{"PATCH", "/gists/:id", ""},
{"PUT", "/gists/:id/star", ""},
{"DELETE", "/gists/:id/star", ""},
{"GET", "/gists/:id/star", ""},
{"POST", "/gists/:id/forks", ""},
{"DELETE", "/gists/:id", ""},
// Git Data
{"GET", "/repos/:owner/:repo/git/blobs/:sha", nil},
{"POST", "/repos/:owner/:repo/git/blobs", nil},
{"GET", "/repos/:owner/:repo/git/commits/:sha", nil},
{"POST", "/repos/:owner/:repo/git/commits", nil},
//{"GET", "/repos/:owner/:repo/git/refs/*ref", nil},
{"GET", "/repos/:owner/:repo/git/refs", nil},
{"POST", "/repos/:owner/:repo/git/refs", nil},
//{"PATCH", "/repos/:owner/:repo/git/refs/*ref", nil},
//{"DELETE", "/repos/:owner/:repo/git/refs/*ref", nil},
{"GET", "/repos/:owner/:repo/git/tags/:sha", nil},
{"POST", "/repos/:owner/:repo/git/tags", nil},
{"GET", "/repos/:owner/:repo/git/trees/:sha", nil},
{"POST", "/repos/:owner/:repo/git/trees", nil},
{"GET", "/repos/:owner/:repo/git/blobs/:sha", ""},
{"POST", "/repos/:owner/:repo/git/blobs", ""},
{"GET", "/repos/:owner/:repo/git/commits/:sha", ""},
{"POST", "/repos/:owner/:repo/git/commits", ""},
//{"GET", "/repos/:owner/:repo/git/refs/*ref", ""},
{"GET", "/repos/:owner/:repo/git/refs", ""},
{"POST", "/repos/:owner/:repo/git/refs", ""},
//{"PATCH", "/repos/:owner/:repo/git/refs/*ref", ""},
//{"DELETE", "/repos/:owner/:repo/git/refs/*ref", ""},
{"GET", "/repos/:owner/:repo/git/tags/:sha", ""},
{"POST", "/repos/:owner/:repo/git/tags", ""},
{"GET", "/repos/:owner/:repo/git/trees/:sha", ""},
{"POST", "/repos/:owner/:repo/git/trees", ""},
// Issues
{"GET", "/issues", nil},
{"GET", "/user/issues", nil},
{"GET", "/orgs/:org/issues", nil},
{"GET", "/repos/:owner/:repo/issues", nil},
{"GET", "/repos/:owner/:repo/issues/:number", nil},
{"POST", "/repos/:owner/:repo/issues", nil},
//{"PATCH", "/repos/:owner/:repo/issues/:number", nil},
{"GET", "/repos/:owner/:repo/assignees", nil},
{"GET", "/repos/:owner/:repo/assignees/:assignee", nil},
{"GET", "/repos/:owner/:repo/issues/:number/comments", nil},
//{"GET", "/repos/:owner/:repo/issues/comments", nil},
//{"GET", "/repos/:owner/:repo/issues/comments/:id", nil},
{"POST", "/repos/:owner/:repo/issues/:number/comments", nil},
//{"PATCH", "/repos/:owner/:repo/issues/comments/:id", nil},
//{"DELETE", "/repos/:owner/:repo/issues/comments/:id", nil},
{"GET", "/repos/:owner/:repo/issues/:number/events", nil},
//{"GET", "/repos/:owner/:repo/issues/events", nil},
//{"GET", "/repos/:owner/:repo/issues/events/:id", nil},
{"GET", "/repos/:owner/:repo/labels", nil},
{"GET", "/repos/:owner/:repo/labels/:name", nil},
{"POST", "/repos/:owner/:repo/labels", nil},
//{"PATCH", "/repos/:owner/:repo/labels/:name", nil},
{"DELETE", "/repos/:owner/:repo/labels/:name", nil},
{"GET", "/repos/:owner/:repo/issues/:number/labels", nil},
{"POST", "/repos/:owner/:repo/issues/:number/labels", nil},
{"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name", nil},
{"PUT", "/repos/:owner/:repo/issues/:number/labels", nil},
{"DELETE", "/repos/:owner/:repo/issues/:number/labels", nil},
{"GET", "/repos/:owner/:repo/milestones/:number/labels", nil},
{"GET", "/repos/:owner/:repo/milestones", nil},
{"GET", "/repos/:owner/:repo/milestones/:number", nil},
{"POST", "/repos/:owner/:repo/milestones", nil},
//{"PATCH", "/repos/:owner/:repo/milestones/:number", nil},
{"DELETE", "/repos/:owner/:repo/milestones/:number", nil},
{"GET", "/issues", ""},
{"GET", "/user/issues", ""},
{"GET", "/orgs/:org/issues", ""},
{"GET", "/repos/:owner/:repo/issues", ""},
{"GET", "/repos/:owner/:repo/issues/:number", ""},
{"POST", "/repos/:owner/:repo/issues", ""},
//{"PATCH", "/repos/:owner/:repo/issues/:number", ""},
{"GET", "/repos/:owner/:repo/assignees", ""},
{"GET", "/repos/:owner/:repo/assignees/:assignee", ""},
{"GET", "/repos/:owner/:repo/issues/:number/comments", ""},
//{"GET", "/repos/:owner/:repo/issues/comments", ""},
//{"GET", "/repos/:owner/:repo/issues/comments/:id", ""},
{"POST", "/repos/:owner/:repo/issues/:number/comments", ""},
//{"PATCH", "/repos/:owner/:repo/issues/comments/:id", ""},
//{"DELETE", "/repos/:owner/:repo/issues/comments/:id", ""},
{"GET", "/repos/:owner/:repo/issues/:number/events", ""},
//{"GET", "/repos/:owner/:repo/issues/events", ""},
//{"GET", "/repos/:owner/:repo/issues/events/:id", ""},
{"GET", "/repos/:owner/:repo/labels", ""},
{"GET", "/repos/:owner/:repo/labels/:name", ""},
{"POST", "/repos/:owner/:repo/labels", ""},
//{"PATCH", "/repos/:owner/:repo/labels/:name", ""},
{"DELETE", "/repos/:owner/:repo/labels/:name", ""},
{"GET", "/repos/:owner/:repo/issues/:number/labels", ""},
{"POST", "/repos/:owner/:repo/issues/:number/labels", ""},
{"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name", ""},
{"PUT", "/repos/:owner/:repo/issues/:number/labels", ""},
{"DELETE", "/repos/:owner/:repo/issues/:number/labels", ""},
{"GET", "/repos/:owner/:repo/milestones/:number/labels", ""},
{"GET", "/repos/:owner/:repo/milestones", ""},
{"GET", "/repos/:owner/:repo/milestones/:number", ""},
{"POST", "/repos/:owner/:repo/milestones", ""},
//{"PATCH", "/repos/:owner/:repo/milestones/:number", ""},
{"DELETE", "/repos/:owner/:repo/milestones/:number", ""},
// Miscellaneous
{"GET", "/emojis", nil},
{"GET", "/gitignore/templates", nil},
{"GET", "/gitignore/templates/:name", nil},
{"POST", "/markdown", nil},
{"POST", "/markdown/raw", nil},
{"GET", "/meta", nil},
{"GET", "/rate_limit", nil},
{"GET", "/emojis", ""},
{"GET", "/gitignore/templates", ""},
{"GET", "/gitignore/templates/:name", ""},
{"POST", "/markdown", ""},
{"POST", "/markdown/raw", ""},
{"GET", "/meta", ""},
{"GET", "/rate_limit", ""},
// Organizations
{"GET", "/users/:user/orgs", nil},
{"GET", "/user/orgs", nil},
{"GET", "/orgs/:org", nil},
//{"PATCH", "/orgs/:org", nil},
{"GET", "/orgs/:org/members", nil},
{"GET", "/orgs/:org/members/:user", nil},
{"DELETE", "/orgs/:org/members/:user", nil},
{"GET", "/orgs/:org/public_members", nil},
{"GET", "/orgs/:org/public_members/:user", nil},
{"PUT", "/orgs/:org/public_members/:user", nil},
{"DELETE", "/orgs/:org/public_members/:user", nil},
{"GET", "/orgs/:org/teams", nil},
{"GET", "/teams/:id", nil},
{"POST", "/orgs/:org/teams", nil},
//{"PATCH", "/teams/:id", nil},
{"DELETE", "/teams/:id", nil},
{"GET", "/teams/:id/members", nil},
{"GET", "/teams/:id/members/:user", nil},
{"PUT", "/teams/:id/members/:user", nil},
{"DELETE", "/teams/:id/members/:user", nil},
{"GET", "/teams/:id/repos", nil},
{"GET", "/teams/:id/repos/:owner/:repo", nil},
{"PUT", "/teams/:id/repos/:owner/:repo", nil},
{"DELETE", "/teams/:id/repos/:owner/:repo", nil},
{"GET", "/user/teams", nil},
{"GET", "/users/:user/orgs", ""},
{"GET", "/user/orgs", ""},
{"GET", "/orgs/:org", ""},
//{"PATCH", "/orgs/:org", ""},
{"GET", "/orgs/:org/members", ""},
{"GET", "/orgs/:org/members/:user", ""},
{"DELETE", "/orgs/:org/members/:user", ""},
{"GET", "/orgs/:org/public_members", ""},
{"GET", "/orgs/:org/public_members/:user", ""},
{"PUT", "/orgs/:org/public_members/:user", ""},
{"DELETE", "/orgs/:org/public_members/:user", ""},
{"GET", "/orgs/:org/teams", ""},
{"GET", "/teams/:id", ""},
{"POST", "/orgs/:org/teams", ""},
//{"PATCH", "/teams/:id", ""},
{"DELETE", "/teams/:id", ""},
{"GET", "/teams/:id/members", ""},
{"GET", "/teams/:id/members/:user", ""},
{"PUT", "/teams/:id/members/:user", ""},
{"DELETE", "/teams/:id/members/:user", ""},
{"GET", "/teams/:id/repos", ""},
{"GET", "/teams/:id/repos/:owner/:repo", ""},
{"PUT", "/teams/:id/repos/:owner/:repo", ""},
{"DELETE", "/teams/:id/repos/:owner/:repo", ""},
{"GET", "/user/teams", ""},
// Pull Requests
{"GET", "/repos/:owner/:repo/pulls", nil},
{"GET", "/repos/:owner/:repo/pulls/:number", nil},
{"POST", "/repos/:owner/:repo/pulls", nil},
//{"PATCH", "/repos/:owner/:repo/pulls/:number", nil},
{"GET", "/repos/:owner/:repo/pulls/:number/commits", nil},
{"GET", "/repos/:owner/:repo/pulls/:number/files", nil},
{"GET", "/repos/:owner/:repo/pulls/:number/merge", nil},
{"PUT", "/repos/:owner/:repo/pulls/:number/merge", nil},
{"GET", "/repos/:owner/:repo/pulls/:number/comments", nil},
//{"GET", "/repos/:owner/:repo/pulls/comments", nil},
//{"GET", "/repos/:owner/:repo/pulls/comments/:number", nil},
{"PUT", "/repos/:owner/:repo/pulls/:number/comments", nil},
//{"PATCH", "/repos/:owner/:repo/pulls/comments/:number", nil},
//{"DELETE", "/repos/:owner/:repo/pulls/comments/:number", nil},
{"GET", "/repos/:owner/:repo/pulls", ""},
{"GET", "/repos/:owner/:repo/pulls/:number", ""},
{"POST", "/repos/:owner/:repo/pulls", ""},
//{"PATCH", "/repos/:owner/:repo/pulls/:number", ""},
{"GET", "/repos/:owner/:repo/pulls/:number/commits", ""},
{"GET", "/repos/:owner/:repo/pulls/:number/files", ""},
{"GET", "/repos/:owner/:repo/pulls/:number/merge", ""},
{"PUT", "/repos/:owner/:repo/pulls/:number/merge", ""},
{"GET", "/repos/:owner/:repo/pulls/:number/comments", ""},
//{"GET", "/repos/:owner/:repo/pulls/comments", ""},
//{"GET", "/repos/:owner/:repo/pulls/comments/:number", ""},
{"PUT", "/repos/:owner/:repo/pulls/:number/comments", ""},
//{"PATCH", "/repos/:owner/:repo/pulls/comments/:number", ""},
//{"DELETE", "/repos/:owner/:repo/pulls/comments/:number", ""},
// Repositories
{"GET", "/user/repos", nil},
{"GET", "/users/:user/repos", nil},
{"GET", "/orgs/:org/repos", nil},
{"GET", "/repositories", nil},
{"POST", "/user/repos", nil},
{"POST", "/orgs/:org/repos", nil},
{"GET", "/repos/:owner/:repo", nil},
//{"PATCH", "/repos/:owner/:repo", nil},
{"GET", "/repos/:owner/:repo/contributors", nil},
{"GET", "/repos/:owner/:repo/languages", nil},
{"GET", "/repos/:owner/:repo/teams", nil},
{"GET", "/repos/:owner/:repo/tags", nil},
{"GET", "/repos/:owner/:repo/branches", nil},
{"GET", "/repos/:owner/:repo/branches/:branch", nil},
{"DELETE", "/repos/:owner/:repo", nil},
{"GET", "/repos/:owner/:repo/collaborators", nil},
{"GET", "/repos/:owner/:repo/collaborators/:user", nil},
{"PUT", "/repos/:owner/:repo/collaborators/:user", nil},
{"DELETE", "/repos/:owner/:repo/collaborators/:user", nil},
{"GET", "/repos/:owner/:repo/comments", nil},
{"GET", "/repos/:owner/:repo/commits/:sha/comments", nil},
{"POST", "/repos/:owner/:repo/commits/:sha/comments", nil},
{"GET", "/repos/:owner/:repo/comments/:id", nil},
//{"PATCH", "/repos/:owner/:repo/comments/:id", nil},
{"DELETE", "/repos/:owner/:repo/comments/:id", nil},
{"GET", "/repos/:owner/:repo/commits", nil},
{"GET", "/repos/:owner/:repo/commits/:sha", nil},
{"GET", "/repos/:owner/:repo/readme", nil},
//{"GET", "/repos/:owner/:repo/contents/*path", nil},
//{"PUT", "/repos/:owner/:repo/contents/*path", nil},
//{"DELETE", "/repos/:owner/:repo/contents/*path", nil},
//{"GET", "/repos/:owner/:repo/:archive_format/:ref", nil},
{"GET", "/repos/:owner/:repo/keys", nil},
{"GET", "/repos/:owner/:repo/keys/:id", nil},
{"POST", "/repos/:owner/:repo/keys", nil},
//{"PATCH", "/repos/:owner/:repo/keys/:id", nil},
{"DELETE", "/repos/:owner/:repo/keys/:id", nil},
{"GET", "/repos/:owner/:repo/downloads", nil},
{"GET", "/repos/:owner/:repo/downloads/:id", nil},
{"DELETE", "/repos/:owner/:repo/downloads/:id", nil},
{"GET", "/repos/:owner/:repo/forks", nil},
{"POST", "/repos/:owner/:repo/forks", nil},
{"GET", "/repos/:owner/:repo/hooks", nil},
{"GET", "/repos/:owner/:repo/hooks/:id", nil},
{"POST", "/repos/:owner/:repo/hooks", nil},
//{"PATCH", "/repos/:owner/:repo/hooks/:id", nil},
{"POST", "/repos/:owner/:repo/hooks/:id/tests", nil},
{"DELETE", "/repos/:owner/:repo/hooks/:id", nil},
{"POST", "/repos/:owner/:repo/merges", nil},
{"GET", "/repos/:owner/:repo/releases", nil},
{"GET", "/repos/:owner/:repo/releases/:id", nil},
{"POST", "/repos/:owner/:repo/releases", nil},
//{"PATCH", "/repos/:owner/:repo/releases/:id", nil},
{"DELETE", "/repos/:owner/:repo/releases/:id", nil},
{"GET", "/repos/:owner/:repo/releases/:id/assets", nil},
{"GET", "/repos/:owner/:repo/stats/contributors", nil},
{"GET", "/repos/:owner/:repo/stats/commit_activity", nil},
{"GET", "/repos/:owner/:repo/stats/code_frequency", nil},
{"GET", "/repos/:owner/:repo/stats/participation", nil},
{"GET", "/repos/:owner/:repo/stats/punch_card", nil},
{"GET", "/repos/:owner/:repo/statuses/:ref", nil},
{"POST", "/repos/:owner/:repo/statuses/:ref", nil},
{"GET", "/user/repos", ""},
{"GET", "/users/:user/repos", ""},
{"GET", "/orgs/:org/repos", ""},
{"GET", "/repositories", ""},
{"POST", "/user/repos", ""},
{"POST", "/orgs/:org/repos", ""},
{"GET", "/repos/:owner/:repo", ""},
//{"PATCH", "/repos/:owner/:repo", ""},
{"GET", "/repos/:owner/:repo/contributors", ""},
{"GET", "/repos/:owner/:repo/languages", ""},
{"GET", "/repos/:owner/:repo/teams", ""},
{"GET", "/repos/:owner/:repo/tags", ""},
{"GET", "/repos/:owner/:repo/branches", ""},
{"GET", "/repos/:owner/:repo/branches/:branch", ""},
{"DELETE", "/repos/:owner/:repo", ""},
{"GET", "/repos/:owner/:repo/collaborators", ""},
{"GET", "/repos/:owner/:repo/collaborators/:user", ""},
{"PUT", "/repos/:owner/:repo/collaborators/:user", ""},
{"DELETE", "/repos/:owner/:repo/collaborators/:user", ""},
{"GET", "/repos/:owner/:repo/comments", ""},
{"GET", "/repos/:owner/:repo/commits/:sha/comments", ""},
{"POST", "/repos/:owner/:repo/commits/:sha/comments", ""},
{"GET", "/repos/:owner/:repo/comments/:id", ""},
//{"PATCH", "/repos/:owner/:repo/comments/:id", ""},
{"DELETE", "/repos/:owner/:repo/comments/:id", ""},
{"GET", "/repos/:owner/:repo/commits", ""},
{"GET", "/repos/:owner/:repo/commits/:sha", ""},
{"GET", "/repos/:owner/:repo/readme", ""},
//{"GET", "/repos/:owner/:repo/contents/*path", ""},
//{"PUT", "/repos/:owner/:repo/contents/*path", ""},
//{"DELETE", "/repos/:owner/:repo/contents/*path", ""},
//{"GET", "/repos/:owner/:repo/:archive_format/:ref", ""},
{"GET", "/repos/:owner/:repo/keys", ""},
{"GET", "/repos/:owner/:repo/keys/:id", ""},
{"POST", "/repos/:owner/:repo/keys", ""},
//{"PATCH", "/repos/:owner/:repo/keys/:id", ""},
{"DELETE", "/repos/:owner/:repo/keys/:id", ""},
{"GET", "/repos/:owner/:repo/downloads", ""},
{"GET", "/repos/:owner/:repo/downloads/:id", ""},
{"DELETE", "/repos/:owner/:repo/downloads/:id", ""},
{"GET", "/repos/:owner/:repo/forks", ""},
{"POST", "/repos/:owner/:repo/forks", ""},
{"GET", "/repos/:owner/:repo/hooks", ""},
{"GET", "/repos/:owner/:repo/hooks/:id", ""},
{"POST", "/repos/:owner/:repo/hooks", ""},
//{"PATCH", "/repos/:owner/:repo/hooks/:id", ""},
{"POST", "/repos/:owner/:repo/hooks/:id/tests", ""},
{"DELETE", "/repos/:owner/:repo/hooks/:id", ""},
{"POST", "/repos/:owner/:repo/merges", ""},
{"GET", "/repos/:owner/:repo/releases", ""},
{"GET", "/repos/:owner/:repo/releases/:id", ""},
{"POST", "/repos/:owner/:repo/releases", ""},
//{"PATCH", "/repos/:owner/:repo/releases/:id", ""},
{"DELETE", "/repos/:owner/:repo/releases/:id", ""},
{"GET", "/repos/:owner/:repo/releases/:id/assets", ""},
{"GET", "/repos/:owner/:repo/stats/contributors", ""},
{"GET", "/repos/:owner/:repo/stats/commit_activity", ""},
{"GET", "/repos/:owner/:repo/stats/code_frequency", ""},
{"GET", "/repos/:owner/:repo/stats/participation", ""},
{"GET", "/repos/:owner/:repo/stats/punch_card", ""},
{"GET", "/repos/:owner/:repo/statuses/:ref", ""},
{"POST", "/repos/:owner/:repo/statuses/:ref", ""},
// Search
{"GET", "/search/repositories", nil},
{"GET", "/search/code", nil},
{"GET", "/search/issues", nil},
{"GET", "/search/users", nil},
{"GET", "/legacy/issues/search/:owner/:repository/:state/:keyword", nil},
{"GET", "/legacy/repos/search/:keyword", nil},
{"GET", "/legacy/user/search/:keyword", nil},
{"GET", "/legacy/user/email/:email", nil},
{"GET", "/search/repositories", ""},
{"GET", "/search/code", ""},
{"GET", "/search/issues", ""},
{"GET", "/search/users", ""},
{"GET", "/legacy/issues/search/:owner/:repository/:state/:keyword", ""},
{"GET", "/legacy/repos/search/:keyword", ""},
{"GET", "/legacy/user/search/:keyword", ""},
{"GET", "/legacy/user/email/:email", ""},
// Users
{"GET", "/users/:user", nil},
{"GET", "/user", nil},
//{"PATCH", "/user", nil},
{"GET", "/users", nil},
{"GET", "/user/emails", nil},
{"POST", "/user/emails", nil},
{"DELETE", "/user/emails", nil},
{"GET", "/users/:user/followers", nil},
{"GET", "/user/followers", nil},
{"GET", "/users/:user/following", nil},
{"GET", "/user/following", nil},
{"GET", "/user/following/:user", nil},
{"GET", "/users/:user/following/:target_user", nil},
{"PUT", "/user/following/:user", nil},
{"DELETE", "/user/following/:user", nil},
{"GET", "/users/:user/keys", nil},
{"GET", "/user/keys", nil},
{"GET", "/user/keys/:id", nil},
{"POST", "/user/keys", nil},
//{"PATCH", "/user/keys/:id", nil},
{"DELETE", "/user/keys/:id", nil},
{"GET", "/users/:user", ""},
{"GET", "/user", ""},
//{"PATCH", "/user", ""},
{"GET", "/users", ""},
{"GET", "/user/emails", ""},
{"POST", "/user/emails", ""},
{"DELETE", "/user/emails", ""},
{"GET", "/users/:user/followers", ""},
{"GET", "/user/followers", ""},
{"GET", "/users/:user/following", ""},
{"GET", "/user/following", ""},
{"GET", "/user/following/:user", ""},
{"GET", "/users/:user/following/:target_user", ""},
{"PUT", "/user/following/:user", ""},
{"DELETE", "/user/following/:user", ""},
{"GET", "/users/:user/keys", ""},
{"GET", "/user/keys", ""},
{"GET", "/user/keys/:id", ""},
{"POST", "/user/keys", ""},
//{"PATCH", "/user/keys/:id", ""},
{"DELETE", "/user/keys/:id", ""},
}
)
@ -283,7 +282,7 @@ func TestRouterStatic(t *testing.T) {
return nil
}, e)
c := NewContext(nil, nil, e)
h, _ := r.Find(GET, path, c.X())
h, _ := r.Find(GET, path, c)
if assert.NotNil(t, h) {
h(c)
assert.Equal(t, path, c.Get("path"))
@ -296,7 +295,7 @@ func TestRouterParam(t *testing.T) {
r.Add(GET, "/users/:id", func(c Context) error {
return nil
}, e)
c := NewContext(nil, nil, e).X()
c := NewContext(nil, nil, e)
h, _ := r.Find(GET, "/users/1", c)
if assert.NotNil(t, h) {
assert.Equal(t, "1", c.P(0))
@ -309,7 +308,7 @@ func TestRouterTwoParam(t *testing.T) {
r.Add(GET, "/users/:uid/files/:fid", func(Context) error {
return nil
}, e)
c := NewContext(nil, nil, e).X()
c := NewContext(nil, nil, e)
h, _ := r.Find(GET, "/users/1/files/1", c)
if assert.NotNil(t, h) {
@ -332,7 +331,7 @@ func TestRouterMatchAny(t *testing.T) {
r.Add(GET, "/users/*", func(Context) error {
return nil
}, e)
c := NewContext(nil, nil, e).X()
c := NewContext(nil, nil, e)
h, _ := r.Find(GET, "/", c)
if assert.NotNil(t, h) {
@ -356,7 +355,7 @@ func TestRouterMicroParam(t *testing.T) {
r.Add(GET, "/:a/:b/:c", func(c Context) error {
return nil
}, e)
c := NewContext(nil, nil, e).X()
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))
@ -373,7 +372,7 @@ func TestRouterMixParamMatchAny(t *testing.T) {
r.Add(GET, "/users/:id/*", func(c Context) error {
return nil
}, e)
c := NewContext(nil, nil, e).X()
c := NewContext(nil, nil, e)
h, _ := r.Find(GET, "/users/joe/comments", c)
if assert.NotNil(t, h) {
@ -394,7 +393,7 @@ func TestRouterMultiRoute(t *testing.T) {
r.Add(GET, "/users/:id", func(c Context) error {
return nil
}, e)
c := NewContext(nil, nil, e).X()
c := NewContext(nil, nil, e)
// Route > /users
h, _ := r.Find(GET, "/users", c)
@ -450,7 +449,7 @@ func TestRouterPriority(t *testing.T) {
c.Set("g", 7)
return nil
}, e)
c := NewContext(nil, nil, e).X()
c := NewContext(nil, nil, e)
// Route > /users
h, _ := r.Find(GET, "/users", c)
@ -518,7 +517,7 @@ func TestRouterParamNames(t *testing.T) {
r.Add(GET, "/users/:uid/files/:fid", func(c Context) error {
return nil
}, e)
c := NewContext(nil, nil, e).X()
c := NewContext(nil, nil, e)
// Route > /users
h, _ := r.Find(GET, "/users", c)
@ -530,16 +529,16 @@ func TestRouterParamNames(t *testing.T) {
// 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, "id", c.X().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, "uid", c.X().pnames[0])
assert.Equal(t, "1", c.P(0))
assert.Equal(t, "fid", c.pnames[1])
assert.Equal(t, "fid", c.X().pnames[1])
assert.Equal(t, "1", c.P(1))
}
}
@ -553,11 +552,11 @@ func TestRouterAPI(t *testing.T) {
return nil
}, e)
}
c := NewContext(nil, nil, e).X()
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 {
for i, n := range c.X().pnames {
if assert.NotEmpty(t, n) {
assert.Equal(t, ":"+n, c.P(i))
}
@ -567,27 +566,6 @@ func TestRouterAPI(t *testing.T) {
}
}
func TestRouterServeHTTP(t *testing.T) {
e := New()
r := e.router
r.Add(GET, "/users", func(Context) error {
return nil
}, e)
// OK
req, _ := http.NewRequest(GET, "/users", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
// Not found
req, _ = http.NewRequest(GET, "/files", nil)
w = httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
}
func (n *node) printTree(pfx string, tail bool) {
p := prefix(tail, pfx, "└── ", "├── ")
fmt.Printf("%s%s, %p: type=%d, parent=%p, handler=%v\n", p, n.prefix, n, n.kind, n.parent, n.methodHandler)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

View File

@ -1,7 +1,7 @@
FROM busybox
FROM reg.lab.st/argo
MAINTAINER Vishal Rana <vr@labstack.com>
COPY server /server
COPY public /public
ADD argo.json /etc
ADD public /www
CMD ["/server"]
CMD ["-c", "/etc/argo.json"]

14
website/argo.json Normal file
View File

@ -0,0 +1,14 @@
{
"www": {
"listen": ":80",
"hosts": {
"*": {
"paths": {
"/*": {
"dir": "/www"
}
}
}
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -55,4 +55,4 @@ $ curl localhost:1323/restricted -H "Authorization: Bearer <token>" => 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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -1,2 +1,2 @@
<pre data-src="https://raw.githubusercontent.com/labstack/echo/master/recipes/{{ .Get 0 }}">
<pre data-src="https://raw.githubusercontent.com/vishr/recipes/master/echo/recipes/{{ .Get 0 }}">
</pre>

View File

@ -1 +0,0 @@
{}

View File

@ -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")
}