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

Fixed #432, Fixed #167.

Signed-off-by: Vishal Rana <vishal.rana@verizon.com>
This commit is contained in:
Vishal Rana 2016-05-02 16:19:35 -07:00
parent 491502c176
commit 190cf80d02
13 changed files with 347 additions and 5 deletions

View File

@ -65,23 +65,38 @@ type (
// for `engine.URL#QueryParam()`. // for `engine.URL#QueryParam()`.
QueryParam(string) string QueryParam(string) string
// QueryParams returns the query parameters as map. It is an alias for `engine.URL#QueryParams()`. // QueryParams returns the query parameters as map.
// It is an alias for `engine.URL#QueryParams()`.
QueryParams() map[string][]string QueryParams() map[string][]string
// FormValue returns the form field value for the provided name. It is an // FormValue returns the form field value for the provided name. It is an
// alias for `engine.Request#FormValue()`. // alias for `engine.Request#FormValue()`.
FormValue(string) string FormValue(string) string
// FormParams returns the form parameters as map. It is an alias for `engine.Request#FormParams()`. // FormParams returns the form parameters as map.
// It is an alias for `engine.Request#FormParams()`.
FormParams() map[string][]string FormParams() map[string][]string
// FormFile returns the multipart form file for the provided name. It is an // FormFile returns the multipart form file for the provided name. It is an
// alias for `engine.Request#FormFile()`. // alias for `engine.Request#FormFile()`.
FormFile(string) (*multipart.FileHeader, error) FormFile(string) (*multipart.FileHeader, error)
// MultipartForm returns the multipart form. It is an alias for `engine.Request#MultipartForm()`. // MultipartForm returns the multipart form.
// It is an alias for `engine.Request#MultipartForm()`.
MultipartForm() (*multipart.Form, error) MultipartForm() (*multipart.Form, error)
// Cookie returns the named cookie provided in the request.
// It is an alias for `engine.Request#Cookie()`.
Cookie(string) engine.Cookie
// SetCookie adds a `Set-Cookie` header in HTTP response.
// It is an alias for `engine.Response#SetCookie()`.
SetCookie(engine.Cookie)
// Cookies returns the HTTP cookies sent with the request.
// It is an alias for `engine.Request#Cookies()`.
Cookies() []engine.Cookie
// Get retrieves data from the context. // Get retrieves data from the context.
Get(string) interface{} Get(string) interface{}
@ -280,6 +295,18 @@ func (c *context) MultipartForm() (*multipart.Form, error) {
return c.request.MultipartForm() return c.request.MultipartForm()
} }
func (c *context) Cookie(name string) engine.Cookie {
return c.request.Cookie(name)
}
func (c *context) SetCookie(cookie engine.Cookie) {
c.response.SetCookie(cookie)
}
func (c *context) Cookies() []engine.Cookie {
return c.request.Cookies()
}
func (c *context) Set(key string, val interface{}) { func (c *context) Set(key string, val interface{}) {
if c.store == nil { if c.store == nil {
c.store = make(store) c.store = make(store)

View File

@ -8,6 +8,7 @@ import (
"os" "os"
"testing" "testing"
"text/template" "text/template"
"time"
"strings" "strings"
@ -174,6 +175,49 @@ func TestContext(t *testing.T) {
c.Reset(req, test.NewResponseRecorder()) c.Reset(req, test.NewResponseRecorder())
} }
func TestContextCookie(t *testing.T) {
e := New()
req := test.NewRequest(GET, "/", nil)
theme := "theme=light"
user := "user=Jon Snow"
req.Header().Add(HeaderCookie, theme)
req.Header().Add(HeaderCookie, user)
rec := test.NewResponseRecorder()
c := e.NewContext(req, rec).(*context)
// Read single
cookie := c.Cookie("theme")
assert.Equal(t, "theme", cookie.Name())
assert.Equal(t, "light", cookie.Value())
// Read multiple
for _, cookie := range c.Cookies() {
switch cookie.Name() {
case "theme":
assert.Equal(t, "light", cookie.Value())
case "user":
assert.Equal(t, "Jon Snow", cookie.Value())
}
}
// Write
cookie = &test.Cookie{&http.Cookie{
Name: "SSID",
Value: "Ap4PGTEq",
Domain: "labstack.com",
Path: "/",
Expires: time.Now(),
Secure: true,
HttpOnly: true,
}}
c.SetCookie(cookie)
assert.Contains(t, rec.Header().Get(HeaderSetCookie), "SSID")
assert.Contains(t, rec.Header().Get(HeaderSetCookie), "Ap4PGTEq")
assert.Contains(t, rec.Header().Get(HeaderSetCookie), "labstack.com")
assert.Contains(t, rec.Header().Get(HeaderSetCookie), "Secure")
assert.Contains(t, rec.Header().Get(HeaderSetCookie), "HttpOnly")
}
func TestContextPath(t *testing.T) { func TestContextPath(t *testing.T) {
e := New() e := New()
r := e.Router() r := e.Router()

View File

@ -145,6 +145,8 @@ const (
HeaderContentEncoding = "Content-Encoding" HeaderContentEncoding = "Content-Encoding"
HeaderContentLength = "Content-Length" HeaderContentLength = "Content-Length"
HeaderContentType = "Content-Type" HeaderContentType = "Content-Type"
HeaderCookie = "Cookie"
HeaderSetCookie = "Set-Cookie"
HeaderIfModifiedSince = "If-Modified-Since" HeaderIfModifiedSince = "If-Modified-Since"
HeaderLastModified = "Last-Modified" HeaderLastModified = "Last-Modified"
HeaderLocation = "Location" HeaderLocation = "Location"

View File

@ -83,6 +83,12 @@ type (
// MultipartForm returns the multipart form. // MultipartForm returns the multipart form.
MultipartForm() (*multipart.Form, error) MultipartForm() (*multipart.Form, error)
// Cookie returns the named cookie provided in the request.
Cookie(string) Cookie
// Cookies returns the HTTP cookies sent with the request.
Cookies() []Cookie
} }
// Response defines the interface for HTTP response. // Response defines the interface for HTTP response.
@ -96,6 +102,9 @@ type (
// Write writes the data to the connection as part of an HTTP reply. // Write writes the data to the connection as part of an HTTP reply.
Write(b []byte) (int, error) Write(b []byte) (int, error)
// SetCookie adds a `Set-Cookie` header in HTTP response.
SetCookie(Cookie)
// Status returns the HTTP response status. // Status returns the HTTP response status.
Status() int Status() int
@ -151,6 +160,30 @@ type (
QueryString() string QueryString() string
} }
// Cookie defines the interface for HTTP cookie.
Cookie interface {
// Name returns the name of the cookie.
Name() string
// Value returns the value of the cookie.
Value() string
// Path returns the path of the cookie.
Path() string
// Domain returns the domain of the cookie.
Domain() string
// Expires returns the expiry time of the cookie.
Expires() time.Time
// Secure indicates if cookie is secured.
Secure() bool
// HTTPOnly indicate if cookies is HTTP only.
HTTPOnly() bool
}
// Config defines engine config. // Config defines engine config.
Config struct { Config struct {
Address string // TCP address to listen on. Address string // TCP address to listen on.

49
engine/fasthttp/cookie.go Normal file
View File

@ -0,0 +1,49 @@
package fasthttp
import (
"time"
"github.com/valyala/fasthttp"
)
type (
// Cookie implements `engine.Cookie`.
Cookie struct {
*fasthttp.Cookie
}
)
// Name implements `engine.Cookie#Name` function.
func (c *Cookie) Name() string {
return string(c.Cookie.Key())
}
// Value implements `engine.Cookie#Value` function.
func (c *Cookie) Value() string {
return string(c.Cookie.Value())
}
// Path implements `engine.Cookie#Path` function.
func (c *Cookie) Path() string {
return string(c.Cookie.Path())
}
// Domain implements `engine.Cookie#Domain` function.
func (c *Cookie) Domain() string {
return string(c.Cookie.Domain())
}
// Expires implements `engine.Cookie#Expires` function.
func (c *Cookie) Expires() time.Time {
return c.Cookie.Expire()
}
// Secure implements `engine.Cookie#Secure` function.
func (c *Cookie) Secure() bool {
return c.Cookie.Secure()
}
// HTTPOnly implements `engine.Cookie#HTTPOnly` function.
func (c *Cookie) HTTPOnly() bool {
return c.Cookie.HTTPOnly()
}

View File

@ -16,8 +16,8 @@ type (
// Request implements `engine.Request`. // Request implements `engine.Request`.
Request struct { Request struct {
*fasthttp.RequestCtx *fasthttp.RequestCtx
url engine.URL
header engine.Header header engine.Header
url engine.URL
logger *log.Logger logger *log.Logger
} }
) )
@ -127,6 +127,27 @@ func (r *Request) MultipartForm() (*multipart.Form, error) {
return r.RequestCtx.MultipartForm() return r.RequestCtx.MultipartForm()
} }
// Cookie implements `engine.Request#Cookie` function.
func (r *Request) Cookie(name string) engine.Cookie {
c := new(fasthttp.Cookie)
c.SetKey(name)
c.ParseBytes(r.Request.Header.Cookie(name))
return &Cookie{c}
}
// Cookies implements `engine.Request#Cookies` function.
func (r *Request) Cookies() []engine.Cookie {
var cookies []engine.Cookie
i := 0
r.Request.Header.VisitAllCookie(func(name, value []byte) {
c := new(fasthttp.Cookie)
c.SetKey(string(name))
c.ParseBytes(value)
cookies[i] = &Cookie{c}
})
return cookies
}
func (r *Request) reset(c *fasthttp.RequestCtx, h engine.Header, u engine.URL) { func (r *Request) reset(c *fasthttp.RequestCtx, h engine.Header, u engine.URL) {
r.RequestCtx = c r.RequestCtx = c
r.header = h r.header = h

View File

@ -57,6 +57,19 @@ func (r *Response) Write(b []byte) (n int, err error) {
return return
} }
// SetCookie implements `engine.Response#SetCookie` function.
func (r *Response) SetCookie(c engine.Cookie) {
cookie := new(fasthttp.Cookie)
cookie.SetKey(c.Name())
cookie.SetValue(c.Value())
cookie.SetPath(c.Path())
cookie.SetDomain(c.Domain())
cookie.SetExpire(c.Expires())
cookie.SetSecure(c.Secure())
cookie.SetHTTPOnly(c.HTTPOnly())
r.Response.Header.SetCookie(cookie)
}
// Status implements `engine.Response#Status` function. // Status implements `engine.Response#Status` function.
func (r *Response) Status() int { func (r *Response) Status() int {
return r.status return r.status

48
engine/standard/cookie.go Normal file
View File

@ -0,0 +1,48 @@
package standard
import (
"net/http"
"time"
)
type (
// Cookie implements `engine.Cookie`.
Cookie struct {
*http.Cookie
}
)
// Name implements `engine.Cookie#Name` function.
func (c *Cookie) Name() string {
return c.Cookie.Name
}
// Value implements `engine.Cookie#Value` function.
func (c *Cookie) Value() string {
return c.Cookie.Value
}
// Path implements `engine.Cookie#Path` function.
func (c *Cookie) Path() string {
return c.Cookie.Path
}
// Domain implements `engine.Cookie#Domain` function.
func (c *Cookie) Domain() string {
return c.Cookie.Domain
}
// Expires implements `engine.Cookie#Expires` function.
func (c *Cookie) Expires() time.Time {
return c.Cookie.Expires
}
// Secure implements `engine.Cookie#Secure` function.
func (c *Cookie) Secure() bool {
return c.Cookie.Secure
}
// HTTPOnly implements `engine.Cookie#HTTPOnly` function.
func (c *Cookie) HTTPOnly() bool {
return c.Cookie.HttpOnly
}

View File

@ -16,8 +16,8 @@ type (
// Request implements `engine.Request`. // Request implements `engine.Request`.
Request struct { Request struct {
*http.Request *http.Request
url engine.URL
header engine.Header header engine.Header
url engine.URL
logger *log.Logger logger *log.Logger
} }
) )
@ -152,6 +152,22 @@ func (r *Request) MultipartForm() (*multipart.Form, error) {
return r.Request.MultipartForm, err return r.Request.MultipartForm, err
} }
// Cookie implements `engine.Request#Cookie` function.
func (r *Request) Cookie(name string) engine.Cookie {
c, _ := r.Request.Cookie(name)
return &Cookie{c}
}
// Cookies implements `engine.Request#Cookies` function.
func (r *Request) Cookies() []engine.Cookie {
cs := r.Request.Cookies()
cookies := make([]engine.Cookie, len(cs))
for i, c := range cs {
cookies[i] = &Cookie{c}
}
return cookies
}
func (r *Request) reset(req *http.Request, h engine.Header, u engine.URL) { func (r *Request) reset(req *http.Request, h engine.Header, u engine.URL) {
r.Request = req r.Request = req
r.header = h r.header = h

View File

@ -61,6 +61,19 @@ func (r *Response) Write(b []byte) (n int, err error) {
return return
} }
// SetCookie implements `engine.Response#SetCookie` function.
func (r *Response) SetCookie(c engine.Cookie) {
http.SetCookie(r.ResponseWriter, &http.Cookie{
Name: c.Name(),
Value: c.Value(),
Path: c.Path(),
Domain: c.Domain(),
Expires: c.Expires(),
Secure: c.Secure(),
HttpOnly: c.HTTPOnly(),
})
}
// Status implements `engine.Response#Status` function. // Status implements `engine.Response#Status` function.
func (r *Response) Status() int { func (r *Response) Status() int {
return r.status return r.status

48
test/cookie.go Normal file
View File

@ -0,0 +1,48 @@
package test
import (
"net/http"
"time"
)
type (
// Cookie implements `engine.Cookie`.
Cookie struct {
*http.Cookie
}
)
// Name implements `engine.Cookie#Name` function.
func (c *Cookie) Name() string {
return c.Cookie.Name
}
// Value implements `engine.Cookie#Value` function.
func (c *Cookie) Value() string {
return c.Cookie.Value
}
// Path implements `engine.Cookie#Path` function.
func (c *Cookie) Path() string {
return c.Cookie.Path
}
// Domain implements `engine.Cookie#Domain` function.
func (c *Cookie) Domain() string {
return c.Cookie.Domain
}
// Expires implements `engine.Cookie#Expires` function.
func (c *Cookie) Expires() time.Time {
return c.Cookie.Expires
}
// Secure implements `engine.Cookie#Secure` function.
func (c *Cookie) Secure() bool {
return c.Cookie.Secure
}
// HTTPOnly implements `engine.Cookie#HTTPOnly` function.
func (c *Cookie) HTTPOnly() bool {
return c.Cookie.HttpOnly
}

View File

@ -130,6 +130,21 @@ func (r *Request) MultipartForm() (*multipart.Form, error) {
return r.request.MultipartForm, err return r.request.MultipartForm, err
} }
func (r *Request) Cookie(name string) engine.Cookie {
c, _ := r.request.Cookie(name)
return &Cookie{c}
}
// Cookies implements `engine.Request#Cookies` function.
func (r *Request) Cookies() []engine.Cookie {
cs := r.request.Cookies()
cookies := make([]engine.Cookie, len(cs))
for i, c := range cs {
cookies[i] = &Cookie{c}
}
return cookies
}
func (r *Request) reset(req *http.Request, h engine.Header, u engine.URL) { func (r *Request) reset(req *http.Request, h engine.Header, u engine.URL) {
r.request = req r.request = req
r.header = h r.header = h

View File

@ -60,6 +60,19 @@ func (r *Response) Write(b []byte) (n int, err error) {
return return
} }
// SetCookie implements `engine.Response#SetCookie` function.
func (r *Response) SetCookie(c engine.Cookie) {
http.SetCookie(r.response, &http.Cookie{
Name: c.Name(),
Value: c.Value(),
Path: c.Path(),
Domain: c.Domain(),
Expires: c.Expires(),
Secure: c.Secure(),
HttpOnly: c.HTTPOnly(),
})
}
func (r *Response) Status() int { func (r *Response) Status() int {
return r.status return r.status
} }