crypto/tls: add CloseWrite method to Conn

The CloseWrite method sends a close_notify alert record to the other
side of the connection. This record indicates that the sender has
finished sending on the connection. Unlike the Close method, the sender
may still read from the connection until it recieves a close_notify
record (or the underlying connection is closed). This is analogous to a
TCP half-close.

Updates #8579

Change-Id: I9c6bc193efcb25cc187f7735ee07170afa7fdde3
Reviewed-on: https://go-review.googlesource.com/25159
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Ben Burkert 2016-07-24 15:13:56 -07:00 committed by Brad Fitzpatrick
parent 46e9439117
commit 53121dd61c
2 changed files with 128 additions and 2 deletions

View file

@ -11,6 +11,7 @@ import (
"fmt"
"internal/testenv"
"io"
"io/ioutil"
"math"
"math/rand"
"net"
@ -458,6 +459,91 @@ func TestConnCloseBreakingWrite(t *testing.T) {
}
}
func TestConnCloseWrite(t *testing.T) {
ln := newLocalListener(t)
defer ln.Close()
go func() {
sconn, err := ln.Accept()
if err != nil {
t.Fatal(err)
}
serverConfig := testConfig.Clone()
srv := Server(sconn, serverConfig)
if err := srv.Handshake(); err != nil {
t.Fatalf("handshake: %v", err)
}
defer srv.Close()
data, err := ioutil.ReadAll(srv)
if err != nil {
t.Fatal(err)
}
if len(data) > 0 {
t.Errorf("Read data = %q; want nothing", data)
}
if err = srv.CloseWrite(); err != nil {
t.Errorf("server CloseWrite: %v", err)
}
}()
clientConfig := testConfig.Clone()
conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
if err != nil {
t.Fatal(err)
}
if err = conn.Handshake(); err != nil {
t.Fatal(err)
}
defer conn.Close()
if err = conn.CloseWrite(); err != nil {
t.Errorf("client CloseWrite: %v", err)
}
if _, err := conn.Write([]byte{0}); err != errShutdown {
t.Errorf("CloseWrite error = %v; want errShutdown", err)
}
data, err := ioutil.ReadAll(conn)
if err != nil {
t.Fatal(err)
}
if len(data) > 0 {
t.Errorf("Read data = %q; want nothing", data)
}
// test CloseWrite called before handshake finished
ln2 := newLocalListener(t)
defer ln2.Close()
go func() {
sconn, err := ln2.Accept()
if err != nil {
t.Fatal(err)
}
serverConfig := testConfig.Clone()
srv := Server(sconn, serverConfig)
srv.Handshake()
srv.Close()
}()
netConn, err := net.Dial("tcp", ln2.Addr().String())
if err != nil {
t.Fatal(err)
}
conn = Client(netConn, clientConfig)
if err = conn.CloseWrite(); err != errEarlyCloseWrite {
t.Errorf("CloseWrite error = %v; want errEarlyCloseWrite", err)
}
}
func TestClone(t *testing.T) {
var c1 Config
v := reflect.ValueOf(&c1).Elem()