This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit d37f063de2f5c9b3fb61845678e3f94e62f29a20 Author: William Collins <punkhor...@gmail.com> AuthorDate: Fri May 11 12:00:49 2018 -0400 [CAMEL-11257] Fixed deserialization of transfer encoded MIME entities --- .../as2/api/entity/ApplicationEDIEntity.java | 8 +++- .../entity/ApplicationPkcs7SignatureEntity.java | 4 +- .../component/as2/api/entity/EntityParser.java | 43 ++++++++------------- .../as2/api/io/AS2SessionInputBuffer.java | 24 +++--------- .../camel/component/as2/api/util/EntityUtils.java | 29 ++++++++++++-- .../camel/component/as2/api/AS2MessageTest.java | 44 +++++++++++++++++----- 6 files changed, 90 insertions(+), 62 deletions(-) diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationEDIEntity.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationEDIEntity.java index 73ec7ff..f5610e8 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationEDIEntity.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationEDIEntity.java @@ -21,6 +21,7 @@ import java.io.OutputStream; import org.apache.camel.component.as2.api.AS2Charset; import org.apache.camel.component.as2.api.CanonicalOutputStream; +import org.apache.camel.component.as2.api.util.EntityUtils; import org.apache.http.Header; import org.apache.http.HeaderIterator; import org.apache.http.entity.ContentType; @@ -45,7 +46,8 @@ public abstract class ApplicationEDIEntity extends MimeEntity { @Override public void writeTo(OutputStream outstream) throws IOException { NoCloseOutputStream ncos = new NoCloseOutputStream(outstream); - try (CanonicalOutputStream canonicalOutstream = new CanonicalOutputStream(ncos, AS2Charset.US_ASCII)) { + try (CanonicalOutputStream canonicalOutstream = new CanonicalOutputStream(ncos, AS2Charset.US_ASCII); + OutputStream transferEncodedStream = EntityUtils.encode(canonicalOutstream, getContentTransferEncodingValue())) { // Write out mime part headers if this is not the main body of message. if (!isMainBody()) { @@ -57,7 +59,9 @@ public abstract class ApplicationEDIEntity extends MimeEntity { canonicalOutstream.writeln(); // ensure empty line between headers and body; RFC2046 - 5.1.1 } - canonicalOutstream.write(ediMessage.getBytes(getCharset()), 0, ediMessage.length()); + transferEncodedStream.write(ediMessage.getBytes(getCharset()), 0, ediMessage.length()); + } catch (Exception e) { + throw new IOException("Failed to write to output stream", e); } } diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7SignatureEntity.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7SignatureEntity.java index a64db26..179d82b 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7SignatureEntity.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7SignatureEntity.java @@ -100,9 +100,9 @@ public class ApplicationPkcs7SignatureEntity extends MimeEntity { // Write out signed data. String transferEncoding = getContentTransferEncoding() == null ? null : getContentTransferEncoding().getValue(); - try (OutputStream trasnsferEncodedStream = EntityUtils.encode(ncos, transferEncoding)) { + try (OutputStream transferEncodedStream = EntityUtils.encode(ncos, transferEncoding)) { - trasnsferEncodedStream.write(signature); + transferEncodedStream.write(signature); } catch (Exception e) { throw new IOException("Failed to write to output stream", e); } diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java index ce17586..76c6491c 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java @@ -357,7 +357,6 @@ public final class EntityParser { String contentTransferEncoding) throws ParseException { CharsetDecoder previousDecoder = inbuffer.getCharsetDecoder(); - String previousContentTransferEncoding = inbuffer.getTransferEncoding(); try { @@ -368,7 +367,6 @@ public final class EntityParser { CharsetDecoder charsetDecoder = charset.newDecoder(); inbuffer.setCharsetDecoder(charsetDecoder); - inbuffer.setTransferEncoding(contentTransferEncoding); MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(boundary, false); @@ -406,7 +404,7 @@ public final class EntityParser { signedEntity.removeAllHeaders(); signedEntity.setHeaders(headers); multipartSignedEntity.addPart(signedEntity); - + // // End Signed Entity Part @@ -460,7 +458,6 @@ public final class EntityParser { throw parseException; } finally { inbuffer.setCharsetDecoder(previousDecoder); - inbuffer.setTransferEncoding(previousContentTransferEncoding); } } @@ -470,7 +467,6 @@ public final class EntityParser { String contentTransferEncoding) throws ParseException { CharsetDecoder previousDecoder = inbuffer.getCharsetDecoder(); - String previousContentTransferEncoding = inbuffer.getTransferEncoding(); try { @@ -481,7 +477,6 @@ public final class EntityParser { CharsetDecoder charsetDecoder = charset.newDecoder(); inbuffer.setCharsetDecoder(charsetDecoder); - inbuffer.setTransferEncoding(contentTransferEncoding); DispositionNotificationMultipartReportEntity dispositionNotificationMultipartReportEntity = new DispositionNotificationMultipartReportEntity(boundary, false); @@ -578,7 +573,6 @@ public final class EntityParser { throw parseException; } finally { inbuffer.setCharsetDecoder(previousDecoder); - inbuffer.setTransferEncoding(previousContentTransferEncoding); } } @@ -589,7 +583,6 @@ public final class EntityParser { String contentTransferEncoding) throws ParseException { CharsetDecoder previousDecoder = inbuffer.getCharsetDecoder(); - String previousContentTransferEncoding = inbuffer.getTransferEncoding(); try { @@ -600,9 +593,11 @@ public final class EntityParser { CharsetDecoder charsetDecoder = charset.newDecoder(); inbuffer.setCharsetDecoder(charsetDecoder); - inbuffer.setTransferEncoding(contentTransferEncoding); String text = parseBodyPartText(inbuffer, boundary); + if (contentTransferEncoding != null) { + text = EntityUtils.decode(text, charset, contentTransferEncoding); + } return new TextPlainEntity(text, charsetName, contentTransferEncoding, false); } catch (Exception e) { ParseException parseException = new ParseException("failed to parse text entity"); @@ -610,7 +605,6 @@ public final class EntityParser { throw parseException; } finally { inbuffer.setCharsetDecoder(previousDecoder); - inbuffer.setTransferEncoding(previousContentTransferEncoding); } } @@ -620,7 +614,6 @@ public final class EntityParser { String contentTransferEncoding) throws ParseException { CharsetDecoder previousDecoder = inbuffer.getCharsetDecoder(); - String previousContentTransferEncoding = inbuffer.getTransferEncoding(); try { @@ -631,7 +624,6 @@ public final class EntityParser { CharsetDecoder charsetDecoder = charset.newDecoder(); inbuffer.setCharsetDecoder(charsetDecoder); - inbuffer.setTransferEncoding(contentTransferEncoding); List<CharArrayBuffer> dispositionNotificationFields = parseBodyPartFields(inbuffer, boundary, BasicLineParser.INSTANCE, new ArrayList<CharArrayBuffer>()); @@ -646,7 +638,6 @@ public final class EntityParser { throw parseException; } finally { inbuffer.setCharsetDecoder(previousDecoder); - inbuffer.setTransferEncoding(previousContentTransferEncoding); } } @@ -657,7 +648,6 @@ public final class EntityParser { Header[] headers) throws ParseException { CharsetDecoder previousDecoder = inbuffer.getCharsetDecoder(); - String previousContentTransferEncoding = inbuffer.getTransferEncoding(); try { Charset charset = entityContentType.getCharset(); @@ -667,7 +657,6 @@ public final class EntityParser { CharsetDecoder charsetDecoder = charset.newDecoder(); inbuffer.setCharsetDecoder(charsetDecoder); - inbuffer.setTransferEncoding(contentTransferEncoding); MimeEntity entity = null; switch (entityContentType.getMimeType().toLowerCase()) { @@ -695,7 +684,7 @@ public final class EntityParser { skipToBoundary(inbuffer, boundary); break; case AS2MimeType.TEXT_PLAIN: - entity = parseTextPlainEntityBody(inbuffer, boundary, charset.name(), previousContentTransferEncoding); + entity = parseTextPlainEntityBody(inbuffer, boundary, charset.name(), contentTransferEncoding); break; case AS2MimeType.APPLICATION_PKCS7_SIGNATURE: entity = parseApplicationPkcs7SignatureEntityBody(inbuffer, boundary, entityContentType, @@ -713,7 +702,6 @@ public final class EntityParser { throw parseException; } finally { inbuffer.setCharsetDecoder(previousDecoder); - inbuffer.setTransferEncoding(previousContentTransferEncoding); } } @@ -724,7 +712,6 @@ public final class EntityParser { String contentTransferEncoding) throws ParseException { CharsetDecoder previousDecoder = inbuffer.getCharsetDecoder(); - String previousContentTransferEncoding = inbuffer.getTransferEncoding(); try { Charset charset = ediMessageContentType.getCharset(); @@ -734,9 +721,11 @@ public final class EntityParser { CharsetDecoder charsetDecoder = charset.newDecoder(); inbuffer.setCharsetDecoder(charsetDecoder); - inbuffer.setTransferEncoding(contentTransferEncoding); String ediMessageBodyPartContent = parseBodyPartText(inbuffer, boundary); + if (contentTransferEncoding != null) { + ediMessageBodyPartContent = EntityUtils.decode(ediMessageBodyPartContent, charset, contentTransferEncoding); + } ApplicationEDIEntity applicationEDIEntity = EntityUtils.createEDIEntity(ediMessageBodyPartContent, ediMessageContentType, contentTransferEncoding, false); @@ -747,7 +736,6 @@ public final class EntityParser { throw parseException; } finally { inbuffer.setCharsetDecoder(previousDecoder); - inbuffer.setTransferEncoding(previousContentTransferEncoding); } } @@ -757,7 +745,6 @@ public final class EntityParser { String contentTransferEncoding) throws ParseException { CharsetDecoder previousDecoder = inbuffer.getCharsetDecoder(); - String previousContentTransferEncoding = inbuffer.getTransferEncoding(); try { Charset charset = contentType.getCharset(); @@ -767,13 +754,14 @@ public final class EntityParser { CharsetDecoder charsetDecoder = charset.newDecoder(); inbuffer.setCharsetDecoder(charsetDecoder); - inbuffer.setTransferEncoding(contentTransferEncoding); String pkcs7SignatureBodyContent = parseBodyPartText(inbuffer, boundary); + + byte[] signature = EntityUtils.decode(pkcs7SignatureBodyContent.getBytes(charset), contentTransferEncoding); String charsetName = charset.toString(); ApplicationPkcs7SignatureEntity applicationPkcs7SignatureEntity = new ApplicationPkcs7SignatureEntity( - charsetName, contentTransferEncoding, pkcs7SignatureBodyContent.getBytes(charset), false); + charsetName, contentTransferEncoding, signature, false); return applicationPkcs7SignatureEntity; } catch (Exception e) { ParseException parseException = new ParseException("failed to parse PKCS7 Signature entity"); @@ -781,7 +769,6 @@ public final class EntityParser { throw parseException; } finally { inbuffer.setCharsetDecoder(previousDecoder); - inbuffer.setTransferEncoding(previousContentTransferEncoding); } } @@ -814,10 +801,10 @@ public final class EntityParser { public static List<CharArrayBuffer> parseBodyPartFields(final AS2SessionInputBuffer inbuffer, final String boundary, final LineParser parser, - final List<CharArrayBuffer> headerLines) + final List<CharArrayBuffer> fields) throws IOException { Args.notNull(parser, "parser"); - Args.notNull(headerLines, "headerLines"); + Args.notNull(fields, "fields"); CharArrayBuffer current = null; CharArrayBuffer previous = null; while (true) { @@ -854,11 +841,11 @@ public final class EntityParser { // leave current line buffer for reuse for next header current.clear(); } else { - headerLines.add(current); + fields.add(current); previous = current; current = null; } } - return headerLines; + return fields; } } diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/io/AS2SessionInputBuffer.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/io/AS2SessionInputBuffer.java index b4ab8c0..630edeb 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/io/AS2SessionInputBuffer.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/io/AS2SessionInputBuffer.java @@ -23,7 +23,6 @@ import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; -import org.apache.camel.component.as2.api.util.EntityUtils; import org.apache.http.MessageConstraintException; import org.apache.http.config.MessageConstraints; import org.apache.http.impl.io.HttpTransportMetricsImpl; @@ -46,8 +45,6 @@ public class AS2SessionInputBuffer implements SessionInputBuffer, BufferInfo { private CharsetDecoder decoder; - private String transferEncoding; - private InputStream instream; private int bufferpos; private int bufferlen; @@ -79,14 +76,6 @@ public class AS2SessionInputBuffer implements SessionInputBuffer, BufferInfo { this.decoder = chardecoder; } - public String getTransferEncoding() { - return transferEncoding; - } - - public void setTransferEncoding(String transferEncoding) { - this.transferEncoding = transferEncoding; - } - public void bind(final InputStream instream) { this.instream = instream; } @@ -221,11 +210,11 @@ public class AS2SessionInputBuffer implements SessionInputBuffer, BufferInfo { return lineFromReadBuffer(charbuffer, pos); } retry = false; - addTransferDecodedBytesToLinebuffer(pos); + addBytesToLinebuffer(pos); } else { // end of line not found if (hasBufferedData()) { - addTransferDecodedBytesToLinebuffer(pos); + addBytesToLinebuffer(pos); } noRead = fillBuffer(); if (noRead == -1) { @@ -280,6 +269,7 @@ public class AS2SessionInputBuffer implements SessionInputBuffer, BufferInfo { } } } + if (this.decoder == null) { charbuffer.append(this.linebuffer, 0, len); } else { @@ -301,6 +291,7 @@ public class AS2SessionInputBuffer implements SessionInputBuffer, BufferInfo { pos--; } len = pos - off; + if (this.decoder == null) { charbuffer.append(this.buffer, off, len); } else { @@ -343,7 +334,7 @@ public class AS2SessionInputBuffer implements SessionInputBuffer, BufferInfo { return len; } - private void addTransferDecodedBytesToLinebuffer(int pos) throws IOException { + private void addBytesToLinebuffer(int pos) throws IOException { try { int len; if (pos != -1) { @@ -351,10 +342,7 @@ public class AS2SessionInputBuffer implements SessionInputBuffer, BufferInfo { } else { len = this.bufferlen - this.bufferpos; } - byte[] data = new byte[len]; - System.arraycopy(this.buffer, this.bufferpos, data, 0, data.length); - data = EntityUtils.decode(data, transferEncoding); // - this.linebuffer.append(data, 0, data.length); + this.linebuffer.append(this.buffer, this.bufferpos, len); this.bufferpos = pos + 1; } catch (Exception e) { throw new IOException("failed to decode transfer encoding", e); diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EntityUtils.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EntityUtils.java index 1bfdc70..576d679 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EntityUtils.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EntityUtils.java @@ -17,8 +17,10 @@ package org.apache.camel.component.as2.api.util; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.concurrent.atomic.AtomicLong; @@ -78,6 +80,11 @@ public final class EntityUtils { public static String appendParameter(String headerString, String parameterName, String parameterValue) { return headerString + "; " + parameterName + "=" + parameterValue; } + + public static String encode(String data, Charset charset, String encoding) throws Exception { + byte[] encoded = encode(data.getBytes(charset), encoding); + return new String(encoded, charset); + } public static byte[] encode(byte[] data, String encoding) throws Exception { Args.notNull(data, "Data"); @@ -125,9 +132,14 @@ public final class EntityUtils { throw new Exception("Unknown encoding: " + encoding); } } + + public static String decode(String data, Charset charset, String encoding) throws Exception { + byte[] decoded = decode(data.getBytes(charset), encoding); + return new String(decoded, charset); + } public static byte[] decode(byte[] data, String encoding) throws Exception { - Args.notNull(data, "Input Stream"); + Args.notNull(data, "Data"); if (encoding == null) { // Identity encoding @@ -242,6 +254,17 @@ public final class EntityUtils { } - - + public static void printEntity(PrintStream out, HttpEntity entity) throws IOException { + entity.writeTo(out); + } + + public static String printEntity(HttpEntity entity) throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos, true, "utf-8")) { + printEntity(ps, entity); + String content = new String(baos.toByteArray(), StandardCharsets.UTF_8); + return content; + } + } + } diff --git a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java index 34730db..01a5200 100644 --- a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java +++ b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java @@ -16,6 +16,11 @@ */ package org.apache.camel.component.as2.api; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -29,14 +34,18 @@ import java.util.List; import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity; import org.apache.camel.component.as2.api.entity.ApplicationEDIFACTEntity; import org.apache.camel.component.as2.api.entity.ApplicationPkcs7SignatureEntity; +import org.apache.camel.component.as2.api.entity.DispositionNotificationMultipartReportEntity; import org.apache.camel.component.as2.api.entity.MimeEntity; import org.apache.camel.component.as2.api.entity.MultipartSignedEntity; +import org.apache.camel.component.as2.api.util.HttpMessageUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.entity.ContentType; +import org.apache.http.impl.EnglishReasonPhraseCatalog; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpCoreContext; @@ -59,11 +68,6 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - public class AS2MessageTest { public static final String EDI_MESSAGE = "UNB+UNOA:1+005435656:1+006415160:1+060515:1434+00000000000778'\n" @@ -361,10 +365,32 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.PLAIN, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), - null, null, null, DISPOSITION_NOTIFICATION_TO, null); - - @SuppressWarnings("unused") + null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS); + HttpResponse response = httpContext.getResponse(); + assertEquals("Unexpected method value", HttpVersion.HTTP_1_1, response.getStatusLine().getProtocolVersion()); + assertEquals("Unexpected method value", HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + assertEquals("Unexpected method value", EnglishReasonPhraseCatalog.INSTANCE.getReason(200, null), response.getStatusLine().getReasonPhrase()); + + HttpEntity responseEntity = response.getEntity(); + assertNotNull("Response entity", responseEntity); + assertTrue("Unexpected response entity type", responseEntity instanceof MultipartSignedEntity); + MultipartSignedEntity responseSignedEntity = (MultipartSignedEntity) responseEntity; + MimeEntity responseSignedDataEntity = responseSignedEntity.getSignedDataEntity(); + assertTrue("Signed entity wrong type", responseSignedDataEntity instanceof DispositionNotificationMultipartReportEntity); + DispositionNotificationMultipartReportEntity reportEntity = (DispositionNotificationMultipartReportEntity)responseSignedDataEntity; + assertEquals("Unexpected number of body parts in report", 2, reportEntity.getPartCount()); + MimeEntity firstPart = reportEntity.getPart(0); + assertEquals("Unexpected content type in first body part of report", ContentType.create(AS2MimeType.TEXT_PLAIN, AS2Charset.US_ASCII).toString(), firstPart.getContentTypeValue()); + MimeEntity secondPart = reportEntity.getPart(1); + assertEquals("Unexpected content type in second body part of report", + ContentType.create(AS2MimeType.MESSAGE_DISPOSITION_NOTIFICATION, AS2Charset.US_ASCII).toString(), + secondPart.getContentTypeValue()); + ApplicationPkcs7SignatureEntity signatureEntity = responseSignedEntity.getSignatureEntity(); + assertNotNull("Signature Entity", signatureEntity); + + // Validate Signature + assertTrue("Signature is invalid", responseSignedEntity.isValid()); } - + } -- To stop receiving notification emails like this one, please contact davscl...@apache.org.