blob: 78d9d87aad0ff02f0bf55f3e64009a63f2538a5f [file] [log] [blame]
/*
* 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.dataformat.mime.multipart;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.util.ByteArrayDataSource;
import org.apache.camel.Exchange;
import org.apache.camel.attachment.Attachment;
import org.apache.camel.attachment.AttachmentMessage;
import org.apache.camel.attachment.DefaultAttachment;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.support.DefaultExchange;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.apache.camel.util.IOHelper;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.StringContains.containsString;
import static org.hamcrest.core.StringStartsWith.startsWith;
public class MimeMultipartDataFormatTest extends CamelTestSupport {
private Exchange exchange;
private AttachmentMessage in;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
exchange = new DefaultExchange(context);
in = exchange.getIn(AttachmentMessage.class);
}
@Test
public void roundtripWithTextAttachments() throws IOException {
String attContentType = "text/plain";
String attText = "Attachment Text";
String attFileName = "Attachment File Name";
in.setBody("Body text");
in.setHeader(Exchange.CONTENT_TYPE, "text/plain;charset=iso8859-1;other-parameter=true");
in.setHeader(Exchange.CONTENT_ENCODING, "UTF8");
Map<String, String> headers = new HashMap<>();
headers.put("Content-Description", "Sample Attachment Data");
headers.put("X-AdditionalData", "additional data");
addAttachment(attContentType, attText, attFileName, headers);
Exchange result = template.send("direct:roundtrip", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text", out.getBody(String.class));
assertThat(out.getHeader(Exchange.CONTENT_TYPE, String.class), startsWith("text/plain"));
assertEquals("UTF8", out.getHeader(Exchange.CONTENT_ENCODING));
assertTrue(out.hasAttachments());
assertEquals(1, out.getAttachmentNames().size());
assertThat(out.getAttachmentNames(), hasItem(attFileName));
Attachment att = out.getAttachmentObject(attFileName);
DataHandler dh = att.getDataHandler();
assertNotNull(dh);
assertEquals(attContentType, dh.getContentType());
InputStream is = dh.getInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOHelper.copyAndCloseInput(is, os);
assertEquals(attText, new String(os.toByteArray()));
assertEquals("Sample Attachment Data", att.getHeader("content-description"));
assertEquals("additional data", att.getHeader("X-AdditionalData"));
}
@Test
public void roundtripWithTextAttachmentsHeadersInline() throws IOException {
String attContentType = "text/plain";
String attText = "Attachment Text";
String attFileName = "Attachment File Name";
in.setBody("Body text");
in.setHeader(Exchange.CONTENT_TYPE, "text/plain;charset=iso8859-1;other-parameter=true");
in.setHeader(Exchange.CONTENT_ENCODING, "UTF8");
addAttachment(attContentType, attText, attFileName);
Exchange result = template.send("direct:roundtripinlineheaders", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text", out.getBody(String.class));
assertThat(out.getHeader(Exchange.CONTENT_TYPE, String.class), startsWith("text/plain"));
assertEquals("UTF8", out.getHeader(Exchange.CONTENT_ENCODING));
assertTrue(out.hasAttachments());
assertEquals(1, out.getAttachmentNames().size());
assertThat(out.getAttachmentNames(), hasItem(attFileName));
DataHandler dh = out.getAttachment(attFileName);
assertNotNull(dh);
assertEquals(attContentType, dh.getContentType());
InputStream is = dh.getInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOHelper.copyAndCloseInput(is, os);
assertEquals(attText, new String(os.toByteArray()));
}
@Test
@Ignore("Fails on CI servers and some platforms - maybe due locale or something")
public void roundtripWithTextAttachmentsAndSpecialCharacters() throws IOException {
String attContentType = "text/plain";
String attText = "Attachment Text with special characters: \u00A9";
String attFileName = "Attachment File Name with special characters: \u00A9";
in.setBody("Body text with special characters: \u00A9");
in.setHeader(Exchange.CONTENT_TYPE, "text/plain");
in.setHeader(Exchange.CONTENT_ENCODING, "UTF8");
addAttachment(attContentType, attText, attFileName);
Exchange result = template.send("direct:roundtrip", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text with special characters: \u00A9", out.getBody(String.class));
assertThat(out.getHeader(Exchange.CONTENT_TYPE, String.class), startsWith("text/plain"));
assertEquals("UTF8", out.getHeader(Exchange.CONTENT_ENCODING));
assertTrue(out.hasAttachments());
assertEquals(1, out.getAttachmentNames().size());
assertThat(out.getAttachmentNames(), hasItem(attFileName));
DataHandler dh = out.getAttachment(attFileName);
assertNotNull(dh);
assertEquals(attContentType, dh.getContentType());
InputStream is = dh.getInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOHelper.copyAndCloseInput(is, os);
assertEquals(attText, new String(os.toByteArray()));
}
@Test
public void roundtripWithTextAttachmentsAndBinaryContent() throws IOException {
String attContentType = "text/plain";
String attText = "Attachment Text";
String attFileName = "Attachment File Name";
in.setBody("Body text");
in.setHeader(Exchange.CONTENT_TYPE, "text/plain;charset=iso8859-1;other-parameter=true");
addAttachment(attContentType, attText, attFileName);
Exchange result = template.send("direct:roundtripbinarycontent", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text", out.getBody(String.class));
assertThat(out.getHeader(Exchange.CONTENT_TYPE, String.class), startsWith("text/plain"));
assertEquals("iso8859-1", out.getHeader(Exchange.CONTENT_ENCODING));
assertTrue(out.hasAttachments());
assertEquals(1, out.getAttachmentNames().size());
assertThat(out.getAttachmentNames(), hasItem(attFileName));
DataHandler dh = out.getAttachment(attFileName);
assertNotNull(dh);
assertEquals(attContentType, dh.getContentType());
InputStream is = dh.getInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOHelper.copyAndCloseInput(is, os);
assertEquals(attText, new String(os.toByteArray()));
}
@Test
public void roundtripWithBinaryAttachments() throws IOException {
String attContentType = "application/binary";
byte[] attText = {0, 1, 2, 3, 4, 5, 6, 7};
String attFileName = "Attachment File Name";
in.setBody("Body text");
DataSource ds = new ByteArrayDataSource(attText, attContentType);
in.addAttachment(attFileName, new DataHandler(ds));
Exchange result = template.send("direct:roundtrip", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text", out.getBody(String.class));
assertTrue(out.hasAttachments());
assertEquals(1, out.getAttachmentNames().size());
assertThat(out.getAttachmentNames(), hasItem(attFileName));
DataHandler dh = out.getAttachment(attFileName);
assertNotNull(dh);
assertEquals(attContentType, dh.getContentType());
InputStream is = dh.getInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOHelper.copyAndCloseInput(is, os);
assertArrayEquals(attText, os.toByteArray());
}
@Test
public void roundtripWithBinaryAttachmentsAndBinaryContent() throws IOException {
String attContentType = "application/binary";
byte[] attText = {0, 1, 2, 3, 4, 5, 6, 7};
String attFileName = "Attachment File Name";
in.setBody("Body text");
DataSource ds = new ByteArrayDataSource(attText, attContentType);
in.addAttachment(attFileName, new DataHandler(ds));
Exchange result = template.send("direct:roundtripbinarycontent", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text", out.getBody(String.class));
assertTrue(out.hasAttachments());
assertEquals(1, out.getAttachmentNames().size());
assertThat(out.getAttachmentNames(), hasItem(attFileName));
DataHandler dh = out.getAttachment(attFileName);
assertNotNull(dh);
assertEquals(attContentType, dh.getContentType());
InputStream is = dh.getInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOHelper.copyAndCloseInput(is, os);
assertArrayEquals(attText, os.toByteArray());
}
@Test
public void roundtripWithoutAttachments() throws IOException {
in.setBody("Body text");
Exchange result = template.send("direct:roundtrip", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text", out.getBody(String.class));
assertFalse(out.hasAttachments());
}
@Test
public void roundtripWithoutAttachmentsToMultipart() throws IOException {
in.setBody("Body text");
Exchange result = template.send("direct:roundtripmultipart", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text", out.getBody(String.class));
assertFalse(out.hasAttachments());
}
@Test
public void roundtripWithoutAttachmentsAndContentType() throws IOException {
in.setBody("Body text");
in.setHeader("Content-Type", "text/plain");
Exchange result = template.send("direct:roundtrip", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text", out.getBody(String.class));
assertFalse(out.hasAttachments());
}
@Test
public void roundtripWithoutAttachmentsAndInvalidContentType() throws IOException {
in.setBody("Body text");
in.setHeader("Content-Type", "text?plain");
Exchange result = template.send("direct:roundtrip", exchange);
AttachmentMessage out = result.getOut(AttachmentMessage.class);
assertEquals("Body text", out.getBody(String.class));
assertFalse(out.hasAttachments());
}
@Test
public void marhsalOnlyMixed() throws IOException {
in.setBody("Body text");
in.setHeader("Content-Type", "text/plain");
Map<String, String> headers = new HashMap<>();
headers.put("Content-Description", "Sample Attachment Data");
headers.put("X-AdditionalData", "additional data");
addAttachment("application/octet-stream", "foobar", "attachment.bin", headers);
Exchange result = template.send("direct:marshalonlymixed", exchange);
assertThat(result.getOut().getHeader("Content-Type", String.class), startsWith("multipart/mixed"));
String resultBody = result.getOut().getBody(String.class);
assertThat(resultBody, containsString("Content-Description: Sample Attachment Data"));
}
@Test
public void marhsalOnlyRelated() throws IOException {
in.setBody("Body text");
in.setHeader("Content-Type", "text/plain");
addAttachment("application/octet-stream", "foobar", "attachment.bin");
Exchange result = template.send("direct:marshalonlyrelated", exchange);
assertThat(result.getOut().getHeader("Content-Type", String.class), startsWith("multipart/related"));
}
@Test
public void marhsalUnmarshalInlineHeaders() throws IOException {
in.setBody("Body text");
in.setHeader("Content-Type", "text/plain");
in.setHeader("included", "must be included");
in.setHeader("excluded", "should not be there");
in.setHeader("x-foo", "any value");
in.setHeader("x-bar", "also there");
in.setHeader("xbar", "should not be there");
addAttachment("application/octet-stream", "foobar", "attachment.bin");
Exchange intermediate = template.send("direct:marshalonlyinlineheaders", exchange);
String bodyStr = intermediate.getOut().getBody(String.class);
assertThat(bodyStr, containsString("must be included"));
assertThat(bodyStr, not(containsString("should not be there")));
assertThat(bodyStr, containsString("x-foo:"));
assertThat(bodyStr, containsString("x-bar:"));
assertThat(bodyStr, not(containsString("xbar")));
intermediate.setIn(intermediate.getOut());
intermediate.setOut(null);
intermediate.getIn().removeHeaders(".*");
intermediate.getIn().setHeader("included", "should be replaced");
Exchange out = template.send("direct:unmarshalonlyinlineheaders", intermediate);
assertEquals("Body text", out.getOut().getBody(String.class));
assertEquals("must be included", out.getOut().getHeader("included"));
assertNull(out.getOut().getHeader("excluded"));
assertEquals("any value", out.getOut().getHeader("x-foo"));
assertEquals("also there", out.getOut().getHeader("x-bar"));
}
@Test
public void unmarshalRelated() throws IOException {
in.setBody(new File("src/test/resources/multipart-related.txt"));
Attachment dh = unmarshalAndCheckAttachmentName("950120.aaCB@XIson.com");
assertNotNull(dh);
assertEquals("The fixed length records", dh.getHeader("Content-Description"));
assertEquals("header value1,header value2", dh.getHeader("X-Additional-Header"));
assertEquals(2, dh.getHeaderAsList("X-Additional-Header").size());
}
@Test
public void unmarshalWithoutId() throws IOException {
in.setBody(new File("src/test/resources/multipart-without-id.txt"));
unmarshalAndCheckAttachmentName("@camel.apache.org");
}
@Test
public void unmarshalNonMimeBody() {
in.setBody("This is not a MIME-Multipart");
Exchange out = template.send("direct:unmarshalonly", exchange);
assertNotNull(out.getOut());
String bodyStr = out.getOut().getBody(String.class);
assertEquals("This is not a MIME-Multipart", bodyStr);
}
@Test
public void unmarshalInlineHeadersNonMimeBody() {
in.setBody("This is not a MIME-Multipart");
Exchange out = template.send("direct:unmarshalonlyinlineheaders", exchange);
assertNotNull(out.getOut());
String bodyStr = out.getOut().getBody(String.class);
assertEquals("This is not a MIME-Multipart", bodyStr);
}
/*
* This test will only work of stream caching is enabled on the route. In order to find out whether the body
* is a multipart or not the stream has to be read, and if the underlying data is a stream (but not a stream cache)
* there is no way back
*/
@Test
public void unmarshalInlineHeadersNonMimeBodyStream() throws UnsupportedEncodingException {
in.setBody(new ByteArrayInputStream("This is not a MIME-Multipart".getBytes("UTF-8")));
Exchange out = template.send("direct:unmarshalonlyinlineheaders", exchange);
assertNotNull(out.getOut());
String bodyStr = out.getOut().getBody(String.class);
assertEquals("This is not a MIME-Multipart", bodyStr);
}
private Attachment unmarshalAndCheckAttachmentName(String matcher) throws IOException, UnsupportedEncodingException {
Exchange intermediate = template.send("direct:unmarshalonlyinlineheaders", exchange);
assertNotNull(intermediate.getOut());
String bodyStr = intermediate.getOut().getBody(String.class);
assertNotNull(bodyStr);
assertThat(bodyStr, startsWith("25"));
assertEquals(1, intermediate.getOut(AttachmentMessage.class).getAttachmentNames().size());
assertThat(intermediate.getOut(AttachmentMessage.class).getAttachmentNames().iterator().next(), containsString(matcher));
Attachment att = intermediate.getOut(AttachmentMessage.class).getAttachmentObject(intermediate.getOut(AttachmentMessage.class).getAttachmentNames().iterator().next());
DataHandler dh = att.getDataHandler();
assertNotNull(dh);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
dh.writeTo(bos);
String attachmentString = new String(bos.toByteArray(), "UTF-8");
assertThat(attachmentString, startsWith("Old MacDonald had a farm"));
return att;
}
private void addAttachment(String attContentType, String attText, String attFileName) throws IOException {
addAttachment(attContentType, attText, attFileName, null);
}
private void addAttachment(String attContentType, String attText, String attFileName, Map<String, String> headers) throws IOException {
DataSource ds = new ByteArrayDataSource(attText, attContentType);
DefaultAttachment attachment = new DefaultAttachment(ds);
if (headers != null) {
for (String headerName : headers.keySet()) {
attachment.addHeader(headerName, headers.get(headerName));
}
}
in.addAttachmentObject(attFileName, attachment);
}
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:roundtrip").marshal().mimeMultipart().to("log:mime?showHeaders=true").unmarshal().mimeMultipart();
from("direct:roundtripmultipart").marshal().mimeMultipart(true, false, false).to("log:mime?showHeaders=true").unmarshal().mimeMultipart();
from("direct:roundtripinlineheaders").marshal().mimeMultipart(false, true, false).to("log:mime?showHeaders=true").unmarshal().mimeMultipart(false, true, false);
from("direct:roundtripbinarycontent").marshal().mimeMultipart(false, false, true).to("log:mime?showHeaders=true").to("dataformat:mime-multipart:unmarshal");
from("direct:marshalonlyrelated").marshal().mimeMultipart("related");
from("direct:marshalonlymixed").marshal().mimeMultipart();
from("direct:marshalonlyinlineheaders").marshal().mimeMultipart("mixed", false, true, "(included|x-.*)", false);
from("direct:unmarshalonly").unmarshal().mimeMultipart(false, false, false);
from("direct:unmarshalonlyinlineheaders").streamCaching().unmarshal().mimeMultipart(false, true, false);
}
};
}
}