/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library 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 library 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. */ package com.liferay.portal.upload; import com.liferay.portal.kernel.io.ByteArrayFileInputStream; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.upload.FileItem; import com.liferay.portal.kernel.upload.UploadException; import com.liferay.portal.kernel.upload.UploadServletRequest; import com.liferay.portal.kernel.util.ArrayUtil; import com.liferay.portal.kernel.util.FileUtil; import com.liferay.portal.kernel.util.ProgressTracker; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.SystemProperties; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import com.liferay.portal.util.PrefsPropsUtil; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpSession; import org.apache.commons.fileupload.FileUploadBase; import org.apache.commons.fileupload.servlet.ServletFileUpload; /** * @author Brian Wing Shun Chan * @author Zongliang Li * @author Harry Mark * @author Raymond Augé */ public class UploadServletRequestImpl extends HttpServletRequestWrapper implements UploadServletRequest { public static File getTempDir() { if (_tempDir == null) { _tempDir = new File( PrefsPropsUtil.getString( PropsKeys.UPLOAD_SERVLET_REQUEST_IMPL_TEMP_DIR, SystemProperties.get(SystemProperties.TMP_DIR))); } return _tempDir; } public static void setTempDir(File tempDir) { _tempDir = tempDir; } public UploadServletRequestImpl(HttpServletRequest request) { super(request); _fileParameters = new LinkedHashMap<>(); _regularParameters = new LinkedHashMap<>(); LiferayServletRequest liferayServletRequest = null; try { HttpSession session = request.getSession(); session.removeAttribute(ProgressTracker.PERCENT); ServletFileUpload servletFileUpload = new ServletFileUpload( new LiferayFileItemFactory(getTempDir())); liferayServletRequest = new LiferayServletRequest(request); List<org.apache.commons.fileupload.FileItem> fileItems = servletFileUpload.parseRequest(liferayServletRequest); liferayServletRequest.setFinishedReadingOriginalStream(true); long uploadServletRequestImplMaxSize = PrefsPropsUtil.getLong( PropsKeys.UPLOAD_SERVLET_REQUEST_IMPL_MAX_SIZE); long uploadServletRequestImplSize = 0; int contentLength = request.getContentLength(); if ((uploadServletRequestImplMaxSize > 0) && ((contentLength == -1) || (contentLength > uploadServletRequestImplMaxSize))) { fileItems = sort(fileItems); } for (org.apache.commons.fileupload.FileItem fileItem : fileItems) { LiferayFileItem liferayFileItem = (LiferayFileItem)fileItem; if (uploadServletRequestImplMaxSize > 0) { long itemSize = liferayFileItem.getItemSize(); if ((uploadServletRequestImplSize + itemSize) > uploadServletRequestImplMaxSize) { StringBundler sb = new StringBundler(3); sb.append( "Request reached the maximum permitted size of "); sb.append(uploadServletRequestImplMaxSize); sb.append(" bytes"); UploadException uploadException = new UploadException( sb.toString()); uploadException.setExceededUploadRequestSizeLimit(true); request.setAttribute( WebKeys.UPLOAD_EXCEPTION, uploadException); continue; } uploadServletRequestImplSize += itemSize; } if (liferayFileItem.isFormField()) { liferayFileItem.setString(request.getCharacterEncoding()); String fieldName = liferayFileItem.getFieldName(); if (!_regularParameters.containsKey(fieldName)) { _regularParameters.put( fieldName, new ArrayList<String>()); } List<String> values = _regularParameters.get(fieldName); if (liferayFileItem.getSize() > LiferayFileItem.THRESHOLD_SIZE) { StringBundler sb = new StringBundler(5); sb.append("The field "); sb.append(fieldName); sb.append(" exceeds its maximum permitted size of "); sb.append(LiferayFileItem.THRESHOLD_SIZE); sb.append(" bytes"); UploadException uploadException = new UploadException( sb.toString()); uploadException.setExceededLiferayFileItemSizeLimit( true); request.setAttribute( WebKeys.UPLOAD_EXCEPTION, uploadException); } values.add(liferayFileItem.getEncodedString()); continue; } FileItem[] liferayFileItems = _fileParameters.get( liferayFileItem.getFieldName()); if (liferayFileItems == null) { liferayFileItems = new LiferayFileItem[] {liferayFileItem}; } else { LiferayFileItem[] newLiferayFileItems = new LiferayFileItem[liferayFileItems.length + 1]; System.arraycopy( liferayFileItems, 0, newLiferayFileItems, 0, liferayFileItems.length); newLiferayFileItems[newLiferayFileItems.length - 1] = liferayFileItem; liferayFileItems = newLiferayFileItems; } _fileParameters.put( liferayFileItem.getFieldName(), liferayFileItems); } } catch (Exception e) { UploadException uploadException = new UploadException(e); if (e instanceof FileUploadBase.FileSizeLimitExceededException) { uploadException.setExceededFileSizeLimit(true); } else if (e instanceof FileUploadBase.SizeLimitExceededException) { uploadException.setExceededUploadRequestSizeLimit(true); } request.setAttribute(WebKeys.UPLOAD_EXCEPTION, uploadException); if (_log.isDebugEnabled()) { _log.debug(e, e); } } _liferayServletRequest = liferayServletRequest; } public UploadServletRequestImpl( HttpServletRequest request, Map<String, FileItem[]> fileParameters, Map<String, List<String>> regularParameters) { super(request); _fileParameters = new LinkedHashMap<>(); _regularParameters = new LinkedHashMap<>(); if (fileParameters != null) { _fileParameters.putAll(fileParameters); } if (regularParameters != null) { _regularParameters.putAll(regularParameters); } _liferayServletRequest = null; } @Override public void cleanUp() { if ((_fileParameters != null) && !_fileParameters.isEmpty()) { for (FileItem[] liferayFileItems : _fileParameters.values()) { for (FileItem liferayFileItem : liferayFileItems) { liferayFileItem.delete(); } } } if (_liferayServletRequest != null) { _liferayServletRequest.cleanUp(); } } @Override public String getContentType(String name) { FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isNotEmpty(liferayFileItems)) { FileItem liferayFileItem = liferayFileItems[0]; return liferayFileItem.getContentType(); } return null; } @Override public File getFile(String name) { return getFile(name, false); } @Override public File getFile(String name, boolean forceCreate) { if (getFileName(name) == null) { return null; } FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isEmpty(liferayFileItems)) { return null; } FileItem liferayFileItem = liferayFileItems[0]; long size = liferayFileItem.getSize(); if ((size > 0) && (size <= liferayFileItem.getSizeThreshold())) { forceCreate = true; } File file = liferayFileItem.getStoreLocation(); if (liferayFileItem.isInMemory() && forceCreate) { try { FileUtil.write(file, liferayFileItem.getInputStream()); } catch (IOException ioe) { if (_log.isWarnEnabled()) { _log.warn( "Unable to write temporary file " + file.getAbsolutePath(), ioe); } } } return file; } @Override public InputStream getFileAsStream(String name) throws IOException { return getFileAsStream(name, true); } @Override public InputStream getFileAsStream(String name, boolean deleteOnClose) throws IOException { if (getFileName(name) == null) { return null; } InputStream inputStream = null; FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isNotEmpty(liferayFileItems)) { FileItem liferayFileItem = liferayFileItems[0]; inputStream = getInputStream(liferayFileItem, deleteOnClose); } return inputStream; } @Override public String getFileName(String name) { FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isNotEmpty(liferayFileItems)) { FileItem liferayFileItem = liferayFileItems[0]; return liferayFileItem.getFileName(); } return null; } @Override public String[] getFileNames(String name) { FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isNotEmpty(liferayFileItems)) { String[] fileNames = new String[liferayFileItems.length]; for (int i = 0; i < liferayFileItems.length; i++) { FileItem liferayFileItem = liferayFileItems[i]; fileNames[i] = liferayFileItem.getFileName(); } return fileNames; } return null; } @Override public File[] getFiles(String name) { String[] fileNames = getFileNames(name); if (fileNames == null) { return null; } FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isNotEmpty(liferayFileItems)) { File[] files = new File[liferayFileItems.length]; for (int i = 0; i < liferayFileItems.length; i++) { FileItem liferayFileItem = liferayFileItems[i]; if (Validator.isNotNull(liferayFileItem.getFileName())) { files[i] = liferayFileItem.getStoreLocation(); } } return files; } return null; } @Override public InputStream[] getFilesAsStream(String name) throws IOException { return getFilesAsStream(name, true); } @Override public InputStream[] getFilesAsStream(String name, boolean deleteOnClose) throws IOException { String[] fileNames = getFileNames(name); if (fileNames == null) { return null; } InputStream[] inputStreams = null; FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isNotEmpty(liferayFileItems)) { inputStreams = new InputStream[liferayFileItems.length]; for (int i = 0; i < liferayFileItems.length; i++) { FileItem liferayFileItem = liferayFileItems[i]; if (Validator.isNotNull(liferayFileItem.getFileName())) { inputStreams[i] = getInputStream( liferayFileItem, deleteOnClose); } } } return inputStreams; } @Override public String getFullFileName(String name) { FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isNotEmpty(liferayFileItems)) { FileItem liferayFileItem = liferayFileItems[0]; return liferayFileItem.getFullFileName(); } return null; } @Override public ServletInputStream getInputStream() throws IOException { if (_liferayServletRequest != null) { return _liferayServletRequest.getInputStream(); } return super.getInputStream(); } @Override public Map<String, FileItem[]> getMultipartParameterMap() { return _fileParameters; } @Override public String getParameter(String name) { List<String> values = _regularParameters.get(name); if ((values != null) && !values.isEmpty()) { return values.get(0); } return super.getParameter(name); } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> map = new HashMap<>(); Enumeration<String> enu = getParameterNames(); while (enu.hasMoreElements()) { String name = enu.nextElement(); String[] values = getParameterValues(name); if (values != null) { map.put(name, values); } } return map; } @Override public Enumeration<String> getParameterNames() { Set<String> parameterNames = new LinkedHashSet<>(); Enumeration<String> enu = super.getParameterNames(); while (enu.hasMoreElements()) { parameterNames.add(enu.nextElement()); } parameterNames.addAll(_regularParameters.keySet()); parameterNames.addAll(_fileParameters.keySet()); return Collections.enumeration(parameterNames); } @Override public String[] getParameterValues(String name) { String[] parameterValues = null; List<String> values = _regularParameters.get(name); if (values != null) { parameterValues = values.toArray(new String[values.size()]); } String[] parentParameterValues = super.getParameterValues(name); if (parameterValues == null) { return parentParameterValues; } else if (parentParameterValues == null) { return parameterValues; } return ArrayUtil.append(parameterValues, parentParameterValues); } @Override public Map<String, List<String>> getRegularParameterMap() { return _regularParameters; } @Override public Long getSize(String name) { FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isNotEmpty(liferayFileItems)) { FileItem liferayFileItem = liferayFileItems[0]; return Long.valueOf(liferayFileItem.getSize()); } return null; } @Override public Boolean isFormField(String name) { FileItem[] liferayFileItems = _fileParameters.get(name); if (ArrayUtil.isNotEmpty(liferayFileItems)) { FileItem liferayFileItem = liferayFileItems[0]; return liferayFileItem.isFormField(); } return null; } protected InputStream getInputStream( FileItem liferayFileItem, boolean deleteOnClose) throws IOException { InputStream inputStream = null; if (liferayFileItem.isInMemory() && (liferayFileItem.getSize() > 0)) { inputStream = liferayFileItem.getInputStream(); } else if (!liferayFileItem.isInMemory()) { inputStream = new ByteArrayFileInputStream( liferayFileItem.getStoreLocation(), liferayFileItem.getSizeThreshold(), deleteOnClose); } return inputStream; } protected List<org.apache.commons.fileupload.FileItem> sort( List<org.apache.commons.fileupload.FileItem> fileItems) { Map<String, GroupedFileItems> groupedFileItemsMap = new HashMap<>(); for (org.apache.commons.fileupload.FileItem fileItem : fileItems) { String fieldName = fileItem.getFieldName(); GroupedFileItems groupedFileItems = groupedFileItemsMap.get( fieldName); if (groupedFileItems == null) { groupedFileItems = new GroupedFileItems(fieldName); groupedFileItemsMap.put(fieldName, groupedFileItems); } groupedFileItems.addFileItem(fileItem); } Set<GroupedFileItems> groupedFileItemsList = new TreeSet<>( groupedFileItemsMap.values()); List<org.apache.commons.fileupload.FileItem> sortedFileItems = new ArrayList<>(); for (GroupedFileItems groupedFileItems : groupedFileItemsList) { sortedFileItems.addAll(groupedFileItems.getFileItems()); } return sortedFileItems; } private static final Log _log = LogFactoryUtil.getLog( UploadServletRequestImpl.class); private static File _tempDir; private final Map<String, FileItem[]> _fileParameters; private final LiferayServletRequest _liferayServletRequest; private final Map<String, List<String>> _regularParameters; private static class GroupedFileItems implements Comparable<GroupedFileItems> { public GroupedFileItems(String key) { _key = key; } public void addFileItem( org.apache.commons.fileupload.FileItem fileItem) { _fileItems.add(fileItem); _fileItemsSize += fileItem.getSize(); } @Override public int compareTo(GroupedFileItems groupedFileItems) { if (groupedFileItems == null) { return 1; } if (equals(groupedFileItems)) { return 0; } if (_key.equals(groupedFileItems._key)) { return 1; } if (getFileItemsSize() >= groupedFileItems.getFileItemsSize()) { return 1; } return -1; } public List<org.apache.commons.fileupload.FileItem> getFileItems() { return _fileItems; } public int getFileItemsSize() { return _fileItemsSize; } private final List<org.apache.commons.fileupload.FileItem> _fileItems = new ArrayList<>(); private int _fileItemsSize; private final String _key; } }