All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yy.androidlib.util.http.HttpMultipartEntity Maven / Gradle / Ivy

There is a newer version: 1.0.5
Show newest version
package com.yy.androidlib.util.http;

import android.util.Pair;
import com.yy.androidlib.util.logging.Logger;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.ByteArrayBuffer;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.zip.Deflater;

public class HttpMultipartEntity implements HttpEntity {
    private static final String CONTENT_DISPOSITION   = "Content-Disposition";
    private static final String FORM_DATA = "form-data";
    private static final String MULTIPART_FORM_DATA = "multipart/form-data";
    private static final String CR_LF = "\r\n";
    private static final String TWO_DASHES = "--";
    private final static char[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

    private static final int INIT_BUF_SIZE = 4096;
    private static final int READ_BUF_SIZE = 1024;

    private final String boundary;
    private final Charset charset;
    private final Header contentType;

    private long length;
    private volatile boolean dirty;
    private List> mStrings = new ArrayList>();
    private Map mFiles = new HashMap();
    private Map mZipData = new HashMap();
    private Map mZipFiles = new HashMap();
    private Map mFileBlocks = new HashMap();
    private Map mFileData = new HashMap();

    private int mStartPos = 0;
    private int mPartSize = 0;
    private int mBlockIndex = 0;

    public HttpMultipartEntity(Charset charset) {
        this.boundary = generateBoundary();
        this.charset = charset;
        this.contentType = new BasicHeader(HTTP.CONTENT_TYPE, getContentTypeString());
    }

    public Header getContentType() {
        return contentType;
    }

    public long getContentLength() {
        if (dirty) {
            try {
                LengthCounter lengthCounter = new LengthCounter();
                writeStringParts(lengthCounter);
                writeZipData(lengthCounter);
                writeZipFile(lengthCounter);
                writeFileParts(lengthCounter);
                writeFileData(lengthCounter);
                writeFileBlockParts(lengthCounter);
                writeFinishPart(lengthCounter);
                length = lengthCounter.getLength();
                dirty = false;
            } catch (IOException e) {
                Logger.error(this, e);
            }
        }
        return length;
    }

    public void writeTo(OutputStream out) throws IOException {
        DataWriter writer = new DataWriter(out);
        writeStringParts(writer);
        writeZipData(writer);
        writeZipFile(writer);
        writeFileParts(writer);
        writeFileData(writer);
        writeFileBlockParts(writer);
        writeFinishPart(writer);
    }

    public void addStringPart(String name, String value) {
        Pair pair = Pair.create(name, value);
        mStrings.add(pair);
        dirty = true;
    }

    public void addFileParts(String name, String filepath) {
        mFiles.put(filepath, name);
        dirty = true;
    }

    public void addZipData(String name, String data) {
        mZipData.put(name, data);
        dirty = true;
    }

    public void addZipFile(String name, String filePath) {
        mZipFiles.put(name, filePath);
        dirty = true;
    }

    public void addFileData(String name, String fileData) {
        mFileData.put(name, fileData);
        dirty = true;
    }

    public void addFileBlock(String name, String filepath, int startPos, int size, int index) {
        this.mStartPos = startPos;
        this.mPartSize = size;
        this.mBlockIndex = index;
        mFileBlocks.put(filepath, name);
        dirty = true;
    }

    private String getContentTypeString() {
        StringBuilder sb = new StringBuilder();
        sb.append(MULTIPART_FORM_DATA);
        sb.append("; ");
        sb.append("boundary=");
        sb.append(this.boundary);
        return sb.toString();
    }

    private interface IDataPolicy {
        void write(byte[] buffer, int offset, int count) throws IOException;
    }

    private static class LengthCounter implements IDataPolicy {
        private int length = 0;

        public int getLength() {
            return this.length;
        }

        public void write(byte[] buffer, int offset, int count) {
            this.length += count;
        }
    }

    private static class DataWriter implements IDataPolicy {
        private OutputStream out;
        public DataWriter(OutputStream out) {
            this.out = out;
        }

        public void write(byte[] buffer, int offset, int count) throws IOException {
            out.write(buffer, offset, count);
        }
    }

    private void writeFileHeader(IDataPolicy dataPolicy, String mimeType,
                                 String name, String uploadFileName) throws IOException {
        writeBoundary(dataPolicy);
        StringBuilder sb = new StringBuilder();
        sb.append(CONTENT_DISPOSITION);
        sb.append(": ");
        sb.append(FORM_DATA);
        sb.append("; ");
        sb.append("name=\"");
        sb.append(name);
        sb.append("\"; ");
        sb.append("filename=\"");
        sb.append(uploadFileName);
        sb.append("\"");
        sb.append(CR_LF);
        sb.append(HTTP.CONTENT_TYPE + ": ");
        sb.append(mimeType);
        sb.append(CR_LF);
        sb.append(CR_LF);
        writeBytes(sb.toString(), dataPolicy);
    }

    private void writeZipFile(IDataPolicy dataPolicy) throws IOException {
        for (Entry entry : mZipFiles.entrySet()) {
            String mimeType = BasicFileUtils.getFileMime(BasicFileUtils.ZIP_EXT);
            String name = entry.getKey();
            writeFileHeader(dataPolicy, mimeType, name, entry.getValue());
            addZlibDataFromFile(dataPolicy, entry.getValue());
        }
    }

    private void addZlibDataFromFile(IDataPolicy dataPolicy, String fileName) throws IOException {
        Deflater compressor = new Deflater();
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(fileName);
            int bytes = 0;
            byte[] buffer = new byte[INIT_BUF_SIZE];
            while ((bytes = fis.read(buffer)) != -1) {
                compressor.setInput(buffer, 0, bytes);
            }
            compressor.finish();
            bytes = 0;
            while (!compressor.finished()) {
                bytes = compressor.deflate(buffer);
                dataPolicy.write(buffer, 0, bytes);
            }
            compressor.end();
        }
        catch (Exception e) {
            Logger.error(this, "addZlibDataFromFile, %s", e);
        }
        finally {
            if (fis != null) {
                fis.close();
            }
        }
    }

