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

Encapsulated fields and exposed public functions.

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2015-05-22 04:40:01 -07:00
parent df924ffc11
commit bf85c56b08
13 changed files with 108 additions and 82 deletions

View File

@ -11,9 +11,9 @@ type (
// Context represents context for the current request. It holds request and
// response objects, path parameters, data and registered handler.
Context struct {
Request *http.Request
Response *Response
Socket *websocket.Conn
request *http.Request
response *Response
socket *websocket.Conn
pnames []string
pvalues []string
store store
@ -24,8 +24,8 @@ type (
func NewContext(req *http.Request, res *Response, e *Echo) *Context {
return &Context{
Request: req,
Response: res,
request: req,
response: res,
echo: e,
pnames: make([]string, e.maxParam),
pvalues: make([]string, e.maxParam),
@ -33,6 +33,21 @@ func NewContext(req *http.Request, res *Response, e *Echo) *Context {
}
}
// Request returns *http.Request.
func (c *Context) Request() *http.Request {
return c.request
}
// Response returns *Response.
func (c *Context) Response() *Response {
return c.response
}
// Socket returns *websocket.Conn.
func (c *Context) Socket() *websocket.Conn {
return c.socket
}
// P returns path parameter by index.
func (c *Context) P(i uint8) (value string) {
l := uint8(len(c.pnames))
@ -57,7 +72,7 @@ func (c *Context) Param(name string) (value string) {
// Bind binds the request body into specified type v. Default binder does it
// based on Content-Type header.
func (c *Context) Bind(i interface{}) error {
return c.echo.binder(c.Request, i)
return c.echo.binder(c.request, i)
}
// Render invokes the registered HTML template renderer and sends a text/html
@ -66,37 +81,37 @@ func (c *Context) Render(code int, name string, data interface{}) error {
if c.echo.renderer == nil {
return RendererNotRegistered
}
c.Response.Header().Set(ContentType, TextHTML+"; charset=utf-8")
c.Response.WriteHeader(code)
return c.echo.renderer.Render(c.Response, name, data)
c.response.Header().Set(ContentType, TextHTML+"; charset=utf-8")
c.response.WriteHeader(code)
return c.echo.renderer.Render(c.response, name, data)
}
// JSON sends an application/json response with status code.
func (c *Context) JSON(code int, i interface{}) error {
c.Response.Header().Set(ContentType, ApplicationJSON+"; charset=utf-8")
c.Response.WriteHeader(code)
return json.NewEncoder(c.Response).Encode(i)
c.response.Header().Set(ContentType, ApplicationJSON+"; charset=utf-8")
c.response.WriteHeader(code)
return json.NewEncoder(c.response).Encode(i)
}
// String sends a text/plain response with status code.
func (c *Context) String(code int, s string) error {
c.Response.Header().Set(ContentType, TextPlain+"; charset=utf-8")
c.Response.WriteHeader(code)
_, err := c.Response.Write([]byte(s))
c.response.Header().Set(ContentType, TextPlain+"; charset=utf-8")
c.response.WriteHeader(code)
_, err := c.response.Write([]byte(s))
return err
}
// HTML sends a text/html response with status code.
func (c *Context) HTML(code int, html string) error {
c.Response.Header().Set(ContentType, TextHTML+"; charset=utf-8")
c.Response.WriteHeader(code)
_, err := c.Response.Write([]byte(html))
c.response.Header().Set(ContentType, TextHTML+"; charset=utf-8")
c.response.WriteHeader(code)
_, err := c.response.Write([]byte(html))
return err
}
// NoContent sends a response with no body and a status code.
func (c *Context) NoContent(code int) error {
c.Response.WriteHeader(code)
c.response.WriteHeader(code)
return nil
}
@ -117,11 +132,11 @@ func (c *Context) Set(key string, val interface{}) {
// Redirect redirects the request using http.Redirect with status code.
func (c *Context) Redirect(code int, url string) {
http.Redirect(c.Response, c.Request, url, code)
http.Redirect(c.response, c.request, url, code)
}
func (c *Context) reset(w http.ResponseWriter, r *http.Request, e *Echo) {
c.Request = r
c.Response.reset(w)
c.request = r
c.response.reset(w)
c.echo = e
}

View File

@ -91,26 +91,26 @@ func TestContext(t *testing.T) {
// JSON
r.Header.Set(Accept, ApplicationJSON)
c.Response.committed = false
c.response.committed = false
if he := c.JSON(http.StatusOK, u1); he != nil {
t.Errorf("json %#v", he)
}
// String
r.Header.Set(Accept, TextPlain)
c.Response.committed = false
c.response.committed = false
if he := c.String(http.StatusOK, "Hello, World!"); he != nil {
t.Errorf("string %#v", he.Error)
}
// HTML
r.Header.Set(Accept, TextHTML)
c.Response.committed = false
c.response.committed = false
if he := c.HTML(http.StatusOK, "Hello, <strong>World!</strong>"); he != nil {
t.Errorf("html %v", he.Error)
}
// Redirect
c.Response.committed = false
c.response.committed = false
c.Redirect(http.StatusMovedPermanently, "http://labstack.github.io/echo")
}

58
echo.go
View File

@ -13,9 +13,9 @@ import (
"strings"
"sync"
"github.com/bradfitz/http2"
"github.com/mattn/go-colorable"
"golang.org/x/net/websocket"
"github.com/bradfitz/http2"
)
type (
@ -34,8 +34,8 @@ type (
debug bool
}
HTTPError struct {
Code int
Message string
code int
message string
}
Middleware interface{}
MiddlewareFunc func(HandlerFunc) HandlerFunc
@ -123,15 +123,21 @@ var (
)
func NewHTTPError(code int, msg ...string) *HTTPError {
he := &HTTPError{Code: code, Message: http.StatusText(code)}
he := &HTTPError{code: code, message: http.StatusText(code)}
for _, m := range msg {
he.Message = m
he.message = m
}
return he
}
// Code returns code.
func (e *HTTPError) Code() int {
return e.code
}
// Error returns message.
func (e *HTTPError) Error() string {
return e.Message
return e.message
}
// New creates an Echo instance.
@ -157,13 +163,13 @@ func New() (e *Echo) {
code := http.StatusInternalServerError
msg := http.StatusText(code)
if he, ok := err.(*HTTPError); ok {
code = he.Code
msg = he.Message
code = he.code
msg = he.message
}
if e.Debug() {
msg = err.Error()
}
http.Error(c.Response, msg, code)
http.Error(c.response, msg, code)
})
e.SetBinder(func(r *http.Request, v interface{}) error {
ct := r.Header.Get(ContentType)
@ -283,12 +289,12 @@ func (e *Echo) WebSocket(path string, h HandlerFunc) {
e.Get(path, func(c *Context) (err error) {
wss := websocket.Server{
Handler: func(ws *websocket.Conn) {
c.Socket = ws
c.Response.status = http.StatusSwitchingProtocols
c.socket = ws
c.response.status = http.StatusSwitchingProtocols
err = h(c)
},
}
wss.ServeHTTP(c.Response.writer, c.Request)
wss.ServeHTTP(c.response.writer, c.request)
return err
})
}
@ -313,7 +319,7 @@ func (e *Echo) Favicon(file string) {
func (e *Echo) Static(path, root string) {
fs := http.StripPrefix(path, http.FileServer(http.Dir(root)))
e.Get(path+"*", func(c *Context) error {
fs.ServeHTTP(c.Response, c.Request)
fs.ServeHTTP(c.response, c.request)
return nil
})
}
@ -321,7 +327,7 @@ func (e *Echo) Static(path, root string) {
// ServeFile serves a file.
func (e *Echo) ServeFile(path, file string) {
e.Get(path, func(c *Context) error {
http.ServeFile(c.Response, c.Request, file)
http.ServeFile(c.response, c.request, file)
return nil
})
}
@ -399,17 +405,17 @@ func (e *Echo) RunTLSServer(srv *http.Server, certFile, keyFile string) {
e.run(srv, certFile, keyFile)
}
func (e *Echo) run(s *http.Server, f ...string) {
func (e *Echo) run(s *http.Server, files ...string) {
s.Handler = e
if e.http2 {
http2.ConfigureServer(s, nil)
}
if len(f) == 0 {
if len(files) == 0 {
log.Fatal(s.ListenAndServe())
} else if len(f) == 2 {
log.Fatal(s.ListenAndServeTLS(f[0], f[1]))
} else if len(files) == 2 {
log.Fatal(s.ListenAndServeTLS(files[0], files[1]))
} else {
log.Fatal("echo: invalid TLS configuration")
log.Fatal("echo => invalid TLS configuration")
}
}
@ -428,10 +434,10 @@ func wrapMiddleware(m Middleware) MiddlewareFunc {
return func(h HandlerFunc) HandlerFunc {
return func(c *Context) (err error) {
m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c.Response.writer = w
c.Request = r
c.response.writer = w
c.request = r
err = h(c)
})).ServeHTTP(c.Response.writer, c.Request)
})).ServeHTTP(c.response.writer, c.request)
return
}
}
@ -462,8 +468,8 @@ func wrapHandlerFuncMW(m HandlerFunc) MiddlewareFunc {
func wrapHTTPHandlerFuncMW(m http.HandlerFunc) MiddlewareFunc {
return func(h HandlerFunc) HandlerFunc {
return func(c *Context) error {
if !c.Response.committed {
m.ServeHTTP(c.Response.writer, c.Request)
if !c.response.committed {
m.ServeHTTP(c.response.writer, c.request)
}
return h(c)
}
@ -479,12 +485,12 @@ func wrapHandler(h Handler) HandlerFunc {
return h
case http.Handler, http.HandlerFunc:
return func(c *Context) error {
h.(http.Handler).ServeHTTP(c.Response, c.Request)
h.(http.Handler).ServeHTTP(c.response, c.request)
return nil
}
case func(http.ResponseWriter, *http.Request):
return func(c *Context) error {
h(c.Response, c.Request)
h(c.response, c.request)
return nil
}
default:

View File

@ -252,7 +252,7 @@ func TestEchoMethod(t *testing.T) {
func TestWebSocket(t *testing.T) {
e := New()
e.WebSocket("/ws", func(c *Context) error {
c.Socket.Write([]byte("test"))
c.socket.Write([]byte("test"))
return nil
})
srv := httptest.NewServer(e)

View File

@ -21,7 +21,7 @@ const (
// For invalid credentials, it sends "401 - Unauthorized" response.
func BasicAuth(fn AuthFunc) echo.HandlerFunc {
return func(c *echo.Context) error {
auth := c.Request.Header.Get(echo.Authorization)
auth := c.Request().Header.Get(echo.Authorization)
i := 0
code := http.StatusBadRequest

View File

@ -48,8 +48,8 @@ func TestBasicAuth(t *testing.T) {
he := ba(c).(*echo.HTTPError)
if ba(c) == nil {
t.Error("expected `fail`, with incorrect password.")
} else if he.Code != http.StatusUnauthorized {
t.Errorf("expected status `401`, got %d", he.Code)
} else if he.Code() != http.StatusUnauthorized {
t.Errorf("expected status `401`, got %d", he.Code())
}
// Empty Authorization header
@ -58,8 +58,8 @@ func TestBasicAuth(t *testing.T) {
he = ba(c).(*echo.HTTPError)
if he == nil {
t.Error("expected `fail`, with empty Authorization header.")
} else if he.Code != http.StatusBadRequest {
t.Errorf("expected status `400`, got %d", he.Code)
} else if he.Code() != http.StatusBadRequest {
t.Errorf("expected status `400`, got %d", he.Code())
}
// Invalid Authorization header
@ -69,8 +69,8 @@ func TestBasicAuth(t *testing.T) {
he = ba(c).(*echo.HTTPError)
if he == nil {
t.Error("expected `fail`, with invalid Authorization header.")
} else if he.Code != http.StatusBadRequest {
t.Errorf("expected status `400`, got %d", he.Code)
} else if he.Code() != http.StatusBadRequest {
t.Errorf("expected status `400`, got %d", he.Code())
}
// Invalid scheme
@ -80,7 +80,7 @@ func TestBasicAuth(t *testing.T) {
he = ba(c).(*echo.HTTPError)
if he == nil {
t.Error("expected `fail`, with invalid scheme.")
} else if he.Code != http.StatusBadRequest {
t.Errorf("expected status `400`, got %d", he.Code)
} else if he.Code() != http.StatusBadRequest {
t.Errorf("expected status `400`, got %d", he.Code())
}
}

View File

@ -6,17 +6,18 @@ import (
"strings"
"github.com/labstack/echo"
"net/http"
)
type (
gzipWriter struct {
io.Writer
*echo.Response
http.ResponseWriter
}
)
func (g gzipWriter) Write(b []byte) (int, error) {
return g.Writer.Write(b)
func (w gzipWriter) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}
// Gzip returns a middleware which compresses HTTP response using gzip compression
@ -26,12 +27,12 @@ func Gzip() echo.MiddlewareFunc {
return func(h echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) error {
if strings.Contains(c.Request.Header.Get(echo.AcceptEncoding), scheme) {
w := gzip.NewWriter(c.Response.Writer())
if strings.Contains(c.Request().Header.Get(echo.AcceptEncoding), scheme) {
w := gzip.NewWriter(c.Response().Writer())
defer w.Close()
gw := gzipWriter{Writer: w, Response: c.Response}
c.Response.Header().Set(echo.ContentEncoding, scheme)
c.Response = echo.NewResponse(gw)
gw := gzipWriter{Writer: w, ResponseWriter: c.Response().Writer()}
c.Response().Header().Set(echo.ContentEncoding, scheme)
c.Response().SetWriter(gw)
}
return h(c)
}

View File

@ -29,7 +29,7 @@ func TestGzip(t *testing.T) {
// Content-Encoding header
req.Header.Set(echo.AcceptEncoding, "gzip")
w = httptest.NewRecorder()
c.Response = echo.NewResponse(w)
c.Response().SetWriter(w)
Gzip()(h)(c)
ce := w.Header().Get(echo.ContentEncoding)
if ce != "gzip" {

View File

@ -16,14 +16,14 @@ func Logger() echo.MiddlewareFunc {
c.Error(err)
}
end := time.Now()
method := c.Request.Method
path := c.Request.URL.Path
method := c.Request().Method
path := c.Request().URL.Path
if path == "" {
path = "/"
}
size := c.Response.Size()
size := c.Response().Size()
n := c.Response.Status()
n := c.Response().Status()
code := color.Green(n)
switch {
case n >= 500:

View File

@ -21,14 +21,14 @@ func TestLogger(t *testing.T) {
Logger()(h)(c)
// Status 4xx
c.Response = echo.NewResponse(w)
c = echo.NewContext(req, echo.NewResponse(w), e)
h = func(c *echo.Context) error {
return c.String(http.StatusNotFound, "test")
}
Logger()(h)(c)
// Status 5xx
c.Response = echo.NewResponse(w)
c = echo.NewContext(req, echo.NewResponse(w), e)
h = func(c *echo.Context) error {
return c.String(http.StatusInternalServerError, "test")
}

View File

@ -15,10 +15,10 @@ type (
// path.
func StripTrailingSlash() echo.HandlerFunc {
return func(c *echo.Context) error {
p := c.Request.URL.Path
p := c.Request().URL.Path
l := len(p)
if p[l-1] == '/' {
c.Request.URL.Path = p[:l-1]
c.Request().URL.Path = p[:l-1]
}
return nil
}
@ -36,7 +36,7 @@ func RedirectToSlash(opts ...RedirectToSlashOptions) echo.HandlerFunc {
}
return func(c *echo.Context) error {
p := c.Request.URL.Path
p := c.Request().URL.Path
l := len(p)
if p[l-1] != '/' {
c.Redirect(code, p+"/")

View File

@ -13,7 +13,7 @@ func TestStripTrailingSlash(t *testing.T) {
res := echo.NewResponse(httptest.NewRecorder())
c := echo.NewContext(req, res, echo.New())
StripTrailingSlash()(c)
p := c.Request.URL.Path
p := c.Request().URL.Path
if p != "/users" {
t.Errorf("expected path `/users` got, %s.", p)
}
@ -31,7 +31,7 @@ func TestRedirectToSlash(t *testing.T) {
}
// Location header
l := c.Response.Header().Get("Location")
l := c.Response().Header().Get("Location")
if l != "/users/" {
t.Errorf("expected Location header `/users/`, got %s.", l)
}

View File

@ -26,6 +26,10 @@ func (r *Response) Header() http.Header {
return r.writer.Header()
}
func (r *Response) SetWriter(w http.ResponseWriter) {
r.writer = w
}
func (r *Response) Writer() http.ResponseWriter {
return r.writer
}