Sfoglia il codice sorgente

Set idle timeouts for HTTP reads and writes in communications with the registry

Otherwise, some operations can get stuck indefinitely when the remote
side is unresponsive.

Fixes #12823

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
Aaron Lehmann 9 anni fa
parent
commit
84b2162c1a
1 ha cambiato i file con 40 aggiunte e 5 eliminazioni
  1. 40 5
      distribution/registry.go

+ 40 - 5
distribution/registry.go

@@ -45,6 +45,30 @@ func (dcs dumbCredentialStore) Basic(*url.URL) (string, string) {
 	return dcs.auth.Username, dcs.auth.Password
 }
 
+// conn wraps a net.Conn, and sets a deadline for every read
+// and write operation.
+type conn struct {
+	net.Conn
+	readTimeout  time.Duration
+	writeTimeout time.Duration
+}
+
+func (c *conn) Read(b []byte) (int, error) {
+	err := c.Conn.SetReadDeadline(time.Now().Add(c.readTimeout))
+	if err != nil {
+		return 0, err
+	}
+	return c.Conn.Read(b)
+}
+
+func (c *conn) Write(b []byte) (int, error) {
+	err := c.Conn.SetWriteDeadline(time.Now().Add(c.writeTimeout))
+	if err != nil {
+		return 0, err
+	}
+	return c.Conn.Write(b)
+}
+
 // NewV2Repository returns a repository (v2 only). It creates a HTTP transport
 // providing timeout settings and authentication support, and also verifies the
 // remote API version.
@@ -58,11 +82,22 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
 	// TODO(dmcgowan): Call close idle connections when complete, use keep alive
 	base := &http.Transport{
 		Proxy: http.ProxyFromEnvironment,
-		Dial: (&net.Dialer{
-			Timeout:   30 * time.Second,
-			KeepAlive: 30 * time.Second,
-			DualStack: true,
-		}).Dial,
+		Dial: func(network, address string) (net.Conn, error) {
+			dialer := &net.Dialer{
+				Timeout:   30 * time.Second,
+				KeepAlive: 30 * time.Second,
+				DualStack: true,
+			}
+			netConn, err := dialer.Dial(network, address)
+			if err != nil {
+				return netConn, err
+			}
+			return &conn{
+				Conn:         netConn,
+				readTimeout:  time.Minute,
+				writeTimeout: time.Minute,
+			}, nil
+		},
 		TLSHandshakeTimeout: 10 * time.Second,
 		TLSClientConfig:     endpoint.TLSConfig,
 		// TODO(dmcgowan): Call close idle connections when complete and use keep alive