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.

Reply via email to