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}