From f3ce16b011be1934cc222085aad8281b7b86bcd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=9A=E5=90=83=E7=82=B9=E8=8B=B9=E6=9E=9C?= Date: Thu, 26 Sep 2024 11:26:57 +0800 Subject: [PATCH] fix: panic on go1.23 (#535) --- bot.go | 2 +- client.go | 6 ++-- cookie_entry_go1.23.go | 26 ---------------- cookie_entry_pre_go1.23.go | 27 ---------------- cookiejar.go | 63 +++++++++++++++++++++++++++----------- 5 files changed, 49 insertions(+), 75 deletions(-) delete mode 100644 cookie_entry_go1.23.go delete mode 100644 cookie_entry_pre_go1.23.go diff --git a/bot.go b/bot.go index 8fa3ad4..5d28faa 100644 --- a/bot.go +++ b/bot.go @@ -312,7 +312,7 @@ func (b *Bot) DumpTo(writer io.Writer) error { jar := b.Caller.Client.Jar() item := HotReloadStorageItem{ BaseRequest: b.Storage.Request, - Jar: fromCookieJar(jar), + Jar: jar, LoginInfo: b.Storage.LoginInfo, WechatDomain: b.Caller.Client.Domain, SyncKey: b.Storage.Response.SyncKey, diff --git a/client.go b/client.go index d6228f8..f36231c 100644 --- a/client.go +++ b/client.go @@ -166,15 +166,15 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) { // Jar 返回当前client的 http.CookieJar // this http.CookieJar must be *Jar type -func (c *Client) Jar() http.CookieJar { - return c.client.Jar +func (c *Client) Jar() *Jar { + return c.client.Jar.(*Jar) } // SetCookieJar 设置cookieJar // 这里限制了cookieJar必须是Jar类型 // 否则进行cookie序列化的时候因为字段的私有性无法进行所有字段的导出 func (c *Client) SetCookieJar(jar *Jar) { - c.client.Jar = jar.AsCookieJar() + c.client.Jar = jar } // HTTPClient 返回http.Client diff --git a/cookie_entry_go1.23.go b/cookie_entry_go1.23.go deleted file mode 100644 index 4203a33..0000000 --- a/cookie_entry_go1.23.go +++ /dev/null @@ -1,26 +0,0 @@ -//go:build !(go1.20 || go1.21 || go1.22) - -package openwechat - -import "time" - -type entry struct { - Name string - Value string - Quoted bool - Domain string - Path string - SameSite string - Secure bool - HttpOnly bool - Persistent bool - HostOnly bool - Expires time.Time - Creation time.Time - LastAccess time.Time - - // seqNum is a sequence number so that Cookies returns cookies in a - // deterministic order, even for cookies that have equal Path length and - // equal Creation time. This simplifies testing. - seqNum uint64 // nolint:unused -} diff --git a/cookie_entry_pre_go1.23.go b/cookie_entry_pre_go1.23.go deleted file mode 100644 index f64e6d9..0000000 --- a/cookie_entry_pre_go1.23.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build go1.20 || go1.21 || go1.22 - -// 小于go1.20的版本会在编译时报错 - -package openwechat - -import "time" - -type entry struct { - Name string - Value string - Domain string - Path string - SameSite string - Secure bool - HttpOnly bool - Persistent bool - HostOnly bool - Expires time.Time - Creation time.Time - LastAccess time.Time - - // seqNum is a sequence number so that Jar returns cookies in a - // deterministic order, even for cookies that have equal Path length and - // equal Creation time. This simplifies testing. - seqNum uint64 // nolint:unused -} diff --git a/cookiejar.go b/cookiejar.go index 7cf799f..3726697 100644 --- a/cookiejar.go +++ b/cookiejar.go @@ -1,41 +1,68 @@ package openwechat import ( + "encoding/json" "net/http" "net/http/cookiejar" - "sync" - "unsafe" + "net/url" ) // Jar is a struct which as same as cookiejar.Jar // cookiejar.Jar's fields are private, so we can't use it directly type Jar struct { - PsList cookiejar.PublicSuffixList - - // mu locks the remaining fields. - mu sync.Mutex + jar *cookiejar.Jar + hosts map[string]*url.URL +} - // Entries is a set of entries, keyed by their eTLD+1 and subkeyed by - // their name/Domain/path. - Entries map[string]map[string]entry +// UnmarshalJSON implements the json.Unmarshaler interface +func (j *Jar) UnmarshalJSON(bytes []byte) error { + var cookies map[string][]*http.Cookie + if err := json.Unmarshal(bytes, &cookies); err != nil { + return err + } + if j.jar == nil { + j.jar, _ = cookiejar.New(nil) + } + for u, cs := range cookies { + u, err := url.Parse(u) + if err != nil { + return err + } + j.jar.SetCookies(u, cs) + } + return nil +} - // nextSeqNum is the next sequence number assigned to a new cookie - // created SetCookies. - NextSeqNum uint64 +// MarshalJSON implements the json.Marshaler interface +func (j *Jar) MarshalJSON() ([]byte, error) { + var cookies = make(map[string][]*http.Cookie) + for path, u := range j.hosts { + cookies[path] = append(cookies[path], j.jar.Cookies(u)...) + } + return json.Marshal(cookies) } -// AsCookieJar unsafe convert to http.CookieJar -func (j *Jar) AsCookieJar() http.CookieJar { - return (*cookiejar.Jar)(unsafe.Pointer(j)) +func (j *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) { + if j.hosts == nil { + j.hosts = make(map[string]*url.URL) + } + path := u.Scheme + "://" + u.Host + if _, exists := j.hosts[path]; !exists { + j.hosts[path] = u + } + j.jar.SetCookies(u, cookies) } -func fromCookieJar(jar http.CookieJar) *Jar { - return (*Jar)(unsafe.Pointer(jar.(*cookiejar.Jar))) +func (j *Jar) Cookies(u *url.URL) []*http.Cookie { + return j.jar.Cookies(u) } func NewJar() *Jar { jar, _ := cookiejar.New(nil) - return fromCookieJar(jar) + return &Jar{ + jar: jar, + hosts: make(map[string]*url.URL), + } } // CookieGroup is a group of cookies