Pull readPreface into its own method, add timeout per TODO
diff --git a/server.go b/server.go
index fc7ad26..a8c4980 100644
--- a/server.go
+++ b/server.go
@@ -21,6 +21,7 @@
"strconv"
"strings"
"sync"
+ "time"
"github.com/bradfitz/http2/hpack"
)
@@ -197,7 +198,7 @@
return
}
str := err.Error()
- if strings.Contains(str, "use of closed network connection") {
+ if err == io.EOF || strings.Contains(str, "use of closed network connection") {
// Boring, expected errors.
sc.vlogf(format, args...)
} else {
@@ -314,18 +315,10 @@
sc.vlogf("HTTP/2 connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
- // Read the client preface
- buf := make([]byte, len(ClientPreface))
- // TODO: timeout reading from the client
- if _, err := io.ReadFull(sc.conn, buf); err != nil {
- sc.logf("error reading client preface: %v", err)
+ if err := sc.readPreface(); err != nil {
+ sc.condlogf(err, "Error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
return
}
- if !bytes.Equal(buf, clientPreface) {
- sc.logf("bogus greeting from client: %q", buf)
- return
- }
- sc.vlogf("client %v said hello", sc.conn.RemoteAddr())
f, err := sc.framer.ReadFrame() // TODO: timeout
if err != nil {
@@ -408,6 +401,35 @@
}
}
+// readPreface reads the ClientPreface greeting from the peer
+// or returns an error on timeout or an invalid greeting.
+func (sc *serverConn) readPreface() error {
+ errc := make(chan error, 1)
+ go func() {
+ // Read the client preface
+ buf := make([]byte, len(ClientPreface))
+ // TODO: timeout reading from the client
+ if _, err := io.ReadFull(sc.conn, buf); err != nil {
+ errc <- err
+ } else if !bytes.Equal(buf, clientPreface) {
+ errc <- fmt.Errorf("bogus greeting %q", buf)
+ } else {
+ errc <- nil
+ }
+ }()
+ timer := time.NewTimer(5 * time.Second) // TODO: configurable on *Server?
+ defer timer.Stop()
+ select {
+ case <-timer.C:
+ return errors.New("timeout waiting for client preface")
+ case err := <-errc:
+ if err == nil {
+ sc.vlogf("client %v said hello", sc.conn.RemoteAddr())
+ }
+ return err
+ }
+}
+
func (sc *serverConn) enqueueFrameWrite(wm frameWriteMsg) {
sc.serveG.check()
// Fast path for common case: