diff -r cb15fc6cc038 -r 9a2e5d103695 jaxws/src/java.xml.soap/share/classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java --- a/jaxws/src/java.xml.soap/share/classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java Thu Jan 15 11:18:14 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,765 +0,0 @@ -/* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @(#)MimeMultipart.java 1.31 03/01/29 - */ - - - -package com.sun.xml.internal.messaging.saaj.packaging.mime.internet; - -import java.io.*; -import java.util.BitSet; - -import javax.activation.DataSource; - -import com.sun.xml.internal.messaging.saaj.packaging.mime.*; -import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*; - -import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream; - -/** - * The MimeMultipart class is an implementation of the abstract Multipart - * class that uses MIME conventions for the multipart data.
- *
- * A MimeMultipart is obtained from a MimePart whose primary type
- * is "multipart" (by invoking the part's getContent()
method)
- * or it can be created by a client as part of creating a new MimeMessage.
- * - * The default multipart subtype is "mixed". The other multipart - * subtypes, such as "alternative", "related", and so on, can be - * implemented as subclasses of MimeMultipart with additional methods - * to implement the additional semantics of that type of multipart - * content. The intent is that service providers, mail JavaBean writers - * and mail clients will write many such subclasses and their Command - * Beans, and will install them into the JavaBeans Activation - * Framework, so that any JavaMail implementation and its clients can - * transparently find and use these classes. Thus, a MIME multipart - * handler is treated just like any other type handler, thereby - * decoupling the process of providing multipart handlers from the - * JavaMail API. Lacking these additional MimeMultipart subclasses, - * all subtypes of MIME multipart data appear as MimeMultipart objects.
- *
- * An application can directly construct a MIME multipart object of any
- * subtype by using the MimeMultipart(String subtype)
- * constructor. For example, to create a "multipart/alternative" object,
- * use new MimeMultipart("alternative")
.
- *
- */
-
-//TODO: cleanup the SharedInputStream handling
-public class BMMimeMultipart extends MimeMultipart {
-
- /*
- * When true it indicates parsing hasnt been done at all
- */
- private boolean begining = true;
-
- int[] bcs = new int[256];
- int[] gss = null;
- private static final int BUFFER_SIZE = 4096;
- private byte[] buffer = new byte[BUFFER_SIZE];
- private byte[] prevBuffer = new byte[BUFFER_SIZE];
- private BitSet lastPartFound = new BitSet(1);
-
- // cached inputstream which is possibly partially consumed
- private InputStream in = null;
- private String boundary = null;
- // current stream position, set to -1 on EOF
- int b = 0;
-
- // property to indicate if lazyAttachments is ON
- private boolean lazyAttachments = false;
-
- /**
- * Default constructor. An empty MimeMultipart object
- * is created. Its content type is set to "multipart/mixed".
- * A unique boundary string is generated and this string is
- * setup as the "boundary" parameter for the
- * contentType
field.
- *
- * MimeBodyParts may be added later.
- */
- public BMMimeMultipart() {
- super();
- //this("mixed");
- }
-
- /**
- * Construct a MimeMultipart object of the given subtype.
- * A unique boundary string is generated and this string is
- * setup as the "boundary" parameter for the
- * contentType
field.
- * - * MimeBodyParts may be added later. - */ - public BMMimeMultipart(String subtype) { - super(subtype); - /* - * Compute a boundary string. - String boundary = UniqueValue.getUniqueBoundaryValue(); - ContentType cType = new ContentType("multipart", subtype, null); - contentType.setParameter("boundary", boundary); - */ - } - - /** - * Constructs a MimeMultipart object and its bodyparts from the - * given DataSource.
- * - * This constructor handles as a special case the situation where the - * given DataSource is a MultipartDataSource object. In this case, this - * method just invokes the superclass (i.e., Multipart) constructor - * that takes a MultipartDataSource object.
- *
- * Otherwise, the DataSource is assumed to provide a MIME multipart
- * byte stream. The parsed
flag is set to false. When
- * the data for the body parts are needed, the parser extracts the
- * "boundary" parameter from the content type of this DataSource,
- * skips the 'preamble' and reads bytes till the terminating
- * boundary and creates MimeBodyParts for each part of the stream.
- *
- * @param ds DataSource, can be a MultipartDataSource
- */
- public BMMimeMultipart(DataSource ds, ContentType ct)
- throws MessagingException {
- super(ds,ct);
- boundary = ct.getParameter("boundary");
- /*
- if (ds instanceof MultipartDataSource) {
- // ask super to do this for us.
- setMultipartDataSource((MultipartDataSource)ds);
- return;
- }
-
- // 'ds' was not a MultipartDataSource, we have
- // to parse this ourself.
- parsed = false;
- this.ds = ds;
- if (ct==null)
- contentType = new ContentType(ds.getContentType());
- else
- contentType = ct;
- */
-
- }
-
- public InputStream initStream() throws MessagingException {
-
- if (in == null) {
- try {
- in = ds.getInputStream();
- if (!(in instanceof ByteArrayInputStream) &&
- !(in instanceof BufferedInputStream) &&
- !(in instanceof SharedInputStream))
- in = new BufferedInputStream(in);
- } catch (Exception ex) {
- throw new MessagingException("No inputstream from datasource");
- }
-
- if (!in.markSupported()) {
- throw new MessagingException(
- "InputStream does not support Marking");
- }
- }
- return in;
- }
-
- /**
- * Parse the InputStream from our DataSource, constructing the
- * appropriate MimeBodyParts. The parsed
flag is
- * set to true, and if true on entry nothing is done. This
- * method is called by all other methods that need data for
- * the body parts, to make sure the data has been parsed.
- *
- * @since JavaMail 1.2
- */
- protected void parse() throws MessagingException {
- if (parsed)
- return;
-
- initStream();
-
- SharedInputStream sin = null;
- if (in instanceof SharedInputStream) {
- sin = (SharedInputStream)in;
- }
-
- String bnd = "--" + boundary;
- byte[] bndbytes = ASCIIUtility.getBytes(bnd);
- try {
- parse(in, bndbytes, sin);
- } catch (IOException ioex) {
- throw new MessagingException("IO Error", ioex);
- } catch (Exception ex) {
- throw new MessagingException("Error", ex);
- }
-
- parsed = true;
- }
-
- public boolean lastBodyPartFound() {
- return lastPartFound.get(0);
- }
-
- public MimeBodyPart getNextPart(
- InputStream stream, byte[] pattern, SharedInputStream sin)
- throws Exception {
-
- if (!stream.markSupported()) {
- throw new Exception("InputStream does not support Marking");
- }
-
- if (begining) {
- compile(pattern);
- if (!skipPreamble(stream, pattern, sin)) {
- throw new Exception(
- "Missing Start Boundary, or boundary does not start on a new line");
- }
- begining = false;
- }
-
- if (lastBodyPartFound()) {
- throw new Exception("No parts found in Multipart InputStream");
- }
-
- if (sin != null) {
- long start = sin.getPosition();
- b = readHeaders(stream);
- if (b == -1) {
- throw new Exception(
- "End of Stream encountered while reading part headers");
- }
- long[] v = new long[1];
- v[0] = -1; // just to ensure the code later sets it correctly
- b = readBody(stream, pattern, v, null, sin);
- // looks like this check has to be disabled
- // it is allowed to have Mime Package without closing boundary
- if (!ignoreMissingEndBoundary) {
- if ((b == -1) && !lastBodyPartFound()) {
- throw new MessagingException("Missing End Boundary for Mime Package : EOF while skipping headers");
- }
- }
- long end = v[0];
- MimeBodyPart mbp = createMimeBodyPart(sin.newStream(start, end));
- addBodyPart(mbp);
- return mbp;
-
- } else {
- InternetHeaders headers = createInternetHeaders(stream);
- ByteOutputStream baos = new ByteOutputStream();
- b = readBody(stream, pattern, null,baos, null);
- // looks like this check has to be disabled
- // in the old impl it is allowed to have Mime Package
- // without closing boundary
- if (!ignoreMissingEndBoundary) {
- if ((b == -1) && !lastBodyPartFound()) {
- throw new MessagingException("Missing End Boundary for Mime Package : EOF while skipping headers");
- }
- }
- MimeBodyPart mbp = createMimeBodyPart(
- headers, baos.getBytes(), baos.getCount());
- addBodyPart(mbp);
- return mbp;
- }
-
- }
-
- public boolean parse(
- InputStream stream, byte[] pattern, SharedInputStream sin)
- throws Exception {
-
- while (!lastPartFound.get(0) && (b != -1)) {
- getNextPart(stream, pattern, sin);
- }
- return true;
- }
-
- private int readHeaders(InputStream is) throws Exception {
- // if the headers are to end properly then there has to be CRLF
- // actually we just need to mark the start and end positions
- int b = is.read();
- while(b != -1) {
- // when it is a shared input stream no need to copy
- if (b == '\r') {
- b = is.read();
- if (b == '\n') {
- b = is.read();
- if (b == '\r') {
- b = is.read();
- if (b == '\n') {
- return b;
- } else {
- continue;
- }
- } else {
- continue;
- }
- } else {
- continue;
- }
- }
- b = is.read();
- }
- if (b == -1) {
- throw new Exception(
- "End of inputstream while reading Mime-Part Headers");
- }
- return b;
- }
-
- private int readBody(
- InputStream is, byte[] pattern, long[] posVector,
- ByteOutputStream baos, SharedInputStream sin)
- throws Exception {
- if (!find(is, pattern, posVector, baos, sin)) {
- throw new Exception(
- "Missing boundary delimitier while reading Body Part");
- }
- return b;
- }
-
- private boolean skipPreamble(
- InputStream is, byte[] pattern, SharedInputStream sin)
- throws Exception {
- if (!find(is, pattern, sin)) {
- return false;
- }
- if (lastPartFound.get(0)) {
- throw new Exception(
- "Found closing boundary delimiter while trying to skip preamble");
- }
- return true;
- }
-
-
- public int readNext(InputStream is, byte[] buff, int patternLength,
- BitSet eof, long[] posVector, SharedInputStream sin)
- throws Exception {
-
- int bufferLength = is.read(buffer, 0, patternLength);
- if (bufferLength == -1) {
- eof.flip(0);
- } else if (bufferLength < patternLength) {
- //repeatedly read patternLength - bufferLength
- int temp = 0;
- long pos = 0;
- int i = bufferLength;
- for (; i < patternLength; i++) {
- if (sin != null) {
- pos = sin.getPosition();
- }
- temp = is.read();
- if (temp == -1) {
- eof.flip(0);
- if (sin != null) {
- posVector[0] = pos;
- }
- break;
- }
- buffer[i] = (byte)temp;
- }
- bufferLength=i;
- }
- return bufferLength;
- }
-
- public boolean find(InputStream is, byte[] pattern, SharedInputStream sin)
- throws Exception {
- int i;
- int l = pattern.length;
- int lx = l -1;
- BitSet eof = new BitSet(1);
- long[] posVector = new long[1];
-
- while (true) {
- is.mark(l);
- readNext(is, buffer, l, eof, posVector, sin);
- if (eof.get(0)) {
- // End of stream
- return false;
- }
-
- /*
- if (bufferLength < l) {
- //is.reset();
- return false;
- }*/
-
- for(i = lx; i >= 0; i--) {
- if (buffer[i] != pattern[i]) {
- break;
- }
- }
-
- if (i < 0) {
- // found the boundary, skip *LWSP-char and CRLF
- if (!skipLWSPAndCRLF(is)) {
- throw new Exception("Boundary does not terminate with CRLF");
- }
- return true;
- }
-
- int s = Math.max(i + 1 - bcs[buffer[i] & 0x7f], gss[i]);
- is.reset();
- is.skip(s);
- }
- }
-
- public boolean find(
- InputStream is, byte[] pattern, long[] posVector,
- ByteOutputStream out, SharedInputStream sin) throws Exception {
- int i;
- int l = pattern.length;
- int lx = l -1;
- int bufferLength = 0;
- int s = 0;
- long endPos = -1;
- byte[] tmp = null;
-
- boolean first = true;
- BitSet eof = new BitSet(1);
-
- while (true) {
- is.mark(l);
- if (!first) {
- tmp = prevBuffer;
- prevBuffer = buffer;
- buffer = tmp;
- }
- if (sin != null) {
- endPos = sin.getPosition();
- }
-
- bufferLength = readNext(is, buffer, l, eof, posVector, sin);
-
- if (bufferLength == -1) {
- // End of stream
- // looks like it is allowed to not have a closing boundary
- //return false;
- //if (sin != null) {
- // posVector[0] = endPos;
- //}
- b = -1;
- if ((s == l) && (sin == null)) {
- out.write(prevBuffer, 0, s);
- }
- return true;
- }
-
- if (bufferLength < l) {
- if (sin != null) {
- //endPos = sin.getPosition();
- //posVector[0] = endPos;
- } else {
- // looks like it is allowed to not have a closing boundary
- // in the old implementation
- out.write(buffer, 0, bufferLength);
- }
- // looks like it is allowed to not have a closing boundary
- // in the old implementation
- //return false;
- b = -1;
- return true;
- }
-
- for(i = lx; i >= 0; i--) {
- if (buffer[i] != pattern[i]) {
- break;
- }
- }
-
- if (i < 0) {
- if (s > 0) {
- //looks like the earlier impl allowed just an LF
- // so if s == 1 : it must be an LF
- // if s == 2 : it must be a CR LF
- if (s <= 2) {
- //it could be "some-char\n" so write some-char
- if (s == 2) {
- if (prevBuffer[1] == '\n') {
- if (prevBuffer[0] != '\r' && prevBuffer[0] != '\n') {
- out.write(prevBuffer,0,1);
- }
- if (sin != null) {
- posVector[0] = endPos;
- }
-
- } else {
- throw new Exception(
- "Boundary characters encountered in part Body " +
- "without a preceeding CRLF");
- }
-
- } else if (s==1) {
- if (prevBuffer[0] != '\n') {
- throw new Exception(
- "Boundary characters encountered in part Body " +
- "without a preceeding CRLF");
- }else {
- if (sin != null) {
- posVector[0] = endPos;
- }
- }
- }
-
- } else if (s > 2) {
- if ((prevBuffer[s-2] == '\r') && (prevBuffer[s-1] == '\n')) {
- if (sin != null) {
- posVector[0] = endPos - 2;
- } else {
- out.write(prevBuffer, 0, s - 2);
- }
- } else if (prevBuffer[s-1] == '\n') {
- //old impl allowed just a \n
- if (sin != null) {
- posVector[0] = endPos - 1;
- } else {
- out.write(prevBuffer, 0, s - 1);
- }
- } else {
- throw new Exception(
- "Boundary characters encountered in part Body " +
- "without a preceeding CRLF");
- }
- }
- }
- // found the boundary, skip *LWSP-char and CRLF
- if (!skipLWSPAndCRLF(is)) {
- //throw new Exception(
- // "Boundary does not terminate with CRLF");
- }
- return true;
- }
-
- if ((s > 0) && (sin == null)) {
- if (prevBuffer[s-1] == (byte)13) {
- // if buffer[0] == (byte)10
- if (buffer[0] == (byte)10) {
- int j;
- for(j = lx-1; j > 0; j--) {
- if (buffer[j+1] != pattern[j]) {
- break;
- }
- }
- if (j == 0) {
- // matched the pattern excluding the last char of the pattern
- // so dont write the CR into stream
- out.write(prevBuffer,0,s-1);
- } else {
- out.write(prevBuffer,0,s);
- }
- } else {
- out.write(prevBuffer, 0, s);
- }
- } else {
- out.write(prevBuffer, 0, s);
- }
- }
-
- s = Math.max(i + 1 - bcs[buffer[i] & 0x7f], gss[i]);
- is.reset();
- is.skip(s);
- if (first) {
- first = false;
- }
- }
- }
-
- private boolean skipLWSPAndCRLF(InputStream is) throws Exception {
-
- b = is.read();
- //looks like old impl allowed just a \n as well
- if (b == '\n') {
- return true;
- }
-
- if (b == '\r') {
- b = is.read();
- //skip any multiple '\r' "\r\n" --> "\r\r\n" on Win2k
- if (b == '\r') {
- b = is.read();
- }
- if (b == '\n') {
- return true;
- } else {
- throw new Exception(
- "transport padding after a Mime Boundary should end in a CRLF, found CR only");
- }
- }
-
- if (b == '-') {
- b = is.read();
- if (b != '-') {
- throw new Exception(
- "Unexpected singular '-' character after Mime Boundary");
- } else {
- //System.out.println("Last Part Found");
- lastPartFound.flip(0);
- // read the next char
- b = is.read();
- }
- }
-
- while ((b != -1) && ((b == ' ') || (b == '\t'))) {
- b = is.read();
- if (b == '\n') {
- return true;
- }
- if (b == '\r') {
- b = is.read();
- //skip any multiple '\r': "\r\n" --> "\r\r\n" on Win2k
- if (b == '\r') {
- b = is.read();
- }
- if (b == '\n') {
- return true;
- }
- }
- }
-
- if (b == -1) {
- // the last boundary need not have CRLF
- if (!lastPartFound.get(0)) {
- throw new Exception(
- "End of Multipart Stream before encountering closing boundary delimiter");
- }
- return true;
- }
- return false;
- }
-
- private void compile(byte[] pattern) {
- int l = pattern.length;
-
- int i;
- int j;
-
- // Copied from J2SE 1.4 regex code
- // java.util.regex.Pattern.java
-
- // Initialise Bad Character Shift table
- for (i = 0; i < l; i++) {
- bcs[pattern[i]] = i + 1;
- }
-
- // Initialise Good Suffix Shift table
- gss = new int[l];
- NEXT: for (i = l; i > 0; i--) {
- // j is the beginning index of suffix being considered
- for (j = l - 1; j >= i; j--) {
- // Testing for good suffix
- if (pattern[j] == pattern[j - i]) {
- // pattern[j..len] is a good suffix
- gss[j - 1] = i;
- } else {
- // No match. The array has already been
- // filled up with correct values before.
- continue NEXT;
- }
- }
- while (j > 0) {
- gss[--j] = i;
- }
- }
- gss[l - 1] = 1;
- }
-
-
- /**
- * Iterates through all the parts and outputs each Mime part
- * separated by a boundary.
- */
-
- public void writeTo(OutputStream os)
- throws IOException, MessagingException {
-
- // inputStream was not null
- if (in != null) {
- contentType.setParameter("boundary", this.boundary);
- }
-
- String bnd = "--" + contentType.getParameter("boundary");
- for (int i = 0; i < parts.size(); i++) {
- OutputUtil.writeln(bnd, os); // put out boundary
- ((MimeBodyPart)parts.get(i)).writeTo(os);
- OutputUtil.writeln(os); // put out empty line
- }
-
- if (in != null) {
- OutputUtil.writeln(bnd, os); // put out boundary
- if ((os instanceof ByteOutputStream) && lazyAttachments) {
- ((ByteOutputStream) os).write(in);
- } else {
- ByteOutputStream baos = null;
- try {
- baos = new ByteOutputStream(in.available());
- baos.write(in);
- baos.writeTo(os);
- // reset the inputstream so that we can support a
- // getAttachment later
- in = baos.newInputStream();
- } finally {
- if (baos != null)
- baos.close();
- }
- }
-
- // this will endup writing the end boundary
- } else {
- // put out last boundary
- OutputUtil.writeAsAscii(bnd, os);
- OutputUtil.writeAsAscii("--", os);
- }
- }
-
- public void setInputStream(InputStream is) {
- this.in = is;
- }
-
- public InputStream getInputStream() {
- return this.in;
- }
-
- public void setBoundary(String bnd) {
- this.boundary = bnd;
- if (this.contentType != null) {
- this.contentType.setParameter("boundary", bnd);
- }
- }
- public String getBoundary() {
- return this.boundary;
- }
-
- public boolean isEndOfStream() {
- return (b == -1);
- }
-
- public void setLazyAttachments(boolean flag) {
- lazyAttachments = flag;
- }
-
-}