diff --git a/pkg/hub/handlers_agent_messaging.go b/pkg/hub/handlers_agent_messaging.go index 67edec9a8..af860d8b9 100644 --- a/pkg/hub/handlers_agent_messaging.go +++ b/pkg/hub/handlers_agent_messaging.go @@ -22,6 +22,7 @@ import ( "net/http" "strings" "time" + "unicode/utf8" "github.com/GoogleCloudPlatform/scion/pkg/agent/state" "github.com/GoogleCloudPlatform/scion/pkg/api" @@ -68,6 +69,10 @@ func (s *Server) handleAgentOutboundMessage(w http.ResponseWriter, r *http.Reque ValidationError(w, "msg is required", nil) return } + if msgLen := utf8.RuneCountInString(req.Msg); msgLen > messages.MaxMessageLength { + ValidationError(w, fmt.Sprintf("message exceeds %d character limit (current: %d chars). Consider splitting into multiple messages using multiple scion message invocations", messages.MaxMessageLength, msgLen), nil) + return + } if req.Type == "" { req.Type = "input-needed" } diff --git a/pkg/messages/types.go b/pkg/messages/types.go index 962593325..e4508dfde 100644 --- a/pkg/messages/types.go +++ b/pkg/messages/types.go @@ -24,6 +24,9 @@ import ( // Schema version for the structured message format. const Version = 1 +// Maximum length of the Msg field in characters for outbound messages. +const MaxMessageLength = 2000 + // Maximum size of the Msg field in bytes. const MaxMsgSize = 64 * 1024 // 64KB @@ -127,6 +130,9 @@ func (m *StructuredMessage) Validate() error { if m.Msg == "" { return fmt.Errorf("msg field is required") } + if len([]rune(m.Msg)) > MaxMessageLength { + return fmt.Errorf("message exceeds %d character limit (current: %d chars). Consider splitting into multiple messages using multiple scion message invocations", MaxMessageLength, len([]rune(m.Msg))) + } if len(m.Msg) > MaxMsgSize { return fmt.Errorf("msg exceeds maximum size of %d bytes", MaxMsgSize) } diff --git a/pkg/messages/types_test.go b/pkg/messages/types_test.go index 0c19ce0cb..b14aa098b 100644 --- a/pkg/messages/types_test.go +++ b/pkg/messages/types_test.go @@ -76,6 +76,25 @@ func TestStructuredMessage_Validate(t *testing.T) { } }) + t.Run("msg exceeds character limit", func(t *testing.T) { + m := validMsg() + m.Msg = strings.Repeat("x", MaxMessageLength+1) + err := m.Validate() + if err == nil { + t.Error("expected error for msg exceeding character limit") + } else if !strings.Contains(err.Error(), "character limit") { + t.Errorf("error should mention character limit, got: %v", err) + } + }) + + t.Run("msg at character limit", func(t *testing.T) { + m := validMsg() + m.Msg = strings.Repeat("x", MaxMessageLength) + if err := m.Validate(); err != nil { + t.Errorf("unexpected error for msg at character limit: %v", err) + } + }) + t.Run("msg too large", func(t *testing.T) { m := validMsg() m.Msg = strings.Repeat("x", MaxMsgSize+1)