hc-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Oleg Kalnichevski <o.kalnichev...@dplanet.ch>
Subject Re: [PATCH] MultipartPost revisited (take 1)
Date Tue, 11 Feb 2003 12:37:33 GMT
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 <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
> >+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
> >  * 
> >  * @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
> >+ * <http://www.apache.org/>.
> >+ *
> >+ * [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 <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
> >+ * 
> >+ * @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 <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
> >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 <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
> >  */
> >@@ -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 <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;
> >     }
> > }
> >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
> >+ * <http://www.apache.org/>.
> >+ *
> >+ * [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 <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
> >+ * 
> >+ * @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
> >+ * <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-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
> 


Mime
View raw message