add CookieOptions

add UnitTest
This commit is contained in:
于湛
2022-01-07 17:10:21 +08:00
parent c91b83969c
commit 572e71d76a
4 changed files with 94 additions and 36 deletions

View File

@ -147,7 +147,7 @@ type ServerConfig struct {
// CookieSameSite specifies cookie SameSite property.
// It also affects the default storage for session id.
CookieSameSite string `json:"sameSite"`
CookieSameSite string `json:"cookieSameSite"`
// CookieSameSite specifies cookie Secure property.
// It also affects the default storage for session id.
@ -155,7 +155,7 @@ type ServerConfig struct {
// CookieSameSite specifies cookie HttpOnly property.
// It also affects the default storage for session id.
CookieHttpOnly bool `json:"CookieHttpOnly"`
CookieHttpOnly bool `json:"cookieHttpOnly"`
// ======================================================================================================
// Session.

View File

@ -7,7 +7,6 @@
package ghttp
import (
"github.com/gogf/gf/v2/util/gconv"
"net/http"
"time"
@ -22,6 +21,13 @@ type Cookie struct {
response *Response // Belonged HTTP response.
}
// CookieOptions provides security config for cookies
type CookieOptions struct {
sameSite http.SameSite // cookie SameSite property
secure bool // cookie Secure property
httpOnly bool // cookie HttpOnly property
}
// cookieItem is the item stored in Cookie.
type cookieItem struct {
*http.Cookie // Underlying cookie items.
@ -89,10 +95,10 @@ func (c *Cookie) Set(key, value string) {
c.request.Server.GetCookieDomain(),
c.request.Server.GetCookiePath(),
c.request.Server.GetCookieMaxAge(),
map[string]interface{}{
"sameSite": c.request.Server.GetCookieSameSite(),
"secure": c.request.Server.GetCookieSecure(),
"httpOnly": c.request.Server.GetCookieHttpOnly(),
CookieOptions{
sameSite: c.request.Server.GetCookieSameSite(),
secure: c.request.Server.GetCookieSecure(),
httpOnly: c.request.Server.GetCookieHttpOnly(),
},
)
}
@ -100,25 +106,20 @@ func (c *Cookie) Set(key, value string) {
// SetCookie sets cookie item with given domain, path and expiration age.
// The optional parameter `httpOnly` specifies if the cookie item is only available in HTTP,
// which is usually empty.
func (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration, extra ...map[string]interface{}) {
func (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration, options ...CookieOptions) {
c.init()
isHttpOnly := false
sameSite := http.SameSiteDefaultMode
secure := false
if len(extra) > 0 {
config := extra[0]
isHttpOnly = gconv.Bool(config["httpOnly"])
sameSite = http.SameSite(gconv.Int(config["sameSite"]))
secure = gconv.Bool(config["secure"])
config := CookieOptions{}
if len(options) > 0 {
config = options[0]
}
httpCookie := &http.Cookie{
Name: key,
Value: value,
Path: path,
Domain: domain,
HttpOnly: isHttpOnly,
SameSite: sameSite,
Secure: secure,
HttpOnly: config.httpOnly,
SameSite: config.sameSite,
Secure: config.secure,
}
if maxAge != 0 {
httpCookie.Expires = time.Now().Add(maxAge)
@ -149,10 +150,10 @@ func (c *Cookie) SetSessionId(id string) {
c.request.Server.GetCookieDomain(),
c.request.Server.GetCookiePath(),
c.server.GetSessionCookieMaxAge(),
map[string]interface{}{
"sameSite": c.request.Server.GetCookieSameSite(),
"secure": c.request.Server.GetCookieSecure(),
"httpOnly": c.request.Server.GetCookieHttpOnly(),
CookieOptions{
sameSite: c.request.Server.GetCookieSameSite(),
secure: c.request.Server.GetCookieSecure(),
httpOnly: c.request.Server.GetCookieHttpOnly(),
},
)
}

View File

@ -28,9 +28,9 @@ func Test_ConfigFromMap(t *testing.T) {
"indexFiles": g.Slice{"index.php", "main.php"},
"errorLogEnabled": true,
"cookieMaxAge": "1y",
"sameSite": "lax",
"cookieSameSite": "lax",
"cookieSecure": true,
"CookieHttpOnly": true,
"cookieHttpOnly": true,
}
config, err := ghttp.ConfigFromMap(m)
t.Assert(err, nil)
@ -41,9 +41,9 @@ func Test_ConfigFromMap(t *testing.T) {
t.Assert(config.CookieMaxAge, d2)
t.Assert(config.IndexFiles, m["indexFiles"])
t.Assert(config.ErrorLogEnabled, m["errorLogEnabled"])
t.Assert(config.CookieSameSite, m["sameSite"])
t.Assert(config.CookieSameSite, m["cookieSameSite"])
t.Assert(config.CookieSecure, m["cookieSecure"])
t.Assert(config.CookieHttpOnly, m["CookieHttpOnly"])
t.Assert(config.CookieHttpOnly, m["cookieHttpOnly"])
})
}
@ -60,9 +60,9 @@ func Test_SetConfigWithMap(t *testing.T) {
"SessionIdName": "MySessionId",
"SessionPath": "/tmp/MySessionStoragePath",
"SessionMaxAge": 24 * time.Hour,
"sameSite": "lax",
"cookieSameSite": "lax",
"cookieSecure": true,
"CookieHttpOnly": true,
"cookieHttpOnly": true,
}
s := g.Server()
err := s.SetConfigWithMap(m)

View File

@ -9,6 +9,7 @@ package ghttp_test
import (
"fmt"
"net/http"
"strings"
"testing"
"time"
@ -105,14 +106,70 @@ func Test_SetHttpCookie(t *testing.T) {
})
}
func Test_CookieSameSite(t *testing.T) {
// todo: 补充测试
func Test_CookieOptionsDefault(t *testing.T) {
p, _ := ports.PopRand()
s := g.Server(p)
s.BindHandler("/test", func(r *ghttp.Request) {
r.Cookie.Set(r.Get("k").String(), r.Get("v").String())
})
s.SetPort(p)
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetBrowserMode(true)
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
r1, e1 := client.Get(ctx, "/test?k=key1&v=100")
if r1 != nil {
defer r1.Close()
}
t.Assert(e1, nil)
t.Assert(r1.ReadAllString(), "")
parts := strings.Split(r1.Header.Get("Set-Cookie"), "; ")
t.AssertEQ(len(parts), 3)
})
}
func Test_CookieSecure(t *testing.T) {
// todo: 补充测试
}
func Test_CookieOptions(t *testing.T) {
p, _ := ports.PopRand()
s := g.Server(p)
s.SetConfigWithMap(g.Map{
"cookieSameSite": "lax",
"cookieSecure": true,
"cookieHttpOnly": true,
})
s.BindHandler("/test", func(r *ghttp.Request) {
r.Cookie.Set(r.Get("k").String(), r.Get("v").String())
})
s.SetPort(p)
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
func Test_CookieHttpOnly(t *testing.T) {
// todo: 补充测试
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetBrowserMode(true)
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
r1, e1 := client.Get(ctx, "/test?k=key1&v=100")
if r1 != nil {
defer r1.Close()
}
t.Assert(e1, nil)
t.Assert(r1.ReadAllString(), "")
parts := strings.Split(r1.Header.Get("Set-Cookie"), "; ")
t.AssertEQ(len(parts), 6)
t.Assert(parts[3], "HttpOnly")
t.Assert(parts[4], "Secure")
t.Assert(parts[5], "SameSite=Lax")
})
}