Quellcode durchsuchen

Replace use of httputil in client hijack

Simplify the hijack process by just performing the http request/response
on the connection and returning the raw conn after success. The client
conn from httputil is deprecated and easily replaced.

Signed-off-by: Derek McGowan <derek@mcg.dev>
Derek McGowan vor 1 Jahr
Ursprung
Commit
bb4e9c72d7
1 geänderte Dateien mit 26 neuen und 20 gelöschten Zeilen
  1. 26 20
      client/hijack.go

+ 26 - 20
client/hijack.go

@@ -6,7 +6,6 @@ import (
 	"fmt"
 	"net"
 	"net/http"
-	"net/http/httputil"
 	"net/url"
 	"time"
 
@@ -81,6 +80,11 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (_ net.Conn,
 	if err != nil {
 		return nil, "", errors.Wrap(err, "cannot connect to the Docker daemon. Is 'docker daemon' running on this host?")
 	}
+	defer func() {
+		if retErr != nil {
+			conn.Close()
+		}
+	}()
 
 	// When we set up a TCP connection for hijack, there could be long periods
 	// of inactivity (a long running command with no output) that in certain
@@ -92,11 +96,10 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (_ net.Conn,
 		_ = tcpConn.SetKeepAlivePeriod(30 * time.Second)
 	}
 
-	clientconn := httputil.NewClientConn(conn, nil)
-	defer clientconn.Close()
+	hc := &hijackedConn{conn, bufio.NewReader(conn)}
 
 	// Server hijacks the connection, error 'connection closed' expected
-	resp, err := clientconn.Do(req)
+	resp, err := hc.RoundTrip(req)
 	if resp != nil {
 		// This is a simplified variant of "httpconv.ClientStatus(resp.StatusCode))";
 		//
@@ -121,29 +124,25 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (_ net.Conn,
 		span.SetStatus(code, "")
 	}
 
-	//nolint:staticcheck // ignore SA1019 for connecting to old (pre go1.8) daemons
-	if err != httputil.ErrPersistEOF {
-		if err != nil {
-			return nil, "", err
-		}
-		if resp.StatusCode != http.StatusSwitchingProtocols {
-			_ = resp.Body.Close()
-			return nil, "", fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
-		}
+	if err != nil {
+		return nil, "", err
+	}
+	if resp.StatusCode != http.StatusSwitchingProtocols {
+		_ = resp.Body.Close()
+		return nil, "", fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
 	}
 
-	c, br := clientconn.Hijack()
-	if br.Buffered() > 0 {
+	if hc.r.Buffered() > 0 {
 		// If there is buffered content, wrap the connection.  We return an
 		// object that implements CloseWrite if the underlying connection
 		// implements it.
-		if _, ok := c.(types.CloseWriter); ok {
-			c = &hijackedConnCloseWriter{&hijackedConn{c, br}}
+		if _, ok := hc.Conn.(types.CloseWriter); ok {
+			conn = &hijackedConnCloseWriter{hc}
 		} else {
-			c = &hijackedConn{c, br}
+			conn = hc
 		}
 	} else {
-		br.Reset(nil)
+		hc.r.Reset(nil)
 	}
 
 	var mediaType string
@@ -152,7 +151,7 @@ func (cli *Client) setupHijackConn(req *http.Request, proto string) (_ net.Conn,
 		mediaType = resp.Header.Get("Content-Type")
 	}
 
-	return c, mediaType, nil
+	return conn, mediaType, nil
 }
 
 // hijackedConn wraps a net.Conn and is returned by setupHijackConn in the case
@@ -164,6 +163,13 @@ type hijackedConn struct {
 	r *bufio.Reader
 }
 
+func (c *hijackedConn) RoundTrip(req *http.Request) (*http.Response, error) {
+	if err := req.Write(c.Conn); err != nil {
+		return nil, err
+	}
+	return http.ReadResponse(c.r, req)
+}
+
 func (c *hijackedConn) Read(b []byte) (int, error) {
 	return c.r.Read(b)
 }