Files
gf/net/ghttp/ghttp_server_cookie.go

206 lines
5.4 KiB
Go
Raw Permalink Normal View History

// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2017-12-29 16:03:30 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
2017-12-31 18:19:58 +08:00
package ghttp
import (
2019-06-19 09:06:52 +08:00
"net/http"
"time"
2021-11-13 23:23:55 +08:00
"github.com/gogf/gf/v2/container/gvar"
)
2020-05-07 23:05:33 +08:00
// Cookie for HTTP COOKIE management.
type Cookie struct {
2020-11-21 11:18:21 +08:00
data map[string]*cookieItem // Underlying cookie items.
server *Server // Belonged HTTP server
request *Request // Belonged HTTP request.
response *Response // Belonged HTTP response.
}
2022-01-07 17:10:21 +08:00
// CookieOptions provides security config for cookies
type CookieOptions struct {
2022-03-02 09:56:58 +08:00
SameSite http.SameSite // cookie SameSite property
Secure bool // cookie Secure property
HttpOnly bool // cookie HttpOnly property
2022-01-07 17:10:21 +08:00
}
2020-11-21 11:18:21 +08:00
// cookieItem is the item stored in Cookie.
type cookieItem struct {
*http.Cookie // Underlying cookie items.
2022-03-19 17:58:21 +08:00
FromClient bool // Mark this cookie received from the client.
}
2020-05-07 23:05:33 +08:00
// GetCookie creates or retrieves a cookie object with given request.
// It retrieves and returns an existing cookie object if it already exists with given request.
// It creates and returns a new cookie object if it does not exist with given request.
2018-04-10 10:32:37 +08:00
func GetCookie(r *Request) *Cookie {
2019-06-19 09:06:52 +08:00
if r.Cookie != nil {
return r.Cookie
}
return &Cookie{
request: r,
server: r.Server,
}
2017-12-13 14:13:36 +08:00
}
2022-03-19 17:58:21 +08:00
// init does lazy initialization for the cookie object.
func (c *Cookie) init() {
if c.data != nil {
return
}
2020-11-21 11:18:21 +08:00
c.data = make(map[string]*cookieItem)
c.response = c.request.Response
// DO NOT ADD ANY DEFAULT COOKIE DOMAIN!
2021-11-13 23:23:55 +08:00
// if c.request.Server.GetCookieDomain() == "" {
// c.request.Server.GetCookieDomain() = c.request.GetHost()
2021-11-13 23:23:55 +08:00
// }
for _, v := range c.request.Cookies() {
2020-11-21 11:18:21 +08:00
c.data[v.Name] = &cookieItem{
Cookie: v,
FromClient: true,
}
2019-06-19 09:06:52 +08:00
}
}
2020-05-07 23:05:33 +08:00
// Map returns the cookie items as map[string]string.
func (c *Cookie) Map() map[string]string {
2019-06-19 09:06:52 +08:00
c.init()
m := make(map[string]string)
for k, v := range c.data {
m[k] = v.Value
2019-06-19 09:06:52 +08:00
}
return m
}
2022-03-19 17:58:21 +08:00
// Contains checks if given key exists and not expire in cookie.
2018-11-16 18:20:09 +08:00
func (c *Cookie) Contains(key string) bool {
2019-06-19 09:06:52 +08:00
c.init()
if r, ok := c.data[key]; ok {
if r.Expires.IsZero() || r.Expires.After(time.Now()) {
2019-06-19 09:06:52 +08:00
return true
}
}
return false
}
2020-05-07 23:05:33 +08:00
// Set sets cookie item with default domain, path and expiration age.
2017-12-13 11:36:29 +08:00
func (c *Cookie) Set(key, value string) {
c.SetCookie(
key,
value,
c.request.Server.GetCookieDomain(),
c.request.Server.GetCookiePath(),
c.request.Server.GetCookieMaxAge(),
2022-01-07 17:10:21 +08:00
CookieOptions{
2022-03-02 09:56:58 +08:00
SameSite: c.request.Server.GetCookieSameSite(),
Secure: c.request.Server.GetCookieSecure(),
HttpOnly: c.request.Server.GetCookieHttpOnly(),
2022-01-05 14:33:20 +08:00
},
)
2017-12-13 11:36:29 +08:00
}
2021-09-27 21:27:24 +08:00
// SetCookie sets cookie item with given domain, path and expiration age.
2022-03-02 09:56:58 +08:00
// The optional parameter `options` specifies extra security configurations,
2020-05-07 23:05:33 +08:00
// which is usually empty.
2022-01-07 17:10:21 +08:00
func (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration, options ...CookieOptions) {
2019-06-19 09:06:52 +08:00
c.init()
2022-01-07 17:10:21 +08:00
config := CookieOptions{}
if len(options) > 0 {
config = options[0]
2019-06-19 09:06:52 +08:00
}
2020-11-21 11:18:21 +08:00
httpCookie := &http.Cookie{
Name: key,
Value: value,
Path: path,
Domain: domain,
2022-03-02 09:56:58 +08:00
HttpOnly: config.HttpOnly,
SameSite: config.SameSite,
Secure: config.Secure,
2019-06-19 09:06:52 +08:00
}
2020-11-21 11:18:21 +08:00
if maxAge != 0 {
httpCookie.Expires = time.Now().Add(maxAge)
}
c.data[key] = &cookieItem{
Cookie: httpCookie,
}
}
// SetHttpCookie sets cookie with *http.Cookie.
2020-11-21 11:18:21 +08:00
func (c *Cookie) SetHttpCookie(httpCookie *http.Cookie) {
c.init()
2020-11-21 11:18:21 +08:00
c.data[httpCookie.Name] = &cookieItem{
Cookie: httpCookie,
}
}
2020-05-07 23:05:33 +08:00
// GetSessionId retrieves and returns the session id from cookie.
func (c *Cookie) GetSessionId() string {
2021-09-27 21:27:24 +08:00
return c.Get(c.server.GetSessionIdName()).String()
}
2020-05-07 23:05:33 +08:00
// SetSessionId sets session id in the cookie.
2018-11-23 09:20:45 +08:00
func (c *Cookie) SetSessionId(id string) {
c.SetCookie(
c.server.GetSessionIdName(),
id,
c.request.Server.GetCookieDomain(),
c.request.Server.GetCookiePath(),
c.server.GetSessionCookieMaxAge(),
2022-01-07 17:10:21 +08:00
CookieOptions{
2022-03-02 09:56:58 +08:00
SameSite: c.request.Server.GetCookieSameSite(),
Secure: c.request.Server.GetCookieSecure(),
HttpOnly: c.request.Server.GetCookieHttpOnly(),
2022-01-05 14:33:20 +08:00
},
)
2018-11-23 09:20:45 +08:00
}
2020-05-07 23:05:33 +08:00
// Get retrieves and returns the value with specified key.
// It returns `def` if specified key does not exist and `def` is given.
2021-09-27 21:27:24 +08:00
func (c *Cookie) Get(key string, def ...string) *gvar.Var {
2019-06-19 09:06:52 +08:00
c.init()
if r, ok := c.data[key]; ok {
if r.Expires.IsZero() || r.Expires.After(time.Now()) {
2021-09-27 21:27:24 +08:00
return gvar.New(r.Value)
2019-06-19 09:06:52 +08:00
}
}
if len(def) > 0 {
2021-09-27 21:27:24 +08:00
return gvar.New(def[0])
2019-06-19 09:06:52 +08:00
}
2021-09-27 21:27:24 +08:00
return nil
}
2020-05-07 23:05:33 +08:00
// Remove deletes specified key and its value from cookie using default domain and path.
// It actually tells the http client that the cookie is expired, do not send it to server next time.
func (c *Cookie) Remove(key string) {
c.SetCookie(
key,
"",
c.request.Server.GetCookieDomain(),
c.request.Server.GetCookiePath(),
2021-03-19 19:16:21 +08:00
-24*time.Hour,
)
}
2020-05-07 23:05:33 +08:00
// RemoveCookie deletes specified key and its value from cookie using given domain and path.
// It actually tells the http client that the cookie is expired, do not send it to server next time.
func (c *Cookie) RemoveCookie(key, domain, path string) {
2021-03-19 19:16:21 +08:00
c.SetCookie(key, "", domain, path, -24*time.Hour)
}
2022-03-19 17:58:21 +08:00
// Flush outputs the cookie items to the client.
func (c *Cookie) Flush() {
2019-06-19 09:06:52 +08:00
if len(c.data) == 0 {
return
}
for _, v := range c.data {
2020-11-21 11:18:21 +08:00
if v.FromClient {
2019-06-19 09:06:52 +08:00
continue
}
2020-11-21 11:18:21 +08:00
http.SetCookie(c.response.Writer, v.Cookie)
2019-06-19 09:06:52 +08:00
}
}