mirror of
https://github.com/stashapp/stash.git
synced 2026-05-09 05:05:29 +02:00
* Fix WebSocket UTF-8 error for non-UTF-8 file paths in subscriptions Sanitize log messages and job fields (description, subtasks, error) before sending over WebSocket. File paths with non-UTF-8 characters caused the browser to close the connection with "Could not decode a text frame as UTF-8." Invalid bytes are replaced with U+FFFD. Only the API response layer is affected — underlying stored data is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Replace direct ToValidUTF8 calls to new sanitiseWebsocketString function --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
71 lines
1.5 KiB
Go
71 lines
1.5 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/stashapp/stash/internal/log"
|
|
"github.com/stashapp/stash/internal/manager"
|
|
)
|
|
|
|
// sanitiseWebsocketString is used to ensure that any strings sent over the websocket are valid UTF-8.
|
|
// Any invalid UTF-8 sequences will be replaced with the Unicode replacement character (U+FFFD).
|
|
// Invalid UTF-8 sequences can cause the websocket connection to be closed.
|
|
func sanitiseWebsocketString(s string) string {
|
|
return strings.ToValidUTF8(s, "\uFFFD")
|
|
}
|
|
|
|
func getLogLevel(logType string) LogLevel {
|
|
switch logType {
|
|
case "progress":
|
|
return LogLevelProgress
|
|
case "trace":
|
|
return LogLevelTrace
|
|
case "debug":
|
|
return LogLevelDebug
|
|
case "info":
|
|
return LogLevelInfo
|
|
case "warn":
|
|
return LogLevelWarning
|
|
case "error":
|
|
return LogLevelError
|
|
default:
|
|
return LogLevelDebug
|
|
}
|
|
}
|
|
|
|
func logEntriesFromLogItems(logItems []log.LogItem) []*LogEntry {
|
|
ret := make([]*LogEntry, len(logItems))
|
|
|
|
for i, entry := range logItems {
|
|
ret[i] = &LogEntry{
|
|
Time: entry.Time,
|
|
Level: getLogLevel(entry.Type),
|
|
Message: sanitiseWebsocketString(entry.Message),
|
|
}
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func (r *subscriptionResolver) LoggingSubscribe(ctx context.Context) (<-chan []*LogEntry, error) {
|
|
ret := make(chan []*LogEntry, 100)
|
|
stop := make(chan int, 1)
|
|
logger := manager.GetInstance().Logger
|
|
logSub := logger.SubscribeToLog(stop)
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
case logEntries := <-logSub:
|
|
ret <- logEntriesFromLogItems(logEntries)
|
|
case <-ctx.Done():
|
|
stop <- 0
|
|
close(ret)
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
return ret, nil
|
|
}
|