/* * Copyright 2013 Simon Thiel * * This file is part of SitJar. * * SitJar is free software: you can redistribute it and/or modify * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * SitJar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with SitJar. If not, see <http://www.gnu.org/licenses/lgpl.txt>. */ package sit.web.multipart; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; import sit.sstl.ByteBuilder; import sit.web.HTTPParseHelper; import sit.web.HttpConstants; import sit.web.WebRequest; import sit.web.WebRequest.ContentType; /** * * @author simon */ public class MultipartParser { public static MultipartContainer parse(String pure_boundary, Charset charSet, byte[] payload) throws UnsupportedEncodingException { MultipartContainer result = new MultipartContainer(pure_boundary); //##CHARSET_MARKER## byte[] part_boundary = result.getPart_boundary().getBytes(charSet); ByteBuilder content = new ByteBuilder(payload); int oldIndex = part_boundary.length + HttpConstants.CRLF_BYTE.length; int index; while (-1 != (index = content.indexOf(oldIndex, part_boundary))) { result.addPart(parsePart(charSet, content.subSequence(oldIndex, index-HttpConstants.CRLF_BYTE.length))); oldIndex = index + part_boundary.length + HttpConstants.CRLF_BYTE.length; } return result; } private static MultipartEntry parsePart(Charset charSet, byte[] subSequence) { ByteBuilder content = new ByteBuilder(subSequence); String name = null; String fileName = null; TYPES type = TYPES.UNKNOWN; ContentType contentType = new WebRequest.ContentType(); contentType.charSet = charSet; int endOfHeader = content.indexOf(HttpConstants.CRLFCRLF_BYTE); if (endOfHeader == -1) { //header not found or last entry ... Logger.getLogger(MultipartParser.class.getName()).log(Level.WARNING, "header not found in " + new String(subSequence, charSet)); return null; } //TODO re-use HTTPMessage parser for parsing the headers !!! //##CHARSET_MARKER## String header = new String(content.subSequence(0, endOfHeader), charSet); HashMap<String, String> headerFields = HTTPParseHelper.parseAndFillFittingValues( new String[]{HttpConstants.CONTENT_DISPOSITION_TAG, HttpConstants.CONTENT_TRANSFER_ENCODING_BINARY_TAG, HttpConstants.CONTENT_TYPE_TAG}, header.split(HttpConstants.CRLF)); if (headerFields.containsKey(HttpConstants.CONTENT_DISPOSITION_TAG)) { String disposition = headerFields.get(HttpConstants.CONTENT_DISPOSITION_TAG); HashMap<String, String> dispoFields = HTTPParseHelper.parseAndFillFittingValues( new String[]{HttpConstants.NAME_DISPOSITION_TAG, HttpConstants.FILENAME_DISPOSITION_TAG}, disposition.split(HttpConstants.SUB_FIELD_SEPARATOR)); name = dispoFields.get(HttpConstants.NAME_DISPOSITION_TAG); fileName = dispoFields.get(HttpConstants.FILENAME_DISPOSITION_TAG); } if (headerFields.containsKey(HttpConstants.CONTENT_TRANSFER_ENCODING_BINARY_TAG)) { type = TYPES.BINARY; } if (headerFields.containsKey(HttpConstants.CONTENT_TYPE_TAG)) { String contentTypePayload = headerFields.get(HttpConstants.CONTENT_TYPE_TAG); contentType.parseContentType(contentTypePayload); if (contentType.mimeType.equalsIgnoreCase(HttpConstants.MIME_APPLICATION_OCTETSTREAM)) { type = TYPES.BINARY; } else if (!contentType.mimeType.equalsIgnoreCase(HttpConstants.DEFAULT_MIME_TYPE)) { type = TYPES.MIME; } charSet = contentType.charSet; //possibly been changed by content-type setting... } MultipartEntry result = null; if (type.equals(TYPES.BINARY)) { result = new MPFileEntry(type, contentType.mimeType, name, fileName, content.subSequence(endOfHeader + HttpConstants.CRLFCRLF_BYTE.length)); } else { //##CHARSET_MARKER## result = new MPTextEntry(type, contentType.mimeType, name, new String(content.subSequence(endOfHeader + HttpConstants.CRLFCRLF_BYTE.length),charSet)); } return result; } }