You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by jo...@apache.org on 2008/03/18 05:42:13 UTC

svn commit: r638212 - in /cocoon/branches/BRANCH_2_1_X: src/java/org/apache/cocoon/servlet/multipart/MultipartParser.java src/java/org/apache/cocoon/servlet/multipart/Part.java src/java/org/apache/cocoon/servlet/multipart/PartInMemory.java status.xml

Author: joerg
Date: Mon Mar 17 21:42:08 2008
New Revision: 638212

URL: http://svn.apache.org/viewvc?rev=638212&view=rev
Log:
Close streams properly after copying Parts (MultipartParser). Allow to access InputStream of PartInMemory multiple times.

Modified:
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/MultipartParser.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/Part.java
    cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/PartInMemory.java
    cocoon/branches/BRANCH_2_1_X/status.xml

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/MultipartParser.java
URL: http://svn.apache.org/viewvc/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/MultipartParser.java?rev=638212&r1=638211&r2=638212&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/MultipartParser.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/MultipartParser.java Mon Mar 17 21:42:08 2008
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,7 +17,6 @@
 package org.apache.cocoon.servlet.multipart;
 
 import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -53,7 +52,7 @@
     private final static int FILE_BUFFER_SIZE = 4096;
 
     private static final int MAX_BOUNDARY_SIZE = 128;
-    
+
     private boolean saveUploadedFilesToDisk;
 
     private File uploadDirectory = null;
@@ -61,23 +60,23 @@
     private boolean allowOverwrite;
 
     private boolean silentlyRename;
-    
+
     private int maxUploadSize;
 
     private String characterEncoding;
-    
+
     private Hashtable parts;
-    
+
     private boolean oversized = false;
-    
+
     private int contentLength;
-    
+
     private HttpSession session;
-    
+
     private boolean hasSession;
-    
+
     private Hashtable uploadStatus;
