Author: remy.maucherat(a)jboss.com
Date: 2009-10-15 10:58:30 -0400 (Thu, 15 Oct 2009)
New Revision: 1195
Modified:
trunk/java/org/apache/catalina/connector/LocalStrings.properties
trunk/java/org/apache/catalina/connector/Request.java
trunk/java/org/apache/catalina/connector/RequestFacade.java
trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileUpload.java
trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
Log:
- Implement the various error conditions for multipart, and fix a couple obvious
problems.
Modified: trunk/java/org/apache/catalina/connector/LocalStrings.properties
===================================================================
--- trunk/java/org/apache/catalina/connector/LocalStrings.properties 2009-10-15 14:57:00
UTC (rev 1194)
+++ trunk/java/org/apache/catalina/connector/LocalStrings.properties 2009-10-15 14:58:30
UTC (rev 1195)
@@ -48,6 +48,7 @@
coyoteRequest.listenerStop=Exception sending context destroyed event to listener instance
of class {0}
coyoteRequest.attributeEvent=Exception thrown by attributes event listener
coyoteRequest.parseMultipart=Exception thrown whilst processing multipart
+coyoteRequest.notMultipart=The request is not multipart content
coyoteRequest.parseParameters=Exception thrown whilst processing POSTed parameters
coyoteRequest.postTooLarge=Parameters were not parsed because the size of the posted data
was too big. Use the maxPostSize attribute of the connector to resolve this if the
application should accept large POSTs.
coyoteRequest.noAuthenticator=No authenticator available for programmatic login
Modified: trunk/java/org/apache/catalina/connector/Request.java
===================================================================
--- trunk/java/org/apache/catalina/connector/Request.java 2009-10-15 14:57:00 UTC (rev
1194)
+++ trunk/java/org/apache/catalina/connector/Request.java 2009-10-15 14:58:30 UTC (rev
1195)
@@ -112,6 +112,7 @@
import org.apache.tomcat.util.http.ServerCookie;
import org.apache.tomcat.util.http.fileupload.DiskFileUpload;
import org.apache.tomcat.util.http.fileupload.FileItem;
+import org.apache.tomcat.util.http.fileupload.FileUploadBase;
import org.apache.tomcat.util.http.mapper.MappingData;
@@ -2667,8 +2668,15 @@
}
if (!("application/x-www-form-urlencoded".equals(contentType))) {
// Check for multipart as an alternate way to send parameters
- if (parts == null) {
- parseMultipart();
+ if (parts == null &&
"multipart/form-data".equals(contentType)) {
+ try {
+ parseMultipart();
+ } catch (Exception e) {
+ if (context.getLogger().isDebugEnabled()) {
+ context.getLogger().debug(
+ sm.getString("coyoteRequest.parseMultipart"),
e);
+ }
+ }
}
return;
}
@@ -2759,7 +2767,8 @@
/**
* Parse multipart.
*/
- protected void parseMultipart() {
+ protected void parseMultipart()
+ throws IOException, ServletException {
Multipart config = wrapper.getMultipartConfig();
if (config == null) {
@@ -2782,7 +2791,7 @@
contentType = contentType.trim();
}
if (!("multipart/form-data".equals(contentType)))
- return;
+ throw new
ServletException(sm.getString("coyoteRequest.notMultipart"));
DiskFileUpload fu = new DiskFileUpload();
fu.setRepositoryPath(config.getLocation());
@@ -2798,21 +2807,16 @@
parts = new HashMap<String, Part>();
try {
- Iterator<FileItem> items = fu.parseRequest(getRequest()).iterator();
- while (items.hasNext()) {
- FileItem fileItem = items.next();
+ for (FileItem fileItem : fu.parseRequest(getRequest())) {
if (fileItem.getFileName() == null) {
coyoteRequest.getParameters().addParameterValues(fileItem.getName(),
new String[] {fileItem.getString()});
}
- parts.put(fileItem.getFieldName(), fileItem);
+ parts.put(fileItem.getName(), fileItem);
}
- } catch (IOException e) {
- // Client disconnect
- if (context.getLogger().isDebugEnabled()) {
- context.getLogger().debug(
- sm.getString("coyoteRequest.parseMultipart"), e);
- }
- return;
+ } catch(FileUploadBase.FileSizeLimitExceededException e) {
+ throw new
IllegalStateException(sm.getString("coyoteRequest.parseMultipart"), e);
+ } catch(FileUploadBase.SizeLimitExceededException e) {
+ throw new
IllegalStateException(sm.getString("coyoteRequest.parseMultipart"), e);
}
}
@@ -3092,7 +3096,7 @@
}
- public Part getPart(String name) throws ServletException {
+ public Part getPart(String name) throws IOException, ServletException {
if (parts == null) {
parseMultipart();
}
@@ -3106,7 +3110,7 @@
}
- public Collection<Part> getParts() throws ServletException {
+ public Collection<Part> getParts() throws IOException, ServletException {
if (parts == null) {
parseMultipart();
}
Modified: trunk/java/org/apache/catalina/connector/RequestFacade.java
===================================================================
--- trunk/java/org/apache/catalina/connector/RequestFacade.java 2009-10-15 14:57:00 UTC
(rev 1194)
+++ trunk/java/org/apache/catalina/connector/RequestFacade.java 2009-10-15 14:58:30 UTC
(rev 1195)
@@ -1081,7 +1081,7 @@
}
- public Part getPart(String name) throws ServletException {
+ public Part getPart(String name) throws IOException, ServletException {
if (request == null) {
throw new IllegalStateException(
sm.getString("requestFacade.nullRequest"));
@@ -1091,7 +1091,7 @@
}
- public Collection<Part> getParts() throws ServletException {
+ public Collection<Part> getParts() throws IOException, ServletException {
if (request == null) {
throw new IllegalStateException(
sm.getString("requestFacade.nullRequest"));
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileUpload.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileUpload.java 2009-10-15
14:57:00 UTC (rev 1194)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileUpload.java 2009-10-15
14:58:30 UTC (rev 1195)
@@ -20,6 +20,7 @@
import java.io.File;
+import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@@ -219,7 +220,7 @@
public List<FileItem> parseRequest(HttpServletRequest req,
int sizeThreshold,
long sizeMax, String path)
- throws FileUploadException
+ throws IOException, FileUploadException
{
setSizeThreshold(sizeThreshold);
setSizeMax(sizeMax);
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java 2009-10-15
14:57:00 UTC (rev 1194)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java 2009-10-15
14:58:30 UTC (rev 1195)
@@ -143,6 +143,11 @@
*/
private long sizeMax = -1;
+ /**
+ * The maximum size permitted for a single uploaded file, as opposed
+ * to {@link #sizeMax}. A value of -1 indicates no maximum.
+ */
+ private long fileSizeMax = -1;
/**
* The content encoding to use when reading part headers.
@@ -198,6 +203,28 @@
/**
+ * Returns the maximum allowed size of a single uploaded file,
+ * as opposed to {@link #getSizeMax()}.
+ *
+ * @see #setFileSizeMax(long)
+ * @return Maximum size of a single uploaded file.
+ */
+ public long getFileSizeMax() {
+ return fileSizeMax;
+ }
+
+ /**
+ * Sets the maximum allowed size of a single uploaded file,
+ * as opposed to {@link #getSizeMax()}.
+ *
+ * @see #getFileSizeMax()
+ * @param fileSizeMax Maximum size of a single uploaded file.
+ */
+ public void setFileSizeMax(long fileSizeMax) {
+ this.fileSizeMax = fileSizeMax;
+ }
+
+ /**
* Retrieves the character encoding used when reading the headers of an
* individual part. When not specified, or <code>null</code>, the
platform
* default encoding is used.
@@ -240,7 +267,7 @@
* the request or storing files.
*/
public List<FileItem> parseRequest(HttpServletRequest req)
- throws FileUploadException
+ throws IOException, FileUploadException
{
if (null == req)
{
@@ -275,75 +302,47 @@
+ "it's size exceeds allowed range");
}
- try
+ int boundaryIndex = contentType.indexOf("boundary=");
+ if (boundaryIndex < 0)
{
- int boundaryIndex = contentType.indexOf("boundary=");
- if (boundaryIndex < 0)
- {
- throw new FileUploadException(
- "the request was rejected because "
- + "no multipart boundary was found");
- }
- byte[] boundary = contentType.substring(
- boundaryIndex + 9).getBytes();
+ throw new FileUploadException(
+ "the request was rejected because "
+ + "no multipart boundary was found");
+ }
+ byte[] boundary = contentType.substring(
+ boundaryIndex + 9).getBytes();
- InputStream input = req.getInputStream();
+ InputStream input = req.getInputStream();
- MultipartStream multi = new MultipartStream(input, boundary);
- multi.setHeaderEncoding(headerEncoding);
+ MultipartStream multi = new MultipartStream(input, boundary);
+ multi.setFileSizeMax(fileSizeMax);
+ multi.setHeaderEncoding(headerEncoding);
- boolean nextPart = multi.skipPreamble();
- while (nextPart)
+ boolean nextPart = multi.skipPreamble();
+ while (nextPart)
+ {
+ Map<String, String> headers = parseHeaders(multi.readHeaders());
+ String fieldName = getFieldName(headers);
+ if (fieldName != null)
{
- Map<String, String> headers = parseHeaders(multi.readHeaders());
- String fieldName = getFieldName(headers);
- if (fieldName != null)
+ String subContentType = getHeader(headers, CONTENT_TYPE);
+ if (subContentType != null && subContentType
+ .startsWith(MULTIPART_MIXED))
{
- String subContentType = getHeader(headers, CONTENT_TYPE);
- if (subContentType != null && subContentType
- .startsWith(MULTIPART_MIXED))
- {
- // Multiple files.
- byte[] subBoundary =
- subContentType.substring(
+ // Multiple files.
+ byte[] subBoundary =
+ subContentType.substring(
subContentType
.indexOf("boundary=") + 9).getBytes();
- multi.setBoundary(subBoundary);
- boolean nextSubPart = multi.skipPreamble();
- while (nextSubPart)
- {
- headers = parseHeaders(multi.readHeaders());
- if (getFileName(headers) != null)
- {
- FileItem item =
- createItem(headers, false);
- OutputStream os = item.getOutputStream();
- try
- {
- multi.readBodyData(os);
- }
- finally
- {
- os.close();
- }
- items.add(item);
- }
- else
- {
- // Ignore anything but files inside
- // multipart/mixed.
- multi.discardBodyData();
- }
- nextSubPart = multi.readBoundary();
- }
- multi.setBoundary(boundary);
- }
- else
+ multi.setBoundary(subBoundary);
+ boolean nextSubPart = multi.skipPreamble();
+ while (nextSubPart)
{
+ headers = parseHeaders(multi.readHeaders());
if (getFileName(headers) != null)
{
- // A single file.
- FileItem item = createItem(headers, false);
+ FileItem item =
+ createItem(headers, false);
OutputStream os = item.getOutputStream();
try
{
@@ -357,35 +356,55 @@
}
else
{
- // A form field.
- FileItem item = createItem(headers, true);
- OutputStream os = item.getOutputStream();
- try
- {
- multi.readBodyData(os);
- }
- finally
- {
- os.close();
- }
- items.add(item);
+ // Ignore anything but files inside
+ // multipart/mixed.
+ multi.discardBodyData();
}
+ nextSubPart = multi.readBoundary();
}
+ multi.setBoundary(boundary);
}
else
{
- // Skip this part.
- multi.discardBodyData();
+ if (getFileName(headers) != null)
+ {
+ // A single file.
+ FileItem item = createItem(headers, false);
+ OutputStream os = item.getOutputStream();
+ try
+ {
+ multi.readBodyData(os);
+ }
+ finally
+ {
+ os.close();
+ }
+ items.add(item);
+ }
+ else
+ {
+ // A form field.
+ FileItem item = createItem(headers, true);
+ OutputStream os = item.getOutputStream();
+ try
+ {
+ multi.readBodyData(os);
+ }
+ finally
+ {
+ os.close();
+ }
+ items.add(item);
+ }
}
- nextPart = multi.readBoundary();
}
+ else
+ {
+ // Skip this part.
+ multi.discardBodyData();
+ }
+ nextPart = multi.readBoundary();
}
- catch (IOException e)
- {
- throw new FileUploadException(
- "Processing of " + MULTIPART_FORM_DATA
- + " request failed. " + e.getMessage());
- }
return items;
}
@@ -639,4 +658,31 @@
}
}
+ /**
+ * Thrown to indicate that the request size exceeds the configured maximum.
+ */
+ public static class FileSizeLimitExceededException
+ extends FileUploadException
+ {
+ /**
+ * Constructs a <code>SizeExceededException</code> with no
+ * detail message.
+ */
+ public FileSizeLimitExceededException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs an <code>SizeExceededException</code> with
+ * the specified detail message.
+ *
+ * @param message The detail message.
+ */
+ public FileSizeLimitExceededException(String message)
+ {
+ super(message);
+ }
+ }
+
}
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java 2009-10-15
14:57:00 UTC (rev 1194)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java 2009-10-15
14:58:30 UTC (rev 1195)
@@ -188,7 +188,10 @@
*/
private String headerEncoding;
+
+ private long fileSizeMax = -1;
+
// ----------------------------------------------------------- Constructors
@@ -261,7 +264,6 @@
*/
public MultipartStream(InputStream input,
byte[] boundary)
- throws IOException
{
this(input, boundary, DEFAULT_BUFSIZE);
}
@@ -269,6 +271,8 @@
// --------------------------------------------------------- Public methods
+
+
/**
* Retrieves the character encoding used when reading the headers of an
@@ -284,6 +288,16 @@
}
+ public long getFileSizeMax() {
+ return fileSizeMax;
+ }
+
+
+ public void setFileSizeMax(long fileSizeMax) {
+ this.fileSizeMax = fileSizeMax;
+ }
+
+
/**
* Specifies the character encoding to be used when reading the headers of
* individual parts. When not specified, or <code>null</code>, the
platform
@@ -497,6 +511,9 @@
int total = 0;
while (!done)
{
+ if (fileSizeMax > 0 && total > fileSizeMax) {
+ throw new FileUploadBase.FileSizeLimitExceededException("File size
exceeded");
+ }
// Is boundary token present somewere in the buffer?
pos = findSeparator();
if (pos != -1)