public void upload( @Observes ControllerFound event, MutableRequest request, MultipartConfig config, Validator validator) { if (!ServletFileUpload.isMultipartContent(request)) { return; } logger.info("Request contains multipart data. Try to parse with commons-upload."); final Multiset<String> indexes = HashMultiset.create(); final Multimap<String, String> params = LinkedListMultimap.create(); ServletFileUpload uploader = createServletFileUpload(config); UploadSizeLimit uploadSizeLimit = event.getMethod().getMethod().getAnnotation(UploadSizeLimit.class); uploader.setSizeMax( uploadSizeLimit != null ? uploadSizeLimit.sizeLimit() : config.getSizeLimit()); uploader.setFileSizeMax( uploadSizeLimit != null ? uploadSizeLimit.fileSizeLimit() : config.getFileSizeLimit()); logger.debug( "Setting file sizes: total={}, file={}", uploader.getSizeMax(), uploader.getFileSizeMax()); try { final List<FileItem> items = uploader.parseRequest(request); logger.debug( "Found {} attributes in the multipart form submission. Parsing them.", items.size()); for (FileItem item : items) { String name = item.getFieldName(); name = fixIndexedParameters(name, indexes); if (item.isFormField()) { logger.debug("{} is a field", name); params.put(name, getValue(item, request)); } else if (isNotEmpty(item)) { logger.debug("{} is a file", name); processFile(item, name, request); } else { logger.debug("A file field is empty: {}", item.getFieldName()); } } for (String paramName : params.keySet()) { Collection<String> paramValues = params.get(paramName); request.setParameter(paramName, paramValues.toArray(new String[paramValues.size()])); } } catch (final SizeLimitExceededException e) { reportSizeLimitExceeded(e, validator); } catch (FileUploadException e) { reportFileUploadException(e, validator); } }
/** * if the filter is configured to parse file uploads, AND the request is multipart (typically a * file upload), then parse the request. * * @return If there is a file upload, and the filter handles it, return the wrapped request that * has the results of the parsed file upload. Parses the files using Apache * commons-fileuplaod. Exposes the results through a wrapped request. Files are available * like: fileItem = (FileItem) request.getAttribute("myHtmlFileUploadId"); */ protected HttpServletRequest handleFileUpload( HttpServletRequest req, HttpServletResponse resp, List<FileItem> tempFiles) throws ServletException, UnsupportedEncodingException { if (!m_uploadEnabled || !ServletFileUpload.isMultipartContent(req) || req.getAttribute(ATTR_UPLOADS_DONE) != null) { return req; } // mark that the uploads have been parsed, so they aren't parsed again on this request req.setAttribute(ATTR_UPLOADS_DONE, ATTR_UPLOADS_DONE); // Result - map that will be created of request parameters, // parsed parameters, and uploaded files Map map = new HashMap(); // parse using commons-fileupload // Create a factory for disk-based file items DiskFileItemFactory factory = new DiskFileItemFactory(); // set the factory parameters: the temp dir and the keep-in-memory-if-smaller threshold if (m_uploadTempDir != null) factory.setRepository(new File(m_uploadTempDir)); if (m_uploadThreshold > 0) factory.setSizeThreshold(m_uploadThreshold); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // set the encoding String encoding = req.getCharacterEncoding(); if (encoding != null && encoding.length() > 0) upload.setHeaderEncoding(encoding); // set the max upload size long uploadMax = -1; if (m_uploadMaxSize > 0) uploadMax = m_uploadMaxSize; // check for request-scoped override to upload.max (value in megs) String override = req.getParameter(CONFIG_UPLOAD_MAX); if (override != null) { try { // get the max in bytes uploadMax = Long.parseLong(override) * 1024L * 1024L; } catch (NumberFormatException e) { M_log.warn(CONFIG_UPLOAD_MAX + " set to non-numeric: " + override); } } // limit to the ceiling if (uploadMax > m_uploadCeiling) { M_log.warn( "Upload size exceeds ceiling: " + ((uploadMax / 1024L) / 1024L) + " > " + ((m_uploadCeiling / 1024L) / 1024L) + " megs"); uploadMax = m_uploadCeiling; } // to let commons-fileupload throw the exception on over-max, and also halt full processing of // input fields if (!m_uploadContinue) { // TODO: when we switch to commons-fileupload 1.2 // // either per file or overall request, as configured // if (m_uploadMaxPerFile) // { // upload.setFileSizeMax(uploadMax); // } // else // { // upload.setSizeMax(uploadMax); // } upload.setSizeMax(uploadMax); } try { // parse multipart encoded parameters boolean uploadOk = true; List list = upload.parseRequest(req); for (int i = 0; i < list.size(); i++) { FileItem item = (FileItem) list.get(i); if (item.isFormField()) { String str = item.getString(encoding); Object obj = map.get(item.getFieldName()); if (obj == null) { map.put(item.getFieldName(), new String[] {str}); } else if (obj instanceof String[]) { String[] old_vals = (String[]) obj; String[] values = new String[old_vals.length + 1]; for (int i1 = 0; i1 < old_vals.length; i1++) { values[i1] = old_vals[i1]; } values[values.length - 1] = str; map.put(item.getFieldName(), values); } else if (obj instanceof String) { String[] values = new String[2]; values[0] = (String) obj; values[1] = str; map.put(item.getFieldName(), values); } } else { // collect it for delete at the end of the request tempFiles.add(item); // check the max, unless we are letting commons-fileupload throw exception on max exceeded // Note: the continue option assumes the max is per-file, not overall. if (m_uploadContinue && (item.getSize() > uploadMax)) { uploadOk = false; M_log.info("Upload size limit exceeded: " + ((uploadMax / 1024L) / 1024L)); req.setAttribute("upload.status", "size_limit_exceeded"); // TODO: for 1.2 commons-fileupload, switch this to a FileSizeLimitExceededException req.setAttribute( "upload.exception", new FileUploadBase.SizeLimitExceededException("", item.getSize(), uploadMax)); req.setAttribute("upload.limit", new Long((uploadMax / 1024L) / 1024L)); } else { req.setAttribute(item.getFieldName(), item); } } } // unless we had an upload file that exceeded max, set the upload status to "ok" if (uploadOk) { req.setAttribute("upload.status", "ok"); } } catch (FileUploadBase.SizeLimitExceededException ex) { M_log.info("Upload size limit exceeded: " + ((upload.getSizeMax() / 1024L) / 1024L)); // DON'T throw an exception, instead note the exception // so that the tool down-the-line can handle the problem req.setAttribute("upload.status", "size_limit_exceeded"); req.setAttribute("upload.exception", ex); req.setAttribute("upload.limit", new Long((upload.getSizeMax() / 1024L) / 1024L)); } // TODO: put in for commons-fileupload 1.2 // catch (FileUploadBase.FileSizeLimitExceededException ex) // { // M_log.info("Upload size limit exceeded: " + ((upload.getFileSizeMax() / 1024L) / 1024L)); // // // DON'T throw an exception, instead note the exception // // so that the tool down-the-line can handle the problem // req.setAttribute("upload.status", "size_limit_exceeded"); // req.setAttribute("upload.exception", ex); // req.setAttribute("upload.limit", new Long((upload.getFileSizeMax() / 1024L) / 1024L)); // } catch (FileUploadException ex) { M_log.info("Unexpected exception in upload parsing", ex); req.setAttribute("upload.status", "exception"); req.setAttribute("upload.exception", ex); } // add any parameters that were in the URL - make sure to get multiples for (Enumeration e = req.getParameterNames(); e.hasMoreElements(); ) { String name = (String) e.nextElement(); String[] values = req.getParameterValues(name); map.put(name, values); } // return a wrapped response that exposes the parsed parameters and files return new WrappedRequestFileUpload(req, map); }