    private void writeZipData(IDataPolicy dataPolicy) throws IOException {
//        for (Entry entry : mZipData.entrySet()) {
////            String mimeType = BasicFileUtils.getFileMime(BasicFileUtils.ZIP_EXT);
//            String name = entry.getKey();
//            writeFileHeader(dataPolicy, mimeType, name, name);
//            addZlibCompressData(dataPolicy, entry.getValue());
//            writeBytes(CR_LF, dataPolicy);
//        }
    }

    private void addZlibCompressData(IDataPolicy dataPolicy, String data) throws IOException {
        Deflater compressor = new Deflater();
        compressor.setInput(data.getBytes());
        compressor.finish();
        int bytes = 0;
        byte[] buffer = new byte[INIT_BUF_SIZE];
        while (!compressor.finished()) {
            bytes = compressor.deflate(buffer);
            dataPolicy.write(buffer, 0, bytes);
        }
        compressor.end();
    }

    private void writeFileParts(IDataPolicy dataPolicy) throws IOException {
        for (String filePath : mFiles.keySet()) {
            final String mimeType = BasicFileUtils.getFileMime(filePath);
            final String name = mFiles.get(filePath);
            String uploadFileName = BasicFileUtils.getFileName(filePath);
            writeFileHeader(dataPolicy, mimeType, name, uploadFileName);
            File f = new File(filePath);
            FileInputStream in = null;
            try {
                in = new FileInputStream(f);
                byte[] buffer = new byte[INIT_BUF_SIZE];
                int readCount = 0;
                while ((readCount = in.read(buffer)) != -1) {
                    dataPolicy.write(buffer, 0, readCount);
                }
                writeBytes(CR_LF, dataPolicy);
            }
            finally {   
                if (in != null) {
                    in.close();
                }
            }
        }
    }

    private void writeFileData(IDataPolicy dataPolicy) throws IOException {
        for (Entry entry : mFileData.entrySet()) {
            String mimeType = BasicFileUtils.getFileMime(BasicFileUtils.ZIP_EXT);
            String name = entry.getKey();
            writeFileHeader(dataPolicy, mimeType, "files", name);
            dataPolicy.write(entry.getValue().getBytes(), 0, entry.getValue().length());
            writeBytes(CR_LF, dataPolicy);
        }
    }

