mirror of
https://github.com/golang/go
synced 2024-11-17 18:04:48 -07:00
crypto/tls: failed tls.Conn.Write returns a permanent error
Fixes #29971 Change-Id: I2f1653640c88fafe0ec17a75dcf41d5896c4cb8e Reviewed-on: https://go-review.googlesource.com/c/go/+/227840 Run-TryBot: Katie Hockman <katie@golang.org> Run-TryBot: Filippo Valsorda <filippo@golang.org> Reviewed-by: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
bd0623b4e7
commit
614a713be5
@ -162,9 +162,22 @@ type halfConn struct {
|
||||
trafficSecret []byte // current TLS 1.3 traffic secret
|
||||
}
|
||||
|
||||
type permamentError struct {
|
||||
err net.Error
|
||||
}
|
||||
|
||||
func (e *permamentError) Error() string { return e.err.Error() }
|
||||
func (e *permamentError) Unwrap() error { return e.err }
|
||||
func (e *permamentError) Timeout() bool { return e.err.Timeout() }
|
||||
func (e *permamentError) Temporary() bool { return false }
|
||||
|
||||
func (hc *halfConn) setErrorLocked(err error) error {
|
||||
if e, ok := err.(net.Error); ok {
|
||||
hc.err = &permamentError{err: e}
|
||||
} else {
|
||||
hc.err = err
|
||||
return err
|
||||
}
|
||||
return hc.err
|
||||
}
|
||||
|
||||
// prepareCipherSpec sets the encryption and MAC states
|
||||
|
@ -355,7 +355,8 @@ func TestAlertForwarding(t *testing.T) {
|
||||
|
||||
err := Server(s, testConfig).Handshake()
|
||||
s.Close()
|
||||
if e, ok := err.(*net.OpError); !ok || e.Err != error(alertUnknownCA) {
|
||||
var opErr *net.OpError
|
||||
if !errors.As(err, &opErr) || opErr.Err != error(alertUnknownCA) {
|
||||
t.Errorf("Got error: %s; expected: %s", err, error(alertUnknownCA))
|
||||
}
|
||||
}
|
||||
|
@ -201,6 +201,77 @@ func TestDialTimeout(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeadlineOnWrite(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
|
||||
ln := newLocalListener(t)
|
||||
defer ln.Close()
|
||||
|
||||
srvCh := make(chan *Conn, 1)
|
||||
|
||||
go func() {
|
||||
sconn, err := ln.Accept()
|
||||
if err != nil {
|
||||
srvCh <- nil
|
||||
return
|
||||
}
|
||||
srv := Server(sconn, testConfig.Clone())
|
||||
if err := srv.Handshake(); err != nil {
|
||||
srvCh <- nil
|
||||
return
|
||||
}
|
||||
srvCh <- srv
|
||||
}()
|
||||
|
||||
clientConfig := testConfig.Clone()
|
||||
clientConfig.MaxVersion = VersionTLS12
|
||||
conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
srv := <-srvCh
|
||||
if srv == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Make sure the client/server is setup correctly and is able to do a typical Write/Read
|
||||
buf := make([]byte, 6)
|
||||
if _, err := srv.Write([]byte("foobar")); err != nil {
|
||||
t.Errorf("Write err: %v", err)
|
||||
}
|
||||
if n, err := conn.Read(buf); n != 6 || err != nil || string(buf) != "foobar" {
|
||||
t.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
|
||||
}
|
||||
|
||||
// Set a deadline which should cause Write to timeout
|
||||
if err = srv.SetDeadline(time.Now()); err != nil {
|
||||
t.Fatalf("SetDeadline(time.Now()) err: %v", err)
|
||||
}
|
||||
if _, err = srv.Write([]byte("should fail")); err == nil {
|
||||
t.Fatal("Write should have timed out")
|
||||
}
|
||||
|
||||
// Clear deadline and make sure it still times out
|
||||
if err = srv.SetDeadline(time.Time{}); err != nil {
|
||||
t.Fatalf("SetDeadline(time.Time{}) err: %v", err)
|
||||
}
|
||||
if _, err = srv.Write([]byte("This connection is permanently broken")); err == nil {
|
||||
t.Fatal("Write which previously failed should still time out")
|
||||
}
|
||||
|
||||
// Verify the error
|
||||
if ne := err.(net.Error); ne.Temporary() != false {
|
||||
t.Error("Write timed out but incorrectly classified the error as Temporary")
|
||||
}
|
||||
if !isTimeoutError(err) {
|
||||
t.Error("Write timed out but did not classify the error as a Timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func isTimeoutError(err error) bool {
|
||||
if ne, ok := err.(net.Error); ok {
|
||||
return ne.Timeout()
|
||||
|
Loading…
Reference in New Issue
Block a user