You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2008/01/30 12:33:03 UTC

svn commit: r616725 - in /httpcomponents/httpclient/trunk/module-httpmime/src: main/java/org/apache/http/client/mime/ main/java/org/apache/http/client/mime/content/ test/java/org/apache/http/client/mime/

Author: olegk
Date: Wed Jan 30 03:32:57 2008
New Revision: 616725

URL: http://svn.apache.org/viewvc?rev=616725&view=rev
Log:
MIME multipart/form-data: strict (RFC 822, RFC 2045, RFC 2046 compliant) and lenient (browser compatible) modes 

Added:
    httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipartMode.java   (with props)
    httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/RFC822Header.java   (with props)
Modified:
    httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/FormBodyPart.java
    httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipart.java
    httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/MIME.java
    httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/FileBody.java
    httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/InputStreamBody.java
    httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/StringBody.java
    httpcomponents/httpclient/trunk/module-httpmime/src/test/java/org/apache/http/client/mime/TestMultipartForm.java

Modified: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/FormBodyPart.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/FormBodyPart.java?rev=616725&r1=616724&r2=616725&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/FormBodyPart.java (original)
+++ httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/FormBodyPart.java Wed Jan 30 03:32:57 2008
@@ -50,7 +50,7 @@
         }
         this.name = name;
         
-        Header header = new Header();
+        Header header = new RFC822Header();
         setHeader(header);
         setBody(body);
 

Modified: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipart.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipart.java?rev=616725&r1=616724&r2=616725&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipart.java (original)
+++ httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipart.java Wed Jan 30 03:32:57 2008
@@ -1,7 +1,7 @@
 /*
- * $HeadURL:$
- * $Revision:$
- * $Date:$
+ * $HeadURL$
+ * $Revision$
+ * $Date$
  *
  * ====================================================================
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -35,8 +35,10 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
 import java.util.List;
 
+import org.apache.http.protocol.HTTP;
 import org.apache.james.mime4j.field.ContentTypeField;
 import org.apache.james.mime4j.field.Field;
 import org.apache.james.mime4j.message.BodyPart;
@@ -51,38 +53,103 @@
  */
 public class HttpMultipart extends Multipart {
 
+    private HttpMultipartMode mode;
+    
+    public HttpMultipart() {
+        super();
+        this.mode = HttpMultipartMode.STRICT;
+    }
+    
+    public HttpMultipartMode getMode() {
+        return this.mode;
+    }
+
+    public void setMode(final HttpMultipartMode mode) {
+        this.mode = mode;
+    }
+
     @Override
     public void writeTo(OutputStream out) throws IOException {
         Entity e = getParent();
+        
         ContentTypeField cField = (ContentTypeField) e.getHeader().getField(
                 Field.CONTENT_TYPE);
         String boundary = cField.getBoundary();
-        String charset = cField.getCharset();
+        Charset charset = null;
+        
+        switch (this.mode) {
+        case STRICT:
+            charset = MIME.DEFAULT_CHARSET;
+            break;
+        case BROWSER_COMPATIBLE:
+            if (cField.getCharset() != null) {
+                charset = CharsetUtil.getCharset(cField.getCharset());
+            } else {
+                charset = CharsetUtil.getCharset(HTTP.DEFAULT_CONTENT_CHARSET);
+            }
+            break;
+        }
         
         List<?> bodyParts = getBodyParts();
 
         BufferedWriter writer = new BufferedWriter(
-                new OutputStreamWriter(out, CharsetUtil.getCharset(charset)),
+                new OutputStreamWriter(out, charset),
                 8192);
         
-        writer.write(getPreamble());
-        writer.write("\r\n");
+        switch (this.mode) {
+        case STRICT:
+            writer.write(getPreamble());
+            writer.write("\r\n");
+
+            for (int i = 0; i < bodyParts.size(); i++) {
+                writer.write("--");
+                writer.write(boundary);
+                writer.write("\r\n");
+                writer.flush();
+                BodyPart part = (BodyPart) bodyParts.get(i);
+                part.writeTo(out);
+                writer.write("\r\n");
+            }
 
-        for (int i = 0; i < bodyParts.size(); i++) {
             writer.write("--");
             writer.write(boundary);
+            writer.write("--\r\n");
+            writer.write(getEpilogue());
             writer.write("\r\n");
             writer.flush();
-            ((BodyPart) bodyParts.get(i)).writeTo(out);
+            break;
+        case BROWSER_COMPATIBLE:
+
+            // (1) Do not write preamble and epilogue
+            // (2) Only write Content-Disposition 
+            // (3) Use content charset
+            
             writer.write("\r\n");
-        }
 
-        writer.write("--");
-        writer.write(boundary);
-        writer.write("--\r\n");
-        writer.write(getEpilogue());
-        writer.write("\r\n");
-        writer.flush();
+            for (int i = 0; i < bodyParts.size(); i++) {
+                writer.write("--");
+                writer.write(boundary);
+                writer.write("\r\n");
+                writer.flush();
+                BodyPart part = (BodyPart) bodyParts.get(i);
+                
+                Field cd = part.getHeader().getField(MIME.CONTENT_DISPOSITION);
+                writer.write(cd.toString());
+                writer.write("\r\n");
+                writer.write("\r\n");
+                writer.flush();
+                part.getBody().writeTo(out);
+                
+                writer.write("\r\n");
+            }
+
+            writer.write("--");
+            writer.write(boundary);
+            writer.write("--\r\n");
+            writer.write("\r\n");
+            writer.flush();
+            break;
+        }
     }
     
 }

