浏览代码

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 年之前
父节点
当前提交
84b2162c1a
共有 1 个文件被更改,包括 40 次插入5 次删除
  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