diff --git a/app/gosqs/queue_attributes.go b/app/gosqs/queue_attributes.go index 8f35a90..c827cdc 100644 --- a/app/gosqs/queue_attributes.go +++ b/app/gosqs/queue_attributes.go @@ -25,9 +25,9 @@ import ( // 4. RedrivePolicy: ARN DLQ разбирается, DLQ должна существовать, иначе // InvalidAttributeValue. func setQueueAttributesV1(q *models.Queue, attr models.QueueAttributes, provided map[string]string) error { - // Шаг 1: whitelist имён атрибутов. + // Шаг 1: whitelist имён атрибутов (единый список — models.AttrNameWhitelist). for name := range provided { - if !attrNameWhitelist[name] { + if !models.AttrNameWhitelist[name] { return fmt.Errorf("InvalidAttributeName") } } @@ -81,14 +81,3 @@ func setQueueAttributesV1(q *models.Queue, attr models.QueueAttributes, provided } return nil } - -// attrNameWhitelist — имена атрибутов, которые SetQueueAttributes может изменять. -// Всё, чего нет в списке, отклоняется с ошибкой InvalidAttributeName. -var attrNameWhitelist = map[string]bool{ - "DelaySeconds": true, - "MaximumMessageSize": true, - "MessageRetentionPeriod": true, - "ReceiveMessageWaitTimeSeconds": true, - "VisibilityTimeout": true, - "RedrivePolicy": true, -} diff --git a/app/models/requests.go b/app/models/requests.go index 3f58632..f71e133 100644 --- a/app/models/requests.go +++ b/app/models/requests.go @@ -401,6 +401,47 @@ type QueueAttributes struct { RedriveAllowPolicy map[string]interface{} `json:"RedriveAllowPolicy"` // NOTE: not implemented } +// AttrNameWhitelist — имена атрибутов, допустимые в SetQueueAttributes/CreateQueue. +// Используется для валидации в ОБОИХ протоколах: +// - Query (form Attribute.N.Name) — в app/gosqs/queue_attributes.go; +// - JSON — в UnmarshalJSON ниже (стандартный парсер молча отбрасывает +// неизвестные поля, поэтому проверка выполняется вручную). +// Policy/RedriveAllowPolicy — допустимы для совместимости, но не реализованы (no-op). +var AttrNameWhitelist = map[string]bool{ + "DelaySeconds": true, + "MaximumMessageSize": true, + "MessageRetentionPeriod": true, + "Policy": true, + "ReceiveMessageWaitTimeSeconds": true, + "VisibilityTimeout": true, + "RedrivePolicy": true, + "RedriveAllowPolicy": true, +} + +// UnmarshalJSON — строгая разборка QueueAttributes для JSON-протокола. +// +// Логическая схема: +// 1. Разбираем тело в map[string]json.RawMessage, чтобы увидеть ВСЕ ключи. +// 2. Каждый ключ проверяем по AttrNameWhitelist: неизвестное имя → ошибка +// (раньше парсер молча отбрасывал чужие поля и SetQueueAttributes принимал +// любой атрибут — «неверное имя атрибута принято» из нагрузочного теста). +// 3. Разбираем штатно: все известные поля попадают в структуру, вложенный +// RedrivePolicy использует собственный UnmarshalJSON. +// Ошибка приводит к TransformRequest=false → InvalidParameterValue в handler. +func (q *QueueAttributes) UnmarshalJSON(data []byte) error { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + for name := range raw { + if !AttrNameWhitelist[name] { + return fmt.Errorf("invalid attribute name: %s", name) + } + } + type plain QueueAttributes + return json.Unmarshal(data, (*plain)(q)) +} + type RedrivePolicy struct { MaxReceiveCount StringToInt `json:"maxReceiveCount"` DeadLetterTargetArn string `json:"deadLetterTargetArn"`