You are viewing a plain text version of this content. The canonical link for it is here.
Posted to soap-dev@xml.apache.org by Pavel Ausianik <Pa...@epam.com> on 2002/11/12 16:53:59 UTC

RE: cvs commit: xml-soap/java/src/org/apache/soap/transport/http SOAPHTTPConnection.java

Scott,

i don't know if this makes sence, but logic little bit strange, in case
contentLength=0. See buffer has been created, but as I can see it is not
used anymore since the following block finishes at the end. Should be there
condition to go inside and read from buffer?

        bytes = new byte[contentLength >= 0 ? contentLength : 4096];
        if (contentLength != 0) {

Pavel

> -----Original Message-----
> From: snichol@apache.org [mailto:snichol@apache.org]
> Sent: Tuesday, November 12, 2002 4:16 PM
> To: xml-soap-cvs@apache.org
> Subject: cvs commit: xml-soap/java/src/org/apache/soap/transport/http
> SOAPHTTPConnection.java
> 
> 
> snichol     2002/11/12 06:15:38
> 
>   Modified:    java/src/org/apache/soap/util/net HTTPUtils.java
>                java/src/org/apache/soap/transport 
> TransportMessage.java
>                java/src/org/apache/soap/transport/http
>                         SOAPHTTPConnection.java
>   Log:
>   Reduce the number of times a response is copied in part or in whole.
>   Improve error reporting during response parsing.
>   Support services that shutdown the write half of the socket 
> rather than
>   provide a Content-Length header.
>   Add getEnvelope to SOAPHTTPConnection.  (The method will 
> also be added
>   to SOAPTransport soon.)
>   
>   Revision  Changes    Path
>   1.36      +104 -82   
> xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java
>   
>   Index: HTTPUtils.java
>   ===================================================================
>   RCS file: 
> /home/cvs/xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java,v
>   retrieving revision 1.35
>   retrieving revision 1.36
>   diff -u -r1.35 -r1.36
>   --- HTTPUtils.java	18 Oct 2002 20:30:54 -0000	1.35
>   +++ HTTPUtils.java	12 Nov 2002 14:15:38 -0000	1.36
>   @@ -57,21 +57,30 @@
>    
>    package org.apache.soap.util.net;
>    
>   -import java.io.*;
>   -import java.lang.reflect.*;
>   -import java.net.*;
>   -import java.util.*;
>   -
>   -import javax.mail.*;
>   -import javax.mail.internet.*;
>   -import javax.activation.*;
>   +import java.io.BufferedInputStream;
>   +import java.io.BufferedOutputStream;
>   +import java.io.BufferedReader;
>   +import java.io.InputStream;
>   +import java.io.IOException;
>   +import java.io.OutputStream;
>   +import java.io.UnsupportedEncodingException;
>   +import java.lang.reflect.InvocationTargetException;
>   +import java.lang.reflect.Method;
>   +import java.net.HttpURLConnection;
>   +import java.net.Socket;
>   +import java.net.URL;
>   +import java.util.Enumeration;
>   +import java.util.Hashtable;
>   +import java.util.StringTokenizer;
>    
>   -import org.apache.soap.*;
>   +import javax.mail.MessagingException;
>   +
>   +import org.apache.soap.Constants;
>   +import org.apache.soap.SOAPException;
>    import org.apache.soap.encoding.soapenc.Base64;
>   -import org.apache.soap.rpc.*;
>   -import org.apache.soap.transport.*;
>   +import org.apache.soap.rpc.SOAPContext;
>   +import org.apache.soap.transport.TransportMessage;
>    import org.apache.soap.util.MutableBoolean;
>   -import org.apache.soap.util.mime.*;
>    
>    /**
>     * A bunch of utility stuff for doing HTTP things.
>   @@ -91,6 +100,7 @@
>      private static final String HTTP_VERSION = "1.0";
>      private static final int    HTTP_DEFAULT_PORT = 80;
>      private static final int    HTTPS_DEFAULT_PORT = 443;
>   +  private static final String ISO_8859_1 = "8859_1";
>    
>      public  static final int    DEFAULT_OUTPUT_BUFFER_SIZE = 
> 8 * 1024;
>    
>   @@ -100,7 +110,7 @@
>      public static String encodeAuth(String userName, String password)
>          throws SOAPException {
>        try {
>   -      return Base64.encode((userName + ":" + 
> password).getBytes("8859_1"));
>   +      return Base64.encode((userName + ":" + 
> password).getBytes(ISO_8859_1));
>        } catch (UnsupportedEncodingException e) {
>          throw new SOAPException 
> (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
>        }
>   @@ -482,65 +492,93 @@
>          bOutStream.flush();
>    
>          BufferedInputStream bInStream = new 
> BufferedInputStream(inStream);
>   +      byte[] linebuf = new byte[1024];
>   +      int count = 0;
>   +      int b;
>   +
>          /* Read the response status line. */
>   +      String versionString = null;
>          int statusCode = 0;
>          String statusString = null;
>   -      StringBuffer linebuf = new StringBuffer(128);
>   -      int b = 0;
>   -      while (b != '\n' && b != -1) {
>   -          b = bInStream.read();
>   -          if (b != '\n' && b != '\r' && b != -1)
>   -              linebuf.append((char)b);
>   -      }
>   -      String line = linebuf.toString();
>   +
>          try {
>   -          StringTokenizer st = new StringTokenizer(line);
>   -          st.nextToken(); // ignore version part
>   -          statusCode = Integer.parseInt (st.nextToken());
>   -          StringBuffer sb = new StringBuffer(128);
>   -          while (st.hasMoreTokens()) {
>   -              sb.append (st.nextToken());
>   -              if (st.hasMoreTokens()) {
>   -                  sb.append(" ");
>   +          int versionEnd = -1;
>   +          int codeStart = -1;
>   +          int codeEnd = -1;
>   +          int stringStart = -1;
>   +    
>   +          for (count = 0, b = bInStream.read(); b != '\n' 
> && b != -1; b = bInStream.read()) {
>   +              if (b != '\r') {
>   +              	  if (b == ' ') {
>   +              	      if (versionEnd == -1) {
>   +              	          versionEnd = count;
>   +              	      } else if (codeStart != -1 && 
> codeEnd == -1) {
>   +              	          codeEnd = count;
>   +              	      }
>   +              	  } else {
>   +              	      if (versionEnd != -1 && codeStart == -1) {
>   +              	          codeStart = count;
>   +              	      } else if (codeEnd != -1 && 
> stringStart == -1) {
>   +              	          stringStart = count;
>   +              	      }
>   +              	  }
>   +                  if (count >= linebuf.length) {
>   +                      byte[] newbuf = new byte[linebuf.length * 2];
>   +                      System.arraycopy(linebuf, 0, newbuf, 
> 0, linebuf.length);
>   +                      linebuf = newbuf;
>   +                  }
>   +                  linebuf[count++] = (byte) b;
>                  }
>              }
>   -          statusString = sb.toString();
>   -      }
>   -      catch (Exception e) {
>   +          if (b == -1)
>   +              throw new Exception("Reached end of stream 
> while reading HTTP response status");
>   +          versionString = new String(linebuf, 0, 
> versionEnd, ISO_8859_1);
>   +          statusCode = Integer.parseInt(new 
> String(linebuf, codeStart, codeEnd - codeStart, ISO_8859_1));
>   +          statusString = new String(linebuf, stringStart, 
> count - stringStart, ISO_8859_1);
>   +      } catch (Exception e) {
>              throw new SOAPException(Constants.FAULT_CODE_CLIENT,
>   -              "Error parsing HTTP status line \"" + line + 
> "\": " + e, e);
>   +              "Error parsing HTTP status line \"" + new 
> String(linebuf, 0, count, ISO_8859_1) + "\": " + e, e);
>          }
>    
>   -      /* Read the entire response (following the status line)
>   -       * into a byte array. */
>   -      ByteArrayDataSource ds = new ByteArrayDataSource(bInStream,
>   -                          Constants.HEADERVAL_DEFAULT_CHARSET);
>   -
>   -      /* Extract the headers, content type and content length. */
>   -      byte[] bytes = ds.toByteArray();
>   +      /* Read the HTTP headers. */
>          Hashtable respHeaders = new Hashtable();
>          int respContentLength = -1;
>          String respContentType = null;
>    
>   -      int nameStart = 0;
>   -      int nameEnd = 0;
>   -      int valStart = 0;
>   -      boolean parsingName = true;
>   -      int offset;
>   -
>   -      for (offset = 0; offset < bytes.length; offset++) {
>   -          if (bytes[offset] == '\n') {
>   -              if (nameStart >= nameEnd)
>   +      try {
>   +          // Read all headers
>   +          for (;;) {
>   +              // Read and parse one header
>   +              int nameEnd = -1;
>   +              int valStart = -1;
>   +              for (count = 0, b = bInStream.read(); b != 
> '\n' && b != -1; b = bInStream.read()) {
>   +                  if (b != '\r') {
>   +                      if (nameEnd == -1 && b == ':') {
>   +                          nameEnd = count;
>   +                      } else if (nameEnd != -1 && valStart 
> == -1 && b != ' ' & b != '\t') {
>   +                          valStart = count;
>   +                      }
>   +                      if (count >= linebuf.length) {
>   +                          byte[] newbuf = new 
> byte[linebuf.length * 2];
>   +                          System.arraycopy(linebuf, 0, 
> newbuf, 0, linebuf.length);
>   +                          linebuf = newbuf;
>   +                      }
>   +                      linebuf[count++] = (byte) b;
>   +                  }
>   +              }
>   +              if (b == -1)
>   +                  throw new Exception("Reached end of 
> stream while reading HTTP response header");
>   +              if (count == 0)   // Read the header/entity separator
>                      break;
>   -              String name = new String(bytes, nameStart, 
> nameEnd-nameStart+1);
>   -
>   -              // Remove trailing ; to prevent ContextType 
> from throwing exception
>   -              int valueLen = offset - valStart -1;
>   +              if (nameEnd == -1 || valStart == -1)
>   +                  throw new Exception("Incorrectly formed 
> HTTP response header");
>    
>   -              if (valueLen > 0 && bytes[offset-1] == ';')
>   -                  valueLen--;
>   +              String name = new String(linebuf, 0, 
> nameEnd, ISO_8859_1);
>   +              // Remove trailing ; to prevent ContentType 
> from throwing exception
>   +              if (linebuf[count - 1] == ';')
>   +                  --count;
>   +              String value = new String(linebuf, valStart, 
> count - valStart, ISO_8859_1);
>    
>   -              String value = new String(bytes, valStart, valueLen);
>                  if 
> (name.equalsIgnoreCase(Constants.HEADER_CONTENT_LENGTH))
>                      respContentLength = Integer.parseInt(value);
>                  else if 
> (name.equalsIgnoreCase(Constants.HEADER_CONTENT_TYPE))
>   @@ -556,27 +594,11 @@
>                          }
>                      }
>                  }
>   -              parsingName = true;
>   -              nameStart = offset+1;
>              }
>   -          else if (bytes[offset] != '\r') {
>   -              if (parsingName) {
>   -                  if (bytes[offset] == ':') {
>   -                      parsingName = false;
>   -                      nameEnd = offset - 1;
>   -                      if ((offset != bytes.length-1) &&
>   -                          bytes[offset+1] == ' ')
>   -                        offset++;
>   -                      valStart = offset+1;
>   -                  }
>   -              }
>   -          }
>   -      } // End of for
>   -
>   -      InputStream is = ds.getInputStream();
>   -      is.skip(offset + 1);
>   -      if (respContentLength < 0)
>   -          respContentLength = ds.getSize() - offset - 1;
>   +      } catch (Exception e) {
>   +          throw new SOAPException(Constants.FAULT_CODE_CLIENT,
>   +              "Error parsing HTTP header line \"" + new 
> String(linebuf, 0, count, ISO_8859_1) + "\": " + e, e);
>   +      }
>    
>          /* Handle redirect here */
>          if (statusCode >= HttpURLConnection.HTTP_MULT_CHOICE &&
>   @@ -595,11 +617,6 @@
>              }
>          }
>    
>   -      /* If required, capture a copy of the response. */
>   -      if (responseCopy != null) {
>   -        
> responseCopy.append(line).append("\r\n").append(new 
> String(bytes));  /* May get junk due to actual encoding */
>   -      }
>   -
>          // TODO: process differently depending on statusCode 
> and respContentLength
>          //       (TransportMessage does not even get statusCode)
>          // e.g. statusCode 401 is Unauthorized
>   @@ -612,13 +629,18 @@
>              // Create response SOAPContext.
>              ctx = new SOAPContext();
>              // Read content.
>   -          response = new TransportMessage(is, respContentLength,
>   +          response = new TransportMessage(bInStream, 
> respContentLength,
>                                              respContentType, 
> ctx, respHeaders);
>              // Extract envelope and SOAPContext
>              response.read();
>          } catch (MessagingException me) {
>              throw new SOAPException(Constants.FAULT_CODE_CLIENT,
>                                      "Error parsing response: 
> " + me, me);
>   +      }
>   +
>   +      /* If required, capture a copy of the response. */
>   +      if (responseCopy != null) {
>   +        responseCopy.append(new 
> String(response.getBytes()));  /* May get junk due to actual 
> encoding */
>          }
>    
>          /* All done here! */
>   
>   
>   
>   1.17      +51 -37    
> xml-soap/java/src/org/apache/soap/transport/TransportMessage.java
>   
>   Index: TransportMessage.java
>   ===================================================================
>   RCS file: 
> /home/cvs/xml-soap/java/src/org/apache/soap/transport/Transpor
tMessage.java,v
>   retrieving revision 1.16
>   retrieving revision 1.17
>   diff -u -r1.16 -r1.17
>   --- TransportMessage.java	6 Sep 2002 17:02:58 -0000	1.16
>   +++ TransportMessage.java	12 Nov 2002 14:15:38 -0000	1.17
>   @@ -128,25 +128,36 @@
>            this.ctx = ctx;
>            this.contentType = contentType;
>    
>   -        if (contentLength < 0)
>   -            throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
>   -                                     "Content length must 
> be specified.");
>   -
>   -        bytes = new byte[contentLength];
>   -        int offset = 0;
>   -        int bytesRead = 0;
>   -
>   -        // We're done reading when we get all the content 
> OR when the stream
>   -        // returns a -1.
>   -        while ((offset < contentLength) && (bytesRead >= 0)) {
>   -            bytesRead = is.read(bytes, offset, 
> contentLength - offset);
>   -            offset += bytesRead;
>   -        }
>   -        if (offset < contentLength)
>   -            throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
>   -                       "Premature end of stream. Data is 
> truncated. Read "
>   -                       + offset + " bytes successfully, expected "
>   -                       + contentLength);
>   +        bytes = new byte[contentLength >= 0 ? 
> contentLength : 4096];
>   +        if (contentLength != 0) {
>   +            int offset = 0;
>   +            int bytesRead = 0;
>   +    
>   +            // We're done reading when we get all the 
> content OR when the stream
>   +            // returns a -1.
>   +            while ((contentLength < 0 || offset < 
> contentLength) && (bytesRead >= 0)) {
>   +                bytesRead = is.read(bytes, offset, 
> bytes.length - offset);
>   +                offset += bytesRead;
>   +                if (contentLength < 0 && offset >= bytes.length) {
>   +                    byte[] newbuf = new byte[bytes.length * 2];
>   +                    System.arraycopy(bytes, 0, newbuf, 0, 
> bytes.length);
>   +                    bytes = newbuf;
>   +                }
>   +            }
>   +
>   +            if (contentLength < 0) {
>   +                if (offset < bytes.length) {
>   +                    byte[] newbuf = new byte[offset];
>   +                    System.arraycopy(bytes, 0, newbuf, 0, offset);
>   +                    bytes = newbuf;
>   +                }
>   +            } else if (offset < contentLength) {
>   +                throw new SOAPException 
> (Constants.FAULT_CODE_PROTOCOL,
>   +                           "Premature end of stream. Data 
> is truncated. Read "
>   +                           + offset + " bytes 
> successfully, expected "
>   +                           + contentLength);
>   +            }
>   +        }
>        }
>    
>        /**
>   @@ -284,7 +295,7 @@
>            }
>    
>            // If the root part is text, extract it as a String.
>   -        // Note that we could use JAF's help to do this 
> (see getEnvelope())
>   +        // Note that we could use JAF's help to do this 
> (see save())
>            // but implementing it ourselves is safer and faster.
>            if (rootContentType.match("text/*")) {
>                String charset = 
> rootContentType.getParameter("charset");
>   @@ -323,9 +334,11 @@
>         */
>        public void save()
>            throws MessagingException, IOException {
>   -        /* If an envelope was provided as a string, set it 
> as the root part.
>   -         * Otherwise, assume that the SOAPContext already 
> has a root part.
>   +        /*
>   +         * If an envelope was provided as a string, set it 
> as the root part.
>             * If there was already a root part, preserve its 
> content-type.
>   +         * Otherwise, assume that the SOAPContext already 
> has a root part,
>   +         * and try to use it as the envelope.
>             */
>            String rootContentType = null;
>            if (ctx.isRootPartSet()) {
>   @@ -339,8 +352,18 @@
>            }
>            if (rootContentType == null)
>                rootContentType = 
> Constants.HEADERVAL_CONTENT_TYPE_UTF8;
>   -        if (getEnvelope() != null)
>   +        if (getEnvelope() != null) {
>                ctx.setRootPart(envelope, rootContentType);
>   +        } else {
>   +            MimeBodyPart rootPart = ctx.getRootPart();
>   +            if (rootPart != null) {
>   +                if (rootPart.isMimeType("text/*")) {
>   +                    ByteArrayDataSource ds = new 
> ByteArrayDataSource(
>   +                        rootPart.getInputStream(), 
> rootPart.getContentType());
>   +                    envelope = ds.getText();
>   +                }
>   +            }
>   +        }
>    
>            // Print the whole response to a byte array.
>            ByteArrayOutputStream payload =
>   @@ -428,20 +451,9 @@
>        }
>    
>        /**
>   -     * Get SOAP Envelope/root part as a String.
>   -     * This method will extract the root part from the 
> SOAPContext as a String
>   -     * if there is no SOAP Envelope.
>   +     * Get SOAP Envelope as a String.
>         */
>   -    public String getEnvelope() throws MessagingException, 
> IOException {
>   -        if (envelope == null) {
>   -            MimeBodyPart rootPart = ctx.getRootPart();
>   -            if (rootPart != null)
>   -                if (rootPart.isMimeType("text/*")) {
>   -                    ByteArrayDataSource ds = new 
> ByteArrayDataSource(
>   -                        rootPart.getInputStream(), 
> rootPart.getContentType());
>   -                    envelope = ds.getText();
>   -            }
>   -        }
>   +    public String getEnvelope() {
>            return envelope;
>        }
>    
>   @@ -449,7 +461,7 @@
>         * Get SOAP Envelope/root part as a Reader. Returns 
> null if the root part
>         * is not text.
>         */
>   -    public Reader getEnvelopeReader() throws 
> MessagingException, IOException {
>   +    public Reader getEnvelopeReader() {
>            if (getEnvelope() == null)
>                return null;
>            else
>   @@ -530,6 +542,8 @@
>    
>        /**
>         * Set the byte array of the response.
>   +     *
>   +     * @deprecated After 2.3.1
>         */
>        public void readFully(InputStream is) throws IOException {
>            offset = 0;
>   
>   
>   
>   1.29      +19 -16    
> xml-soap/java/src/org/apache/soap/transport/http/SOAPHTTPConne
> ction.java
>   
>   Index: SOAPHTTPConnection.java
>   ===================================================================
>   RCS file: 
> /home/cvs/xml-soap/java/src/org/apache/soap/transport/http/SOA
PHTTPConnection.java,v
>   retrieving revision 1.28
>   retrieving revision 1.29
>   diff -u -r1.28 -r1.29
>   --- SOAPHTTPConnection.java	16 Oct 2002 04:16:15 -0000	1.28
>   +++ SOAPHTTPConnection.java	12 Nov 2002 14:15:38 -0000	1.29
>   @@ -84,9 +84,7 @@
>     * @author Arek Wnukowski (apache@wnuko.demon.co.uk)
>     */
>    public class SOAPHTTPConnection implements SOAPTransport {
>   -  private BufferedReader responseReader;
>   -  private Hashtable responseHeaders;
>   -  private SOAPContext responseSOAPContext;
>   +  private TransportMessage response;
>    
>      private String httpProxyHost;
>      private int    httpProxyPort = 80;
>   @@ -369,7 +367,6 @@
>                        "Basic " + 
> HTTPUtils.encodeAuth(proxyUserName, proxyPassword));
>          }
>    
>   -      TransportMessage response;
>          try
>          {
>            TransportMessage msg = new 
> TransportMessage(payload, ctx, headers);
>   @@ -385,18 +382,12 @@
>            throw new IOException ("Failed to encode mime 
> multipart: " + uee);
>          }
>    
>   -      Reader envReader = response.getEnvelopeReader();
>   -      if (envReader != null)
>   -        responseReader = new BufferedReader(envReader);
>   -      else
>   -        responseReader = null;
>   -      responseSOAPContext = response.getSOAPContext();
>   -      responseHeaders = response.getHeaders();
>          if (maintainSession) {
>            // look for Set-Cookie2 and Set-Cookie headers and 
> save them.
>            // Only update my state iff the header is there .. 
> otherwise
>            // leave the current 
>            // Note: Header is case-insensitive
>   +        Hashtable responseHeaders = response.getHeaders();
>            String hdr;
>    
>            hdr = HTTPUtils.getHeaderValue (responseHeaders, 
> "Set-Cookie2");
>   @@ -421,8 +412,6 @@
>          }
>        } catch (IllegalArgumentException e) {
>          throw new SOAPException 
> (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
>   -    } catch (MessagingException e) {
>   -      throw new SOAPException 
> (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
>        } catch (IOException e) {
>          throw new SOAPException 
> (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
>        }
>   @@ -436,7 +425,21 @@
>       *         possible.
>       */
>      public BufferedReader receive () {
>   -    return responseReader;
>   +    if (response != null) {
>   +      Reader envReader = response.getEnvelopeReader();
>   +      if (envReader != null)
>   +        return new BufferedReader(envReader);
>   +    }
>   +    return null;
>   +  }
>   +
>   +  /**
>   +   * Returns the SOAP envelope.
>   +   *
>   +   * @return The SOAP envelope.
>   +   */
>   +  public String getEnvelope() {
>   +    return response != null ? response.getEnvelope() : null;
>      }
>    
>      /**
>   @@ -445,7 +448,7 @@
>       * @return a hashtable containing all the headers
>       */
>      public Hashtable getHeaders () {
>   -    return responseHeaders;
>   +    return response != null ? response.getHeaders() : null;
>      }
>    
>      /**
>   @@ -454,6 +457,6 @@
>       * @return response SOAPContext
>       */
>      public SOAPContext getResponseSOAPContext () {
>   -    return responseSOAPContext;
>   +    return response != null ? response.getSOAPContext() : null;
>      }
>    }
>   
>   
>   
> 
> --
> To unsubscribe, e-mail:   <ma...@xml.apache.org>
> For additional commands, e-mail: <ma...@xml.apache.org>
> 

--
To unsubscribe, e-mail:   <ma...@xml.apache.org>
For additional commands, e-mail: <ma...@xml.apache.org>


Re: cvs commit: xml-soap/java/src/org/apache/soap/transport/http SOAPHTTPConnection.java

Posted by Scott Nichol <sn...@scottnichol.com>.
This is the case where the message has a Content-Length header
specifying 0 octets.  I create the byte array of that length, but there
is no reason to read, since I want 0 bytes, which is what I already
have.

Scott Nichol

----- Original Message -----
From: "Pavel Ausianik" <Pa...@epam.com>
To: <so...@xml.apache.org>
Sent: Tuesday, November 12, 2002 10:53 AM
Subject: RE: cvs commit:
xml-soap/java/src/org/apache/soap/transport/http SOAPHTTPConnection.java


> Scott,
>
> i don't know if this makes sence, but logic little bit strange, in
case
> contentLength=0. See buffer has been created, but as I can see it is
not
> used anymore since the following block finishes at the end. Should be
there
> condition to go inside and read from buffer?
>
>         bytes = new byte[contentLength >= 0 ? contentLength : 4096];
>         if (contentLength != 0) {
>
> Pavel
>
> > -----Original Message-----
> > From: snichol@apache.org [mailto:snichol@apache.org]
> > Sent: Tuesday, November 12, 2002 4:16 PM
> > To: xml-soap-cvs@apache.org
> > Subject: cvs commit:
xml-soap/java/src/org/apache/soap/transport/http
> > SOAPHTTPConnection.java
> >
> >
> > snichol     2002/11/12 06:15:38
> >
> >   Modified:    java/src/org/apache/soap/util/net HTTPUtils.java
> >                java/src/org/apache/soap/transport
> > TransportMessage.java
> >                java/src/org/apache/soap/transport/http
> >                         SOAPHTTPConnection.java
> >   Log:
> >   Reduce the number of times a response is copied in part or in
whole.
> >   Improve error reporting during response parsing.
> >   Support services that shutdown the write half of the socket
> > rather than
> >   provide a Content-Length header.
> >   Add getEnvelope to SOAPHTTPConnection.  (The method will
> > also be added
> >   to SOAPTransport soon.)
> >
> >   Revision  Changes    Path
> >   1.36      +104 -82
> > xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java
> >
> >   Index: HTTPUtils.java
> >
===================================================================
> >   RCS file:
> >
/home/cvs/xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java,v
> >   retrieving revision 1.35
> >   retrieving revision 1.36
> >   diff -u -r1.35 -r1.36
> >   --- HTTPUtils.java 18 Oct 2002 20:30:54 -0000 1.35
> >   +++ HTTPUtils.java 12 Nov 2002 14:15:38 -0000 1.36
> >   @@ -57,21 +57,30 @@
> >
> >    package org.apache.soap.util.net;
> >
> >   -import java.io.*;
> >   -import java.lang.reflect.*;
> >   -import java.net.*;
> >   -import java.util.*;
> >   -
> >   -import javax.mail.*;
> >   -import javax.mail.internet.*;
> >   -import javax.activation.*;
> >   +import java.io.BufferedInputStream;
> >   +import java.io.BufferedOutputStream;
> >   +import java.io.BufferedReader;
> >   +import java.io.InputStream;
> >   +import java.io.IOException;
> >   +import java.io.OutputStream;
> >   +import java.io.UnsupportedEncodingException;
> >   +import java.lang.reflect.InvocationTargetException;
> >   +import java.lang.reflect.Method;
> >   +import java.net.HttpURLConnection;
> >   +import java.net.Socket;
> >   +import java.net.URL;
> >   +import java.util.Enumeration;
> >   +import java.util.Hashtable;
> >   +import java.util.StringTokenizer;
> >
> >   -import org.apache.soap.*;
> >   +import javax.mail.MessagingException;
> >   +
> >   +import org.apache.soap.Constants;
> >   +import org.apache.soap.SOAPException;
> >    import org.apache.soap.encoding.soapenc.Base64;
> >   -import org.apache.soap.rpc.*;
> >   -import org.apache.soap.transport.*;
> >   +import org.apache.soap.rpc.SOAPContext;
> >   +import org.apache.soap.transport.TransportMessage;
> >    import org.apache.soap.util.MutableBoolean;
> >   -import org.apache.soap.util.mime.*;
> >
> >    /**
> >     * A bunch of utility stuff for doing HTTP things.
> >   @@ -91,6 +100,7 @@
> >      private static final String HTTP_VERSION = "1.0";
> >      private static final int    HTTP_DEFAULT_PORT = 80;
> >      private static final int    HTTPS_DEFAULT_PORT = 443;
> >   +  private static final String ISO_8859_1 = "8859_1";
> >
> >      public  static final int    DEFAULT_OUTPUT_BUFFER_SIZE =
> > 8 * 1024;
> >
> >   @@ -100,7 +110,7 @@
> >      public static String encodeAuth(String userName, String
password)
> >          throws SOAPException {
> >        try {
> >   -      return Base64.encode((userName + ":" +
> > password).getBytes("8859_1"));
> >   +      return Base64.encode((userName + ":" +
> > password).getBytes(ISO_8859_1));
> >        } catch (UnsupportedEncodingException e) {
> >          throw new SOAPException
> > (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
> >        }
> >   @@ -482,65 +492,93 @@
> >          bOutStream.flush();
> >
> >          BufferedInputStream bInStream = new
> > BufferedInputStream(inStream);
> >   +      byte[] linebuf = new byte[1024];
> >   +      int count = 0;
> >   +      int b;
> >   +
> >          /* Read the response status line. */
> >   +      String versionString = null;
> >          int statusCode = 0;
> >          String statusString = null;
> >   -      StringBuffer linebuf = new StringBuffer(128);
> >   -      int b = 0;
> >   -      while (b != '\n' && b != -1) {
> >   -          b = bInStream.read();
> >   -          if (b != '\n' && b != '\r' && b != -1)
> >   -              linebuf.append((char)b);
> >   -      }
> >   -      String line = linebuf.toString();
> >   +
> >          try {
> >   -          StringTokenizer st = new StringTokenizer(line);
> >   -          st.nextToken(); // ignore version part
> >   -          statusCode = Integer.parseInt (st.nextToken());
> >   -          StringBuffer sb = new StringBuffer(128);
> >   -          while (st.hasMoreTokens()) {
> >   -              sb.append (st.nextToken());
> >   -              if (st.hasMoreTokens()) {
> >   -                  sb.append(" ");
> >   +          int versionEnd = -1;
> >   +          int codeStart = -1;
> >   +          int codeEnd = -1;
> >   +          int stringStart = -1;
> >   +
> >   +          for (count = 0, b = bInStream.read(); b != '\n'
> > && b != -1; b = bInStream.read()) {
> >   +              if (b != '\r') {
> >   +                if (b == ' ') {
> >   +                    if (versionEnd == -1) {
> >   +                        versionEnd = count;
> >   +                    } else if (codeStart != -1 &&
> > codeEnd == -1) {
> >   +                        codeEnd = count;
> >   +                    }
> >   +                } else {
> >   +                    if (versionEnd != -1 && codeStart == -1) {
> >   +                        codeStart = count;
> >   +                    } else if (codeEnd != -1 &&
> > stringStart == -1) {
> >   +                        stringStart = count;
> >   +                    }
> >   +                }
> >   +                  if (count >= linebuf.length) {
> >   +                      byte[] newbuf = new byte[linebuf.length *
2];
> >   +                      System.arraycopy(linebuf, 0, newbuf,
> > 0, linebuf.length);
> >   +                      linebuf = newbuf;
> >   +                  }
> >   +                  linebuf[count++] = (byte) b;
> >                  }
> >              }
> >   -          statusString = sb.toString();
> >   -      }
> >   -      catch (Exception e) {
> >   +          if (b == -1)
> >   +              throw new Exception("Reached end of stream
> > while reading HTTP response status");
> >   +          versionString = new String(linebuf, 0,
> > versionEnd, ISO_8859_1);
> >   +          statusCode = Integer.parseInt(new
> > String(linebuf, codeStart, codeEnd - codeStart, ISO_8859_1));
> >   +          statusString = new String(linebuf, stringStart,
> > count - stringStart, ISO_8859_1);
> >   +      } catch (Exception e) {
> >              throw new SOAPException(Constants.FAULT_CODE_CLIENT,
> >   -              "Error parsing HTTP status line \"" + line +
> > "\": " + e, e);
> >   +              "Error parsing HTTP status line \"" + new
> > String(linebuf, 0, count, ISO_8859_1) + "\": " + e, e);
> >          }
> >
> >   -      /* Read the entire response (following the status line)
> >   -       * into a byte array. */
> >   -      ByteArrayDataSource ds = new ByteArrayDataSource(bInStream,
> >   -                          Constants.HEADERVAL_DEFAULT_CHARSET);
> >   -
> >   -      /* Extract the headers, content type and content length. */
> >   -      byte[] bytes = ds.toByteArray();
> >   +      /* Read the HTTP headers. */
> >          Hashtable respHeaders = new Hashtable();
> >          int respContentLength = -1;
> >          String respContentType = null;
> >
> >   -      int nameStart = 0;
> >   -      int nameEnd = 0;
> >   -      int valStart = 0;
> >   -      boolean parsingName = true;
> >   -      int offset;
> >   -
> >   -      for (offset = 0; offset < bytes.length; offset++) {
> >   -          if (bytes[offset] == '\n') {
> >   -              if (nameStart >= nameEnd)
> >   +      try {
> >   +          // Read all headers
> >   +          for (;;) {
> >   +              // Read and parse one header
> >   +              int nameEnd = -1;
> >   +              int valStart = -1;
> >   +              for (count = 0, b = bInStream.read(); b !=
> > '\n' && b != -1; b = bInStream.read()) {
> >   +                  if (b != '\r') {
> >   +                      if (nameEnd == -1 && b == ':') {
> >   +                          nameEnd = count;
> >   +                      } else if (nameEnd != -1 && valStart
> > == -1 && b != ' ' & b != '\t') {
> >   +                          valStart = count;
> >   +                      }
> >   +                      if (count >= linebuf.length) {
> >   +                          byte[] newbuf = new
> > byte[linebuf.length * 2];
> >   +                          System.arraycopy(linebuf, 0,
> > newbuf, 0, linebuf.length);
> >   +                          linebuf = newbuf;
> >   +                      }
> >   +                      linebuf[count++] = (byte) b;
> >   +                  }
> >   +              }
> >   +              if (b == -1)
> >   +                  throw new Exception("Reached end of
> > stream while reading HTTP response header");
> >   +              if (count == 0)   // Read the header/entity
separator
> >                      break;
> >   -              String name = new String(bytes, nameStart,
> > nameEnd-nameStart+1);
> >   -
> >   -              // Remove trailing ; to prevent ContextType
> > from throwing exception
> >   -              int valueLen = offset - valStart -1;
> >   +              if (nameEnd == -1 || valStart == -1)
> >   +                  throw new Exception("Incorrectly formed
> > HTTP response header");
> >
> >   -              if (valueLen > 0 && bytes[offset-1] == ';')
> >   -                  valueLen--;
> >   +              String name = new String(linebuf, 0,
> > nameEnd, ISO_8859_1);
> >   +              // Remove trailing ; to prevent ContentType
> > from throwing exception
> >   +              if (linebuf[count - 1] == ';')
> >   +                  --count;
> >   +              String value = new String(linebuf, valStart,
> > count - valStart, ISO_8859_1);
> >
> >   -              String value = new String(bytes, valStart,
valueLen);
> >                  if
> > (name.equalsIgnoreCase(Constants.HEADER_CONTENT_LENGTH))
> >                      respContentLength = Integer.parseInt(value);
> >                  else if
> > (name.equalsIgnoreCase(Constants.HEADER_CONTENT_TYPE))
> >   @@ -556,27 +594,11 @@
> >                          }
> >                      }
> >                  }
> >   -              parsingName = true;
> >   -              nameStart = offset+1;
> >              }
> >   -          else if (bytes[offset] != '\r') {
> >   -              if (parsingName) {
> >   -                  if (bytes[offset] == ':') {
> >   -                      parsingName = false;
> >   -                      nameEnd = offset - 1;
> >   -                      if ((offset != bytes.length-1) &&
> >   -                          bytes[offset+1] == ' ')
> >   -                        offset++;
> >   -                      valStart = offset+1;
> >   -                  }
> >   -              }
> >   -          }
> >   -      } // End of for
> >   -
> >   -      InputStream is = ds.getInputStream();
> >   -      is.skip(offset + 1);
> >   -      if (respContentLength < 0)
> >   -          respContentLength = ds.getSize() - offset - 1;
> >   +      } catch (Exception e) {
> >   +          throw new SOAPException(Constants.FAULT_CODE_CLIENT,
> >   +              "Error parsing HTTP header line \"" + new
> > String(linebuf, 0, count, ISO_8859_1) + "\": " + e, e);
> >   +      }
> >
> >          /* Handle redirect here */
> >          if (statusCode >= HttpURLConnection.HTTP_MULT_CHOICE &&
> >   @@ -595,11 +617,6 @@
> >              }
> >          }
> >
> >   -      /* If required, capture a copy of the response. */
> >   -      if (responseCopy != null) {
> >   -
> > responseCopy.append(line).append("\r\n").append(new
> > String(bytes));  /* May get junk due to actual encoding */
> >   -      }
> >   -
> >          // TODO: process differently depending on statusCode
> > and respContentLength
> >          //       (TransportMessage does not even get statusCode)
> >          // e.g. statusCode 401 is Unauthorized
> >   @@ -612,13 +629,18 @@
> >              // Create response SOAPContext.
> >              ctx = new SOAPContext();
> >              // Read content.
> >   -          response = new TransportMessage(is, respContentLength,
> >   +          response = new TransportMessage(bInStream,
> > respContentLength,
> >                                              respContentType,
> > ctx, respHeaders);
> >              // Extract envelope and SOAPContext
> >              response.read();
> >          } catch (MessagingException me) {
> >              throw new SOAPException(Constants.FAULT_CODE_CLIENT,
> >                                      "Error parsing response:
> > " + me, me);
> >   +      }
> >   +
> >   +      /* If required, capture a copy of the response. */
> >   +      if (responseCopy != null) {
> >   +        responseCopy.append(new
> > String(response.getBytes()));  /* May get junk due to actual
> > encoding */
> >          }
> >
> >          /* All done here! */
> >
> >
> >
> >   1.17      +51 -37
> > xml-soap/java/src/org/apache/soap/transport/TransportMessage.java
> >
> >   Index: TransportMessage.java
> >
===================================================================
> >   RCS file:
> > /home/cvs/xml-soap/java/src/org/apache/soap/transport/Transpor
> tMessage.java,v
> >   retrieving revision 1.16
> >   retrieving revision 1.17
> >   diff -u -r1.16 -r1.17
> >   --- TransportMessage.java 6 Sep 2002 17:02:58 -0000 1.16
> >   +++ TransportMessage.java 12 Nov 2002 14:15:38 -0000 1.17
> >   @@ -128,25 +128,36 @@
> >            this.ctx = ctx;
> >            this.contentType = contentType;
> >
> >   -        if (contentLength < 0)
> >   -            throw new SOAPException
(Constants.FAULT_CODE_PROTOCOL,
> >   -                                     "Content length must
> > be specified.");
> >   -
> >   -        bytes = new byte[contentLength];
> >   -        int offset = 0;
> >   -        int bytesRead = 0;
> >   -
> >   -        // We're done reading when we get all the content
> > OR when the stream
> >   -        // returns a -1.
> >   -        while ((offset < contentLength) && (bytesRead >= 0)) {
> >   -            bytesRead = is.read(bytes, offset,
> > contentLength - offset);
> >   -            offset += bytesRead;
> >   -        }
> >   -        if (offset < contentLength)
> >   -            throw new SOAPException
(Constants.FAULT_CODE_PROTOCOL,
> >   -                       "Premature end of stream. Data is
> > truncated. Read "
> >   -                       + offset + " bytes successfully, expected
"
> >   -                       + contentLength);
> >   +        bytes = new byte[contentLength >= 0 ?
> > contentLength : 4096];
> >   +        if (contentLength != 0) {
> >   +            int offset = 0;
> >   +            int bytesRead = 0;
> >   +
> >   +            // We're done reading when we get all the
> > content OR when the stream
> >   +            // returns a -1.
> >   +            while ((contentLength < 0 || offset <
> > contentLength) && (bytesRead >= 0)) {
> >   +                bytesRead = is.read(bytes, offset,
> > bytes.length - offset);
> >   +                offset += bytesRead;
> >   +                if (contentLength < 0 && offset >= bytes.length)
{
> >   +                    byte[] newbuf = new byte[bytes.length * 2];
> >   +                    System.arraycopy(bytes, 0, newbuf, 0,
> > bytes.length);
> >   +                    bytes = newbuf;
> >   +                }
> >   +            }
> >   +
> >   +            if (contentLength < 0) {
> >   +                if (offset < bytes.length) {
> >   +                    byte[] newbuf = new byte[offset];
> >   +                    System.arraycopy(bytes, 0, newbuf, 0,
offset);
> >   +                    bytes = newbuf;
> >   +                }
> >   +            } else if (offset < contentLength) {
> >   +                throw new SOAPException
> > (Constants.FAULT_CODE_PROTOCOL,
> >   +                           "Premature end of stream. Data
> > is truncated. Read "
> >   +                           + offset + " bytes
> > successfully, expected "
> >   +                           + contentLength);
> >   +            }
> >   +        }
> >        }
> >
> >        /**
> >   @@ -284,7 +295,7 @@
> >            }
> >
> >            // If the root part is text, extract it as a String.
> >   -        // Note that we could use JAF's help to do this
> > (see getEnvelope())
> >   +        // Note that we could use JAF's help to do this
> > (see save())
> >            // but implementing it ourselves is safer and faster.
> >            if (rootContentType.match("text/*")) {
> >                String charset =
> > rootContentType.getParameter("charset");
> >   @@ -323,9 +334,11 @@
> >         */
> >        public void save()
> >            throws MessagingException, IOException {
> >   -        /* If an envelope was provided as a string, set it
> > as the root part.
> >   -         * Otherwise, assume that the SOAPContext already
> > has a root part.
> >   +        /*
> >   +         * If an envelope was provided as a string, set it
> > as the root part.
> >             * If there was already a root part, preserve its
> > content-type.
> >   +         * Otherwise, assume that the SOAPContext already
> > has a root part,
> >   +         * and try to use it as the envelope.
> >             */
> >            String rootContentType = null;
> >            if (ctx.isRootPartSet()) {
> >   @@ -339,8 +352,18 @@
> >            }
> >            if (rootContentType == null)
> >                rootContentType =
> > Constants.HEADERVAL_CONTENT_TYPE_UTF8;
> >   -        if (getEnvelope() != null)
> >   +        if (getEnvelope() != null) {
> >                ctx.setRootPart(envelope, rootContentType);
> >   +        } else {
> >   +            MimeBodyPart rootPart = ctx.getRootPart();
> >   +            if (rootPart != null) {
> >   +                if (rootPart.isMimeType("text/*")) {
> >   +                    ByteArrayDataSource ds = new
> > ByteArrayDataSource(
> >   +                        rootPart.getInputStream(),
> > rootPart.getContentType());
> >   +                    envelope = ds.getText();
> >   +                }
> >   +            }
> >   +        }
> >
> >            // Print the whole response to a byte array.
> >            ByteArrayOutputStream payload =
> >   @@ -428,20 +451,9 @@
> >        }
> >
> >        /**
> >   -     * Get SOAP Envelope/root part as a String.
> >   -     * This method will extract the root part from the
> > SOAPContext as a String
> >   -     * if there is no SOAP Envelope.
> >   +     * Get SOAP Envelope as a String.
> >         */
> >   -    public String getEnvelope() throws MessagingException,
> > IOException {
> >   -        if (envelope == null) {
> >   -            MimeBodyPart rootPart = ctx.getRootPart();
> >   -            if (rootPart != null)
> >   -                if (rootPart.isMimeType("text/*")) {
> >   -                    ByteArrayDataSource ds = new
> > ByteArrayDataSource(
> >   -                        rootPart.getInputStream(),
> > rootPart.getContentType());
> >   -                    envelope = ds.getText();
> >   -            }
> >   -        }
> >   +    public String getEnvelope() {
> >            return envelope;
> >        }
> >
> >   @@ -449,7 +461,7 @@
> >         * Get SOAP Envelope/root part as a Reader. Returns
> > null if the root part
> >         * is not text.
> >         */
> >   -    public Reader getEnvelopeReader() throws
> > MessagingException, IOException {
> >   +    public Reader getEnvelopeReader() {
> >            if (getEnvelope() == null)
> >                return null;
> >            else
> >   @@ -530,6 +542,8 @@
> >
> >        /**
> >         * Set the byte array of the response.
> >   +     *
> >   +     * @deprecated After 2.3.1
> >         */
> >        public void readFully(InputStream is) throws IOException {
> >            offset = 0;
> >
> >
> >
> >   1.29      +19 -16
> > xml-soap/java/src/org/apache/soap/transport/http/SOAPHTTPConne
> > ction.java
> >
> >   Index: SOAPHTTPConnection.java
> >
===================================================================
> >   RCS file:
> > /home/cvs/xml-soap/java/src/org/apache/soap/transport/http/SOA
> PHTTPConnection.java,v
> >   retrieving revision 1.28
> >   retrieving revision 1.29
> >   diff -u -r1.28 -r1.29
> >   --- SOAPHTTPConnection.java 16 Oct 2002 04:16:15 -0000 1.28
> >   +++ SOAPHTTPConnection.java 12 Nov 2002 14:15:38 -0000 1.29
> >   @@ -84,9 +84,7 @@
> >     * @author Arek Wnukowski (apache@wnuko.demon.co.uk)
> >     */
> >    public class SOAPHTTPConnection implements SOAPTransport {
> >   -  private BufferedReader responseReader;
> >   -  private Hashtable responseHeaders;
> >   -  private SOAPContext responseSOAPContext;
> >   +  private TransportMessage response;
> >
> >      private String httpProxyHost;
> >      private int    httpProxyPort = 80;
> >   @@ -369,7 +367,6 @@
> >                        "Basic " +
> > HTTPUtils.encodeAuth(proxyUserName, proxyPassword));
> >          }
> >
> >   -      TransportMessage response;
> >          try
> >          {
> >            TransportMessage msg = new
> > TransportMessage(payload, ctx, headers);
> >   @@ -385,18 +382,12 @@
> >            throw new IOException ("Failed to encode mime
> > multipart: " + uee);
> >          }
> >
> >   -      Reader envReader = response.getEnvelopeReader();
> >   -      if (envReader != null)
> >   -        responseReader = new BufferedReader(envReader);
> >   -      else
> >   -        responseReader = null;
> >   -      responseSOAPContext = response.getSOAPContext();
> >   -      responseHeaders = response.getHeaders();
> >          if (maintainSession) {
> >            // look for Set-Cookie2 and Set-Cookie headers and
> > save them.
> >            // Only update my state iff the header is there ..
> > otherwise
> >            // leave the current
> >            // Note: Header is case-insensitive
> >   +        Hashtable responseHeaders = response.getHeaders();
> >            String hdr;
> >
> >            hdr = HTTPUtils.getHeaderValue (responseHeaders,
> > "Set-Cookie2");
> >   @@ -421,8 +412,6 @@
> >          }
> >        } catch (IllegalArgumentException e) {
> >          throw new SOAPException
> > (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
> >   -    } catch (MessagingException e) {
> >   -      throw new SOAPException
> > (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
> >        } catch (IOException e) {
> >          throw new SOAPException
> > (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
> >        }
> >   @@ -436,7 +425,21 @@
> >       *         possible.
> >       */
> >      public BufferedReader receive () {
> >   -    return responseReader;
> >   +    if (response != null) {
> >   +      Reader envReader = response.getEnvelopeReader();
> >   +      if (envReader != null)
> >   +        return new BufferedReader(envReader);
> >   +    }
> >   +    return null;
> >   +  }
> >   +
> >   +  /**
> >   +   * Returns the SOAP envelope.
> >   +   *
> >   +   * @return The SOAP envelope.
> >   +   */
> >   +  public String getEnvelope() {
> >   +    return response != null ? response.getEnvelope() : null;
> >      }
> >
> >      /**
> >   @@ -445,7 +448,7 @@
> >       * @return a hashtable containing all the headers
> >       */
> >      public Hashtable getHeaders () {
> >   -    return responseHeaders;
> >   +    return response != null ? response.getHeaders() : null;
> >      }
> >
> >      /**
> >   @@ -454,6 +457,6 @@
> >       * @return response SOAPContext
> >       */
> >      public SOAPContext getResponseSOAPContext () {
> >   -    return responseSOAPContext;
> >   +    return response != null ? response.getSOAPContext() : null;
> >      }
> >    }
> >
> >
> >
> >
> > --
> > To unsubscribe, e-mail:
<ma...@xml.apache.org>
> > For additional commands, e-mail:
<ma...@xml.apache.org>
> >
>
> --
> To unsubscribe, e-mail:   <ma...@xml.apache.org>
> For additional commands, e-mail: <ma...@xml.apache.org>
>
>


--
To unsubscribe, e-mail:   <ma...@xml.apache.org>
For additional commands, e-mail: <ma...@xml.apache.org>


Re: cvs commit: xml-soap/java/src/org/apache/soap/transport/http SOAPHTTPConnection.java

Posted by Scott Nichol <sn...@scottnichol.com>.
This is the case where the message has a Content-Length header
specifying 0 octets.  I create the byte array of that length, but there
is no reason to read, since I want 0 bytes, which is what I already
have.

Scott Nichol

----- Original Message -----
From: "Pavel Ausianik" <Pa...@epam.com>
To: <so...@xml.apache.org>
Sent: Tuesday, November 12, 2002 10:53 AM
Subject: RE: cvs commit:
xml-soap/java/src/org/apache/soap/transport/http SOAPHTTPConnection.java


> Scott,
>
> i don't know if this makes sence, but logic little bit strange, in
case
> contentLength=0. See buffer has been created, but as I can see it is
not
> used anymore since the following block finishes at the end. Should be
there
> condition to go inside and read from buffer?
>
>         bytes = new byte[contentLength >= 0 ? contentLength : 4096];
>         if (contentLength != 0) {
>
> Pavel
>
> > -----Original Message-----
> > From: snichol@apache.org [mailto:snichol@apache.org]
> > Sent: Tuesday, November 12, 2002 4:16 PM
> > To: xml-soap-cvs@apache.org
> > Subject: cvs commit:
xml-soap/java/src/org/apache/soap/transport/http
> > SOAPHTTPConnection.java
> >
> >
> > snichol     2002/11/12 06:15:38
> >
> >   Modified:    java/src/org/apache/soap/util/net HTTPUtils.java
> >                java/src/org/apache/soap/transport
> > TransportMessage.java
> >                java/src/org/apache/soap/transport/http
> >                         SOAPHTTPConnection.java
> >   Log:
> >   Reduce the number of times a response is copied in part or in
whole.
> >   Improve error reporting during response parsing.
> >   Support services that shutdown the write half of the socket
> > rather than
> >   provide a Content-Length header.
> >   Add getEnvelope to SOAPHTTPConnection.  (The method will
> > also be added
> >   to SOAPTransport soon.)
> >
> >   Revision  Changes    Path
> >   1.36      +104 -82
> > xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java
> >
> >   Index: HTTPUtils.java
> >
===================================================================
> >   RCS file:
> >
/home/cvs/xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java,v
> >   retrieving revision 1.35
> >   retrieving revision 1.36
> >   diff -u -r1.35 -r1.36
> >   --- HTTPUtils.java 18 Oct 2002 20:30:54 -0000 1.35
> >   +++ HTTPUtils.java 12 Nov 2002 14:15:38 -0000 1.36
> >   @@ -57,21 +57,30 @@
> >
> >    package org.apache.soap.util.net;
> >
> >   -import java.io.*;
> >   -import java.lang.reflect.*;
> >   -import java.net.*;
> >   -import java.util.*;
> >   -
> >   -import javax.mail.*;
> >   -import javax.mail.internet.*;
> >   -import javax.activation.*;
> >   +import java.io.BufferedInputStream;
> >   +import java.io.BufferedOutputStream;
> >   +import java.io.BufferedReader;
> >   +import java.io.InputStream;
> >   +import java.io.IOException;
> >   +import java.io.OutputStream;
> >   +import java.io.UnsupportedEncodingException;
> >   +import java.lang.reflect.InvocationTargetException;
> >   +import java.lang.reflect.Method;
> >   +import java.net.HttpURLConnection;
> >   +import java.net.Socket;
> >   +import java.net.URL;
> >   +import java.util.Enumeration;
> >   +import java.util.Hashtable;
> >   +import java.util.StringTokenizer;
> >
> >   -import org.apache.soap.*;
> >   +import javax.mail.MessagingException;
> >   +
> >   +import org.apache.soap.Constants;
> >   +import org.apache.soap.SOAPException;
> >    import org.apache.soap.encoding.soapenc.Base64;
> >   -import org.apache.soap.rpc.*;
> >   -import org.apache.soap.transport.*;
> >   +import org.apache.soap.rpc.SOAPContext;
> >   +import org.apache.soap.transport.TransportMessage;
> >    import org.apache.soap.util.MutableBoolean;
> >   -import org.apache.soap.util.mime.*;
> >
> >    /**
> >     * A bunch of utility stuff for doing HTTP things.
> >   @@ -91,6 +100,7 @@
> >      private static final String HTTP_VERSION = "1.0";
> >      private static final int    HTTP_DEFAULT_PORT = 80;
> >      private static final int    HTTPS_DEFAULT_PORT = 443;
> >   +  private static final String ISO_8859_1 = "8859_1";
> >
> >      public  static final int    DEFAULT_OUTPUT_BUFFER_SIZE =
> > 8 * 1024;
> >
> >   @@ -100,7 +110,7 @@
> >      public static String encodeAuth(String userName, String
password)
> >          throws SOAPException {
> >        try {
> >   -      return Base64.encode((userName + ":" +
> > password).getBytes("8859_1"));
> >   +      return Base64.encode((userName + ":" +
> > password).getBytes(ISO_8859_1));
> >        } catch (UnsupportedEncodingException e) {
> >          throw new SOAPException
> > (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
> >        }
> >   @@ -482,65 +492,93 @@
> >          bOutStream.flush();
> >
> >          BufferedInputStream bInStream = new
> > BufferedInputStream(inStream);
> >   +      byte[] linebuf = new byte[1024];
> >   +      int count = 0;
> >   +      int b;
> >   +
> >          /* Read the response status line. */
> >   +      String versionString = null;
> >          int statusCode = 0;
> >          String statusString = null;
> >   -      StringBuffer linebuf = new StringBuffer(128);
> >   -      int b = 0;
> >   -      while (b != '\n' && b != -1) {
> >   -          b = bInStream.read();
> >   -          if (b != '\n' && b != '\r' && b != -1)
> >   -              linebuf.append((char)b);
> >   -      }
> >   -      String line = linebuf.toString();
> >   +
> >          try {
> >   -          StringTokenizer st = new StringTokenizer(line);
> >   -          st.nextToken(); // ignore version part
> >   -          statusCode = Integer.parseInt (st.nextToken());
> >   -          StringBuffer sb = new StringBuffer(128);
> >   -          while (st.hasMoreTokens()) {
> >   -              sb.append (st.nextToken());
> >   -              if (st.hasMoreTokens()) {
> >   -                  sb.append(" ");
> >   +          int versionEnd = -1;
> >   +          int codeStart = -1;
> >   +          int codeEnd = -1;
> >   +          int stringStart = -1;
> >   +
> >   +          for (count = 0, b = bInStream.read(); b != '\n'
> > && b != -1; b = bInStream.read()) {
> >   +              if (b != '\r') {
> >   +                if (b == ' ') {
> >   +                    if (versionEnd == -1) {
> >   +                        versionEnd = count;
> >   +                    } else if (codeStart != -1 &&
> > codeEnd == -1) {
> >   +                        codeEnd = count;
> >   +                    }
> >   +                } else {
> >   +                    if (versionEnd != -1 && codeStart == -1) {
> >   +                        codeStart = count;
> >   +                    } else if (codeEnd != -1 &&
> > stringStart == -1) {
> >   +                        stringStart = count;
> >   +                    }
> >   +                }
> >   +                  if (count >= linebuf.length) {
> >   +                      byte[] newbuf = new byte[linebuf.length *
2];
> >   +                      System.arraycopy(linebuf, 0, newbuf,
> > 0, linebuf.length);
> >   +                      linebuf = newbuf;
> >   +                  }
> >   +                  linebuf[count++] = (byte) b;
> >                  }
> >              }
> >   -          statusString = sb.toString();
> >   -      }
> >   -      catch (Exception e) {
> >   +          if (b == -1)
> >   +              throw new Exception("Reached end of stream
> > while reading HTTP response status");
> >   +          versionString = new String(linebuf, 0,
> > versionEnd, ISO_8859_1);
> >   +          statusCode = Integer.parseInt(new
> > String(linebuf, codeStart, codeEnd - codeStart, ISO_8859_1));
> >   +          statusString = new String(linebuf, stringStart,
> > count - stringStart, ISO_8859_1);
> >   +      } catch (Exception e) {
> >              throw new SOAPException(Constants.FAULT_CODE_CLIENT,
> >   -              "Error parsing HTTP status line \"" + line +
> > "\": " + e, e);
> >   +              "Error parsing HTTP status line \"" + new
> > String(linebuf, 0, count, ISO_8859_1) + "\": " + e, e);
> >          }
> >
> >   -      /* Read the entire response (following the status line)
> >   -       * into a byte array. */
> >   -      ByteArrayDataSource ds = new ByteArrayDataSource(bInStream,
> >   -                          Constants.HEADERVAL_DEFAULT_CHARSET);
> >   -
> >   -      /* Extract the headers, content type and content length. */
> >   -      byte[] bytes = ds.toByteArray();
> >   +      /* Read the HTTP headers. */
> >          Hashtable respHeaders = new Hashtable();
> >          int respContentLength = -1;
> >          String respContentType = null;
> >
> >   -      int nameStart = 0;
> >   -      int nameEnd = 0;
> >   -      int valStart = 0;
> >   -      boolean parsingName = true;
> >   -      int offset;
> >   -
> >   -      for (offset = 0; offset < bytes.length; offset++) {
> >   -          if (bytes[offset] == '\n') {
> >   -              if (nameStart >= nameEnd)
> >   +      try {
> >   +          // Read all headers
> >   +          for (;;) {
> >   +              // Read and parse one header
> >   +              int nameEnd = -1;
> >   +              int valStart = -1;
> >   +              for (count = 0, b = bInStream.read(); b !=
> > '\n' && b != -1; b = bInStream.read()) {
> >   +                  if (b != '\r') {
> >   +                      if (nameEnd == -1 && b == ':') {
> >   +                          nameEnd = count;
> >   +                      } else if (nameEnd != -1 && valStart
> > == -1 && b != ' ' & b != '\t') {
> >   +                          valStart = count;
> >   +                      }
> >   +                      if (count >= linebuf.length) {
> >   +                          byte[] newbuf = new
> > byte[linebuf.length * 2];
> >   +                          System.arraycopy(linebuf, 0,
> > newbuf, 0, linebuf.length);
> >   +                          linebuf = newbuf;
> >   +                      }
> >   +                      linebuf[count++] = (byte) b;
> >   +                  }
> >   +              }
> >   +              if (b == -1)
> >   +                  throw new Exception("Reached end of
> > stream while reading HTTP response header");
> >   +              if (count == 0)   // Read the header/entity
separator
> >                      break;
> >   -              String name = new String(bytes, nameStart,
> > nameEnd-nameStart+1);
> >   -
> >   -              // Remove trailing ; to prevent ContextType
> > from throwing exception
> >   -              int valueLen = offset - valStart -1;
> >   +              if (nameEnd == -1 || valStart == -1)
> >   +                  throw new Exception("Incorrectly formed
> > HTTP response header");
> >
> >   -              if (valueLen > 0 && bytes[offset-1] == ';')
> >   -                  valueLen--;
> >   +              String name = new String(linebuf, 0,
> > nameEnd, ISO_8859_1);
> >   +              // Remove trailing ; to prevent ContentType
> > from throwing exception
> >   +              if (linebuf[count - 1] == ';')
> >   +                  --count;
> >   +              String value = new String(linebuf, valStart,
> > count - valStart, ISO_8859_1);
> >
> >   -              String value = new String(bytes, valStart,
valueLen);
> >                  if
> > (name.equalsIgnoreCase(Constants.HEADER_CONTENT_LENGTH))
> >                      respContentLength = Integer.parseInt(value);
> >                  else if
> > (name.equalsIgnoreCase(Constants.HEADER_CONTENT_TYPE))
> >   @@ -556,27 +594,11 @@
> >                          }
> >                      }
> >                  }
> >   -              parsingName = true;
> >   -              nameStart = offset+1;
> >              }
> >   -          else if (bytes[offset] != '\r') {
> >   -              if (parsingName) {
> >   -                  if (bytes[offset] == ':') {
> >   -                      parsingName = false;
> >   -                      nameEnd = offset - 1;
> >   -                      if ((offset != bytes.length-1) &&
> >   -                          bytes[offset+1] == ' ')
> >   -                        offset++;
> >   -                      valStart = offset+1;
> >   -                  }
> >   -              }
> >   -          }
> >   -      } // End of for
> >   -
> >   -      InputStream is = ds.getInputStream();
> >   -      is.skip(offset + 1);
> >   -      if (respContentLength < 0)
> >   -          respContentLength = ds.getSize() - offset - 1;
> >   +      } catch (Exception e) {
> >   +          throw new SOAPException(Constants.FAULT_CODE_CLIENT,
> >   +              "Error parsing HTTP header line \"" + new
> > String(linebuf, 0, count, ISO_8859_1) + "\": " + e, e);
> >   +      }
> >
> >          /* Handle redirect here */
> >          if (statusCode >= HttpURLConnection.HTTP_MULT_CHOICE &&
> >   @@ -595,11 +617,6 @@
> >              }
> >          }
> >
> >   -      /* If required, capture a copy of the response. */
> >   -      if (responseCopy != null) {
> >   -
> > responseCopy.append(line).append("\r\n").append(new
> > String(bytes));  /* May get junk due to actual encoding */
> >   -      }
> >   -
> >          // TODO: process differently depending on statusCode
> > and respContentLength
> >          //       (TransportMessage does not even get statusCode)
> >          // e.g. statusCode 401 is Unauthorized
> >   @@ -612,13 +629,18 @@
> >              // Create response SOAPContext.
> >              ctx = new SOAPContext();
> >              // Read content.
> >   -          response = new TransportMessage(is, respContentLength,
> >   +          response = new TransportMessage(bInStream,
> > respContentLength,
> >                                              respContentType,
> > ctx, respHeaders);
> >              // Extract envelope and SOAPContext
> >              response.read();
> >          } catch (MessagingException me) {
> >              throw new SOAPException(Constants.FAULT_CODE_CLIENT,
> >                                      "Error parsing response:
> > " + me, me);
> >   +      }
> >   +
> >   +      /* If required, capture a copy of the response. */
> >   +      if (responseCopy != null) {
> >   +        responseCopy.append(new
> > String(response.getBytes()));  /* May get junk due to actual
> > encoding */
> >          }
> >
> >          /* All done here! */
> >
> >
> >
> >   1.17      +51 -37
> > xml-soap/java/src/org/apache/soap/transport/TransportMessage.java
> >
> >   Index: TransportMessage.java
> >
===================================================================
> >   RCS file:
> > /home/cvs/xml-soap/java/src/org/apache/soap/transport/Transpor
> tMessage.java,v
> >   retrieving revision 1.16
> >   retrieving revision 1.17
> >   diff -u -r1.16 -r1.17
> >   --- TransportMessage.java 6 Sep 2002 17:02:58 -0000 1.16
> >   +++ TransportMessage.java 12 Nov 2002 14:15:38 -0000 1.17
> >   @@ -128,25 +128,36 @@
> >            this.ctx = ctx;
> >            this.contentType = contentType;
> >
> >   -        if (contentLength < 0)
> >   -            throw new SOAPException
(Constants.FAULT_CODE_PROTOCOL,
> >   -                                     "Content length must
> > be specified.");
> >   -
> >   -        bytes = new byte[contentLength];
> >   -        int offset = 0;
> >   -        int bytesRead = 0;
> >   -
> >   -        // We're done reading when we get all the content
> > OR when the stream
> >   -        // returns a -1.
> >   -        while ((offset < contentLength) && (bytesRead >= 0)) {
> >   -            bytesRead = is.read(bytes, offset,
> > contentLength - offset);
> >   -            offset += bytesRead;
> >   -        }
> >   -        if (offset < contentLength)
> >   -            throw new SOAPException
(Constants.FAULT_CODE_PROTOCOL,
> >   -                       "Premature end of stream. Data is
> > truncated. Read "
> >   -                       + offset + " bytes successfully, expected
"
> >   -                       + contentLength);
> >   +        bytes = new byte[contentLength >= 0 ?
> > contentLength : 4096];
> >   +        if (contentLength != 0) {
> >   +            int offset = 0;
> >   +            int bytesRead = 0;
> >   +
> >   +            // We're done reading when we get all the
> > content OR when the stream
> >   +            // returns a -1.
> >   +            while ((contentLength < 0 || offset <
> > contentLength) && (bytesRead >= 0)) {
> >   +                bytesRead = is.read(bytes, offset,
> > bytes.length - offset);
> >   +                offset += bytesRead;
> >   +                if (contentLength < 0 && offset >= bytes.length)
{
> >   +                    byte[] newbuf = new byte[bytes.length * 2];
> >   +                    System.arraycopy(bytes, 0, newbuf, 0,
> > bytes.length);
> >   +                    bytes = newbuf;
> >   +                }
> >   +            }
> >   +
> >   +            if (contentLength < 0) {
> >   +                if (offset < bytes.length) {
> >   +                    byte[] newbuf = new byte[offset];
> >   +                    System.arraycopy(bytes, 0, newbuf, 0,
offset);
> >   +                    bytes = newbuf;
> >   +                }
> >   +            } else if (offset < contentLength) {
> >   +                throw new SOAPException
> > (Constants.FAULT_CODE_PROTOCOL,
> >   +                           "Premature end of stream. Data
> > is truncated. Read "
> >   +                           + offset + " bytes
> > successfully, expected "
> >   +                           + contentLength);
> >   +            }
> >   +        }
> >        }
> >
> >        /**
> >   @@ -284,7 +295,7 @@
> >            }
> >
> >            // If the root part is text, extract it as a String.
> >   -        // Note that we could use JAF's help to do this
> > (see getEnvelope())
> >   +        // Note that we could use JAF's help to do this
> > (see save())
> >            // but implementing it ourselves is safer and faster.
> >            if (rootContentType.match("text/*")) {
> >                String charset =
> > rootContentType.getParameter("charset");
> >   @@ -323,9 +334,11 @@
> >         */
> >        public void save()
> >            throws MessagingException, IOException {
> >   -        /* If an envelope was provided as a string, set it
> > as the root part.
> >   -         * Otherwise, assume that the SOAPContext already
> > has a root part.
> >   +        /*
> >   +         * If an envelope was provided as a string, set it
> > as the root part.
> >             * If there was already a root part, preserve its
> > content-type.
> >   +         * Otherwise, assume that the SOAPContext already
> > has a root part,
> >   +         * and try to use it as the envelope.
> >             */
> >            String rootContentType = null;
> >            if (ctx.isRootPartSet()) {
> >   @@ -339,8 +352,18 @@
> >            }
> >            if (rootContentType == null)
> >                rootContentType =
> > Constants.HEADERVAL_CONTENT_TYPE_UTF8;
> >   -        if (getEnvelope() != null)
> >   +        if (getEnvelope() != null) {
> >                ctx.setRootPart(envelope, rootContentType);
> >   +        } else {
> >   +            MimeBodyPart rootPart = ctx.getRootPart();
> >   +            if (rootPart != null) {
> >   +                if (rootPart.isMimeType("text/*")) {
> >   +                    ByteArrayDataSource ds = new
> > ByteArrayDataSource(
> >   +                        rootPart.getInputStream(),
> > rootPart.getContentType());
> >   +                    envelope = ds.getText();
> >   +                }
> >   +            }
> >   +        }
> >
> >            // Print the whole response to a byte array.
> >            ByteArrayOutputStream payload =
> >   @@ -428,20 +451,9 @@
> >        }
> >
> >        /**
> >   -     * Get SOAP Envelope/root part as a String.
> >   -     * This method will extract the root part from the
> > SOAPContext as a String
> >   -     * if there is no SOAP Envelope.
> >   +     * Get SOAP Envelope as a String.
> >         */
> >   -    public String getEnvelope() throws MessagingException,
> > IOException {
> >   -        if (envelope == null) {
> >   -            MimeBodyPart rootPart = ctx.getRootPart();
> >   -            if (rootPart != null)
> >   -                if (rootPart.isMimeType("text/*")) {
> >   -                    ByteArrayDataSource ds = new
> > ByteArrayDataSource(
> >   -                        rootPart.getInputStream(),
> > rootPart.getContentType());
> >   -                    envelope = ds.getText();
> >   -            }
> >   -        }
> >   +    public String getEnvelope() {
> >            return envelope;
> >        }
> >
> >   @@ -449,7 +461,7 @@
> >         * Get SOAP Envelope/root part as a Reader. Returns
> > null if the root part
> >         * is not text.
> >         */
> >   -    public Reader getEnvelopeReader() throws
> > MessagingException, IOException {
> >   +    public Reader getEnvelopeReader() {
> >            if (getEnvelope() == null)
> >                return null;
> >            else
> >   @@ -530,6 +542,8 @@
> >
> >        /**
> >         * Set the byte array of the response.
> >   +     *
> >   +     * @deprecated After 2.3.1
> >         */
> >        public void readFully(InputStream is) throws IOException {
> >            offset = 0;
> >
> >
> >
> >   1.29      +19 -16
> > xml-soap/java/src/org/apache/soap/transport/http/SOAPHTTPConne
> > ction.java
> >
> >   Index: SOAPHTTPConnection.java
> >
===================================================================
> >   RCS file:
> > /home/cvs/xml-soap/java/src/org/apache/soap/transport/http/SOA
> PHTTPConnection.java,v
> >   retrieving revision 1.28
> >   retrieving revision 1.29
> >   diff -u -r1.28 -r1.29
> >   --- SOAPHTTPConnection.java 16 Oct 2002 04:16:15 -0000 1.28
> >   +++ SOAPHTTPConnection.java 12 Nov 2002 14:15:38 -0000 1.29
> >   @@ -84,9 +84,7 @@
> >     * @author Arek Wnukowski (apache@wnuko.demon.co.uk)
> >     */
> >    public class SOAPHTTPConnection implements SOAPTransport {
> >   -  private BufferedReader responseReader;
> >   -  private Hashtable responseHeaders;
> >   -  private SOAPContext responseSOAPContext;
> >   +  private TransportMessage response;
> >
> >      private String httpProxyHost;
> >      private int    httpProxyPort = 80;
> >   @@ -369,7 +367,6 @@
> >                        "Basic " +
> > HTTPUtils.encodeAuth(proxyUserName, proxyPassword));
> >          }
> >
> >   -      TransportMessage response;
> >          try
> >          {
> >            TransportMessage msg = new
> > TransportMessage(payload, ctx, headers);
> >   @@ -385,18 +382,12 @@
> >            throw new IOException ("Failed to encode mime
> > multipart: " + uee);
> >          }
> >
> >   -      Reader envReader = response.getEnvelopeReader();
> >   -      if (envReader != null)
> >   -        responseReader = new BufferedReader(envReader);
> >   -      else
> >   -        responseReader = null;
> >   -      responseSOAPContext = response.getSOAPContext();
> >   -      responseHeaders = response.getHeaders();
> >          if (maintainSession) {
> >            // look for Set-Cookie2 and Set-Cookie headers and
> > save them.
> >            // Only update my state iff the header is there ..
> > otherwise
> >            // leave the current
> >            // Note: Header is case-insensitive
> >   +        Hashtable responseHeaders = response.getHeaders();
> >            String hdr;
> >
> >            hdr = HTTPUtils.getHeaderValue (responseHeaders,
> > "Set-Cookie2");
> >   @@ -421,8 +412,6 @@
> >          }
> >        } catch (IllegalArgumentException e) {
> >          throw new SOAPException
> > (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
> >   -    } catch (MessagingException e) {
> >   -      throw new SOAPException
> > (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
> >        } catch (IOException e) {
> >          throw new SOAPException
> > (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
> >        }
> >   @@ -436,7 +425,21 @@
> >       *         possible.
> >       */
> >      public BufferedReader receive () {
> >   -    return responseReader;
> >   +    if (response != null) {
> >   +      Reader envReader = response.getEnvelopeReader();
> >   +      if (envReader != null)
> >   +        return new BufferedReader(envReader);
> >   +    }
> >   +    return null;
> >   +  }
> >   +
> >   +  /**
> >   +   * Returns the SOAP envelope.
> >   +   *
> >   +   * @return The SOAP envelope.
> >   +   */
> >   +  public String getEnvelope() {
> >   +    return response != null ? response.getEnvelope() : null;
> >      }
> >
> >      /**
> >   @@ -445,7 +448,7 @@
> >       * @return a hashtable containing all the headers
> >       */
> >      public Hashtable getHeaders () {
> >   -    return responseHeaders;
> >   +    return response != null ? response.getHeaders() : null;
> >      }
> >
> >      /**
> >   @@ -454,6 +457,6 @@
> >       * @return response SOAPContext
> >       */
> >      public SOAPContext getResponseSOAPContext () {
> >   -    return responseSOAPContext;
> >   +    return response != null ? response.getSOAPContext() : null;
> >      }
> >    }
> >
> >
> >
> >
> > --
> > To unsubscribe, e-mail:
<ma...@xml.apache.org>
> > For additional commands, e-mail:
<ma...@xml.apache.org>
> >
>
> --
> To unsubscribe, e-mail:   <ma...@xml.apache.org>
> For additional commands, e-mail: <ma...@xml.apache.org>
>
>