tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r...@apache.org
Subject cvs commit: jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5 CoyoteReader.java InputBuffer.java CoyoteInputStream.java CoyoteRequest.java
Date Sun, 05 Jan 2003 11:24:23 GMT
remm        2003/01/05 03:24:23

  Modified:    coyote/src/java/org/apache/coyote/tomcat5
                        CoyoteInputStream.java CoyoteRequest.java
  Added:       coyote/src/java/org/apache/coyote/tomcat5 CoyoteReader.java
                        InputBuffer.java
  Log:
  - Implement more efficient input handling, similar to output.
  - InputStream functionality appears to work.
  - Reader handling is untested (so it probably doesn't work yet).
  - String BufferedReader.readLine() is not implemented yet.
  
  Revision  Changes    Path
  1.3       +13 -94    jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteInputStream.java
  
  Index: CoyoteInputStream.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteInputStream.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CoyoteInputStream.java	3 Oct 2002 17:20:52 -0000	1.2
  +++ CoyoteInputStream.java	5 Jan 2003 11:24:22 -0000	1.3
  @@ -60,57 +60,31 @@
   
   package org.apache.coyote.tomcat5;
   
  -import java.io.InputStream;
   import java.io.IOException;
   
   import javax.servlet.ServletInputStream;
   
  -import org.apache.tomcat.util.buf.ByteChunk;
  -
  -import org.apache.coyote.Request;
  -
   
   /**
  - * This class handles the readin input bytes, as well as the input buffering.
  + * This class handles reading bytes.
    * 
    * @author Remy Maucherat
    */
  -public class CoyoteInputStream extends ServletInputStream {
  +public class CoyoteInputStream
  +    extends ServletInputStream {
   
   
       // ----------------------------------------------------- Instance Variables
   
   
  -    private boolean closed = false;
  -
  -    private Request coyoteRequest;
  -
  -    private ByteChunk readChunk = new ByteChunk();
  -
  -    /**
  -     * Current read position in the byte buffer.
  -     */
  -    private int pos = -1;
  -    private int end = -1;
  -    private byte[] readBuffer = null;
  +    protected InputBuffer ib;
   
   
  -    // --------------------------------------------------------- Public Methods
  +    // ----------------------------------------------------------- Constructors
   
   
  -    void setRequest(Request coyoteRequest) {
  -        this.coyoteRequest = coyoteRequest;
  -    }
  -
  -
  -    /**
  -     * Recycle the input stream.
  -     */
  -    void recycle() {
  -        closed = false;
  -        pos = -1;
  -        end = -1;
  -        readBuffer = null;
  +    protected CoyoteInputStream(InputBuffer ib) {
  +        this.ib = ib;
       }
   
   
  @@ -119,56 +93,21 @@
   
       public int read()
           throws IOException {
  -
  -        if (closed)
  -            throw new IOException("Stream closed");
  -
  -        // Read additional bytes if none are available
  -        while (pos >= end) {
  -            if (readBytes() < 0)
  -                return -1;
  -        }
  -
  -        return (readBuffer[pos++] & 0xFF);
  -
  +        return ib.read();
       }
   
       public int available() throws IOException {
  -        if( pos < end ) return end-pos;
  -        return 0;
  +        return ib.available();
       }
   
       public int read(byte[] b) throws IOException {
  -
  -        return read(b, 0, b.length);
  -
  +        return ib.read(b, 0, b.length);
       }
   
   
       public int read(byte[] b, int off, int len)
           throws IOException {
  -
  -        if (closed)
  -            throw new IOException("Stream closed");
  -
  -        // Read additional bytes if none are available
  -        while (pos >= end) {
  -            if (readBytes() < 0)
  -                return -1;
  -        }
  -
  -        int n = -1;
  -        if ((end - pos) > len) {
  -            n = len;
  -        } else {
  -            n = end - pos;
  -        }
  -
  -        System.arraycopy(readBuffer, pos, b, off, n);
  -
  -        pos += n;
  -        return n;
  -
  +        return ib.read(b, off, len);
       }
   
   
  @@ -182,28 +121,8 @@
        * Since we re-cycle, we can't allow the call to super.close()
        * which would permantely disable us.
        */
  -    public void close() {
  -        closed = true;
  -    }
  -
  -
  -    // ------------------------------------------------------ Protected Methods
  -
  -
  -    /**
  -     * Read bytes to the read chunk buffer.
  -     */
  -    protected int readBytes()
  -        throws IOException {
  -
  -        int result = coyoteRequest.doRead(readChunk);
  -        if (result > 0) {
  -            readBuffer = readChunk.getBytes();
  -            end = readChunk.getEnd();
  -            pos = readChunk.getStart();
  -        }
  -        return result;
  -
  +    public void close() throws IOException {
  +        ib.close();
       }
   
   
  
  
  
  1.14      +17 -23    jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequest.java
  
  Index: CoyoteRequest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequest.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- CoyoteRequest.java	3 Jan 2003 19:31:54 -0000	1.13
  +++ CoyoteRequest.java	5 Jan 2003 11:24:22 -0000	1.14
  @@ -164,7 +164,7 @@
        */
       public void setCoyoteRequest(Request coyoteRequest) {
           this.coyoteRequest = coyoteRequest;
  -        inputStream.setRequest(coyoteRequest);
  +        inputBuffer.setRequest(coyoteRequest);
       }
   
       /**
  @@ -239,18 +239,22 @@
   
   
       /**
  -     * Reader.
  -     * Note: At the moment, no attempt is being made at recycling the reader,
  -     * but this could be implemented in the future, using a design like the one
  -     * used for the output buffer.
  +     * The associated input buffer.
        */
  -    protected BufferedReader reader = null;
  +    protected InputBuffer inputBuffer = new InputBuffer();
   
   
       /**
        * ServletInputStream.
        */
  -    protected CoyoteInputStream inputStream = new CoyoteInputStream();
  +    protected CoyoteInputStream inputStream = 
  +        new CoyoteInputStream(inputBuffer);
  +
  +
  +    /**
  +     * Reader.
  +     */
  +    protected BufferedReader reader = new CoyoteReader(inputBuffer);
   
   
       /**
  @@ -387,13 +391,12 @@
           wrapper = null;
   
           authType = null;
  +        inputBuffer.recycle();
           usingInputStream = false;
           usingReader = false;
           contextPath = "";
           pathInfo = null;
           servletPath = null;
  -        reader = null;
  -        inputStream.recycle();
           userPrincipal = null;
           sessionParsed = false;
           requestParametersParsed = false;
  @@ -1037,16 +1040,7 @@
                   (sm.getString("coyoteRequest.getReader.ise"));
   
           usingReader = true;
  -        if (reader == null) {
  -            String encoding = getCharacterEncoding();
  -            if (encoding == null) {
  -                encoding = 
  -                    org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
  -            }
  -            InputStreamReader r = new InputStreamReader(inputStream, encoding);
  -            reader = new BufferedReader(r);
  -        }
  -        return (reader);
  +        return reader;
   
       }
   
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteReader.java
  
  Index: CoyoteReader.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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.coyote.tomcat5;
  
  import java.io.BufferedReader;
  import java.io.IOException;
  
  
  /**
   * Coyote implementation of the buffred reader.
   * 
   * @author Remy Maucherat
   */
  final class CoyoteReader
      extends BufferedReader {
  
  
      // -------------------------------------------------------------- Constants
  
  
      private static final char[] LINE_SEP = { '\r', '\n' };
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      protected InputBuffer ib;
  
  
      // ----------------------------------------------------------- Constructors
  
  
      public CoyoteReader(InputBuffer ib) {
          super(ib);
          this.ib = ib;
      }
  
  
      // --------------------------------------------------------- Reader Methods
  
  
      public void close()
          throws IOException {
          ib.close();
      }
  
  
      public int read()
          throws IOException {
          return ib.read();
      }
  
  
      public int read(char[] cbuf)
          throws IOException {
          return ib.read(cbuf, 0, cbuf.length);
      }
  
  
      public int read(char[] cbuf, int off, int len)
          throws IOException {
          return ib.read(cbuf, off, len);
      }
  
  
      public long skip(long n)
          throws IOException {
          return ib.skip(n);
      }
  
  
      public boolean ready()
          throws IOException {
          return ib.ready();
      }
  
  
      public boolean markSupported() {
          return true;
      }
  
  
      public void mark(int readAheadLimit)
          throws IOException {
          ib.mark(readAheadLimit);
      }
  
  
      public void reset()
          throws IOException {
          ib.reset();
      }
  
  
      public String readLine()
          throws IOException {
          // FIXME
          return "";
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/InputBuffer.java
  
  Index: InputBuffer.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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.coyote.tomcat5;
  
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.Reader;
  import java.io.UnsupportedEncodingException;
  import java.util.Hashtable;
  
  import org.apache.tomcat.util.buf.B2CConverter;
  import org.apache.tomcat.util.buf.ByteChunk;
  import org.apache.tomcat.util.buf.CharChunk;
  
  import org.apache.coyote.Request;
  
  
  /**
   * The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3
   * OutputBuffer, adapted to handle input instead of output. This allows 
   * complete recycling of the facade objects (the ServletInputStream and the
   * BufferedReader).
   *
   * @author Remy Maucherat
   */
  public class InputBuffer extends Reader
      implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel,
                 CharChunk.CharOutputChannel {
  
  
      // -------------------------------------------------------------- Constants
  
  
      public static final String DEFAULT_ENCODING = 
          org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
      public static final int DEFAULT_BUFFER_SIZE = 8*1024;
      static final int debug = 0;
  
  
      // The buffer can be used for byte[] and char[] reading
      // ( this is needed to support ServletInputStream and BufferedReader )
      public final int INITIAL_STATE = 0;
      public final int CHAR_STATE = 1;
      public final int BYTE_STATE = 2;
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The byte buffer.
       */
      private ByteChunk bb;
  
  
      /**
       * The chunk buffer.
       */
      private CharChunk cb;
  
  
      /**
       * State of the output buffer.
       */
      private int state = 0;
  
  
      /**
       * Number of bytes read.
       */
      private int bytesRead = 0;
  
  
      /**
       * Number of chars read.
       */
      private int charsRead = 0;
  
  
      /**
       * Flag which indicates if the input buffer is closed.
       */
      private boolean closed = false;
  
  
      /**
       * Byte chunk used to input bytes.
       */
      private ByteChunk inputChunk = new ByteChunk();
  
  
      /**
       * Encoding to use.
       */
      private String enc;
  
  
      /**
       * Encoder is set.
       */
      private boolean gotEnc = false;
  
  
      /**
       * List of encoders.
       */
      protected Hashtable encoders = new Hashtable();
  
  
      /**
       * Current byte to char converter.
       */
      protected B2CConverter conv;
  
  
      /**
       * Associated Coyote request.
       */
      private Request coyoteRequest;
  
  
      /**
       * Buffer position.
       */
      private int markPos = -1;
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Default constructor. Allocate the buffer with the default buffer size.
       */
      public InputBuffer() {
  
          this(DEFAULT_BUFFER_SIZE);
  
      }
  
  
      /**
       * Alternate constructor which allows specifying the initial buffer size.
       * 
       * @param size Buffer size to use
       */
      public InputBuffer(int size) {
  
          bb = new ByteChunk(size);
          bb.setLimit(size);
          bb.setByteInputChannel(this);
          cb = new CharChunk(size);
          cb.setLimit(size);
          cb.setCharInputChannel(this);
          cb.setCharOutputChannel(this);
  
      }
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Associated Coyote request.
       * 
       * @param coyoteRequest Associated Coyote request
       */
      public void setRequest(Request coyoteRequest) {
  	this.coyoteRequest = coyoteRequest;
      }
  
  
      /**
       * Get associated Coyote request.
       * 
       * @return the associated Coyote request
       */
      public Request getRequest() {
          return this.coyoteRequest;
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Recycle the output buffer.
       */
      public void recycle() {
  
  	if (debug > 0)
              log("recycle()");
  
  	state = INITIAL_STATE;
  	bytesRead = 0;
  	charsRead = 0;
  
          cb.recycle();
          markPos = -1;
          bb.recycle(); 
          closed = false;
  
          if (conv != null) {
              conv.recycle();
          }
  
          gotEnc = false;
          enc = null;
  
      }
  
  
      /**
       * Close the input buffer.
       * 
       * @throws IOException An underlying IOException occurred
       */
      public void close()
          throws IOException {
          closed = true;
      }
  
  
      public int available()
          throws IOException {
          if (state == BYTE_STATE) {
              return bb.getLength();
          } else if (state == CHAR_STATE) {
              return cb.getLength();
          } else {
              return 0;
          }
      }
  
  
      // ------------------------------------------------- Bytes Handling Methods
  
  
      /** 
       * Reads new bytes in the byte chunk.
       * 
       * @param buf Byte buffer to be written to the response
       * @param off Offset
       * @param cnt Length
       * 
       * @throws IOException An underlying IOException occurred
       */
      public int realReadBytes(byte cbuf[], int off, int len)
  	throws IOException {
  
          if (debug > 2)
              log("realRead() " + coyoteRequest);
  
          if (closed)
              return -1;
          if (coyoteRequest == null)
              return -1;
  
          state = BYTE_STATE;
  
          int result = coyoteRequest.doRead(bb);
  
          return result;
  
      }
  
  
      public int readByte()
          throws IOException {
          return bb.substract();
      }
  
  
      public int read(byte[] b, int off, int len)
          throws IOException {
          return bb.substract(b, off, len);
      }
  
  
      // ------------------------------------------------- Chars Handling Methods
  
  
      /**
       * Since the converter will use append, it is possible to get chars to
       * be removed from the buffer for "writing". Since the chars have already
       * been read before, they are ignored. If a mark was set, then the
       * mark is lost.
       */
      public void realWriteChars(char c[], int off, int len) 
          throws IOException {
          markPos = -1;
      }
  
  
      public void setEncoding(String s) {
          enc = s;
      }
  
  
      public int realReadChars(char cbuf[], int off, int len)
          throws IOException {
  
          if (debug > 0)
              log("realRead() " + cb.getOffset() + " " + len);
  
          if (!gotEnc)
              setConverter();
  
          if (debug > 0)
              log("encoder:  " + conv + " " + gotEnc);
  
          if (bb.getLength() <= 0) {
              int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
              if (nRead < 0) {
                  return -1;
              } else {
                  bb.setBytes(bb.getBytes(), 0, nRead);
              }
          }
  
          if (markPos == -1) {
              cb.setChars(cb.getChars(), 0, 0);
          }
  
          conv.convert(bb, cb);
          state = CHAR_STATE;
  
          return cb.getLength();
  
      }
  
  
      public int read()
          throws IOException {
          return cb.substract();
      }
  
  
      public int read(char[] cbuf)
          throws IOException {
          return read(cbuf, 0, cbuf.length);
      }
  
  
      public int read(char[] cbuf, int off, int len)
          throws IOException {
          return cb.substract(cbuf, off, len);
      }
  
  
      public long skip(long n)
          throws IOException {
  
          if (n < 0) {
              throw new IllegalArgumentException();
          }
  
          long nRead = 0;
          while (nRead < n) {
              if (cb.getLength() > n) {
                  cb.setOffset(cb.getStart() + (int) n);
                  nRead = n;
              } else {
                  nRead += cb.getLength();
                  cb.setOffset(cb.getEnd());
                  int nb = realReadChars(cb.getChars(), 0, cb.getEnd());
                  if (nb < 0)
                      break;
              }
          }
  
          return nRead;
  
      }
  
  
      public boolean ready()
          throws IOException {
          return (cb.getLength() > 0);
      }
  
  
      public boolean markSupported() {
          return true;
      }
  
  
      public void mark(int readAheadLimit)
          throws IOException {
          cb.setLimit(cb.getEnd() + readAheadLimit);
          markPos = cb.getStart();
      }
  
  
      public void reset()
          throws IOException {
          bb.recycle();
          if (state == CHAR_STATE) {
              if (markPos < 0) {
                  cb.recycle();
                  markPos = -1;
                  throw new IOException("Mark not set"); //FIXME: i18n
              }
          }
          /*
          cb.recycle();
          gotEnc = false;
          enc = null;
          */
      }
  
  
      protected void setConverter() {
  
          if (coyoteRequest != null)
              enc = coyoteRequest.getCharacterEncoding();
  
          if (debug > 0)
              log("Got encoding: " + enc);
  
          gotEnc = true;
          if (enc == null)
              enc = DEFAULT_ENCODING;
          conv = (B2CConverter) encoders.get(enc);
          if (conv == null) {
              try {
                  conv = new B2CConverter(enc);
                  encoders.put(enc, conv);
              } catch (IOException e) {
                  conv = (B2CConverter) encoders.get(DEFAULT_ENCODING);
                  if (conv == null) {
                      try {
                          conv = new B2CConverter(DEFAULT_ENCODING);
                          encoders.put(DEFAULT_ENCODING, conv);
                      } catch (IOException ex) {
                          // Ignore
                      }
                  }
              }
          }
  
      }
  
  
      protected void log( String s ) {
  	System.out.println("InputBuffer: " + s);
      }
  
  
  }
  
  
  

--
To unsubscribe, e-mail:   <mailto:tomcat-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:tomcat-dev-help@jakarta.apache.org>


Mime
View raw message