/** * Copyright (C) 2009 eXo Platform SAS. * * This 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 2.1 of * the License, or (at your option) any later version. * * This software 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 this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.upload; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.exoplatform.services.html.refs.RefsDecoder; /** * Author : Oleg Kalnichevski oleg@ural.ru Author : Nhu Dinh Thuan nhudinhthuan@exoplatform.com Dec 26, 2006 * */ class RequestStreamReader { private static final byte LF = 0x0A; private static final byte DASH = 0x2D; private static final byte CR = 0x0D; private static final byte[] HEADER_SEPARATOR = { CR, LF, CR, LF }; private static final byte[] BOUNDARY_PREFIX = { CR, LF, DASH, DASH }; private static final String CONTENT_DISPOSITION = "Content-disposition"; private static final String FORM_DATA = "form-data"; private static final int HEADER_PART_SIZE_MAX = 10240; private static final String ATTACHMENT = "attachment"; private static final int DEFAULT_BUFSIZE = 4096; static final String CONTENT_TYPE = "content-type"; private int head; private int tail; private int bufSize; private byte[] buffer; private UploadResource upResource_; private RefsDecoder refsDecoder_; RequestStreamReader(UploadResource upResource) { upResource_ = upResource; head = 0; tail = 0; bufSize = DEFAULT_BUFSIZE; buffer = new byte[bufSize]; refsDecoder_ = new RefsDecoder(); } void readBodyData(HttpServletRequest request, OutputStream output) throws IOException { readBodyData(request.getInputStream(), request.getContentType(), output); } void readBodyData(InputStream input, String contentType, OutputStream output) throws IOException { int pad; int bytesRead; int total = 0; byte[] bdr = getBoundary(contentType); byte[] boundary = new byte[bdr.length + BOUNDARY_PREFIX.length]; int keepRegion = boundary.length + 4; try { while (upResource_.getStatus() == UploadResource.UPLOADING_STATUS) { if (tail - head > keepRegion) { pad = keepRegion; } else { pad = tail - head; } output.write(buffer, head, tail - head - pad); upResource_.addUploadedBytes(tail - head - pad); total += tail - head - pad; System.arraycopy(buffer, tail - pad, buffer, 0, pad); head = 0; bytesRead = input.read(buffer, pad, bufSize - pad); if (bytesRead != -1) { tail = pad + bytesRead; continue; } output.flush(); total += pad; break; } } finally { if (input != null) input.close(); if (output != null) output.close(); } } Map<String, String> parseHeaders(InputStream input, String headerEncoding) throws IOException { String txtHeaders = readHeaders(input, headerEncoding); return parseHeaders(txtHeaders); } Map<String, String> parseHeaders(String headerPart) { Map<String, String> headers = new HashMap<String, String>(); char[] chars = new char[1024]; boolean done = false; int j = 0; int i; String header, headerName, headerValue; while (!done) { i = 0; while (i < 2 || chars[i - 2] != '\r' || chars[i - 1] != '\n') { chars[i++] = headerPart.charAt(j++); } header = new String(chars, 0, i - 2); if (header.length() < 1) { done = true; continue; } if (header.indexOf(':') == -1) continue; headerName = header.substring(0, header.indexOf(':')).trim().toLowerCase(); headerValue = header.substring(header.indexOf(':') + 1).trim(); if (getHeader(headers, headerName) != null) { headers.put(headerName, getHeader(headers, headerName) + ',' + headerValue); continue; } headers.put(headerName, headerValue); } return headers; } private String getHeader(Map<String, String> headers, String name) { return headers.get(name.toLowerCase()); } private String readHeaders(InputStream input, String headerEncoding) throws IOException { int i = 0; byte[] b = new byte[1]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); int sizeMax = HEADER_PART_SIZE_MAX; int size = 0; while (i < HEADER_SEPARATOR.length) { try { b[0] = readByte(input); } catch (IOException e) { throw new IOException("Stream ended unexpectedly"); } size++; if (b[0] == HEADER_SEPARATOR[i]) i++; else i = 0; if (size <= sizeMax) baos.write(b[0]); } if (headerEncoding != null) { try { return baos.toString(headerEncoding); } catch (Exception e) { } } return baos.toString("UTF-8"); } private byte readByte(InputStream input) throws IOException { if (head != tail) return buffer[head++]; head = 0; tail = input.read(buffer, head, bufSize); if (tail == -1) throw new IOException("No more data is available"); return buffer[head++]; } private byte[] getBoundary(String contentType) { ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); Map<String, String> params = parser.parse(contentType, ';'); String boundaryStr = params.get("boundary"); if (boundaryStr == null) return null; try { return boundaryStr.getBytes("ISO-8859-1"); } catch (Exception e) { return boundaryStr.getBytes(); } } String getFileName(Map<String, String> headers) { String cd = getHeader(headers, CONTENT_DISPOSITION); if (cd == null) return null; String cdl = cd.toLowerCase(); if (!cdl.startsWith(FORM_DATA) && !cdl.startsWith(ATTACHMENT)) return null; ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); Map<String, String> params = parser.parse(cd, ';'); if (params.containsKey("filename")) { String fileName = params.get("filename"); fileName = refsDecoder_.decode(fileName); if (fileName != null) return fileName.trim(); return ""; } return null; } }