Skip to content
This repository was archived by the owner on Oct 25, 2018. It is now read-only.

Commit 7b0d822

Browse files
committed
Unlock mutex on response.Body.Close()
1 parent b8abc63 commit 7b0d822

File tree

1 file changed

+38
-3
lines changed

1 file changed

+38
-3
lines changed

fleet/ssh.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package fleet
22

33
import (
44
"fmt"
5+
"io"
56
"net"
67
"net/http"
78
"net/url"
@@ -118,8 +119,42 @@ func (t *sshTunnel) NewHostKeyChecker() *ssh.HostKeyChecker {
118119
// simply a synchronized wrapper to the underlying http.Transport.
119120
func (t *sshTunnel) RoundTrip(req *http.Request) (*http.Response, error) {
120121
t.Mutex.Lock()
121-
defer t.Mutex.Unlock()
122122

123-
fmt.Printf("req.URL.Path: %#v\n", req.URL.Path)
124-
return t.HTTPTransport.RoundTrip(req)
123+
fmt.Printf("req.URL.Path: %#v?%s\n", req.URL.Path, req.URL.Query().Encode())
124+
resp, err := t.HTTPTransport.RoundTrip(req)
125+
126+
/**
127+
Learning:
128+
129+
The fleet ssh tunnel does not support (for unknown reasons) more than one
130+
command-session in parallel. Just adding a mutex here does not 100% help,
131+
as the connection is only returned to the idle pool when the body gets closed.
132+
If multiple go routines try to call RoundTrip() the first one performs the request,
133+
then return the response. Then the second goroutine would start calling its
134+
request and since the initial connection is not yet closed would try to open a second
135+
connection which would fail with "forward request denied".
136+
137+
Thus we only unlock the mutex when the body of the response has been closed.
138+
This ensures the connection has been returned to the pool.
139+
**/
140+
resp.Body = &synchronousReadCloser{
141+
body: resp.Body,
142+
mutex: &t.Mutex,
143+
}
144+
145+
return resp, err
146+
}
147+
148+
type synchronousReadCloser struct {
149+
body io.ReadCloser
150+
mutex *sync.Mutex
151+
}
152+
153+
func (s *synchronousReadCloser) Read(p []byte) (n int, err error) {
154+
return s.body.Read(p)
155+
}
156+
157+
func (s *synchronousReadCloser) Close() error {
158+
defer s.mutex.Unlock()
159+
return s.body.Close()
125160
}

0 commit comments

Comments
 (0)