Return-Path: Delivered-To: apmail-hc-commits-archive@www.apache.org Received: (qmail 28908 invoked from network); 30 Jan 2008 11:33:41 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 30 Jan 2008 11:33:41 -0000 Received: (qmail 33383 invoked by uid 500); 30 Jan 2008 11:33:32 -0000 Delivered-To: apmail-hc-commits-archive@hc.apache.org Received: (qmail 33359 invoked by uid 500); 30 Jan 2008 11:33:32 -0000 Mailing-List: contact commits-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list commits@hc.apache.org Received: (qmail 33350 invoked by uid 99); 30 Jan 2008 11:33:32 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 30 Jan 2008 03:33:32 -0800 X-ASF-Spam-Status: No, hits=-100.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 30 Jan 2008 11:33:13 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id CC2FF1A9832; Wed, 30 Jan 2008 03:33:04 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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/ Date: Wed, 30 Jan 2008 11:33:03 -0000 To: commits@hc.apache.org From: olegk@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080130113304.CC2FF1A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 + * . + * + */ + +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 + * . + * + */ + +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(); } }