tiny-rdm/backend/utils/proxy/http.go

97 lines
1.8 KiB
Go

package proxy
import (
"bufio"
"fmt"
"net"
"net/http"
"net/url"
"time"
"golang.org/x/net/proxy"
)
type HttpProxy struct {
scheme string // HTTP Proxy scheme
host string // HTTP Proxy host or host:port
auth *proxy.Auth // authentication
forward proxy.Dialer // forwarding Dialer
}
func (p *HttpProxy) Dial(network, addr string) (net.Conn, error) {
c, err := p.forward.Dial(network, p.host)
if err != nil {
return nil, err
}
err = c.SetDeadline(time.Now().Add(15 * time.Second))
if err != nil {
return nil, err
}
reqUrl := &url.URL{
Scheme: "",
Host: addr,
}
// create with CONNECT method
req, err := http.NewRequest("CONNECT", reqUrl.String(), nil)
if err != nil {
c.Close()
return nil, err
}
req.Close = false
// authentication
if p.auth != nil {
req.SetBasicAuth(p.auth.User, p.auth.Password)
req.Header.Add("Proxy-Authorization", req.Header.Get("Authorization"))
}
// send request
err = req.Write(c)
if err != nil {
c.Close()
return nil, err
}
res, err := http.ReadResponse(bufio.NewReader(c), req)
if err != nil {
res.Body.Close()
c.Close()
return nil, err
}
res.Body.Close()
if res.StatusCode != http.StatusOK {
c.Close()
return nil, fmt.Errorf("proxy connection error: StatusCode[%d]", res.StatusCode)
}
return c, nil
}
func NewHttpProxyDialer(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error) {
var auth *proxy.Auth
if u.User != nil {
pwd, _ := u.User.Password()
auth = &proxy.Auth{
User: u.User.Username(),
Password: pwd,
}
}
hp := &HttpProxy{
scheme: u.Scheme,
host: u.Host,
auth: auth,
forward: forward,
}
return hp, nil
}
func init() {
proxy.RegisterDialerType("http", NewHttpProxyDialer)
proxy.RegisterDialerType("https", NewHttpProxyDialer)
}