You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@casbin.apache.org by hs...@apache.org on 2026/08/18 10:22:52 UTC

(casbin-gateway) branch master updated: fix: route outbound requests through the configured httpProxy

This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git


The following commit(s) were added to refs/heads/master by this push:
     new d83c6ba  fix: route outbound requests through the configured httpProxy
d83c6ba is described below

commit d83c6bad291dd8bae3edd325b952d44ec0c02133
Author: Yang Luo <hs...@gmail.com>
AuthorDate: Tue Aug 18 18:22:24 2026 +0800

    fix: route outbound requests through the configured httpProxy
---
 controllers/proxy.go        |   3 +-
 object/cert_whois.go        |   6 ---
 object/channel.go           |   4 +-
 object/site_cert_account.go |   3 +-
 proxy/proxy.go              | 103 +++++++++++++++++++++-----------------------
 5 files changed, 57 insertions(+), 62 deletions(-)

diff --git a/controllers/proxy.go b/controllers/proxy.go
index 892d29a..45b9dc1 100644
--- a/controllers/proxy.go
+++ b/controllers/proxy.go
@@ -27,6 +27,7 @@ import (
 	"time"
 
 	"github.com/apache/casbin-gateway/object"
+	"github.com/apache/casbin-gateway/proxy"
 	"github.com/beego/beego"
 )
 
@@ -77,7 +78,7 @@ type openaiErrorDetail struct {
 var proxyClient = &http.Client{
 	CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse },
 	Transport: &http.Transport{
-		Proxy: http.ProxyFromEnvironment,
+		Proxy: proxy.Proxy,
 		DialContext: (&net.Dialer{
 			Timeout:   10 * time.Second,
 			KeepAlive: 30 * time.Second,
diff --git a/object/cert_whois.go b/object/cert_whois.go
index 9513a8a..85c678a 100644
--- a/object/cert_whois.go
+++ b/object/cert_whois.go
@@ -47,12 +47,6 @@ func getDomainExpireTime(domainName string) (string, error) {
 	}
 
 	client := whois.NewClient()
-	//if server != "whois.cnnic.cn" && server != "grs-whois.hichina.com" {
-	//	dialer := proxy.GetProxyDialer()
-	//	if dialer != nil {
-	//		client.SetDialer(dialer)
-	//	}
-	//}
 
 	data, err := client.Whois(domainName, server)
 	if err != nil {
diff --git a/object/channel.go b/object/channel.go
index a638b47..b11489c 100644
--- a/object/channel.go
+++ b/object/channel.go
@@ -23,6 +23,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/apache/casbin-gateway/proxy"
 	"github.com/apache/casbin-gateway/util"
 	"github.com/xorm-io/core"
 )
@@ -304,7 +305,8 @@ func TestChannelConnectivity(channel *Channel) (bool, int, string) {
 	}
 
 	client := &http.Client{
-		Timeout: 10 * time.Second,
+		Timeout:   10 * time.Second,
+		Transport: proxy.Transport(),
 		// Do not follow redirects, so the reported status is the one the
 		// configured base URL actually returns.
 		CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse },
diff --git a/object/site_cert_account.go b/object/site_cert_account.go
index 5755f70..5a1f546 100644
--- a/object/site_cert_account.go
+++ b/object/site_cert_account.go
@@ -17,6 +17,7 @@ package object
 import (
 	"crypto"
 	"fmt"
+	"net/http"
 
 	"github.com/apache/casbin-gateway/proxy"
 	"github.com/beego/beego"
@@ -70,7 +71,7 @@ func getLegoClientAndAccount(email string, privateKey string, devMode bool, useP
 	if useProxy {
 		config.HTTPClient = proxy.ProxyHttpClient
 	} else {
-		config.HTTPClient = proxy.DefaultHttpClient
+		config.HTTPClient = http.DefaultClient
 	}
 
 	client, err := lego.NewClient(config)
diff --git a/proxy/proxy.go b/proxy/proxy.go
index 0b2535e..ff955fb 100644
--- a/proxy/proxy.go
+++ b/proxy/proxy.go
@@ -12,83 +12,80 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// Package proxy routes every outbound request through the proxy configured as
+// httpProxy in conf/app.conf, falling back to the HTTP_PROXY / HTTPS_PROXY
+// environment variables when that setting is empty.
 package proxy
 
 import (
 	"fmt"
-	"net"
 	"net/http"
-	"time"
+	"net/url"
+	"strings"
+	"sync"
 
 	"github.com/beego/beego"
-	"golang.org/x/net/proxy"
 )
 
-var DefaultHttpClient *http.Client
+// ProxyHttpClient sends its requests through the configured proxy.
 var ProxyHttpClient *http.Client
 
-func InitHttpClient() {
-	// not use proxy
-	DefaultHttpClient = http.DefaultClient
-
-	// use proxy
-	ProxyHttpClient = getProxyHttpClient()
-}
-
-func isAddressOpen(address string) bool {
-	timeout := time.Millisecond * 100
-	conn, err := net.DialTimeout("tcp", address, timeout)
-	if err != nil {
-		// cannot connect to address, proxy is not active
-		return false
-	}
+var (
+	proxyUrlOnce sync.Once
+	proxyUrl     *url.URL
 
-	if conn != nil {
-		defer conn.Close()
-		fmt.Printf("Socks5 proxy enabled: %s\n", address)
-		return true
-	}
+	transportOnce sync.Once
+	transport     *http.Transport
+)
 
-	return false
+func InitHttpClient() {
+	proxyUrlOnce.Do(initProxyUrl)
+	ProxyHttpClient = &http.Client{Transport: Transport()}
 }
 
-func getProxyHttpClient() *http.Client {
-	httpProxy := beego.AppConfig.String("httpProxy")
-	if httpProxy == "" {
-		return &http.Client{}
-	}
-
-	if !isAddressOpen(httpProxy) {
-		return &http.Client{}
-	}
-
-	// https://stackoverflow.com/questions/33585587/creating-a-go-socks5-client
-	dialer, err := proxy.SOCKS5("tcp", httpProxy, nil, proxy.Direct)
-	if err != nil {
-		panic(err)
+// Proxy picks the proxy to reach req through. It is meant to be assigned to
+// http.Transport.Proxy, which calls it per request, so the httpProxy setting is
+// read on first use instead of at package initialization: in -tags embed builds
+// the embedded conf/app.conf is only loaded once main's init() runs, after every
+// imported package has already initialized its own variables.
+func Proxy(req *http.Request) (*url.URL, error) {
+	proxyUrlOnce.Do(initProxyUrl)
+	if proxyUrl == nil {
+		return http.ProxyFromEnvironment(req)
 	}
+	return proxyUrl, nil
+}
 
-	tr := &http.Transport{Dial: dialer.Dial}
-	return &http.Client{
-		Transport: tr,
-	}
+// Transport returns the shared transport for outbound requests. Sharing one
+// instance keeps the connection pool shared as well.
+func Transport() *http.Transport {
+	transportOnce.Do(func() {
+		transport = http.DefaultTransport.(*http.Transport).Clone()
+		transport.Proxy = Proxy
+	})
+	return transport
 }
 
-func GetProxyDialer() *net.Dialer {
-	httpProxy := beego.AppConfig.String("httpProxy")
+// initProxyUrl parses the httpProxy setting. A bare "host:port" means SOCKS5,
+// which is what the setting has always been taken to mean; "socks5://",
+// "socks5h://", "http://" and "https://" addresses are honoured as written, and
+// may carry credentials.
+func initProxyUrl() {
+	httpProxy := strings.TrimSpace(beego.AppConfig.String("httpProxy"))
 	if httpProxy == "" {
-		return nil
+		return
 	}
 
-	if !isAddressOpen(httpProxy) {
-		return nil
+	if !strings.Contains(httpProxy, "://") {
+		httpProxy = "socks5://" + httpProxy
 	}
 
-	// https://stackoverflow.com/questions/33585587/creating-a-go-socks5-client
-	dialer, err := proxy.SOCKS5("tcp", httpProxy, nil, proxy.Direct)
-	if err != nil {
-		panic(err)
+	parsedUrl, err := url.Parse(httpProxy)
+	if err != nil || parsedUrl.Host == "" {
+		fmt.Printf("httpProxy is not a valid proxy address, outbound traffic is left unproxied: %s\n", httpProxy)
+		return
 	}
 
-	return dialer.(*net.Dialer)
+	proxyUrl = parsedUrl
+	fmt.Printf("Proxy enabled for outbound traffic: %s\n", proxyUrl.Redacted())
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@casbin.apache.org
For additional commands, e-mail: commits-help@casbin.apache.org