Files
gf/g/net/ghttp/http_server_cookie.go
2018-01-08 11:38:31 +08:00

161 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// 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://gitee.com/johng/gf.
//
// HTTP Cookie管理对象
// 由于Cookie是和HTTP请求挂钩的因此被包含到 ghttp 包中进行管理
package ghttp
import (
"sync"
"time"
"strings"
"net/http"
"gitee.com/johng/gf/g/os/gtime"
"gitee.com/johng/gf/g/container/gmap"
)
const (
gDEFAULT_PATH = "/" // 默认path
gDEFAULT_MAX_AGE = 86400*365 // 默认cookie有效期(一年)
SESSION_ID_NAME = "gfsessionid" // 默认存放Cookie中的SessionId名称
)
// cookie对象
type Cookie struct {
mu sync.RWMutex // 并发安全互斥锁
data map[string]CookieItem // 数据项
domain string // 默认的cookie域名
request *Request // 所属HTTP请求对象
response *Response // 所属HTTP返回对象
}
// cookie项
type CookieItem struct {
value string
domain string // 有效域名
path string // 有效路径
expire int // 过期时间
}
// 包含所有当前服务器正在服务的Cookie(每个请求一个Cookie对象)
var cookies = gmap.NewUintInterfaceMap()
// 创建一个cookie对象与传入的请求对应
func NewCookie(r *Request) *Cookie {
if r := GetCookie(r.Id); r != nil {
return r
}
c := &Cookie {
data : make(map[string]CookieItem),
domain : defaultDomain(r),
request : r,
response : r.Response,
}
c.init()
cookies.Set(uint(r.Id), c)
return c
}
// 获取一个已经存在的Cookie对象
func GetCookie(requestid int) *Cookie {
if r := cookies.Get(uint(requestid)); r != nil {
return r.(*Cookie)
}
return nil
}
// 获取默认的domain参数
func defaultDomain(r *Request) string {
return strings.Split(r.Host, ":")[0]
}
// 从请求流中初始化
func (c *Cookie) init() {
c.mu.Lock()
defer c.mu.Unlock()
for _, v := range c.request.Cookies() {
c.data[v.Name] = CookieItem {
v.Value, v.Domain, v.Path, v.Expires.Second(),
}
}
}
// 获取SessionId
func (c *Cookie) SessionId() string {
v := c.Get(SESSION_ID_NAME)
if v == "" {
v = makeSessionId()
c.SetSessionId(v)
}
return v
}
// 设置SessionId
func (c *Cookie) SetSessionId(sessionid string) {
c.Set(SESSION_ID_NAME, sessionid)
}
// 设置cookie使用默认参数
func (c *Cookie) Set(key, value string) {
c.SetCookie(key, value, c.domain, gDEFAULT_PATH, gDEFAULT_MAX_AGE)
}
// 设置cookie带详细cookie参数
func (c *Cookie) SetCookie(key, value, domain, path string, maxage int) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[key] = CookieItem {
value, domain, path, int(gtime.Second()) + maxage,
}
}
// 查询cookie
func (c *Cookie) Get(key string) string {
c.mu.RLock()
defer c.mu.RUnlock()
if r, ok := c.data[key]; ok {
if r.expire >= 0 {
return r.value
} else {
return ""
}
}
return ""
}
// 标记该cookie在对应的域名和路径失效
// 删除cookie的重点是需要通知浏览器客户端cookie已过期
func (c *Cookie) Remove(key, domain, path string) {
c.SetCookie(key, "", domain, path, -86400)
}
// 请求完毕后删除已经存在的Cookie对象
func (c *Cookie) Close() {
cookies.Remove(uint(c.request.Id))
}
// 输出到客户端
func (c *Cookie) Output() {
c.mu.RLock()
defer c.mu.RUnlock()
for k, v := range c.data {
if v.expire == 0 {
continue
}
http.SetCookie(
c.response.ResponseWriter,
&http.Cookie {
Name : k,
Value : v.value,
Domain : v.domain,
Path : v.path,
Expires : time.Unix(int64(v.expire), 0),
},
)
}
}