NIHVIVO-160 Create a request wrapper that will parse the uploaded files without losing track of the request parameters.
This commit is contained in:
parent
2f46ad2986
commit
b565e92b00
3 changed files with 553 additions and 0 deletions
|
@ -0,0 +1,332 @@
|
|||
/* $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.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.Principal;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wraps an HTTP request and parses it for file uploads, without losing the
|
||||
* request parameters.
|
||||
* </p>
|
||||
* <p>
|
||||
* Most methods are declared here, and simply delegate to the wrapped request.
|
||||
* Methods that have to do with parameters or files are handled differently for
|
||||
* simple requests and multipart request, and are implemented in the
|
||||
* sub-classes.
|
||||
* </p>
|
||||
*/
|
||||
public abstract class FileUploadServletRequest implements HttpServletRequest {
|
||||
// ----------------------------------------------------------------------
|
||||
// The factory method
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Wrap this {@link HttpServletRequest} in an appropriate wrapper class.
|
||||
*/
|
||||
public static FileUploadServletRequest parseRequest(
|
||||
HttpServletRequest request) throws IOException {
|
||||
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
|
||||
if (isMultipart) {
|
||||
return new MultipartHttpServletRequest(request);
|
||||
} else {
|
||||
return new SimpleHttpServletRequestWrapper(request);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// The constructor and the delegate.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private final HttpServletRequest delegate;
|
||||
|
||||
public FileUploadServletRequest(HttpServletRequest delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
protected HttpServletRequest getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// New functionality to be implemented by the subclasses.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public abstract boolean isMultipart();
|
||||
|
||||
public abstract Map<String, List<FileItem>> getFiles();
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Delegated methods.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public String getAuthType() {
|
||||
return delegate.getAuthType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextPath() {
|
||||
return delegate.getContextPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookie[] getCookies() {
|
||||
return delegate.getCookies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDateHeader(String name) {
|
||||
return delegate.getDateHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
return delegate.getHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<?> getHeaderNames() {
|
||||
return delegate.getHeaderNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<?> getHeaders(String name) {
|
||||
return delegate.getHeaders(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntHeader(String name) {
|
||||
return delegate.getIntHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return delegate.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathInfo() {
|
||||
return delegate.getPathInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathTranslated() {
|
||||
return delegate.getPathTranslated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryString() {
|
||||
return delegate.getQueryString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteUser() {
|
||||
return delegate.getRemoteUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestURI() {
|
||||
return delegate.getRequestURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuffer getRequestURL() {
|
||||
return delegate.getRequestURL();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestedSessionId() {
|
||||
return delegate.getRequestedSessionId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServletPath() {
|
||||
return delegate.getServletPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession() {
|
||||
return delegate.getSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession(boolean create) {
|
||||
return delegate.getSession(create);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
return delegate.getUserPrincipal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequestedSessionIdFromCookie() {
|
||||
return delegate.isRequestedSessionIdFromCookie();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequestedSessionIdFromURL() {
|
||||
return delegate.isRequestedSessionIdFromURL();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean isRequestedSessionIdFromUrl() {
|
||||
return delegate.isRequestedSessionIdFromUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequestedSessionIdValid() {
|
||||
return delegate.isRequestedSessionIdValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInRole(String role) {
|
||||
return delegate.isUserInRole(role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name) {
|
||||
return delegate.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<?> getAttributeNames() {
|
||||
return delegate.getAttributeNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterEncoding() {
|
||||
return delegate.getCharacterEncoding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentLength() {
|
||||
return delegate.getContentLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return delegate.getContentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
return delegate.getInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalAddr() {
|
||||
return delegate.getLocalAddr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalName() {
|
||||
return delegate.getLocalName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalPort() {
|
||||
return delegate.getLocalPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return delegate.getLocale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<?> getLocales() {
|
||||
return delegate.getLocales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return delegate.getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedReader getReader() throws IOException {
|
||||
return delegate.getReader();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public String getRealPath(String path) {
|
||||
return delegate.getRealPath(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddr() {
|
||||
return delegate.getRemoteAddr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteHost() {
|
||||
return delegate.getRemoteHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRemotePort() {
|
||||
return delegate.getRemotePort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestDispatcher getRequestDispatcher(String path) {
|
||||
return delegate.getRequestDispatcher(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return delegate.getScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
return delegate.getServerName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getServerPort() {
|
||||
return delegate.getServerPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return delegate.isSecure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
delegate.removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object o) {
|
||||
delegate.setAttribute(name, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterEncoding(String env)
|
||||
throws UnsupportedEncodingException {
|
||||
delegate.setCharacterEncoding(env);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/* $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.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.FileItemFactory;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* 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 Logger LOG = Logger
|
||||
.getLogger(MultipartHttpServletRequest.class);
|
||||
|
||||
private static final String[] EMPTY_ARRAY = new String[0];
|
||||
|
||||
private final Map<String, List<String>> parameters;
|
||||
private final Map<String, List<FileItem>> files;
|
||||
|
||||
/**
|
||||
* Parse the multipart request. Store the info about the request parameters
|
||||
* and the uploaded files.
|
||||
*/
|
||||
public MultipartHttpServletRequest(HttpServletRequest request)
|
||||
throws IOException {
|
||||
super(request);
|
||||
|
||||
Map<String, List<String>> parameters = new HashMap<String, List<String>>();
|
||||
Map<String, List<FileItem>> files = new HashMap<String, List<FileItem>>();
|
||||
|
||||
try {
|
||||
FileItemFactory factory = new DiskFileItemFactory();
|
||||
ServletFileUpload upload = new ServletFileUpload(factory);
|
||||
List<FileItem> items = parseRequestIntoFileItems(request, upload);
|
||||
for (FileItem item : items) {
|
||||
// Process a regular form field
|
||||
if (item.isFormField()) {
|
||||
addToParameters(parameters, item.getFieldName(), item
|
||||
.getString());
|
||||
LOG.debug("Form field (parameter) " + item.getFieldName()
|
||||
+ "=" + item.getString());
|
||||
} else {
|
||||
addToFileItems(files, item);
|
||||
LOG.debug("File " + item.getFieldName() + ": "
|
||||
+ item.getName());
|
||||
}
|
||||
}
|
||||
} catch (FileUploadException e) {
|
||||
String message = "Failed to parse a multipart-content request.";
|
||||
LOG.error(message, e);
|
||||
throw new IOException(message, e);
|
||||
}
|
||||
|
||||
this.parameters = Collections.unmodifiableMap(parameters);
|
||||
LOG.debug("Parameters are: " + this.parameters);
|
||||
this.files = Collections.unmodifiableMap(files);
|
||||
LOG.debug("Files are: " + this.files);
|
||||
}
|
||||
|
||||
/** Either create a new List for the value, or add to an existing List. */
|
||||
private void addToParameters(Map<String, List<String>> map, String name,
|
||||
String value) {
|
||||
if (!map.containsKey(name)) {
|
||||
map.put(name, new ArrayList<String>());
|
||||
}
|
||||
map.get(name).add(value);
|
||||
}
|
||||
|
||||
/** Either create a new List for the file, or add to an existing List. */
|
||||
private void addToFileItems(Map<String, List<FileItem>> map,
|
||||
FileItem file) {
|
||||
String name = file.getFieldName();
|
||||
if (!map.containsKey(name)) {
|
||||
map.put(name, new ArrayList<FileItem>());
|
||||
}
|
||||
map.get(name).add(file);
|
||||
}
|
||||
|
||||
/** Minimize the code that uses the unchecked cast. */
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<FileItem> parseRequestIntoFileItems(HttpServletRequest req,
|
||||
ServletFileUpload upload) throws FileUploadException {
|
||||
return upload.parseRequest(req);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// This is a multipart request, so make the file info available.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean isMultipart() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<FileItem>> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// 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<String, String[]> result = new HashMap<String, String[]>();
|
||||
for (Entry<String, List<String>> entry : parameters.entrySet()) {
|
||||
result.put(entry.getKey(), entry.getValue().toArray(EMPTY_ARRAY));
|
||||
}
|
||||
LOG.debug("resulting parameter map: " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/* $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;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Not a multipart request, so there are no files.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean isMultipart() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<FileItem>> getFiles() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue