mschachter 01/05/11 15:33:38
Modified: src/share/org/apache/struts/action Action.java
ActionServlet.java
src/share/org/apache/struts/upload
DiskMultipartRequestHandler.java
src/share/org/apache/struts/util RequestUtils.java
Added: src/share/org/apache/struts/upload
MultipartRequestWrapper.java
Log:
- Added the MultipartRequestWrapper class, which is a class that implements
HttpServletRequest and wraps a normal request. All normal HttpServletRequest
methods will be called to the underlying request, except for methods involving
parameters, which were over-ridden to provide a transparent way of accessing
multipart elements. The version of the HttpServletRequest is Servlet 2.2, however
the new methods from Servlet 2.3 are also included in this class with empty
implementations so that Struts will build against the servlet 2.2 and 2.3 jars
- Removed the isCancelled(MultipartRequestHandler) method from Action, in favor
of isCancelled(HttpServletRequest), which now works for multipart requests
- The process() method of ActionServlet now determines whether or not the current
request is a multipart request, and if it is, wraps it in the new
MultipartRequestWrapper class temporarily, and right before the ActionForward
is processed, reverts the request back to the original one
- Modified DiskMultipartRequestHandler to populate the request with multipart
data if it's passed a request of type MultipartRequestWrapper
- Modified RequestUtils to check to make sure the method of the request is
"POST" before processing a multipart request (Submitted by Martin Cooper). It
does
this in RequestUtils as well as ActionServlet when it checks for multipart
requests
This change has been tested against all the webapps included with Struts,
and doesn't seem to cause any issues. Command tokens and cancel buttons
should now work fine for multipart requests without any modifications
Revision Changes Path
1.21 +5 -27 jakarta-struts/src/share/org/apache/struts/action/Action.java
Index: Action.java
===================================================================
RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- Action.java 2001/05/11 17:10:55 1.20
+++ Action.java 2001/05/11 22:33:31 1.21
@@ -1,7 +1,7 @@
/*
- * $Header:
/home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.20
2001/05/11 17:10:55 mschachter Exp $
- * $Revision: 1.20 $
- * $Date: 2001/05/11 17:10:55 $
+ * $Header:
/home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.21
2001/05/11 22:33:31 mschachter Exp $
+ * $Revision: 1.21 $
+ * $Date: 2001/05/11 22:33:31 $
*
* ====================================================================
*
@@ -108,7 +108,7 @@
* by this Action.
*
* @author Craig R. McClanahan
- * @version $Revision: 1.20 $ $Date: 2001/05/11 17:10:55 $
+ * @version $Revision: 1.21 $ $Date: 2001/05/11 22:33:31 $
*/
public class Action {
@@ -423,7 +423,7 @@
}
}
-
+
/**
* Return the user's currently selected Locale.
@@ -470,28 +470,6 @@
}
- /**
- * Returns <code>true</code> if the current multipart form's cancel button was
- * pressed. This method will check if the cancel button generated by
- * <strong>CancelTag</strong> was pressed by the user in the
- * current request. If true, validation performed by an
- * <strong>ActionForm</strong> validate() method will have been
- * skipped by the controller servlet. A MultipartRequestHandler instance
- * can be obtained from a multipart form by calling
- * {@link ActionForm#getMultipartRequestHandler()
ActionForm.getMultipartRequestHandler()}.
- *
- * @param request The servlet request we are processing
- * @see org.apache.struts.taglib.CancelTag
- * @see org.apache.struts.action.ValidatingActionForm
- */
- protected boolean isCancelled(MultipartRequestHandler request) {
-
- Hashtable elements = request.getTextElements();
- return ((elements.get(Constants.CANCEL_PROPERTY) != null) ||
- (elements.get(Constants.CANCEL_PROPERTY_X) != null));
- }
-
-
/**
* Return <code>true</code> if there is a transaction token stored in
* the user's current session, and the value submitted as a request
1.68 +23 -5
jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java
Index: ActionServlet.java
===================================================================
RCS file:
/home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v
retrieving revision 1.67
retrieving revision 1.68
diff -u -r1.67 -r1.68
--- ActionServlet.java 2001/05/10 02:31:35 1.67
+++ ActionServlet.java 2001/05/11 22:33:32 1.68
@@ -1,7 +1,7 @@
/*
- * $Header:
/home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.67
2001/05/10 02:31:35 craigmcc Exp $
- * $Revision: 1.67 $
- * $Date: 2001/05/10 02:31:35 $
+ * $Header:
/home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.68
2001/05/11 22:33:32 mschachter Exp $
+ * $Revision: 1.68 $
+ * $Date: 2001/05/11 22:33:32 $
*
* ====================================================================
*
@@ -88,6 +88,7 @@
import org.apache.struts.util.MessageResources;
import org.apache.struts.util.MessageResourcesFactory;
import org.apache.struts.util.RequestUtils;
+import org.apache.struts.upload.MultipartRequestWrapper;
import org.xml.sax.AttributeList;
import org.xml.sax.SAXException;
@@ -228,7 +229,7 @@
* </ul>
*
* @author Craig R. McClanahan
- * @version $Revision: 1.67 $ $Date: 2001/05/10 02:31:35 $
+ * @version $Revision: 1.68 $ $Date: 2001/05/11 22:33:32 $
*/
public class ActionServlet
@@ -1500,6 +1501,18 @@
HttpServletResponse response)
throws IOException, ServletException {
+ String contentType = request.getContentType();
+ String method = request.getMethod();
+
+ //if this is a multipart request, wrap the HttpServletRequest object
+ //with a MultipartRequestWrapper to keep the process sub-methods
+ //from failing when checking for certain request parameters
+ //for command tokens and cancel button detection
+ if ((contentType != null) && (contentType.startsWith("multipart/form-data"))
+ && (method.equals("POST"))) {
+ request = new MultipartRequestWrapper(request);
+ }
+
// Identify the path component we will use to select a mapping
String path = processPath(request);
if (path == null) {
@@ -1539,7 +1552,7 @@
processPopulate(formInstance, mapping, request);
if (!processValidate(mapping, formInstance, request, response))
return;
-
+
// Execute a forward if specified by this mapping
if (!processForward(mapping, request, response))
return;
@@ -1561,6 +1574,11 @@
ActionForward forward =
processActionPerform(actionInstance, mapping, formInstance,
request, response);
+ //set the request back to it's normal state if it's currently wrapped,
+ //to avoid ClassCastExceptions from ServletContainers if forwarding
+ if (request instanceof MultipartRequestWrapper) {
+ request = ((MultipartRequestWrapper) request).getRequest();
+ }
// Process the returned ActionForward (if any)
processActionForward(forward, mapping, formInstance,
1.10 +13 -3
jakarta-struts/src/share/org/apache/struts/upload/DiskMultipartRequestHandler.java
Index: DiskMultipartRequestHandler.java
===================================================================
RCS file:
/home/cvs/jakarta-struts/src/share/org/apache/struts/upload/DiskMultipartRequestHandler.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- DiskMultipartRequestHandler.java 2001/05/10 00:56:54 1.9
+++ DiskMultipartRequestHandler.java 2001/05/11 22:33:36 1.10
@@ -16,7 +16,7 @@
/**
* This is a MultipartRequestHandler that writes file data directly to
- * to temporary files on disk
+ * to temporary files on disk.
*
* @author Mike Schachter
*/
@@ -52,6 +52,12 @@
*/
protected String tempDir;
+
+ /**
+ * This method populates the internal hashtables with multipart request data.
+ * If the request argument is an instance of MultipartRequestWrapper,
+ * the request wrapper will be populated as well.
+ */
public void handleRequest(HttpServletRequest request) throws ServletException {
retrieveTempDir();
@@ -70,8 +76,13 @@
while ((element = iterator.getNextElement()) != null) {
if (!element.isFile()) {
+ if (request instanceof MultipartRequestWrapper) {
+ ((MultipartRequestWrapper)
request).setParameter(element.getName(),
+
element.getValue());
+ }
String[] textValues = (String[])
textElements.get(element.getName());
- if (textValues != null) {
+
+ if (textValues != null) {
String[] textValues2 = new String[textValues.length + 1];
System.arraycopy(textValues, 0, textValues2, 0,
textValues.length);
textValues2[textValues.length] = element.getValue();
@@ -81,7 +92,6 @@
textValues = new String[1];
textValues[0] = element.getValue();
}
-
textElements.put(element.getName(), textValues);
allElements.put(element.getName(), textValues);
}
1.1
jakarta-struts/src/share/org/apache/struts/upload/MultipartRequestWrapper.java
Index: MultipartRequestWrapper.java
===================================================================
package org.apache.struts.upload;
import java.util.Map;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedReader;
import java.security.Principal;
import javax.servlet.ServletInputStream;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
/**
* This class functions as a wrapper around HttpServletRequest to
* provide working getParameter methods for multipart requests. Once
* Struts requires Servlet 2.3, this class will definately be changed to
* extend javax.servlet.http.HttpServletRequestWrapper instead of
* implementing HttpServletRequest. Servlet 2.3 methods are implemented
* to return <code>null</code> or do nothing if called on. Use
* {@link #getRequest() getRequest} to retrieve the underlying HttpServletRequest
* object and call on the 2.3 method there, the empty methods are here only
* so that this will compile with the Servlet 2.3 jar. This class exists temporarily
* in the process() method of ActionServlet, just before the ActionForward is
processed
* and just after the Action is performed, the request is set back to the original
* HttpServletRequest object.
*/
public class MultipartRequestWrapper implements HttpServletRequest {
/**
* The parameters for this multipart request
*/
protected Map parameters;
/**
* The underlying HttpServletRequest
*/
protected HttpServletRequest request;
public MultipartRequestWrapper(HttpServletRequest request) {
this.request = request;
this.parameters = new HashMap();
}
/**
* Sets a parameter for this request. The parameter is actually
* separate from the request parameters, but calling on the
* getParameter() methods of this class will work as if they weren't.
*/
public void setParameter(String name, String value) {
String[] mValue = (String[]) parameters.get(name);
if (mValue == null) {
mValue = new String[0];
}
String[] newValue = new String[mValue.length + 1];
System.arraycopy(mValue, 0, newValue, 0, mValue.length);
newValue[mValue.length] = value;
parameters.put(name, newValue);
}
/**
* Attempts to get a parameter for this request. It first looks in the
* underlying HttpServletRequest object for the parameter, and if that
* doesn't exist it looks for the parameters retrieved from the multipart
* request
*/
public String getParameter(String name) {
String value = request.getParameter(name);
if (value == null) {
String[] mValue = (String[]) parameters.get(name);
if ((mValue != null) && (mValue.length > 0)) {
value = mValue[0];
}
}
return value;
}
/**
* Returns the names of the parameters for this request.
* The enumeration consists of the normal request parameter
* names plus the parameters read from the multipart request
*/
public Enumeration getParameterNames() {
Enumeration baseParams = request.getParameterNames();
Vector list = new Vector();
while (baseParams.hasMoreElements()) {
list.add(baseParams.nextElement());
}
Collection multipartParams = parameters.keySet();
Iterator iterator = multipartParams.iterator();
while (iterator.hasNext()) {
list.add(iterator.next());
}
return Collections.enumeration(list);
}
public String[] getParameterValues(String name) {
String[] value = request.getParameterValues(name);
if (value == null) {
value = (String[]) parameters.get(name);
}
return value;
}
/**
* Returns the underlying HttpServletRequest for this wrapper
*/
public HttpServletRequest getRequest() {
return request;
}
//WRAPPER IMPLEMENTATIONS OF SERVLET REQUEST METHODS
public Object getAttribute(String name) {
return request.getAttribute(name);
}
public Enumeration getAttributeNames() {
return request.getAttributeNames();
}
public String getCharacterEncoding() {
return request.getCharacterEncoding();
}
public int getContentLength() {
return request.getContentLength();
}
public String getContentType() {
return request.getContentType();
}
public ServletInputStream getInputStream() throws IOException {
return request.getInputStream();
}
public String getProtocol() {
return request.getProtocol();
}
public String getScheme() {
return request.getScheme();
}
public String getServerName() {
return request.getServerName();
}
public int getServerPort() {
return request.getServerPort();
}
public BufferedReader getReader() throws IOException {
return request.getReader();
}
public String getRemoteAddr() {
return request.getRemoteAddr();
}
public String getRemoteHost() {
return request.getRemoteHost();
}
public void setAttribute(String name, Object o) {
request.setAttribute(name, o);
}
public void removeAttribute(String name) {
request.removeAttribute(name);
}
public Locale getLocale() {
return request.getLocale();
}
public Enumeration getLocales() {
return request.getLocales();
}
public boolean isSecure() {
return request.isSecure();
}
public RequestDispatcher getRequestDispatcher(String path) {
return request.getRequestDispatcher(path);
}
public String getRealPath(String path) {
return request.getRealPath(path);
}
//WRAPPER IMPLEMENTATIONS OF HTTPSERVLETREQUEST METHODS
public String getAuthType() {
return request.getAuthType();
}
public Cookie[] getCookies() {
return request.getCookies();
}
public long getDateHeader(String name) {
return request.getDateHeader(name);
}
public String getHeader(String name) {
return request.getHeader(name);
}
public Enumeration getHeaders(String name) {
return request.getHeaders(name);
}
public Enumeration getHeaderNames() {
return request.getHeaderNames();
}
public int getIntHeader(String name) {
return request.getIntHeader(name);
}
public String getMethod() {
return request.getMethod();
}
public String getPathInfo() {
return request.getPathInfo();
}
public String getPathTranslated() {
return request.getPathTranslated();
}
public String getContextPath() {
return request.getContextPath();
}
public String getQueryString() {
return request.getQueryString();
}
public String getRemoteUser() {
return request.getRemoteUser();
}
public boolean isUserInRole(String user) {
return request.isUserInRole(user);
}
public Principal getUserPrincipal() {
return request.getUserPrincipal();
}
public String getRequestedSessionId() {
return request.getRequestedSessionId();
}
public String getRequestURI() {
return request.getRequestURI();
}
public String getServletPath() {
return request.getServletPath();
}
public HttpSession getSession(boolean create) {
return request.getSession(create);
}
public HttpSession getSession() {
return request.getSession();
}
public boolean isRequestedSessionIdValid() {
return request.isRequestedSessionIdValid();
}
public boolean isRequestedSessionIdFromURL() {
return request.isRequestedSessionIdFromURL();
}
public boolean isRequestedSessionIdFromUrl() {
return request.isRequestedSessionIdFromUrl();
}
//SERVLET 2.3 EMPTY METHODS
/**
* This method returns null. To use any Servlet 2.3 methods,
* call on getRequest() and use that request object. Once Servlet 2.3
* is required to build Struts, this will no longer be an issue.
*/
public Map getParameterMap() {
return null;
}
/**
* This method does nothing. To use any Servlet 2.3 methods,
* call on getRequest() and use that request object. Once Servlet 2.3
* is required to build Struts, this will no longer be an issue.
*/
public void setCharacterEncoding(String encoding) {
;
}
/**
* This method returns null. To use any Servlet 2.3 methods,
* call on getRequest() and use that request object. Once Servlet 2.3
* is required to build Struts, this will no longer be an issue.
*/
public StringBuffer getRequestURL() {
return null;
}
/**
* This method returns false. To use any Servlet 2.3 methods,
* call on getRequest() and use that request object. Once Servlet 2.3
* is required to build Struts, this will no longer be an issue.
*/
public boolean isRequestedSessionIdFromCookie() {
return false;
}
}
1.12 +10 -5
jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java
Index: RequestUtils.java
===================================================================
RCS file:
/home/cvs/jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- RequestUtils.java 2001/05/09 19:31:29 1.11
+++ RequestUtils.java 2001/05/11 22:33:37 1.12
@@ -1,7 +1,7 @@
/*
- * $Header:
/home/cvs/jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java,v 1.11
2001/05/09 19:31:29 craigmcc Exp $
- * $Revision: 1.11 $
- * $Date: 2001/05/09 19:31:29 $
+ * $Header:
/home/cvs/jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java,v 1.12
2001/05/11 22:33:37 mschachter Exp $
+ * $Revision: 1.12 $
+ * $Date: 2001/05/11 22:33:37 $
*
* ====================================================================
*
@@ -95,7 +95,7 @@
* in the Struts controller framework.
*
* @author Craig R. McClanahan
- * @version $Revision: 1.11 $ $Date: 2001/05/09 19:31:29 $
+ * @version $Revision: 1.12 $ $Date: 2001/05/11 22:33:37 $
*/
public class RequestUtils {
@@ -609,6 +609,9 @@
* If you specify a non-null <code>prefix</code> and a non-null
* <code>suffix</code>, the parameter name must match <strong>both</strong>
* conditions for its value(s) to be used in populating bean properties.
+ * If the request's content type is "multipart/form-data" and the
+ * method is "POST", the HttpServletRequest object will be wrapped in
+ * a MultipartRequestWrapper object.
*
* @param bean The JavaBean whose properties are to be set
* @param prefix The prefix (if any) to be prepend to bean property
@@ -634,8 +637,10 @@
boolean isMultipart = false;
String contentType = request.getContentType();
+ String method = request.getMethod();
if ((contentType != null) &&
- (contentType.startsWith("multipart/form-data"))) {
+ (contentType.startsWith("multipart/form-data")) &&
+ (method.equalsIgnoreCase("POST"))) {
isMultipart = true;
//initialize a MultipartRequestHandler
MultipartRequestHandler multipart = null;