From 2edb81edbb53e502fa5ca621e7e7d94b136a8771 Mon Sep 17 00:00:00 2001 From: rekby Date: Sat, 9 Apr 2022 14:58:00 +0300 Subject: [PATCH] Fix redirect double slash --- internal/proxy/http-proxy.go | 4 +- internal/proxy/http-proxy_test.go | 61 ++++++++++++++++++++++++++++++- internal/th/fixenv.go | 4 +- internal/th/fixtures.go | 35 ++++++++++++++++++ 4 files changed, 98 insertions(+), 6 deletions(-) diff --git a/internal/proxy/http-proxy.go b/internal/proxy/http-proxy.go index 469e6163..ac32429c 100644 --- a/internal/proxy/http-proxy.go +++ b/internal/proxy/http-proxy.go @@ -71,13 +71,11 @@ func (p *HTTPProxy) Start() error { } p.logger.Info("Access log", zap.Bool("enabled", p.EnableAccessLog)) - mux := &http.ServeMux{} - mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { + p.httpServer.Handler = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { if !p.HandleHTTPValidation(writer, request) { p.httpReverseProxy.ServeHTTP(writer, request) } }) - p.httpServer.Handler = mux p.httpServer.IdleTimeout = p.IdleTimeout p.logger.Info("Http builtin reverse proxy start") diff --git a/internal/proxy/http-proxy_test.go b/internal/proxy/http-proxy_test.go index 62e47b38..1bdcc792 100644 --- a/internal/proxy/http-proxy_test.go +++ b/internal/proxy/http-proxy_test.go @@ -10,11 +10,13 @@ import ( "net/url" "strings" "testing" + "time" "github.com/gojuno/minimock/v3" - "github.com/maxatome/go-testdeep" + "github.com/rekby/fixenv" zc "github.com/rekby/zapcontext" + "golang.org/x/xerrors" "github.com/rekby/lets-proxy2/internal/th" ) @@ -141,3 +143,60 @@ func TestNewHttpProxy(t *testing.T) { td.CmpNoError(err) td.CmpDeeply(res, []byte{3, 4}) } + +func TestNoDoubleSlashredirectIssue177(t *testing.T) { + e, _, flush := th.NewEnv(t) + defer flush() + + _, addr := httpProxy(e, th.HttpQuery(e)) + + client := http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + resp, err := client.Get(addr + "/test//") + e.CmpNoError(err) + + body, err := ioutil.ReadAll(resp.Body) + e.CmpNoError(err) + e.CmpNoError(resp.Body.Close()) + + e.Cmp(string(body), "/test//") +} + +func httpProxy(e *th.Env, dst string) (*HTTPProxy, string) { + var proxy *HTTPProxy + var addr string + e.Cache(dst, + &fixenv.FixtureOptions{ + CleanupFunc: func() { + _ = proxy.Close() + }, + }, func() (res interface{}, err error) { + dstURL, err := url.Parse(dst) + if err != nil { + return nil, xerrors.Errorf("failed parse dst url %q: %%w", dst, err) + } + listener := th.TcpListener(e) + addr = "http://" + listener.Addr().String() + proxy = NewHTTPProxy(e.Ctx, listener) + proxy.Director = NewDirectorChain( + DirectorHost(dstURL.Host), + DirectorSetScheme(dstURL.Scheme), + ) + errChan := make(chan error, 1) + + go func() { errChan <- proxy.Start() }() + + select { + case proxyStartErr := <-errChan: + err = proxyStartErr + case <-time.After(time.Millisecond * 10): + // pass + } + + return proxy, err + }) + return proxy, addr +} diff --git a/internal/th/fixenv.go b/internal/th/fixenv.go index cbcbc4b0..3d787980 100644 --- a/internal/th/fixenv.go +++ b/internal/th/fixenv.go @@ -11,7 +11,7 @@ import ( ) type Env struct { - ctx context.Context + Ctx context.Context *fixenv.EnvT TD } @@ -22,7 +22,7 @@ func NewEnv(t *testing.T) (env *Env, ctx context.Context, cancel func()) { tWrap := &testWrapper{T: td} env = &Env{ EnvT: fixenv.NewEnv(tWrap), - ctx: ctx, + Ctx: ctx, TD: TD{T: td}, } tWrap.Cleanup(ctxCancel) diff --git a/internal/th/fixtures.go b/internal/th/fixtures.go index cda7e130..6c0c6ef0 100644 --- a/internal/th/fixtures.go +++ b/internal/th/fixtures.go @@ -2,11 +2,46 @@ package th import ( "io/ioutil" + "net" + "net/http" + "net/http/httptest" "os" "github.com/rekby/fixenv" ) +func HttpQuery(e fixenv.Env) string { + var server *httptest.Server + return e.Cache(nil, + &fixenv.FixtureOptions{ + CleanupFunc: func() { + server.Close() + }, + }, func() (res interface{}, err error) { + server = httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + u := *request.URL + u.Scheme = "" + u.Host = "" + _, _ = writer.Write([]byte(u.String())) + })) + return server.URL, nil + }).(string) +} + +func TcpListener(e fixenv.Env) *net.TCPListener { + var listener *net.TCPListener + + return e.Cache(nil, + &fixenv.FixtureOptions{ + CleanupFunc: func() { + _ = listener.Close() + }}, + func() (res interface{}, err error) { + listener, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)}) + return listener, err + }).(*net.TCPListener) +} + func TmpDir(e fixenv.Env) string { var dirPath string return e.Cache(nil, &fixenv.FixtureOptions{CleanupFunc: func() {