From 8ca9a1293092b64aa81ad40fa1debedba7b0744b Mon Sep 17 00:00:00 2001
From: Martins Sipenko <martins.sipenko@gmail.com>
Date: Wed, 12 Jul 2023 14:09:40 +0300
Subject: [PATCH] base64 encode SNS Header message attribure

---
 pkg/sns/SnsProducer.php               |  2 +-
 pkg/sns/Tests/SnsProducerTest.php     |  4 ++--
 pkg/snsqs/SnsQsConsumer.php           |  6 +++++-
 pkg/snsqs/Tests/SnsQsConsumerTest.php | 31 +++++++++++++++++++++++++++
 4 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/pkg/sns/SnsProducer.php b/pkg/sns/SnsProducer.php
index bbd46a96f..3a6bd4263 100644
--- a/pkg/sns/SnsProducer.php
+++ b/pkg/sns/SnsProducer.php
@@ -51,7 +51,7 @@ public function send(Destination $destination, Message $message): void
             'MessageAttributes' => [
                 'Headers' => [
                     'DataType' => 'String',
-                    'StringValue' => json_encode([$message->getHeaders(), $message->getProperties()]),
+                    'StringValue' => base64_encode(json_encode([$message->getHeaders(), $message->getProperties()])),
                 ],
             ],
             'TopicArn' => $topicArn,
diff --git a/pkg/sns/Tests/SnsProducerTest.php b/pkg/sns/Tests/SnsProducerTest.php
index 5f8784905..07f5e23ba 100644
--- a/pkg/sns/Tests/SnsProducerTest.php
+++ b/pkg/sns/Tests/SnsProducerTest.php
@@ -138,7 +138,7 @@ public function testShouldPublish()
             'MessageAttributes' => [
                 'Headers' => [
                     'DataType' => 'String',
-                    'StringValue' => '[{"hkey":"hvaleu"},{"key":"value"}]',
+                    'StringValue' => base64_encode('[{"hkey":"hvaleu"},{"key":"value"}]'),
                 ],
             ],
             'TopicArn' => 'theTopicArn',
@@ -189,7 +189,7 @@ public function testShouldPublishWithMergedAttributes()
             'MessageAttributes' => [
                 'Headers' => [
                     'DataType' => 'String',
-                    'StringValue' => '[[],[]]',
+                    'StringValue' => base64_encode('[[],[]]'),
                 ],
                 'Foo' => [
                     'DataType' => 'String',
diff --git a/pkg/snsqs/SnsQsConsumer.php b/pkg/snsqs/SnsQsConsumer.php
index 17ec39ae0..630d11a7e 100644
--- a/pkg/snsqs/SnsQsConsumer.php
+++ b/pkg/snsqs/SnsQsConsumer.php
@@ -124,7 +124,11 @@ private function convertMessage(SqsMessage $sqsMessage): SnsQsMessage
                 }
 
                 if (isset($data['MessageAttributes']['Headers'])) {
-                    $headersData = json_decode($data['MessageAttributes']['Headers']['Value'], true);
+                    $rawHeaderData = $data['MessageAttributes']['Headers']['Value'];
+                    if (isset($rawHeaderData[0]) && '[' !== $rawHeaderData[0]) {
+                        $rawHeaderData = base64_decode($rawHeaderData);
+                    }
+                    $headersData = json_decode($rawHeaderData, true);
 
                     $message->setHeaders($headersData[0]);
                     $message->setProperties($headersData[1]);
diff --git a/pkg/snsqs/Tests/SnsQsConsumerTest.php b/pkg/snsqs/Tests/SnsQsConsumerTest.php
index a16e133b3..1cfe30924 100644
--- a/pkg/snsqs/Tests/SnsQsConsumerTest.php
+++ b/pkg/snsqs/Tests/SnsQsConsumerTest.php
@@ -15,6 +15,37 @@
 final class SnsQsConsumerTest extends TestCase
 {
     public function testReceivesSnsMessage(): void
+    {
+        $context = $this->createMock(SnsQsContext::class);
+        $context->expects($this->once())
+            ->method('createMessage')
+            ->willReturn(new SnsQsMessage());
+
+        $sqsConsumer = $this->createMock(SqsConsumer::class);
+        $sqsConsumer->expects($this->once())
+            ->method('receive')
+            ->willReturn(new SqsMessage(json_encode([
+                'Type' => 'Notification',
+                'TopicArn' => 'arn:aws:sns:us-east-2:12345:topic-name',
+                'Message' => 'The Body',
+                'MessageAttributes' => [
+                    'Headers' => [
+                        'Type' => 'String',
+                        'Value' => base64_encode('[{"headerKey":"headerVal"},{"propKey": "propVal"}]'),
+                    ],
+                ],
+            ])));
+
+        $consumer = new SnsQsConsumer($context, $sqsConsumer, new SnsQsQueue('queue'));
+        $result = $consumer->receive();
+
+        $this->assertInstanceOf(SnsQsMessage::class, $result);
+        $this->assertSame('The Body', $result->getBody());
+        $this->assertSame(['headerKey' => 'headerVal'], $result->getHeaders());
+        $this->assertSame(['propKey' => 'propVal'], $result->getProperties());
+    }
+
+    public function testReceivesSnsMessageWithUnencodedHeaders(): void
     {
         $context = $this->createMock(SnsQsContext::class);
         $context->expects($this->once())