From e2ad45f2cbfaaefdb25fd03175274c7bb6202993 Mon Sep 17 00:00:00 2001 From: j2blake Date: Fri, 20 Dec 2013 15:02:57 -0500 Subject: [PATCH 1/3] line-end characters --- .../utilities/testing/VitroTestRunner.java | 288 +++++++++--------- 1 file changed, 144 insertions(+), 144 deletions(-) diff --git a/utilities/buildutils/src/edu/cornell/mannlib/vitro/utilities/testing/VitroTestRunner.java b/utilities/buildutils/src/edu/cornell/mannlib/vitro/utilities/testing/VitroTestRunner.java index 76664d4e3..0c4f5ae2c 100644 --- a/utilities/buildutils/src/edu/cornell/mannlib/vitro/utilities/testing/VitroTestRunner.java +++ b/utilities/buildutils/src/edu/cornell/mannlib/vitro/utilities/testing/VitroTestRunner.java @@ -1,7 +1,7 @@ /* $This file is distributed under the terms of the license in /doc/license.txt$ */ -package edu.cornell.mannlib.vitro.utilities.testing; - +package edu.cornell.mannlib.vitro.utilities.testing; + import java.io.File; import java.util.ArrayList; import java.util.List; @@ -9,145 +9,145 @@ import java.util.SortedSet; import java.util.TreeSet; import org.junit.runner.JUnitCore; - -/** - * A Java application that will run the Vitro unit tests. It searches for unit - * tests in the supplied source directory (any file whose name is *Test.Java). - * It runs the tests with a variety of reporting detail, depending on the level - * selected. If the level selector is absent or unrecognized, the medium level - * is used. - * - * @author jeb228 - */ -public class VitroTestRunner { - public enum ReportLevel { - /** Report only the one-line summary. */ - BRIEF, - /** Report times and statistics for each test class. */ - MORE, - /** Report times and statistics for each test method. */ - FULL - } - - private final List> classes; - private final VitroTestRunListener listener; - - /** - * Locate the test classes. Initialize the test listener. - */ - public VitroTestRunner(File sourceRootDir, ReportLevel reportLevel) { - List classNames = getListOfTestClassNames(sourceRootDir); - this.classes = getTestClasses(classNames); - this.listener = new VitroTestRunListener(reportLevel); - } - - /** - * Start a recursive search through the source directory. - */ - private List getListOfTestClassNames(File sourceRootDir) { - SortedSet names = new TreeSet(); - searchForTestClasses(names, "", sourceRootDir); - return new ArrayList(names); - } - - /** - * Recursively search the directory for files in the form "*Test.java". - * Ignore any files or directories whose names start with a "." - */ - private void searchForTestClasses(SortedSet names, String prefix, - File directory) { - for (File file : directory.listFiles()) { - String filename = file.getName(); - if (filename.startsWith(".")) { - // ignore .svn, etc. - } else if (file.isDirectory()) { - searchForTestClasses(names, prefix + filename + ".", file); - } else if (filename.endsWith("Test.java")) { - String classname = filename.substring(0, filename.length() - 5); - names.add(prefix + classname); - } - } - } - - /** - * Instantiate a class for each test class name. - */ - private List> getTestClasses(List classNames) { - List> classes = new ArrayList>(); - for (String classname : classNames) { - try { - classes.add(Class.forName(classname)); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Can't load test class: " - + classname, e); - } - } - return classes; - } - - /** - * We've located all of the test clases. Now run them. - */ - private void run() { - JUnitCore junitCore = new JUnitCore(); - junitCore.addListener(this.listener); - junitCore.run(this.classes.toArray(new Class[0])); - } - - /** - * Did any of the tests fail? - */ - private boolean didEverythingPass() { - return this.listener.didEverythingPass(); - } - - /** - *

- * You must provide a path to the source directory of the test classes. - *

- *

- * You may also provide a reporting level of "BRIEF", "MORE", or "FULL". If - * no level is provided, or if it is not recognized, "BRIEF" is used. - *

- */ - public static void main(String[] args) { - if ((args.length < 1) || (args.length > 2)) { - usage("Wrong number of arguments: expecting 1 or 2, but found " - + args.length + "."); - } - File sourceRootDir = new File(args[0]); - - if (!sourceRootDir.exists()) { - usage(sourceRootDir + " does not exist."); - } - if (!sourceRootDir.isDirectory()) { - usage(sourceRootDir + " is not a directory."); - } - - ReportLevel reportLevel = ReportLevel.MORE; - if (args.length == 2) { - for (ReportLevel level : ReportLevel.values()) { - if (level.toString().equalsIgnoreCase(args[1])) { - reportLevel = level; - } - } - } - - VitroTestRunner runner = new VitroTestRunner(sourceRootDir, reportLevel); - runner.run(); - - if (!runner.didEverythingPass()) { - System.exit(1); - } - } - - /** - * Tell them how it should have been done. - */ - private static void usage(String message) { - System.out.println(message); - System.out.println("usage: " + VitroTestRunner.class.getSimpleName() - + " sourceRootDirectory [ BRIEF | MORE | FULL ]"); - System.exit(1); - } -} + +/** + * A Java application that will run the Vitro unit tests. It searches for unit + * tests in the supplied source directory (any file whose name is *Test.Java). + * It runs the tests with a variety of reporting detail, depending on the level + * selected. If the level selector is absent or unrecognized, the medium level + * is used. + * + * @author jeb228 + */ +public class VitroTestRunner { + public enum ReportLevel { + /** Report only the one-line summary. */ + BRIEF, + /** Report times and statistics for each test class. */ + MORE, + /** Report times and statistics for each test method. */ + FULL + } + + private final List> classes; + private final VitroTestRunListener listener; + + /** + * Locate the test classes. Initialize the test listener. + */ + public VitroTestRunner(File sourceRootDir, ReportLevel reportLevel) { + List classNames = getListOfTestClassNames(sourceRootDir); + this.classes = getTestClasses(classNames); + this.listener = new VitroTestRunListener(reportLevel); + } + + /** + * Start a recursive search through the source directory. + */ + private List getListOfTestClassNames(File sourceRootDir) { + SortedSet names = new TreeSet(); + searchForTestClasses(names, "", sourceRootDir); + return new ArrayList(names); + } + + /** + * Recursively search the directory for files in the form "*Test.java". + * Ignore any files or directories whose names start with a "." + */ + private void searchForTestClasses(SortedSet names, String prefix, + File directory) { + for (File file : directory.listFiles()) { + String filename = file.getName(); + if (filename.startsWith(".")) { + // ignore .svn, etc. + } else if (file.isDirectory()) { + searchForTestClasses(names, prefix + filename + ".", file); + } else if (filename.endsWith("Test.java")) { + String classname = filename.substring(0, filename.length() - 5); + names.add(prefix + classname); + } + } + } + + /** + * Instantiate a class for each test class name. + */ + private List> getTestClasses(List classNames) { + List> classes = new ArrayList>(); + for (String classname : classNames) { + try { + classes.add(Class.forName(classname)); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Can't load test class: " + + classname, e); + } + } + return classes; + } + + /** + * We've located all of the test clases. Now run them. + */ + private void run() { + JUnitCore junitCore = new JUnitCore(); + junitCore.addListener(this.listener); + junitCore.run(this.classes.toArray(new Class[0])); + } + + /** + * Did any of the tests fail? + */ + private boolean didEverythingPass() { + return this.listener.didEverythingPass(); + } + + /** + *

+ * You must provide a path to the source directory of the test classes. + *

+ *

+ * You may also provide a reporting level of "BRIEF", "MORE", or "FULL". If + * no level is provided, or if it is not recognized, "BRIEF" is used. + *

+ */ + public static void main(String[] args) { + if ((args.length < 1) || (args.length > 2)) { + usage("Wrong number of arguments: expecting 1 or 2, but found " + + args.length + "."); + } + File sourceRootDir = new File(args[0]); + + if (!sourceRootDir.exists()) { + usage(sourceRootDir + " does not exist."); + } + if (!sourceRootDir.isDirectory()) { + usage(sourceRootDir + " is not a directory."); + } + + ReportLevel reportLevel = ReportLevel.MORE; + if (args.length == 2) { + for (ReportLevel level : ReportLevel.values()) { + if (level.toString().equalsIgnoreCase(args[1])) { + reportLevel = level; + } + } + } + + VitroTestRunner runner = new VitroTestRunner(sourceRootDir, reportLevel); + runner.run(); + + if (!runner.didEverythingPass()) { + System.exit(1); + } + } + + /** + * Tell them how it should have been done. + */ + private static void usage(String message) { + System.out.println(message); + System.out.println("usage: " + VitroTestRunner.class.getSimpleName() + + " sourceRootDirectory [ BRIEF | MORE | FULL ]"); + System.exit(1); + } +} From b7b28cc896ec6cc76c60af62a62ec9c80960c212 Mon Sep 17 00:00:00 2001 From: j2blake Date: Fri, 20 Dec 2013 17:10:18 -0500 Subject: [PATCH 2/3] VIVO-617 Change the way we deal with Multipart requests. --- .../controller/MultipartRequestWrapper.java | 288 ++++++++++++++++++ .../webapp/controller/VitroHttpServlet.java | 25 +- .../vitro/webapp/controller/VitroRequest.java | 63 ++++ .../FileUploadServletRequest.java | 112 ------- .../MultipartHttpServletRequest.java | 261 ---------------- .../SimpleHttpServletRequestWrapper.java | 81 ----- 6 files changed, 373 insertions(+), 457 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/MultipartRequestWrapper.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/FileUploadServletRequest.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/MultipartHttpServletRequest.java delete mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/SimpleHttpServletRequestWrapper.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/MultipartRequestWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/MultipartRequestWrapper.java new file mode 100644 index 000000000..02a7eee72 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/MultipartRequestWrapper.java @@ -0,0 +1,288 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Wraps a multipart HTTP request, and pre-parses it for file uploads, without + * losing the request parameters. + * + * Parsing through the request with an Apache ServletFileUpload builds a list of + * FileItems that includes the parameters and the file parts. After that, + * however, the parameters are no longer accessible from the request. This + * wrapper will see that they don't get lost. + * + * The List of FileItems includes both "formField" items and "file" items. As + * with the usual parameters on a request, we can have more than one value with + * the same name. So this creates a map of > to hold the + * parameters, and a map of > to hold the files. + * + * The parameters will be available to the wrapper through the normal methods. + * The files will be available as an attribute that holds the map. Also, a + * separate attribute will hold a Boolean to indicate that this was indeed a + * multipart request. + * + * Conveninence methods in VitroRequest will make these easy to handle, without + * actually touching the attributes. + */ +public class MultipartRequestWrapper extends HttpServletRequestWrapper { + private static final Log log = LogFactory + .getLog(MultipartRequestWrapper.class); + + private static final String CLASS_NAME = MultipartRequestWrapper.class + .getSimpleName(); + public static final String ATTRIBUTE_IS_MULTIPART = CLASS_NAME + + "_isMultipart"; + public static final String ATTRIBUTE_FILE_ITEM_MAP = CLASS_NAME + + "_fileItemMap"; + public static final String ATTRIBUTE_FILE_SIZE_EXCEPTION = CLASS_NAME + + "_fileSizeException"; + + private static final String[] EMPTY_ARRAY = new String[0]; + + // ---------------------------------------------------------------------- + // The factory + // ---------------------------------------------------------------------- + + /** + * If this is a multipart request, wrap it. Otherwise, just return the + * request as it is. + */ + public static HttpServletRequest parse(HttpServletRequest req, + ParsingStrategy strategy) throws IOException { + if (!ServletFileUpload.isMultipartContent(req)) { + return req; + } + + ListsMap parameters = new ListsMap<>(); + ListsMap files = new ListsMap<>(); + + parseQueryString(req.getQueryString(), parameters); + parseFileParts(req, parameters, files, strategy); + + return new MultipartRequestWrapper(req, parameters, files); + } + + /** + * Pull any parameters out of the URL. + */ + private static void parseQueryString(String queryString, + ListsMap parameters) { + log.debug("Query string is : '" + queryString + "'"); + if (queryString != null) { + String[] pieces = queryString.split("&"); + + for (String piece : pieces) { + int equalsHere = piece.indexOf('='); + if (piece.trim().isEmpty()) { + // Ignore an empty piece. + } else if (equalsHere <= 0) { + // A parameter without a value. + parameters.add(decode(piece), ""); + } else { + // A parameter with a value. + String key = piece.substring(0, equalsHere); + String value = piece.substring(equalsHere + 1); + parameters.add(decode(key), decode(value)); + } + } + } + log.debug("Parameters from query string are: " + parameters); + } + + /** + * Remove any special URL-style encoding. + */ + private static String decode(String encoded) { + try { + return URLDecoder.decode(encoded, "UTF-8"); + } catch (UnsupportedEncodingException e) { + log.error(e, e); + return encoded; + } + } + + private static void parseFileParts(HttpServletRequest req, + ListsMap parameters, ListsMap files, + ParsingStrategy strategy) throws IOException { + + ServletFileUpload upload = createUploadHandler(req, + strategy.maximumMultipartFileSize()); + List items = parseRequestIntoFileItems(req, upload, strategy); + + for (FileItem item : items) { + // Process a regular form field + String name = item.getFieldName(); + if (item.isFormField()) { + String value; + try { + value = item.getString("UTF-8"); + } catch (UnsupportedEncodingException e) { + value = item.getString(); + } + parameters.add(name, value); + log.debug("Form field (parameter) " + name + "=" + value); + } else { + files.add(name, item); + log.debug("File " + name + ": " + item.getSize() + " bytes."); + } + } + } + + /** + * Create an upload handler that will throw an exception if the file is too + * large. + */ + private static ServletFileUpload createUploadHandler( + HttpServletRequest req, long maxFileSize) { + File tempDir = figureTemporaryDirectory(req); + + DiskFileItemFactory factory = new DiskFileItemFactory(); + factory.setSizeThreshold(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD); + factory.setRepository(tempDir); + + ServletFileUpload upload = new ServletFileUpload(factory); + upload.setSizeMax(maxFileSize); + return upload; + } + + /** + * Find the temporary storage directory for this webapp. + */ + private static File figureTemporaryDirectory(HttpServletRequest request) { + return (File) request.getSession().getServletContext() + .getAttribute("javax.servlet.context.tempdir"); + } + + /** + * Parse the raw request into a list of parts. + * + * If there is a parsing error, let the strategy handle it. If the strategy + * throws it back, wrap it in an IOException and throw it on up. + */ + @SuppressWarnings("unchecked") + private static List parseRequestIntoFileItems( + HttpServletRequest req, ServletFileUpload upload, + ParsingStrategy strategy) throws IOException { + try { + return upload.parseRequest(req); + } catch (FileSizeLimitExceededException e) { + if (strategy.stashFileSizeException()) { + req.setAttribute(ATTRIBUTE_FILE_SIZE_EXCEPTION, e); + return Collections.emptyList(); + } else { + throw new IOException(e); + } + } catch (FileUploadException e) { + throw new IOException(e); + } + } + + // ---------------------------------------------------------------------- + // The instance + // ---------------------------------------------------------------------- + + private final ListsMap parameters; + + public MultipartRequestWrapper(HttpServletRequest req, + ListsMap parameters, ListsMap files) { + super(req); + + this.parameters = parameters; + + req.setAttribute(ATTRIBUTE_IS_MULTIPART, Boolean.TRUE); + req.setAttribute(ATTRIBUTE_FILE_ITEM_MAP, files); + } + + /** + * Look in the map of parsed parameters. + */ + @Override + public String getParameter(String name) { + if (parameters.containsKey(name)) { + return parameters.get(name).get(0); + } else { + return null; + } + } + + /** + * Look in the map of parsed parameters. Make a protective copy. + */ + @Override + public Enumeration getParameterNames() { + return Collections.enumeration(new HashSet<>(parameters.keySet())); + } + + /** + * Look in the map of parsed parameters. + */ + @Override + public String[] getParameterValues(String name) { + if (parameters.containsKey(name)) { + return parameters.get(name).toArray(EMPTY_ARRAY); + } else { + return null; + } + } + + /** + * Make a copy of the map of parsed parameters; + */ + @Override + public Map getParameterMap() { + Map result = new HashMap(); + for (String key : parameters.keySet()) { + result.put(key, parameters.get(key).toArray(EMPTY_ARRAY)); + } + return result; + } + + // ---------------------------------------------------------------------- + // Helper classes + // ---------------------------------------------------------------------- + + private static class ListsMap extends HashMap> { + void add(String key, T value) { + if (!containsKey(key)) { + put(key, new ArrayList()); + } + get(key).add(value); + } + } + + public interface ParsingStrategy { + long maximumMultipartFileSize(); + + /** + * Allows you to handle the exception in your code. + * + * Be aware that the multipart parameters have been lost, and that may + * include form fields. + */ + boolean stashFileSizeException(); + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroHttpServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroHttpServlet.java index dcc80a040..bf082aa56 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroHttpServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroHttpServlet.java @@ -30,14 +30,13 @@ import edu.cornell.mannlib.vedit.beans.LoginStatusBean; import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; -import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean; import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage; import edu.cornell.mannlib.vitro.webapp.beans.ResourceBean; import edu.cornell.mannlib.vitro.webapp.controller.authenticate.LogoutRedirector; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.i18n.I18n; -public class VitroHttpServlet extends HttpServlet { +public class VitroHttpServlet extends HttpServlet implements MultipartRequestWrapper.ParsingStrategy { private static final long serialVersionUID = 1L; protected static DateFormat publicDateFormat = new SimpleDateFormat( @@ -60,8 +59,9 @@ public class VitroHttpServlet extends HttpServlet { if ((req instanceof HttpServletRequest) && (resp instanceof HttpServletResponse)) { HttpServletRequest hreq = (HttpServletRequest) req; - HttpServletResponse hresp = (HttpServletResponse) resp; + hreq = MultipartRequestWrapper.parse(hreq, this); + if (log.isTraceEnabled()) { dumpRequestHeaders(hreq); } @@ -70,6 +70,25 @@ public class VitroHttpServlet extends HttpServlet { super.service(req, resp); } + /** + * Override this to change the maximum size of uploaded files in multipart + * requests. + */ + @Override + public long maximumMultipartFileSize() { + return 50 * 1024 * 1024; // default is 50 megabytes + } + + /** + * Override this to change the way that exceptions are handled when parsing + * a multipart request. Be aware that multipart parameters have been lost, + * and that may include form fields. + */ + @Override + public boolean stashFileSizeException() { + return false; + } + /** * doGet does nothing. */ diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroRequest.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroRequest.java index 05c0fc158..9878fe0b9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroRequest.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/VitroRequest.java @@ -3,12 +3,20 @@ package edu.cornell.mannlib.vitro.webapp.controller; +import static edu.cornell.mannlib.vitro.webapp.controller.MultipartRequestWrapper.ATTRIBUTE_FILE_ITEM_MAP; +import static edu.cornell.mannlib.vitro.webapp.controller.MultipartRequestWrapper.ATTRIBUTE_FILE_SIZE_EXCEPTION; +import static edu.cornell.mannlib.vitro.webapp.controller.MultipartRequestWrapper.ATTRIBUTE_IS_MULTIPART; + import java.text.Collator; +import java.util.Collections; +import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -231,4 +239,59 @@ public class VitroRequest extends HttpServletRequestWrapper { public WebappDaoFactory getLanguageNeutralWebappDaoFactory() { return (WebappDaoFactory) getAttribute("languageNeutralWebappDaoFactory"); } + + // ---------------------------------------------------------------------- + // Deal with parsed multipart requests. + // ---------------------------------------------------------------------- + + public boolean isMultipart() { + return getAttribute(ATTRIBUTE_IS_MULTIPART) != null; + } + + @SuppressWarnings("unchecked") + public Map> getFiles() { + Map> map; + map = (Map>) getAttribute(ATTRIBUTE_FILE_ITEM_MAP); + if (map == null) { + return Collections.emptyMap(); + } else { + return map; + } + } + + /** + * There may be more than one file item with the given name. If the first + * one is empty (size is zero), keep looking for a non-empty one. + */ + public FileItem getFileItem(String name) { + Map> map = getFiles(); + List items = map.get(name); + if (items == null) { + return null; + } + for (FileItem item : items) { + if (item.getSize() > 0L) { + return item; + } + } + return null; + } + + /** + * If the uploaded file exceeded the maximum size, and if the strategy said + * to stash the exception, it will be stored as a request attribute. + */ + public boolean hasFileSizeException() { + return getFileSizeException() != null; + } + + public FileSizeLimitExceededException getFileSizeException() { + Object e = getAttribute(ATTRIBUTE_FILE_SIZE_EXCEPTION); + if (e instanceof FileSizeLimitExceededException) { + return (FileSizeLimitExceededException) e; + } else { + return null; + } + } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/FileUploadServletRequest.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/FileUploadServletRequest.java deleted file mode 100644 index 519e2f07c..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/FileUploadServletRequest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileUploadException; -import org.apache.commons.fileupload.servlet.ServletFileUpload; - -/** - *

- * Wraps an HTTP request and parses it for file uploads, without losing the - * request parameters. - *

- *

- * The request will have an attribute named by {@link #FILE_ITEM_MAP}. Either - * this attribute or the call to {@link #getFiles()} will produce a map that may - * be empty but is never null. The keys to the map are the field names for the - * file fields. Since a form may have multiple fields with the same name, each - * field name maps to a list of items. If a user does not provide a file to be - * uploaded in a given field, the length of the file will be 0. - *

- *

- * If the uploaded file(s) would be larger than the maxFileSize, - * {@link #parseRequest(HttpServletRequest, int)} does not throw an Exception. - * Instead, it records the exception in a request attribute named by - * {@link #FILE_UPLOAD_EXCEPTION}. This attribute can be accessed directly, or - * indirectly via the methods {@link #hasFileUploadException()} and - * {@link #getFileUploadException()}. If there is an exception, the file item - * map (see above) will still be non-null, but it will be empty. - *

- *

- * Most methods are declared here simply delegate to the wrapped request. - * Methods that have to do with parameters, files, or parsing exceptions, are - * handled differently for simple requests and multipart request, and are - * implemented in the sub-classes. - *

- */ -public abstract class FileUploadServletRequest extends HttpServletRequestWrapper { - public static final String FILE_ITEM_MAP = "file_item_map"; - public static final String FILE_UPLOAD_EXCEPTION = "file_upload_exception"; - - // ---------------------------------------------------------------------- - // The factory method - // ---------------------------------------------------------------------- - - /** - * Wrap this {@link HttpServletRequest} in an appropriate wrapper class. - */ - public static FileUploadServletRequest parseRequest( - HttpServletRequest request, int maxFileSize) throws IOException { - boolean isMultipart = ServletFileUpload.isMultipartContent(request); - if (isMultipart) { - return new MultipartHttpServletRequest(request, maxFileSize); - } else { - return new SimpleHttpServletRequestWrapper(request); - } - } - - // ---------------------------------------------------------------------- - // The constructor and the delegate. - // ---------------------------------------------------------------------- - - private final HttpServletRequest delegate; - - public FileUploadServletRequest(HttpServletRequest delegate) { - super(delegate); - this.delegate = delegate; - } - - protected HttpServletRequest getDelegate() { - return this.delegate; - } - - // ---------------------------------------------------------------------- - // New functionality to be implemented by the subclasses. - // ---------------------------------------------------------------------- - - /** Was this a multipart HTTP request? */ - public abstract boolean isMultipart(); - - /** - * Get the map of file items, by name. - */ - public abstract Map> getFiles(); - - /** - * Find a non-empty file item with this name. - * - * @return the first such file item, or null if no matching, - * non-empty items were found. - */ - public abstract FileItem getFileItem(String string); - - /** - * Was there an exception when uploading the file items? - */ - public abstract boolean hasFileUploadException(); - - /** - * Get the exception that occurred when uploading the file items. If no such - * exception, return null. - */ - public abstract FileUploadException getFileUploadException(); - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/MultipartHttpServletRequest.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/MultipartHttpServletRequest.java deleted file mode 100644 index 56cf480fc..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/MultipartHttpServletRequest.java +++ /dev/null @@ -1,261 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest; - -import java.io.File; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileUploadException; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A wrapper for a servlet request that holds multipart content. Parsing the - * request will consume the parameters, so we need to hold them here to answer - * any parameter-related requests. File-related information will also be held - * here, to answer file-related requests. - */ -class MultipartHttpServletRequest extends FileUploadServletRequest { - private static final Log log = LogFactory - .getLog(MultipartHttpServletRequest.class); - - private static final String[] EMPTY_ARRAY = new String[0]; - - private final Map> parameters; - private final Map> files; - private FileUploadException fileUploadException; - - /** - * Parse the multipart request. Store the info about the request parameters - * and the uploaded files. - */ - public MultipartHttpServletRequest(HttpServletRequest request, - int maxFileSize) throws IOException { - super(request); - - Map> parameters = new HashMap>(); - Map> files = new HashMap>(); - - File tempDir = figureTemporaryDirectory(request); - ServletFileUpload upload = createUploadHandler(maxFileSize, tempDir); - - parseQueryString(request.getQueryString(), parameters); - - try { - List items = parseRequestIntoFileItems(request, upload); - - for (FileItem item : items) { - // Process a regular form field - if (item.isFormField()) { - addToParameters(parameters, item.getFieldName(), item - .getString("UTF-8")); - log.debug("Form field (parameter) " + item.getFieldName() - + "=" + item.getString()); - } else { - addToFileItems(files, item); - log.debug("File " + item.getFieldName() + ": " - + item.getName()); - } - } - } catch (FileUploadException e) { - fileUploadException = e; - request.setAttribute( - FileUploadServletRequest.FILE_UPLOAD_EXCEPTION, e); - } - - this.parameters = Collections.unmodifiableMap(parameters); - log.debug("Parameters are: " + this.parameters); - this.files = Collections.unmodifiableMap(files); - log.debug("Files are: " + this.files); - request.setAttribute(FILE_ITEM_MAP, this.files); - } - - /** - * Pull any parameters out of the URL. - */ - private void parseQueryString(String queryString, - Map> parameters) { - log.debug("Query string is : '" + queryString + "'"); - if (queryString != null) { - String[] pieces = queryString.split("&"); - - for (String piece : pieces) { - int equalsHere = piece.indexOf('='); - if (piece.trim().isEmpty()) { - // Ignore an empty piece. - } else if (equalsHere <= 0) { - // A parameter without a value. - addToParameters(parameters, decode(piece), ""); - } else { - // A parameter with a value. - String key = piece.substring(0, equalsHere); - String value = piece.substring(equalsHere + 1); - addToParameters(parameters, decode(key), decode(value)); - } - } - } - log.debug("Parameters from query string are: " + parameters); - } - - /** - * Remove any special URL-style encoding. - */ - private String decode(String encoded) { - try { - return URLDecoder.decode(encoded, "UTF-8"); - } catch (UnsupportedEncodingException e) { - log.error(e, e); - return encoded; - } - } - - /** - * Find the temporary storage directory for this webapp. - */ - private File figureTemporaryDirectory(HttpServletRequest request) { - return (File) request.getSession().getServletContext().getAttribute( - "javax.servlet.context.tempdir"); - } - - /** - * Create an upload handler that will throw an exception if the file is too - * large. - */ - private ServletFileUpload createUploadHandler(int maxFileSize, File tempDir) { - DiskFileItemFactory factory = new DiskFileItemFactory(); - factory.setSizeThreshold(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD); - factory.setRepository(tempDir); - - ServletFileUpload upload = new ServletFileUpload(factory); - upload.setSizeMax(maxFileSize); - - return upload; - } - - /** Either create a new List for the value, or add to an existing List. */ - private void addToParameters(Map> map, String name, - String value) { - if (!map.containsKey(name)) { - map.put(name, new ArrayList()); - } - map.get(name).add(value); - } - - /** Either create a new List for the file, or add to an existing List. */ - private void addToFileItems(Map> map, FileItem file) { - String name = file.getFieldName(); - if (!map.containsKey(name)) { - map.put(name, new ArrayList()); - } - map.get(name).add(file); - } - - /** Minimize the code that uses the unchecked cast. */ - @SuppressWarnings("unchecked") - private List parseRequestIntoFileItems(HttpServletRequest req, - ServletFileUpload upload) throws FileUploadException { - return upload.parseRequest(req); - } - - // ---------------------------------------------------------------------- - // This is a multipart request, so make the file info available. If there - // was an exception during parsing, make that available too. - // ---------------------------------------------------------------------- - - @Override - public boolean isMultipart() { - return true; - } - - @Override - public Map> getFiles() { - return files; - } - - /** - * {@inheritDoc} - *

- * There may be more than one file item with the given name. If the first - * one is empty (size is zero), keep looking for a non-empty one. - *

- */ - @Override - public FileItem getFileItem(String name) { - List items = files.get(name); - if (items == null) { - return null; - } - - for (FileItem item : items) { - if (item.getSize() > 0L) { - return item; - } - } - - return null; - } - - @Override - public FileUploadException getFileUploadException() { - return fileUploadException; - } - - @Override - public boolean hasFileUploadException() { - return fileUploadException != null; - } - - // ---------------------------------------------------------------------- - // Parameter-related methods won't find anything on the delegate request, - // since parsing consumed the parameters. So we need to look to the parsed - // info for the answers. - // ---------------------------------------------------------------------- - - @Override - public String getParameter(String name) { - if (parameters.containsKey(name)) { - return parameters.get(name).get(0); - } else { - return null; - } - } - - @Override - public Enumeration getParameterNames() { - return Collections.enumeration(parameters.keySet()); - } - - @Override - public String[] getParameterValues(String name) { - if (parameters.containsKey(name)) { - return parameters.get(name).toArray(EMPTY_ARRAY); - } else { - return null; - } - } - - @Override - public Map getParameterMap() { - Map result = new HashMap(); - for (Entry> entry : parameters.entrySet()) { - result.put(entry.getKey(), entry.getValue().toArray(EMPTY_ARRAY)); - } - log.debug("resulting parameter map: " + result); - return result; - } - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/SimpleHttpServletRequestWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/SimpleHttpServletRequestWrapper.java deleted file mode 100644 index 246377048..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/filestorage/uploadrequest/SimpleHttpServletRequestWrapper.java +++ /dev/null @@ -1,81 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest; - -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileUploadException; - -/** - * A wrapper for a servlet request that does not hold multipart content. Pass - * all parameter-related requests to the delegate, and give simple answers to - * all file-related requests. - */ -class SimpleHttpServletRequestWrapper extends FileUploadServletRequest { - - SimpleHttpServletRequestWrapper(HttpServletRequest request) { - super(request); - request.setAttribute(FILE_ITEM_MAP, Collections.EMPTY_MAP); - } - - // ---------------------------------------------------------------------- - // Not a multipart request, so there are no files or upload exceptions. - // ---------------------------------------------------------------------- - - @Override - public boolean isMultipart() { - return false; - } - - @Override - public Map> getFiles() { - return Collections.emptyMap(); - } - - @Override - public FileItem getFileItem(String string) { - return null; - } - - @Override - public FileUploadException getFileUploadException() { - return null; - } - - @Override - public boolean hasFileUploadException() { - return false; - } - - // ---------------------------------------------------------------------- - // Since this is not a multipart request, the parameter methods can be - // delegated. - // ---------------------------------------------------------------------- - - @Override - public String getParameter(String name) { - return getDelegate().getParameter(name); - } - - @Override - public Map getParameterMap() { - return getDelegate().getParameterMap(); - } - - @Override - public Enumeration getParameterNames() { - return getDelegate().getParameterNames(); - } - - @Override - public String[] getParameterValues(String name) { - return getDelegate().getParameterValues(name); - } - -} From c42d9af70fe471baaf77ce6483af9986ea358cf0 Mon Sep 17 00:00:00 2001 From: j2blake Date: Fri, 20 Dec 2013 17:11:16 -0500 Subject: [PATCH 3/3] VIVO-617 Adjust the client code to use the new file upload tools. --- .../FedoraDatastreamController.java | 19 ++- .../freemarker/ImageUploadController.java | 109 ++++++------------ .../freemarker/ImageUploadHelper.java | 19 +-- .../jena/JenaCsv2RdfController.java | 24 ++-- .../controller/jena/JenaXMLFileUpload.java | 26 +++-- .../controller/jena/RDFUploadController.java | 39 ++++--- .../controller/SearchServiceController.java | 9 +- .../search/controller/UpdateUrisInIndex.java | 11 +- 8 files changed, 116 insertions(+), 140 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/FedoraDatastreamController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/FedoraDatastreamController.java index 93def6de3..9ae6b7b86 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/FedoraDatastreamController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/FedoraDatastreamController.java @@ -45,7 +45,6 @@ import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; -import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest; import fedora.client.FedoraClient; import fedora.common.Constants; import fedora.server.management.FedoraAPIM; @@ -220,12 +219,22 @@ public class FedoraDatastreamController extends VitroHttpServlet implements Cons } @Override + public long maximumMultipartFileSize() { + return maxFileSize; + } + + @Override + public boolean stashFileSizeException() { + return true; + } + + @Override public void doPost(HttpServletRequest rawRequest, HttpServletResponse res) throws ServletException, IOException { - try{ - FileUploadServletRequest req = FileUploadServletRequest.parseRequest(rawRequest, maxFileSize); - if (req.hasFileUploadException()) { - throw new FdcException("Size limit exceeded: " + req.getFileUploadException().getLocalizedMessage()); + try{ + VitroRequest req = new VitroRequest(rawRequest); + if (req.hasFileSizeException()) { + throw new FdcException("Size limit exceeded: " + req.getFileSizeException().getLocalizedMessage()); } if (!req.isMultipart()) { throw new FdcException("Must POST a multipart encoded request"); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java index 537b4573c..d01d163e9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadController.java @@ -2,12 +2,6 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.Map; -import java.util.Map.Entry; - -import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; @@ -36,7 +30,6 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage; import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup; import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo; import edu.cornell.mannlib.vitro.webapp.filestorage.model.ImageInfo; -import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest; import edu.cornell.mannlib.vitro.webapp.i18n.I18n; import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil; @@ -52,6 +45,7 @@ public class ImageUploadController extends FreemarkerHttpServlet { private static final String ERROR_CODE_UNRECOGNIZED_URI = "imageUpload.errorUnrecognizedURI"; private static final String ERROR_CODE_NO_URI = "imageUpload.errorNoURI"; + private static final String ERROR_CODE_FILE_TOO_BIG = "imageUpload.errorFileTooBig"; /** Limit file size to 6 megabytes. */ public static final int MAXIMUM_FILE_SIZE = 6 * 1024 * 1024; @@ -136,6 +130,22 @@ public class ImageUploadController extends FreemarkerHttpServlet { + FileStorage.class.getName() + "'"); } } + + /** + * How large an image file will we accept? + */ + @Override + public long maximumMultipartFileSize() { + return MAXIMUM_FILE_SIZE; + } + + /** + * What will we do if there is a problem parsing the request? + */ + @Override + public boolean stashFileSizeException() { + return true; + } /** * The required action depends on what we are trying to do. @@ -171,52 +181,17 @@ public class ImageUploadController extends FreemarkerHttpServlet { } } - /** - *

- * Parse the multi-part request, process the request, and produce the - * output. - *

- *

- * If the request was a multi-part file upload, it will parse to a - * normal-looking request with a "file_item_map" attribute. - *

- *

- * The processing will produce a {@link ResponseValues} object, which - * represents either a request for a FreeMarker template or a forwarding - * operation. - *

    - *
  • If a FreeMarker template, we emulate the actions that - * FreeMarkerHttpServlet would have taken to produce the output.
  • - *
  • If a forwarding operation, we create a {@link RequestDispatcher} to - * do the forwarding.
  • - *
- *

- */ - - @Override - protected ResponseValues processRequest(VitroRequest vreq) { - try { - // Parse the multi-part request. - FileUploadServletRequest.parseRequest(vreq, MAXIMUM_FILE_SIZE); - if (log.isTraceEnabled()) { - dumpRequestDetails(vreq); - } - - return buildTheResponse(vreq); - } catch (Exception e) { - // log.error("Could not produce response page", e); - return new ExceptionResponseValues(e); - } - } - /** * Handle the different actions. If not specified, the default action is to * show the intro screen. */ - private ResponseValues buildTheResponse(VitroRequest vreq) { - String action = vreq.getParameter(PARAMETER_ACTION); - + @Override + protected ResponseValues processRequest(VitroRequest vreq) { try { + checkForFileTooBigException(vreq); + + String action = vreq.getParameter(PARAMETER_ACTION); + Individual entity = validateEntityUri(vreq); if (ACTION_UPLOAD.equals(action)) { return doUploadImage(vreq, entity); @@ -240,6 +215,19 @@ public class ImageUploadController extends FreemarkerHttpServlet { } } + /** + * If our exception handler caught a "file too big" exception, we need to + * deal with it before anything else, since we can't trust the other + * parameters. + */ + private void checkForFileTooBigException(VitroRequest vreq) + throws UserMistakeException { + if (vreq.hasFileSizeException()) { + int limit = MAXIMUM_FILE_SIZE / (1024 * 1024); + throw new UserMistakeException(ERROR_CODE_FILE_TOO_BIG, limit); + } + } + /** * We are just starting the upload process. Record where we came from, so if * they hit "cancel" we know where to send them. If we have problems, just @@ -626,31 +614,6 @@ public class ImageUploadController extends FreemarkerHttpServlet { } - /** - * For debugging, dump all sorts of information about the request. - * - * WARNING: if "req" represents a Multi-part request which has not yet been - * parsed, then reading these parameters will consume them. - */ - @SuppressWarnings("unchecked") - private void dumpRequestDetails(HttpServletRequest req) { - log.trace("Request is " + req.getClass().getName()); - - Map parms = req.getParameterMap(); - for (Entry entry : parms.entrySet()) { - log.trace("Parameter '" + entry.getKey() + "'=" - + Arrays.deepToString(entry.getValue())); - } - - Enumeration attrs = req.getAttributeNames(); - while (attrs.hasMoreElements()) { - String key = attrs.nextElement(); - String valueString = String.valueOf(req.getAttribute(key)); - String valueOneLine = valueString.replace("\n", " | "); - log.trace("Attribute '" + key + "'=" + valueOneLine); - } - } - static class Dimensions { final int width; final int height; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadHelper.java index 68d0d00f6..3528ecc35 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadHelper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/ImageUploadHelper.java @@ -2,12 +2,9 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker; -import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.MAXIMUM_FILE_SIZE; import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.PARAMETER_UPLOADED_FILE; import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_HEIGHT; import static edu.cornell.mannlib.vitro.webapp.controller.freemarker.ImageUploadController.THUMBNAIL_WIDTH; -import static edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest.FILE_ITEM_MAP; -import static edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest.FILE_UPLOAD_EXCEPTION; import java.io.FileNotFoundException; import java.io.IOException; @@ -21,7 +18,6 @@ import javax.media.jai.JAI; import javax.media.jai.RenderedOp; import javax.media.jai.util.ImagingListener; import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; import org.apache.commons.fileupload.FileItem; import org.apache.commons.io.FilenameUtils; @@ -41,7 +37,6 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.UploadedFileHelper; import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileAlreadyExistsException; import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorage; import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo; -import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest; /** * Handle the mechanics of validating, storing, and deleting file images. @@ -55,7 +50,6 @@ public class ImageUploadHelper { private static final String ERROR_CODE_NO_IMAGE_TO_CROP = "imageUpload.errorNoImageForCropping"; private static final String ERROR_CODE_IMAGE_TOO_SMALL = "imageUpload.errorImageTooSmall"; private static final String ERROR_CODE_UNKNOWN = "imageUpload.errorUnknown"; - private static final String ERROR_CODE_FILE_TOO_BIG = "imageUpload.errorFileTooBig"; private static final String ERROR_CODE_UNRECOGNIZED_FILE_TYPE = "imageUpload.errorUnrecognizedFileType"; private static final String ERROR_CODE_NO_PHOTO_SELECTED = "imageUpload.errorNoPhotoSelected"; private static final String ERROR_CODE_BAD_MULTIPART_REQUEST = "imageUpload.errorBadMultipartRequest"; @@ -133,20 +127,13 @@ public class ImageUploadHelper { * if there is no file, if it is empty, or if it is not an image * file. */ - @SuppressWarnings("unchecked") - FileItem validateImageFromRequest(HttpServletRequest request) + FileItem validateImageFromRequest(VitroRequest vreq) throws UserMistakeException { - Object exception = request.getAttribute(FILE_UPLOAD_EXCEPTION); - if (exception != null) { - int limit = MAXIMUM_FILE_SIZE / (1024 * 1024); - throw new UserMistakeException(ERROR_CODE_FILE_TOO_BIG, limit); - } - - Map> map = (Map>) request - .getAttribute(FILE_ITEM_MAP); + Map> map = vreq.getFiles(); if (map == null) { throw new IllegalStateException(ERROR_CODE_BAD_MULTIPART_REQUEST); } + List list = map.get(PARAMETER_UPLOADED_FILE); if ((list == null) || list.isEmpty()) { throw new UserMistakeException(ERROR_CODE_FORM_FIELD_MISSING, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaCsv2RdfController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaCsv2RdfController.java index c310de156..877bb05c0 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaCsv2RdfController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaCsv2RdfController.java @@ -25,7 +25,6 @@ import com.hp.hpl.jena.rdf.model.ModelMaker; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest; import edu.cornell.mannlib.vitro.webapp.utils.Csv2Rdf; import edu.cornell.mannlib.vitro.webapp.utils.jena.JenaIngestUtils; @@ -37,6 +36,17 @@ public class JenaCsv2RdfController extends JenaIngestController { private static final String CSV2RDF_SELECT_URI_JSP = "/jenaIngest/csv2rdfSelectUri.jsp"; private static int maxFileSizeInBytes = 1024 * 1024 * 2000; //2000mb + + @Override + public long maximumMultipartFileSize() { + return maxFileSizeInBytes; + } + + @Override + public boolean stashFileSizeException() { + return true; + } + @Override public void doPost(HttpServletRequest rawRequest, HttpServletResponse response) throws ServletException, IOException { @@ -45,15 +55,13 @@ public class JenaCsv2RdfController extends JenaIngestController { return; } - FileUploadServletRequest req = FileUploadServletRequest.parseRequest(rawRequest, - maxFileSizeInBytes); - if (req.hasFileUploadException()) { - forwardToFileUploadError(req.getFileUploadException().getLocalizedMessage(), req, response); + VitroRequest request = new VitroRequest(rawRequest); + if (request.hasFileSizeException()) { + forwardToFileUploadError(request.getFileSizeException().getLocalizedMessage(), request, response); return; } - VitroRequest request = new VitroRequest(req); - Map> fileStreams = req.getFiles(); + Map> fileStreams = request.getFiles(); FileItem fileStream = fileStreams.get("filePath").get(0); String filePath = fileStreams.get("filePath").get(0).getName(); @@ -70,7 +78,7 @@ public class JenaCsv2RdfController extends JenaIngestController { csv2rdfResult = doExecuteCsv2Rdf( request, fileStream, filePath); }catch(Exception ex){ - forwardToFileUploadError(ex.getMessage(),req,response); + forwardToFileUploadError(ex.getMessage(),request,response); return; } ModelMaker maker = getVitroJenaModelMaker(request); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaXMLFileUpload.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaXMLFileUpload.java index f9ea1335b..39e862325 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaXMLFileUpload.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/JenaXMLFileUpload.java @@ -36,7 +36,6 @@ import com.hp.hpl.jena.shared.Lock; import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission; import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest; public class JenaXMLFileUpload extends JenaIngestController { Log log = LogFactory.getLog(JenaXMLFileUpload.class); @@ -76,6 +75,16 @@ public class JenaXMLFileUpload extends JenaIngestController { } } + @Override + public long maximumMultipartFileSize() { + return maxFileSize; + } + + @Override + public boolean stashFileSizeException() { + return true; + } + /** * Each file will be converted to RDF/XML and loaded to the target model. * If any of the files fail, no data will be loaded. @@ -86,14 +95,14 @@ public class JenaXMLFileUpload extends JenaIngestController { * */ @Override - public void doPost(HttpServletRequest rawRequest, HttpServletResponse resp) + public void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException { - FileUploadServletRequest request = FileUploadServletRequest.parseRequest(rawRequest, maxFileSize); - if (request.hasFileUploadException()) { + VitroRequest vreq = new VitroRequest(request); + if (vreq.hasFileSizeException()) { throw new ServletException("Size limit exceeded: " - + request.getFileUploadException().getLocalizedMessage()); + + vreq.getFileSizeException().getLocalizedMessage()); } - if (request.isMultipart()) { + if (vreq.isMultipart()) { log.debug("multipart content detected"); } else { // TODO: forward to error message @@ -105,7 +114,6 @@ public class JenaXMLFileUpload extends JenaIngestController { return; } - VitroRequest vreq = new VitroRequest(request); ModelMaker modelMaker = getVitroJenaModelMaker(vreq); String targetModel = request.getParameter("targetModel"); if (targetModel == null) { @@ -117,7 +125,7 @@ public class JenaXMLFileUpload extends JenaIngestController { throw new ServletException("targetModel '" + targetModel + "' was not found."); request.setAttribute("targetModel", targetModel); - List filesToLoad = saveFiles( request.getFiles() ); + List filesToLoad = saveFiles( vreq.getFiles() ); List rdfxmlToLoad = convertFiles( filesToLoad); List modelsToLoad = loadRdfXml( rdfxmlToLoad ); @@ -136,7 +144,7 @@ public class JenaXMLFileUpload extends JenaIngestController { request.setAttribute("title","Uploaded files and converted to RDF"); request.setAttribute("bodyJsp","/jenaIngest/xmlFileUploadSuccess.jsp"); - request.setAttribute("fileItems",request.getFiles()); + request.setAttribute("fileItems",vreq.getFiles()); RequestDispatcher rd = request.getRequestDispatcher(Controllers.BASIC_JSP); request.setAttribute("css", ""); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/RDFUploadController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/RDFUploadController.java index a196d8d28..bcb2eb635 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/RDFUploadController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/jena/RDFUploadController.java @@ -42,7 +42,6 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceGraph; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.BulkUpdateEvent; import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent; -import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest; import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; @@ -56,31 +55,39 @@ public class RDFUploadController extends JenaIngestController { private static FileItem fileStream = null; private static final String LOAD_RDF_DATA_JSP="/jenaIngest/loadRDFData.jsp"; - public void doPost(HttpServletRequest rawRequest, + @Override + public long maximumMultipartFileSize() { + return maxFileSizeInBytes; + } + + @Override + public boolean stashFileSizeException() { + return true; + } + + public void doPost(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException { - if (!isAuthorizedToDisplayPage(rawRequest, response, + if (!isAuthorizedToDisplayPage(req, response, SimplePermission.USE_ADVANCED_DATA_TOOLS_PAGES.ACTIONS)) { return; } - FileUploadServletRequest req = FileUploadServletRequest.parseRequest( - rawRequest, maxFileSizeInBytes); - if (req.hasFileUploadException()) { + VitroRequest request = new VitroRequest(req); + if (request.hasFileSizeException()) { forwardToFileUploadError( - req.getFileUploadException().getLocalizedMessage(), + request.getFileSizeException().getLocalizedMessage(), req, response); return; } - Map> fileStreams = req.getFiles(); + Map> fileStreams = request.getFiles(); - VitroRequest request = new VitroRequest(req); LoginStatusBean loginBean = LoginStatusBean.getBean(request); try { String modelName = req.getParameter("modelName"); if(modelName!=null){ - loadRDF(req,request,response); + loadRDF(request,response); return; } } catch (Exception e) { @@ -234,15 +241,13 @@ public class RDFUploadController extends JenaIngestController { } } - public void loadRDF(FileUploadServletRequest req, - VitroRequest request, - HttpServletResponse response) - throws ServletException, IOException { - Map> fileStreams = req.getFiles(); + public void loadRDF(VitroRequest request, HttpServletResponse response) + throws ServletException { + Map> fileStreams = request.getFiles(); String filePath = fileStreams.get("filePath").get(0).getName(); fileStream = fileStreams.get("filePath").get(0); - String modelName = req.getParameter("modelName"); - String docLoc = req.getParameter("docLoc"); + String modelName = request.getParameter("modelName"); + String docLoc = request.getParameter("docLoc"); String languageStr = request.getParameter("language"); ModelMaker maker = getVitroJenaModelMaker(request); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SearchServiceController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SearchServiceController.java index 88175db88..490fff4ef 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SearchServiceController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/SearchServiceController.java @@ -23,7 +23,6 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ExceptionResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; -import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest; import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder; /** @@ -35,7 +34,10 @@ public class SearchServiceController extends FreemarkerHttpServlet { .getLog(SearchServiceController.class); /** Limit file size to 1 Gigabyte. */ - public static final int MAXIMUM_FILE_SIZE = 1024 * 1024 * 1024; + @Override + public long maximumMultipartFileSize() { + return 1024 * 1024 * 1024; + } /** * Handle the different actions. If not specified, the default action is to @@ -44,9 +46,6 @@ public class SearchServiceController extends FreemarkerHttpServlet { @Override protected ResponseValues processRequest(VitroRequest req) { try { - req = new VitroRequest(FileUploadServletRequest.parseRequest(req, - MAXIMUM_FILE_SIZE)); - // Check the authorization here, because we don't want to redirect // to the login page if they are not authorized. (The file upload // would be lost. diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/UpdateUrisInIndex.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/UpdateUrisInIndex.java index 5c3e1636f..f723613ac 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/UpdateUrisInIndex.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/search/controller/UpdateUrisInIndex.java @@ -2,8 +2,6 @@ package edu.cornell.mannlib.vitro.webapp.search.controller; -import static edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest.FILE_ITEM_MAP; - import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; @@ -21,6 +19,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder; /** @@ -41,9 +40,7 @@ public class UpdateUrisInIndex { */ protected int doUpdateUris(HttpServletRequest req, IndexBuilder builder) throws ServletException, IOException { - @SuppressWarnings("unchecked") - Map> map = (Map>) req - .getAttribute(FILE_ITEM_MAP); + Map> map = new VitroRequest(req).getFiles(); if (map == null) { throw new ServletException("Expected Multipart Content"); } @@ -54,13 +51,13 @@ public class UpdateUrisInIndex { for (String name : map.keySet()) { for (FileItem item : map.get(name)) { log.debug("Found " + item.getSize() + " byte file for '" + name + "'"); - uriCount += processFileItem(builder, name, item, enc); + uriCount += processFileItem(builder, item, enc); } } return uriCount; } - private int processFileItem(IndexBuilder builder, String name, + private int processFileItem(IndexBuilder builder, FileItem item, Charset enc) throws IOException { int count = 0; Reader reader = new InputStreamReader(item.getInputStream(), enc.name());