115 lines
3.8 KiB
Go
115 lines
3.8 KiB
Go
package utils_test
|
||
|
||
import (
|
||
"crypto/tls"
|
||
"errors"
|
||
"net/http"
|
||
"net/http/httptest"
|
||
"testing"
|
||
|
||
"github.com/EthanCodeCraft/xlgo-core/utils"
|
||
)
|
||
|
||
// 回归 H2:默认 HTTPClient 必须 校验 TLS(InsecureSkipVerify=false),
|
||
// 访问自签证书的 https server 应失败。旧实现 DefaultHTTPClientConfig.SkipTLSVerify=true,
|
||
// HTTPGet/Post 默认可被 MITM。
|
||
func TestHTTPClientDefaultVerifiesTLS(t *testing.T) {
|
||
// 启动一个使用自签证书的 TLS server(httptest 自动生成证书,未被客户端信任)。
|
||
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
w.Write([]byte("ok"))
|
||
}))
|
||
defer srv.Close()
|
||
|
||
// 默认客户端(H2 修复后 SkipTLSVerify=false)应因证书校验失败而报错。
|
||
c := utils.NewHTTPClient()
|
||
if _, err := c.Get(srv.URL, nil); err == nil {
|
||
t.Error("default HTTPClient should fail TLS verification against self-signed cert (H2: was InsecureSkipVerify=true)")
|
||
}
|
||
}
|
||
|
||
// 回归 H2:HTTPGet 包级函数(经 DefaultHTTPClient)默认同样校验 TLS。
|
||
func TestHTTPGetDefaultVerifiesTLS(t *testing.T) {
|
||
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
w.Write([]byte("ok"))
|
||
}))
|
||
defer srv.Close()
|
||
|
||
if _, err := utils.HTTPGet(srv.URL, nil); err == nil {
|
||
t.Error("HTTPGet should fail TLS verification against self-signed cert by default")
|
||
}
|
||
}
|
||
|
||
// 回归 H2:显式 SetSkipTLS(true) 后可访问自签证书 server(opt-in 跳过校验)。
|
||
func TestHTTPClientSkipTLSOptIn(t *testing.T) {
|
||
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
w.Write([]byte("ok"))
|
||
}))
|
||
defer srv.Close()
|
||
|
||
c := utils.NewHTTPClient()
|
||
c.SetSkipTLS(true)
|
||
|
||
body, err := c.Get(srv.URL, nil)
|
||
if err != nil {
|
||
t.Fatalf("Get with SkipTLS=true should succeed against self-signed cert, got: %v", err)
|
||
}
|
||
if string(body) != "ok" {
|
||
t.Errorf("body = %q, want ok", string(body))
|
||
}
|
||
}
|
||
|
||
// 回归 H2:NewHTTPClientWithConfig 显式设 SkipTLSVerify=true 可跳过校验。
|
||
func TestHTTPClientWithConfigSkipTLS(t *testing.T) {
|
||
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
w.Write([]byte("ok"))
|
||
}))
|
||
defer srv.Close()
|
||
|
||
c := utils.NewHTTPClientWithConfig(utils.HTTPClientConfig{
|
||
SkipTLSVerify: true,
|
||
})
|
||
body, err := c.Get(srv.URL, nil)
|
||
if err != nil {
|
||
t.Fatalf("Get with config SkipTLSVerify=true should succeed, got: %v", err)
|
||
}
|
||
if string(body) != "ok" {
|
||
t.Errorf("body = %q, want ok", string(body))
|
||
}
|
||
}
|
||
|
||
// 回归 H2:DefaultHTTPClientConfig.SkipTLSVerify 默认 false。
|
||
func TestDefaultHTTPClientConfigNoSkipTLS(t *testing.T) {
|
||
if utils.DefaultHTTPClientConfig.SkipTLSVerify {
|
||
t.Error("DefaultHTTPClientConfig.SkipTLSVerify = true, want false (H2: default must verify TLS)")
|
||
}
|
||
}
|
||
|
||
// 回归 H2:默认 transport 的 TLSClientConfig.InsecureSkipVerify 为 false。
|
||
// 直接构造一个对 https 的请求,确认未跳过校验。用 errors 判断是否为 x509 校验类错误。
|
||
func TestDefaultClientTransportVerifiesTLS(t *testing.T) {
|
||
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
w.Write([]byte("ok"))
|
||
}))
|
||
defer srv.Close()
|
||
|
||
c := utils.NewHTTPClient()
|
||
// 用自定义 client 配自定义 transport 不可行(封装),直接调 Get 验证错误类型。
|
||
_, err := c.Get(srv.URL, nil)
|
||
if err == nil {
|
||
t.Fatal("expected TLS verification error, got nil")
|
||
}
|
||
// 错误应包含证书校验相关提示(如 x509 / certificate / tls)。
|
||
if !isTLSError(err) {
|
||
t.Logf("err = %v (not strictly x509 classified, but default did reject — acceptable)", err)
|
||
}
|
||
}
|
||
|
||
// isTLSError 粗略判断错误是否为 TLS 证书校验失败。
|
||
func isTLSError(err error) bool {
|
||
if err == nil {
|
||
return false
|
||
}
|
||
var ve *tls.CertificateVerificationError
|
||
return errors.As(err, &ve)
|
||
}
|