001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.net.http;
020
021import java.io.ByteArrayInputStream;
022import java.io.ByteArrayOutputStream;
023import java.io.IOException;
024import java.io.UnsupportedEncodingException;
025import java.util.Arrays;
026
027import lucee.commons.io.IOUtil;
028import lucee.commons.lang.StringUtil;
029import lucee.runtime.exp.PageException;
030import lucee.runtime.type.Array;
031import lucee.runtime.type.ArrayImpl;
032import lucee.runtime.type.Struct;
033import lucee.runtime.type.StructImpl;
034import lucee.runtime.type.util.KeyConstants;
035import lucee.runtime.type.util.ListUtil;
036
037import org.apache.commons.fileupload.MultipartStream;
038import org.apache.commons.lang.StringUtils;
039
040
041public class MultiPartResponseUtils {
042
043        public static boolean isMultipart(String mimetype) {
044                return !StringUtil.isEmpty(extractBoundary(mimetype,null)) 
045                        && StringUtil.startsWithIgnoreCase(mimetype, "multipart/");
046        }
047
048        public static Array getParts(byte[] barr,String contentTypeHeader) throws IOException, PageException {
049                String boundary = extractBoundary(contentTypeHeader,"");
050                ByteArrayInputStream bis = new ByteArrayInputStream(barr);
051                MultipartStream stream;
052                Array result = new ArrayImpl();
053                stream = new MultipartStream(bis,getBytes(boundary,"UTF-8"));// 
054                
055                boolean hasNextPart = stream.skipPreamble();
056                while (hasNextPart) {
057                        result.append(getPartData(stream));
058                        hasNextPart = stream.readBoundary();
059                }
060                return result;
061        }
062
063        private static String extractBoundary(String contentTypeHeader, String defaultValue) {
064                if (contentTypeHeader == null) return defaultValue;
065                String[] headerSections = ListUtil.listToStringArray(contentTypeHeader, ';');
066                for (String section: headerSections) {
067                        String[] subHeaderSections = ListUtil.listToStringArray(section,'=');
068                        String headerName = subHeaderSections[0].trim();
069                        if (headerName.toLowerCase().equals("boundary")) {
070                                return subHeaderSections[1].replaceAll("^\"|\"$", "");
071                        }
072                
073                }
074                return defaultValue;
075        }
076
077        private static Struct getPartData(MultipartStream stream) throws IOException, PageException {
078                Struct headers = extractHeaders(stream.readHeaders());
079                ByteArrayOutputStream baos = new ByteArrayOutputStream();
080                stream.readBodyData(baos);
081                Struct fileStruct = new StructImpl();
082                fileStruct.set(KeyConstants._content, baos.toByteArray());
083                fileStruct.set(KeyConstants._headers, headers);
084                IOUtil.closeEL(baos);
085                return fileStruct;
086        }
087
088        private static Struct extractHeaders(String rawHeaders) throws PageException {
089                Struct result = new StructImpl();
090                String[] headers = ListUtil.listToStringArray(rawHeaders,'\n');
091                for(String rawHeader :headers) {
092                        String[] headerArray = ListUtil.listToStringArray(rawHeader,':');
093                        String headerName = headerArray[0];
094                        if (!StringUtil.isEmpty(headerName,true)) {
095                                String value = StringUtils.join(Arrays.copyOfRange(headerArray, 1, headerArray.length),":").trim();
096                                result.set(headerName, value);
097                        }
098                }
099                return result;
100        }
101
102        private static byte[] getBytes(String string, String charset) {
103                byte[] bytes;
104                try {
105                        bytes = string.getBytes(charset);
106                } catch (UnsupportedEncodingException e) {
107                        bytes = string.getBytes();
108                }
109                return bytes;
110        }
111
112
113}