108 lines
2.4 KiB
Go
108 lines
2.4 KiB
Go
package proxyutil
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
// Info is a parsed proxy configuration.
|
|
//
|
|
// It supports the following input formats:
|
|
// - http://host:port
|
|
// - http://user:pass@host:port
|
|
// - host:port (defaults to http)
|
|
// - host:port:user:pass (defaults to http; password may contain ':')
|
|
// - user:pass@host:port (defaults to http)
|
|
type Info struct {
|
|
// URL is the normalized proxy URL (may include credentials).
|
|
URL *url.URL
|
|
// Server is the proxy server URL without credentials (scheme + host:port).
|
|
Server *url.URL
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
func Parse(raw string) (*Info, error) {
|
|
raw = strings.TrimSpace(raw)
|
|
if raw == "" {
|
|
return &Info{}, nil
|
|
}
|
|
|
|
// URL-style proxy (has scheme)
|
|
if strings.Contains(raw, "://") {
|
|
u, err := url.Parse(raw)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse proxy url: %w", err)
|
|
}
|
|
if u.Scheme == "" || u.Host == "" {
|
|
return nil, fmt.Errorf("invalid proxy url: %q", raw)
|
|
}
|
|
|
|
u = &url.URL{
|
|
Scheme: strings.ToLower(u.Scheme),
|
|
Host: u.Host,
|
|
User: u.User,
|
|
}
|
|
|
|
user := ""
|
|
pass := ""
|
|
if u.User != nil {
|
|
user = u.User.Username()
|
|
pass, _ = u.User.Password()
|
|
}
|
|
|
|
server := &url.URL{Scheme: u.Scheme, Host: u.Host}
|
|
return &Info{
|
|
URL: u,
|
|
Server: server,
|
|
Username: user,
|
|
Password: pass,
|
|
}, nil
|
|
}
|
|
|
|
// user:pass@host:port (no scheme)
|
|
if strings.Contains(raw, "@") {
|
|
return Parse("http://" + raw)
|
|
}
|
|
|
|
// host:port[:user:pass]
|
|
parts := strings.Split(raw, ":")
|
|
switch {
|
|
case len(parts) == 2:
|
|
host, port := parts[0], parts[1]
|
|
hp := net.JoinHostPort(host, port)
|
|
u := &url.URL{Scheme: "http", Host: hp}
|
|
return &Info{URL: u, Server: &url.URL{Scheme: u.Scheme, Host: u.Host}}, nil
|
|
case len(parts) >= 4:
|
|
host, port := parts[0], parts[1]
|
|
user := parts[2]
|
|
pass := strings.Join(parts[3:], ":")
|
|
hp := net.JoinHostPort(host, port)
|
|
u := &url.URL{Scheme: "http", Host: hp, User: url.UserPassword(user, pass)}
|
|
return &Info{
|
|
URL: u,
|
|
Server: &url.URL{Scheme: u.Scheme, Host: u.Host},
|
|
Username: user,
|
|
Password: pass,
|
|
}, nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported proxy format: %q", raw)
|
|
}
|
|
}
|
|
|
|
// Normalize returns a normalized proxy URL string.
|
|
// Empty input returns empty output.
|
|
func Normalize(raw string) (string, error) {
|
|
info, err := Parse(raw)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if info.URL == nil {
|
|
return "", nil
|
|
}
|
|
return info.URL.String(), nil
|
|
}
|
|
|