/* * Copyright (C) 2000-2015 aw2.0 LTD * * This file is part of Open BlueDragon (OpenBD) CFML Server Engine. * * OpenBD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * Free Software Foundation,version 3. * * OpenBD 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenBD. If not, see http://www.gnu.org/licenses/ * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining * it with any of the JARS listed in the README.txt (or a modified version of * (that library), containing parts covered by the terms of that JAR, the * licensors of this Program grant you additional permission to convey the * resulting work. * README.txt @ http://www.openbluedragon.org/license/README.txt * * http://www.openbd.org/ * $Id: MultipartRequestDecode.java 2526 2015-02-26 15:58:34Z alan $ */ package com.nary.servlet; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; /** * This class will manage all the decoding of the input stream, including the saving * of any uploaded files to a temporary directory, and also the inclusion of parameters. * * The class has been optimized with respect to the choice of buffer size. */ public class MultipartRequestDecode extends Object { List<MultiPartUploadedFile> uploadedFiles; Hashtable formParameters; Hashtable rawFormParameters; BufferedInputStream In; String delimitor; byte buffer[]; boolean endOfPostData; MultiPartUploadedFile currentFile; public MultipartRequestDecode(String contentType, InputStream requestData, File tempDirectory, String _encoding) throws Exception { uploadedFiles = new ArrayList<MultiPartUploadedFile>(1); formParameters = new Hashtable(); rawFormParameters = new Hashtable(); setupConnection(contentType, requestData); decodeInputStream(tempDirectory, _encoding); } private void setupConnection(String contentType, InputStream requestData) throws Exception { In = new BufferedInputStream(requestData); delimitor = contentType; if (delimitor.indexOf("boundary=") != -1) { delimitor = delimitor.substring(delimitor.indexOf("boundary=") + 9, delimitor.length()); delimitor = "--" + delimitor; } buffer = new byte[1024]; currentFile = null; endOfPostData = false; } private void decodeInputStream(File tempDirectory, String _encoding) throws Exception { String param; while ((param = getNextParameter(_encoding)) != null) { if (currentFile != null) { File tmpFile = currentFile.getTempFile(tempDirectory); getParameter( new FileOutputStream( tmpFile ) ); uploadedFiles.add(currentFile); currentFile = null; } else { String nextRawParameter = getParameter(); addRawFormParameter(param, nextRawParameter); addFormParameter(param, new String(nextRawParameter.getBytes("ISO-8859-1"), _encoding)); } } currentFile = null; buffer = null; } private String getParameter() { String Line = ""; String val = ""; for (;;) { Line = readLine(); if (Line == null) continue; else if (Line.startsWith(delimitor)) break; else { val += Line; } } if (val.length() > 1 && val.charAt(val.length() - 1) == '\n') { val = val.substring(0, val.length() - 2); // remove CRLF } return val; } private String getNextParameter(String _encoding) { if (endOfPostData) return null; try { String LineIn = null, paramName = null; while ((LineIn = readLine()) != null) { if (LineIn.indexOf(delimitor + "--") == 0) return null; if (LineIn.indexOf("name=") != -1) { int c1 = LineIn.indexOf("name="); int c2 = LineIn.indexOf("\"", c1 + 6); paramName = LineIn.substring(c1 + 6, c2); if (LineIn.indexOf("filename=") != -1) { currentFile = new MultiPartUploadedFile(); currentFile.formName = paramName; currentFile.setFilename(new String(LineIn.getBytes("ISO-8859-1"), _encoding)); } // - Move the pointer to the start of the data LineIn = readLine(); if (LineIn.indexOf("Content-Type") != -1) { if (currentFile != null) currentFile.setContentType(LineIn); LineIn = readLine(); // --[ clean up the last line while (!LineIn.equals("\r\n")) LineIn = readLine(); } return paramName; } } } catch (Exception E) { } return null; } private boolean getParameter(OutputStream _Out) { try { int noData, noData2 = -1; String tester; boolean bFirst = true; byte buffer1[] = new byte[64000]; byte buffer2[] = new byte[64000]; int delimLen = delimitor.length(); int delimPos; while ((noData = read(buffer1, 0, buffer1.length)) != -1) { /* * Generally the file post is ended by a \r\n followed by the boundary * but if the file content ends in a blank line then we have a single \n * or \r followed by the boundary. */ if ((buffer1[0] == '-' || buffer1[0] == '\n' || buffer1[0] == '\r') && noData >= delimLen) { tester = new String(buffer1, 0, noData, "ISO-8859-1"); delimPos = tester.indexOf(delimitor); if (tester.length() >= delimLen && delimPos != -1) { if (noData2 >= 2) noData2 -= 2; _Out.write(buffer2, 0, noData2); // if boundary isn't at the start of the line write out the chars // that appear before it if (delimPos != 0) _Out.write(buffer1, 0, delimPos); // Check to see if this was the end of the stream if (tester.indexOf(delimitor + "--") == 0) endOfPostData = true; break; } } if (!bFirst) _Out.write(buffer2, 0, noData2); else bFirst = false; for (int x = 0; x < noData; x++) buffer2[x] = buffer1[x]; noData2 = noData; _Out.flush(); } _Out.flush(); return true; } catch (Exception E) { }finally{ try { _Out.close(); } catch (IOException e) {} } return false; } private String readLine() { try { byte b[] = new byte[1024]; int noData = read(b, 0, b.length); if (noData != -1) { return new String(b, 0, noData, "ISO-8859-1"); } } catch (Exception E) { } return null; } private int read(byte b[], int off, int len) throws IOException { // This method reads up to the current buffer, or the next line. int inChar; int noChars = -1; while ((noChars < len) && ((inChar = In.read()) != -1)) { if (noChars == -1) noChars = 0; noChars++; b[noChars + off - 1] = (byte) inChar; if (noChars > 1 && (((char) b[noChars + off - 2] == '\r' && (char) b[noChars + off - 1] == '\n') || ((char) b[noChars + off - 2] == '\n' && (char) b[noChars + off - 1] == '\r'))) { break; } if (noChars == len) break; } return noChars; } private void addRawFormParameter(String key, String _data) { Object data = _data; if (rawFormParameters.containsKey(key)) { data = rawFormParameters.get(key); if (data instanceof List) { ((List) data).add(_data); } else { ArrayList newList = new ArrayList(); newList.add(data); newList.add(_data); data = newList; } } rawFormParameters.put(key, data); } private void addFormParameter(String key, String data) { if (formParameters.containsKey(key)) data = (String) formParameters.get(key) + "," + data; formParameters.put(key, data); } public List<MultiPartUploadedFile> getFiles() { return uploadedFiles; } public Hashtable getRawParameters() { return rawFormParameters; } public Enumeration getParameterNames() { return formParameters.keys(); } public String getParameter(String param) { return (String) formParameters.get(param); } }