Explorar o código

http2: disable server push on receiving a GOAWAY

Fixes golang/go#17800

Change-Id: Ibcba9302e2e595ae49d9246ecedd332760486441
Reviewed-on: https://go-review.googlesource.com/32887
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Tom Bergan %!s(int64=9) %!d(string=hai) anos
pai
achega
87635b2611
Modificáronse 2 ficheiros con 52 adicións e 0 borrados
  1. 16 0
      http2/server.go
  2. 36 0
      http2/server_push_test.go

+ 16 - 0
http2/server.go

@@ -1166,6 +1166,8 @@ func (sc *serverConn) processFrame(f Frame) error {
 		return sc.processResetStream(f)
 	case *PriorityFrame:
 		return sc.processPriority(f)
+	case *GoAwayFrame:
+		return sc.processGoAway(f)
 	case *PushPromiseFrame:
 		// A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE
 		// frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
@@ -1441,6 +1443,20 @@ func (sc *serverConn) processData(f *DataFrame) error {
 	return nil
 }
 
+func (sc *serverConn) processGoAway(f *GoAwayFrame) error {
+	sc.serveG.check()
+	if f.ErrCode != ErrCodeNo {
+		sc.logf("http2: received GOAWAY %+v, starting graceful shutdown", f)
+	} else {
+		sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
+	}
+	sc.goAwayIn(ErrCodeNo, 0)
+	// http://tools.ietf.org/html/rfc7540#section-6.8
+	// We should not create any new streams, which means we should disable push.
+	sc.pushEnabled = false
+	return nil
+}
+
 // isPushed reports whether the stream is server-initiated.
 func (st *stream) isPushed() bool {
 	return st.id%2 == 0

+ 36 - 0
http2/server_push_test.go

@@ -427,3 +427,39 @@ func TestServer_Push_StateTransitions(t *testing.T) {
 	}
 	close(finishedPush)
 }
+
+func TestServer_Push_RejectAfterGoAway(t *testing.T) {
+	ready := make(chan struct{})
+	errc := make(chan error, 2)
+	st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
+		select {
+		case <-ready:
+		case <-time.After(5 * time.Second):
+			errc <- fmt.Errorf("timeout waiting for GOAWAY to be processed")
+		}
+		if got, want := w.(http.Pusher).Push("https://"+r.Host+"/pushed", nil), http.ErrNotSupported; got != want {
+			errc <- fmt.Errorf("Push()=%v, want %v", got, want)
+		}
+		errc <- nil
+	})
+	defer st.Close()
+	st.greet()
+	getSlash(st)
+
+	// Send GOAWAY and wait for it to be processed.
+	st.fr.WriteGoAway(1, ErrCodeNo, nil)
+	go func() {
+		done := false
+		for !done {
+			st.sc.testHookCh <- func(loopNum int) {
+				if !st.sc.pushEnabled {
+					close(ready)
+					done = true
+				}
+			}
+		}
+	}()
+	if err := <-errc; err != nil {
+		t.Error(err)
+	}
+}