mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-19 06:14:45 +08:00
fix(proxy): encode special chars in proxy credentials
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,10 +25,14 @@ func (p *Proxy) IsActive() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proxy) URL() string {
|
func (p *Proxy) URL() string {
|
||||||
if p.Username != "" && p.Password != "" {
|
u := &url.URL{
|
||||||
return fmt.Sprintf("%s://%s:%s@%s:%d", p.Protocol, p.Username, p.Password, p.Host, p.Port)
|
Scheme: p.Protocol,
|
||||||
|
Host: net.JoinHostPort(p.Host, strconv.Itoa(p.Port)),
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s://%s:%d", p.Protocol, p.Host, p.Port)
|
if p.Username != "" && p.Password != "" {
|
||||||
|
u.User = url.UserPassword(p.Username, p.Password)
|
||||||
|
}
|
||||||
|
return u.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProxyWithAccountCount struct {
|
type ProxyWithAccountCount struct {
|
||||||
|
|||||||
95
backend/internal/service/proxy_test.go
Normal file
95
backend/internal/service/proxy_test.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProxyURL(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
proxy Proxy
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "without auth",
|
||||||
|
proxy: Proxy{
|
||||||
|
Protocol: "http",
|
||||||
|
Host: "proxy.example.com",
|
||||||
|
Port: 8080,
|
||||||
|
},
|
||||||
|
want: "http://proxy.example.com:8080",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with auth",
|
||||||
|
proxy: Proxy{
|
||||||
|
Protocol: "socks5",
|
||||||
|
Host: "socks.example.com",
|
||||||
|
Port: 1080,
|
||||||
|
Username: "user",
|
||||||
|
Password: "pass",
|
||||||
|
},
|
||||||
|
want: "socks5://user:pass@socks.example.com:1080",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "username only keeps no auth for compatibility",
|
||||||
|
proxy: Proxy{
|
||||||
|
Protocol: "http",
|
||||||
|
Host: "proxy.example.com",
|
||||||
|
Port: 8080,
|
||||||
|
Username: "user-only",
|
||||||
|
},
|
||||||
|
want: "http://proxy.example.com:8080",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with special characters in credentials",
|
||||||
|
proxy: Proxy{
|
||||||
|
Protocol: "http",
|
||||||
|
Host: "proxy.example.com",
|
||||||
|
Port: 3128,
|
||||||
|
Username: "first last@corp",
|
||||||
|
Password: "p@ ss:#word",
|
||||||
|
},
|
||||||
|
want: "http://first%20last%40corp:p%40%20ss%3A%23word@proxy.example.com:3128",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if got := tc.proxy.URL(); got != tc.want {
|
||||||
|
t.Fatalf("Proxy.URL() mismatch: got=%q want=%q", got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProxyURL_SpecialCharactersRoundTrip(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
proxy := Proxy{
|
||||||
|
Protocol: "http",
|
||||||
|
Host: "proxy.example.com",
|
||||||
|
Port: 3128,
|
||||||
|
Username: "first last@corp",
|
||||||
|
Password: "p@ ss:#word",
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := url.Parse(proxy.URL())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse proxy URL failed: %v", err)
|
||||||
|
}
|
||||||
|
if got := parsed.User.Username(); got != proxy.Username {
|
||||||
|
t.Fatalf("username mismatch after parse: got=%q want=%q", got, proxy.Username)
|
||||||
|
}
|
||||||
|
pass, ok := parsed.User.Password()
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("password missing after parse")
|
||||||
|
}
|
||||||
|
if pass != proxy.Password {
|
||||||
|
t.Fatalf("password mismatch after parse: got=%q want=%q", pass, proxy.Password)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user