123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- //go:build windows
- package yu_curl
- import (
- yu_http "gogs.qqck.cn/s/tools/http"
- yu_strings "gogs.qqck.cn/s/tools/strings"
- yu_sys "gogs.qqck.cn/s/tools/sys"
- "runtime"
- "strings"
- "unsafe"
- )
- // Request
- // @Description: 请求对象
- type Request struct {
- curl uintptr
- perform uintptr
- headers map[string]string
- headers_setopt bool
- headers_list uintptr
- useragent string
- referer string
- cookies map[string]string
- cookies_setopt bool
- cookies_updata bool
- connect_to map[string]string
- connect_to_setopt bool
- connect_to_list uintptr
- // -------------------------------------------------------------------resp
- resp_body []byte
- resp_headers_raw []byte
- resp_headers map[string]string
- resp_cookies map[string]string
- }
- // NewRequest
- //
- // @Description: 创建请求对象
- func NewRequest() (t *Request) {
- t = &Request{}
- runtime.SetFinalizer(t, _finalizer)
- t.curl, _, _ = curl_easy_init.Call()
- curl_easy_setopt.Call(t.curl, OPT_NOSIGNAL, 1)
- curl_easy_setopt.Call(t.curl, OPT_SUPPRESS_CONNECT_HEADERS, 1)
- curl_easy_setopt.Call(t.curl, OPT_PREREQFUNCTION, callback_PREREQFUNCTION_ptr)
- curl_easy_setopt.Call(t.curl, OPT_PREREQDATA, unsafe.Pointer(t))
- curl_easy_setopt.Call(t.curl, OPT_HEADERFUNCTION, callback_HEADERFUNCTION_ptr)
- curl_easy_setopt.Call(t.curl, OPT_HEADERDATA, unsafe.Pointer(t))
- curl_easy_setopt.Call(t.curl, OPT_WRITEFUNCTION, callback_WRITEFUNCTION_ptr)
- curl_easy_setopt.Call(t.curl, OPT_WRITEDATA, unsafe.Pointer(t))
- // ------------------------------------------------init
- t.SetRdirect(true)
- t.SetSslVerifyPeer(false)
- t.SetTimeout(60000)
- return
- }
- func _finalizer(t *Request) {
- t.Close()
- }
- // Close
- //
- // @Description: 关闭并销毁请求对象
- func (t *Request) Close() {
- if t.curl != 0 {
- curl_easy_cleanup.Call(t.curl)
- t.curl = 0
- }
- t.headers = nil
- if t.headers_list != 0 {
- curl_slist_free_all.Call(t.headers_list)
- t.headers_list = 0
- }
- t.cookies = nil
- t.connect_to = nil
- if t.connect_to_list != 0 {
- curl_slist_free_all.Call(t.connect_to_list)
- t.connect_to_list = 0
- }
- t.resp_body = nil
- t.resp_headers_raw = nil
- t.resp_headers = nil
- t.resp_cookies = nil
- }
- func (t *Request) opt() {
- if t.headers_setopt {
- if t.headers_list != 0 {
- curl_slist_free_all.Call(t.headers_list)
- t.headers_list = 0
- curl_easy_setopt.Call(t.curl, OPT_HTTPHEADER, 0)
- }
- for j_key, j_val := range t.headers {
- t.headers_list, _, _ = curl_slist_append.Call(t.headers_list, yu_sys.S{yu_sys.Gbk, j_key + ":" + j_val})
- }
- curl_easy_setopt.Call(t.curl, OPT_HTTPHEADER, t.headers_list)
- t.headers_setopt = false
- }
- if t.cookies_setopt {
- curl_easy_setopt.Call(t.curl, OPT_COOKIE, yu_sys.S{yu_sys.Gbk, t.GetCookies()})
- t.cookies_setopt = false
- }
- if t.connect_to_setopt {
- if t.connect_to_list != 0 {
- curl_slist_free_all.Call(t.connect_to_list)
- t.connect_to_list = 0
- }
- for j_host, j_to := range t.connect_to {
- t.connect_to_list, _, _ = curl_slist_append.Call(t.connect_to_list, yu_sys.S{yu_sys.Gbk, j_host + ":" + j_to})
- }
- curl_easy_setopt.Call(t.curl, OPT_CONNECT_TO, t.connect_to_list)
- t.connect_to_setopt = false
- }
- }
- // -----------------------------------------------------------------------------------------------------------------------------------------------Headers
- // SetHeader
- //
- // @Description: 设置单个协议头
- func (t *Request) SetHeader(name, value string) *Request {
- name = yu_http.Normalize(name)
- if name == "Cookie" {
- t.SetCookies(value)
- } else if name == "User-Agent" {
- t.SetUserAgent(value)
- } else if name == "Referer" {
- t.SetReferer(value)
- } else {
- if t.headers == nil {
- t.headers = make(map[string]string)
- }
- if value == "" {
- t.headers[name] = " " // " " 才可以删除
- } else {
- t.headers[name] = value
- }
- t.headers_setopt = true
- }
- return t
- }
- // SetHeaders
- //
- // @Description: 清空之前的协议头并设置新的协议头
- func (t *Request) SetHeaders(headers string) *Request {
- if headers == "" {
- t.headers = nil
- t.headers_setopt = true
- } else {
- t.headers = make(map[string]string)
- t.AddHeaders(headers)
- }
- return t
- }
- // AddHeaders
- //
- // @Description: 保留之前的协议头并添加新的协议头
- func (t *Request) AddHeaders(headers string) *Request {
- if headers != "" {
- var j_headers []string
- if strings.Index(headers, "\r\n") > -1 {
- j_headers = strings.Split(headers, "\r\n")
- } else if strings.Index(headers, "\n") > -1 {
- j_headers = strings.Split(headers, "\n")
- }
- for j_i := 0; j_i < len(j_headers); j_i++ {
- j_key, j_value := yu_strings.Left(j_headers[j_i], ":"), yu_strings.EmptyLeft(yu_strings.Right(j_headers[j_i], ":"))
- if j_key == "" && j_value == "" {
- if j_header := yu_strings.EmptyRight(j_headers[j_i]); strings.HasSuffix(j_header, ";") {
- t.SetHeader(j_header, "")
- }
- } else if j_key != "" {
- t.SetHeader(j_key, j_value)
- }
- }
- }
- return t
- }
- // GetHeader
- //
- // @Description: 获取单个协议头
- func (t *Request) GetHeader(name string) string {
- name = yu_http.Normalize(name)
- if name == "Cookie" {
- return t.GetCookies()
- } else if name == "User-Agent" {
- return t.GetUserAgent()
- } else if name == "Referer" {
- return t.GetReferer()
- } else {
- if t.headers[name] == " " {
- return ""
- }
- return t.headers[name]
- }
- }
- // GetHeaders
- //
- // @Description: 获取全部协议头
- func (t *Request) GetHeaders() string {
- if len(t.headers) == 0 {
- return ""
- }
- j_headers := make([]byte, 0, 4096)
- for j_name, j_value := range t.headers {
- j_headers = append(j_headers, j_name...)
- j_headers = append(j_headers, ':')
- j_headers = append(j_headers, ' ')
- j_headers = append(j_headers, j_value...)
- j_headers = append(j_headers, 13, 10)
- }
- return string(j_headers)
- }
- // -----------------------------------------------------------------------------------------------------------------------------------------------Content-Type
- // SetContentType
- //
- // @Description: 设置提交的"ContentType"类型
- func (t *Request) SetContentType(value string) *Request {
- t.SetHeader("Content-Type", value)
- return t
- }
- // -----------------------------------------------------------------------------------------------------------------------------------------------Headers-Utils
- // SetUserAgent
- //
- // @Description: 设置请求的 UserAgent
- func (t *Request) SetUserAgent(value string) *Request {
- t.useragent = value
- curl_easy_setopt.Call(t.curl, OPT_USERAGENT, yu_sys.S{yu_sys.Gbk, t.useragent})
- return t
- }
- // GetUserAgent
- //
- // @Description: 获取请求的 UserAgent
- func (t *Request) GetUserAgent() string {
- return t.useragent
- }
- // SetReferer
- //
- // @Description: 设置来路地址
- func (t *Request) SetReferer(value string) *Request {
- t.referer = value
- curl_easy_setopt.Call(t.curl, OPT_REFERER, yu_sys.S{yu_sys.Gbk, t.referer})
- return t
- }
- // GetReferer
- //
- // @Description: 获取来路地址
- func (t *Request) GetReferer() string {
- return t.referer
- }
- // SetAutoReferer
- //
- // @Description: 自动更新引用标头,启用后,会自动将 HTTP 请求中的 Referer: 标头字段设置为完整的 URL,它位于 Location: 重定向之后。默认为:false, 禁用
- func (t *Request) SetAutoReferer(enable bool) *Request {
- curl_easy_setopt.Call(t.curl, OPT_AUTOREFERER, enable)
- return t
- }
- // -----------------------------------------------------------------------------------------------------------------------------------------------Cookies
- // SetCookie
- //
- // @Description: 设置单个 Cookie
- func (t *Request) SetCookie(name, value string) *Request {
- if value == "" {
- delete(t.cookies, name)
- } else {
- if t.cookies == nil {
- t.cookies = make(map[string]string)
- }
- t.cookies[name] = value
- }
- t.cookies_setopt = true
- return t
- }
- // SetCookies
- //
- // @Description: 清空之前的 Cookies 并设置新的 Cookies
- func (t *Request) SetCookies(value string) *Request {
- if value == "" {
- t.cookies = nil
- t.cookies_setopt = true
- } else {
- t.cookies = make(map[string]string)
- t.AddCookies(value)
- }
- return t
- }
- // AddCookies
- //
- // @Description: 保留之前的 Cookies 并增加新的 Cookies
- func (t *Request) AddCookies(val string) *Request {
- if val != "" {
- for _, j_cookie := range strings.Split(val, ";") {
- if j_key, j_val := yu_strings.Left(j_cookie, "="), yu_strings.Empty(yu_strings.Right(j_cookie, "=")); j_key != "" {
- t.SetCookie(j_key, j_val)
- }
- }
- }
- return t
- }
- // GetCookie
- //
- // @Description: 获取单个 Cookie
- func (t *Request) GetCookie(name string) string {
- return t.cookies[name]
- }
- // GetCookies
- //
- // @Description: 获取全部 Cookie
- func (t *Request) GetCookies() string {
- if len(t.cookies) == 0 {
- return ""
- }
- j_cookies := make([]byte, 0, 1024)
- for j_name, j_value := range t.cookies {
- j_cookies = append(j_cookies, j_name...)
- j_cookies = append(j_cookies, '=')
- j_cookies = append(j_cookies, j_value...)
- j_cookies = append(j_cookies, ';')
- j_cookies = append(j_cookies, ' ')
- }
- return string(j_cookies)
- }
- // SetAutoCookies
- //
- // @Description: 设置自动合并更新Cookies,初始值为"false"
- func (t *Request) SetAutoCookies(enable bool) *Request {
- t.cookies_updata = enable
- return t
- }
- // -----------------------------------------------------------------------------------------------------------------------------------------------Utils
- // SetTimeout
- //
- // @Description: 设置整个请求的超时,单位:毫秒,默认超时为 60000(60秒),设置为零这意味着它在传输过程中永远不会超时。
- func (t *Request) SetTimeout(s int) *Request {
- if s < 0 {
- s = 0
- }
- curl_easy_setopt.Call(t.curl, OPT_TIMEOUT_MS, s)
- return t
- }
- // SetRdirect
- //
- // @Description: 是否遵循 HTTP 3xx 重定向,默认:true
- func (t *Request) SetRdirect(enable bool) *Request {
- curl_easy_setopt.Call(t.curl, OPT_FOLLOWLOCATION, enable)
- return t
- }
- // SetProxy 设置代理
- //
- // @Description:
- // @param proxy 格式 ProxyType://user:pass@host:port,ProxyType: http, socks4, socks4a, socks5, socks5h,设置为""以取消代理
- func (t *Request) SetProxy(proxy string) *Request {
- curl_easy_setopt.Call(t.curl, OPT_PROXY, yu_sys.S{yu_sys.Gbk, proxy})
- return t
- }
- // SetMaxConnects
- //
- // @Description: 设置的数量将是 libcurl 可以在与此句柄关联的池中缓存的同时打开的最大持久连接数。默认值为 5,更改此值没有多大意义,
- // 除非您完全了解它的工作原理并更改 libcurl 的行为。这涉及使用任何支持持久连接的协议的连接。
- // 当达到最大限制时,curl 会关闭缓存中最早的一个,以防止增加打开的连接数。
- // 如果您已经使用此 curl 句柄执行传输,则设置比以前更小的CURLOPT_MAXCONNECTS可能会导致打开的连接不必要地关闭。
- // 如果将此简单句柄添加到多句柄,则不会确认此设置,您必须改为使用curl_multi_setopt和CURLMOPT_MAXCONNECTS选项。
- // 默认5个
- // @param s
- func (t *Request) SetMaxConnects(s int) *Request {
- if s < 0 {
- s = 0
- }
- curl_easy_setopt.Call(t.curl, OPT_MAXCONNECTS, s)
- return t
- }
- // SetSslVerifyPeer
- //
- // @Description: 验证 SSL 证书,默认为:false
- func (t *Request) SetSslVerifyPeer(enable bool) *Request {
- curl_easy_setopt.Call(t.curl, OPT_SSL_VERIFYPEER, enable)
- return t
- }
- // SetSslVerifyHost
- //
- // @Description: 验证 SSL 证书中的主机名
- // 指定要验证的内容。
- // 此选项确定是否验证服务器证书是否适用于已知的服务器。
- // 在协商TLS和SSL连接时,服务器会发送一个表明其身份的证书。
- // 当为2时,该证书必须表明服务器是您要连接的服务器,否则连接失败。简单地说,这意味着它必须在证书中与您操作的URL中具有相同的名称。
- // 当证书中的“通用名称”字段或“使用者备用名称”字段与您要求Curl连接的URL中的主机名匹配时,Curl认为服务器是预期的服务器。
- // 如果验证值设置为1:
- // 在7.28.0及更早版本中:被视为某种调试选项,由于经常导致程序员错误而不再受支持。
- // 从7.28.1到7.65.3:将其设置为1则无效,并保持标志不变。
- // 从7.66.0开始:对1和2进行相同处理。
- // 当验证值为0时,无论证书中的名称如何,连接都会成功。小心使用这个能力!
- // 此选项的默认值为 2。
- // 此选项控制检查服务器证书声明的身份。服务器可能在撒谎。要控制说谎,请参见 "SetSslVerifyPeer"。
- func (t *Request) SetSslVerifyHost(verify uintptr) *Request {
- curl_easy_setopt.Call(t.curl, OPT_SSL_VERIFYHOST, verify)
- return t
- }
- // SetHttplVersion
- //
- // @Description: 传递一个长版本,设置为下面描述的值之一。他们要求 libcurl 使用特定的 HTTP 版本。
- // HTTP_VERSION_NONE
- // 我们不关心库使用什么版本。libcurl 将使用它认为合适的任何内容。
- //
- // HTTP_VERSION_1_0
- // 强制执行 HTTP 1.0 请求。
- //
- // HTTP_VERSION_1_1
- // 执行 HTTP 1.1 请求。
- //
- // HTTP_VERSION_2_0
- // 尝试 HTTP 2 请求。如果无法与服务器协商 HTTP 2,libcurl 将退回到 HTTP 1.1。(在 7.33.0 中添加)
- //
- // 当 libcurl 在 HTTPS 上使用 HTTP/2 时,它本身并不坚持使用 TLS 1.2 或更高版本,即使这是规范所要求的。用户可以使用CURLOPT_SSLVERSION添加此版本要求。
- // 在 7.43.0 中添加了别名CURL_HTTP_VERSION_2以更好地反映实际的协议名称。
- //
- // HTTP_VERSION_2TLS
- // 仅尝试通过 TLS (HTTPS) 的 HTTP 2。如果无法与 HTTPS 服务器协商 HTTP 2,libcurl 将回退到 HTTP 1.1。对于明文 HTTP 服务器,libcurl 将使用 1.1。(在 7.47.0 中添加)
- //
- // HTTP_VERSION_2_PRIOR_KNOWLEDGE
- // 在没有 HTTP/1.1 升级的情况下使用 HTTP/2 发出非 TLS HTTP 请求。它需要事先知道服务器直接支持 HTTP/2。HTTPS 请求仍将以标准方式执行 HTTP/2,并在 TLS 握手中协商协议版本。(在 7.49.0 中添加)
- //
- // HTTP_VERSION_3
- // (在 7.66.0 中添加)此选项使 libcurl 尝试对 URL 中给定的主机使用 HTTP/3,并在需要时回退到早期的 HTTP 版本。
- func (t *Request) SetHttplVersion(ver uintptr) *Request {
- curl_easy_setopt.Call(t.curl, OPT_HTTP_VERSION, ver)
- return t
- }
- // SetConnectTo
- //
- // @Description: 设置DNS转向
- // @param old 要拦截的 域名:端口,数字IPv6地址必须写在[括号]内,例如:"example.com"、"example.com:443"、"17.59.98.164:"、"17.59.98.164:80"、"[240e:e9:6002:189:0:ff:b06d:69df]"、"[240e:e9:6002:189:0:ff:b06d:69df]:443"
- // @param new 目标 域名:端口,数字IPv6地址必须写在[括号]内,例如:"example.com"、"example.com:443"、"17.59.98.164:"、"17.59.98.164:80"、"[240e:e9:6002:189:0:ff:b06d:69df]"、"[240e:e9:6002:189:0:ff:b06d:69df]:443"
- func (t *Request) SetConnectTo(old, new string) *Request {
- if t.connect_to == nil {
- t.connect_to = make(map[string]string)
- }
- if new == "" {
- delete(t.connect_to, old)
- } else {
- t.connect_to[old] = new
- }
- t.connect_to_setopt = true
- return t
- }
- // CleanConnectTo
- //
- // @Description: 清空DNS转向
- func (t *Request) CleanConnectTo() *Request {
- t.connect_to = nil
- t.connect_to_setopt = true
- return t
- }
- // SetSSLVersion
- //
- // @Description:传递一个长参数来控制要使用的 SSL/TLS 版本的版本范围。
- // SSL 和 TLS 版本通常从最不安全的版本发展到越来越安全的顺序:SSL v2、SSLv3、TLS v1.0、TLS v1.1、TLS v1.2 和最新的 TLS v1 .3.
- // 为此目的使用可用的定义之一。可用的选项是:
- //
- // SSLVERSION_DEFAULT
- // 默认可接受的版本范围。自 7.39.0 起,最低可接受版本默认为 TLS v1.0(除非 TLS 库有更严格的规则)。
- //
- // SSLVERSION_TLSv1
- // # TLS v1.0 或更高版本
- //
- // SSLVERSION_SSLv2
- // # SSL v2 - 拒绝
- //
- // SSLVERSION_SSLv3
- // # SSL v3 - 拒绝
- //
- // SSLVERSION_TLSv1_0
- // TLS v1.0 或更高版本(在 7.34.0 中添加)
- //
- // SSLVERSION_TLSv1_1
- // TLS v1.1 或更高版本(在 7.34.0 中添加)
- //
- // SSLVERSION_TLSv1_2
- // TLS v1.2 或更高版本(在 7.34.0 中添加)
- //
- // SSLVERSION_TLSv1_3
- // TLS v1.3 或更高版本(在 7.52.0 中添加)
- func (t *Request) SetSSLVersion(ver uintptr) *Request {
- curl_easy_setopt.Call(t.curl, OPT_SSLVERSION, ver)
- return t
- }
- // -----------------------------------------------------------------------------------------------------------------------------------------------Send
- // Get
- //
- // @Description: 发起Get请求
- func (t *Request) Get(url string) *Request {
- t.SetContentType("")
- t.SetHeader("Content-Encoding", "")
- curl_easy_setopt.Call(t.curl, OPT_URL, yu_sys.S{yu_sys.Gbk, url})
- curl_easy_setopt.Call(t.curl, OPT_HTTPGET, 1)
- t.opt()
- t.perform, _, _ = curl_easy_perform.Call(t.curl)
- return t
- }
- // Post
- //
- // @Description: 发起Post请求
- func (t *Request) Post(url string, data []byte) *Request {
- curl_easy_setopt.Call(t.curl, OPT_URL, yu_sys.S{yu_sys.Gbk, url})
- curl_easy_setopt.Call(t.curl, OPT_POST, 1)
- curl_easy_setopt.Call(t.curl, OPT_POSTFIELDSIZE, len(data))
- if len(data) > 0 {
- curl_easy_setopt.Call(t.curl, OPT_COPYPOSTFIELDS, data)
- }
- t.opt()
- t.perform, _, _ = curl_easy_perform.Call(t.curl)
- return t
- }
- // PostS
- //
- // @Description: 发起Post请求
- func (t *Request) PostS(url string, data string) *Request {
- curl_easy_setopt.Call(t.curl, OPT_URL, yu_sys.S{yu_sys.Gbk, url})
- curl_easy_setopt.Call(t.curl, OPT_POST, 1)
- curl_easy_setopt.Call(t.curl, OPT_POSTFIELDSIZE, len(data))
- if len(data) > 0 {
- curl_easy_setopt.Call(t.curl, OPT_COPYPOSTFIELDS, data)
- }
- t.opt()
- t.perform, _, _ = curl_easy_perform.Call(t.curl)
- return t
- }
- // // OpenWs
- // //
- // // @Description: 发起 Ws 请求
- // func (t *Request) OpenWs(url string) *Request {
- // t.SetContentType("")
- // t.SetHeader("Content-Encoding", "")
- // curl_easy_setopt.Call(t.curl, OPT_URL, yu_sys.S{yu_sys.Gbk, url})
- // curl_easy_setopt.Call(t.curl, OPT_CONNECT_ONLY, 2)
- // t.opt()
- // t.perform, _, _ = curl_easy_perform.Call(t.curl)
- // return t
- // }
|