JAMES-3977 Add bytes preservation in manager and mapper contracts

This was not preserved for the Cassandra mailbox, leading to
innacurrate backpressure and down the line to OutOfMemoryExceptions
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index f70d7f5..e7d875a 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -2923,6 +2923,13 @@
             MessageResult messageResult = inboxManager.getMessages(MessageRange.one(composeId1.getUid()), FetchGroup.MINIMAL, session).next();
             assertThat(messageResult.getSaveDate()).isPresent();
         }
+
+        @Test
+        void fullFetchGroupShouldPreserveBytesSequence() throws Exception {
+            ComposedMessageId composeId1 = inboxManager.appendMessage(AppendCommand.builder().build(message), session).getId();
+            MessageResult messageResult = inboxManager.getMessages(MessageRange.one(composeId1.getUid()), FetchGroup.FULL_CONTENT, session).next();
+            assertThat(messageResult.getFullContent().asBytesSequence()).isPresent();
+        }
     }
 
     @Nested
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMetadata.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMetadata.java
index 56e1203..c741f7e 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMetadata.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMetadata.java
@@ -269,6 +269,16 @@
         }
 
         @Override
+        public Optional<byte[][]> getFullBytes() {
+            return delegate.getFullBytes();
+        }
+
+        @Override
+        public Optional<byte[][]> getHeadersBytes() {
+            return delegate.getHeadersBytes();
+        }
+
+        @Override
         public ThreadId getThreadId() {
             return delegate.getThreadId();
         }
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMapperProvider.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMapperProvider.java
index 4667385..286057e 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMapperProvider.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMapperProvider.java
@@ -113,7 +113,8 @@
             Capabilities.ANNOTATION,
             Capabilities.MOVE,
             Capabilities.ACL_STORAGE,
-            Capabilities.UNIQUE_MESSAGE_ID);
+            Capabilities.UNIQUE_MESSAGE_ID,
+            Capabilities.FULL_BYTES);
     }
 
     @Override
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java
index 29726f4..4a743ec 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java
@@ -132,4 +132,9 @@
     public Optional<byte[][]> getFullBytes() {
         return message.getFullBytes();
     }
+
+    @Override
+    public Optional<byte[][]> getHeadersBytes() {
+        return message.getHeadersBytes();
+    }
 }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java
index ffe9b02..1fb0a44 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java
@@ -106,11 +106,23 @@
 
     @Override
     public InputStream getHeaderContent() throws IOException {
-        long headerEnd = bodyStartOctet;
-        if (headerEnd < 0) {
-            headerEnd = 0;
+        return new BoundedInputStream(content.getInputStream(), headerSize());
+    }
+
+    private long headerSize() {
+        return Math.max(0, bodyStartOctet);
+    }
+
+    @Override
+    public Optional<byte[][]> getHeadersBytes() {
+        try {
+            if (headerSize() == content.size()) {
+                return content.asBytesSequence();
+            }
+        } catch (MailboxException e) {
+            return Optional.empty();
         }
-        return new BoundedInputStream(content.getInputStream(), headerEnd);
+        return Optional.empty();
     }
 
     @Override
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MapperProvider.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MapperProvider.java
index 2db1faa..b6bd054 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MapperProvider.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MapperProvider.java
@@ -42,7 +42,9 @@
         UNIQUE_MESSAGE_ID,
         THREAD_SAFE_FLAGS_UPDATE,
         INCREMENTAL_APPLICABLE_FLAGS,
-        ACL_STORAGE
+        ACL_STORAGE,
+        FULL_BYTES,
+        HEADER_BYTES
     }
 
     List<Capabilities> getSupportedCapabilities();
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
index b4514d3..3d16316 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
@@ -73,7 +73,7 @@
 
     private static final char DELIMITER = '.';
     private static final int LIMIT = 10;
-    private static final int BODY_START = 16;
+    private static final int BODY_START = 19;
     private static final UidValidity UID_VALIDITY = UidValidity.of(42);
 
     private static final String CUSTOMS_USER_FLAGS_VALUE = "CustomsFlags";
@@ -115,12 +115,12 @@
         benwaInboxMailbox = createMailbox(MailboxPath.forUser(BENWA, "INBOX"));
         benwaWorkMailbox = createMailbox(MailboxPath.forUser(BENWA, "INBOX" + DELIMITER + "work"));
 
