org.apache.http.entity.mime.HttpMultipart.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.http.entity.mime.HttpMultipart.java

Source

/*
 * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/entity/mime/HttpMultipart.java $
 * $Revision: 675712 $
 * $Date: 2008-07-10 22:16:33 +0200 (Thu, 10 Jul 2008) $
 *
 * ====================================================================
 * 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */

package org.apache.http.entity.mime;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.List;

import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.protocol.HTTP;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.field.ContentTypeField;
import org.apache.james.mime4j.field.Field;
import org.apache.james.mime4j.message.Body;
import org.apache.james.mime4j.message.BodyPart;
import org.apache.james.mime4j.message.Entity;
import org.apache.james.mime4j.message.Multipart;
import org.apache.james.mime4j.util.CharsetUtil;
import org.apache.james.mime4j.util.MessageUtils;

/**
 * An extension of the mime4j standard {@link Multipart} class, which is
 * capable of operating either in the strict (fully RFC 822, RFC 2045, 
 * RFC 2046 compliant) or the browser compatible modes.
 * 
 * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
 */
public class HttpMultipart extends Multipart {

    private HttpMultipartMode mode;

    public HttpMultipart(final String subType) {
        super(subType);
        this.mode = HttpMultipartMode.STRICT;
    }

    public HttpMultipartMode getMode() {
        return this.mode;
    }

    public void setMode(final HttpMultipartMode mode) {
        this.mode = mode;
    }

    protected Charset getCharset() {
        Entity e = getParent();
        ContentTypeField cField = (ContentTypeField) e.getHeader().getField(Field.CONTENT_TYPE);
        Charset charset = null;

        switch (this.mode) {
        case STRICT:
            charset = MIME.DEFAULT_CHARSET;
            break;
        case BROWSER_COMPATIBLE:
            if (cField.getCharset() != null) {
                charset = CharsetUtil.getCharset(cField.getCharset());
            } else {
                charset = CharsetUtil.getCharset(HTTP.DEFAULT_CONTENT_CHARSET);
            }
            break;
        }
        return charset;
    }

    protected String getBoundary() {
        Entity e = getParent();
        ContentTypeField cField = (ContentTypeField) e.getHeader().getField(Field.CONTENT_TYPE);
        return cField.getBoundary();
    }

    private void doWriteTo(final HttpMultipartMode mode, final OutputStream out, boolean writeContent)
            throws IOException {

        List<?> bodyParts = getBodyParts();
        Charset charset = getCharset();
        String boundary = getBoundary();

        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, charset), 8192);

        switch (mode) {
        case STRICT:
            String preamble = getPreamble();
            if (preamble != null && preamble.length() != 0) {
                writer.write(preamble);
                writer.write("\r\n");
            }

            for (int i = 0; i < bodyParts.size(); i++) {
                writer.write("--");
                writer.write(boundary);
                writer.write("\r\n");
                writer.flush();
                BodyPart part = (BodyPart) bodyParts.get(i);
                part.getHeader().writeTo(out, MessageUtils.STRICT_IGNORE);
                if (writeContent) {
                    part.getBody().writeTo(out, MessageUtils.STRICT_IGNORE);
                }
                writer.write("\r\n");
            }

            writer.write("--");
            writer.write(boundary);
            writer.write("--\r\n");
            String epilogue = getEpilogue();
            if (epilogue != null && epilogue.length() != 0) {
                writer.write(epilogue);
                writer.write("\r\n");
            }
            writer.flush();
            break;
        case BROWSER_COMPATIBLE:

            // (1) Do not write preamble and epilogue
            // (2) Only write Content-Disposition 
            // (3) Use content charset

            for (int i = 0; i < bodyParts.size(); i++) {
                writer.write("--");
                writer.write(boundary);
                writer.write("\r\n");
                writer.flush();
                BodyPart part = (BodyPart) bodyParts.get(i);

                Field cd = part.getHeader().getField(MIME.CONTENT_DISPOSITION);
                writer.write(cd.toString());
                writer.write("\r\n");
                writer.write("\r\n");
                writer.flush();
                if (writeContent) {
                    part.getBody().writeTo(out, MessageUtils.LENIENT);
                }

                writer.write("\r\n");
            }

            writer.write("--");
            writer.write(boundary);
            writer.write("--\r\n");
            writer.flush();
            break;
        }
    }

    /**
     * Writes out the content in the multipart/form encoding. This method 
     * produces slightly different formatting depending on its compatibility 
     * mode.
     * 
     * @see #getMode()
     */
    public void writeTo(final OutputStream out) throws IOException {
        doWriteTo(this.mode, out, true);
    }

    @Override
    public void writeTo(final OutputStream out, int mode) throws IOException, MimeException {
        if (mode == MessageUtils.LENIENT) {
            doWriteTo(HttpMultipartMode.BROWSER_COMPATIBLE, out, true);
        } else {
            doWriteTo(HttpMultipartMode.STRICT, out, true);
        }
    }

    /**
     * Determines the total length of the multipart content (content length of 
     * individual parts plus that of extra elements required to delimit the parts 
     * from one another). If any of the @{link BodyPart}s contained in this object 
     * is of a streaming entity of unknown length the total length is also unknown.
     * <p/>
     * This method buffers only a small amount of data in order to determine the
     * total length of the entire entity. The content of individual parts is not 
     * buffered.  
     * 
     * @return total length of the multipart entity if known, <code>-1</code> 
     *   otherwise.
     */
    public long getTotalLength() {
        List<?> bodyParts = getBodyParts();

        long contentLen = 0;
        for (int i = 0; i < bodyParts.size(); i++) {
            BodyPart part = (BodyPart) bodyParts.get(i);
            Body body = part.getBody();
            if (body instanceof ContentBody) {
                long len = ((ContentBody) body).getContentLength();
                if (len >= 0) {
                    contentLen += len;
                } else {
                    return -1;
                }
            } else {
                return -1;
            }
        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            doWriteTo(this.mode, out, false);
            byte[] extra = out.toByteArray();
            return contentLen + extra.length;
        } catch (IOException ex) {
            // Should never happen
            return -1;
        }
    }

}