Return-Path: Mailing-List: contact commons-httpclient-dev-help@jakarta.apache.org; run by ezmlm Delivered-To: mailing list commons-httpclient-dev@jakarta.apache.org Received: (qmail 1082 invoked from network); 11 Feb 2003 13:51:35 -0000 Received: from tomts21.bellnexxia.net (HELO tomts21-srv.bellnexxia.net) (209.226.175.183) by daedalus.apache.org with SMTP; 11 Feb 2003 13:51:35 -0000 Received: from sympatico.ca ([64.230.109.177]) by tomts21-srv.bellnexxia.net (InterMail vM.5.01.04.19 201-253-122-122-119-20020516) with ESMTP id <20030211135130.FNJF21070.tomts21-srv.bellnexxia.net@sympatico.ca> for ; Tue, 11 Feb 2003 08:51:30 -0500 Message-ID: <3E48FFE2.1000302@sympatico.ca> Date: Tue, 11 Feb 2003 08:51:30 -0500 From: Jeffrey Dever User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 X-Accept-Language: en-ca, en-us, en MIME-Version: 1.0 To: Commons HttpClient Project Subject: Re: [PATCH] MultipartPost revisited (take 1) References: <1044916212.1521.54.camel@kczrh-okt22.corp.bearingpoint.com> <3E486BD6.6050609@sympatico.ca> <1044967052.15380.5.camel@kczrh-okt22.corp.bearingpoint.com> Content-Type: text/plain; charset=KOI8-R; format=flowed Content-Transfer-Encoding: 8bit X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N Yea. Java does not have all the answers to visibility needs. What we really need is a "jar" access level. Perhaps we'll get that in java version 3 ;-) Jandalf. Oleg Kalnichevski wrote: >Jeff, > >Wire, WireLogOutputStream, WireLogInputStream classes need to be >accessible by classes from the following packages: >org.apache.commons.httpclient >org.apache.commons.httpclient.methods >org.apache.commons.httpclient.methods.multipart > >Making wire logging related classes non-public does not seem feasible >with the present package structure. > >Cheers > >Oleg > >On Tue, 2003-02-11 at 04:19, Jeffrey Dever wrote: > > >>I like the refactoring. Only complaint is that the classes are public. >>Package access would be prefered, but this may not be possible. >> >> >>Oleg Kalnichevski wrote: >> >> >> >>>Fixes the following bugs: >>> >>>http://nagoya.apache.org/bugzilla/show_bug.cgi?id=14782 >>> >>>Change log: >>>- MultipartPost related methods clean-up >>>- Part#send(OutputStream out) & long Part#length() are no more final >>>- Content encoding can be specified >>>- FilePart's content type can be specified >>>- FilePart's transfer encoding can be specified >>>- Wire logging improvement >>> >>>While working on multi-part post stuff I have been through many pains >>>debugging modified classes and trying to figure out what exactly gets >>>sent to the server. Currently wire logging can be regarded as >>>inconsistent at best. In those parts where wire logging is implemented I >>>find it not particularly visually appealing. While "scratching my own >>>itch" I have taken liberty of rewriting wire logging. Please comment if >>>you find these changes acceptable. Suggestions on possible improvements >>>are welcome. >>> >>>To be done next: >>> >>>- Fix bug #14036 >>>- Apply new wire logging consistently throughout the HttpClient codebase >>>(provided new wire logging meets your approval) >>> >>> >>>------------------------------------------------------------------------ >>> >>>Index: src/java/org/apache/commons/httpclient/HttpConnection.java >>>=================================================================== >>>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java,v >>>retrieving revision 1.42 >>>diff -u -r1.42 HttpConnection.java >>>--- src/java/org/apache/commons/httpclient/HttpConnection.java 8 Feb 2003 19:22:49 -0000 1.42 >>>+++ src/java/org/apache/commons/httpclient/HttpConnection.java 10 Feb 2003 22:02:08 -0000 >>>@@ -75,6 +75,7 @@ >>>import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; >>>import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; >>>import org.apache.commons.httpclient.util.TimeoutController; >>>+import org.apache.commons.httpclient.util.Wire; >>>import org.apache.commons.logging.Log; >>>import org.apache.commons.logging.LogFactory; >>> >>>@@ -727,9 +728,8 @@ >>> >>> assertOpen(); >>> >>>- if (WIRE_LOG.isDebugEnabled()) { >>>- String dataString = new String(data, offset, length, "ISO-8859-1"); >>>- WIRE_LOG.debug(">> \"" + dataString + "\" [\\r\\n]"); >>>+ if (Wire.enabled()) { >>>+ Wire.output(data, offset, length, HttpConstants.HTTP_ELEMENT_CHARSET); >>> } >>> try { >>> outputStream.write(data, offset, length); >>>@@ -758,9 +758,8 @@ >>> LOG.trace("enter HttpConnection.writeLine(byte[])"); >>> >>> assertOpen(); >>>- if (WIRE_LOG.isDebugEnabled() && (data.length > 0)) { >>>- String dataString = HttpConstants.getContentString(data); >>>- WIRE_LOG.debug(">> \"" + dataString.trim() + "\" [\\r\\n]"); >>>+ if (Wire.enabled()) { >>>+ Wire.output(data, HttpConstants.HTTP_ELEMENT_CHARSET); >>> } >>> try { >>> outputStream.write(data); >>>@@ -786,7 +785,9 @@ >>> throws IOException, IllegalStateException, HttpRecoverableException { >>> LOG.trace("enter HttpConnection.writeLine()"); >>> >>>- WIRE_LOG.debug(">> [\\r\\n]"); >>>+ if (Wire.enabled()) { >>>+ Wire.output(CRLF, HttpConstants.HTTP_ELEMENT_CHARSET); >>>+ } >>> try { >>> outputStream.write(CRLF); >>> } catch (SocketException se) { >>>@@ -871,8 +872,8 @@ >>> buf.append((char) ch); >>> ch = inputStream.read(); >>> } >>>- if (WIRE_LOG.isDebugEnabled()) { >>>- WIRE_LOG.debug("<< \"" + buf.toString() + (ch>0 ? "\" [\\r\\n]" : "")); >>>+ if (Wire.enabled()) { >>>+ Wire.input(HttpConstants.getBytes(buf.toString()), HttpConstants.HTTP_ELEMENT_CHARSET); >>> } >>> return (buf.toString()); >>> } >>>@@ -1059,9 +1060,6 @@ >>> >>> /** Log object for this class. */ >>> private static final Log LOG = LogFactory.getLog(HttpConnection.class); >>>- >>>- /** Log for any wire messages. */ >>>- private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); >>> >>> // ----------------------------------------------------- Instance Variables >>> /** My host. */ >>>Index: src/java/org/apache/commons/httpclient/HttpMethodBase.java >>>=================================================================== >>>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v >>>retrieving revision 1.110 >>>diff -u -r1.110 HttpMethodBase.java >>>--- src/java/org/apache/commons/httpclient/HttpMethodBase.java 8 Feb 2003 19:22:49 -0000 1.110 >>>+++ src/java/org/apache/commons/httpclient/HttpMethodBase.java 10 Feb 2003 22:02:13 -0000 >>>@@ -1752,7 +1752,7 @@ >>> Header transferEncodingHeader = getResponseHeader("Transfer-Encoding"); >>> InputStream is = conn.getResponseInputStream(); >>> if (WIRE_LOG.isDebugEnabled()) { >>>- is = new WireLogInputStream(is); >>>+ is = new WireLogInputStream(is, getResponseCharSet()); >>> } >>> InputStream result = null; >>> // We use Transfer-Encoding if present and ignore Content-Length. >>>Index: src/java/org/apache/commons/httpclient/WireLogInputStream.java >>>=================================================================== >>>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/WireLogInputStream.java,v >>>retrieving revision 1.8 >>>diff -u -r1.8 WireLogInputStream.java >>>--- src/java/org/apache/commons/httpclient/WireLogInputStream.java 31 Jan 2003 00:33:36 -0000 1.8 >>>+++ src/java/org/apache/commons/httpclient/WireLogInputStream.java 10 Feb 2003 22:02:13 -0000 >>>@@ -68,26 +68,38 @@ >>>import java.io.InputStream; >>>import org.apache.commons.logging.Log; >>>import org.apache.commons.logging.LogFactory; >>>+import org.apache.commons.httpclient.util.Wire; >>> >>>/** >>> * Logs all data read to the wire LOG. >>> * >>> * @author Ortwin Gl?�? >>> * @author Mike Bowler >>>+ * @author Oleg Kalnichevski >>> * >>> * @since 2.0 >>> */ >>> >>>class WireLogInputStream extends FilterInputStream { >>>+ >>> /** Log for any wire messages. */ >>> private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); >>> >>>+ /** Content encoding. */ >>>+ private String charset = "US-ASCII"; >>>+ >>>+ /** Original input stream. */ >>>+ private InputStream in; >>> /** >>> * Create an instance that wraps the specified input stream. >>> * @param in The input stream. >>> */ >>>- public WireLogInputStream(InputStream in) { >>>+ public WireLogInputStream(InputStream in, String charset) { >>> super(in); >>>+ if (charset != null) { >>>+ this.charset = charset; >>>+ } >>>+ this.in = in; >>> } >>> >>> /** >>>@@ -95,8 +107,10 @@ >>> * @see java.io.InputStream#read(byte[], int, int) >>> */ >>> public int read(byte[] b, int off, int len) throws IOException { >>>- int l = super.read(b, off, len); >>>- WIRE_LOG.debug("<< " + new String(b, off, len)); >>>+ int l = this.in.read(b, off, len); >>>+ if (l > 0) { >>>+ Wire.input(b, off, len, null); >>>+ } >>> return l; >>> } >>> >>>@@ -105,9 +119,9 @@ >>> * @see java.io.InputStream#read() >>> */ >>> public int read() throws IOException { >>>- int l = super.read(); >>>+ int l = this.in.read(); >>> if (l > 0) { >>>- WIRE_LOG.debug("<< " + (char) l); >>>+ Wire.input(l, null); >>> } >>> return l; >>> } >>>@@ -117,8 +131,10 @@ >>> * @see java.io.InputStream#read(byte[]) >>> */ >>> public int read(byte[] b) throws IOException { >>>- int l = super.read(b); >>>- WIRE_LOG.debug("<< " + HttpConstants.getString(b)); >>>+ int l = this.in.read(b); >>>+ if (l > 0) { >>>+ Wire.input(b, null); >>>+ } >>> return l; >>> } >>>} >>>Index: src/java/org/apache/commons/httpclient/WireLogOutputStream.java >>>=================================================================== >>>RCS file: src/java/org/apache/commons/httpclient/WireLogOutputStream.java >>>diff -N src/java/org/apache/commons/httpclient/WireLogOutputStream.java >>>--- /dev/null 1 Jan 1970 00:00:00 -0000 >>>+++ src/java/org/apache/commons/httpclient/WireLogOutputStream.java 10 Feb 2003 22:02:14 -0000 >>>@@ -0,0 +1,132 @@ >>>+/* >>>+ * ==================================================================== >>>+ * >>>+ * The Apache Software License, Version 1.1 >>>+ * >>>+ * Copyright (c) 1999-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 >>>+ * . >>>+ * >>>+ * [Additional notices, if required by prior licensing conditions] >>>+ * >>>+ */ >>>+ >>>+package org.apache.commons.httpclient; >>>+ >>>+import java.io.FilterOutputStream; >>>+import java.io.IOException; >>>+import java.io.InputStream; >>>+import java.io.OutputStream; >>>+import java.io.ByteArrayInputStream; >>>+import java.io.Reader; >>>+import java.io.InputStreamReader; >>>+import java.io.BufferedReader; >>>+import java.io.UnsupportedEncodingException; >>>+import org.apache.commons.logging.Log; >>>+import org.apache.commons.logging.LogFactory; >>>+import org.apache.commons.httpclient.util.Wire; >>>+ >>>+/** >>>+ * Logs all data written to the wire LOG. >>>+ * >>>+ * @author Oleg Kalnichevski >>>+ * >>>+ * @since 2.0beta1 >>>+ */ >>>+ >>>+public class WireLogOutputStream extends FilterOutputStream { >>>+ >>>+ /** Log for any wire messages. */ >>>+ private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); >>>+ >>>+ /** Content encoding. */ >>>+ private String charset = "US-ASCII"; >>>+ >>>+ /** Original input stream. */ >>>+ private OutputStream out; >>>+ >>>+ /** >>>+ * Create an instance that wraps the specified output stream. >>>+ * @param out The output stream. >>>+ */ >>>+ public WireLogOutputStream(OutputStream out, String charset) { >>>+ super(out); >>>+ if (charset != null) { >>>+ this.charset = charset; >>>+ } >>>+ this.out = out; >>>+ } >>>+ >>>+ /** >>>+ * >>>+ * @see java.io.OutputStream#write(byte[], int, int) >>>+ */ >>>+ public void write(byte[] b, int off, int len) throws IOException { >>>+ this.out.write(b, off, len); >>>+ Wire.output(b, off, len, this.charset); >>>+ } >>>+ >>>+ /** >>>+ * >>>+ * @see java.io.OutputStream#write() >>>+ */ >>>+ public void write(int b) throws IOException { >>>+ this.out.write(b); >>>+ Wire.output(b, this.charset); >>>+ } >>>+ >>>+ /** >>>+ * >>>+ * @see java.io.OutputStream#write(byte[]) >>>+ */ >>>+ public void write(byte[] b) throws IOException { >>>+ this.out.write(b); >>>+ Wire.output(b, this.charset); >>>+ } >>>+} >>>Index: src/java/org/apache/commons/httpclient/methods/MultipartPostMethod.java >>>=================================================================== >>>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/MultipartPostMethod.java,v >>>retrieving revision 1.8 >>>diff -u -r1.8 MultipartPostMethod.java >>>--- src/java/org/apache/commons/httpclient/methods/MultipartPostMethod.java 2 Feb 2003 04:30:13 -0000 1.8 >>>+++ src/java/org/apache/commons/httpclient/methods/MultipartPostMethod.java 10 Feb 2003 22:02:15 -0000 >>>@@ -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); >>> } >>> } >>>} >>>Index: src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java >>>=================================================================== >>>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v >>>retrieving revision 1.10 >>>diff -u -r1.10 FilePart.java >>>--- src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java 28 Jan 2003 22:25:31 -0000 1.10 >>>+++ src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java 10 Feb 2003 22:02:15 -0000 >>>@@ -82,27 +82,84 @@ >>> * @author Michael Becke >>> * @author Mark Diggory >>> * @author Mike Bowler >>>+ * @author Oleg Kalnichevski >>> * >>> * @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); >>> >>>- /** >>>- *

