aboutsummaryrefslogtreecommitdiff
path: root/src/net/error_test.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-04-07 15:53:19 -0700
committerIan Lance Taylor <iant@golang.org>2017-04-26 00:03:14 +0000
commitfb4b4342fe298fda640bfa74f24b7bd58519deba (patch)
treec7a059175bfb5630b432a5efe5d467abc59c2794 /src/net/error_test.go
parent2fb2ebc32ee37a66e3d6a77ff9450665153a604c (diff)
downloadgo-fb4b4342fe298fda640bfa74f24b7bd58519deba.tar.xz
os, net, internal/poll: return consistent error for closed socket
In the past we returned "use of closed network connection" when using a closed network descriptor in some way. In CL 36799 that was changed to return "use of closed file or network connection". Because programs have no access to a value of this error type (see issue #4373) they resort to doing direct string comparisons (see issue #19252). This CL restores the old error string so that we don't break programs unnecessarily with the 1.9 release. This adds a test to the net package for the expected string. For symmetry check that the os package returns the expected error, which for os already exists as os.ErrClosed. Updates #4373. Fixed #19252. Change-Id: I5b83fd12cfa03501a077cad9336499b819f4a38b Reviewed-on: https://go-review.googlesource.com/39997 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/net/error_test.go')
-rw-r--r--src/net/error_test.go35
1 files changed, 23 insertions, 12 deletions
diff --git a/src/net/error_test.go b/src/net/error_test.go
index 021968b079..9791e6fe4d 100644
--- a/src/net/error_test.go
+++ b/src/net/error_test.go
@@ -13,6 +13,7 @@ import (
"net/internal/socktest"
"os"
"runtime"
+ "strings"
"testing"
"time"
)
@@ -98,7 +99,7 @@ second:
goto third
}
switch nestedErr {
- case errCanceled, poll.ErrClosing, errMissingAddress, errNoSuitableAddress,
+ case errCanceled, poll.ErrNetClosing, errMissingAddress, errNoSuitableAddress,
context.DeadlineExceeded, context.Canceled:
return nil
}
@@ -433,7 +434,7 @@ second:
goto third
}
switch nestedErr {
- case poll.ErrClosing, poll.ErrTimeout:
+ case poll.ErrNetClosing, poll.ErrTimeout:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -475,7 +476,7 @@ second:
goto third
}
switch nestedErr {
- case errCanceled, poll.ErrClosing, errMissingAddress, poll.ErrTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
+ case errCanceled, poll.ErrNetClosing, errMissingAddress, poll.ErrTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -490,11 +491,21 @@ third:
// parseCloseError parses nestedErr and reports whether it is a valid
// error value from Close functions.
// It returns nil when nestedErr is valid.
-func parseCloseError(nestedErr error) error {
+func parseCloseError(nestedErr error, isShutdown bool) error {
if nestedErr == nil {
return nil
}
+ // Because historically we have not exported the error that we
+ // return for an operation on a closed network connection,
+ // there are programs that test for the exact error string.
+ // Verify that string here so that we don't break those
+ // programs unexpectedly. See issues #4373 and #19252.
+ want := "use of closed network connection"
+ if !isShutdown && !strings.Contains(nestedErr.Error(), want) {
+ return fmt.Errorf("error string %q does not contain expected string %q", nestedErr, want)
+ }
+
switch err := nestedErr.(type) {
case *OpError:
if err := err.isValid(); err != nil {
@@ -518,7 +529,7 @@ second:
goto third
}
switch nestedErr {
- case poll.ErrClosing:
+ case poll.ErrNetClosing:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -548,23 +559,23 @@ func TestCloseError(t *testing.T) {
for i := 0; i < 3; i++ {
err = c.(*TCPConn).CloseRead()
- if perr := parseCloseError(err); perr != nil {
+ if perr := parseCloseError(err, true); perr != nil {
t.Errorf("#%d: %v", i, perr)
}
}
for i := 0; i < 3; i++ {
err = c.(*TCPConn).CloseWrite()
- if perr := parseCloseError(err); perr != nil {
+ if perr := parseCloseError(err, true); perr != nil {
t.Errorf("#%d: %v", i, perr)
}
}
for i := 0; i < 3; i++ {
err = c.Close()
- if perr := parseCloseError(err); perr != nil {
+ if perr := parseCloseError(err, false); perr != nil {
t.Errorf("#%d: %v", i, perr)
}
err = ln.Close()
- if perr := parseCloseError(err); perr != nil {
+ if perr := parseCloseError(err, false); perr != nil {
t.Errorf("#%d: %v", i, perr)
}
}
@@ -577,7 +588,7 @@ func TestCloseError(t *testing.T) {
for i := 0; i < 3; i++ {
err = pc.Close()
- if perr := parseCloseError(err); perr != nil {
+ if perr := parseCloseError(err, false); perr != nil {
t.Errorf("#%d: %v", i, perr)
}
}
@@ -614,7 +625,7 @@ second:
goto third
}
switch nestedErr {
- case poll.ErrClosing, poll.ErrTimeout:
+ case poll.ErrNetClosing, poll.ErrTimeout:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -693,7 +704,7 @@ second:
goto third
}
switch nestedErr {
- case poll.ErrClosing:
+ case poll.ErrNetClosing:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)