func (s *Stream) resetWith(errorCode frame.ErrorCode, resetErr error) { // only ever send one reset if !atomic.CompareAndSwapUint32(&s.sentRst, 0, 1) { return } // close the stream s.closeWithAndRemoveLater(resetErr) // make the reset frame rst := frame.NewWStreamRst() if err := rst.Set(s.id, errorCode); err != nil { s.die(frame.InternalError, err) } // need write lock to make sure no data frames get sent after we send the reset s.writer.Lock() // send it if err := s.session.writeFrame(rst, zeroTime); err != nil { s.writer.Unlock() s.die(frame.InternalError, err) } s.writer.Unlock() }
func TestDataAfterRst(t *testing.T) { local, remote := newFakeConnPair() _ = NewSession(local, NewStream, false, []Extension{}) trans := frame.NewBasicTransport(remote) // make sure that we get an RST STREAM_CLOSED done := make(chan int) go func() { defer func() { done <- 1 }() f, err := trans.ReadFrame() if err != nil { t.Errorf("Failed to read frame sent from session: %v", err) return } fr, ok := f.(*frame.RStreamRst) if !ok { t.Errorf("Frame is not STREAM_RST: %v", f) return } if fr.ErrorCode() != frame.StreamClosed { t.Errorf("Error code on STREAM_RST is not STREAM_CLOSED. Got %d, expected %d", fr.ErrorCode(), frame.StreamClosed) return } }() fSyn := frame.NewWStreamSyn() if err := fSyn.Set(301, 0, 0, false); err != nil { t.Fatalf("Failed to make syn frame: %v", err) } if err := trans.WriteFrame(fSyn); err != nil { t.Fatalf("Failed to send syn: %v", err) } fRst := frame.NewWStreamRst() if err := fRst.Set(301, frame.Cancel); err != nil { t.Fatal("Failed to make rst frame: %v", err) } if err := trans.WriteFrame(fRst); err != nil { t.Fatalf("Failed to write rst frame: %v", err) } fData := frame.NewWStreamData() if err := fData.Set(301, []byte{0xa, 0xFF}, false); err != nil { t.Fatalf("Failed to set data frame") } trans.WriteFrame(fData) <-done }