Added: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipartMode.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipartMode.java?rev=616725&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipartMode.java (added)
+++ httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipartMode.java Wed Jan 30 03:32:57 2008
@@ -0,0 +1,39 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  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.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.mime;
+
+public enum HttpMultipartMode {
+    
+    STRICT,
+    BROWSER_COMPATIBLE
+
+}

Propchange: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipartMode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipartMode.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/HttpMultipartMode.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/MIME.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/MIME.java?rev=616725&r1=616724&r2=616725&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/MIME.java (original)
+++ httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/MIME.java Wed Jan 30 03:32:57 2008
@@ -31,7 +31,10 @@
 
 package org.apache.http.client.mime;
 
+import java.nio.charset.Charset;
+
 import org.apache.james.mime4j.field.Field;
+import org.apache.james.mime4j.util.CharsetUtil;
 
 public final class MIME {
 
@@ -41,5 +44,7 @@
  
     public static final String ENC_8BIT              = "8bit";
     public static final String ENC_BINARY            = "binary";
+
+    public static final Charset DEFAULT_CHARSET      = CharsetUtil.getCharset("US-ASCII");
     
 }

Added: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/RFC822Header.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/RFC822Header.java?rev=616725&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/RFC822Header.java (added)
+++ httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/RFC822Header.java Wed Jan 30 03:32:57 2008
@@ -0,0 +1,56 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  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.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.client.mime;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.Iterator;
+
+import org.apache.james.mime4j.message.Header;
+
+class RFC822Header extends Header {
+
+    @Override
+    public void writeTo(final OutputStream out) throws IOException {
+        BufferedWriter writer = new BufferedWriter(
+                new OutputStreamWriter(out, MIME.DEFAULT_CHARSET), 8192);
+        for (Iterator<?> it = getFields().iterator(); it.hasNext();) {
+            writer.write(it.next().toString());
+            writer.write("\r\n");
+        }
+        writer.write("\r\n");
+        writer.flush();
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/RFC822Header.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/RFC822Header.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/RFC822Header.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/FileBody.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/FileBody.java?rev=616725&r1=616724&r2=616725&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/FileBody.java (original)
+++ httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/FileBody.java Wed Jan 30 03:32:57 2008
@@ -35,16 +35,15 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
-import java.io.Reader;
 import java.nio.charset.Charset;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.http.client.mime.MIME;
 import org.apache.james.mime4j.message.AbstractBody;
+import org.apache.james.mime4j.message.BinaryBody;
 
-public class FileBody extends AbstractBody implements ContentBody {
+public class FileBody extends AbstractBody implements BinaryBody, ContentBody {
 
     private final File file;
     
@@ -56,8 +55,8 @@
         this.file = file;
     }
     
-    public Reader getReader() throws IOException {
-        return new InputStreamReader(new FileInputStream(this.file));
+    public InputStream getInputStream() throws IOException {
+        return new FileInputStream(this.file);
     }
 
     public void writeTo(final OutputStream out) throws IOException {

Modified: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/InputStreamBody.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/InputStreamBody.java?rev=616725&r1=616724&r2=616725&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/InputStreamBody.java (original)
+++ httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/InputStreamBody.java Wed Jan 30 03:32:57 2008
@@ -33,16 +33,15 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
-import java.io.Reader;
 import java.nio.charset.Charset;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.http.client.mime.MIME;
 import org.apache.james.mime4j.message.AbstractBody;
+import org.apache.james.mime4j.message.BinaryBody;
 
-public class InputStreamBody extends AbstractBody implements ContentBody {
+public class InputStreamBody extends AbstractBody implements BinaryBody, ContentBody {
 
     private final InputStream in;
     private final String filename;
@@ -56,8 +55,8 @@
         this.filename = filename;
     }
     
-    public Reader getReader() throws IOException {
-        return new InputStreamReader(this.in);
+    public InputStream getInputStream() throws IOException {
+        return this.in;
     }
 
     public void writeTo(final OutputStream out) throws IOException {

Modified: httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/StringBody.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/StringBody.java?rev=616725&r1=616724&r2=616725&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/StringBody.java (original)
+++ httpcomponents/httpclient/trunk/module-httpmime/src/main/java/org/apache/http/client/mime/content/StringBody.java Wed Jan 30 03:32:57 2008
@@ -42,8 +42,9 @@
 import org.apache.commons.io.IOUtils;
 import org.apache.http.client.mime.MIME;
 import org.apache.james.mime4j.message.AbstractBody;
+import org.apache.james.mime4j.message.TextBody;
 
-public class StringBody extends AbstractBody implements ContentBody {
+public class StringBody extends AbstractBody implements TextBody, ContentBody {
 
     private final byte[] content;
     private final Charset charset;

Modified: httpcomponents/httpclient/trunk/module-httpmime/src/test/java/org/apache/http/client/mime/TestMultipartForm.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-httpmime/src/test/java/org/apache/http/client/mime/TestMultipartForm.java?rev=616725&r1=616724&r2=616725&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-httpmime/src/test/java/org/apache/http/client/mime/TestMultipartForm.java (original)
+++ httpcomponents/httpclient/trunk/module-httpmime/src/test/java/org/apache/http/client/mime/TestMultipartForm.java Wed Jan 30 03:32:57 2008
@@ -183,6 +183,7 @@
         message.setHeader(header);
 
         File tmpfile = File.createTempFile("tmp", ".bin");
+        tmpfile.deleteOnExit();
         Writer writer = new FileWriter(tmpfile);
         try {
             writer.append("some random whatever");
@@ -225,6 +226,61 @@
             "\r\n";
         String s = out.toString("US-ASCII");
         assertEquals(expected, s);
+        
+        tmpfile.delete();
+    }
+
+    public void testMultipartFormBrowserCompatible() throws Exception {
+        Message message = new Message();
+        Header header = new Header();
+        header.addField(
+                Field.parse("Content-Type: multipart/form-data; boundary=foo"));
+        message.setHeader(header);
+
+        File tmpfile = File.createTempFile("tmp", ".bin");
+        tmpfile.deleteOnExit();
+        Writer writer = new FileWriter(tmpfile);
+        try {
+            writer.append("some random whatever");
+        } finally {
+            writer.close();
+        }
+        
+        HttpMultipart multipart = new HttpMultipart();
+        multipart.setParent(message);
+        FormBodyPart p1 = new FormBodyPart(
+                "field1",
+                new FileBody(tmpfile));
+        FormBodyPart p2 = new FormBodyPart(
+                "field2",
+                new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
+        
+        multipart.addBodyPart(p1);
+        multipart.addBodyPart(p2);
+        
+        multipart.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
+        
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        multipart.writeTo(out);
+        out.close();
+        
+        String expected = "\r\n" + 
+            "--foo\r\n" +
+            "Content-Disposition: form-data; name=\"field1\"; " +
+                "filename=\"" + tmpfile.getName() + "\"\r\n" +
+            "\r\n" +
+            "some random whatever\r\n" +
+            "--foo\r\n" +
+            "Content-Disposition: form-data; name=\"field2\"; " +
+                "filename=\"file.tmp\"\r\n" +
+            "\r\n" +
+            "some random whatever\r\n" +
+            "--foo--\r\n" +
+            "\r\n";
+        String s = out.toString("US-ASCII");
+        assertEquals(expected, s);
+        
+        tmpfile.delete();
     }
 
 }