mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-06-02 22:20:41 +08:00
feat: implement httpProxyDialer for HTTP CONNECT proxies and enhance newProxyDialer function
This commit is contained in:
@@ -1,6 +1,12 @@
|
|||||||
package tgutil
|
package tgutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/gotd/td/telegram/dcs"
|
"github.com/gotd/td/telegram/dcs"
|
||||||
@@ -8,24 +14,108 @@ import (
|
|||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newProxyDialer(proxyUrl string) (proxy.Dialer, error) {
|
// httpProxyDialer implements proxy.ContextDialer for HTTP CONNECT proxies
|
||||||
url, err := url.Parse(proxyUrl)
|
type httpProxyDialer struct {
|
||||||
|
proxyURL *url.URL
|
||||||
|
forward proxy.Dialer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *httpProxyDialer) Dial(network, addr string) (net.Conn, error) {
|
||||||
|
return d.DialContext(context.Background(), network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *httpProxyDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
proxyAddr := d.proxyURL.Host
|
||||||
|
if d.proxyURL.Port() == "" {
|
||||||
|
if d.proxyURL.Scheme == "https" {
|
||||||
|
proxyAddr = net.JoinHostPort(d.proxyURL.Hostname(), "443")
|
||||||
|
} else {
|
||||||
|
proxyAddr = net.JoinHostPort(d.proxyURL.Hostname(), "80")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var conn net.Conn
|
||||||
|
var err error
|
||||||
|
if ctxDialer, ok := d.forward.(proxy.ContextDialer); ok {
|
||||||
|
conn, err = ctxDialer.DialContext(ctx, "tcp", proxyAddr)
|
||||||
|
} else {
|
||||||
|
conn, err = d.forward.Dial("tcp", proxyAddr)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to connect to proxy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send CONNECT request
|
||||||
|
connectReq := &http.Request{
|
||||||
|
Method: "CONNECT",
|
||||||
|
URL: &url.URL{Opaque: addr},
|
||||||
|
Host: addr,
|
||||||
|
Header: make(http.Header),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add proxy authentication if provided
|
||||||
|
if d.proxyURL.User != nil {
|
||||||
|
username := d.proxyURL.User.Username()
|
||||||
|
password, _ := d.proxyURL.User.Password()
|
||||||
|
auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||||
|
connectReq.Header.Set("Proxy-Authorization", "Basic "+auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := connectReq.Write(conn); err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, fmt.Errorf("failed to write CONNECT request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read response
|
||||||
|
br := bufio.NewReader(conn)
|
||||||
|
resp, err := http.ReadResponse(br, connectReq)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, fmt.Errorf("failed to read CONNECT response: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
conn.Close()
|
||||||
|
return nil, fmt.Errorf("proxy CONNECT failed with status: %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProxyDialer(proxyUrl string) (proxy.ContextDialer, error) {
|
||||||
|
parsedURL, err := url.Parse(proxyUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return proxy.FromURL(url, proxy.Direct)
|
|
||||||
|
switch parsedURL.Scheme {
|
||||||
|
case "http", "https":
|
||||||
|
return &httpProxyDialer{
|
||||||
|
proxyURL: parsedURL,
|
||||||
|
forward: proxy.Direct,
|
||||||
|
}, nil
|
||||||
|
case "socks5", "socks5h":
|
||||||
|
dialer, err := proxy.FromURL(parsedURL, proxy.Direct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dialer.(proxy.ContextDialer), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported proxy scheme: %s", parsedURL.Scheme)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConfigProxyResolver() (dcs.Resolver, error) {
|
func NewConfigProxyResolver() (dcs.Resolver, error) {
|
||||||
resolver := dcs.DefaultResolver()
|
resolver := dcs.DefaultResolver()
|
||||||
if config.C().Proxy != "" {
|
if config.C().Proxy != "" {
|
||||||
// gloabl proxy, which has lower priority
|
// global proxy, which has lower priority
|
||||||
dialer, err := newProxyDialer(config.C().Proxy)
|
dialer, err := newProxyDialer(config.C().Proxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resolver = dcs.Plain(dcs.PlainOptions{
|
resolver = dcs.Plain(dcs.PlainOptions{
|
||||||
Dial: dialer.(proxy.ContextDialer).DialContext,
|
Dial: dialer.DialContext,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if config.C().Telegram.Proxy.Enable && config.C().Telegram.Proxy.URL != "" {
|
if config.C().Telegram.Proxy.Enable && config.C().Telegram.Proxy.URL != "" {
|
||||||
@@ -34,7 +124,7 @@ func NewConfigProxyResolver() (dcs.Resolver, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resolver = dcs.Plain(dcs.PlainOptions{
|
resolver = dcs.Plain(dcs.PlainOptions{
|
||||||
Dial: dialer.(proxy.ContextDialer).DialContext,
|
Dial: dialer.DialContext,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return resolver, nil
|
return resolver, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user