This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-4.10.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.10.x by this push:
new 848f70660ca CAMEL-22037: Provide fix for TextPlainEntity along with a
unit test (#17967)
848f70660ca is described below
commit 848f70660ca11adf3c40fbc04998cc9c047647d8
Author: Jürgen Link <[email protected]>
AuthorDate: Tue May 6 13:13:45 2025 +0200
CAMEL-22037: Provide fix for TextPlainEntity along with a unit test (#17967)
* Provide fix for TextPlainEntity along with a unit test
* Add Apache license header, alter test to use complete HTTP request as
input
* Duplicate EntityParserTest and provide test data provider with the
ability to use LF or CRLF line endings
* Add Apache license header
* remove debug output
* Format code, rename unit test method
---------
Co-authored-by: jlink <[email protected]>
---
.../component/as2/api/entity/TextPlainEntity.java | 2 +-
.../entity/EntityParserContentLineEndingTest.java | 333 +++++++++++++++++++++
.../api/entity/EntityParserContentProvider.java | 144 +++++++++
.../as2/api/entity/TextPlainEntityTest.java | 51 ++++
4 files changed, 529 insertions(+), 1 deletion(-)
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/TextPlainEntity.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/TextPlainEntity.java
index 00f5659fb68..9c308b2ea21 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/TextPlainEntity.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/TextPlainEntity.java
@@ -54,7 +54,7 @@ public class TextPlainEntity extends MimeEntity {
}
// Write out content
-
canonicalOutstream.write(content.getBytes(StandardCharsets.US_ASCII), 0,
content.length());
+ outstream.write(content.getBytes(StandardCharsets.US_ASCII), 0,
content.length());
}
}
diff --git
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserContentLineEndingTest.java
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserContentLineEndingTest.java
new file mode 100644
index 00000000000..fa85444aebf
--- /dev/null
+++
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserContentLineEndingTest.java
@@ -0,0 +1,333 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.as2.api.entity;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.camel.component.as2.api.AS2Header;
+import org.apache.camel.component.as2.api.io.AS2SessionInputBuffer;
+import org.apache.camel.component.as2.api.util.EntityUtils;
+import org.apache.camel.component.as2.api.util.HttpMessageUtils;
+import org.apache.hc.core5.http.*;
+import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics;
+import org.apache.hc.core5.http.impl.EnglishReasonPhraseCatalog;
+import org.apache.hc.core5.http.io.entity.BasicHttpEntity;
+import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.bc.BcX509ExtensionUtils;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.cms.CMSAlgorithm;
+import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
+import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.OutputEncryptor;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.apache.camel.component.as2.api.entity.EntityParserTest.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+public class EntityParserContentLineEndingTest {
+
+ private static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
+
+ //
+ // certificate serial number seed.
+ //
+ int serialNo = 1;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ }
+
+ @AfterEach
+ public void tearDown() throws Exception {
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "\r", "" })
+ public void parseMessageDispositionNotificationReportMessageTest(String
carriageReturn) throws Exception {
+ HttpResponse response = new BasicClassicHttpResponse(
+ HttpStatus.SC_OK,
EnglishReasonPhraseCatalog.INSTANCE.getReason(HttpStatus.SC_OK, null));
+ response.setVersion(new ProtocolVersion("HTTP", 1, 1));
+ HttpMessageUtils.setHeaderValue(response,
AS2Header.CONTENT_TRANSFER_ENCODING,
+ DISPOSITION_NOTIFICATION_CONTENT_TRANSFER_ENCODING);
+
+ InputStream is = new ByteArrayInputStream(
+
EntityParserContentProvider.dispositionNotificationReportContent(carriageReturn)
+
.getBytes(DISPOSITION_NOTIFICATION_REPORT_CONTENT_CHARSET_NAME));
+ BasicHttpEntity entity = new BasicHttpEntity(is,
ContentType.parse(REPORT_CONTENT_TYPE_VALUE));
+ EntityUtils.setMessageEntity(response, entity);
+
+ EntityParser.parseAS2MessageEntity(response);
+ HttpEntity parsedEntity = EntityUtils.getMessageEntity(response);
+ assertNotNull(parsedEntity, "Unexpected Null message disposition
notification report entity");
+ assertTrue(parsedEntity instanceof
DispositionNotificationMultipartReportEntity,
+ "Unexpected type for message disposition notification report
entity");
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "\r", "" })
+ public void parseMessageDispositionNotificationReportBodyTest(String
carriageReturn) throws Exception {
+
+ DispositionNotificationMultipartReportEntity
dispositionNotificationMultipartReportEntity
+ =
createMdnEntity(EntityParserContentProvider.dispositionNotificationReportContent(carriageReturn),
+ DISPOSITION_NOTIFICATION_REPORT_CONTENT_BOUNDARY);
+
+ assertNotNull(dispositionNotificationMultipartReportEntity,
+ "Unexpected Null disposition notification multipart entity");
+ assertEquals(2,
dispositionNotificationMultipartReportEntity.getPartCount(), "Unexpected number
of body parts");
+
+ assertTrue(dispositionNotificationMultipartReportEntity.getPart(0)
instanceof TextPlainEntity,
+ "Unexpected type for first body part");
+ assertTrue(dispositionNotificationMultipartReportEntity.getPart(1)
instanceof AS2MessageDispositionNotificationEntity,
+ "Unexpected type for second body part");
+ }
+
+ // verify that parsing the Disposition Notification Report has made no
alteration to the entity's body part fields
+ @ParameterizedTest
+ @ValueSource(strings = { "\r", "" })
+ public void messageDispositionNotificationReportBodyContentTest(String
carriageReturn) throws Exception {
+
+ DispositionNotificationMultipartReportEntity
dispositionNotificationMultipartReportEntity
+ =
createMdnEntity(EntityParserContentProvider.dispositionNotificationReportContentUnfolded(carriageReturn),
+ DISPOSITION_NOTIFICATION_REPORT_CONTENT_BOUNDARY);
+
+ String expectedContent = String.format("%s\r\n%s\r\n%s",
+ new BasicHeader(AS2Header.CONTENT_TYPE,
REPORT_CONTENT_TYPE_VALUE),
+ new BasicHeader(AS2Header.CONTENT_TRANSFER_ENCODING,
DISPOSITION_NOTIFICATION_REPORT_CONTENT_TRANSFER_ENCODING),
+
EntityParserContentProvider.dispositionNotificationReportContentUnfolded(carriageReturn));
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ dispositionNotificationMultipartReportEntity.writeTo(out);
+
+ assertEquals(expectedContent,
out.toString(DISPOSITION_NOTIFICATION_CONTENT_CHARSET_NAME));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "\r", "" })
+ public void parseTextPlainBodyTest(String carriageReturn) throws Exception
{
+
+ InputStream is = new ByteArrayInputStream(
+
EntityParserContentProvider.textPlainContent(carriageReturn).getBytes(TEXT_PLAIN_CONTENT_CHARSET_NAME));
+ AS2SessionInputBuffer inbuffer
+ = new AS2SessionInputBuffer(new BasicHttpTransportMetrics(),
DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
+
+ TextPlainEntity textPlainEntity =
EntityParser.parseTextPlainEntityBody(inbuffer, is, TEXT_PLAIN_CONTENT_BOUNDARY,
+ TEXT_PLAIN_CONTENT_CHARSET_NAME,
TEXT_PLAIN_CONTENT_TRANSFER_ENCODING);
+
+ String text = textPlainEntity.getText();
+
+
assertEquals(EntityParserContentProvider.expectedTextPlainContent(carriageReturn),
text, "Unexpected text");
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "\r", "" })
+ public void parseTextPlainBodyTestWithEntityMarshalling(String
carriageReturn) throws Exception {
+
+ InputStream is = new ByteArrayInputStream(
+
EntityParserContentProvider.textPlainContent(carriageReturn).getBytes(TEXT_PLAIN_CONTENT_CHARSET_NAME));
+ AS2SessionInputBuffer inbuffer
+ = new AS2SessionInputBuffer(new BasicHttpTransportMetrics(),
DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
+
+ TextPlainEntity textPlainEntity =
EntityParser.parseTextPlainEntityBody(inbuffer, is, TEXT_PLAIN_CONTENT_BOUNDARY,
+ TEXT_PLAIN_CONTENT_CHARSET_NAME,
TEXT_PLAIN_CONTENT_TRANSFER_ENCODING);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ textPlainEntity.setMainBody(true);
+ textPlainEntity.writeTo(out);
+ String text = out.toString();
+
+
assertEquals(EntityParserContentProvider.expectedTextPlainContent(carriageReturn),
text, "Unexpected text");
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "\r", "" })
+ public void parseMessageDispositionNotificationBodyTest(String
carriageReturn) throws Exception {
+
+ InputStream is = new ByteArrayInputStream(
+
EntityParserContentProvider.dispositionNotificationContent(carriageReturn)
+
.getBytes(DISPOSITION_NOTIFICATION_CONTENT_CHARSET_NAME));
+ AS2SessionInputBuffer inbuffer
+ = new AS2SessionInputBuffer(new BasicHttpTransportMetrics(),
DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
+
+ AS2MessageDispositionNotificationEntity
messageDispositionNotificationEntity = EntityParser
+ .parseMessageDispositionNotificationEntityBody(inbuffer, is,
DISPOSITION_NOTIFICATION_CONTENT_BOUNDARY,
+ DISPOSITION_NOTIFICATION_CONTENT_CHARSET_NAME);
+
+ assertEquals(EXPECTED_REPORTING_UA,
messageDispositionNotificationEntity.getReportingUA(),
+ "Unexpected Reporting UA value");
+ assertEquals(EXPECTED_MTN_NAME,
messageDispositionNotificationEntity.getMtnName(), "Unexpected MTN Name");
+ assertEquals(EXPECTED_ORIGINAL_RECIPIENT,
+
messageDispositionNotificationEntity.getExtensionFields().get("Original-Recipient"),
+ "Unexpected Original Recipient");
+ assertEquals(EXPECTED_FINAL_RECIPIENT,
messageDispositionNotificationEntity.getFinalRecipient(),
+ "Unexpected Final Reciptient");
+ assertEquals(EXPECTED_ORIGINAL_MESSAGE_ID,
messageDispositionNotificationEntity.getOriginalMessageId(),
+ "Unexpected Original Message ID");
+ assertEquals(EXPECTED_DISPOSITION_MODE,
messageDispositionNotificationEntity.getDispositionMode(),
+ "Unexpected Disposition Mode");
+
assertNotNull(messageDispositionNotificationEntity.getDispositionModifier(),
"Unexpected Null Disposition Modifier");
+ assertEquals(EXPECTED_DISPOSITION_MODIFIER,
messageDispositionNotificationEntity.getDispositionModifier().getModifier(),
+ "Unexpected Disposition Modifier");
+ assertEquals(EXPECTED_DISPOSITION_TYPE,
messageDispositionNotificationEntity.getDispositionType(),
+ "Unexpected Disposition Type");
+ assertArrayEquals(EXPECTED_FAILURE,
messageDispositionNotificationEntity.getFailureFields(),
+ "Unexpected Failure Array value");
+ assertArrayEquals(EXPECTED_ERROR,
messageDispositionNotificationEntity.getErrorFields(),
+ "Unexpected Error Array value");
+ assertArrayEquals(EXPECTED_WARNING,
messageDispositionNotificationEntity.getWarningFields(),
+ "Unexpected Warning Array value");
+
assertNotNull(messageDispositionNotificationEntity.getReceivedContentMic(),
"Unexpected Null Received Content MIC");
+ assertEquals(EXPECTED_ENCODED_MESSAGE_DIGEST,
+
messageDispositionNotificationEntity.getReceivedContentMic().getEncodedMessageDigest(),
+ "Unexpected Encoded Message Digest");
+ assertEquals(EXPECTED_DIGEST_ALGORITHM_ID,
+
messageDispositionNotificationEntity.getReceivedContentMic().getDigestAlgorithmId(),
+ "Unexpected Digest Algorithm ID");
+ }
+
+ @Test
+ public void parseEnvelopedBodyTest() throws Exception {
+
+ Security.addProvider(new BouncyCastleProvider());
+
+ //
+ // set up our certificates
+ //
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
+
+ kpg.initialize(1024, new SecureRandom());
+
+ String issueDN = "O=Punkhorn Software, C=US";
+ KeyPair issueKP = kpg.generateKeyPair();
+ X509Certificate issuerCertificate = makeCertificate(issueKP, issueDN,
issueKP, issueDN);
+
+ //
+ // certificate we encrypt against
+ //
+ String encryptDN = "CN=William J. Collins, [email protected],
O=Punkhorn Software, C=US";
+ KeyPair encryptKP = kpg.generateKeyPair();
+ X509Certificate encryptionCertificate = makeCertificate(encryptKP,
encryptDN, issueKP, issueDN);
+
+ List<X509Certificate> certList = new ArrayList<>();
+
+ certList.add(encryptionCertificate);
+ certList.add(issuerCertificate);
+
+ //
+ // Create generator
+ //
+ CMSEnvelopedDataGenerator cmsEnvelopeDataGenerator = new
CMSEnvelopedDataGenerator();
+
+ JceKeyTransRecipientInfoGenerator recipientInfoGenerator = new
JceKeyTransRecipientInfoGenerator(encryptionCertificate);
+
cmsEnvelopeDataGenerator.addRecipientInfoGenerator(recipientInfoGenerator);
+
+ //
+ // Create encryptor
+ //
+ OutputEncryptor contentEncryptor = new
JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CCM).build();
+
+ //
+ // Build Enveloped Entity
+ //
+ TextPlainEntity textEntity = new TextPlainEntity("This is a super
secret messatge!", "US-ASCII", "7bit", false);
+ ApplicationPkcs7MimeEnvelopedDataEntity applicationPkcs7MimeEntity =
new ApplicationPkcs7MimeEnvelopedDataEntity(
+ textEntity, cmsEnvelopeDataGenerator, contentEncryptor,
"binary", true);
+
+ MimeEntity decryptedMimeEntity =
applicationPkcs7MimeEntity.getEncryptedEntity(encryptKP.getPrivate());
+ assertEquals("text/plain; charset=US-ASCII",
decryptedMimeEntity.getContentType(),
+ "Decrypted entity has unexpected content type");
+ assertEquals("This is a super secret messatge!", ((TextPlainEntity)
decryptedMimeEntity).getText(),
+ "Decrypted entity has unexpected content");
+ }
+
+ /**
+ * create a basic X509 certificate from the given keys
+ */
+ private X509Certificate makeCertificate(KeyPair subKP, String subDN,
KeyPair issKP, String issDN)
+ throws GeneralSecurityException, IOException,
OperatorCreationException {
+ PublicKey subPub = subKP.getPublic();
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v3CertificateBuilder v3CertGen = new JcaX509v3CertificateBuilder(
+ new X500Name(issDN),
+ BigInteger.valueOf(serialNo++), new
Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 *
100)), new X500Name(subDN), subPub);
+
+ v3CertGen.addExtension(Extension.subjectKeyIdentifier, false,
createSubjectKeyId(subPub));
+
+ v3CertGen.addExtension(Extension.authorityKeyIdentifier, false,
createAuthorityKeyId(issPub));
+
+ return new
JcaX509CertificateConverter().setProvider("BC").getCertificate(
+ v3CertGen.build(new
JcaContentSignerBuilder("MD5withRSA").setProvider("BC").build(issPriv)));
+ }
+
+ private AuthorityKeyIdentifier createAuthorityKeyId(PublicKey pub) throws
IOException {
+ SubjectPublicKeyInfo info =
SubjectPublicKeyInfo.getInstance(pub.getEncoded());
+
+ BcX509ExtensionUtils utils = new BcX509ExtensionUtils();
+ return utils.createAuthorityKeyIdentifier(info);
+ }
+
+ private DispositionNotificationMultipartReportEntity
createMdnEntity(String reportContent, String boundary)
+ throws Exception {
+ InputStream is = new ByteArrayInputStream(
+
reportContent.getBytes(DISPOSITION_NOTIFICATION_REPORT_CONTENT_CHARSET_NAME));
+ AS2SessionInputBuffer inbuffer
+ = new AS2SessionInputBuffer(new BasicHttpTransportMetrics(),
DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
+
+ DispositionNotificationMultipartReportEntity
dispositionNotificationMultipartReportEntity = EntityParser
+ .parseMultipartReportEntityBody(inbuffer, is, boundary,
+ DISPOSITION_NOTIFICATION_REPORT_CONTENT_CHARSET_NAME,
+
DISPOSITION_NOTIFICATION_REPORT_CONTENT_TRANSFER_ENCODING);
+
+ assertNotNull(dispositionNotificationMultipartReportEntity,
+ "Unexpected Null disposition notification multipart entity");
+
+ return dispositionNotificationMultipartReportEntity;
+ }
+
+ static SubjectKeyIdentifier createSubjectKeyId(PublicKey pub) throws
IOException {
+ SubjectPublicKeyInfo info =
SubjectPublicKeyInfo.getInstance(pub.getEncoded());
+
+ return new BcX509ExtensionUtils().createSubjectKeyIdentifier(info);
+ }
+}
diff --git
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserContentProvider.java
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserContentProvider.java
new file mode 100644
index 00000000000..81c80dc0188
--- /dev/null
+++
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserContentProvider.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.as2.api.entity;
+
+public class EntityParserContentProvider {
+
+ public static String dispositionNotificationReportContent(String
contentLineEnding) {
+ return """
+ \r
+ ------=_Part_56_1672293592.1028122454656\r
+ Content-Type: text/plain\r
+ Content-Transfer-Encoding: 7bit\r
+ \r
+ MDN for -_CR
+ Message ID: <200207310834482A70BF63@\\"~~foo~~\\">_CR
+ From: "\\" as2Name \\""_CR
+ To: "0123456780000" Received on: 2002-07-31 at 09:34:14
(EDT)_CR
+ Status: processed_CR
+ Comment: This is not a guarantee that the message has_CR
+ been completely processed or &understood by the receiving_CR
+ translator_CR
+ \r
+ ------=_Part_56_1672293592.1028122454656\r
+ Content-Type: message/disposition-notification\r
+ Content-Transfer-Encoding: 7bit\r
+ \r
+ Reporting-UA: AS2 Server\r
+ MDN-Gateway: dns; example.com\r
+ Original-Recipient: rfc822; 0123456780000\r
+ Final-Recipient: rfc822; 0123456780000\r
+ Original-Message-ID: <200207310834482A70BF63@\\"~~foo~~\\">\r
+ Disposition: automatic-action/MDN-sent-automatically;\r
+ processed/warning: you're awesome\r
+ Failure: oops-a-failure\r
+ Error: oops-an-error\r
+ Warning: oops-a-warning\r
+ Received-content-MIC: 7v7F++fQaNB1sVLFtMRp+dF+eG4=, sha1\r
+ \r
+ ------=_Part_56_1672293592.1028122454656--\r
+ """
+ .replaceAll("_CR", contentLineEnding);
+ }
+
+ public static String dispositionNotificationReportContentUnfolded(String
contentLineEnding) {
+ return """
+ \r
+ ------=_Part_56_1672293592.1028122454656\r
+ Content-Type: text/plain\r
+ Content-Transfer-Encoding: 7bit\r
+ \r
+ MDN for -_CR
+ Message ID: <200207310834482A70BF63@\\"~~foo~~\\">_CR
+ From: "\\" as2Name \\""_CR
+ To: "0123456780000""
+ Received on: 2002-07-31 at 09:34:14 (EDT)_CR
+ Status: processed_CR
+ Comment: This is not a guarantee that the message has_CR
+ been completely processed or &understood by the receiving_CR
+ translator_CR
+ \r
+ ------=_Part_56_1672293592.1028122454656\r
+ Content-Type: message/disposition-notification\r
+ Content-Transfer-Encoding: 7bit\r
+ \r
+ Reporting-UA: AS2 Server\r
+ MDN-Gateway: dns; example.com\r
+ Original-Recipient: rfc822; 0123456780000\r
+ Final-Recipient: rfc822; 0123456780000\r
+ Original-Message-ID: <200207310834482A70BF63@\\"~~foo~~\\">\r
+ Disposition: automatic-action/MDN-sent-automatically;
rocessed/warning: you're awesome\r
+ Failure: oops-a-failure\r
+ Error: oops-an-error\r
+ Warning: oops-a-warning\r
+ Received-content-MIC: 7v7F++fQaNB1sVLFtMRp+dF+eG4=, sha1\r
+ \r
+ ------=_Part_56_1672293592.1028122454656--\r
+ """
+ .replaceAll("_CR", contentLineEnding);
+ }
+
+ public static String textPlainContent(String contentLineEnding) {
+ return """
+ MDN for -_CR
+ Message ID: <200207310834482A70BF63@\\"~~foo~~\\">_CR
+ From: "\\" as2Name \\""_CR
+ To: "0123456780000" Received on: 2002-07-31 at 09:34:14
(EDT)_CR
+ Status: processed_CR
+ Comment: This is not a guarantee that the message has_CR
+ been completely processed or &understood by the receiving_CR
+ translator_CR
+ \r
+ ------=_Part_56_1672293592.1028122454656--\r
+ """
+ .replaceAll("_CR", contentLineEnding);
+ }
+
+ public static String expectedTextPlainContent(String contentLineEnding) {
+
+ return """
+ MDN for -_CR
+ Message ID: <200207310834482A70BF63@\\"~~foo~~\\">_CR
+ From: "\\" as2Name \\""_CR
+ To: "0123456780000" Received on: 2002-07-31 at 09:34:14
(EDT)_CR
+ Status: processed_CR
+ Comment: This is not a guarantee that the message has_CR
+ been completely processed or &understood by the receiving_CR
+ translator_CR
+ """
+ .replaceAll("_CR", contentLineEnding);
+ }
+
+ public static String dispositionNotificationContent(String
contentLineEnding) {
+ return """
+ Reporting-UA: AS2 Server_CR
+ MDN-Gateway: dns; example.com_CR
+ Original-Recipient: rfc822; 0123456780000_CR
+ Final-Recipient: rfc822; 0123456780000_CR
+ Original-Message-ID: <200207310834482A70BF63@\\"~~foo~~\\">_CR
+ Disposition: automatic-action/MDN-sent-automatically;_CR
+ processed/warning: you're awesome_CR
+ Failure: oops-a-failure_CR
+ Error: oops-an-error_CR
+ Warning: oops-a-warning_CR
+ Received-content-MIC: 7v7F++fQaNB1sVLFtMRp+dF+eG4=, sha1_CR
+ \r
+ ------=_Part_56_1672293592.1028122454656--\r
+ """
+ .replaceAll("_CR", contentLineEnding);
+ }
+}
diff --git
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/TextPlainEntityTest.java
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/TextPlainEntityTest.java
new file mode 100644
index 00000000000..c4c28124b4a
--- /dev/null
+++
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/TextPlainEntityTest.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.as2.api.entity;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.hc.core5.http.HttpException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TextPlainEntityTest {
+
+ @Test
+ void test_parse() throws IOException, HttpException {
+
+ String parsedMimeMessage;
+ try (MimeEntity mimeEntity =
EntityParser.parseEntity(MESSAGE.getBytes(StandardCharsets.US_ASCII))) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ mimeEntity.writeTo(out);
+ parsedMimeMessage = new String(out.toByteArray(),
StandardCharsets.US_ASCII);
+ }
+
+ Assertions.assertEquals(parsedMimeMessage, MESSAGE);
+ }
+
+ String MESSAGE = """
+ Content-Type: text/plain; charset=US-ASCII\r
+ Content-Transfer-Encoding: binary\r
+ \r
+ <root>
+ \t<item/>
+ </root>
+ """;
+
+}