1
0
mirror of https://github.com/labstack/echo.git synced 2025-01-07 23:01:56 +02:00

license update, some .gitattributes and .gitignore expansion, .travis.yml expansion, golint fixes and .godir for heroku

This commit is contained in:
Chase Hutchins 2016-01-29 04:06:20 -08:00
parent f5a7fb7342
commit e9808b69b4
11 changed files with 194 additions and 59 deletions

18
.gitattributes vendored
View File

@ -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
*.go text eol=lf
*.yml text eol=lf
*.html text eol=lf
# order) to prevent newline related issues)
.* text eolf=lf
*.css text eol=lf
*.go text eol=lf
*.html 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

41
.gitignore vendored
View File

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

1
.godir Normal file
View File

@ -0,0 +1 @@
github.com/labstack/echo

View File

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

View File

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

28
echo.go
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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