Open winteraz opened 7 years ago
You can do something like
proxy.OnRequest().DoFunc(func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
proxy.Tr = &http.Transport{...}
return r, nil
})
Isn't that a race condition? What about the other clients that make requests at the same time(each with its own/different transport). Isn't this overwriting their Transport?
maybe @elazarl can answer it better.
-which race condition? I'm not sure I understands
On Thu, Apr 13, 2017, 3:53 PM Rahul Sinha notifications@github.com wrote:
maybe @elazarl https://github.com/elazarl can answer it better.
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/elazarl/goproxy/issues/217#issuecomment-293886844, or mute the thread https://github.com/notifications/unsubscribe-auth/AAP4omg8mwrd_a4-wo4cpjdH46q7i59fks5rvhrOgaJpZM4M8Jl9 .
ConnectDial and Tr are global values of *ProxyHttpServer. If multiple go routines are reading and writing these fields concurrently as @rahulwa proposed that's a race condition, right? Not to mention that one request could modify ConnectDial and Tr for another request that is running concurrently so you can't really set a different Tr because you have no guarantee that it won't be changed by another go routine before the request is processed. Does it make sense to you?
In order to fix this I think Transport and ConnectDial should be copied on each request and provided perhaps in *goproxy.ProxyCtx
though I'm not very familiar with the code base so I can't say for sure. I
@elazarl I also see a RoundTripper on *goproxy.ProxyCtx but I don't know when or how is being used because it's not documented. Can I use a custom RoundTripper to process requests? Is ConnectDial or Tr from ProxyHttpServer still used if I use a custom RoundTripper
? What I need is to use a different transport for each request. That's because based on the request content(headers) I would like to use a different dialer(i.e. dial through a SOCKS5).
Yes, this is the way to do that
On Thu, Apr 13, 2017, 5:27 PM winteraz notifications@github.com wrote:
@elazarl https://github.com/elazarl I also see a RoundTripper on *goproxy.ProxyCtx but I don't know when or how is being used because it's not documented. Can I use a custom RoundTripper to process requests? Is ConnectDial or Tr from ProxyHttpServer still used if I use a custom RoundTripper? What I need is to use a different transport for each request. That's because based on the request content(headers) I would like to use a different dialer(i.e. dial through a SOCKS5).
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/elazarl/goproxy/issues/217#issuecomment-293911257, or mute the thread https://github.com/notifications/unsubscribe-auth/AAP4ogD-cwYvcSd1S5GqgU4HUvIiJJGSks5rvjDMgaJpZM4M8Jl9 .
@qZanity doesn't RoundTripper work for you?
On Tue, Apr 25, 2017 at 9:09 AM, qZanity notifications@github.com wrote:
@winteraz https://github.com/winteraz Did you find a good solution?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/elazarl/goproxy/issues/217#issuecomment-297081247, or mute the thread https://github.com/notifications/unsubscribe-auth/AAP4ovd7aw1Mvgu-KrNL_RWVbo3hGEJaks5rzhrEgaJpZM4M8Jl9 .
If anyone comes here, I have an example to use a custom roundtripper for each request:
rt := goproxy.RoundTripperFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Response, error) {
return custom.RoundTrip(req)
})
rp.OnRequest().HandleConnect(goproxy.AlwaysMitm)
rp.OnRequest().DoFunc(
func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
ctx.RoundTripper = rt
return r, nil
})
@mikegleasonjr
If anyone comes here, I have an example to use a custom roundtripper for each request:
rt := goproxy.RoundTripperFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Response, error) { return custom.RoundTrip(req) }) rp.OnRequest().HandleConnect(goproxy.AlwaysMitm) rp.OnRequest().DoFunc( func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { ctx.RoundTripper = rt return r, nil })
this way will return a self-sigined certificate created by goproxy , our client must skip tls v2rify.Is there a way to return certificate of target site? I have tested with below code:
proxyServer.ConnectDial = proxyServer.NewConnectDialToProxyWithHandler(https_proxy, func(req *http.Request) {
SetBasicAuth(username, password, req)
})
this way can return a certificate of target site, but can only set a proxy once,I want to set a proxy per request :(
Hello, I have some news on this issue. By adding the following function to https.go
, I managed to add a callback that will dinamically set the ConnectDial proxy.
I had to implement this, because AlwaysMITM is too slow and made my CPU usage spike to 100% on thousands of requests. This is a more light implementation if you don't need MITM or dont want to break the TLS.
func (proxy *ProxyHttpServer) CustomHTTPDialer(https_proxy func(req *http.Request) string, connectReqHandler func(req *http.Request)) func(network, addr string) (net.Conn, error) {
return func(network, addr string) (net.Conn, error) {
connectReq := &http.Request{
Method: "CONNECT",
URL: &url.URL{Opaque: addr},
Host: addr,
Header: make(http.Header),
}
u, err := url.Parse(https_proxy(connectReq))
if err != nil {
log.Fatal(err)
}
if connectReqHandler != nil {
connectReqHandler(connectReq)
}
c, err := proxy.dial(network, u.Host)
if err != nil {
return nil, err
}
connectReq.Write(c)
// Read response.
// Okay to use and discard buffered reader here, because
// TLS server will not speak until spoken to.
br := bufio.NewReader(c)
resp, err := http.ReadResponse(br, connectReq)
if err != nil {
c.Close()
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
resp, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
c.Close()
return nil, errors.New("proxy refused connection" + string(resp))
}
return c, nil
}
}
You can implement it on your program by doing:
proxy.ConnectDial = proxy.CustomHTTPDialer(yourOwnProxyCallback, nil)
I have tested it and it seems to be working!
I would like to set a different
http.Transport
andConnectDial
function based on the request received(e.g. within aDoFunc
) . How can I do that? Currently it seems they can be set only globally which makes the whole package useless for my use case.