@@ -48,6 +48,8 @@ import (
4848 "net/http"
4949 "net/textproto"
5050 "net/url"
51+ "os"
52+ "reflect"
5153 "runtime"
5254 "strconv"
5355 "strings"
@@ -482,12 +484,57 @@ func (sc *serverConn) logf(format string, args ...interface{}) {
482484 }
483485}
484486
487+ var uintptrType = reflect .TypeOf (uintptr (0 ))
488+
489+ // errno returns v's underlying uintptr, else 0.
490+ //
491+ // TODO: remove this helper function once http2 can use build
492+ // tags. See comment in isClosedConnError.
493+ func errno (v error ) uintptr {
494+ if rv := reflect .ValueOf (v ); rv .Kind () == reflect .Uintptr {
495+ return uintptr (rv .Uint ())
496+ }
497+ return 0
498+ }
499+
500+ // isClosedConnError reports whether err is an error from use of a closed
501+ // network connection.
502+ func isClosedConnError (err error ) bool {
503+ if err == nil {
504+ return false
505+ }
506+
507+ // TODO: remove this string search and be more like the Windows
508+ // case below. That might involve modifying the standard library
509+ // to return better error types.
510+ str := err .Error ()
511+ if strings .Contains (str , "use of closed network connection" ) {
512+ return true
513+ }
514+
515+ // TODO(bradfitz): x/tools/cmd/bundle doesn't really support
516+ // build tags, so I can't make an http2_windows.go file with
517+ // Windows-specific stuff. Fix that and move this, once we
518+ // have a way to bundle this into std's net/http somehow.
519+ if runtime .GOOS == "windows" {
520+ if oe , ok := err .(* net.OpError ); ok && oe .Op == "read" {
521+ if se , ok := oe .Err .(* os.SyscallError ); ok && se .Syscall == "wsarecv" {
522+ const WSAECONNABORTED = 10053
523+ const WSAECONNRESET = 10054
524+ if n := errno (se .Err ); n == WSAECONNRESET || n == WSAECONNABORTED {
525+ return true
526+ }
527+ }
528+ }
529+ }
530+ return false
531+ }
532+
485533func (sc * serverConn ) condlogf (err error , format string , args ... interface {}) {
486534 if err == nil {
487535 return
488536 }
489- str := err .Error ()
490- if err == io .EOF || strings .Contains (str , "use of closed network connection" ) {
537+ if err == io .EOF || err == io .ErrUnexpectedEOF || isClosedConnError (err ) {
491538 // Boring, expected errors.
492539 sc .vlogf (format , args ... )
493540 } else {
@@ -1031,7 +1078,7 @@ func (sc *serverConn) processFrameFromReader(res readFrameResult) bool {
10311078 sc .goAway (ErrCodeFrameSize )
10321079 return true // goAway will close the loop
10331080 }
1034- clientGone := err == io .EOF || strings . Contains ( err . Error (), "use of closed network connection" )
1081+ clientGone := err == io .EOF || err == io . ErrUnexpectedEOF || isClosedConnError ( err )
10351082 if clientGone {
10361083 // TODO: could we also get into this state if
10371084 // the peer does a half close
@@ -1067,7 +1114,7 @@ func (sc *serverConn) processFrameFromReader(res readFrameResult) bool {
10671114 return true // goAway will handle shutdown
10681115 default :
10691116 if res .err != nil {
1070- sc .logf ("http2: server closing client connection; error reading frame from client %s: %v" , sc .conn .RemoteAddr (), err )
1117+ sc .vlogf ("http2: server closing client connection; error reading frame from client %s: %v" , sc .conn .RemoteAddr (), err )
10711118 } else {
10721119 sc .logf ("http2: server closing client connection: %v" , err )
10731120 }
0 commit comments