@@ -48,6 +48,8 @@ import (
48
48
"net/http"
49
49
"net/textproto"
50
50
"net/url"
51
+ "os"
52
+ "reflect"
51
53
"runtime"
52
54
"strconv"
53
55
"strings"
@@ -482,12 +484,57 @@ func (sc *serverConn) logf(format string, args ...interface{}) {
482
484
}
483
485
}
484
486
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
+
485
533
func (sc * serverConn ) condlogf (err error , format string , args ... interface {}) {
486
534
if err == nil {
487
535
return
488
536
}
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 ) {
491
538
// Boring, expected errors.
492
539
sc .vlogf (format , args ... )
493
540
} else {
@@ -1031,7 +1078,7 @@ func (sc *serverConn) processFrameFromReader(res readFrameResult) bool {
1031
1078
sc .goAway (ErrCodeFrameSize )
1032
1079
return true // goAway will close the loop
1033
1080
}
1034
- clientGone := err == io .EOF || strings . Contains ( err . Error (), "use of closed network connection" )
1081
+ clientGone := err == io .EOF || err == io . ErrUnexpectedEOF || isClosedConnError ( err )
1035
1082
if clientGone {
1036
1083
// TODO: could we also get into this state if
1037
1084
// the peer does a half close
@@ -1067,7 +1114,7 @@ func (sc *serverConn) processFrameFromReader(res readFrameResult) bool {
1067
1114
return true // goAway will handle shutdown
1068
1115
default :
1069
1116
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 )
1071
1118
} else {
1072
1119
sc .logf ("http2: server closing client connection: %v" , err )
1073
1120
}
0 commit comments