• Brad Fitzpatrick's avatar
    crypto/tls: make Conn.Read return (n, io.EOF) when EOF is next in buffer · f61f18d6
    Brad Fitzpatrick authored
    Update #3514
    
    An io.Reader is permitted to return either (n, nil)
    or (n, io.EOF) on EOF or other error.
    
    The tls package previously always returned (n, nil) for a read
    of size n if n bytes were available, not surfacing errors at
    the same time.
    
    Amazon's HTTPS frontends like to hang up on clients without
    sending the appropriate HTTP headers. (In their defense,
    they're allowed to hang up any time, but generally a server
    hangs up after a bit of inactivity, not immediately.) In any
    case, the Go HTTP client tries to re-use connections by
    looking at whether the response headers say to keep the
    connection open, and because the connection looks okay, under
    heavy load it's possible we'll reuse it immediately, writing
    the next request, just as the Transport's always-reading
    goroutine returns from tls.Conn.Read and sees (0, io.EOF).
    
    But because Amazon does send an AlertCloseNotify record before
    it hangs up on us, and the tls package does its own internal
    buffering (up to 1024 bytes) of pending data, we have the
    AlertCloseNotify in an unread buffer when our Conn.Read (to
    the HTTP Transport code) reads its final bit of data in the
    HTTP response body.
    
    This change makes that final Read return (n, io.EOF) when
    an AlertCloseNotify record is buffered right after, if we'd
    otherwise return (n, nil).
    
    A dependent change in the HTTP code then notes whether a
    client connection has seen an io.EOF and uses that as an
    additional signal to not reuse a HTTPS connection. With both
    changes, the majority of Amazon request failures go
    away. Without either one, 10-20 goroutines hitting the S3 API
    leads to such an error rate that empirically up to 5 retries
    are needed to complete an API call.
    
    LGTM=agl, rsc
    R=agl, rsc
    CC=golang-codereviews
    https://golang.org/cl/76400046
    f61f18d6
Name
Last commit
Last update
..
testdata Loading commit data...
alert.go Loading commit data...
cipher_suites.go Loading commit data...
common.go Loading commit data...
conn.go Loading commit data...
conn_test.go Loading commit data...
example_test.go Loading commit data...
generate_cert.go Loading commit data...
handshake_client.go Loading commit data...
handshake_client_test.go Loading commit data...
handshake_messages.go Loading commit data...
handshake_messages_test.go Loading commit data...
handshake_server.go Loading commit data...
handshake_server_test.go Loading commit data...
handshake_test.go Loading commit data...
key_agreement.go Loading commit data...
prf.go Loading commit data...
prf_test.go Loading commit data...
ticket.go Loading commit data...
tls.go Loading commit data...
tls_test.go Loading commit data...