fix(terminal): prevent UTF-8 chunk truncation falling back to GBK

This fixes an issue where outputting large amounts of Chinese text caused the 4096-byte chunk to split a multi-byte UTF-8 character, falsely triggering the GBK fallback logic and resulting in garbled text.
This commit is contained in:
duorameng
2026-06-18 17:51:54 +08:00
parent 50daa79c0a
commit 19374e7054
+62 -10
View File
@@ -138,14 +138,40 @@ func (tc *TerminalController) handlePtyMode(conn *websocket.Conn, userID string)
go func() { go func() {
defer wg.Done() defer wg.Done()
buf := make([]byte, 4096) buf := make([]byte, 4096)
var remainder []byte
for { for {
n, err := ptmx.Read(buf) n, err := ptmx.Read(buf)
if err != nil {
return
}
if n > 0 { if n > 0 {
text := toUTF8(buf[:n]) chunk := append(remainder, buf[:n]...)
writeMessage([]byte(text)) lastSafe := len(chunk)
for i := len(chunk); i > 0 && i > len(chunk)-4; i-- {
if utf8.RuneStart(chunk[i-1]) {
if !utf8.FullRune(chunk[i-1 : len(chunk)]) {
lastSafe = i - 1
}
break
}
}
safe := chunk[:lastSafe]
if len(safe) == 0 && len(chunk) >= 4 {
safe = chunk
remainder = nil
} else {
remainder = make([]byte, len(chunk[lastSafe:]))
copy(remainder, chunk[lastSafe:])
}
if len(safe) > 0 {
text := toUTF8(safe)
writeMessage([]byte(text))
}
}
if err != nil {
if len(remainder) > 0 {
writeMessage([]byte(toUTF8(remainder)))
}
return
} }
} }
}() }()
@@ -259,14 +285,40 @@ func (tc *TerminalController) handlePipeMode(conn *websocket.Conn, userID string
defer wg.Done() defer wg.Done()
defer func() { recover() }() defer func() { recover() }()
buf := make([]byte, 4096) buf := make([]byte, 4096)
var remainder []byte
for { for {
n, err := reader.Read(buf) n, err := reader.Read(buf)
if err != nil {
return
}
if n > 0 { if n > 0 {
text := toUTF8(buf[:n]) chunk := append(remainder, buf[:n]...)
writeMessage([]byte(text)) lastSafe := len(chunk)
for i := len(chunk); i > 0 && i > len(chunk)-4; i-- {
if utf8.RuneStart(chunk[i-1]) {
if !utf8.FullRune(chunk[i-1 : len(chunk)]) {
lastSafe = i - 1
}
break
}
}
safe := chunk[:lastSafe]
if len(safe) == 0 && len(chunk) >= 4 {
safe = chunk
remainder = nil
} else {
remainder = make([]byte, len(chunk[lastSafe:]))
copy(remainder, chunk[lastSafe:])
}
if len(safe) > 0 {
text := toUTF8(safe)
writeMessage([]byte(text))
}
}
if err != nil {
if len(remainder) > 0 {
writeMessage([]byte(toUTF8(remainder)))
}
return
} }
} }
} }