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 }