Fix docker/docker#27539
After io.Copy(to, from), we should call to.CloseWrite(), not to.CloseRead().
Without this fix, TestTCP4ProxyHalfClose (newly added in this commit) fails as
follows:
--- FAIL: TestTCP4ProxyHalfClose (0.00s)
network_proxy_test.go:135: EOF
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"flag" |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"io" |
| 8 |
+ "io/ioutil" |
|
| 8 | 9 |
"net" |
| 9 | 10 |
"strings" |
| 10 | 11 |
"testing" |
| ... | ... |
@@ -22,9 +23,14 @@ type EchoServer interface {
|
| 22 | 22 |
LocalAddr() net.Addr |
| 23 | 23 |
} |
| 24 | 24 |
|
| 25 |
+type EchoServerOptions struct {
|
|
| 26 |
+ TCPHalfClose bool |
|
| 27 |
+} |
|
| 28 |
+ |
|
| 25 | 29 |
type TCPEchoServer struct {
|
| 26 | 30 |
listener net.Listener |
| 27 | 31 |
testCtx *testing.T |
| 32 |
+ opts EchoServerOptions |
|
| 28 | 33 |
} |
| 29 | 34 |
|
| 30 | 35 |
type UDPEchoServer struct {
|
| ... | ... |
@@ -32,15 +38,18 @@ type UDPEchoServer struct {
|
| 32 | 32 |
testCtx *testing.T |
| 33 | 33 |
} |
| 34 | 34 |
|
| 35 |
-func NewEchoServer(t *testing.T, proto, address string) EchoServer {
|
|
| 35 |
+func NewEchoServer(t *testing.T, proto, address string, opts EchoServerOptions) EchoServer {
|
|
| 36 | 36 |
var server EchoServer |
| 37 | 37 |
if strings.HasPrefix(proto, "tcp") {
|
| 38 | 38 |
listener, err := net.Listen(proto, address) |
| 39 | 39 |
if err != nil {
|
| 40 | 40 |
t.Fatal(err) |
| 41 | 41 |
} |
| 42 |
- server = &TCPEchoServer{listener: listener, testCtx: t}
|
|
| 42 |
+ server = &TCPEchoServer{listener: listener, testCtx: t, opts: opts}
|
|
| 43 | 43 |
} else {
|
| 44 |
+ if opts.TCPHalfClose {
|
|
| 45 |
+ t.Fatalf("TCPHalfClose is not supported for %s", proto)
|
|
| 46 |
+ } |
|
| 44 | 47 |
socket, err := net.ListenPacket(proto, address) |
| 45 | 48 |
if err != nil {
|
| 46 | 49 |
t.Fatal(err) |
| ... | ... |
@@ -58,10 +67,21 @@ func (server *TCPEchoServer) Run() {
|
| 58 | 58 |
return |
| 59 | 59 |
} |
| 60 | 60 |
go func(client net.Conn) {
|
| 61 |
- if _, err := io.Copy(client, client); err != nil {
|
|
| 62 |
- server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
|
|
| 61 |
+ if server.opts.TCPHalfClose {
|
|
| 62 |
+ data, err := ioutil.ReadAll(client) |
|
| 63 |
+ if err != nil {
|
|
| 64 |
+ server.testCtx.Logf("io.ReadAll() failed for the client: %v\n", err.Error())
|
|
| 65 |
+ } |
|
| 66 |
+ if _, err := client.Write(data); err != nil {
|
|
| 67 |
+ server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
|
|
| 68 |
+ } |
|
| 69 |
+ client.(*net.TCPConn).CloseWrite() |
|
| 70 |
+ } else {
|
|
| 71 |
+ if _, err := io.Copy(client, client); err != nil {
|
|
| 72 |
+ server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
|
|
| 73 |
+ } |
|
| 74 |
+ client.Close() |
|
| 63 | 75 |
} |
| 64 |
- client.Close() |
|
| 65 | 76 |
}(client) |
| 66 | 77 |
} |
| 67 | 78 |
}() |
| ... | ... |
@@ -92,7 +112,7 @@ func (server *UDPEchoServer) Run() {
|
| 92 | 92 |
func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() }
|
| 93 | 93 |
func (server *UDPEchoServer) Close() { server.conn.Close() }
|
| 94 | 94 |
|
| 95 |
-func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) {
|
|
| 95 |
+func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string, halfClose bool) {
|
|
| 96 | 96 |
defer proxy.Close() |
| 97 | 97 |
go proxy.Run() |
| 98 | 98 |
client, err := net.Dial(proto, addr) |
| ... | ... |
@@ -104,6 +124,12 @@ func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) {
|
| 104 | 104 |
if _, err = client.Write(testBuf); err != nil {
|
| 105 | 105 |
t.Fatal(err) |
| 106 | 106 |
} |
| 107 |
+ if halfClose {
|
|
| 108 |
+ if proto != "tcp" {
|
|
| 109 |
+ t.Fatalf("halfClose is not supported for %s", proto)
|
|
| 110 |
+ } |
|
| 111 |
+ client.(*net.TCPConn).CloseWrite() |
|
| 112 |
+ } |
|
| 107 | 113 |
recvBuf := make([]byte, testBufSize) |
| 108 | 114 |
if _, err = client.Read(recvBuf); err != nil {
|
| 109 | 115 |
t.Fatal(err) |
| ... | ... |
@@ -113,12 +139,12 @@ func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) {
|
| 113 | 113 |
} |
| 114 | 114 |
} |
| 115 | 115 |
|
| 116 |
-func testProxy(t *testing.T, proto string, proxy Proxy) {
|
|
| 117 |
- testProxyAt(t, proto, proxy, proxy.FrontendAddr().String()) |
|
| 116 |
+func testProxy(t *testing.T, proto string, proxy Proxy, halfClose bool) {
|
|
| 117 |
+ testProxyAt(t, proto, proxy, proxy.FrontendAddr().String(), halfClose) |
|
| 118 | 118 |
} |
| 119 | 119 |
|
| 120 |
-func TestTCP4Proxy(t *testing.T) {
|
|
| 121 |
- backend := NewEchoServer(t, "tcp", "127.0.0.1:0") |
|
| 120 |
+func testTCP4Proxy(t *testing.T, halfClose bool) {
|
|
| 121 |
+ backend := NewEchoServer(t, "tcp", "127.0.0.1:0", EchoServerOptions{TCPHalfClose: halfClose})
|
|
| 122 | 122 |
defer backend.Close() |
| 123 | 123 |
backend.Run() |
| 124 | 124 |
frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
|
| ... | ... |
@@ -126,12 +152,20 @@ func TestTCP4Proxy(t *testing.T) {
|
| 126 | 126 |
if err != nil {
|
| 127 | 127 |
t.Fatal(err) |
| 128 | 128 |
} |
| 129 |
- testProxy(t, "tcp", proxy) |
|
| 129 |
+ testProxy(t, "tcp", proxy, halfClose) |
|
| 130 |
+} |
|
| 131 |
+ |
|
| 132 |
+func TestTCP4Proxy(t *testing.T) {
|
|
| 133 |
+ testTCP4Proxy(t, false) |
|
| 134 |
+} |
|
| 135 |
+ |
|
| 136 |
+func TestTCP4ProxyHalfClose(t *testing.T) {
|
|
| 137 |
+ testTCP4Proxy(t, true) |
|
| 130 | 138 |
} |
| 131 | 139 |
|
| 132 | 140 |
func TestTCP6Proxy(t *testing.T) {
|
| 133 | 141 |
t.Skip("Need to start CI docker with --ipv6")
|
| 134 |
- backend := NewEchoServer(t, "tcp", "[::1]:0") |
|
| 142 |
+ backend := NewEchoServer(t, "tcp", "[::1]:0", EchoServerOptions{})
|
|
| 135 | 143 |
defer backend.Close() |
| 136 | 144 |
backend.Run() |
| 137 | 145 |
frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
|
| ... | ... |
@@ -139,14 +173,14 @@ func TestTCP6Proxy(t *testing.T) {
|
| 139 | 139 |
if err != nil {
|
| 140 | 140 |
t.Fatal(err) |
| 141 | 141 |
} |
| 142 |
- testProxy(t, "tcp", proxy) |
|
| 142 |
+ testProxy(t, "tcp", proxy, false) |
|
| 143 | 143 |
} |
| 144 | 144 |
|
| 145 | 145 |
func TestTCPDualStackProxy(t *testing.T) {
|
| 146 | 146 |
// If I understand `godoc -src net favoriteAddrFamily` (used by the |
| 147 | 147 |
// net.Listen* functions) correctly this should work, but it doesn't. |
| 148 | 148 |
t.Skip("No support for dual stack yet")
|
| 149 |
- backend := NewEchoServer(t, "tcp", "[::1]:0") |
|
| 149 |
+ backend := NewEchoServer(t, "tcp", "[::1]:0", EchoServerOptions{})
|
|
| 150 | 150 |
defer backend.Close() |
| 151 | 151 |
backend.Run() |
| 152 | 152 |
frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
|
| ... | ... |
@@ -158,11 +192,11 @@ func TestTCPDualStackProxy(t *testing.T) {
|
| 158 | 158 |
IP: net.IPv4(127, 0, 0, 1), |
| 159 | 159 |
Port: proxy.FrontendAddr().(*net.TCPAddr).Port, |
| 160 | 160 |
} |
| 161 |
- testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String()) |
|
| 161 |
+ testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String(), false) |
|
| 162 | 162 |
} |
| 163 | 163 |
|
| 164 | 164 |
func TestUDP4Proxy(t *testing.T) {
|
| 165 |
- backend := NewEchoServer(t, "udp", "127.0.0.1:0") |
|
| 165 |
+ backend := NewEchoServer(t, "udp", "127.0.0.1:0", EchoServerOptions{})
|
|
| 166 | 166 |
defer backend.Close() |
| 167 | 167 |
backend.Run() |
| 168 | 168 |
frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
|
| ... | ... |
@@ -170,12 +204,12 @@ func TestUDP4Proxy(t *testing.T) {
|
| 170 | 170 |
if err != nil {
|
| 171 | 171 |
t.Fatal(err) |
| 172 | 172 |
} |
| 173 |
- testProxy(t, "udp", proxy) |
|
| 173 |
+ testProxy(t, "udp", proxy, false) |
|
| 174 | 174 |
} |
| 175 | 175 |
|
| 176 | 176 |
func TestUDP6Proxy(t *testing.T) {
|
| 177 | 177 |
t.Skip("Need to start CI docker with --ipv6")
|
| 178 |
- backend := NewEchoServer(t, "udp", "[::1]:0") |
|
| 178 |
+ backend := NewEchoServer(t, "udp", "[::1]:0", EchoServerOptions{})
|
|
| 179 | 179 |
defer backend.Close() |
| 180 | 180 |
backend.Run() |
| 181 | 181 |
frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0}
|
| ... | ... |
@@ -183,7 +217,7 @@ func TestUDP6Proxy(t *testing.T) {
|
| 183 | 183 |
if err != nil {
|
| 184 | 184 |
t.Fatal(err) |
| 185 | 185 |
} |
| 186 |
- testProxy(t, "udp", proxy) |
|
| 186 |
+ testProxy(t, "udp", proxy, false) |
|
| 187 | 187 |
} |
| 188 | 188 |
|
| 189 | 189 |
func TestUDPWriteError(t *testing.T) {
|
| ... | ... |
@@ -204,7 +238,7 @@ func TestUDPWriteError(t *testing.T) {
|
| 204 | 204 |
// Make sure the proxy doesn't stop when there is no actual backend: |
| 205 | 205 |
client.Write(testBuf) |
| 206 | 206 |
client.Write(testBuf) |
| 207 |
- backend := NewEchoServer(t, "udp", "127.0.0.1:25587") |
|
| 207 |
+ backend := NewEchoServer(t, "udp", "127.0.0.1:25587", EchoServerOptions{})
|
|
| 208 | 208 |
defer backend.Close() |
| 209 | 209 |
backend.Run() |
| 210 | 210 |
client.SetDeadline(time.Now().Add(10 * time.Second)) |