mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
add CookieOptions
add UnitTest
This commit is contained in:
@ -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.
|
||||
|
||||
@ -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(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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")
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user