Ensure a hijacked connection implements CloseWrite whenever its underlying
connection does.  If this isn't done, then a container listening on stdin won't
receive an EOF when the client closes the stream at their end.
@@ -188,8 +188,14 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (net.Conn, e
c, br := clientconn.Hijack()
if br.Buffered() > 0 {
- // If there is buffered content, wrap the connection
+ // If there is buffered content, wrap the connection. We return an
+ // object that implements CloseWrite iff the underlying connection
+ // implements it.
+ if _, ok := c.(types.CloseWriter); ok {
+ c = &hijackedConnCloseWriter{c, br}
+ } else {
c = &hijackedConn{c, br}
+ }
} else {
br.Reset(nil)
}
@@ -197,6 +203,10 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (net.Conn, e
return c, nil
}
+// hijackedConn wraps a net.Conn and is returned by setupHijackConn in the case
+// that a) there was already buffered data in the http layer when Hijack() was
+// called, and b) the underlying net.Conn does *not* implement CloseWrite().
+// hijackedConn does not implement CloseWrite() either.
type hijackedConn struct {
net.Conn
r *bufio.Reader
@@ -205,3 +215,16 @@ type hijackedConn struct {
func (c *hijackedConn) Read(b []byte) (int, error) {
return c.r.Read(b)
}
+
+// hijackedConnCloseWriter is a hijackedConn which additionally implements
+// CloseWrite(). It is returned by setupHijackConn in the case that a) there
+// was already buffered data in the http layer when Hijack() was called, and b)
+// the underlying net.Conn *does* implement CloseWrite().
+type hijackedConnCloseWriter hijackedConn
+
+var _ types.CloseWriter = &hijackedConnCloseWriter{}
+
+func (c *hijackedConnCloseWriter) CloseWrite() error {
+ conn := c.Conn.(types.CloseWriter)
+ return conn.CloseWrite()
+}
