Index: src/java/org/apache/cocoon/components/request/multipart/MultipartParser.java
===================================================================
RCS file: /home/cvspublic/cocoon-2.1/src/java/org/apache/cocoon/components/request/multipart/MultipartParser.java,v
retrieving revision 1.1
diff -u -r1.1 MultipartParser.java
--- src/java/org/apache/cocoon/components/request/multipart/MultipartParser.java	9 Mar 2003 00:09:10 -0000	1.1
+++ src/java/org/apache/cocoon/components/request/multipart/MultipartParser.java	22 Mar 2003 15:53:19 -0000
@@ -59,6 +59,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PushbackInputStream;
+import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.StringTokenizer;
 import java.util.Vector;
@@ -99,6 +100,10 @@
 
     /** Field characterEncoding       */
     private String characterEncoding;
+
+	/** Field UPLOAD_ATTRIBUTE - name of request attribute storing 
+     * keys to uploaded files placed in the request */
+    private final static String UPLOAD_ATTRIBUTE = "cocoon-uploads";
     /**
      * Constructor, parses given request
      *
@@ -136,7 +141,7 @@
                 new TokenStream(
                         new PushbackInputStream(
                                 new BufferedInputStream(request.getInputStream()),
-                                MAX_BOUNDARY_SIZE)), getBoundary(request.getContentType()));
+                                MAX_BOUNDARY_SIZE)), getBoundary(request.getContentType()), request);
     }
 
     /**
@@ -148,7 +153,7 @@
      * @throws IOException
      * @throws MultipartException
      */
-    private void parseMultiPart(TokenStream ts, String boundary)
+    private void parseMultiPart(TokenStream ts, String boundary, HttpServletRequest request)
             throws IOException, MultipartException {
 
         ts.setBoundary(boundary.getBytes());
@@ -157,7 +162,7 @@
 
         while (ts.getState() == TokenStream.STATE_NEXTPART) {
             ts.nextPart();
-            parsePart(ts);
+            parsePart(ts, request);
         }
 
         if (ts.getState() != TokenStream.STATE_ENDMULTIPART) {    // sanity check
@@ -173,7 +178,7 @@
      * @throws IOException
      * @throws MultipartException
      */
-    private void parsePart(TokenStream ts)
+    private void parsePart(TokenStream ts, HttpServletRequest request)
             throws IOException, MultipartException {
 
         Hashtable headers = new Hashtable();
@@ -181,7 +186,7 @@
         try {
             if (headers.containsKey("filename")) {
 		        if (!"".equals(headers.get("filename"))) {
-                	parseFilePart(ts, headers);
+                	parseFilePart(ts, headers, request);
 		        } else {
         			// IE6 sends an empty part with filename="" for
         			// empty upload fields. Just parse away the part
@@ -198,7 +203,7 @@
             else if (((String) headers.get("content-disposition")).toLowerCase()
                     .indexOf("multipart") > -1) {
                 parseMultiPart(new TokenStream(ts, MAX_BOUNDARY_SIZE),
-                        "--" + (String) headers.get("boundary"));
+                        "--" + (String) headers.get("boundary"), request);
                 ts.read();    // read past boundary
             } else {
                 throw new MultipartException("Unknown part type");
@@ -219,7 +224,7 @@
      * @throws IOException
      * @throws MultipartException
      */
-    private void parseFilePart(TokenStream in, Hashtable headers)
+    private void parseFilePart(TokenStream in, Hashtable headers, HttpServletRequest request)
             throws IOException, MultipartException {
 
         byte[] buf = new byte[FILE_BUFFER_SIZE];
@@ -241,6 +246,7 @@
 
             if (file.exists()) {
                 if (!allowOverwrite) {
+                    // FIXME: race condition if simultaneous threads upload a file of the same name
                     if (silentlyRename) {
                         int c = 0;
 
@@ -272,6 +278,13 @@
         } else {
             put(headers.get("name"), new FilePartFile(headers, file));
         }
+        
+        ArrayList uploads = (ArrayList)request.getAttribute(UPLOAD_ATTRIBUTE);;
+        if (uploads == null) {
+            uploads = new ArrayList();
+        }
+        uploads.add(headers.get("name"));
+        request.setAttribute(UPLOAD_ATTRIBUTE,uploads);
     }
 
     /**
Index: src/webapp/samples/docs/samples/xsp/upload.xsp
===================================================================
RCS file: /home/cvspublic/cocoon-2.1/src/webapp/samples/docs/samples/xsp/upload.xsp,v
retrieving revision 1.1
diff -u -r1.1 upload.xsp
--- src/webapp/samples/docs/samples/xsp/upload.xsp	9 Mar 2003 00:10:59 -0000	1.1
+++ src/webapp/samples/docs/samples/xsp/upload.xsp	22 Mar 2003 15:53:14 -0000
@@ -27,30 +27,52 @@
      <para>
        <form method="post" enctype="multipart/form-data" action="upload">
          File:  <input type="file" name="uploaded_file" size="50" />
+         <br/>
+		File2:  <input type="file" name="uploaded_file2" size="50" />
          <p>
            <input type="submit" value="Upload File" />
          </p>
-       </form>
+        </form>
      </para>
      <para>
-       <xsp:logic>
-         if (<xsp-request:get-parameter name="uploaded_file"/> != null) {
+       <xsp:logic> <p>You can either get the FilePart objects out of the 
+       		request by parameter name, or you can iterate through the List (currently ArrayList) 
+       		"cocoon-uploads" stored in a request attribute to get the names to look up.</p>
+       	 List myUploads = (List)<xsp-request:get-attribute name="cocoon-uploads"/>;
+         if ( myUploads != null) {
+           
+           java.util.Iterator myIt = myUploads.iterator();
            <xsp:content>
-             Parameter uploaded_file:
+			 Request attribute cocoon-uploads:
              <strong>
-               <xsp-request:get-parameter name="uploaded_file"/>
+               <xsp-request:get-attribute name="cocoon-uploads"/>
              </strong>
-             <br/>
-
-             Parameter uploaded_file is instance of:
-             <!-- note usage of get() instead of getParameter() -->
-             <strong>
-               <xsp:expr>
-                 request.get("uploaded_file").getClass()
-               </xsp:expr>
-             </strong>
-             <br/>
-           </xsp:content>
+             <br/>	
+            </xsp:content> 		            
+           while (myIt.hasNext()) {
+           		String uploadParam = (String)myIt.next();
+	           <xsp:content>
+	            <p>
+	             Parameter <xsp:expr>uploadParam</xsp:expr>:
+					<strong>
+						<xsp:expr>request.getParameter(uploadParam)</xsp:expr>
+					</strong>
+	             <br/>
+	             
+	             Parameter <xsp:expr>uploadParam</xsp:expr> is instance of:
+	             <!-- note usage of get() instead of getParameter() -->
+	             <strong>
+	               <xsp:expr>
+	                 request.get(uploadParam).getClass()
+	               </xsp:expr>
+	             </strong>
+	            </p>
+	           </xsp:content>
+           }
+         } else {
+			<xsp:content>
+				<strong>No files uploaded</strong><br/>
+			</xsp:content>         
          }
        </xsp:logic>
 