-        message1 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test1 \n\nBody1\n.\n", BODY_START, new PropertyBuilder());
-        message2 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test2 \n\nBody2\n.\n", BODY_START, new PropertyBuilder());
-        message3 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test3 \n\nBody3\n.\n", BODY_START, new PropertyBuilder());
-        message4 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test4 \n\nBody4\n.\n", BODY_START, new PropertyBuilder());
-        message5 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test5 \n\nBody5\n.\n", BODY_START, new PropertyBuilder());
-        message6 = createMessage(benwaWorkMailbox, mapperProvider.generateMessageId(), "Subject: Test6 \n\nBody6\n.\n", BODY_START, new PropertyBuilder());
+        message1 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test1 \r\n\r\nBody1\n.\n", BODY_START, new PropertyBuilder());
+        message2 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test2 \r\n\r\nBody2\n.\n", BODY_START, new PropertyBuilder());
+        message3 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test3 \r\n\r\nBody3\n.\n", BODY_START, new PropertyBuilder());
+        message4 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test4 \r\n\r\nBody4\n.\n", BODY_START, new PropertyBuilder());
+        message5 = createMessage(benwaInboxMailbox, mapperProvider.generateMessageId(), "Subject: Test5 \r\n\r\nBody5\n.\n", BODY_START, new PropertyBuilder());
+        message6 = createMessage(benwaWorkMailbox, mapperProvider.generateMessageId(), "Subject: Test6 \r\n\r\nBody6\n.\n", BODY_START, new PropertyBuilder());
     }
 
     @Test
@@ -213,6 +213,54 @@
     }
 
     @Test
+    void getFullBytesShouldBePresentWhenFullFetchType() throws MailboxException, IOException {
+        Assume.assumeTrue(mapperProvider.getSupportedCapabilities().contains(Capabilities.FULL_BYTES));
+        saveMessages();
+        int limit = 10;
+        MailboxMessage next = messageMapper.findInMailbox(benwaInboxMailbox, MessageRange.one(message1.getUid()), FetchType.FULL, limit).next();
+        assertThat(next.getFullBytes())
+            .isNotEmpty();
+    }
+
+    @Test
+    void getFullBytesShouldBePresentWhenHeadersFetchType() throws Exception {
+        Assume.assumeTrue(mapperProvider.getSupportedCapabilities().contains(Capabilities.FULL_BYTES));
+        saveMessages();
+        int limit = 10;
+        assertThat(messageMapper.findInMailbox(benwaInboxMailbox, MessageRange.one(message1.getUid()), FetchType.HEADERS, limit).next().getFullBytes())
+            .get()
+            .satisfies(b -> assertThat(b.length).isEqualTo(1));
+    }
+
+    @Test
+    void getHeadersBytesShouldBePresentWhenHeadersFetchType() throws Exception {
+        Assume.assumeTrue(mapperProvider.getSupportedCapabilities().contains(Capabilities.HEADER_BYTES));
+        saveMessages();
+        int limit = 10;
+        assertThat(messageMapper.findInMailbox(benwaInboxMailbox, MessageRange.one(message1.getUid()), FetchType.HEADERS, limit).next().getHeadersBytes())
+            .isNotEmpty();
+    }
+
+    @Test
+    void getFullBytesShouldBePresentWhenAttachmentMetadataFetchType() throws Exception {
+        Assume.assumeTrue(mapperProvider.getSupportedCapabilities().contains(Capabilities.FULL_BYTES));
+        saveMessages();
+        int limit = 10;
+        assertThat(messageMapper.findInMailbox(benwaInboxMailbox, MessageRange.one(message1.getUid()), FetchType.ATTACHMENTS_METADATA, limit).next().getFullBytes())
+            .get()
+            .satisfies(b -> assertThat(b.length).isEqualTo(1));
+    }
+
+    @Test
+    void getHeadersBytesShouldBePresentWhenAttachmentMetadataFetchType() throws Exception {
+        Assume.assumeTrue(mapperProvider.getSupportedCapabilities().contains(Capabilities.HEADER_BYTES));
+        saveMessages();
+        int limit = 10;
+        assertThat(messageMapper.findInMailbox(benwaInboxMailbox, MessageRange.one(message1.getUid()), FetchType.ATTACHMENTS_METADATA, limit).next().getHeadersBytes())
+            .isNotEmpty();
+    }
+
+    @Test
     void messagesCanBeRetrievedInMailboxWithRangeTypeRange() throws MailboxException, IOException {
         saveMessages();
         Iterator<MailboxMessage> retrievedMessageIterator = messageMapper