I think I didn't get what you're building right. Now, it looks like, instead of implementing a custom RR's director, you need to configure its Transport [1], which will be aware of your auth proxy in the middle. Have a look at net/http.Transport.Proxy field [2] for that.
[1]: https://pkg.go.dev/net/http/httputil?utm_source=godoc#ReverseProxy [2]: https://pkg.go.dev/net/http?utm_source=godoc#Transport On Tuesday, March 16, 2021 at 11:17:49 AM UTC+1 hugo....@gmail.com wrote: > Thank you for your advice that I applied. > But now I have a *407 Proxy Authentication Required* error, while the > header is added to the request... > Here is the output: > > INFO[0019] 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:45382 RequestURI:google.com:443 > TLS:<nil> Cancel:<nil> Response:<nil> ctx:0xc000814240} function=func1 > line=60 > > INFO[0019] Edited Request: &{Method:CONNECT URL:http://51.178.xx.xx:3128/ > 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:45382 RequestURI:google.com:443 TLS:<nil> Cancel:<nil> > Response:<nil> ctx:0xc000814240} function=func1 line=69 > > INFO[0019] Scheme: http, Host: 51.178.xx.xx:3128, Port: 3128 > function=func1 line=70 > > INFO[0019] Response: &{Status:407 Proxy Authentication Required > StatusCode:407 Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 > Header:map[Content-Language:[en] Content-Length:[3520] > Content-Type:[text/html;charset=utf-8] Date:[Tue, 16 Mar 2021 10:03:44 GMT] > Mime-Version:[1.0] Server:[squid/3.5.27] Vary:[Accept-Language] Via:[1.1 > vps799016 (squid/3.5.27)] X-Cache:[MISS from vps799xxx] > X-Cache-Lookup:[NONE from vps799xxx:3128] > X-Squid-Error:[ERR_CACHE_ACCESS_DENIED 0]] Body:0xc0004de180 > ContentLength:3520 TransferEncoding:[] Close:false Uncompressed:false > Trailer:map[] Request:0xc0005ee100 TLS:<nil>} function=PrintResponse > line=33 > > > PS: Is it possible on Google Groups to format code snippets? Markdown not > seems to be supported > > Le mardi 16 mars 2021 à 09:04:31 UTC+1, vlad...@varank.in a écrit : > >> 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/803d7ee6-f847-435a-8207-abb7df968773n%40googlegroups.com.