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

com.emc.atmos.api.multipart.MultipartEntity Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2013 EMC Corporation. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * or in the "license" file accompanying this file. This file 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.
 */
package com.emc.atmos.api.multipart;

import com.emc.atmos.api.Range;
import com.emc.util.StreamUtil;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Represents a multipart response entity.
 */
public class MultipartEntity extends ArrayList {
    private static final long serialVersionUID = -4788353053749563899L;

    private static final Pattern PATTERN_CONTENT_TYPE = Pattern.compile( "^Content-Type: (.+)$" );
    private static final Pattern PATTERN_CONTENT_RANGE = Pattern.compile( "^Content-Range: bytes (\\d+)-(\\d+)/(\\d+)$" );

    /**
     * Parses a multipart response body provided by an InputStream. Returns an instance of this class that represents
     * the response. boundary may start with "--" or omit it.
     */
    public static MultipartEntity fromStream( InputStream is, String boundary ) throws IOException {
        if ( boundary.startsWith( "--" ) ) boundary = boundary.substring( 2 );

        List parts = new ArrayList();

        try {
            while ( true ) {

                // first, we expect a boundary ( EOL + '--' +  + EOL )
                if ( !"".equals( StreamUtil.readLine( is ) ) )
                    throw new MultipartException( "Parse error: expected EOL before boundary" );
                String line = StreamUtil.readLine( is );

                // two dashes after the boundary means EOS
                if ( ("--" + boundary + "--").equals( line ) ) break;

                if ( !("--" + boundary).equals( line ) ) throw new MultipartException(
                        "Parse error: expected [--" + boundary + "], instead got [" + line + "]" );

                Matcher matcher;
                String contentType = null;
                int start = -1, end = 0, length = 0;
                while ( !"".equals( line = StreamUtil.readLine( is ) ) ) {
                    matcher = PATTERN_CONTENT_TYPE.matcher( line );
                    if ( matcher.find() ) {
                        contentType = matcher.group( 1 );
                        continue;
                    }

                    matcher = PATTERN_CONTENT_RANGE.matcher( line );
                    if ( matcher.find() ) {
                        start = Integer.parseInt( matcher.group( 1 ) );
                        end = Integer.parseInt( matcher.group( 2 ) );
                        length = end - start + 1;
                        // total = Integer.parseInt( matcher.group( 3 ) );
                        continue;
                    }

                    throw new MultipartException( "Unrecognized header line: " + line );
                }

                if ( contentType == null )
                    throw new MultipartException( "Parse error: No content-type specified in part" );

                if ( start == -1 )
                    throw new MultipartException( "Parse error: No content-range specified in part" );

                // then the data of the part
                byte[] data = new byte[length];
                int read, count = 0;
                while ( count < length ) {
                    read = is.read( data, 0, length - count );
                    count += read;
                }

                parts.add( new MultipartPart( contentType, new Range( start, end ), data ) );
            }
        } finally {
            is.close();
        }

        return new MultipartEntity( parts );
    }

    public MultipartEntity( List parts ) {
        super( parts );
    }

    /**
     * Convenience method that aggregates the bytes of all parts into one contiguous byte array.
     */
    public byte[] aggregateBytes() {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            for ( MultipartPart part : this ) {
                baos.write( part.getData() );
            }
            return baos.toByteArray();
        } catch ( IOException e ) {
            throw new RuntimeException( "Unexpected error", e ); // unrecoverable
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy