From 4cfa24440d642b3545095510771ade0d57797231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Matczuk?= Date: Wed, 9 Nov 2022 10:35:37 +0100 Subject: [PATCH] proxy: move handleHttp function to a dedicated file http.go This is for parity with HTTPS and the handleHttps function. --- http.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ proxy.go | 79 ---------------------------------------------------- 2 files changed, 85 insertions(+), 79 deletions(-) create mode 100644 http.go diff --git a/http.go b/http.go new file mode 100644 index 00000000..400219f3 --- /dev/null +++ b/http.go @@ -0,0 +1,85 @@ +package goproxy + +import ( + "io" + "net/http" + "sync/atomic" +) + +func (proxy *ProxyHttpServer) handleHttp(w http.ResponseWriter, r *http.Request) { + ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), Proxy: proxy} + + var err error + ctx.Logf("Got request %v %v %v %v", r.URL.Path, r.Host, r.Method, r.URL.String()) + if !r.URL.IsAbs() { + proxy.NonproxyHandler.ServeHTTP(w, r) + return + } + r, resp := proxy.filterRequest(r, ctx) + + if resp == nil { + if isWebSocketRequest(r) { + ctx.Logf("Request looks like websocket upgrade.") + proxy.serveWebsocket(ctx, w, r) + } + + if !proxy.KeepHeader { + removeProxyHeaders(ctx, r) + } + resp, err = ctx.RoundTrip(r) + if err != nil { + ctx.Error = err + resp = proxy.filterResponse(nil, ctx) + + } + if resp != nil { + ctx.Logf("Received response %v", resp.Status) + } + } + + var origBody io.ReadCloser + + if resp != nil { + origBody = resp.Body + defer origBody.Close() + } + + resp = proxy.filterResponse(resp, ctx) + + if resp == nil { + var errorString string + if ctx.Error != nil { + errorString = "error read response " + r.URL.Host + " : " + ctx.Error.Error() + ctx.Logf(errorString) + http.Error(w, ctx.Error.Error(), 500) + } else { + errorString = "error read response " + r.URL.Host + ctx.Logf(errorString) + http.Error(w, errorString, 500) + } + return + } + ctx.Logf("Copying response to client %v [%d]", resp.Status, resp.StatusCode) + // http.ResponseWriter will take care of filling the correct response length + // Setting it now, might impose wrong value, contradicting the actual new + // body the user returned. + // We keep the original body to remove the header only if things changed. + // This will prevent problems with HEAD requests where there's no body, yet, + // the Content-Length header should be set. + if origBody != resp.Body { + resp.Header.Del("Content-Length") + } + copyHeaders(w.Header(), resp.Header, proxy.KeepDestinationHeaders) + w.WriteHeader(resp.StatusCode) + var copyWriter io.Writer = w + if w.Header().Get("content-type") == "text/event-stream" { + // server-side events, flush the buffered data to the client. + copyWriter = &flushWriter{w: w} + } + + nr, err := io.Copy(copyWriter, resp.Body) + if err := resp.Body.Close(); err != nil { + ctx.Warnf("Can't close response body %v", err) + } + ctx.Logf("Copied %v bytes to client error=%v", nr, err) +} diff --git a/proxy.go b/proxy.go index c9273b11..fe096ca3 100644 --- a/proxy.go +++ b/proxy.go @@ -8,7 +8,6 @@ import ( "net/http" "os" "regexp" - "sync/atomic" ) // The basic proxy type. Implements http.Handler. @@ -132,84 +131,6 @@ func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) } } -func (proxy *ProxyHttpServer) handleHttp(w http.ResponseWriter, r *http.Request) { - ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), Proxy: proxy} - - var err error - ctx.Logf("Got request %v %v %v %v", r.URL.Path, r.Host, r.Method, r.URL.String()) - if !r.URL.IsAbs() { - proxy.NonproxyHandler.ServeHTTP(w, r) - return - } - r, resp := proxy.filterRequest(r, ctx) - - if resp == nil { - if isWebSocketRequest(r) { - ctx.Logf("Request looks like websocket upgrade.") - proxy.serveWebsocket(ctx, w, r) - } - - if !proxy.KeepHeader { - removeProxyHeaders(ctx, r) - } - resp, err = ctx.RoundTrip(r) - if err != nil { - ctx.Error = err - resp = proxy.filterResponse(nil, ctx) - - } - if resp != nil { - ctx.Logf("Received response %v", resp.Status) - } - } - - var origBody io.ReadCloser - - if resp != nil { - origBody = resp.Body - defer origBody.Close() - } - - resp = proxy.filterResponse(resp, ctx) - - if resp == nil { - var errorString string - if ctx.Error != nil { - errorString = "error read response " + r.URL.Host + " : " + ctx.Error.Error() - ctx.Logf(errorString) - http.Error(w, ctx.Error.Error(), 500) - } else { - errorString = "error read response " + r.URL.Host - ctx.Logf(errorString) - http.Error(w, errorString, 500) - } - return - } - ctx.Logf("Copying response to client %v [%d]", resp.Status, resp.StatusCode) - // http.ResponseWriter will take care of filling the correct response length - // Setting it now, might impose wrong value, contradicting the actual new - // body the user returned. - // We keep the original body to remove the header only if things changed. - // This will prevent problems with HEAD requests where there's no body, yet, - // the Content-Length header should be set. - if origBody != resp.Body { - resp.Header.Del("Content-Length") - } - copyHeaders(w.Header(), resp.Header, proxy.KeepDestinationHeaders) - w.WriteHeader(resp.StatusCode) - var copyWriter io.Writer = w - if w.Header().Get("content-type") == "text/event-stream" { - // server-side events, flush the buffered data to the client. - copyWriter = &flushWriter{w: w} - } - - nr, err := io.Copy(copyWriter, resp.Body) - if err := resp.Body.Close(); err != nil { - ctx.Warnf("Can't close response body %v", err) - } - ctx.Logf("Copied %v bytes to client error=%v", nr, err) -} - // NewProxyHttpServer creates and returns a proxy server, logging to stderr by default func NewProxyHttpServer() *ProxyHttpServer { proxy := ProxyHttpServer{