package com.idega.content.upload.servlet; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUpload; import org.apache.commons.fileupload.FileUploadBase; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletRequestContext; import com.idega.content.business.ContentConstants; import com.idega.content.business.ContentUtil; import com.idega.content.repository.stream.bean.StreamData; import com.idega.content.repository.stream.bean.StreamResult; import com.idega.content.themes.helpers.business.ThemesConstants; import com.idega.content.upload.bean.UploadFile; import com.idega.content.upload.business.FileUploadProgressListener; import com.idega.content.upload.business.FileUploader; import com.idega.idegaweb.IWApplicationContext; import com.idega.idegaweb.IWResourceBundle; import com.idega.presentation.IWContext; import com.idega.util.CoreConstants; import com.idega.util.CoreUtil; import com.idega.util.FileUtil; import com.idega.util.IOUtil; import com.idega.util.ListUtil; import com.idega.util.StringHandler; import com.idega.util.StringUtil; import com.idega.util.expression.ELUtil; public class ContentFileUploadServlet extends HttpServlet { private static Logger LOGGER = Logger.getLogger(ContentFileUploadServlet.class.getName()); private static final long serialVersionUID = -6282517406996613536L; public static final long MAX_UPLOAD_SIZE = 20 * 1024 * 1024; // 20 MBs public static final String PARAMETER_BINARY_STREAM = "binaryStream"; @SuppressWarnings("unchecked") @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String binaryStream = request.getParameter(PARAMETER_BINARY_STREAM); if (!StringUtil.isEmpty(binaryStream) && Boolean.TRUE.toString().equals(binaryStream)) { handleStream(request, response); return; } Boolean success = Boolean.FALSE; String uploadId = null; IWApplicationContext iwac = null; FileUploadProgressListener uploadProgressListener = null; try { IWContext iwc = new IWContext(request, response, getServletContext()); iwac = iwc.getApplicationContext(); ServletRequestContext src = new ServletRequestContext(request); if (!FileUploadBase.isMultipartContent(src)) { LOGGER.log(Level.WARNING, "Request is not multipart content, terminating upload!"); return; } String uploadPath = null; boolean zipFile = false; boolean themePack = false; boolean extractContent = false; boolean stripNonRomanLetters = false; uploadProgressListener = ELUtil.getInstance().getBean(FileUploadProgressListener.class); DiskFileItemFactory factory = new DiskFileItemFactory(); FileUpload fileUploadService = new FileUpload(factory); long maxUploadSize = uploadProgressListener.getMaxSize(); maxUploadSize = maxUploadSize <= 0 ? MAX_UPLOAD_SIZE : maxUploadSize; // 10% reserved for other data when file(s) maxUploadSize = maxUploadSize == MAX_UPLOAD_SIZE ? maxUploadSize : Double.valueOf(maxUploadSize * 1.1).longValue(); fileUploadService.setSizeMax(maxUploadSize); fileUploadService.setProgressListener(uploadProgressListener); uploadId = uploadProgressListener.getUploadId(); if (!StringUtil.isEmpty(uploadId)) iwac.setApplicationAttribute(uploadId, Boolean.TRUE); if (IOUtil.isUploadExceedingLimits(request, maxUploadSize)) { IWResourceBundle iwrb = ContentUtil.getBundle().getResourceBundle(iwc); writeToResponse(response, "error=".concat(iwrb.getLocalizedString("uploader_error_exceeds_max_size", "The file you are uploading is exceeding the limits")).concat(": ").concat(FileUtil.getHumanReadableSize(maxUploadSize))); uploadProgressListener.markFailedUpload(uploadId); finishUpUpload(iwac, uploadProgressListener, uploadId, false); return; } String fileItem = request.getParameter("fileItem"); if (!StringUtil.isEmpty(fileItem)) { int fileItemNr = -1; try { fileItemNr = Integer.valueOf(fileItem); } catch (NumberFormatException e) {} uploadProgressListener.setFileNumberInUploadSequence(fileItemNr); } List<FileItem> fileItems = null; try { // Submitted data is copied from client to server fileItems = fileUploadService.parseRequest(src); } catch (Exception e) { String message = "Error parsing request " + src + "\n. Client: " + iwc.getUserAgent(); LOGGER.log(Level.WARNING, message, e); CoreUtil.sendExceptionNotification(message, e); } if (ListUtil.isEmpty(fileItems)) { LOGGER.log(Level.WARNING, "No files to upload, terminating upload!"); IWResourceBundle iwrb = ContentUtil.getBundle().getResourceBundle(iwc); writeToResponse(response, "error=".concat(iwrb.getLocalizedString("uploader_error_failed_to_upload", "Failed to upload file(s) to the server. Please try again."))); uploadProgressListener.markFailedUpload(uploadId); finishUpUpload(iwac, uploadProgressListener, uploadId, false); return; } LOGGER.info("Data was copied to the server (ID: " + uploadId + "), now will upload to the repository"); String fieldName = null; List<UploadFile> files = new ArrayList<UploadFile>(); for (FileItem file: fileItems) { fieldName = file.getFieldName(); if (!StringUtil.isEmpty(fieldName)) { if (file.getSize() > 0 && fieldName.equals(ContentConstants.UPLOAD_FIELD_NAME)) { files.add(new UploadFile(file.getName(), file.getContentType(), file.getSize(), file.get())); } else if (fieldName.equals(ContentConstants.UPLOADER_PATH)) { uploadPath = getValueFromBytes(file.get()); } else if (fieldName.equals(ContentConstants.UPLOADER_UPLOAD_ZIP_FILE)) { zipFile = getValueFromString(getValueFromBytes(file.get())); } else if (fieldName.equals(ContentConstants.UPLOADER_UPLOAD_THEME_PACK)) { themePack = getValueFromString(getValueFromBytes(file.get())); } else if (fieldName.equals(ContentConstants.UPLOADER_UPLOAD_EXTRACT_ARCHIVED_FILE)) { extractContent = getValueFromString(getValueFromBytes(file.get())); } else if (fieldName.equals(ContentConstants.UPLOADER_UPLOAD_IDENTIFIER)) { uploadId = getValueFromBytes(file.get()); } else if (fieldName.equals(ContentConstants.UPLOADER_STRIP_NON_ROMAN_LETTERS)) { stripNonRomanLetters = getValueFromString(getValueFromBytes(file.get())); } } } if (ListUtil.isEmpty(files)) { LOGGER.log(Level.WARNING, "No files to upload, terminating upload!"); return; } if (!StringUtil.isEmpty(uploadId)) iwac.setApplicationAttribute(uploadId, Boolean.TRUE); String errorMessage = null; try { // Checking upload path if (uploadPath == null) { // Using default upload path uploadPath = CoreConstants.PUBLIC_PATH + CoreConstants.SLASH; } if (!uploadPath.startsWith(CoreConstants.SLASH)) { uploadPath = CoreConstants.SLASH + uploadPath; } if (!uploadPath.endsWith(CoreConstants.SLASH)) { uploadPath += CoreConstants.SLASH; } if (stripNonRomanLetters) { uploadPath = getStripped(uploadPath); prepareFiles(files); } boolean isIE = CoreUtil.isIE(request); if (!(success = upload(files, uploadPath, zipFile, themePack, isIE, extractContent))) success = upload(files, uploadPath, zipFile, themePack, isIE, extractContent); // Re-uploading in case of error if (success) { StringBuffer responseBuffer = new StringBuffer(); for (Iterator<UploadFile> filesIter = files.iterator(); filesIter.hasNext();) { UploadFile file = filesIter.next(); file.setPath(uploadPath); responseBuffer.append(file.getName()); if (filesIter.hasNext()) { responseBuffer.append(CoreConstants.COMMA); } } uploadProgressListener.addUploadedFiles(uploadId, files); writeToResponse(response, responseBuffer.toString()); } else { errorMessage = "Unable to upload files (" + files + ") to: " + uploadPath + ". Upload ID: " + uploadId; throw new RuntimeException(errorMessage); } } catch(Exception e) { errorMessage = errorMessage == null ? "Files uploader failed! Unable to upload files: " + files + " to: " + uploadPath + ". Upload ID: " + uploadId : errorMessage; LOGGER.log(Level.SEVERE, errorMessage, e); CoreUtil.sendExceptionNotification(errorMessage, e); } finally { finishUpUpload(iwac, uploadProgressListener, uploadId, success); } } finally { if (!success && uploadProgressListener != null) { uploadProgressListener.markFailedUpload(uploadId); finishUpUpload(iwac, uploadProgressListener, uploadId, success); } } } private void handleStream(HttpServletRequest request, HttpServletResponse response) throws IOException { StreamResult result = new StreamResult(); StreamData data = IOUtil.getObjectFromInputStream(request.getInputStream()); if (data == null) { writeToResponse(response, result); return; } result.setDestinationDirectory(data.getDestinationDirectory()); result.setName(data.getName()); result.setUuid(data.getUuid()); result.setSize(data.getBytes().length); result.setSuccess(upload(Arrays.asList(new UploadFile(data.getName(), null, data.getBytes().length, data.getBytes())), data.getDestinationDirectory(), false, false, false, false)); writeToResponse(response, result); } private void finishUpUpload(IWApplicationContext iwac, FileUploadProgressListener uploadProgressListener, String uploadId, Boolean success) { LOGGER.info("Upload by ID " + uploadId + " has ended. Successfully: " + success); if (StringUtil.isEmpty(uploadId)) return; uploadProgressListener.setUploadSuccessful(uploadId, success); if (iwac != null) iwac.removeApplicationAttribute(uploadId); } private void writeToResponse(HttpServletResponse response, String responseText) throws IOException { StringBuffer responseBuffer = new StringBuffer("web2FilesUploaderFilesListStarts").append(responseText); response.setCharacterEncoding(CoreConstants.ENCODING_UTF8); response.getWriter().print(responseBuffer.toString()); } private void writeToResponse(HttpServletResponse response, StreamResult responseObject) throws IOException { response.setCharacterEncoding(CoreConstants.ENCODING_UTF8); response.getOutputStream().write(IOUtil.getBytesFromObject(responseObject)); } private boolean upload(List<UploadFile> files, String uploadPath, boolean zipFile, boolean themePack, boolean isIE, boolean extractContent) { try { FileUploader uploader = ELUtil.getInstance().getBean(FileUploader.class); if (zipFile || themePack) { if (themePack) { uploadPath = ThemesConstants.THEMES_PATH; return uploader.uploadThemePack(files, uploadPath, isIE); } else { return uploader.uploadZipFile(files, uploadPath, extractContent, isIE); } } else { return uploader.uploadFile(files, uploadPath, isIE); } } catch (Exception e) { String message = "Error uploading files (" + files + ") to: " + uploadPath; LOGGER.log(Level.WARNING, message, e); CoreUtil.sendExceptionNotification(message, e); } return false; } private void prepareFiles(List<UploadFile> files) { for (UploadFile file: files) { file.setName(getStripped(file.getName())); } } private String getStripped(String input) { if (StringUtil.isEmpty(input)) return input; return StringHandler.stripNonRomanCharacters(input, ContentConstants.UPLOADER_EXCEPTIONS_FOR_LETTERS); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { super.doGet(request, response); } private String getValueFromBytes(byte[] bytes) { if (bytes == null) { return null; } try { return new String(bytes, CoreConstants.ENCODING_UTF8); } catch (UnsupportedEncodingException e) { LOGGER.log(Level.WARNING, "Unable to use encoding " + CoreConstants.ENCODING_UTF8, e); return new String(bytes); } } private boolean getValueFromString(String value) { return Boolean.TRUE.toString().equals(value); } }