Question

I use javax.mail.internet.MimeBody* version 1.4.1

My program wants to send some binary data with multiple level of nesting from a server to client using MimeMultiPart. I observed that if on a level if we use GetContent it corrupts the data. I was able to reproduce this problem with this snippet

  public static void CreateResponse() throws Exception {
        //Simulate the Server side
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        MimeMultipart multiPartValues = new MimeMultipart();
        MimeBodyPart valueBody = new MimeBodyPart();

        byte[] firstKeyValue = new byte[] { (byte)0x8c};
        valueBody.setContent(firstKeyValue,"application/octet-stream");
        valueBody.addHeader(RestMessageHeaders.CONTENT_LENGTH,
                Integer.toString(firstKeyValue.length));
        multiPartValues.addBodyPart(valueBody);

        Object input = valueBody.getContent();
        System.out.println(String.format("input %02X", ((byte[])input)[0]));
        multiPartValues.writeTo(outputStream);

        //Simulate the client side
        byte[] mimeOutput = outputStream.toByteArray();

        ByteArrayDataSource ds = new ByteArrayDataSource(mimeOutput,
                "multipart/mixed");
        MimeMultipart mp = new MimeMultipart(ds);
        MimeBodyPart part = (MimeBodyPart) mp.getBodyPart(0);

        byte[] myOutput = new byte[1];
        //Verified that getContent returns a String, why ?? 
        Object output = part.getContent();
        System.out.println("getContent type " + output.getClass());
        String result = (String)output;
        ByteArrayDataSource partDS = new ByteArrayDataSource(result, "multipart/mixed");
        partDS.getInputStream().read(myOutput); 
        System.out.println(String.format("getContent %02X %02X", result.getBytes()[0],result.getBytes()[1]));
        System.out.println(String.format("getContent %02X", myOutput[0]));

        part.getInputStream().read(myOutput);
        System.out.println(String.format("getInputStream %02X", myOutput[0]));

        part.getRawInputStream().read(myOutput);
        System.out.println(String.format("getRawInputStream %02X", myOutput[0]));

}

Here is the output

        input 8C
        getContent type class java.lang.String
        getContent C2 8C
        getContent C2
        getInputStream 8C
        getRawInputStream 8C

I have completely simplified the code here and it looks obvious to use get(Raw)InputStream, but we have nestedMultiPart and the top level was doing getContent which caused it to fail for some cases.

  1. Input is of type byte Array, but on the client getContent responds with String. The server sets the content to application/octet-stream but on the client side it is outputted as string. What is going wrong here?
  2. I am not sure why the byte c2 is added before 8c. What is so special about the 8c character?
  3. What is the difference between getInputStream and getRawInputStream. When to use one over the another ?
Was it helpful?

Solution

What does the complete stream contain that the server is creating and the client is reading?

Note that by using MimeMultipart without MimeMessage, you're missing some of the things that are done automatically for you by MimeMessage, in particular you're missing the call to MimeMultipart.updateHeaders(). Since the method is protected, you'll need to subclass MimeMultipart and call that method before calling writeTo. If that doesn't fix your problem, show us the exact data that's being written and read on the stream.

As mentioned above, if you're expecting binary data, you almost certainly want to use getInputStream. The getRawInputStream gives you the data before it has been decoded, e.g., the base64 input instead of binary output.

OTHER TIPS

Don't use getContent() if it returns a String and you want binary. String is not a container for binary data. Use getInputStream() and copy the bytes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top