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/e10c5585-33b1-432e-ad09-6b02601a8bd5n%40googlegroups.com.

Reply via email to