Hey there,

Seems the issue hides in the chunk, where you overwrite reverse proxy's 
"Director" method, which NewSingleHostReverseProxy creates internally. 
Since your own director doesn't set the client request's Schema and Host, 
you have to either do that manually or make sure you call the original 
director.

Try doing the following:

proxyDirector := proxy.Director // ← keep the original director
d := func(req *http.Request) {
        logrus.Infof("Pre-Edited request: %+v\n", req)

        proxyDirector(req) // ← call the original director to make sure the 
request will go through the proxy

        // 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

Also, have a look at the implementation of NewSingleHostReverseProxy 
https://go.googlesource.com/go/+/go1.16/src/net/http/httputil/reverseproxy.go#142

Cheers,
V.

On Monday, March 15, 2021 at 11:37:51 PM UTC+1 hugo....@gmail.com wrote:

> 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:
>
> [image: IGopher_proxies.jpg]
>
> Something like this:  proxy-login-automator 
> <https://github.com/sjitech/proxy-login-automator>
>
> 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! :)
>
> You can find all IGopher sources here: GitHub repository 
> <https://github.com/hbollon/IGopher> (Proxy stuff excluded)
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/3acdea0b-4bb7-4246-944c-e4ecbb983a84n%40googlegroups.com.

Reply via email to