You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ol...@apache.org on 2003/02/12 13:30:45 UTC
cvs commit: jakarta-commons/httpclient/src/test/org/apache/commons/httpclient TestWebappMultiPostMethod.java TestWebapp.java
olegk 2003/02/12 04:30:44
Modified: httpclient/src/java/org/apache/commons/httpclient/methods
MultipartPostMethod.java
httpclient/src/java/org/apache/commons/httpclient/methods/multipart
FilePart.java Part.java StringPart.java
httpclient/src/test/org/apache/commons/httpclient
TestWebapp.java
Added: httpclient/src/test/org/apache/commons/httpclient
TestWebappMultiPostMethod.java
Log:
Bug fix:
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=14782
Change log:
- MultipartPost clean-up
- Part#send(OutputStream out) & long Part#length() are no longer final
- Custom character set can be specified for all multipart classes
- Custom content type can be specified for FilePart derived multipart classes
Contributed by Oleg Kalnichevski
Revision Changes Path
1.9 +28 -30 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/MultipartPostMethod.java
Index: MultipartPostMethod.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/MultipartPostMethod.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- MultipartPostMethod.java 2 Feb 2003 04:30:13 -0000 1.8
+++ MultipartPostMethod.java 12 Feb 2003 12:30:44 -0000 1.9
@@ -94,6 +94,10 @@
*/
public class MultipartPostMethod extends GetMethod {
+ /** The Content-Type for multipart/form-data. */
+ public static final String MULTIPART_FORM_CONTENT_TYPE =
+ "multipart/form-data";
+
/** Log object for this class. */
private static final Log LOG = LogFactory.getLog(MultipartPostMethod.class);
@@ -204,6 +208,14 @@
}
/**
+ * Return all parts.
+ *
+ * @return an array of containing all parts
+ */
+ public Part[] getParts() {
+ return (Part[])parameters.toArray(new Part[parameters.size()]);
+ }
+ /**
* Add a request header.
*
* @param state the client state
@@ -218,8 +230,12 @@
super.addRequestHeaders(state, conn);
if (!parameters.isEmpty()) {
- setRequestHeader("Content-Type",
- "multipart/form-data; boundary=" + Part.getBoundary());
+ StringBuffer buffer = new StringBuffer(MULTIPART_FORM_CONTENT_TYPE);
+ if (Part.getBoundary() != null) {
+ buffer.append("; boundary=");
+ buffer.append(Part.getBoundary());
+ }
+ setRequestHeader("Content-Type", buffer.toString());
}
}
@@ -237,16 +253,7 @@
throws IOException, HttpException {
LOG.trace("enter writeRequestBody(HttpState state, HttpConnection conn)");
OutputStream out = conn.getRequestOutputStream();
-
- for (Iterator it = parameters.iterator(); it.hasNext();) {
- final Part part = (Part) it.next();
- part.send(out);
- }
-
- Part.sendLastBoundary(out);
-
- out.flush();
-
+ Part.sendParts(out, getParts());
return true;
}
@@ -260,26 +267,17 @@
*/
protected int getRequestContentLength() {
LOG.trace("enter getRequestContentLength()");
- long length = 0;
-
try {
- for (Iterator it = parameters.iterator(); it.hasNext();) {
- final Part part = (Part) it.next();
-
- length += part.length();
+ long len = Part.getLengthOfParts(getParts());
+ // Chop the length to the max int value.
+ if (len <= Integer.MAX_VALUE) {
+ return (int)len;
+ } else {
+ return (Integer.MAX_VALUE);
}
- length += Part.lengthOfLastBoundary();
-
} catch (IOException e) {
// Can't throw an IOException and still override
throw new RuntimeException(e.toString());
- }
-
- // Chop the length to the max int value.
- if (length <= Integer.MAX_VALUE) {
- return ((new Long(length)).intValue());
- } else {
- return (Integer.MAX_VALUE);
}
}
}
1.11 +142 -71 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java
Index: FilePart.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- FilePart.java 28 Jan 2003 22:25:31 -0000 1.10
+++ FilePart.java 12 Feb 2003 12:30:44 -0000 1.11
@@ -82,27 +82,84 @@
* @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
* @author <a href="mailto:mdiggory@latte.harvard.edu">Mark Diggory</a>
* @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
*
* @since 2.0
*
*/
public class FilePart extends Part {
+ /** Default content encoding of file attachments. */
+ public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
+
+ /** Default charset of file attachments. */
+ public static final String DEFAULT_CHARSET = HttpConstants.DEFAULT_CONTENT_CHARSET;
+
+ /** Default transfer encoding of file attachments. */
+ public static final String DEFAULT_TRANSFER_ENCODING = "binary";
+
/** Log object for this class. */
private static final Log LOG = LogFactory.getLog(FilePart.class);
- /**
- * <p>The maximum buffer size.</p>
- * TODO: make this configurable
- */
- private static final int MAX_BUFF_SIZE = 1 * 1024 * 1024; // 1 MiBs
-
+
+ /** Attachment's file name */
+ protected static final String FILE_NAME = "; filename=";
+
+ /** Attachment's file name as a byte array */
+ protected static final byte[] FILE_NAME_BYTES =
+ HttpConstants.getAsciiBytes(FILE_NAME);
+
/** Name of the file part. */
private String name;
/** Source of the file part. */
private PartSource source;
+ /** Content type of the file part. */
+ private String contentType;
+
+ /** Content encoding of the file part. */
+ private String charset;
+
+ /**
+ * FilePart Constructor.
+ *
+ * @param name the name for this part
+ * @param partSource the source for this part
+ * @param contentType the content type for this part
+ * @param charset the charset encoding for this part
+ */
+ public FilePart(String name, PartSource partSource, String contentType, String charset) {
+ LOG.trace("enter FilePart(String, PartSource, String, String)");
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
+ this.name = name;
+ if (partSource == null) {
+ throw new IllegalArgumentException("Source may not be null");
+ }
+ if (partSource.getLength() < 0) {
+ throw new IllegalArgumentException("Source length must be >= 0");
+ }
+ this.source = partSource;
+ if (contentType != null) {
+ this.contentType = contentType;
+ } else {
+ this.contentType = DEFAULT_CONTENT_TYPE;
+ }
+ this.charset = charset;
+ }
+
+ /**
+ * FilePart Constructor.
+ *
+ * @param name the name for this part
+ * @param partSource the source for this part
+ */
+ public FilePart(String name, PartSource partSource) {
+ this(name, partSource, null, null);
+ }
+
/**
* FilePart Constructor.
*
@@ -114,7 +171,23 @@
*/
public FilePart(String name, File file)
throws FileNotFoundException {
- this(name, new FilePartSource(file));
+ this(name, new FilePartSource(file), null, null);
+ }
+
+ /**
+ * FilePart Constructor.
+ *
+ * @param name the name of the file part
+ * @param file the file to post
+ * @param contentType the content type for the file
+ * @param charset the charset encoding of the file
+ *
+ * @throws FileNotFoundException if the <i>file</i> is not a normal
+ * file or if it is not readable.
+ */
+ public FilePart(String name, File file, String contentType, String charset)
+ throws FileNotFoundException {
+ this(name, new FilePartSource(file), contentType, charset);
}
/**
@@ -129,71 +202,77 @@
*/
public FilePart(String name, String fileName, File file)
throws FileNotFoundException {
- this(name, new FilePartSource(fileName, file));
+ this(name, new FilePartSource(fileName, file), null, null);
}
- /**
+ /**
* FilePart Constructor.
*
- * @param name the name for this part
- * @param partSource the source for this part
+ * @param name the name of the file part
+ * @param fileName the file name
+ * @param file the file to post
+ * @param contentType the content type for the file
+ * @param charset the charset encoding of the file
+ *
+ * @throws FileNotFoundException if the <i>file</i> is not a normal
+ * file or if it is not readable.
*/
- public FilePart(String name, PartSource partSource) {
-
- if (partSource.getLength() < 0) {
- throw new IllegalArgumentException("fileLength must be >= 0");
- }
-
- this.name = name;
- this.source = partSource;
-
+ public FilePart(String name, String fileName, File file, String contentType, String charset)
+ throws FileNotFoundException {
+ this(name, new FilePartSource(fileName, file), contentType, charset);
}
-
+
/**
- * Write the header to the output stream
- * @param out The output stream
- * @throws IOException If an IO problem occurs
- * @see org.apache.commons.httpclient.methods.multipart.Part#sendHeader(OutputStream)
+ * Return the name.
+ * @return The name.
+ * @see org.apache.commons.httpclient.methods.multipart.Part#getName()
*/
- protected void sendHeader(OutputStream out)
- throws IOException {
- LOG.trace("enter sendHeader(OutputStream out)");
- super.sendHeader(out);
- sendFilename(out);
- sendContentType(out);
+ public String getName() {
+ return this.name;
}
-
+
/**
- * Write the filename to the output stream
- * @param out The output stream
- * @throws IOException If an IO problem occurs
+ * Return the content type of this part.
+ * @return String The name.
*/
- protected void sendFilename(OutputStream out)
- throws IOException {
- LOG.trace("enter sendFilename(OutputStream out)");
- String filename = "; filename=\"" + source.getFileName() + "\"";
- out.write(HttpConstants.getBytes(filename));
+ public String getContentType() {
+ return this.contentType;
}
/**
- * Write the Content-Type header to the output stream
- * @param out The output stream.
- * @throws IOException If an IO problem occurs
+ * Return the character encoding of this part.
+ * @return String The name.
*/
- protected void sendContentType(OutputStream out)
- throws IOException {
- LOG.trace("enter sendContentType(OutputStream out)");
- out.write(CRLF_BYTES);
- out.write(HttpConstants.getBytes("Content-Type: application/octet-stream"));
- }
+ public String getCharSet() {
+ return this.charset;
+ }
/**
- * Return the name.
- * @return The name.
- * @see org.apache.commons.httpclient.methods.multipart.Part#getName()
+ * Return the transfer encoding of this part.
+ * @return String The name.
*/
- public String getName() {
- return name;
+
+ public String getTransferEncoding() {
+ return DEFAULT_TRANSFER_ENCODING;
+ }
+
+ /**
+ * Write the disposition header to the output stream
+ * @param out The output stream
+ * @throws IOException If an IO problem occurs
+ * @see org.apache.commons.httpclient.methods.multipart.Part#sendHeader(OutputStream)
+ */
+ protected void sendDispositionHeader(OutputStream out)
+ throws IOException {
+ LOG.trace("enter sendDispositionHeader(OutputStream out)");
+ super.sendDispositionHeader(out);
+ String filename = this.source.getFileName();
+ if (filename != null) {
+ out.write(FILE_NAME_BYTES);
+ out.write(QUOTE_BYTES);
+ out.write(HttpConstants.getAsciiBytes(filename));
+ out.write(QUOTE_BYTES);
+ }
}
/**
@@ -204,9 +283,6 @@
*/
protected void sendData(OutputStream out) throws IOException {
LOG.trace("enter sendData(OutputStream out)");
-
- byte[] buff;
-
if (lengthOfData() == 0) {
// this file contains no data, so there is nothing to send.
@@ -214,20 +290,15 @@
// cause an infinite loop when reading.
LOG.debug("No data to send.");
return;
-
- } else if (lengthOfData() > MAX_BUFF_SIZE) {
- buff = new byte[MAX_BUFF_SIZE];
- } else {
- buff = new byte[(new Long(lengthOfData())).intValue()];
}
- InputStream is = source.createInputStream();
+ byte[] tmp = new byte[4096];
+ InputStream instream = source.createInputStream();
int len;
- while ((len = is.read(buff)) != -1) {
- out.write(buff, 0, len);
+ while ((len = instream.read(tmp)) >= 0) {
+ out.write(tmp, 0, len);
}
-
}
/**
@@ -237,8 +308,8 @@
* @see org.apache.commons.httpclient.methods.multipart.Part#lengthOfData()
*/
protected long lengthOfData() throws IOException {
+ LOG.trace("enter lengthOfData()");
return source.getLength();
}
-}
-
+}
\ No newline at end of file
1.8 +173 -104 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/Part.java
Index: Part.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/Part.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- Part.java 28 Jan 2003 22:25:31 -0000 1.7
+++ Part.java 12 Feb 2003 12:30:44 -0000 1.8
@@ -63,9 +63,11 @@
package org.apache.commons.httpclient.methods.multipart;
+import java.io.IOException;
import java.io.OutputStream;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
+
import org.apache.commons.httpclient.HttpConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -77,6 +79,7 @@
* @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
* @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
* @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
*
* @since 2.0
*/
@@ -88,23 +91,59 @@
//TODO: Make this configurable
/** The boundary */
- private static final String BOUNDARY = "----------------314159265358979323846";
+ protected static final String BOUNDARY = "----------------314159265358979323846";
/** The boundary as a byte array */
- private static final byte[] BOUNDARY_BYTES = HttpConstants.getBytes(BOUNDARY);
+ protected static final byte[] BOUNDARY_BYTES = HttpConstants.getAsciiBytes(BOUNDARY);
/** Carriage return/linefeed */
- private static final String CRLF = "\r\n";
+ protected static final String CRLF = "\r\n";
/** Carriage return/linefeed as a byte array */
- protected static final byte[] CRLF_BYTES = HttpConstants.getBytes(CRLF);
+ protected static final byte[] CRLF_BYTES = HttpConstants.getAsciiBytes(CRLF);
+
+ /** Content dispostion characters */
+ protected static final String QUOTE = "\"";
+ /** Content dispostion as a byte array */
+ protected static final byte[] QUOTE_BYTES =
+ HttpConstants.getAsciiBytes(QUOTE);
+
/** Extra characters */
- private static final String EXTRA = "--";
+ protected static final String EXTRA = "--";
/** Extra characters as a byte array */
- private static final byte[] EXTRA_BYTES = HttpConstants.getBytes(EXTRA);
+ protected static final byte[] EXTRA_BYTES =
+ HttpConstants.getAsciiBytes(EXTRA);
+
+ /** Content dispostion characters */
+ protected static final String CONTENT_DISPOSITION = "Content-Disposition: form-data; name=";
+ /** Content dispostion as a byte array */
+ protected static final byte[] CONTENT_DISPOSITION_BYTES =
+ HttpConstants.getAsciiBytes(CONTENT_DISPOSITION);
+
+ /** Content type header */
+ protected static final String CONTENT_TYPE = "Content-Type: ";
+
+ /** Content type header as a byte array */
+ protected static final byte[] CONTENT_TYPE_BYTES =
+ HttpConstants.getAsciiBytes(CONTENT_TYPE);
+
+ /** Content charset */
+ protected static final String CHARSET = "; charset=";
+
+ /** Content charset as a byte array */
+ protected static final byte[] CHARSET_BYTES =
+ HttpConstants.getAsciiBytes(CHARSET);
+
+ /** Content type header */
+ protected static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding: ";
+
+ /** Content type header as a byte array */
+ protected static final byte[] CONTENT_TRANSFER_ENCODING_BYTES =
+ HttpConstants.getAsciiBytes(CONTENT_TRANSFER_ENCODING);
+
/**
* Return the boundary string.
* @return the boundary string
@@ -114,40 +153,29 @@
}
/**
- * Write the last boundary to the specified output stream
- * @param out The output stream
- * @throws IOException If an IO problem occurs.
+ * Return the name of this part.
+ * @return String The name.
*/
- public static void sendLastBoundary(OutputStream out)
- throws IOException {
- LOG.trace("enter sendLastBoundary(OutputStream out)");
- out.write(EXTRA_BYTES);
- out.write(BOUNDARY_BYTES);
- out.write(EXTRA_BYTES);
- out.write(CRLF_BYTES);
- }
+ public abstract String getName();
/**
- * Return the length of the last boundary string
- *
- * @return int The length of the last boundary string
- * @throws IOException If an IO problem occurs
+ * Return the content type of this part.
+ * @return String The name.
*/
- public static int lengthOfLastBoundary() throws IOException {
- LOG.trace("enter lengthOfLastBoundary()");
- ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- sendLastBoundary(out);
-
- return out.size();
- }
-
+ public abstract String getContentType();
+
/**
- * Return the name of this part.
+ * Return the character encoding of this part.
* @return String The name.
*/
- public abstract String getName();
-
+ public abstract String getCharSet();
+
+ /**
+ * Return the transfer encoding of this part.
+ * @return String The name.
+ */
+ public abstract String getTransferEncoding();
+
/**
* Write the start to the specified output stream
* @param out The output stream
@@ -161,44 +189,58 @@
}
/**
- * Return the length of the starting data
- * @return int The length of the data
- * @throws IOException If an IO problem occurs
+ * Write the content disposition header to the specified output stream
+ *
+ * @param out The output stream
+ * @throws IOException If an IO problem occurs.
*/
- protected int lengthOfStart() throws IOException {
- LOG.trace("enter lengthOfStart()");
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- sendStart(out);
- return out.size();
+ protected void sendDispositionHeader(OutputStream out) throws IOException {
+ LOG.trace("enter sendDispositionHeader(OutputStream out)");
+ out.write(CONTENT_DISPOSITION_BYTES);
+ out.write(QUOTE_BYTES);
+ out.write(HttpConstants.getAsciiBytes(getName()));
+ out.write(QUOTE_BYTES);
}
/**
- * Write the header to the specified output stream
+ * Write the content type header to the specified output stream
* @param out The output stream
* @throws IOException If an IO problem occurs.
*/
- protected void sendHeader(OutputStream out) throws IOException {
- LOG.trace("enter sendHeader(OutputStream out)");
- String contentDisposition = "Content-Disposition: form-data; name=\""
- + getName() + "\"";
-
- out.write(HttpConstants.getBytes(contentDisposition));
+
+ protected void sendContentTypeHeader(OutputStream out) throws IOException {
+ LOG.trace("enter sendContentTypeHeader(OutputStream out)");
+ String contentType = getContentType();
+ if (contentType != null) {
+ out.write(CRLF_BYTES);
+ out.write(CONTENT_TYPE_BYTES);
+ out.write(HttpConstants.getAsciiBytes(contentType));
+ String charSet = getCharSet();
+ if (charSet != null) {
+ out.write(CHARSET_BYTES);
+ out.write(HttpConstants.getAsciiBytes(charSet));
+ }
+ }
}
-
+
/**
- * Return the length of the header
+ * Write the content transfer encoding header to the specified
+ * output stream
*
- * @return long The length.
- * @throws IOException If an IO problem occurs
+ * @param out The output stream
+ * @throws IOException If an IO problem occurs.
*/
- protected int lengthOfHeader() throws IOException {
- LOG.trace("enter lengthOfHeader()");
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- sendHeader(out);
- return (out.size());
+
+ protected void sendTransferEncodingHeader(OutputStream out) throws IOException {
+ LOG.trace("enter sendTransferEncodingHeader(OutputStream out)");
+ String transferEncoding = getTransferEncoding();
+ if (transferEncoding != null) {
+ out.write(CRLF_BYTES);
+ out.write(CONTENT_TRANSFER_ENCODING_BYTES);
+ out.write(HttpConstants.getAsciiBytes(transferEncoding));
+ }
}
-
-
+
/**
* Write the end of the header to the output stream
* @param out The output stream
@@ -211,20 +253,6 @@
}
/**
- * Return the length of the end of header
- *
- * @return long The length.
- * @throws IOException If an IO problem occurs
- */
- protected int lengthOfEndOfHeader() throws IOException {
- LOG.trace("enter lengthOfEndOfHeader()");
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- sendEndOfHeader(out);
- return out.size();
- }
-
-
- /**
* Write the data to the specified output stream
* @param out The output stream
* @throws IOException If an IO problem occurs.
@@ -250,50 +278,43 @@
}
/**
- * Return the length of the end data
- *
- * @return long The length.
- * @throws IOException If an IO problem occurs
- */
- protected int lengthOfEnd() throws IOException {
- LOG.trace("enter lengthOfEnd()");
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- sendEnd(out);
- return out.size();
- }
-
- /* The following 2 methods don't need to be final, but they DO need
- * to be overridden as a pair, and the only way to make sure of that
- * is to make sure they AREN'T overridden.
- */
-
- /**
* Write all the data to the output stream.
+ * If you override this method make sure to override
+ * #length() as well
+ *
* @param out The output stream
* @throws IOException If an IO problem occurs.
*/
- public final void send(OutputStream out) throws IOException {
+ public void send(OutputStream out) throws IOException {
LOG.trace("enter send(OutputStream out)");
sendStart(out);
- sendHeader(out);
+ sendDispositionHeader(out);
+ sendContentTypeHeader(out);
+ sendTransferEncodingHeader(out);
sendEndOfHeader(out);
sendData(out);
sendEnd(out);
}
-
+
+
/**
* Return the full length of all the data.
+ * If you override this method make sure to override
+ * #send(OutputStream) as well
*
* @return long The length.
* @throws IOException If an IO problem occurs
*/
- public final long length() throws IOException {
+ public long length() throws IOException {
LOG.trace("enter length()");
- return lengthOfStart()
- + lengthOfHeader()
- + lengthOfEndOfHeader()
- + lengthOfData()
- + lengthOfEnd();
+ ByteArrayOutputStream overhead = new ByteArrayOutputStream();
+ sendStart(overhead);
+ sendDispositionHeader(overhead);
+ sendContentTypeHeader(overhead);
+ sendTransferEncodingHeader(overhead);
+ sendEndOfHeader(overhead);
+ sendEnd(overhead);
+ return overhead.size() + lengthOfData();
}
/**
@@ -304,4 +325,52 @@
public String toString() {
return this.getName();
}
+
+
+ /**
+ * Write all parts and the last boundary to the specified output stream
+ *
+ * @param out The output stream
+ * @param parts The array of parts to be sent
+ *
+ * @throws IOException If an IO problem occurs.
+ */
+ public static void sendParts(OutputStream out, final Part[] parts)
+ throws IOException {
+ LOG.trace("enter sendParts(OutputStream out, Parts[])");
+ if (parts == null) {
+ throw new IllegalArgumentException("Parts may not be null");
+ }
+ for (int i = 0; i < parts.length; i++) {
+ parts[i].send(out);
+ }
+ out.write(EXTRA_BYTES);
+ out.write(BOUNDARY_BYTES);
+ out.write(EXTRA_BYTES);
+ out.write(CRLF_BYTES);
+ }
+
+ /**
+ * Return the total sum of all parts and that of the last boundary
+ *
+ * @param parts The array of parts
+ *
+ * @throws IOException If an IO problem occurs.
+ */
+ public static long getLengthOfParts(final Part[] parts)
+ throws IOException {
+ LOG.trace("getLengthOfParts(Parts[])");
+ if (parts == null) {
+ throw new IllegalArgumentException("Parts may not be null");
+ }
+ long total = 0;
+ for (int i = 0; i < parts.length; i++) {
+ total += parts[i].length();
+ }
+ total += EXTRA_BYTES.length;
+ total += BOUNDARY_BYTES.length;
+ total += EXTRA_BYTES.length;
+ total += CRLF_BYTES.length;
+ return total;
+ }
}
1.6 +79 -13 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java
Index: StringPart.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- StringPart.java 28 Jan 2003 22:25:31 -0000 1.5
+++ StringPart.java 12 Feb 2003 12:30:44 -0000 1.6
@@ -66,6 +66,8 @@
import java.io.OutputStream;
import java.io.IOException;
import org.apache.commons.httpclient.HttpConstants;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* Simple string parameter for a multipart post
@@ -73,26 +75,69 @@
* @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a>
* @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
* @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
*
* @since 2.0
*/
public class StringPart extends Part {
+ /** Log object for this class. */
+ private static final Log LOG = LogFactory.getLog(StringPart.class);
+
+ /** Default content encoding of string parameters. */
+ public static final String DEFAULT_CONTENT_TYPE = "text/plain";
+
+ /** Default charset of string parameters*/
+ public static final String DEFAULT_CHARSET = "US-ASCII";
+
+ /** Default transfer encoding of string parameters*/
+ public static final String DEFAULT_TRANSFER_ENCODING = "8bit";
+
/** Name of this StringPart. */
private String name;
/** Contents of this StringPart. */
- private String value;
+ private byte[] content;
+
+ /** Charset of this StringPart. */
+ private String charset;
/**
* Constructor.
*
* @param name The name of the part
* @param value the string to post
+ * @param charset the charset to be used to encode the string
*/
- public StringPart(String name, String value) {
+ public StringPart(String name, String value, String charset) {
+ LOG.trace("enter StringPart(String, String, String)");
+ if (name == null) {
+ throw new IllegalArgumentException("Name may not be null");
+ }
this.name = name;
- this.value = value;
+ if (charset != null) {
+ this.charset = charset;
+ } else {
+ this.charset = DEFAULT_CHARSET;
+ }
+ if (value == null) {
+ throw new IllegalArgumentException("Value may not be null");
+ }
+ if (value.indexOf(0) != -1) {
+ // See RFC 2048, 2.8. "8bit Data"
+ throw new IllegalArgumentException("NULs may not be present in string parts");
+ }
+ this.content = HttpConstants.getContentBytes(value, this.charset);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name The name of the part
+ * @param value the string to post
+ */
+ public StringPart(String name, String value) {
+ this(name, value, null);
}
/**
@@ -102,15 +147,35 @@
public String getName() {
return name;
}
-
+
/**
- * Write the data to the specified output stream
- * @param out The output stream.
- * @throws IOException If an IO problem occurs
- * @see org.apache.commons.httpclient.methods.multipart.Part#sendData(OutputStream)
+ * Return the content type of this part.
+ * @return String The name.
+ */
+ public String getContentType() {
+ return DEFAULT_CONTENT_TYPE;
+ }
+
+ /**
+ * Return the character encoding of this part.
+ * @return String The name.
*/
+ public String getCharSet() {
+ return this.charset;
+ }
+
+ /**
+ * Return the transfer encoding of this part.
+ * @return String The name.
+ */
+
+ public String getTransferEncoding() {
+ return DEFAULT_TRANSFER_ENCODING;
+ }
+
protected void sendData(OutputStream out) throws IOException {
- out.write(HttpConstants.getBytes(value));
+ LOG.trace("enter sendData(OutputStream)");
+ out.write(this.content);
}
/**
@@ -120,6 +185,7 @@
* @see org.apache.commons.httpclient.methods.multipart.Part#lengthOfData()
*/
protected long lengthOfData() throws IOException {
- return HttpConstants.getBytes(value).length;
+ LOG.trace("enter lengthOfData()");
+ return this.content.length;
}
}
1.7 +5 -4 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebapp.java
Index: TestWebapp.java
===================================================================
RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebapp.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- TestWebapp.java 1 Feb 2003 16:10:48 -0000 1.6
+++ TestWebapp.java 12 Feb 2003 12:30:44 -0000 1.7
@@ -100,6 +100,7 @@
suite.addTest(TestWebappBasicAuth.suite());
suite.addTest(TestWebappCookie.suite());
suite.addTest(TestWebappPostMethod.suite());
+ suite.addTest(TestWebappMultiPostMethod.suite());
suite.addTest(TestWebappNoncompliant.suite());
return suite;
}
1.1 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebappMultiPostMethod.java
Index: TestWebappMultiPostMethod.java
===================================================================
/*
* $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebappMultiPostMethod.java,v 1.1 2003/02/12 12:30:44 olegk Exp $
* $Revision: 1.1 $
* $Date: 2003/02/12 12:30:44 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* 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/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.commons.httpclient;
import junit.framework.*;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.methods.multipart.*;
import java.io.*;
/**
* Webapp tests specific to the MultiPostMethod.
*
* @author <a href="oleg@ural.ru">Oleg Kalnichevski</a>
*/
public class TestWebappMultiPostMethod extends TestWebappBase {
HttpClient httpClient;
final static String paramsUrl = "http://" + host + ":" + port
+ "/" + context + "/params";
final static String bodyUrl = "http://" + host + ":" + port
+ "/" + context + "/body";
public TestWebappMultiPostMethod(String testName) {
super(testName);
}
public static Test suite() {
TestSuite suite = new TestSuite(TestWebappMultiPostMethod.class);
return suite;
}
public static void main(String args[]) {
String[] testCaseName = { TestWebappMultiPostMethod.class.getName() };
junit.textui.TestRunner.main(testCaseName);
}
public void setUp() {
httpClient = new HttpClient();
}
// ------------------------------------------------------------------ Tests
/**
* Test that the body consisting of a string part can be posted.
*/
public void testPostStringPart() throws Exception {
MultipartPostMethod method = new MultipartPostMethod(bodyUrl);
method.addPart(new StringPart("param", "Hello", "ISO-8859-1"));
httpClient.executeMethod(method);
assertEquals(200,method.getStatusCode());
String body = method.getResponseBodyAsString();
assertTrue(body.indexOf("Content-Disposition: form-data; name=\"param\"") >= 0);
assertTrue(body.indexOf("Content-Type: text/plain; charset=ISO-8859-1") >= 0);
assertTrue(body.indexOf("Content-Transfer-Encoding: 8bit") >= 0);
assertTrue(body.indexOf("Hello") >= 0);
}
/**
* Test that the body consisting of a file part can be posted.
*/
public void testPostFilePart() throws Exception {
MultipartPostMethod method = new MultipartPostMethod(bodyUrl);
byte[] content = new byte[] {'H', 'e', 'l', 'l', 'o' };
method.addPart(
new FilePart(
"param1",
new ByteArrayPartSource("filename.txt", content),
"text/plain",
"ISO-8859-1"));
httpClient.executeMethod(method);
assertEquals(200,method.getStatusCode());
String body = method.getResponseBodyAsString();
assertTrue(body.indexOf("Content-Disposition: form-data; name=\"param1\"; filename=\"filename.txt\"") >= 0);
assertTrue(body.indexOf("Content-Type: text/plain; charset=ISO-8859-1") >= 0);
assertTrue(body.indexOf("Content-Transfer-Encoding: binary") >= 0);
assertTrue(body.indexOf("Hello") >= 0);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org