github.com/wangyougui/gf/v2@v2.6.5/net/ghttp/ghttp_server_cookie.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/wangyougui/gf.
     6  
     7  package ghttp
     8  
     9  import (
    10  	"net/http"
    11  	"time"
    12  
    13  	"github.com/wangyougui/gf/v2/container/gvar"
    14  )
    15  
    16  // Cookie for HTTP COOKIE management.
    17  type Cookie struct {
    18  	data     map[string]*cookieItem // Underlying cookie items.
    19  	server   *Server                // Belonged HTTP server
    20  	request  *Request               // Belonged HTTP request.
    21  	response *Response              // Belonged HTTP response.
    22  }
    23  
    24  // CookieOptions provides security config for cookies
    25  type CookieOptions struct {
    26  	SameSite http.SameSite // cookie SameSite property
    27  	Secure   bool          // cookie Secure property
    28  	HttpOnly bool          // cookie HttpOnly property
    29  }
    30  
    31  // cookieItem is the item stored in Cookie.
    32  type cookieItem struct {
    33  	*http.Cookie      // Underlying cookie items.
    34  	FromClient   bool // Mark this cookie received from the client.
    35  }
    36  
    37  // GetCookie creates or retrieves a cookie object with given request.
    38  // It retrieves and returns an existing cookie object if it already exists with given request.
    39  // It creates and returns a new cookie object if it does not exist with given request.
    40  func GetCookie(r *Request) *Cookie {
    41  	if r.Cookie != nil {
    42  		return r.Cookie
    43  	}
    44  	return &Cookie{
    45  		request: r,
    46  		server:  r.Server,
    47  	}
    48  }
    49  
    50  // init does lazy initialization for the cookie object.
    51  func (c *Cookie) init() {
    52  	if c.data != nil {
    53  		return
    54  	}
    55  	c.data = make(map[string]*cookieItem)
    56  	c.response = c.request.Response
    57  	// DO NOT ADD ANY DEFAULT COOKIE DOMAIN!
    58  	// if c.request.Server.GetCookieDomain() == "" {
    59  	//	c.request.Server.GetCookieDomain() = c.request.GetHost()
    60  	// }
    61  	for _, v := range c.request.Cookies() {
    62  		c.data[v.Name] = &cookieItem{
    63  			Cookie:     v,
    64  			FromClient: true,
    65  		}
    66  	}
    67  }
    68  
    69  // Map returns the cookie items as map[string]string.
    70  func (c *Cookie) Map() map[string]string {
    71  	c.init()
    72  	m := make(map[string]string)
    73  	for k, v := range c.data {
    74  		m[k] = v.Value
    75  	}
    76  	return m
    77  }
    78  
    79  // Contains checks if given key exists and not expire in cookie.
    80  func (c *Cookie) Contains(key string) bool {
    81  	c.init()
    82  	if r, ok := c.data[key]; ok {
    83  		if r.Expires.IsZero() || r.Expires.After(time.Now()) {
    84  			return true
    85  		}
    86  	}
    87  	return false
    88  }
    89  
    90  // Set sets cookie item with default domain, path and expiration age.
    91  func (c *Cookie) Set(key, value string) {
    92  	c.SetCookie(
    93  		key,
    94  		value,
    95  		c.request.Server.GetCookieDomain(),
    96  		c.request.Server.GetCookiePath(),
    97  		c.request.Server.GetCookieMaxAge(),
    98  		CookieOptions{
    99  			SameSite: c.request.Server.GetCookieSameSite(),
   100  			Secure:   c.request.Server.GetCookieSecure(),
   101  			HttpOnly: c.request.Server.GetCookieHttpOnly(),
   102  		},
   103  	)
   104  }
   105  
   106  // SetCookie sets cookie item with given domain, path and expiration age.
   107  // The optional parameter `options` specifies extra security configurations,
   108  // which is usually empty.
   109  func (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration, options ...CookieOptions) {
   110  	c.init()
   111  	config := CookieOptions{}
   112  	if len(options) > 0 {
   113  		config = options[0]
   114  	}
   115  	httpCookie := &http.Cookie{
   116  		Name:     key,
   117  		Value:    value,
   118  		Path:     path,
   119  		Domain:   domain,
   120  		HttpOnly: config.HttpOnly,
   121  		SameSite: config.SameSite,
   122  		Secure:   config.Secure,
   123  	}
   124  	if maxAge != 0 {
   125  		httpCookie.Expires = time.Now().Add(maxAge)
   126  	}
   127  	c.data[key] = &cookieItem{
   128  		Cookie: httpCookie,
   129  	}
   130  }
   131  
   132  // SetHttpCookie sets cookie with *http.Cookie.
   133  func (c *Cookie) SetHttpCookie(httpCookie *http.Cookie) {
   134  	c.init()
   135  	c.data[httpCookie.Name] = &cookieItem{
   136  		Cookie: httpCookie,
   137  	}
   138  }
   139  
   140  // GetSessionId retrieves and returns the session id from cookie.
   141  func (c *Cookie) GetSessionId() string {
   142  	return c.Get(c.server.GetSessionIdName()).String()
   143  }
   144  
   145  // SetSessionId sets session id in the cookie.
   146  func (c *Cookie) SetSessionId(id string) {
   147  	c.SetCookie(
   148  		c.server.GetSessionIdName(),
   149  		id,
   150  		c.request.Server.GetCookieDomain(),
   151  		c.request.Server.GetCookiePath(),
   152  		c.server.GetSessionCookieMaxAge(),
   153  		CookieOptions{
   154  			SameSite: c.request.Server.GetCookieSameSite(),
   155  			Secure:   c.request.Server.GetCookieSecure(),
   156  			HttpOnly: c.request.Server.GetCookieHttpOnly(),
   157  		},
   158  	)
   159  }
   160  
   161  // Get retrieves and returns the value with specified key.
   162  // It returns `def` if specified key does not exist and `def` is given.
   163  func (c *Cookie) Get(key string, def ...string) *gvar.Var {
   164  	c.init()
   165  	if r, ok := c.data[key]; ok {
   166  		if r.Expires.IsZero() || r.Expires.After(time.Now()) {
   167  			return gvar.New(r.Value)
   168  		}
   169  	}
   170  	if len(def) > 0 {
   171  		return gvar.New(def[0])
   172  	}
   173  	return nil
   174  }
   175  
   176  // Remove deletes specified key and its value from cookie using default domain and path.
   177  // It actually tells the http client that the cookie is expired, do not send it to server next time.
   178  func (c *Cookie) Remove(key string) {
   179  	c.SetCookie(
   180  		key,
   181  		"",
   182  		c.request.Server.GetCookieDomain(),
   183  		c.request.Server.GetCookiePath(),
   184  		-24*time.Hour,
   185  	)
   186  }
   187  
   188  // RemoveCookie deletes specified key and its value from cookie using given domain and path.
   189  // It actually tells the http client that the cookie is expired, do not send it to server next time.
   190  func (c *Cookie) RemoveCookie(key, domain, path string) {
   191  	c.SetCookie(key, "", domain, path, -24*time.Hour)
   192  }
   193  
   194  // Flush outputs the cookie items to the client.
   195  func (c *Cookie) Flush() {
   196  	if len(c.data) == 0 {
   197  		return
   198  	}
   199  	for _, v := range c.data {
   200  		if v.FromClient {
   201  			continue
   202  		}
   203  		http.SetCookie(c.response.Writer, v.Cookie)
   204  	}
   205  }