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

more godoc

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2016-03-19 15:47:20 -07:00
parent d01e856db6
commit c4caeb8ffb
21 changed files with 372 additions and 189 deletions

View File

@ -22,40 +22,108 @@ import (
)
type (
// Context represents context for the current request. It holds request and
// response objects, path parameters, data and registered handler.
// Context represents the context of the current HTTP request. It holds request and
// response objects, path, path parameters, data and registered handler.
Context interface {
netContext.Context
// NetContext returns `http://blog.golang.org/context.Context` interface.
NetContext() netContext.Context
// SetNetContext sets `http://blog.golang.org/context.Context` interface.
SetNetContext(netContext.Context)
// Request returns `engine.Request` interface.
Request() engine.Request
// Request returns `engine.Response` interface.
Response() engine.Response
// Path returns the registered path for the handler.
Path() string
// P returns path parameter by index.
P(int) string
// Param returns path parameter by name.
Param(string) string
// ParamNames returns path parameter names.
ParamNames() []string
// Query returns query parameter by name.
Query(string) string
// Form returns form parameter by name.
Form(string) string
// Get retrieves data from the context.
Get(string) interface{}
// Set saves data in the context.
Set(string, interface{})
// Bind binds the request body into provided type `i`. The default binder does
// it based on Content-Type header.
Bind(interface{}) error
// Render renders a template with data and sends a text/html response with status
// code. Templates can be registered using `Echo.SetRenderer()`.
Render(int, string, interface{}) error
// HTML sends an HTTP response with status code.
HTML(int, string) error
// String sends a string response with status code.
String(int, string) error
// JSON sends a JSON response with status code.
JSON(int, interface{}) error
// JSONBlob sends a JSON blob response with status code.
JSONBlob(int, []byte) error
// JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload.
JSONP(int, string, interface{}) error
// XML sends an XML response with status code.
XML(int, interface{}) error
// XMLBlob sends a XML blob response with status code.
XMLBlob(int, []byte) error
// File sends a response with the content of the file.
File(string) error
// Attachment sends a response from `io.Reader` as attachment, prompting client
// to save the file.
Attachment(io.Reader, string) error
// NoContent sends a response with no body and a status code.
NoContent(int) error
// Redirect redirects the request with status code.
Redirect(int, string) error
// Error invokes the registered HTTP error handler. Generally used by middleware.
Error(err error)
// Handler implements `Handler` interface.
Handle(Context) error
// Logger returns the `Logger` instance.
Logger() *log.Logger
// Echo returns the `Echo` instance.
Echo() *Echo
// Object returns the `context` instance.
Object() *context
// Reset resets the context after request completes. It must be called along
// with `Echo#GetContext()` and `Echo#PutContext()`. See `Echo#ServeHTTP()`
Reset(engine.Request, engine.Response)
}
context struct {
@ -118,22 +186,18 @@ func (c *context) Handle(ctx Context) error {
return c.handler.Handle(ctx)
}
// Request returns *http.Request.
func (c *context) Request() engine.Request {
return c.request
}
// Response returns `engine.Response`.
func (c *context) Response() engine.Response {
return c.response
}
// Path returns the registered path for the handler.
func (c *context) Path() string {
return c.path
}
// P returns path parameter by index.
func (c *context) P(i int) (value string) {
l := len(c.pnames)
if i < l {
@ -142,7 +206,6 @@ func (c *context) P(i int) (value string) {
return
}
// Param returns path parameter by name.
func (c *context) Param(name string) (value string) {
l := len(c.pnames)
for i, n := range c.pnames {
@ -154,22 +217,18 @@ func (c *context) Param(name string) (value string) {
return
}
// ParamNames returns path parameter names.
func (c *context) ParamNames() []string {
return c.pnames
}
// Query returns query parameter by name.
func (c *context) Query(name string) string {
return c.request.URL().QueryValue(name)
}
// Form returns form parameter by name.
func (c *context) Form(name string) string {
return c.request.FormValue(name)
}
// Set saves data in the context.
func (c *context) Set(key string, val interface{}) {
if c.store == nil {
c.store = make(store)
@ -177,19 +236,14 @@ func (c *context) Set(key string, val interface{}) {
c.store[key] = val
}
// Get retrieves data from the context.
func (c *context) Get(key string) interface{} {
return c.store[key]
}
// Bind binds the request body into provided type `i`. The default binder does
// it based on Content-Type header.
func (c *context) Bind(i interface{}) error {
return c.echo.binder.Bind(i, c)
}
// Render renders a template with data and sends a text/html response with status
// 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 ErrRendererNotRegistered
@ -204,7 +258,6 @@ func (c *context) Render(code int, name string, data interface{}) (err error) {
return
}
// HTML sends an HTTP response with status code.
func (c *context) HTML(code int, html string) (err error) {
c.response.Header().Set(ContentType, TextHTMLCharsetUTF8)
c.response.WriteHeader(code)
@ -212,7 +265,6 @@ func (c *context) HTML(code int, html string) (err error) {
return
}
// String sends a string response with status code.
func (c *context) String(code int, s string) (err error) {
c.response.Header().Set(ContentType, TextPlainCharsetUTF8)
c.response.WriteHeader(code)
@ -220,7 +272,6 @@ func (c *context) String(code int, s string) (err error) {
return
}
// JSON sends a JSON response with status code.
func (c *context) JSON(code int, i interface{}) (err error) {
b, err := json.Marshal(i)
if c.echo.Debug() {
@ -232,7 +283,6 @@ func (c *context) JSON(code int, i interface{}) (err error) {
return c.JSONBlob(code, b)
}
// 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)
@ -240,8 +290,6 @@ func (c *context) JSONBlob(code int, b []byte) (err error) {
return
}
// JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload.
func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
b, err := json.Marshal(i)
if err != nil {
@ -259,7 +307,6 @@ func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
return
}
// XML sends an XML response with status code.
func (c *context) XML(code int, i interface{}) (err error) {
b, err := xml.Marshal(i)
if c.echo.Debug() {
@ -271,7 +318,6 @@ func (c *context) XML(code int, i interface{}) (err error) {
return c.XMLBlob(code, b)
}
// XMLBlob sends a XML blob response with status code.
func (c *context) XMLBlob(code int, b []byte) (err error) {
c.response.Header().Set(ContentType, ApplicationXMLCharsetUTF8)
c.response.WriteHeader(code)
@ -282,7 +328,6 @@ func (c *context) XMLBlob(code int, b []byte) (err error) {
return
}
// File sends a response with the content of the file.
func (c *context) File(file string) error {
root, file := filepath.Split(file)
fs := http.Dir(root)
@ -305,8 +350,6 @@ func (c *context) File(file string) error {
return ServeContent(c.Request(), c.Response(), f, fi)
}
// Attachment sends a response from `io.Reader` as attachment, prompting client
// to save the file.
func (c *context) Attachment(r io.Reader, name string) (err error) {
c.response.Header().Set(ContentType, detectContentType(name))
c.response.Header().Set(ContentDisposition, "attachment; filename="+name)
@ -315,13 +358,11 @@ func (c *context) Attachment(r io.Reader, name string) (err error) {
return
}
// NoContent sends a response with no body and a status code.
func (c *context) NoContent(code int) error {
c.response.WriteHeader(code)
return nil
}
// Redirect redirects the request with status code.
func (c *context) Redirect(code int, url string) error {
if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
return ErrInvalidRedirectCode
@ -331,26 +372,24 @@ func (c *context) Redirect(code int, url string) error {
return nil
}
// Error invokes the registered HTTP error handler. Generally used by middleware.
func (c *context) Error(err error) {
c.echo.httpErrorHandler(err, c)
}
// Echo returns the `Echo` instance.
func (c *context) Echo() *Echo {
return c.echo
}
// Logger returns the `Logger` instance.
func (c *context) Logger() *log.Logger {
return c.echo.logger
}
// Object returns the `context` object.
func (c *context) Object() *context {
return c
}
// ServeContent sends a response from `io.Reader`. It automatically sets the `Content-Type`
// and `Last-Modified` headers.
func ServeContent(req engine.Request, res engine.Response, f http.File, fi os.FileInfo) error {
res.Header().Set(ContentType, detectContentType(fi.Name()))
res.Header().Set(LastModified, fi.ModTime().UTC().Format(http.TimeFormat))
@ -366,7 +405,7 @@ func detectContentType(name string) (t string) {
return
}
func (c *context) reset(req engine.Request, res engine.Response) {
func (c *context) Reset(req engine.Request, res engine.Response) {
c.netContext = nil
c.request = req
c.response = res

View File

@ -191,8 +191,8 @@ func TestContext(t *testing.T) {
c.Error(errors.New("error"))
assert.Equal(t, http.StatusInternalServerError, rec.Status())
// reset
c.Object().reset(req, test.NewResponseRecorder())
// Reset
c.Object().Reset(req, test.NewResponseRecorder())
}
func TestContextPath(t *testing.T) {

179
echo.go
View File

@ -1,3 +1,42 @@
/*
Package echo implements a fast and unfancy micro web framework for Go.
Example:
package main
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/engine/standard"
"github.com/labstack/echo/middleware"
)
// Handler
func hello() echo.HandlerFunc {
return func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!\n")
}
}
func main() {
// Echo instance
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.Get("/", hello())
// Start server
e.Run(standard.New(":1323"))
}
Learn more at https://labstack.com/echo
*/
package echo
import (
@ -20,6 +59,7 @@ import (
)
type (
// Echo is the top-level framework instance.
Echo struct {
prefix string
middleware []Middleware
@ -36,33 +76,43 @@ type (
logger *log.Logger
}
// Route contains a handler and information for matching against requests.
Route struct {
Method string
Path string
Handler string
}
// HTTPError represents an error that occured while handling a request.
HTTPError struct {
Code int
Message string
}
// Middleware defines an interface for middleware via `Handle(Handler) Handler`
// function.
Middleware interface {
Handle(Handler) Handler
}
// MiddlewareFunc is an adapter to allow the use of `func(Handler) Handler` as
// middleware.
MiddlewareFunc func(Handler) Handler
// Handler defines an interface to server HTTP requests via `Handle(Context)`
// function.
Handler interface {
Handle(Context) error
}
// HandlerFunc is an adapter to allow the use of `func(Context)` as an HTTP
// handler.
HandlerFunc func(Context) error
// HTTPErrorHandler is a centralized HTTP error handler.
HTTPErrorHandler func(error, Context)
// Binder is the interface that wraps the Bind method.
// Binder is the interface that wraps the Bind function.
Binder interface {
Bind(interface{}, Context) error
}
@ -70,41 +120,36 @@ type (
binder struct {
}
// Validator is the interface that wraps the Validate method.
// Validator is the interface that wraps the Validate function.
Validator interface {
Validate() error
}
// Renderer is the interface that wraps the Render method.
// Renderer is the interface that wraps the Render function.
Renderer interface {
Render(io.Writer, string, interface{}, Context) error
}
)
//--------------
// HTTP methods
//--------------
const (
// CONNECT HTTP method
CONNECT = "CONNECT"
// DELETE HTTP method
DELETE = "DELETE"
// GET HTTP method
GET = "GET"
// HEAD HTTP method
HEAD = "HEAD"
// OPTIONS HTTP method
DELETE = "DELETE"
GET = "GET"
HEAD = "HEAD"
OPTIONS = "OPTIONS"
// PATCH HTTP method
PATCH = "PATCH"
// POST HTTP method
POST = "POST"
// PUT HTTP method
PUT = "PUT"
// TRACE HTTP method
TRACE = "TRACE"
//-------------
// Media types
//-------------
PATCH = "PATCH"
POST = "POST"
PUT = "PUT"
TRACE = "TRACE"
)
//-------------
// Media types
//-------------
const (
ApplicationJSON = "application/json"
ApplicationJSONCharsetUTF8 = ApplicationJSON + "; " + CharsetUTF8
ApplicationJavaScript = "application/javascript"
@ -120,17 +165,19 @@ const (
TextPlainCharsetUTF8 = TextPlain + "; " + CharsetUTF8
MultipartForm = "multipart/form-data"
OctetStream = "application/octet-stream"
)
//---------
// Charset
//---------
//---------
// Charset
//---------
const (
CharsetUTF8 = "charset=utf-8"
)
//---------
// Headers
//---------
//---------
// Headers
//---------
const (
AcceptEncoding = "Accept-Encoding"
Authorization = "Authorization"
ContentDisposition = "Content-Disposition"
@ -158,22 +205,24 @@ var (
PUT,
TRACE,
}
)
//--------
// Errors
//--------
//--------
// Errors
//--------
var (
ErrUnsupportedMediaType = NewHTTPError(http.StatusUnsupportedMediaType)
ErrNotFound = NewHTTPError(http.StatusNotFound)
ErrUnauthorized = NewHTTPError(http.StatusUnauthorized)
ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed)
ErrRendererNotRegistered = errors.New("renderer not registered")
ErrInvalidRedirectCode = errors.New("invalid redirect status code")
)
//----------------
// Error handlers
//----------------
//----------------
// Error handlers
//----------------
var (
notFoundHandler = HandlerFunc(func(c Context) error {
return ErrNotFound
})
@ -206,12 +255,14 @@ func New() (e *Echo) {
return
}
func (m MiddlewareFunc) Handle(h Handler) Handler {
return m(h)
// Handle chains middleware.
func (f MiddlewareFunc) Handle(h Handler) Handler {
return f(h)
}
func (h HandlerFunc) Handle(c Context) error {
return h(c)
// Handle serves HTTP request.
func (f HandlerFunc) Handle(c Context) error {
return f(c)
}
// Router returns router.
@ -261,12 +312,12 @@ func (e *Echo) SetHTTPErrorHandler(h HTTPErrorHandler) {
e.httpErrorHandler = h
}
// SetBinder registers a custom binder. It's invoked by Context.Bind().
// SetBinder registers a custom binder. It's invoked by `Context#Bind()`.
func (e *Echo) SetBinder(b Binder) {
e.binder = b
}
// SetRenderer registers an HTML template renderer. It's invoked by Context.Render().
// SetRenderer registers an HTML template renderer. It's invoked by `Context#Render()`.
func (e *Echo) SetRenderer(r Renderer) {
e.renderer = r
}
@ -301,59 +352,70 @@ func (e *Echo) chainMiddleware() {
}
}
// Connect adds a CONNECT route > handler to the router.
// Connect registers a new CONNECT route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Connect(path string, h Handler, m ...Middleware) {
e.add(CONNECT, path, h, m...)
}
// Delete adds a DELETE route > handler to the router.
// Delete registers a new DELETE route for a path with matching handler in the router
// with optional route-level middleware.
func (e *Echo) Delete(path string, h Handler, m ...Middleware) {
e.add(DELETE, path, h, m...)
}
// Get adds a GET route > handler to the router.
// Get registers a new GET route for a path with matching handler in the router
// with optional route-level middleware.
func (e *Echo) Get(path string, h Handler, m ...Middleware) {
e.add(GET, path, h, m...)
}
// Head adds a HEAD route > handler to the router.
// Head registers a new HEAD route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Head(path string, h Handler, m ...Middleware) {
e.add(HEAD, path, h, m...)
}
// Options adds an OPTIONS route > handler to the router.
// Options registers a new OPTIONS route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Options(path string, h Handler, m ...Middleware) {
e.add(OPTIONS, path, h, m...)
}
// Patch adds a PATCH route > handler to the router.
// Patch registers a new PATCH route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Patch(path string, h Handler, m ...Middleware) {
e.add(PATCH, path, h, m...)
}
// Post adds a POST route > handler to the router.
// Post registers a new POST route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Post(path string, h Handler, m ...Middleware) {
e.add(POST, path, h, m...)
}
// Put adds a PUT route > handler to the router.
// Put registers a new PUT route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Put(path string, h Handler, m ...Middleware) {
e.add(PUT, path, h, m...)
}
// Trace adds a TRACE route > handler to the router.
// Trace registers a new TRACE route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Trace(path string, h Handler, m ...Middleware) {
e.add(TRACE, path, h, m...)
}
// Any adds a route > handler to the router for all HTTP methods.
// Any registers a new route for all HTTP methods and path with matching handler
// in the router with optional route-level middleware.
func (e *Echo) Any(path string, handler Handler, middleware ...Middleware) {
for _, m := range methods {
e.add(m, path, handler, middleware...)
}
}
// Match adds a route > handler to the router for multiple HTTP methods provided.
// Match registers a new route for multiple HTTP methods and path with matching
// handler in the router with optional route-level middleware.
func (e *Echo) Match(methods []string, path string, handler Handler, middleware ...Middleware) {
for _, m := range methods {
e.add(m, path, handler, middleware...)
@ -392,7 +454,7 @@ func (e *Echo) add(method, path string, handler Handler, middleware ...Middlewar
e.router.routes = append(e.router.routes, r)
}
// Group creates a new router group with prefix.
// Group creates a new router group with prefix and optional group-level middleware.
func (e *Echo) Group(prefix string, m ...Middleware) (g *Group) {
g = &Group{prefix: prefix, echo: e}
g.Use(m...)
@ -448,7 +510,7 @@ func (e *Echo) PutContext(c Context) {
func (e *Echo) ServeHTTP(req engine.Request, res engine.Response) {
c := e.pool.Get().(*context)
c.reset(req, res)
c.Reset(req, res)
// Execute chain
if err := e.head.Handle(c); err != nil {
@ -465,6 +527,7 @@ func (e *Echo) Run(s engine.Server) error {
return s.Start()
}
// 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 {

View File

@ -54,7 +54,7 @@ type (
// RemoteAddress returns the client's network address.
RemoteAddress() string
// Method returns the request's HTTP method.
// Method returns the request's HTTP function.
Method() string
// SetMethod sets the HTTP method of the request.
@ -136,7 +136,7 @@ type (
QueryString() string
}
// Config defines engine configuration.
// Config defines engine config.
Config struct {
Address string // TCP address to listen on.
Listener net.Listener // Custom `net.Listener`. If set, server accepts connections on it.
@ -152,7 +152,8 @@ type (
ServeHTTP(Request, Response)
}
// HandlerFunc is an adapter to allow the use of `func(Request, Response)` as HTTP handlers.
// HandlerFunc is an adapter to allow the use of `func(Request, Response)` as
// an HTTP handler.
HandlerFunc func(Request, Response)
)

View File

@ -16,27 +16,27 @@ type (
}
)
// Add implements `engine.Header#Add` method.
// Add implements `engine.Header#Add` function.
func (h *RequestHeader) Add(key, val string) {
// h.RequestHeader.Add(key, val)
}
// Del implements `engine.Header#Del` method.
// Del implements `engine.Header#Del` function.
func (h *RequestHeader) Del(key string) {
h.RequestHeader.Del(key)
}
// Set implements `engine.Header#Set` method.
// Set implements `engine.Header#Set` function.
func (h *RequestHeader) Set(key, val string) {
h.RequestHeader.Set(key, val)
}
// Get implements `engine.Header#Get` method.
// Get implements `engine.Header#Get` function.
func (h *RequestHeader) Get(key string) string {
return string(h.Peek(key))
}
// Keys implements `engine.Header#Keys` method.
// Keys implements `engine.Header#Keys` function.
func (h *RequestHeader) Keys() (keys []string) {
keys = make([]string, h.Len())
i := 0
@ -51,28 +51,28 @@ func (h *RequestHeader) reset(hdr *fasthttp.RequestHeader) {
h.RequestHeader = hdr
}
// Add implements `engine.Header#Add` method.
// Add implements `engine.Header#Add` function.
func (h *ResponseHeader) Add(key, val string) {
// TODO: https://github.com/valyala/fasthttp/issues/69
// h.header.Add(key, val)
}
// Del implements `engine.Header#Del` method.
// Del implements `engine.Header#Del` function.
func (h *ResponseHeader) Del(key string) {
h.ResponseHeader.Del(key)
}
// Get implements `engine.Header#Get` method.
// Get implements `engine.Header#Get` function.
func (h *ResponseHeader) Get(key string) string {
return string(h.Peek(key))
}
// Set implements `engine.Header#Set` method.
// Set implements `engine.Header#Set` function.
func (h *ResponseHeader) Set(key, val string) {
h.ResponseHeader.Set(key, val)
}
// Keys implements `engine.Header#Keys` method.
// Keys implements `engine.Header#Keys` function.
func (h *ResponseHeader) Keys() (keys []string) {
keys = make([]string, h.Len())
i := 0

View File

@ -22,72 +22,72 @@ type (
}
)
// TLS implements `engine.Request#TLS` method.
// TLS implements `engine.Request#TLS` function.
func (r *Request) TLS() bool {
return r.IsTLS()
}
// Scheme implements `engine.Request#Scheme` method.
// Scheme implements `engine.Request#Scheme` function.
func (r *Request) Scheme() string {
return string(r.RequestCtx.URI().Scheme())
}
// Host implements `engine.Request#Host` method.
// Host implements `engine.Request#Host` function.
func (r *Request) Host() string {
return string(r.RequestCtx.Host())
}
// URL implements `engine.Request#URL` method.
// URL implements `engine.Request#URL` function.
func (r *Request) URL() engine.URL {
return r.url
}
// Header implements `engine.Request#Header` method.
// Header implements `engine.Request#Header` function.
func (r *Request) Header() engine.Header {
return r.header
}
// UserAgent implements `engine.Request#UserAgent` method.
// UserAgent implements `engine.Request#UserAgent` function.
func (r *Request) UserAgent() string {
return string(r.RequestCtx.UserAgent())
}
// RemoteAddress implements `engine.Request#RemoteAddress` method.
// RemoteAddress implements `engine.Request#RemoteAddress` function.
func (r *Request) RemoteAddress() string {
return r.RemoteAddr().String()
}
// Method implements `engine.Request#Method` method.
// Method implements `engine.Request#Method` function.
func (r *Request) Method() string {
return string(r.RequestCtx.Method())
}
// SetMethod implements `engine.Request#SetMethod` method.
// SetMethod implements `engine.Request#SetMethod` function.
func (r *Request) SetMethod(method string) {
r.Request.Header.SetMethod(method)
}
// URI implements `engine.Request#URI` method.
// URI implements `engine.Request#URI` function.
func (r *Request) URI() string {
return string(r.RequestURI())
}
// Body implements `engine.Request#Body` method.
// Body implements `engine.Request#Body` function.
func (r *Request) Body() io.Reader {
return bytes.NewBuffer(r.PostBody())
}
// FormValue implements `engine.Request#FormValue` method.
// FormValue implements `engine.Request#FormValue` function.
func (r *Request) FormValue(name string) string {
return string(r.RequestCtx.FormValue(name))
}
// FormFile implements `engine.Request#FormFile` method.
// FormFile implements `engine.Request#FormFile` function.
func (r *Request) FormFile(name string) (*multipart.FileHeader, error) {
return r.RequestCtx.FormFile(name)
}
// MultipartForm implements `engine.Request#MultipartForm` method.
// MultipartForm implements `engine.Request#MultipartForm` function.
func (r *Request) MultipartForm() (*multipart.Form, error) {
return r.RequestCtx.MultipartForm()
}

View File

@ -24,12 +24,12 @@ type (
}
)
// Header implements `engine.Response#Header` method.
// Header implements `engine.Response#Header` function.
func (r *Response) Header() engine.Header {
return r.header
}
// WriteHeader implements `engine.Response#WriteHeader` method.
// WriteHeader implements `engine.Response#WriteHeader` function.
func (r *Response) WriteHeader(code int) {
if r.committed {
r.logger.Warn("response already committed")
@ -40,34 +40,34 @@ func (r *Response) WriteHeader(code int) {
r.committed = true
}
// Write implements `engine.Response#Write` method.
// Write implements `engine.Response#Write` function.
func (r *Response) Write(b []byte) (n int, err error) {
n, err = r.writer.Write(b)
r.size += int64(n)
return
}
// Status implements `engine.Response#Status` method.
// Status implements `engine.Response#Status` function.
func (r *Response) Status() int {
return r.status
}
// Size implements `engine.Response#Size` method.
// Size implements `engine.Response#Size` function.
func (r *Response) Size() int64 {
return r.size
}
// Committed implements `engine.Response#Committed` method.
// Committed implements `engine.Response#Committed` function.
func (r *Response) Committed() bool {
return r.committed
}
// Writer implements `engine.Response#Writer` method.
// Writer implements `engine.Response#Writer` function.
func (r *Response) Writer() io.Writer {
return r.writer
}
// SetWriter implements `engine.Response#SetWriter` method.
// SetWriter implements `engine.Response#SetWriter` function.
func (r *Response) SetWriter(w io.Writer) {
r.writer = w
}

View File

@ -87,17 +87,17 @@ func NewFromConfig(c engine.Config) (s *Server) {
return
}
// SetHandler implements `engine.Server#SetHandler` method.
// SetHandler implements `engine.Server#SetHandler` function.
func (s *Server) SetHandler(h engine.Handler) {
s.handler = h
}
// SetLogger implements `engine.Server#SetLogger` method.
// SetLogger implements `engine.Server#SetLogger` function.
func (s *Server) SetLogger(l *log.Logger) {
s.logger = l
}
// Start implements `engine.Server#Start` method.
// Start implements `engine.Server#Start` function.
func (s *Server) Start() error {
if s.config.Listener == nil {
return s.startDefaultListener()

View File

@ -11,22 +11,22 @@ type (
}
)
// Path implements `engine.URL#Path` method.
// Path implements `engine.URL#Path` function.
func (u *URL) Path() string {
return string(u.URI.Path())
}
// SetPath implements `engine.URL#SetPath` method.
// SetPath implements `engine.URL#SetPath` function.
func (u *URL) SetPath(path string) {
u.URI.SetPath(path)
}
// QueryValue implements `engine.URL#QueryValue` method.
// QueryValue implements `engine.URL#QueryValue` function.
func (u *URL) QueryValue(name string) string {
return string(u.QueryArgs().Peek(name))
}
// QueryString implements `engine.URL#QueryString` method.
// QueryString implements `engine.URL#QueryString` function.
func (u *URL) QueryString() string {
return string(u.URI.QueryString())
}

View File

@ -9,27 +9,27 @@ type (
}
)
// Add implements `engine.Header#Add` method.
// Add implements `engine.Header#Add` function.
func (h *Header) Add(key, val string) {
h.Header.Add(key, val)
}
// Del implements `engine.Header#Del` method.
// Del implements `engine.Header#Del` function.
func (h *Header) Del(key string) {
h.Header.Del(key)
}
// Set implements `engine.Header#Set` method.
// Set implements `engine.Header#Set` function.
func (h *Header) Set(key, val string) {
h.Header.Set(key, val)
}
// Get implements `engine.Header#Get` method.
// Get implements `engine.Header#Get` function.
func (h *Header) Get(key string) string {
return h.Header.Get(key)
}
// Keys implements `engine.Header#Keys` method.
// Keys implements `engine.Header#Keys` function.
func (h *Header) Keys() (keys []string) {
keys = make([]string, len(h.Header))
i := 0

View File

@ -17,12 +17,12 @@ type (
}
)
// TLS implements `engine.Request#TLS` method.
// TLS implements `engine.Request#TLS` function.
func (r *Request) TLS() bool {
return r.Request.TLS != nil
}
// Scheme implements `engine.Request#Scheme` method.
// Scheme implements `engine.Request#Scheme` function.
func (r *Request) Scheme() string {
if r.TLS() {
return "https"
@ -30,17 +30,17 @@ func (r *Request) Scheme() string {
return "http"
}
// Host implements `engine.Request#Host` method.
// Host implements `engine.Request#Host` function.
func (r *Request) Host() string {
return r.Request.Host
}
// URL implements `engine.Request#URL` method.
// URL implements `engine.Request#URL` function.
func (r *Request) URL() engine.URL {
return r.url
}
// Header implements `engine.Request#URL` method.
// Header implements `engine.Request#URL` function.
func (r *Request) Header() engine.Header {
return r.header
}
@ -57,48 +57,48 @@ func (r *Request) Header() engine.Header {
// return r.request.ProtoMinor()
// }
// UserAgent implements `engine.Request#UserAgent` method.
// UserAgent implements `engine.Request#UserAgent` function.
func (r *Request) UserAgent() string {
return r.Request.UserAgent()
}
// RemoteAddress implements `engine.Request#RemoteAddress` method.
// RemoteAddress implements `engine.Request#RemoteAddress` function.
func (r *Request) RemoteAddress() string {
return r.RemoteAddr
}
// Method implements `engine.Request#Method` method.
// Method implements `engine.Request#Method` function.
func (r *Request) Method() string {
return r.Request.Method
}
// SetMethod implements `engine.Request#SetMethod` method.
// SetMethod implements `engine.Request#SetMethod` function.
func (r *Request) SetMethod(method string) {
r.Request.Method = method
}
// URI implements `engine.Request#URI` method.
// URI implements `engine.Request#URI` function.
func (r *Request) URI() string {
return r.RequestURI
}
// Body implements `engine.Request#Body` method.
// Body implements `engine.Request#Body` function.
func (r *Request) Body() io.Reader {
return r.Request.Body
}
// FormValue implements `engine.Request#FormValue` method.
// FormValue implements `engine.Request#FormValue` function.
func (r *Request) FormValue(name string) string {
return r.Request.FormValue(name)
}
// FormFile implements `engine.Request#FormFile` method.
// FormFile implements `engine.Request#FormFile` function.
func (r *Request) FormFile(name string) (*multipart.FileHeader, error) {
_, fh, err := r.Request.FormFile(name)
return fh, err
}
// MultipartForm implements `engine.Request#MultipartForm` method.
// MultipartForm implements `engine.Request#MultipartForm` function.
func (r *Request) MultipartForm() (*multipart.Form, error) {
err := r.Request.ParseMultipartForm(32 << 20) // 32 MB
return r.Request.MultipartForm, err

View File

@ -28,12 +28,12 @@ type (
}
)
// Header implements `engine.Response#Header` method.
// Header implements `engine.Response#Header` function.
func (r *Response) Header() engine.Header {
return r.header
}
// WriteHeader implements `engine.Response#WriteHeader` method.
// WriteHeader implements `engine.Response#WriteHeader` function.
func (r *Response) WriteHeader(code int) {
if r.committed {
r.logger.Warn("response already committed")
@ -44,48 +44,48 @@ func (r *Response) WriteHeader(code int) {
r.committed = true
}
// Write implements `engine.Response#Write` method.
// Write implements `engine.Response#Write` function.
func (r *Response) Write(b []byte) (n int, err error) {
n, err = r.writer.Write(b)
r.size += int64(n)
return
}
// Status implements `engine.Response#Status` method.
// Status implements `engine.Response#Status` function.
func (r *Response) Status() int {
return r.status
}
// Size implements `engine.Response#Size` method.
// Size implements `engine.Response#Size` function.
func (r *Response) Size() int64 {
return r.size
}
// Committed implements `engine.Response#Committed` method.
// Committed implements `engine.Response#Committed` function.
func (r *Response) Committed() bool {
return r.committed
}
// Writer implements `engine.Response#Writer` method.
// Writer implements `engine.Response#Writer` function.
func (r *Response) Writer() io.Writer {
return r.writer
}
// SetWriter implements `engine.Response#SetWriter` method.
// SetWriter implements `engine.Response#SetWriter` function.
func (r *Response) SetWriter(w io.Writer) {
r.writer = w
}
// 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)
// See https://golang.org/pkg/net/http/#Flusher
func (r *Response) Flush() {
r.ResponseWriter.(http.Flusher).Flush()
}
// 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)
// See https://golang.org/pkg/net/http/#Hijacker
func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return r.ResponseWriter.(http.Hijacker).Hijack()
}
@ -94,7 +94,7 @@ func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
// 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)
// See https://golang.org/pkg/net/http/#CloseNotifier
func (r *Response) CloseNotify() <-chan bool {
return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

View File

@ -80,17 +80,17 @@ func NewFromConfig(c engine.Config) (s *Server) {
return
}
// SetHandler implements `engine.Server#SetHandler` method.
// SetHandler implements `engine.Server#SetHandler` function.
func (s *Server) SetHandler(h engine.Handler) {
s.handler = h
}
// SetLogger implements `engine.Server#SetLogger` method.
// SetLogger implements `engine.Server#SetLogger` function.
func (s *Server) SetLogger(l *log.Logger) {
s.logger = l
}
// Start implements `engine.Server#Start` method.
// Start implements `engine.Server#Start` function.
func (s *Server) Start() error {
if s.config.Listener == nil {
return s.startDefaultListener()

View File

@ -10,17 +10,17 @@ type (
}
)
// Path implements `engine.URL#Path` method.
// Path implements `engine.URL#Path` function.
func (u *URL) Path() string {
return u.URL.Path
}
// SetPath implements `engine.URL#SetPath` method.
// SetPath implements `engine.URL#SetPath` function.
func (u *URL) SetPath(path string) {
u.URL.Path = path
}
// QueryValue implements `engine.URL#QueryValue` method.
// QueryValue implements `engine.URL#QueryValue` function.
func (u *URL) QueryValue(name string) string {
if u.query == nil {
u.query = u.Query()
@ -28,7 +28,7 @@ func (u *URL) QueryValue(name string) string {
return u.query.Get(name)
}
// QueryString implements `engine.URL#QueryString` method.
// QueryString implements `engine.URL#QueryString` function.
func (u *URL) QueryString() string {
return u.URL.RawQuery
}

View File

@ -1,6 +1,9 @@
package echo
type (
// Group is a set of sub-routes 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.
Group struct {
prefix string
middleware []Middleware
@ -8,59 +11,71 @@ type (
}
)
// Use implements `Echo#Use()` for sub-routes within the Group.
func (g *Group) Use(m ...Middleware) {
g.middleware = append(g.middleware, m...)
}
// Connect implements `Echo#Connect()` for sub-routes within the Group.
func (g *Group) Connect(path string, h Handler, m ...Middleware) {
g.add(CONNECT, path, h, m...)
}
// Delete implements `Echo#Delete()` for sub-routes within the Group.
func (g *Group) Delete(path string, h Handler, m ...Middleware) {
g.add(DELETE, path, h, m...)
}
// Get implements `Echo#Get()` for sub-routes within the Group.
func (g *Group) Get(path string, h Handler, m ...Middleware) {
g.add(GET, path, h, m...)
}
// Head implements `Echo#Head()` for sub-routes within the Group.
func (g *Group) Head(path string, h Handler, m ...Middleware) {
g.add(HEAD, path, h, m...)
}
// Options implements `Echo#Options()` for sub-routes within the Group.
func (g *Group) Options(path string, h Handler, m ...Middleware) {
g.add(OPTIONS, path, h, m...)
}
// Patch implements `Echo#Patch()` for sub-routes within the Group.
func (g *Group) Patch(path string, h Handler, m ...Middleware) {
g.add(PATCH, path, h, m...)
}
// Post implements `Echo#Post()` for sub-routes within the Group.
func (g *Group) Post(path string, h Handler, m ...Middleware) {
g.add(POST, path, h, m...)
}
// Put implements `Echo#Put()` for sub-routes within the Group.
func (g *Group) Put(path string, h Handler, m ...Middleware) {
g.add(PUT, path, h, m...)
}
// Trace implements `Echo#Trace()` for sub-routes within the Group.
func (g *Group) Trace(path string, h Handler, m ...Middleware) {
g.add(TRACE, path, h, m...)
}
// Any implements `Echo#Any()` for sub-routes within the Group.
func (g *Group) Any(path string, handler Handler, middleware ...Middleware) {
for _, m := range methods {
g.add(m, path, handler, middleware...)
}
}
// Match implements `Echo#Match()` for sub-routes within the Group.
func (g *Group) Match(methods []string, path string, handler Handler, middleware ...Middleware) {
for _, m := range methods {
g.add(m, path, handler, middleware...)
}
}
// Group creates a new sub-group with prefix.
// Group creates a new sub-group with prefix and optional sub-group-level middleware.
func (g *Group) Group(prefix string, m ...Middleware) *Group {
m = append(g.middleware, m...)
return g.echo.Group(g.prefix+prefix, m...)

View File

@ -7,10 +7,12 @@ import (
)
type (
// BasicAuthConfig defines config for HTTP basic auth middleware.
BasicAuthConfig struct {
AuthFunc BasicAuthFunc
}
// BasicAuthFunc defines a function to validate basic auth credentials.
BasicAuthFunc func(string, string) bool
)
@ -19,10 +21,11 @@ const (
)
var (
// DefaultBasicAuthConfig is the default basic auth middleware config.
DefaultBasicAuthConfig = BasicAuthConfig{}
)
// BasicAuth returns an HTTP basic authentication middleware.
// BasicAuth returns an HTTP basic auth middleware.
//
// For valid credentials it calls the next handler.
// For invalid credentials, it sends "401 - Unauthorized" response.
@ -32,6 +35,8 @@ func BasicAuth(f BasicAuthFunc) echo.MiddlewareFunc {
return BasicAuthFromConfig(c)
}
// BasicAuthFromConfig returns an HTTP basic auth middleware from config.
// See `BasicAuth()`.
func BasicAuthFromConfig(config BasicAuthConfig) echo.MiddlewareFunc {
return func(next echo.Handler) echo.Handler {
return echo.HandlerFunc(func(c echo.Context) error {

View File

@ -13,7 +13,9 @@ import (
)
type (
// GzipConfig defines config for gzip middleware.
GzipConfig struct {
// Level is the gzip level.
Level int
}
@ -24,7 +26,8 @@ type (
)
var (
defaultGzipConfig = GzipConfig{
// DefaultGzipConfig is the default gzip middleware config.
DefaultGzipConfig = GzipConfig{
Level: gzip.DefaultCompression,
}
)
@ -32,10 +35,11 @@ var (
// Gzip returns a middleware which compresses HTTP response using gzip compression
// scheme.
func Gzip() echo.MiddlewareFunc {
return GzipFromConfig(defaultGzipConfig)
return GzipFromConfig(DefaultGzipConfig)
}
// GzipFromConfig return `Gzip` middleware from config.
// GzipFromConfig return gzip middleware from config.
// See `Gzip()`.
func GzipFromConfig(config GzipConfig) echo.MiddlewareFunc {
pool := gzipPool(config)
scheme := "gzip"

View File

@ -15,26 +15,46 @@ import (
)
type (
// LoggerConfig defines config for logger middleware.
//
LoggerConfig struct {
Format string
Output io.Writer
// Format is the log format.
//
// Example "${remote_id} ${status}"
// Available tags:
// - time_rfc3339
// - remote_ip
// - method
// - path
// - status
// - response_time
// - response_size
Format string
// Output is the writer where logs are written. Default is `os.Stdout`.
Output io.Writer
template *fasttemplate.Template
color *color.Color
}
)
var (
// DefaultLoggerConfig is the default logger middleware config.
DefaultLoggerConfig = LoggerConfig{
Format: "time=${time_rfc3339}, remote_ip=${remote_ip}, method=${method}, path=${path}, status=${status}, response_time=${response_time}, size=${size}\n",
Format: "time=${time_rfc3339}, remote_ip=${remote_ip}, method=${method}, path=${path}, status=${status}, response_time=${response_time}, response_size=${response_size} bytes\n",
color: color.New(),
Output: os.Stdout,
}
)
// Logger returns a middleware that logs HTTP requests.
func Logger() echo.MiddlewareFunc {
return LoggerFromConfig(DefaultLoggerConfig)
}
// LoggerFromConfig returns a logger middleware from config.
// See `Logger()`.
func LoggerFromConfig(config LoggerConfig) echo.MiddlewareFunc {
config.template = fasttemplate.New(config.Format, "${", "}")
config.color = color.New()
@ -94,7 +114,7 @@ func LoggerFromConfig(config LoggerConfig) echo.MiddlewareFunc {
return w.Write([]byte(status))
case "response_time":
return w.Write([]byte(took.String()))
case "size":
case "response_size":
return w.Write([]byte(size))
default:
return w.Write([]byte(fmt.Sprintf("[unknown tag %s]", tag)))

View File

@ -9,14 +9,22 @@ import (
)
type (
// RecoverConfig defines config for recover middleware.
RecoverConfig struct {
StackSize int
StackAll bool
// StackSize is the stack size to be printed.
StackSize int
// StackAll is flag to format stack traces of all other goroutines into
// buffer after the trace for the current goroutine, or not. Default is true.
StackAll bool
// PrintStack is the flag to print stack or not. Default is true.
PrintStack bool
}
)
var (
// DefaultRecoverConfig is the default recover middleware config.
DefaultRecoverConfig = RecoverConfig{
StackSize: 4 << 10, // 4 KB
StackAll: true,
@ -24,12 +32,14 @@ var (
}
)
// Recover returns a middleware which recovers from panics anywhere in the chain
// and handles the control to the centralized HTTPErrorHandler.
func Recover() echo.MiddlewareFunc {
return RecoverFromConfig(DefaultRecoverConfig)
}
// Recover returns a middleware which recovers from panics anywhere in the chain
// and handles the control to the centralized HTTPErrorHandler.
// RecoverFromConfig returns a recover middleware from config.
// See `Recover()`.
func RecoverFromConfig(config RecoverConfig) echo.MiddlewareFunc {
return func(next echo.Handler) echo.Handler {
return echo.HandlerFunc(func(c echo.Context) error {

View File

@ -9,26 +9,38 @@ import (
)
type (
// StaticConfig defines config for static middleware.
StaticConfig struct {
Root string `json:"root"`
Index string `json:"index"`
Browse bool `json:"browse"`
// Root is the directory from where the static content is served.
Root string `json:"root"`
// Index is the index file to be used while serving a directory.
// Default is `index.html`.
Index string `json:"index"`
// Browse is the flag to list directory or not. Default is false.
Browse bool `json:"browse"`
}
)
var (
// DefaultStaticConfig is the default static middleware config.
DefaultStaticConfig = StaticConfig{
Index: "index.html",
Browse: false,
}
)
// Static returns a static middleware to deliever static content from the provided
// root directory.
func Static(root string) echo.MiddlewareFunc {
c := DefaultStaticConfig
c.Root = root
return StaticFromConfig(c)
}
// StaticFromConfig returns a static middleware from config.
// See `Static()`.
func StaticFromConfig(config StaticConfig) echo.MiddlewareFunc {
return func(next echo.Handler) echo.Handler {
return echo.HandlerFunc(func(c echo.Context) error {

View File

@ -1,6 +1,8 @@
package echo
type (
// Router is the registry of all registered routes for an `Echo` instance for
// request matching and URL path parameter parsing.
Router struct {
tree *node
routes []Route
@ -37,6 +39,7 @@ const (
akind
)
// NewRouter returns a new Router instance.
func NewRouter(e *Echo) *Router {
return &Router{
tree: &node{
@ -47,6 +50,7 @@ func NewRouter(e *Echo) *Router {
}
}
// Handle implements `echo.Middleware` which makes router a middleware.
func (r *Router) Handle(next Handler) Handler {
return HandlerFunc(func(c Context) error {
method := c.Request().Method()
@ -56,10 +60,12 @@ func (r *Router) Handle(next Handler) Handler {
})
}
// Priority is super secret.
func (r *Router) Priority() int {
return 0
}
// Add registers a new route for method and path with matching handler.
func (r *Router) Add(method, path string, h Handler, e *Echo) {
ppath := path // Pristine path
pnames := []string{} // Param names
@ -280,6 +286,14 @@ func (n *node) check405() HandlerFunc {
return notFoundHandler
}
// Find lookup a handler registed for method and path. It also parses URL for path
// parameters and load them into context.
//
// For performance:
//
// - Get context from `Echo#GetContext()`
// - Reset it `Context#Reset()`
// - Return it `Echo#PutContext()`.
func (r *Router) Find(method, path string, context Context) {
ctx := context.Object()
cn := r.tree // Current node as root