    private void writeFileBlockParts(IDataPolicy dataPolicy) throws IOException {
        if (mPartSize == 0) {
            return ;
        }
        for (String filePath : mFileBlocks.keySet()) {
            final String mimeType = BasicFileUtils.getFileMime(filePath);
            String uploadFilename = BasicFileUtils.getFileName(filePath);
            writeBoundary(dataPolicy);
            StringBuilder sb0 = new StringBuilder();
            sb0.append(CONTENT_DISPOSITION);
            sb0.append(": ");
            sb0.append(FORM_DATA);
            sb0.append("; ");
            sb0.append("name=\"");
            sb0.append("block");
            sb0.append("\"; ");
            sb0.append(CR_LF);
            sb0.append(CR_LF);
            sb0.append(mBlockIndex);
            writeBytes(sb0.toString(), dataPolicy);
            writeBytes(CR_LF, dataPolicy);

            writeFileHeader(dataPolicy, mimeType, mFileBlocks.get(filePath), uploadFilename);

            File f = new File(filePath);
            FileInputStream in = null;
            try {
                in = new FileInputStream(f);
                byte[] buffer = new byte[READ_BUF_SIZE];

                in.skip(mStartPos);

                int readCount = 0, tmp = 0;
                while (tmp < mPartSize && ((readCount = in.read(buffer)) != -1)) {
                    if (readCount > mPartSize) {
                        dataPolicy.write(buffer, 0, mPartSize);
                    }
                    else {
                        dataPolicy.write(buffer, 0, readCount);
                    }
                    tmp += readCount;
                }

                writeBytes(CR_LF, dataPolicy);
            }
            finally {
                if (in != null) {
                    in.close();
                }
            }
        }
    }

    private void writeStringParts(IDataPolicy dataPolicy) throws IOException {
        for (Pair pair : mStrings) {
            writeBoundary(dataPolicy);
            StringBuilder sb = new StringBuilder();
            sb.append(CONTENT_DISPOSITION);
            sb.append(": ");
            sb.append(FORM_DATA);
            sb.append("; ");
            sb.append("name=\"");
            sb.append(pair.first);
            sb.append("\"");
            sb.append(CR_LF);
            sb.append(CR_LF);
            sb.append(pair.second);
            sb.append(CR_LF);
            writeBytes(sb.toString(), dataPolicy);
        }
    }

    private void writeFinishPart(IDataPolicy dataPolicy) throws IOException {
        writeBytes(TWO_DASHES, dataPolicy);
        writeBytes(boundary, dataPolicy);
        writeBytes(TWO_DASHES, dataPolicy);
        writeBytes(CR_LF, dataPolicy);
    }

    private void writeBoundary(IDataPolicy dataPolicy) throws IOException {
        writeBytes(encode(TWO_DASHES), dataPolicy);
        writeBytes(encode(boundary), dataPolicy);
        writeBytes(encode(CR_LF), dataPolicy);
    }

    private void writeBytes(final String str, final IDataPolicy dataPolicy) throws IOException {
        writeBytes(encode(str), dataPolicy);
    }

    private void writeBytes(final ByteArrayBuffer b, IDataPolicy dataPolicy) throws IOException {
        dataPolicy.write(b.buffer(), 0, b.length());
    }

    private ByteArrayBuffer encode(final String string) {
        ByteBuffer encoded = charset.encode(CharBuffer.wrap(string));
        ByteArrayBuffer bab = new ByteArrayBuffer(encoded.remaining());
        bab.append(encoded.array(), encoded.position(), encoded.remaining());
        return bab;
    }

    private String generateBoundary() {
        StringBuilder buffer = new StringBuilder();
        Random rand = new Random();
        int count = rand.nextInt(11) + 30; // a random size from 30 to 40
        for (int i = 0; i < count; i++) {
            buffer.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
        }
        return buffer.toString();
    }

    //below functions are not used for multipart data

    public void consumeContent() throws IOException {
        throw new IOException("consumeContent is not supported!");
    }

    public InputStream getContent() throws IOException, IllegalStateException {
        throw new IOException("getContent is not supported!");
    }

    public Header getContentEncoding() {
        return null;
    }

    public boolean isChunked() {
        return !isRepeatable();
    }

    public boolean isRepeatable() {
        return true;
    }

    public boolean isStreaming() {
        return !isRepeatable();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy