diff --git a/stream.go b/stream.go index ad38fa6..f60501a 100644 --- a/stream.go +++ b/stream.go @@ -25,13 +25,13 @@ type Stream struct { // if more than a single instruction is read, the rest are buffered here parseStart int - buffer []byte - reset []byte + buffer []rune + reset []rune } // NewStream creates a new stream func NewStream(conn net.Conn, timeout time.Duration) (ret *Stream) { - buffer := make([]byte, 0, MaxGuacMessage*3) + buffer := make([]rune, 0, MaxGuacMessage*3) return &Stream{ conn: conn, timeout: timeout, @@ -111,14 +111,14 @@ func (s *Stream) ReadSome() (instruction []byte, err error) { // instruction. switch terminator { case ';': - instruction = s.buffer[0:i] + instruction = []byte(string(s.buffer[0:i])) s.parseStart = 0 s.buffer = s.buffer[i:] return case ',': // keep going default: - err = ErrServer.NewError("Element terminator of instruction was not ';' nor ','") + err = ErrServer.NewError("Element terminator of instruction was not ';' nor ',', twas " + string(terminator)) return } default: @@ -128,11 +128,8 @@ func (s *Stream) ReadSome() (instruction []byte, err error) { } } - if cap(s.buffer) < MaxGuacMessage { - s.Flush() - } - - n, err = s.conn.Read(s.buffer[len(s.buffer):cap(s.buffer)]) + buffer := make([]byte, 1024) + n, err = s.conn.Read(buffer) if err != nil && n == 0 { switch err.(type) { case net.Error: @@ -150,6 +147,13 @@ func (s *Stream) ReadSome() (instruction []byte, err error) { if n == 0 { err = ErrServer.NewError("read 0 bytes") } + runes := []rune(string(buffer[:n])) + + if cap(s.buffer)-len(s.buffer) < len(runes) { + s.Flush() + } + + n = copy(s.buffer[len(s.buffer):cap(s.buffer)], runes) // must reslice so len is changed s.buffer = s.buffer[:len(s.buffer)+n] } diff --git a/stream_test.go b/stream_test.go index 713f511..f5f8bc5 100644 --- a/stream_test.go +++ b/stream_test.go @@ -43,6 +43,41 @@ func TestInstructionReader_ReadSome(t *testing.T) { } } +func TestInstructionReader_ReadSome_Unicode(t *testing.T) { + conn := &fakeConn{ + ToRead: []byte("4.copy,1.🚀;4.copy"), + } + stream := NewStream(conn, 1*time.Minute) + + ins, err := stream.ReadSome() + + if err != nil { + t.Error("Unexpected error", err) + } + if !bytes.Equal(ins, []byte("4.copy,1.🚀;")) { + t.Error("Unexpected bytes returned") + } + if !stream.Available() { + t.Error("Stream has more available but returned false") + } + + // Read the rest of the fragmented instruction + n := copy(conn.ToRead, ",1.🚀;") + conn.ToRead = conn.ToRead[:n] + conn.HasRead = false + ins, err = stream.ReadSome() + + if err != nil { + t.Error("Unexpected error", err) + } + if !bytes.Equal(ins, []byte("4.copy,1.🚀;")) { + t.Error("Unexpected bytes returned") + } + if stream.Available() { + t.Error("Stream thinks it has more available but doesn't") + } +} + func TestInstructionReader_Flush(t *testing.T) { s := NewStream(&fakeConn{}, time.Second) s.buffer = s.buffer[:4]