From c55dec6bc451ff4d5ed004e3fda07762b09055b5 Mon Sep 17 00:00:00 2001 From: Adrien PONSIN Date: Thu, 17 Apr 2025 18:41:32 +0200 Subject: [PATCH] use a sync.Pool to reuse connexions --- command/serve.go | 75 +++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/command/serve.go b/command/serve.go index 8fa245e..06adb8f 100644 --- a/command/serve.go +++ b/command/serve.go @@ -17,6 +17,7 @@ import ( "regexp" "slices" "strings" + "sync" "time" ) @@ -35,25 +36,8 @@ type methodRegex = map[string]*regexp.Regexp // ProxyHandler takes an incoming request and sends it to another server, proxying the response back to the client. type ProxyHandler struct { - rp *httputil.ReverseProxy -} - -// ErrHTTPMethodNotAllowed is returned if the request's HTTP method is not allowed for this container. -type ErrHTTPMethodNotAllowed struct { - httpMethod string -} - -// ErrNoMatch is returned if the request's URL path is not allowed for this container. -type ErrNoMatch struct { - path, httpMethod string -} - -func (e ErrHTTPMethodNotAllowed) Error() string { - return fmt.Sprintf("%s is not in the list of HTTP methods allowed this container", e.httpMethod) -} - -func (e ErrNoMatch) Error() string { - return fmt.Sprintf("%s does not match any registered regular expression for this HTTP method (%s)", e.path, e.httpMethod) + rp *httputil.ReverseProxy + connPool *sync.Pool } // ServeCmd is the command name. @@ -155,7 +139,7 @@ func (ph *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.Error(w, http.StatusText(code), code) return } - ph.rp.ServeHTTP(w, r) + ph.proxyRequest(w, r) return } host, _, _ := net.SplitHostPort(r.RemoteAddr) @@ -165,32 +149,21 @@ func (ph *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.Error(w, http.StatusText(code), code) return } - ph.rp.ServeHTTP(w, r) + ph.proxyRequest(w, r) return } } - /* - for containerName, mr = range containerMethodRegex { - resolvedIPs, err := net.LookupIP(containerName) - if err != nil { - continue - } - for _, resolvedIP := range resolvedIPs { - if resolvedIP.Equal(net.ParseIP(host)) { - if code := ph.checkMethodAndRegex(mr, r, containerName); code != http.StatusOK { - http.Error(w, http.StatusText(code), code) - return - } - ph.rp.ServeHTTP(w, r) - return - } - } - } - */ logDeniedRequest(r, http.StatusUnauthorized, "this container is not on the list of authorized ones") http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) } +func (ph *ProxyHandler) proxyRequest(w http.ResponseWriter, r *http.Request) { + transport := ph.connPool.Get().(*http.Transport) + defer ph.connPool.Put(transport) + ph.rp.Transport = transport + ph.rp.ServeHTTP(w, r) +} + func (ph *ProxyHandler) isContainerAuthorized(containerName, host string) bool { resolvedIPs, err := net.LookupIP(containerName) if err != nil { @@ -253,15 +226,33 @@ func (s serve) action(ctx context.Context, command *cli.Command) error { return err } dummyURL, _ := url.Parse("http://dummy") - rp := httputil.NewSingleHostReverseProxy(dummyURL) - rp.Transport = &http.Transport{ + /* + rp := httputil.NewSingleHostReverseProxy(dummyURL) + rp.Transport = &http.Transport{ + DialContext: func(_ context.Context, _ string, _ string) (net.Conn, error) { + return net.Dial("unix", command.String(dockerSocketPathFlagName)) + }, + MaxIdleConns: 10, + } + */ + transport := &http.Transport{ DialContext: func(_ context.Context, _ string, _ string) (net.Conn, error) { return net.Dial("unix", command.String(dockerSocketPathFlagName)) }, + MaxIdleConns: 10, + } + ph := &ProxyHandler{ + rp: httputil.NewSingleHostReverseProxy(dummyURL), + connPool: &sync.Pool{ + New: func() any { + return transport.Clone() + }, + }, } srv := &http.Server{ // #nosec: G112 - Handler: &ProxyHandler{rp: rp}, + Handler: ph, } + ph.rp.Transport = ph.connPool.Get().(*http.Transport) s.group.Go(func() error { if err = srv.Serve(l); err != nil && !errors.Is(err, http.ErrServerClosed) { return err