From c25598659d734938368707fabc73115fb882be58 Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Thu, 15 Jul 2021 23:32:58 +0200 Subject: [PATCH 1/2] feat: Export Handlers (req, rest, https) This is usufull when handlers will be dynamicaly created and removed. --- README.md | 6 +++--- dispatcher.go | 8 ++++---- https.go | 4 ++-- proxy.go | 16 ++++++++-------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b9e7941c..8a96ee92 100644 --- a/README.md +++ b/README.md @@ -109,14 +109,14 @@ There are 3 kinds of useful handlers to manipulate the behavior, as follows: ```go // handler called after receiving HTTP CONNECT from the client, and before proxy establish connection // with destination host -httpsHandlers []HttpsHandler +HttpsHandlers []HttpsHandler // handler called before proxy send HTTP request to destination host -reqHandlers []ReqHandler +ReqHandlers []ReqHandler // handler called after proxy receives HTTP Response from destination host, and before proxy forward // the Response to the client. -respHandlers []RespHandler +RespHandlers []RespHandler ``` Depending on what you want to manipulate, the ways to add handlers to each handler list are: diff --git a/dispatcher.go b/dispatcher.go index 25c949c0..cc0c1009 100644 --- a/dispatcher.go +++ b/dispatcher.go @@ -206,7 +206,7 @@ func (pcond *ReqProxyConds) DoFunc(f func(req *http.Request, ctx *ProxyCtx) (*ht // // given request to the proxy, will test if cond1.HandleReq(req,ctx) && cond2.HandleReq(req,ctx) are true // // if they are, will call handler.Handle(req,ctx) func (pcond *ReqProxyConds) Do(h ReqHandler) { - pcond.proxy.reqHandlers = append(pcond.proxy.reqHandlers, + pcond.proxy.ReqHandlers = append(pcond.proxy.ReqHandlers, FuncReqHandler(func(r *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response) { for _, cond := range pcond.reqConds { if !cond.HandleReq(r, ctx) { @@ -229,7 +229,7 @@ func (pcond *ReqProxyConds) Do(h ReqHandler) { // will use the default tls configuration. // proxy.OnRequest().HandleConnect(goproxy.AlwaysReject) // rejects all CONNECT requests func (pcond *ReqProxyConds) HandleConnect(h HttpsHandler) { - pcond.proxy.httpsHandlers = append(pcond.proxy.httpsHandlers, + pcond.proxy.HttpsHandlers = append(pcond.proxy.HttpsHandlers, FuncHttpsHandler(func(host string, ctx *ProxyCtx) (*ConnectAction, string) { for _, cond := range pcond.reqConds { if !cond.HandleReq(ctx.Req, ctx) { @@ -257,7 +257,7 @@ func (pcond *ReqProxyConds) HandleConnectFunc(f func(host string, ctx *ProxyCtx) } func (pcond *ReqProxyConds) HijackConnect(f func(req *http.Request, client net.Conn, ctx *ProxyCtx)) { - pcond.proxy.httpsHandlers = append(pcond.proxy.httpsHandlers, + pcond.proxy.HttpsHandlers = append(pcond.proxy.HttpsHandlers, FuncHttpsHandler(func(host string, ctx *ProxyCtx) (*ConnectAction, string) { for _, cond := range pcond.reqConds { if !cond.HandleReq(ctx.Req, ctx) { @@ -285,7 +285,7 @@ func (pcond *ProxyConds) DoFunc(f func(resp *http.Response, ctx *ProxyCtx) *http // ProxyConds.Do will register the RespHandler on the proxy, h.Handle(resp,ctx) will be called on every // request that matches the conditions aggregated in pcond. func (pcond *ProxyConds) Do(h RespHandler) { - pcond.proxy.respHandlers = append(pcond.proxy.respHandlers, + pcond.proxy.RespHandlers = append(pcond.proxy.RespHandlers, FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response { for _, cond := range pcond.reqConds { if !cond.HandleReq(ctx.Req, ctx) { diff --git a/https.go b/https.go index 6fcf17a9..8689db9e 100644 --- a/https.go +++ b/https.go @@ -89,9 +89,9 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request panic("Cannot hijack connection " + e.Error()) } - ctx.Logf("Running %d CONNECT handlers", len(proxy.httpsHandlers)) + ctx.Logf("Running %d CONNECT handlers", len(proxy.HttpsHandlers)) todo, host := OkConnect, r.URL.Host - for i, h := range proxy.httpsHandlers { + for i, h := range proxy.HttpsHandlers { newtodo, newhost := h.HandleConnect(host, ctx) // If found a result, break the loop immediately diff --git a/proxy.go b/proxy.go index cac3f889..f2f611b7 100644 --- a/proxy.go +++ b/proxy.go @@ -22,9 +22,9 @@ type ProxyHttpServer struct { Verbose bool Logger Logger NonproxyHandler http.Handler - reqHandlers []ReqHandler - respHandlers []RespHandler - httpsHandlers []HttpsHandler + ReqHandlers []ReqHandler + RespHandlers []RespHandler + HttpsHandlers []HttpsHandler Tr *http.Transport // ConnectDial will be used to create TCP connections for CONNECT requests // if nil Tr.Dial will be used @@ -58,7 +58,7 @@ func isEof(r *bufio.Reader) bool { func (proxy *ProxyHttpServer) filterRequest(r *http.Request, ctx *ProxyCtx) (req *http.Request, resp *http.Response) { req = r - for _, h := range proxy.reqHandlers { + for _, h := range proxy.ReqHandlers { req, resp = h.Handle(r, ctx) // non-nil resp means the handler decided to skip sending the request // and return canned response instead. @@ -70,7 +70,7 @@ func (proxy *ProxyHttpServer) filterRequest(r *http.Request, ctx *ProxyCtx) (req } func (proxy *ProxyHttpServer) filterResponse(respOrig *http.Response, ctx *ProxyCtx) (resp *http.Response) { resp = respOrig - for _, h := range proxy.respHandlers { + for _, h := range proxy.RespHandlers { ctx.Resp = resp resp = h.Handle(resp, ctx) } @@ -189,9 +189,9 @@ func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) func NewProxyHttpServer() *ProxyHttpServer { proxy := ProxyHttpServer{ Logger: log.New(os.Stderr, "", log.LstdFlags), - reqHandlers: []ReqHandler{}, - respHandlers: []RespHandler{}, - httpsHandlers: []HttpsHandler{}, + ReqHandlers: []ReqHandler{}, + RespHandlers: []RespHandler{}, + HttpsHandlers: []HttpsHandler{}, NonproxyHandler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { http.Error(w, "This is a proxy server. Does not respond to non-proxy requests.", 500) }), From 881d8411c11c54fbdafbc1efba5b019632677e51 Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Mon, 31 Jan 2022 17:24:53 +0100 Subject: [PATCH 2/2] refactor: use a pointer to slice for Req/Rep/Https This permit to update content without edgecases Signed-off-by: Guilhem Lettron --- dispatcher.go | 8 ++++---- https.go | 4 ++-- proxy.go | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/dispatcher.go b/dispatcher.go index cc0c1009..bf51b504 100644 --- a/dispatcher.go +++ b/dispatcher.go @@ -206,7 +206,7 @@ func (pcond *ReqProxyConds) DoFunc(f func(req *http.Request, ctx *ProxyCtx) (*ht // // given request to the proxy, will test if cond1.HandleReq(req,ctx) && cond2.HandleReq(req,ctx) are true // // if they are, will call handler.Handle(req,ctx) func (pcond *ReqProxyConds) Do(h ReqHandler) { - pcond.proxy.ReqHandlers = append(pcond.proxy.ReqHandlers, + *pcond.proxy.ReqHandlers = append(*pcond.proxy.ReqHandlers, FuncReqHandler(func(r *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response) { for _, cond := range pcond.reqConds { if !cond.HandleReq(r, ctx) { @@ -229,7 +229,7 @@ func (pcond *ReqProxyConds) Do(h ReqHandler) { // will use the default tls configuration. // proxy.OnRequest().HandleConnect(goproxy.AlwaysReject) // rejects all CONNECT requests func (pcond *ReqProxyConds) HandleConnect(h HttpsHandler) { - pcond.proxy.HttpsHandlers = append(pcond.proxy.HttpsHandlers, + *pcond.proxy.HttpsHandlers = append(*pcond.proxy.HttpsHandlers, FuncHttpsHandler(func(host string, ctx *ProxyCtx) (*ConnectAction, string) { for _, cond := range pcond.reqConds { if !cond.HandleReq(ctx.Req, ctx) { @@ -257,7 +257,7 @@ func (pcond *ReqProxyConds) HandleConnectFunc(f func(host string, ctx *ProxyCtx) } func (pcond *ReqProxyConds) HijackConnect(f func(req *http.Request, client net.Conn, ctx *ProxyCtx)) { - pcond.proxy.HttpsHandlers = append(pcond.proxy.HttpsHandlers, + *pcond.proxy.HttpsHandlers = append(*pcond.proxy.HttpsHandlers, FuncHttpsHandler(func(host string, ctx *ProxyCtx) (*ConnectAction, string) { for _, cond := range pcond.reqConds { if !cond.HandleReq(ctx.Req, ctx) { @@ -285,7 +285,7 @@ func (pcond *ProxyConds) DoFunc(f func(resp *http.Response, ctx *ProxyCtx) *http // ProxyConds.Do will register the RespHandler on the proxy, h.Handle(resp,ctx) will be called on every // request that matches the conditions aggregated in pcond. func (pcond *ProxyConds) Do(h RespHandler) { - pcond.proxy.RespHandlers = append(pcond.proxy.RespHandlers, + *pcond.proxy.RespHandlers = append(*pcond.proxy.RespHandlers, FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response { for _, cond := range pcond.reqConds { if !cond.HandleReq(ctx.Req, ctx) { diff --git a/https.go b/https.go index 8689db9e..cf5d0c8f 100644 --- a/https.go +++ b/https.go @@ -89,9 +89,9 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request panic("Cannot hijack connection " + e.Error()) } - ctx.Logf("Running %d CONNECT handlers", len(proxy.HttpsHandlers)) + ctx.Logf("Running %d CONNECT handlers", len(*proxy.HttpsHandlers)) todo, host := OkConnect, r.URL.Host - for i, h := range proxy.HttpsHandlers { + for i, h := range *proxy.HttpsHandlers { newtodo, newhost := h.HandleConnect(host, ctx) // If found a result, break the loop immediately diff --git a/proxy.go b/proxy.go index f2f611b7..8b4b46f8 100644 --- a/proxy.go +++ b/proxy.go @@ -22,9 +22,9 @@ type ProxyHttpServer struct { Verbose bool Logger Logger NonproxyHandler http.Handler - ReqHandlers []ReqHandler - RespHandlers []RespHandler - HttpsHandlers []HttpsHandler + ReqHandlers *[]ReqHandler + RespHandlers *[]RespHandler + HttpsHandlers *[]HttpsHandler Tr *http.Transport // ConnectDial will be used to create TCP connections for CONNECT requests // if nil Tr.Dial will be used @@ -58,7 +58,7 @@ func isEof(r *bufio.Reader) bool { func (proxy *ProxyHttpServer) filterRequest(r *http.Request, ctx *ProxyCtx) (req *http.Request, resp *http.Response) { req = r - for _, h := range proxy.ReqHandlers { + for _, h := range *proxy.ReqHandlers { req, resp = h.Handle(r, ctx) // non-nil resp means the handler decided to skip sending the request // and return canned response instead. @@ -70,7 +70,7 @@ func (proxy *ProxyHttpServer) filterRequest(r *http.Request, ctx *ProxyCtx) (req } func (proxy *ProxyHttpServer) filterResponse(respOrig *http.Response, ctx *ProxyCtx) (resp *http.Response) { resp = respOrig - for _, h := range proxy.RespHandlers { + for _, h := range *proxy.RespHandlers { ctx.Resp = resp resp = h.Handle(resp, ctx) } @@ -189,9 +189,9 @@ func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) func NewProxyHttpServer() *ProxyHttpServer { proxy := ProxyHttpServer{ Logger: log.New(os.Stderr, "", log.LstdFlags), - ReqHandlers: []ReqHandler{}, - RespHandlers: []RespHandler{}, - HttpsHandlers: []HttpsHandler{}, + ReqHandlers: &[]ReqHandler{}, + RespHandlers: &[]RespHandler{}, + HttpsHandlers: &[]HttpsHandler{}, NonproxyHandler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { http.Error(w, "This is a proxy server. Does not respond to non-proxy requests.", 500) }),