Permalink
Browse files

Fixing pullreq #414 by dgouvea: allow multiple file upload

  • Loading branch information...
1 parent eed6129 commit 9215ba1ce9a17a8301fc76ae92f2c16a2e497858 @garcia-jj garcia-jj committed Nov 19, 2011
@@ -26,8 +26,8 @@
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
-import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
+import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
@@ -45,17 +45,19 @@
import br.com.caelum.vraptor.validator.Validations;
import com.google.common.base.Strings;
+import com.google.common.collect.HashMultiset;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
+import com.google.common.collect.Multiset;
/**
* A multipart interceptor based on Apache Commons Upload. Provided parameters are injected through
* RequestParameters.set and uploaded files are made available through
- *
+ *
* @author Guilherme Silveira
* @author Otávio Scherer Garcia
*/
-@Intercepts(before=ResourceLookupInterceptor.class, after = {})
+@Intercepts(before = ResourceLookupInterceptor.class, after = {})
@RequestScoped
public class CommonsUploadMultipartInterceptor
implements MultipartInterceptor {
@@ -68,6 +70,8 @@
private final Validator validator;
private final ServletFileUploadCreator fileUploadCreator;
+ final Multiset<String> indexes = HashMultiset.create();
+
public CommonsUploadMultipartInterceptor(HttpServletRequest request, MutableRequest parameters, MultipartConfig cfg,
Validator validator, ServletFileUploadCreator fileUploadCreator) {
this.request = request;
@@ -99,18 +103,10 @@ public void intercept(InterceptorStack stack, ResourceMethod method, Object inst
final Multimap<String, String> params = LinkedListMultimap.create();
- Map<String, Integer> variables = new HashMap<String, Integer>();
-
for (FileItem item : items) {
String name = item.getFieldName();
- if (name.contains("[]")) {
- Integer count = variables.get(name);
- if (count == null)
- count = -1;
- variables.put(name, ++count);
- name = name.replace("[]", "[" + count + "]");
- }
-
+ name = fixIndexedParameters(name);
+
if (item.isFormField()) {
logger.debug("{} is a field", name);
params.put(name, getValue(item));
@@ -120,7 +116,7 @@ public void intercept(InterceptorStack stack, ResourceMethod method, Object inst
processFile(item, name);
} else {
- logger.debug("A file field was empty: {}", item.getFieldName());
+ logger.debug("A file field was empty: {}", item.getFieldName());
}
}
@@ -147,7 +143,7 @@ private boolean isNotEmpty(FileItem item) {
/**
* This method is called when the {@link SizeLimitExceededException} was thrown. By default, add the key
* file.limit.exceeded using {@link Validations}.
- *
+ *
* @param e
*/
protected void reportSizeLimitExceeded(final SizeLimitExceededException e) {
@@ -180,7 +176,7 @@ protected FileItemFactory createFactoryForDiskBasedFileItems(File temporaryDirec
return factory;
}
- private String getValue(FileItem item) {
+ protected String getValue(FileItem item) {
String encoding = request.getCharacterEncoding();
if (!Strings.isNullOrEmpty(encoding)) {
try {
@@ -191,4 +187,14 @@ private String getValue(FileItem item) {
}
return item.getString();
}
+
+ protected String fixIndexedParameters(String name) {
+ if (name.contains("[]")) {
+ String newName = name.replace("[]", "[" + (indexes.count(name)) + "]");
+ indexes.add(name);
+ logger.debug("{} was renamed to {}", name, newName);
+ name = newName;
+ }
+ return name;
+ }
}
@@ -42,8 +42,10 @@
import br.com.caelum.vraptor.validator.Validations;
import com.google.common.base.Strings;
+import com.google.common.collect.HashMultiset;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
+import com.google.common.collect.Multiset;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
@@ -59,18 +61,18 @@
* https://servlet-spec-public.dev.java.net/issues/show_bug.cgi?id=14 for more info.
* </p>
* <p>
- * TODO According JSR315, all form fields are also avaliable via request.getParameter and request.getParameters(), but not
- * all containers implements this issue (Glassfish 3.0 fails).
+ * TODO According JSR315, all form fields are also avaliable via request.getParameter and request.getParameters(), but
+ * not all containers implements this issue (Glassfish 3.0 fails).
* </p>
- *
+ *
* @author Otávio Scherer Garcia
* @since 3.2
* @see DefaultMultipartConfig
* @see NullMultipartInterceptor
* @see MultipartInterceptor
*/
-@Intercepts(before=ParametersInstantiatorInterceptor.class)
+@Intercepts(before = ParametersInstantiatorInterceptor.class)
@RequestScoped
public class Servlet3MultipartInterceptor
implements MultipartInterceptor {
@@ -86,6 +88,8 @@
private final MutableRequest parameters;
private final Validator validator;
+ final Multiset<String> indexes = HashMultiset.create();
+
public Servlet3MultipartInterceptor(HttpServletRequest request, MutableRequest parameters, Validator validator) {
this.request = request;
this.parameters = parameters;
@@ -97,8 +101,8 @@ public Servlet3MultipartInterceptor(HttpServletRequest request, MutableRequest p
*/
public boolean accepts(ResourceMethod method) {
if (!request.getMethod().toUpperCase().equals("POST")) {
- return false;
- }
+ return false;
+ }
String contentType = request.getContentType();
return contentType != null && contentType.startsWith(ACCEPT_MULTIPART);
@@ -112,7 +116,8 @@ public void intercept(InterceptorStack stack, ResourceMethod method, Object reso
try {
for (Part part : request.getParts()) {
- final String name = part.getName();
+ String name = part.getName();
+ name = fixIndexedParameters(name);
if (isField(part)) {
logger.debug("{} is a field", name);
@@ -149,7 +154,7 @@ public void intercept(InterceptorStack stack, ResourceMethod method, Object reso
/**
* This method is called when the max upload size is reached. There are no way to get the maxFileSize() and
* maxRequestSize() attributes in a Filter.
- *
+ *
* @param e
*/
protected void reportSizeLimitExceeded(final IllegalStateException e) {
@@ -165,22 +170,22 @@ protected void reportSizeLimitExceeded(final IllegalStateException e) {
/**
* Returns true if the part is a field, false otherwise.
*/
- private boolean isField(Part part) {
+ protected boolean isField(Part part) {
return Strings.isNullOrEmpty(part.getContentType());
}
/**
* Get the filename of the part. The filename is extracted by header.
*/
- private String getFileName(Part part) {
+ protected String getFileName(Part part) {
String name = part.getHeader(CONTENT_DISPOSITION_KEY);
return EXTRACT_FILENAME.matcher(name).replaceAll("$2");
}
/**
* Get the content of a part as String.
*/
- private String getStringValue(Part part)
+ protected String getStringValue(Part part)
throws IOException {
String encoding = request.getCharacterEncoding();
@@ -198,4 +203,14 @@ private String getStringValue(Part part)
return new String(out);
}
+
+ protected String fixIndexedParameters(String name) {
+ if (name.contains("[]")) {
+ String newName = name.replace("[]", "[" + (indexes.count(name)) + "]");
+ indexes.add(name);
+ logger.debug("{} was renamed to {}", name, newName);
+ name = newName;
+ }
+ return name;
+ }
}
@@ -143,4 +143,28 @@ public void fieldsWithSameName()
verify(request).setAttribute(eq("myfile0"), any(UploadedFile.class));
verify(request).setAttribute(eq("myfile1"), any(UploadedFile.class));
}
+
+ @Test
+ public void multipleUpload()
+ throws Exception {
+ interceptor = new CommonsUploadMultipartInterceptor(request, parameters, config, validator, mockCreator);
+
+ final List<FileItem> elements = new ArrayList<FileItem>();
+ elements.add(new MockFileItem("myfile0[]", "foo.txt", "foo".getBytes()));
+ elements.add(new MockFileItem("myfile0[]", "foo.txt", "bar".getBytes()));
+
+ when(request.getContentType()).thenReturn("multipart/form-data");
+ when(request.getMethod()).thenReturn("POST");
+ when(mockUpload.parseRequest(request)).thenReturn(elements);
+
+ interceptor.intercept(stack, method, instance);
+
+ System.out.println(parameters.getParameterMap());
+
+ verify(parameters).setParameter("myfile0[0]", "myfile0[0]");
+ verify(parameters).setParameter("myfile0[1]", "myfile0[1]");
+
+ verify(request).setAttribute(eq("myfile0[0]"), any(UploadedFile.class));
+ verify(request).setAttribute(eq("myfile0[1]"), any(UploadedFile.class));
+ }
}
@@ -124,4 +124,23 @@ public void filesWithSameName()
verify(request).setAttribute(eq("myfile0"), any(UploadedFile.class));
verify(request).setAttribute(eq("myfile1"), any(UploadedFile.class));
}
+
+ @Test
+ public void multipleUpload()
+ throws Exception {
+ Part file0 = new VraptorPart("myfile0[]", "text/plain", "file.txt", "vraptor3".getBytes());
+ Part file1 = new VraptorPart("myfile0[]", "text/plain", "file.txt", "vraptor3".getBytes());
+
+ when(request.getContentType()).thenReturn("multipart/form-data");
+ when(request.getMethod()).thenReturn("POST");
+ when(request.getParts()).thenReturn(Arrays.asList(file0, file1));
+
+ interceptor.intercept(stack, method, instance);
+
+ verify(parameters).setParameter("myfile0[0]", "myfile0[0]");
+ verify(parameters).setParameter("myfile0[1]", "myfile0[1]");
+
+ verify(request).setAttribute(eq("myfile0[0]"), any(UploadedFile.class));
+ verify(request).setAttribute(eq("myfile0[1]"), any(UploadedFile.class));
+ }
}

0 comments on commit 9215ba1

Please sign in to comment.