-    
+
     /**
      * Constructor, parses given request
      *
@@ -116,19 +115,18 @@
         TokenStream stream = new TokenStream(pushbackStream);
 
         parseMultiPart(stream, getBoundary(contentType));
-
     }
-    
+
     public Hashtable getParts(int contentLength, String contentType, InputStream requestStream)
     throws IOException, MultipartException {
         this.parts = new Hashtable();
         parseParts(contentLength, contentType, requestStream);
         return this.parts;
     }
-    
+
     public Hashtable getParts(HttpServletRequest request) throws IOException, MultipartException {
         this.parts = new Hashtable();
-        
+
         // Copy all parameters coming from the request URI to the parts table.
         // This happens when a form's action attribute has some parameters
         Enumeration names = request.getParameterNames();
@@ -151,21 +149,21 @@
             this.uploadStatus.put("finished", Boolean.FALSE);
             this.uploadStatus.put("sent", new Integer(0));
             this.uploadStatus.put("total", new Integer(request.getContentLength()));
-            this.uploadStatus.put("filename",  "");
+            this.uploadStatus.put("filename", "");
             this.uploadStatus.put("error", Boolean.FALSE);
             this.uploadStatus.put("uploadsdone", new Integer(0));
             this.session.setAttribute(UPLOAD_STATUS_SESSION_ATTR, this.uploadStatus);
         }
 
-        parseParts(request.getContentLength(), request.getContentType(), request.getInputStream());    
+        parseParts(request.getContentLength(), request.getContentType(), request.getInputStream());
 
         if (this.hasSession) {
             this.uploadStatus.put("finished", Boolean.TRUE);
         }
 
-        return this.parts;    
+        return this.parts;
     }
-    
+
     /**
      * Parse a multipart block
      *
@@ -214,7 +212,7 @@
                     // empty upload fields. Just parse away the part
                     byte[] buf = new byte[32];
                     while(ts.getState() == TokenStream.STATE_READING)
-                        ts.read(buf);  
+                        ts.read(buf);
                 }
             } else if (((String) headers.get("content-disposition"))
                     .toLowerCase().equals("form-data")) {
@@ -283,30 +281,31 @@
 
             out = new FileOutputStream(file);
         }
-        
+
         if (hasSession) { // upload widget support
             this.uploadStatus.put("finished", Boolean.FALSE);
             this.uploadStatus.put("started", Boolean.TRUE);
             this.uploadStatus.put("widget", headers.get("name"));
             this.uploadStatus.put("filename", headers.get("filename"));
         }
-        
+
         int length = 0; // Track length for OversizedPart
         try {
             int read = 0;
-            while (in.getState() == TokenStream.STATE_READING) {    // read data
+            while (in.getState() == TokenStream.STATE_READING) {
+                // read data
                 read = in.read(buf);
                 length += read;
                 out.write(buf, 0, read);
-                
+
                 if (this.hasSession) {
-                    this.uploadStatus.put("sent", 
+                    this.uploadStatus.put("sent",
                         new Integer(((Integer)this.uploadStatus.get("sent")).intValue() + read)
                     );
                 }
             }
             if (this.hasSession) { // upload widget support
-                this.uploadStatus.put("uploadsdone", 
+                this.uploadStatus.put("uploadsdone",
                     new Integer(((Integer)this.uploadStatus.get("uploadsdone")).intValue() + 1)
                 );
                 this.uploadStatus.put("error", Boolean.FALSE);
@@ -324,13 +323,13 @@
         } finally {
             if ( out!=null ) out.close();
         }
-        
+
         String name = (String)headers.get("name");
         if (oversized) {
             this.parts.put(name, new RejectedPart(headers, length, this.contentLength, this.maxUploadSize));
         } else if (file == null) {
             byte[] bytes = ((ByteArrayOutputStream) out).toByteArray();
-            this.parts.put(name, new PartInMemory(headers, new ByteArrayInputStream(bytes), bytes.length));
+            this.parts.put(name, new PartInMemory(headers, bytes));
         } else {
             this.parts.put(name, new PartOnDisk(headers, file));
         }
@@ -347,14 +346,14 @@
     private void parseInlinePart(TokenStream in, Hashtable headers)
             throws IOException {
 
-		// Buffer incoming bytes for proper string decoding (there can be multibyte chars)
+        // Buffer incoming bytes for proper string decoding (there can be multibyte chars)
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 
         while (in.getState() == TokenStream.STATE_READING) {
-        	int c = in.read();
-        	if (c != -1) bos.write(c);
+            int c = in.read();
+            if (c != -1) bos.write(c);
         }
-        
+
         String field = (String) headers.get("name");
         Vector v = (Vector) this.parts.get(field);
 
@@ -384,9 +383,9 @@
             headers.put(tokenizer.nextToken(" :").toLowerCase(),
                     tokenizer.nextToken(" :;"));
 
-	        // The extra tokenizer.hasMoreTokens() in headers.put
-	        // handles the filename="" case IE6 submits for an empty
-	        // upload field.
+            // The extra tokenizer.hasMoreTokens() in headers.put
+            // handles the filename="" case IE6 submits for an empty
+            // upload field.
             while (tokenizer.hasMoreTokens()) {
                 headers.put(tokenizer.nextToken(" ;=\""),
                         tokenizer.hasMoreTokens()?tokenizer.nextToken("=\""):"");
@@ -400,17 +399,14 @@
 
     /**
      * Get boundary from contentheader
-     *
-     * @param hdr
      */
     private String getBoundary(String hdr) {
 
         int start = hdr.toLowerCase().indexOf("boundary=");
         if (start > -1) {
             return "--" + hdr.substring(start + 9);
-        } else {
-            return null;
         }
+        return null;
     }
 
     /**
@@ -421,9 +417,9 @@
      * @throws IOException
      */
     private String readln(TokenStream in) throws IOException {
-    	
-    	ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    	
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
         int b = in.read();
 
         while ((b != -1) && (b != '\r')) {
@@ -437,4 +433,5 @@
 
         return new String(bos.toByteArray(), this.characterEncoding);
     }
+
 }

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/Part.java
URL: http://svn.apache.org/viewvc/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/Part.java?rev=638212&r1=638211&r2=638212&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/Part.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/Part.java Mon Mar 17 21:42:08 2008
@@ -125,10 +125,16 @@
      */
     public void copyToSource(ModifiableSource source) throws IOException {
         InputStream is = getInputStream();
-        OutputStream os = source.getOutputStream();
-        IOUtils.copy(is, os);
-        is.close();
-        os.close();
+        try {
+            OutputStream os = source.getOutputStream();
+            try {
+                IOUtils.copy(is, os);
+            } finally {
+                os.close();
+            }
+        } finally {
+            is.close();
+        }
     }
     
     /**
@@ -140,10 +146,16 @@
      */
     public void copyToFile(String filename) throws IOException {
         InputStream is = getInputStream();
-        OutputStream os = new FileOutputStream(filename);
-        IOUtils.copy(is, os);
-        is.close();
-        os.close();
+        try {
+            OutputStream os = new FileOutputStream(filename);
+            try {
+                IOUtils.copy(is, os);
+            } finally {
+                os.close();
+            }
+        } finally {
+            is.close();
+        }
     }
     
     /**

Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/PartInMemory.java
URL: http://svn.apache.org/viewvc/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/PartInMemory.java?rev=638212&r1=638211&r2=638212&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/PartInMemory.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/servlet/multipart/PartInMemory.java Mon Mar 17 21:42:08 2008
@@ -16,6 +16,7 @@
  */
 package org.apache.cocoon.servlet.multipart;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Map;
@@ -28,21 +29,16 @@
  */
 public class PartInMemory extends Part {
 
-    private InputStream in;
-
+    private byte[] bytes;
     private int size;
 
     /**
      * Constructor PartInMemory
-     *
-     * @param headers
-     * @param in
-     * @param size
      */
-    public PartInMemory(Map headers, InputStream in, int size) {
+    public PartInMemory(Map headers, byte[] bytes) {
         super(headers);
-        this.in = in;
-        this.size = size;
+        this.bytes = bytes;
+        this.size = bytes.length;
     }
 
     /**
@@ -65,17 +61,18 @@
      * @throws IOException
      */
     public InputStream getInputStream() throws IOException {
-        if (this.in != null) {
-            return this.in;
+        if (this.bytes != null) {
+            return new ByteArrayInputStream(this.bytes);
         } else {
             throw new IllegalStateException("This part has already been disposed.");
         }
     }
-    
+
     /**
      * Clean the byte array content buffer holding part data
      */
     public void dispose() {
-        this.in = null;
+        this.bytes = null;
     }
+
 }

Modified: cocoon/branches/BRANCH_2_1_X/status.xml
URL: http://svn.apache.org/viewvc/cocoon/branches/BRANCH_2_1_X/status.xml?rev=638212&r1=638211&r2=638212&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/status.xml (original)
+++ cocoon/branches/BRANCH_2_1_X/status.xml Mon Mar 17 21:42:08 2008
@@ -182,6 +182,10 @@
 
   <changes>
   <release version="2.1.12" date="TBD">
+    <action dev="JH" type="fix">
+      Core: Close streams properly after copying Parts (MultipartParser). Allow to access InputStream of PartInMemory
+      multiple times. 
+    </action>
     <action dev="CZ" type="fix">
       Portal: Remove user management tools.
     </action>