code: func (s *Stream) readData(hdr header, flags uint16, conn io.Reader) error {
  	if err := s.processFlags(flags); err != nil {
  		return err
  	}
  
  	// Check that our recv window is not exceeded
  	length := hdr.Length()
  	if length == 0 {
  		return nil
  	}
  
  	// Wrap in a limited reader
  	conn = &io.LimitedReader{R: conn, N: int64(length)}
  
  	// Copy into buffer
  	s.recvLock.Lock()
  
  	if length > s.recvWindow {
  		s.session.logger.Printf("[ERR] yamux: receive window exceeded (stream: %d, remain: %d, recv: %d)", s.id, s.recvWindow, length)
  		return ErrRecvWindowExceeded
  	}
  
  	if s.recvBuf == nil {
  		// Allocate the receive buffer just-in-time to fit the full data frame.
  		// This way we can read in the whole packet without further allocations.
  		s.recvBuf = bytes.NewBuffer(make([]byte, 0, length))
  	}
  	if _, err := io.Copy(s.recvBuf, conn); err != nil {
  		s.session.logger.Printf("[ERR] yamux: Failed to read stream data: %v", err)
  		s.recvLock.Unlock()
  		return err
  	}
  
  	// Decrement the receive window
  	s.recvWindow -= length
  	s.recvLock.Unlock()
  
  	// Unblock any readers
  	asyncNotify(s.recvNotifyCh)
  	return nil
  }
docs: // readData is used to handle a data frame