@@ -2961,3 +2961,90 @@ func (s) TestReadMessageHeaderMultipleBuffers(t *testing.T) {
29612961 t .Errorf ("bytesRead = %d, want = %d" , bytesRead , headerLen )
29622962 }
29632963}
2964+
2965+ // Tests a scenario when the client doesn't send an RST frame when the
2966+ // configured deadline is reached. The test verifies that the server sends an
2967+ // RST stream only after the deadline is reached.
2968+ func (s ) TestServerSendsRSTAfterDeadlineToMisbehavedClient (t * testing.T ) {
2969+ server := setUpServerOnly (t , 0 , & ServerConfig {}, suspended )
2970+ defer server .stop ()
2971+ // Create a client that can override server stream quota.
2972+ mconn , err := net .Dial ("tcp" , server .lis .Addr ().String ())
2973+ if err != nil {
2974+ t .Fatalf ("Clent failed to dial:%v" , err )
2975+ }
2976+ defer mconn .Close ()
2977+ if err := mconn .SetWriteDeadline (time .Now ().Add (time .Second * 10 )); err != nil {
2978+ t .Fatalf ("Failed to set write deadline: %v" , err )
2979+ }
2980+ if n , err := mconn .Write (clientPreface ); err != nil || n != len (clientPreface ) {
2981+ t .Fatalf ("mconn.Write(clientPreface) = %d, %v, want %d, <nil>" , n , err , len (clientPreface ))
2982+ }
2983+ // rstTimeChan chan indicates that reader received a RSTStream from server.
2984+ rstTimeChan := make (chan time.Time , 1 )
2985+ var mu sync.Mutex
2986+ framer := http2 .NewFramer (mconn , mconn )
2987+ if err := framer .WriteSettings (); err != nil {
2988+ t .Fatalf ("Error while writing settings: %v" , err )
2989+ }
2990+ go func () { // Launch a reader for this misbehaving client.
2991+ for {
2992+ frame , err := framer .ReadFrame ()
2993+ if err != nil {
2994+ return
2995+ }
2996+ switch frame := frame .(type ) {
2997+ case * http2.PingFrame :
2998+ // Write ping ack back so that server's BDP estimation works right.
2999+ mu .Lock ()
3000+ framer .WritePing (true , frame .Data )
3001+ mu .Unlock ()
3002+ case * http2.RSTStreamFrame :
3003+ if frame .Header ().StreamID != 1 || http2 .ErrCode (frame .ErrCode ) != http2 .ErrCodeCancel {
3004+ t .Errorf ("RST stream received with streamID: %d and code: %v, want streamID: 1 and code: http2.ErrCodeCancel" , frame .Header ().StreamID , http2 .ErrCode (frame .ErrCode ))
3005+ }
3006+ rstTimeChan <- time .Now ()
3007+ return
3008+ default :
3009+ // Do nothing.
3010+ }
3011+ }
3012+ }()
3013+ // Create a stream.
3014+ var buf bytes.Buffer
3015+ henc := hpack .NewEncoder (& buf )
3016+ if err := henc .WriteField (hpack.HeaderField {Name : ":method" , Value : "POST" }); err != nil {
3017+ t .Fatalf ("Error while encoding header: %v" , err )
3018+ }
3019+ if err := henc .WriteField (hpack.HeaderField {Name : ":path" , Value : "foo" }); err != nil {
3020+ t .Fatalf ("Error while encoding header: %v" , err )
3021+ }
3022+ if err := henc .WriteField (hpack.HeaderField {Name : ":authority" , Value : "localhost" }); err != nil {
3023+ t .Fatalf ("Error while encoding header: %v" , err )
3024+ }
3025+ if err := henc .WriteField (hpack.HeaderField {Name : "content-type" , Value : "application/grpc" }); err != nil {
3026+ t .Fatalf ("Error while encoding header: %v" , err )
3027+ }
3028+ if err := henc .WriteField (hpack.HeaderField {Name : "grpc-timeout" , Value : "10m" }); err != nil {
3029+ t .Fatalf ("Error while encoding header: %v" , err )
3030+ }
3031+ mu .Lock ()
3032+ startTime := time .Now ()
3033+ if err := framer .WriteHeaders (http2.HeadersFrameParam {StreamID : 1 , BlockFragment : buf .Bytes (), EndHeaders : true }); err != nil {
3034+ mu .Unlock ()
3035+ t .Fatalf ("Error while writing headers: %v" , err )
3036+ }
3037+ mu .Unlock ()
3038+
3039+ // Test server behavior for deadline expiration.
3040+ var rstTime time.Time
3041+ select {
3042+ case <- time .After (5 * time .Second ):
3043+ t .Fatalf ("Test timed out." )
3044+ case rstTime = <- rstTimeChan :
3045+ }
3046+
3047+ if got , want := rstTime .Sub (startTime ), 10 * time .Millisecond ; got < want {
3048+ t .Fatalf ("RST frame received earlier than expected by duration: %v" , want - got )
3049+ }
3050+ }
0 commit comments