The maximum buffer size.

>>>- * 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 file 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 file 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 >>>Index: src/java/org/apache/commons/httpclient/methods/multipart/Part.java >>>=================================================================== >>>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/Part.java,v >>>retrieving revision 1.7 >>>diff -u -r1.7 Part.java >>>--- src/java/org/apache/commons/httpclient/methods/multipart/Part.java 28 Jan 2003 22:25:31 -0000 1.7 >>>+++ src/java/org/apache/commons/httpclient/methods/multipart/Part.java 10 Feb 2003 22:02:16 -0000 >>>@@ -63,10 +63,13 @@ >>> >>>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.httpclient.WireLogOutputStream; >>>import org.apache.commons.logging.Log; >>>import org.apache.commons.logging.LogFactory; >>> >>>@@ -77,6 +80,7 @@ >>> * @author Jeff Dever >>> * @author Adrian Sutton >>> * @author Mike Bowler >>>+ * @author Oleg Kalnichevski >>> * >>> * @since 2.0 >>> */ >>>@@ -85,26 +89,65 @@ >>> /** Log object for this class. */ >>> private static final Log LOG = LogFactory.getLog(Part.class); >>> >>>+ /** Log for any wire messages. */ >>>+ private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); >>>+ >>> //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 +157,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 +193,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 +257,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. >>>@@ -249,51 +281,60 @@ >>> out.write(CRLF_BYTES); >>> } >>> >>>- /** >>>- * 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. >>>- */ >>>- >>>+/* >>>+ protected static void byteArrayToWire(final byte[] rawdata, final String charset) >>>+ throws IOException { >>>+ Reader reader = null; >>>+ try { >>>+ reader = new InputStreamReader(new ByteArrayInputStream(rawdata), charset); >>>+ } catch (UnsupportedEncodingException e) { >>>+ reader = new InputStreamReader(new ByteArrayInputStream(rawdata)); >>>+ } >>>+ BufferedReader in = new BufferedReader(reader); >>>+ String line; >>>+ while( (line = in.readLine()) != null ) { >>>+ WIRE_LOG.debug(">> \"" + line + "\" [\\r\\n]"); >>>+ } >>>+ } >>>+ */ >>> /** >>> * 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 +345,55 @@ >>> 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"); >>>+ } >>>+ if (WIRE_LOG.isDebugEnabled()) { >>>+ out = new WireLogOutputStream(out, "US-ACSII"); >>>+ } >>>+ 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; >>>+ } >>>} >>>Index: src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java >>>=================================================================== >>>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java,v >>>retrieving revision 1.5 >>>diff -u -r1.5 StringPart.java >>>--- src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java 28 Jan 2003 22:25:31 -0000 1.5 >>>+++ src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java 10 Feb 2003 22:02:17 -0000 >>>@@ -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 Matthew Albright >>> * @author Jeff Dever >>> * @author Mike Bowler >>>+ * @author Oleg Kalnichevski >>> * >>> * @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; >>> } >>>} >>>Index: src/java/org/apache/commons/httpclient/util/Wire.java >>>=================================================================== >>>RCS file: src/java/org/apache/commons/httpclient/util/Wire.java >>>diff -N src/java/org/apache/commons/httpclient/util/Wire.java >>>--- /dev/null 1 Jan 1970 00:00:00 -0000 >>>+++ src/java/org/apache/commons/httpclient/util/Wire.java 10 Feb 2003 22:02:14 -0000 >>>@@ -0,0 +1,167 @@ >>>+/* >>>+ * ==================================================================== >>>+ * >>>+ * The Apache Software License, Version 1.1 >>>+ * >>>+ * Copyright (c) 1999-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 >>>+ * . >>>+ * >>>+ * [Additional notices, if required by prior licensing conditions] >>>+ * >>>+ */ >>>+ >>>+package org.apache.commons.httpclient.util; >>>+ >>>+import java.io.IOException; >>>+import java.io.InputStream; >>>+import java.io.ByteArrayInputStream; >>>+import java.io.Reader; >>>+import java.io.InputStreamReader; >>>+import java.io.BufferedReader; >>>+import java.io.UnsupportedEncodingException; >>>+import org.apache.commons.logging.Log; >>>+import org.apache.commons.logging.LogFactory; >>>+ >>>+/** >>>+ * Logs data to the wire LOG. >>>+ * >>>+ * @author Oleg Kalnichevski >>>+ * >>>+ * @since 2.0beta1 >>>+ */ >>>+ >>>+public class Wire { >>>+ >>>+ /** Log for any wire messages. */ >>>+ private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); >>>+ >>>+ private static void wire(String header, InputStream instream, String charset) >>>+ throws IOException { >>>+ if (charset == null) { >>>+ charset = "US-ASCII"; >>>+ } >>>+ Reader reader = null; >>>+ try { >>>+ reader = new InputStreamReader(instream, charset); >>>+ } catch (UnsupportedEncodingException e) { >>>+ reader = new InputStreamReader(instream); >>>+ } >>>+ StringBuffer buffer = new StringBuffer(); >>>+ int ch; >>>+ while ((ch = reader.read()) != -1) { >>>+ if (ch == 13) { >>>+ buffer.append("[\\r]"); >>>+ } else if (ch == 10){ >>>+ buffer.append("[\\n]\""); >>>+ buffer.insert(0, "\""); >>>+ buffer.insert(0, header); >>>+ WIRE_LOG.debug(buffer.toString()); >>>+ buffer.setLength(0); >>>+ } else if ((ch < 32) || (ch > 127)) { >>>+ buffer.append("[0x"); >>>+ buffer.append(Integer.toHexString(ch)); >>>+ buffer.append("]"); >>>+ } else { >>>+ buffer.append((char)ch); >>>+ } >>>+ } >>>+ if (buffer.length() > 0) { >>>+ buffer.append("\""); >>>+ buffer.insert(0, "\""); >>>+ buffer.insert(0, header); >>>+ WIRE_LOG.debug(buffer.toString()); >>>+ } >>>+ } >>>+ >>>+ >>>+ public static final boolean enabled() { >>>+ return WIRE_LOG.isDebugEnabled(); >>>+ } >>>+ >>>+ public static final void output(InputStream instream, String charset) >>>+ throws IOException { >>>+ wire(">> ", instream, charset); >>>+ } >>>+ >>>+ public static final void input(InputStream instream, String charset) >>>+ throws IOException { >>>+ wire("<< ", instream, charset); >>>+ } >>>+ >>>+ public static final void output(byte[] b, int off, int len, String charset) >>>+ throws IOException { >>>+ wire(">> ", new ByteArrayInputStream(b, off, len), charset); >>>+ } >>>+ >>>+ public static final void input(byte[] b, int off, int len, String charset) >>>+ throws IOException { >>>+ wire("<< ", new ByteArrayInputStream(b, off, len), charset); >>>+ } >>>+ >>>+ public static final void output(byte[] b, String charset) >>>+ throws IOException { >>>+ wire(">> ", new ByteArrayInputStream(b), charset); >>>+ } >>>+ >>>+ public static final void input(byte[] b, String charset) >>>+ throws IOException { >>>+ wire("<< ", new ByteArrayInputStream(b), charset); >>>+ } >>>+ >>>+ public static final void output(int b, String charset) >>>+ throws IOException { >>>+ output(new byte[] {(byte)b}, charset); >>>+ } >>>+ >>>+ public static final void input(int b, String charset) >>>+ throws IOException { >>>+ input(new byte[] {(byte)b}, charset); >>>+ } >>>+} >>>Index: src/test/org/apache/commons/httpclient/TestWebapp.java >>>=================================================================== >>>RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebapp.java,v >>>retrieving revision 1.6 >>>diff -u -r1.6 TestWebapp.java >>>--- src/test/org/apache/commons/httpclient/TestWebapp.java 1 Feb 2003 16:10:48 -0000 1.6 >>>+++ src/test/org/apache/commons/httpclient/TestWebapp.java 10 Feb 2003 22:02:05 -0000 >>>@@ -1,5 +1,5 @@ >>>/* >>>- * $Header: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebapp.java,v 1.6 2003/02/01 16:10:48 olegk Exp $ >>>+ * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebapp.java,v 1.6 2003/02/01 16:10:48 olegk Exp $ >>> * $Revision: 1.6 $ >>> * $Date: 2003/02/01 16:10:48 $ >>> * ==================================================================== >>>@@ -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; >>> } >>>Index: src/test/org/apache/commons/httpclient/TestWebappMultiPostMethod.java >>>=================================================================== >>>RCS file: src/test/org/apache/commons/httpclient/TestWebappMultiPostMethod.java >>>diff -N src/test/org/apache/commons/httpclient/TestWebappMultiPostMethod.java >>>--- /dev/null 1 Jan 1970 00:00:00 -0000 >>>+++ src/test/org/apache/commons/httpclient/TestWebappMultiPostMethod.java 10 Feb 2003 22:02:06 -0000 >>>@@ -0,0 +1,146 @@ >>>+/* >>>+ * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebappPostMethod.java,v 1.2 2003/02/03 21:21:19 olegk Exp $ >>>+ * $Revision: 1.2 $ >>>+ * $Date: 2003/02/03 21:21:19 $ >>>+ * >>>+ * ==================================================================== >>>+ * >>>+ * 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 >>>+ * . >>>+ * >>>+ * [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 Oleg Kalnichevski >>>+ */ >>>+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-httpclient-dev-unsubscribe@jakarta.apache.org >>>For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org >>> >>> >>> >> >>--------------------------------------------------------------------- >>To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org >>For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org >> >> >> > > >--------------------------------------------------------------------- >To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org >For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org > > > >