diff --git a/api/chisel/service.go b/api/chisel/service.go index 9ef172589..374b7d075 100644 --- a/api/chisel/service.go +++ b/api/chisel/service.go @@ -21,6 +21,7 @@ const ( tunnelCleanupInterval = 10 * time.Second requiredTimeout = 15 * time.Second activeTimeout = 4*time.Minute + 30*time.Second + pingTimeout = 3 * time.Second ) // Service represents a service to manage the state of multiple reverse tunnels. @@ -59,14 +60,18 @@ func (service *Service) pingAgent(endpointID portainer.EndpointID) error { } httpClient := &http.Client{ - Timeout: 3 * time.Second, + Timeout: pingTimeout, } resp, err := httpClient.Do(req) + if err != nil { + return err + } + io.Copy(io.Discard, resp.Body) resp.Body.Close() - return err + return nil } // KeepTunnelAlive keeps the tunnel of the given environment for maxAlive duration, or until ctx is done diff --git a/api/chisel/service_test.go b/api/chisel/service_test.go new file mode 100644 index 000000000..884895a27 --- /dev/null +++ b/api/chisel/service_test.go @@ -0,0 +1,39 @@ +package chisel + +import ( + "net" + "net/http" + "testing" + "time" + + portainer "github.com/portainer/portainer/api" + + "github.com/stretchr/testify/require" +) + +func TestPingAgentPanic(t *testing.T) { + endpointID := portainer.EndpointID(1) + + s := NewService(nil, nil, nil) + + defer func() { + require.Nil(t, recover()) + }() + + mux := http.NewServeMux() + mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { + time.Sleep(pingTimeout + 1*time.Second) + }) + + ln, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}) + require.NoError(t, err) + + go func() { + require.NoError(t, http.Serve(ln, mux)) + }() + + s.getTunnelDetails(endpointID) + s.tunnelDetailsMap[endpointID].Port = ln.Addr().(*net.TCPAddr).Port + + require.Error(t, s.pingAgent(endpointID)) +}