Hi!
I'm actually building an automation tool based on Selenium with Go called IGopher and I have had a few requests to implement native proxy support.
However, I am facing an issue with those with authentication...
I can't send the proxy credentials to Chrome and without them it asks through an alert box for authentication that I can hardly interact with through Selenium (I'm not even sure it's possible in headless mode) .
So I thought of an intermediary proxy system hosted locally by my program which will add the Proxy-Authorization header and transfer the request to the remote proxy:
I'm not very familiar with proxies to be honest, but I tried this approach using NewSingleHostReverseProxy:
```go
var (
localServerHost string
remoteServerHost string
remoteServerAuth string
)
// ProxyConfig store all remote proxy configuration
type ProxyConfig struct {
IP string `yaml:"ip"`
Port int `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Enabled bool `yaml:"activated"`
}
func PrintResponse(r *http.Response) error {
logrus.Infof("Response: %+v\n", r)
return nil
}
// LaunchForwardingProxy launch forward server used to inject proxy authentication header
// into outgoing requests
func LaunchForwardingProxy(localPort uint16, remoteProxy ProxyConfig) error {
localServerHost = fmt.Sprintf("localhost:%d", localPort)
remoteServerHost = fmt.Sprintf(
"http://%s:%d",
remoteProxy.IP,
remoteProxy.Port,
)
remoteServerAuth = fmt.Sprintf(
"%s:%s",
remoteProxy.Username,
remoteProxy.Password,
)
remote, err := url.Parse(remoteServerHost)
if err != nil {
panic(err)
}
proxy := httputil.NewSingleHostReverseProxy(remote)
d := func(req *http.Request) {
logrus.Infof("Pre-Edited request: %+v\n", req)
// Inject proxy authentication headers to outgoing request into new Header
basicAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte(remoteServerAuth))
req.Header.Set("Proxy-Authorization", basicAuth)
logrus.Infof("Edited Request: %+v\n", req)
logrus.Infof("Scheme: %s, Host: %s, Port: %s\n", req.URL.Scheme, req.URL.Host, req.URL.Port())
}
proxy.Director = d
proxy.ModifyResponse = PrintResponse
http.ListenAndServe(localServerHost, proxy)
return nil
}
```
With this code snippet, I'm able to intercept the request and update the header.
However, resending the CONNECT request fails with the following output:
```
INFO[0028] Pre-Edited request: &{Method:CONNECT URL://
google.com:443 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Proxy-Connection:[Keep-Alive] User-Agent:[curl/7.68.0]] Body:<nil> GetBody:<nil> ContentLength:0 TransferEncoding:[] Close:false Host:
google.com:443 Form:map[] PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr:
127.0.0.1:35610 RequestURI:
google.com:443 TLS:<nil> Cancel:<nil> Response:<nil> ctx:0xc000164300} function=func1 line=59
INFO[0028] Edited Request: &{Method:CONNECT URL://
google.com:443 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Proxy-Authorization:[Basic <auth>] Proxy-Connection:[Keep-Alive] User-Agent:[curl/7.68.0]] Body:<nil> GetBody:<nil> ContentLength:0 TransferEncoding:[] Close:false Host:
google.com:443 Form:map[] PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr:
127.0.0.1:35610 RequestURI:
google.com:443 TLS:<nil> Cancel:<nil> Response:<nil> ctx:0xc000164300} function=func1 line=63
INFO[0028] Scheme: , Host:
google.com:443, Port: 443 function=func1 line=64
2021/03/15 21:35:11 http: proxy error: unsupported protocol scheme ""
```
What am I doing wrong? Is there a way to send a CONNECT request without scheme in Go?
Maybe I'm doing something wrong or my approach to this problem is wrong. Are there better methods to achieve my goals?
If you have an idea to complete what I did or any other method, please let me know! :)