You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@locus.apache.org on 2000/09/17 08:37:54 UTC

cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/modules/server Ajp12ConnectionHandler.java Ajp13ConnectionHandler.java Ajp13ConnectorRequest.java Ajp13ConnectorResponse.java HttpConnectionHandler.java HttpInterceptor.java HttpRequestAdapter.java HttpResponseAdapter.java JNIConnectionHandler.java JNIEndpoint.java MsgBuffer.java PoolTcpConnector.java TcpConnector.java package.html

costin      00/09/16 23:37:53

  Added:       src/share/org/apache/tomcat/modules/server
                        Ajp12ConnectionHandler.java
                        Ajp13ConnectionHandler.java
                        Ajp13ConnectorRequest.java
                        Ajp13ConnectorResponse.java
                        HttpConnectionHandler.java HttpInterceptor.java
                        HttpRequestAdapter.java HttpResponseAdapter.java
                        JNIConnectionHandler.java JNIEndpoint.java
                        MsgBuffer.java PoolTcpConnector.java
                        TcpConnector.java package.html
  Log:
  Added the new server adapters.
  
  The configuration is following the same rules as normal interceptors.
  All tcp based interceptors extend PoolTcpConnector.
  
  XXX need to test JNIEndpoint ( and change mod_jk to point to the new location)
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/Ajp12ConnectionHandler.java
  
  Index: Ajp12ConnectionHandler.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]
   *
   */
  
  
  /*
    Based on Ajp11ConnectionHandler and Ajp12 implementation of JServ
  */
  package org.apache.tomcat.modules.server;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.net.*;
  import org.apache.tomcat.util.*;
  import org.apache.tomcat.logging.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  /* Deprecated - must be rewriten to the connector model.
   */
  public class Ajp12ConnectionHandler extends PoolTcpConnector
      implements  TcpConnectionHandler
  {
      public Ajp12ConnectionHandler() {
  	super();
      }
      // -------------------- PoolTcpConnector --------------------
  
      protected void localInit() throws Exception {
  	ep.setConnectionHandler( this );
      }
  
      // -------------------- Handler implementation --------------------
  
      public Object[] init() {
  	Object thData[]=new Object[2];
  	AJP12RequestAdapter reqA=new AJP12RequestAdapter();
  	AJP12ResponseAdapter resA=new AJP12ResponseAdapter();
  	cm.initRequest( reqA, resA );
  	thData[0]=reqA;
  	thData[1]=resA;
  
  	return  thData;
      }
  
      public void setServer( Object cm ) {
  	this.cm=(ContextManager )cm;
      }
  
      public void processConnection(TcpConnection connection, Object[] thData) {
          try {
  	    // XXX - Add workarounds for the fact that the underlying
  	    // serverSocket.accept() call can now time out.  This whole
  	    // architecture needs some serious review.
  	    if (connection == null)
  		return;
  	    Socket socket=connection.getSocket();
  	    if (socket == null)
  		return;
  
  	    socket.setSoLinger( true, 100);
  	    //	    socket.setSoTimeout( 1000); // or what ?
  
  	    AJP12RequestAdapter reqA=null;
  	    AJP12ResponseAdapter resA=null;
  	    
  	    if( thData != null ) {
  		reqA=(AJP12RequestAdapter)thData[0];
  		resA=(AJP12ResponseAdapter)thData[1];
  		if( reqA!=null ) reqA.recycle();
  		if( resA!=null ) resA.recycle();
  	    }
  
  	    if( reqA==null || resA==null ) {
  		reqA = new AJP12RequestAdapter();
  		resA=new AJP12ResponseAdapter();
  		cm.initRequest( reqA, resA );
  	    }
  
  	    InputStream in=socket.getInputStream();
  	    OutputStream out=socket.getOutputStream();
  
  	    reqA.setSocket( socket);
  	    resA.setOutputStream(out);
  
  	    reqA.readNextRequest();
  	    if( reqA.isPing )
  		return;
  	    if( reqA.shutdown )
  		return;
  	    if (resA.getStatus() >= 400) {
  		resA.finish();
  		socket.close();
  		return;
  	    }
  
  	    cm.service( reqA, resA );
  	    //resA.finish(); // is part of contextM !
  	    socket.close();
  	} catch (Exception e) {
  	    log("HANDLER THREAD PROBLEM", e);
  	}
      }
  }
  
  class AJP12RequestAdapter extends Request {
      Socket socket;
      InputStream sin;
      BufferedInputStream ajpin;
      boolean shutdown=false;
      boolean isPing=false;
      boolean doLog;
  
      // Debug only - use only to debug this component
      void d( String s ) {
  	System.out.print("Ajp12RequestAdapter: ");
  	System.out.println( s );
      }
      
      public int doRead() throws IOException {
  	return ajpin.read();
      }
  
      public  int doRead( byte b[], int off, int len ) throws IOException {
  	return ajpin.read( b,off,len);
      }
  
      public AJP12RequestAdapter() {
      }
  
      public void setContextManager(ContextManager cm ) {
  	contextM=cm;
  	doLog=contextM.getDebug() > 10;
      }
  
      public void setSocket( Socket s ) throws IOException {
  	this.socket = s;
  	sin = s.getInputStream();
  	ajpin = new BufferedInputStream(sin);
      }
      
      public AJP12RequestAdapter(ContextManager cm, Socket s) throws IOException {
  	this.socket = s;
  	this.contextM=cm;
  	sin = s.getInputStream();
  	ajpin = new BufferedInputStream(sin);
  	doLog=contextM.getDebug() > 10;
      }
  
      protected void readNextRequest() throws IOException {
  	String dummy,token1,token2;
  	int marker;
  	int signal;
  //      Hashtable env_vars=new Hashtable();
  
  	try {
  	    boolean more=true;
              while (more) {
  		marker = ajpin.read();
  		switch (marker) {
  		case 0:       //NOP marker useful for testing if stream is OK
  		    break;
  		    
  		case 1: //beginning of request
  		    method = readString(ajpin, null);              //Method
  		    
  		    contextPath = readString(ajpin, null);               //Zone
  		    // GS, the following commented line causes the Apache + Jserv + Tomcat
  		    // combination to hang with a 404!!!
  		    // if("ROOT".equals( contextPath ) ) contextPath="";
  		    if("ROOT".equalsIgnoreCase( contextPath ) ) contextPath=null;
  		    if( doLog ) d("AJP: CP=" + contextPath);
  		    
  		    if( contextPath!= null )
  			context=contextM.getContext( contextPath );
  		    if( doLog ) d("AJP: context=" + context );
  		    
  		    servletName = readString(ajpin, null);         //Servlet
  		    if( doLog ) d("AJP: servlet=" + servletName );
  		    
  		    serverName = readString(ajpin, null);            //Server hostname
  		    if( doLog ) d("AJP: serverName=" + serverName );
  		    
  		    dummy = readString(ajpin, null);               //Apache document root
  		    
  		    pathInfo = readString(ajpin, null);               //Apache parsed path-info
  		    if( doLog ) d("AJP: PI=" + pathInfo );
  		    
  		    // XXX Bug in mod_jserv !!!!!
  		    pathTranslated = readString(ajpin, null);               //Apache parsed path-translated
  		    if( doLog ) d("AJP: PT=" + pathTranslated );
  		    
  		    queryString = readString(ajpin, null);         //query string
  		    if( doLog ) d("AJP: QS=" + queryString );
  		    
  		    remoteAddr = readString(ajpin, "");            //remote address
  		    if( doLog ) d("AJP: RA=" + remoteAddr );
  		    
  		    remoteHost = readString(ajpin, "");            //remote host
  		    if( doLog ) d("AJP: RH=" + remoteHost );
  		    
  		    remoteUser = readString(ajpin, null);                 //remote user
  		    if( doLog ) d("AJP: RU=" + remoteUser);
  		    
  		    authType = readString(ajpin, null);                 //auth type
  		    if( doLog ) d("AJP: AT=" + authType);
  		    
  		    dummy = readString(ajpin, null);                 //remote port
  		    
  		    method = readString(ajpin, null);                //request method
  		    if( doLog ) d("AJP: Meth=" + method );
  		    
  		    requestURI = readString(ajpin, "");             //request uri
  		    if( doLog ) d("AJP: URI: " + requestURI + " CP:" + contextPath + " LP: " + lookupPath);
  
  		    // XXX don't set lookup path - problems with URL rewriting.
  		    // need to be fixed.
  		    //		if(contextPath!=null && contextPath.length() >0 )
  		    //		    lookupPath=requestURI.substring( contextPath.length() + 1 );
  		    if( doLog ) d("AJP: URI: " + requestURI + " CP:" + contextPath + " LP: " + lookupPath);
  		    
  		    dummy = readString(ajpin, null);                   //script filename
  		    //		System.out.println("AJP: Script filen=" + dummy);
  		    
  		    dummy = readString(ajpin, null);                   //script name
  		    //		System.out.println("AJP: Script name=" + dummy);
  
  		    serverName = readString(ajpin, "");                //server name
  		    if( doLog ) d("AJP: serverName=" + serverName );
  		    try {
  			serverPort = Integer.parseInt(readString(ajpin, "80")); //server port
  		    } catch (Exception any) {
  			serverPort = 80;
  		    }
  
  		    dummy = readString(ajpin, "");                     //server protocol
  		    //		System.out.println("AJP: Server proto=" + dummy);
  		    dummy = readString(ajpin, "");                     //server signature
  		    //		System.out.println("AJP: Server sign=" + dummy);
  		    dummy = readString(ajpin, "");                     //server software
  		    //		System.out.println("AJP: Server softw=" + dummy);
  		    jvmRoute = readString(ajpin, "");                     //JSERV ROUTE
  		    if(jvmRoute.length() == 0) {
  			jvmRoute = null;
  		    }
  		    if( doLog ) d("AJP: Server jvmRoute=" + jvmRoute);
  
  
                      /**
                       * The two following lines are commented out because we don't
                       * want to depend on unreleased versions of the jserv module.
                       *                                            - costin
                       * The two following lines are uncommented because JServ 1.1 final
                       * is far behind.
                       * NB: you need a recent mod_jserv to use the latest protocol version.
                       * Theses env vars are simply ignored. (just here for compatibility)
                       *                                            - jluc
                       */
                       dummy = readString(ajpin, "");
                       dummy = readString(ajpin, "");
  		    // XXX all dummy fields will be used after core is changed to make use
  		    // of them!
  
  		    break;
  
  
                      /**
                       * Marker = 5 will be used by mod_jserv to send environment vars
                       * as key+value (dynamically configurable).
                       * can be considered as "reserved", and safely ignored by other connectors.
                       * env_vars is (above in this  code) commented out for performance issues.
                       * so theses env vars are simply ignored. (just here for compatibility)
                       * but it is where mod_jserv would place SSL_* env vars (by exemple)
                       * See the new parameter for mod_jserv (version > 1.1):
                       * ApJServEnvVar localname remotename
                       *                                            - jluc
                       */
                  case 5: // Environment vars
                      token1 = readString(ajpin, null);
                      token2 = readString(ajpin, "");
                      /*
                       * Env variables should go into the request attributes
                       * table. 
  					 *
  					 * Also, if one of the request attributes is HTTPS=on
                       * assume that there is an SSL connection.
  					 */
                      attributes.put(token1, token2);
                      if(token1.equals("HTTPS") && token2.equals("on")) {
                          setScheme("https");
                      }
                      break;
  
  		case 3: // Header
  		    token1 = readString(ajpin, null);
  		    token2 = readString(ajpin, "");
  		    headers.addValue(token1).setString(token2);
  		    break;
  
  		case 254: // Signal
  		    signal = ajpin.read();
  
  		    if (signal == 0) { // PING implemented as signal
  			try {
  			    // close the socket connection after we send reply
  			    socket.getOutputStream().write(0); // PING reply
  			    sin.close();
  			} catch (IOException ignored) {
  			    contextM.log("Exception closing, ignored",  ignored);
  			}
                          isPing = true;
                          return;
  		    } else {
  			try {
  			    // close the socket connection before handling any signal
  			    // but get the addresses first so they are not corrupted
  			    InetAddress serverAddr = socket.getLocalAddress();
  			    InetAddress clientAddr = socket.getInetAddress();
  			    sin.close();
  			    if ( (signal== 15) &&
  				 isSameAddress(serverAddr, clientAddr) ) {
  				// Shutdown - probably apache was stoped with apachectl stop
  				contextM.stop();
  				// same behavior as in past, because it seems that
  				// stopping everything doesn't work - need to figure
  				// out what happens with the threads ( XXX )
  				System.exit(0);
  
  				shutdown=true;
  				return;
  			    }
  			} catch (Exception ignored) {
  			    contextM.log("Ignored exception processing signal " +
  			      signal, ignored);
  			}
  		    }
  		    return;
  		    
  		case 4:
  		case 255:
  		    more=false;
  		    break;
  		    
  		case -1:
  		    throw new java.io.IOException("Stream closed prematurely");
  		    
  		    
  		default:
  		    throw new java.io.IOException("Stream broken");
  		    
  		    
  		} // switch
              } // while
  	} catch (IOException ioe) {
  	    throw ioe;
          } catch (Exception e) {
  	    contextM.log("Uncaught exception handling request", e);
          }
  	
  	// REQUEST_URI includes query string
  	int indexQ=requestURI.indexOf("?");
  	int rLen=requestURI.length();
  	if ( (indexQ >-1) && ( indexQ  < rLen) ) {
  	    if(doLog) d("Orig QS " + queryString );
  	    queryString = requestURI.substring(indexQ + 1, requestURI.length());
  	    if(doLog) d("New QS " + queryString );
  	    requestURI = requestURI.substring(0, indexQ);
  	} 
  	
  	if( doLog ) d("Request: " + requestURI );
  	if( doLog ) d("Query: " + queryString );
  	// System.out.println("ENV: " + env_vars );
  	// 	System.out.println("HEADERS: " + headers_in );
  	// 	System.out.println("PARAMETERS: " + parameters );
  	
  
  	//processCookies();
  
  
  	// XXX
  	// detect for real whether or not we have more requests
  	// coming
  
  	// XXX
  	// Support persistent connection in AJP21
  	//moreRequests = false;
      }
  
      /**
       * Return <code>true</code> if the specified client and server addresses
       * are the same.  This method works around a bug in the IBM 1.1.8 JVM on
       * Linux, where the address bytes are returned reversed in some
       * circumstances.
       *
       * @param server The server's InetAddress
       * @param client The client's InetAddress
       */
      private boolean isSameAddress(InetAddress server, InetAddress client) {
  
  	// Compare the byte array versions of the two addresses
  	byte serverAddr[] = server.getAddress();
  	byte clientAddr[] = client.getAddress();
  	if (serverAddr.length != clientAddr.length)
  	    return (false);
  	boolean match = true;
  	for (int i = 0; i < serverAddr.length; i++) {
  	    if (serverAddr[i] != clientAddr[i]) {
  		match = false;
  		break;
  	    }
  	}
  	if (match)
  	    return (true);
  
  	// Compare the reversed form of the two addresses
  	for (int i = 0; i < serverAddr.length; i++) {
  	    if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i])
  		return (false);
  	}
  	return (true);
  
      }
  
      
      public int readWord(InputStream in ) throws java.io.IOException {
          int b1 = in.read();
          if( b1 == -1)
              return -1;
  
          int b2 = in.read();
          if ( b2==-1)
              return -1;
  
          return ((int)((b1 << 8) | b2)) & 0xffff;
      }
  
      // UTF8 is a strict superset of ASCII.
      final static String CHARSET = "UTF8";
  
      public String readString(InputStream in, String def) throws java.io.IOException {
          int len = readWord(in);
  
          if( len == 0xffff)
              return def;
  
          if( len == -1)
              throw new java.io.IOException("Stream broken");
  
          byte[] b = new byte[len];
          int p = 0;
          int r;
          while(p<len) {
              r = in.read(b,p, len - p);
              if( r< 0) {
                  throw new java.io.IOException("Stream broken, couldn't demarshal string :"+len+":"+p);
              }
              p = p+r;
          }
          return new String(b, CHARSET);
      }
  
  }
  
  
  // Ajp use Status: instead of Status
  class AJP12ResponseAdapter extends HttpResponseAdapter {
      /** Override setStatus
       */
      protected void sendStatus( int status, String message)  throws IOException {
  	printHead("Status: " );
  	printHead( String.valueOf( status ));
  	printHead( " " );
  	printHead( message );
  	printHead("\r\n");
  
  	// We set it here because we extend HttpResponseAdapter, and this is the
  	// method that is different. 
  	
  	// Servlet Engine header will be set per/adapter - smarter adapters will
  	// not send it every time ( have it in C side ), and we may also want
  	// to add informations about the adapter used 
  	if( request.getContext() != null)
  	    setHeader("Servlet-Engine", request.getContext().getEngineHeader());
  
      }
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/Ajp13ConnectionHandler.java
  
  Index: Ajp13ConnectionHandler.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/Ajp13ConnectionHandler.java,v 1.1 2000/09/17 06:37:52 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:52 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.net.*;
  import org.apache.tomcat.util.*;
  import org.apache.tomcat.logging.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  
  public class Ajp13ConnectionHandler extends PoolTcpConnector
      implements  TcpConnectionHandler
  {
      public static final byte JK_AJP13_FORWARD_REQUEST   = 2;
      public static final byte JK_AJP13_SHUTDOWN          = 7;
  
      public Ajp13ConnectionHandler()
      {
          super();
      }
  
      // -------------------- PoolTcpConnector --------------------
  
      protected void localInit() throws Exception {
  	ep.setConnectionHandler( this );
      }
  
      // -------------------- Handler implementation --------------------
      
      public Object[] init()
      {
          Object thData[]=new Object[3];
          Ajp13ConnectorRequest req=new Ajp13ConnectorRequest();
          Ajp13ConnectorResponse res=new Ajp13ConnectorResponse();
          cm.initRequest(req, res);
          thData[0]=req;
          thData[1]=res;
          thData[2]=new TcpConnector();
  
          return  thData;
      }
  
      // XXX
      //    Nothing overriden, right now AJPRequest implment AJP and read everything.
      //    "Shortcuts" to be added here ( Vhost and context set by Apache, etc)
      // XXX handleEndpoint( Endpoint x )
      public void processConnection(TcpConnection connection, Object thData[])
      {
          try {
              if(connection == null) {
                  return;
              }
              Socket socket = connection.getSocket();
              if(socket == null) {
                  return;
              }
  
              socket.setSoLinger( true, 100);
  
              TcpConnector con=null;
              Ajp13ConnectorRequest req=null;
              Ajp13ConnectorResponse res=null;
  
              if(thData != null) {
                  req = (Ajp13ConnectorRequest)thData[0];
                  res = (Ajp13ConnectorResponse)thData[1];
                  con = (TcpConnector)thData[2];
                  if(req != null) req.recycle();
                  if(res != null) res.recycle();
                  if(con != null) con.recycle();
              }
  
              if(req == null || res == null || con == null) {
                  req = new Ajp13ConnectorRequest();
                  res = new Ajp13ConnectorResponse();
                  con = new TcpConnector();
                  cm.initRequest( req, res );
              }
  
              con.setSocket(socket);
              res.setConnector(con);
              req.setConnector(con);
  
              boolean moreRequests = true;
              while(moreRequests) { // XXX how to exit ? // request.hasMoreRequests()) {
                  MsgBuffer msg = con.getMsgBuffer();
                  int err = con.receive(msg);
                  if(err < 0) {
                      //log("ERR rec " + err );
                      moreRequests=false;
                      break;
                  }
  
                  // XXX right now the only incoming packet is "new request"
                  // We need to deal with arbitrary calls
                  int type = (int)msg.getByte();
                  switch(type) {
                      
                      case JK_AJP13_FORWARD_REQUEST:
                          err = req.decodeRequest(msg);                
                          cm.service(req, res);
  
                          req.recycle();
                          res.recycle();                                                                    
                      break;
                      
                      case JK_AJP13_SHUTDOWN:
                          if(!doShutdown(con, 
                                         socket.getLocalAddress(),
  			                           socket.getInetAddress())) {
                              moreRequests = false;
                          }                        
                      break;
                  }                
              }
              log("Closing connection", Logger.DEBUG);
              socket.close();
          } catch (Exception e) {
  	    log("Processing connection " + connection, e);
          }
      }
  
      public void setServer(Object contextM)
      {
          this.cm=(ContextManager)contextM;
      }
      
      protected boolean doShutdown(TcpConnector con,
                                   InetAddress serverAddr,
                                   InetAddress clientAddr)
      {
          try {
  	    // close the socket connection before handling any signal
  	    // but get the addresses first so they are not corrupted			
  	    con.close();
              if(isSameAddress(serverAddr, clientAddr)) {
  		// Shutdown - probably apache was stoped with apachectl stop
  		cm.stop();
  		
  		// same behavior as in past, because it seems that
  		// stopping everything doesn't work - need to figure
  		// out what happens with the threads ( XXX )
  		System.exit(0);
  	    }
  	} catch(Exception ignored) {
  	    log("Ignored " + ignored);
  	}
  	log("Shutdown command ignored");
  	return false;
      }
      
      /**
       * Return <code>true</code> if the specified client and server addresses
       * are the same.  This method works around a bug in the IBM 1.1.8 JVM on
       * Linux, where the address bytes are returned reversed in some
       * circumstances.
       * <br>
       * Was copied from <code>Ajp12ConnectionHandler</code>
       * 
       * @param server The server's InetAddress
       * @param client The client's InetAddress
       */
      private boolean isSameAddress(InetAddress server, InetAddress client) {
  
  	    // Compare the byte array versions of the two addresses
  	    byte serverAddr[] = server.getAddress();
  	    byte clientAddr[] = client.getAddress();
  	    if (serverAddr.length != clientAddr.length)
  	        return (false);
  	    boolean match = true;
  	    for (int i = 0; i < serverAddr.length; i++) {
  	        if (serverAddr[i] != clientAddr[i]) {
  		        match = false;
  		        break;
  	        }
  	    }
  	    if(match)
  	        return (true);
  
  	    // Compare the reversed form of the two addresses
  	    for (int i = 0; i < serverAddr.length; i++) {
  	        if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i])
  		    return (false);
  	    }
  	    return (true);
      }
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/Ajp13ConnectorRequest.java
  
  Index: Ajp13ConnectorRequest.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/Ajp13ConnectorRequest.java,v 1.1 2000/09/17 06:37:52 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:52 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  public class Ajp13ConnectorRequest extends Request 
  {
  	public static final int  MAX_READ_SIZE = TcpConnector.MAX_PACKET_SIZE - 
  	                                         TcpConnector.H_SIZE - 
  	                                         2;
  	                                         
  	public static final byte JK_AJP13_GET_BODY_CHUNK = 6;
  	
      public static final byte SC_A_CONTEXT       = 1;
      public static final byte SC_A_SERVLET_PATH  = 2;
      public static final byte SC_A_REMOTE_USER   = 3;
      public static final byte SC_A_AUTH_TYPE     = 4;
      public static final byte SC_A_QUERY_STRING  = 5;
      public static final byte SC_A_JVM_ROUTE     = 6;
      public static final byte SC_A_SSL_CERT      = 7;
      public static final byte SC_A_SSL_CIPHER    = 8;
      public static final byte SC_A_SSL_SESSION   = 9;
      public static final byte SC_A_REQ_ATTRIBUTE = 10;
      public static final byte SC_A_ARE_DONE      = (byte)0xFF;
  
      public static final String []methodTransArray = {
          "OPTIONS",
          "GET",
          "HEAD",
          "POST",
          "PUT",
          "DELETE",
          "TRACE"
      };
      
      public static final String []headerTransArray = {
          "accept",
          "accept-charset",
          "accept-encoding",
          "accept-language",
          "authorization",
          "connection",
          "content-type",
          "content-length",
          "cookie",
          "cookie2",
          "host",
          "pragma",
          "referer",
          "user-agent"
      };
  
      TcpConnector con;
  
      byte []bodyBuff = new byte[MAX_READ_SIZE];
      int blen;
      int pos;
  
      public Ajp13ConnectorRequest() 
      {
          super();
      }
      
      protected int decodeRequest(MsgBuffer msg) throws IOException 
      {
          boolean isSSL = false;
          byte bsc;
          int  hCount = 0;
  
          /*
           * Read the method and translate it to a String
           */
          bsc        = msg.getByte();
          method     = methodTransArray[(int)bsc - 1];
          protocol   = msg.getString();
          requestURI = msg.getString();
          remoteAddr = msg.getString();
          remoteHost = msg.getString();
          serverName = msg.getString();
          serverPort = msg.getInt();
          bsc        = msg.getByte();
          if(bsc != 0) {
              isSSL = true;
          }
          hCount     = msg.getInt();
          for(int i = 0 ; i < hCount ; i++) {
              String hName = null;
  
              int isc = msg.peekInt();
              int hId = isc & 0x000000FF;
  
              isc &= 0x0000FF00;
              if(0x0000A000 == isc) {
                  msg.getInt();
                  hName = headerTransArray[hId - 1];
              } else {
                  hName = msg.getString().toLowerCase();
              }
  
              String hValue = msg.getString();
              headers.addValue( hName ).setString( hValue );
              //log( "Head: " + hName + "=" + hValue);
          }
  
          for(bsc = msg.getByte() ;
              bsc != SC_A_ARE_DONE ;
              bsc = msg.getByte()) {
              switch(bsc) {
                  case SC_A_CONTEXT      :
                      contextPath = msg.getString();
                  break;
  
                  case SC_A_SERVLET_PATH :
                      //log("SC_A_SERVLET_PATH not in use " + msg.getString());
                  break;
  
                  case SC_A_REMOTE_USER  :
                      remoteUser = msg.getString();
                  break;
  
                  case SC_A_AUTH_TYPE    :
                      authType = msg.getString();
                  break;
  
                  case SC_A_QUERY_STRING :
                      queryString = msg.getString();
                  break;
  
                  case SC_A_JVM_ROUTE    :
                      jvmRoute = msg.getString();
                  break;
  
                  case SC_A_SSL_CERT     :
                      isSSL = true;
  		            attributes.put("javax.servlet.request.X509Certificate",
  	                               msg.getString());
                  break;
  
                  case SC_A_SSL_CIPHER   :
                      isSSL = true;
  		            attributes.put("javax.servlet.request.cipher_suite",
  	                               msg.getString());
                  break;
  
                  case SC_A_SSL_SESSION  :
                      isSSL = true;
  		            attributes.put("javax.servlet.request.ssl_session",
  	                               msg.getString());
                  break;
  
                  case SC_A_REQ_ATTRIBUTE :
                      isSSL = true;
  		            attributes.put(msg.getString(), msg.getString());
                  break;
  
                  default:
                      return -1;
              }
          }
  
          if(isSSL) {
              setScheme("https");
          }
  
  	MessageBytes clB=headers.getValue("content-length");
          contentLength = (clB==null) ? -1 : clB.getInt();
      	if(contentLength > 0) {
      		/* Read present data */
      		int err = con.receive(msg);
              if(err < 0) {
              	return -1;
  			}
  
      		blen = msg.peekInt();
      		msg.getBytes(bodyBuff);
      	}
      
          return 0;
      }
      
      public int doRead() throws IOException 
      {
          if(pos > blen) {
              refeelReadBuffer();
          }
          return bodyBuff[pos++];
      }
      
      public int doRead(byte[] b, int off, int len) throws IOException 
      {
          // XXXXXX Stupid, but the whole thing must be rewriten ( see super()! )
          for(int i = off ; i < (len + off) ; i++) {
              int a = doRead();
              if(-1 == a) {
                  return i-off;
              }
              b[i] = (byte)a;
          }
          
          return len;
      }
      
      public void recycle() 
      {
          super.recycle();
          pos=0;
      }
      
      public void setConnector(TcpConnector con) 
      {
          this.con = con;
          pos = 0;
  	//        this.in = new BufferedServletInputStream(this);
      }   
      
      public void refeelReadBuffer() throws IOException 
      {
  		MsgBuffer msg = con.getMsgBuffer();
  		msg.appendByte(JK_AJP13_GET_BODY_CHUNK);
  		msg.appendInt(MAX_READ_SIZE);
  		con.send(msg);
  		
  		int err = con.receive(msg);
          if(err < 0) {
          	throw new IOException();
  		}
  
      	blen = msg.peekInt();
      	pos = 0;
      	msg.getBytes(bodyBuff);
      }    
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/Ajp13ConnectorResponse.java
  
  Index: Ajp13ConnectorResponse.java
  ===================================================================
  
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/Ajp13ConnectorResponse.java,v 1.1 2000/09/17 06:37:52 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:52 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  
  public class Ajp13ConnectorResponse extends Response 
  {
      public static final int  MAX_SEND_SIZE = TcpConnector.MAX_PACKET_SIZE - 
  	TcpConnector.H_SIZE - 4;
  	
      public static final byte JK_AJP13_SEND_BODY_CHUNK   = 3;
      public static final byte JK_AJP13_SEND_HEADERS      = 4;
      public static final byte JK_AJP13_END_RESPONSE      = 5;
      
      public static final int SC_RESP_CONTENT_TYPE        = 0xA001;
      public static final int SC_RESP_CONTENT_LANGUAGE    = 0xA002;
      public static final int SC_RESP_CONTENT_LENGTH      = 0xA003;
      public static final int SC_RESP_DATE                = 0xA004;
      public static final int SC_RESP_LAST_MODIFIED       = 0xA005;
      public static final int SC_RESP_LOCATION            = 0xA006;
      public static final int SC_RESP_SET_COOKIE          = 0xA007;
      public static final int SC_RESP_SET_COOKIE2         = 0xA008;
      public static final int SC_RESP_SERVLET_ENGINE      = 0xA009;
      public static final int SC_RESP_STATUS              = 0xA00A;
      public static final int SC_RESP_WWW_AUTHENTICATE    = 0xA00B;
      
      TcpConnector con;
  
      public Ajp13ConnectorResponse() 
      {
      }
  
      // XXX if more headers that MAX_SIZE, send 2 packets!   
      public void endHeaders() throws IOException 
      {
          super.endHeaders();
      
          if (request.getProtocol() == null) {
              return;
          }
      
          MsgBuffer msg=con.getMsgBuffer();
          msg.reset();
  
          msg.appendByte(JK_AJP13_SEND_HEADERS);
          msg.appendInt(getStatus());
          msg.appendString("");
          
          msg.appendInt(headers.size());
          
          Enumeration e = headers.names();
          while(e.hasMoreElements()) {
              String headerName = (String)e.nextElement();            
              int sc = headerNameToSc(headerName);
              if(-1 != sc) {
                  msg.appendInt(sc);
              } else {
                  msg.appendString(headerName);
              }
              msg.appendString(headers.getHeader(headerName));
          }
  
          msg.end();
          con.send(msg);
      } 
           
      public void finish() throws IOException 
      {
          super.finish();
          MsgBuffer msg = con.getMsgBuffer();
          msg.reset();
          msg.appendByte(JK_AJP13_END_RESPONSE);
          msg.appendByte((byte)1);        
          msg.end();
          con.send(msg);
      }
      
      protected int headerNameToSc(String name)
      {       
          switch(name.charAt(0)) {
  	case 'c':
  	case 'C':
  	    if(name.equalsIgnoreCase("Content-Type")) {
  		return SC_RESP_CONTENT_TYPE;
  	    } else if(name.equalsIgnoreCase("Content-Language")) {
  		return SC_RESP_CONTENT_LANGUAGE;
  	    } else if(name.equalsIgnoreCase("Content-Length")) {
  		return SC_RESP_CONTENT_LENGTH;
  	    }
              break;
              
  	case 'd':
  	case 'D':
  	    if(name.equalsIgnoreCase("Date")) {
                      return SC_RESP_DATE;
  	    }
              break;
              
  	case 'l':
  	case 'L':
  	    if(name.equalsIgnoreCase("Last-Modified")) {
  		return SC_RESP_LAST_MODIFIED;
  	    } else if(name.equalsIgnoreCase("Location")) {
  		return SC_RESP_LOCATION;
  	    }
              break;
  
  	case 's':
  	case 'S':
  	    if(name.equalsIgnoreCase("Set-Cookie")) {
  		return SC_RESP_SET_COOKIE;
  	    } else if(name.equalsIgnoreCase("Set-Cookie2")) {
  		return SC_RESP_SET_COOKIE2;
  	    }
              break;
              
  	case 'w':
  	case 'W':
  	    if(name.equalsIgnoreCase("WWW-Autheticate")) {
  		return SC_RESP_WWW_AUTHENTICATE;
  	    }
              break;          
          }
          
          return -1;
      }
      
      public void recycle() 
      {
          super.recycle();
      }
      
      public void setConnector(TcpConnector con) 
      {
          this.con = con;
      }
          
      public void doWrite(  byte b[], int off, int len) throws IOException 
      {
  	int sent = 0;
  	while(sent < len) {
  	    int to_send = len - sent;
  	    to_send = to_send > MAX_SEND_SIZE ? MAX_SEND_SIZE : to_send;
  	    
  	    MsgBuffer buf = con.getMsgBuffer();
  	    buf.reset();
  	    buf.appendByte(Ajp13ConnectorResponse.JK_AJP13_SEND_BODY_CHUNK);	        	
  	    buf.appendBytes(b, off + sent, to_send);	        
  	    con.send(buf);
  	    sent += to_send;
  	}
      }
      
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/HttpConnectionHandler.java
  
  Index: HttpConnectionHandler.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/HttpConnectionHandler.java,v 1.1 2000/09/17 06:37:52 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:52 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  import org.apache.tomcat.util.net.*;
  import org.apache.tomcat.logging.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  
  public class HttpConnectionHandler  implements  TcpConnectionHandler {
      
      boolean secure=false;
      ContextManager contextM;
      
      public HttpConnectionHandler() {
  	super();
      }
  
      public void setSecure( boolean b ) {
  	secure=b;
      }
      
      public void setAttribute(String name, Object value ) {
  	if("context.manager".equals(name) ) {
  	    setServer(value);
  	}
      }
      
      public void setServer( Object  contextM ) {
  	this.contextM=(ContextManager)contextM;
  	loghelper.setProxy(this.contextM.getLoggerHelper());
      }
  
      public Object[] init() {
  	if(reuse) return null;
  	Object thData[]=new Object[3];
  	HttpRequestAdapter reqA=new HttpRequestAdapter();
  	HttpResponseAdapter resA=new HttpResponseAdapter();
  	contextM.initRequest( reqA, resA );
  	thData[0]=reqA;
  	thData[1]=resA;
  	thData[2]=null;
  	return  thData;
      }
  
      //    static Vector pool=new Vector();
      Object pool[]=new Object[100]; // XXX 
      int pos=0;
      static boolean reuse=true;
  
      public void setReuse( boolean b ) {
  	reuse=b;
  	log("Reuse = " + b );
      }
      // XXX
      //    Nothing overriden, right now AJPRequest implment AJP and read everything.
      //    "Shortcuts" to be added here ( Vhost and context set by Apache, etc)
      // XXX handleEndpoint( Endpoint x )
      public void processConnection(TcpConnection connection, Object thData[]) {
  	Socket socket=null;
  	HttpRequestAdapter reqA=null;
  	HttpResponseAdapter resA=null;
  
  	//	log("New Connection");
  	try {
  	    // XXX - Add workarounds for the fact that the underlying
  	    // serverSocket.accept() call can now time out.  This whole
  	    // architecture needs some serious review.
  	    if (connection == null)
  		return;
  	    //	    System.out.print("1");
  	    socket=connection.getSocket();
  	    if (socket == null)
  		return;
  	    //	    System.out.print("2");
  	    InputStream in=socket.getInputStream();
  	    OutputStream out=socket.getOutputStream();
  	    if( thData != null ) {
  		reqA=(HttpRequestAdapter)thData[0];
  		resA=(HttpResponseAdapter)thData[1];
  		if( reqA!=null ) reqA.recycle();
  		if( resA!=null ) resA.recycle();
  		//		log("Request ID " + thData[2]);
  	    }
  	    // No thData - use Pool
  
  	    if( reuse && ( reqA==null || resA==null ) ) {
  		int myPos=-1;
  		synchronized( this ) {
  		    if( pos>0 ) {
  			pos--;
  			myPos=pos; // >=0
  			reqA =  (HttpRequestAdapter)pool[pos]; // (HttpRequestAdapter)pool.lastElement();
  			if( reqA==null )
  			    log("Get Obj " + pos + " " + reqA);
  			else
  			    resA= (HttpResponseAdapter)reqA.getResponse();
  		    }
  		}
  		if( reqA==null ) {
  		    //log("XXX REQUEST_IMPL new " + pool.size());
  		    reqA=new HttpRequestAdapter();
  		    resA=new HttpResponseAdapter();
  		    contextM.initRequest( reqA, resA );
  		} 
  		reqA.recycle();
  		resA.recycle();
  	    } 
  	    
  	    if( reqA==null || resA==null ) {	
  		//log("XXX NO POOL " );
  		reqA=new HttpRequestAdapter();
  		resA=new HttpResponseAdapter();
  		contextM.initRequest( reqA, resA );
  	    }
  	    
  	    reqA.setSocket( socket );
  	    resA.setOutputStream( out );
  
  	    reqA.readNextRequest(resA);
  	    if( secure ) {
  		reqA.setScheme( "https" );
  	    }
  	    
  	    contextM.service( reqA, resA );
  
  	    try {
                 InputStream is = socket.getInputStream();
                 int available = is.available ();
  	       
                 // XXX on JDK 1.3 just socket.shutdownInput () which
                 // was added just to deal with such issues.
  
                 // skip any unread (bogus) bytes
                 if (available > 1) {
                     is.skip (available);
                 }
  	    }catch(NullPointerException npe) {
  		// do nothing - we are just cleaning up, this is
  		// a workaround for Netscape \n\r in POST - it is supposed
  		// to be ignored
  	    }
  	}
  	catch(java.net.SocketException e) {
  	    // SocketExceptions are normal
  	    log( "SocketException reading request, ignored", null, Logger.INFORMATION);
  	    log( "SocketException reading request:", e, Logger.DEBUG);
  	}
  	catch (java.io.IOException e) {
  	    // IOExceptions are normal 
  	    log( "IOException reading request, ignored", null, Logger.INFORMATION);
  	    log( "IOException reading request:", e, Logger.DEBUG);
  	}
  	// Future developers: if you discover any other
  	// rare-but-nonfatal exceptions, catch them here, and log as
  	// above.
  	catch (Throwable e) {
  	    // any other exception or error is odd. Here we log it
  	    // with "ERROR" level, so it will show up even on
  	    // less-than-verbose logs.
  	    log( "Error reading request, ignored", e, Logger.ERROR);
  	} 
  	finally {
  	    // recycle kernel sockets ASAP
  	    try { if (socket != null) socket.close (); }
  	    catch (IOException e) { /* ignore */ }
          }
  	if( reuse ) {
  	    synchronized( this ) {
  		if( pos<pool.length && reqA!= null ) {
  		    //log("Set Obj " + pos + " " + reqA);
  		    pool[pos]= reqA ;
  		    pos++;
  		}
  	    }
  	}
  
  	//	System.out.print("6");
      }
  
      Logger.Helper loghelper = new Logger.Helper("tc_log", this);
      // note: as soon as we get a ContextManager, we start using its
      // log stream, see setServer()
  
      void log(String msg) {
  	loghelper.log(msg);
      }
  
      void log(String msg, Throwable t, int level) {
  	loghelper.log(msg,t,level);
      }
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/HttpInterceptor.java
  
  Index: HttpInterceptor.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.tomcat.modules.server;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  import org.apache.tomcat.util.net.*;
  import org.apache.tomcat.util.net.ServerSocketFactory;
  import org.apache.tomcat.logging.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  
  /** Standalone http.
   *
   *  Connector properties:
   *  - secure - will load a SSL socket factory and act as https server
   *
   *  Properties passed to the net layer:
   *  - timeout
   *  - backlog
   *  - address
   *  - port
   * Thread pool properties:
   *  - minSpareThreads
   *  - maxSpareThreads
   *  - maxThreads
   *  - poolOn
   * Properties for HTTPS:
   *  - keystore - certificates - default to ~/.keystore
   *  - keypass - password
   *  - clientauth - true if the server should authenticate the client using certs
   */
  public class HttpInterceptor extends PoolTcpConnector
      implements  TcpConnectionHandler
  {
      public HttpInterceptor() {
  	super();
      }
  
      // -------------------- PoolTcpConnector --------------------
  
      protected void localInit() throws Exception {
  	ep.setConnectionHandler( this );
      }
  
      // -------------------- Attributes --------------------
      // -------------------- Handler implementation --------------------
      public void setServer( Object o ) {
  	this.cm=(ContextManager)o;
      }
      
      public Object[] init() {
  	Object thData[]=new Object[3];
  	HttpRequestAdapter reqA=new HttpRequestAdapter();
  	HttpResponseAdapter resA=new HttpResponseAdapter();
  	cm.initRequest( reqA, resA );
  	thData[0]=reqA;
  	thData[1]=resA;
  	thData[2]=null;
  	return  thData;
      }
  
      public void processConnection(TcpConnection connection, Object thData[]) {
  	Socket socket=null;
  	HttpRequestAdapter reqA=null;
  	HttpResponseAdapter resA=null;
  
  	try {
  	    // XXX - Add workarounds for the fact that the underlying
  	    // serverSocket.accept() call can now time out.  This whole
  	    // architecture needs some serious review.
  	    if (connection == null)
  		return;
  
  	    socket=connection.getSocket();
  	    if (socket == null)
  		return;
  
  	    InputStream in=socket.getInputStream();
  	    OutputStream out=socket.getOutputStream();
  	    if( thData != null ) {
  		reqA=(HttpRequestAdapter)thData[0];
  		resA=(HttpResponseAdapter)thData[1];
  		if( reqA!=null ) reqA.recycle();
  		if( resA!=null ) resA.recycle();
  	    }
  
  	    if( reqA==null || resA==null ) {	
  		log("No thread data ??");
  		reqA=new HttpRequestAdapter();
  		resA=new HttpResponseAdapter();
  		cm.initRequest( reqA, resA );
  	    }
  	    
  	    reqA.setSocket( socket );
  	    resA.setOutputStream( out );
  
  	    reqA.readNextRequest(resA);
  	    if( secure ) {
  		reqA.setScheme( "https" );
  	    }
  	    
  	    cm.service( reqA, resA );
  
  	    try {
                 InputStream is = socket.getInputStream();
                 int available = is.available ();
  	       
                 // XXX on JDK 1.3 just socket.shutdownInput () which
                 // was added just to deal with such issues.
  
                 // skip any unread (bogus) bytes
                 if (available > 1) {
                     is.skip (available);
                 }
  	    }catch(NullPointerException npe) {
  		// do nothing - we are just cleaning up, this is
  		// a workaround for Netscape \n\r in POST - it is supposed
  		// to be ignored
  	    }
  	}
  	catch(java.net.SocketException e) {
  	    // SocketExceptions are normal
  	    log( "SocketException reading request, ignored", null, Logger.INFORMATION);
  	    log( "SocketException reading request:", e, Logger.DEBUG);
  	}
  	catch (java.io.IOException e) {
  	    // IOExceptions are normal 
  	    log( "IOException reading request, ignored", null, Logger.INFORMATION);
  	    log( "IOException reading request:", e, Logger.DEBUG);
  	}
  	// Future developers: if you discover any other
  	// rare-but-nonfatal exceptions, catch them here, and log as
  	// above.
  	catch (Throwable e) {
  	    // any other exception or error is odd. Here we log it
  	    // with "ERROR" level, so it will show up even on
  	    // less-than-verbose logs.
  	    log( "Error reading request, ignored", e, Logger.ERROR);
  	} 
  	finally {
  	    // recycle kernel sockets ASAP
  	    try { if (socket != null) socket.close (); }
  	    catch (IOException e) { /* ignore */ }
          }
      }
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/HttpRequestAdapter.java
  
  Index: HttpRequestAdapter.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/HttpRequestAdapter.java,v 1.1 2000/09/17 06:37:52 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:52 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.helper.*;
  import org.apache.tomcat.util.*;
  import org.apache.tomcat.logging.*;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  public class HttpRequestAdapter extends Request {
      static StringManager sm = StringManager.getManager("org.apache.tomcat.resources");
      private Socket socket;
      private boolean moreRequests = false;
      RecycleBufferedInputStream sin;
      byte[] buf;
      int bufSize=2048; // default
      int off=0;
      int count=0;
      public static final String DEFAULT_CHARACTER_ENCODING = "8859_1";
      
      Logger.Helper loghelper = new Logger.Helper("tc_log", this);
      
      public HttpRequestAdapter() {
          super();
  	buf=new byte[bufSize];
      }
  
      public void setSocket(Socket socket) throws IOException {
  	if( sin==null)
  	    sin = new RecycleBufferedInputStream ( socket.getInputStream());
  	else
  	    sin.setInputStream( socket.getInputStream());
          this.socket = socket;
      	moreRequests = true;
      }
  
      public void recycle() {
  	super.recycle();
  	off=0;
  	count=0;
  	if( sin!=null )  sin.recycle();
      }
      
      public Socket getSocket() {
          return this.socket;
      }
  
      public boolean hasMoreRequests() {
          return moreRequests;
      }
      
      public int doRead() throws IOException {
  	return sin.read();
      }
  
      public int doRead(byte[] b, int off, int len) throws IOException {
  	return sin.read(b, off, len);
      }
  
      // cut&paste from ServletInputStream - but it's as inefficient as before
      public int readLine(InputStream in, byte[] b, int off, int len) throws IOException {
  
  	if (len <= 0) {
  	    return 0;
  	}
  	int count = 0, c;
  
  	while ((c = in.read()) != -1) {
  	    b[off++] = (byte)c;
  	    count++;
  	    if (c == '\n' || count == len) {
  		break;
  	    }
  	}
  	return count > 0 ? count : -1;
      }
      
  
      
      public void readNextRequest(Response response) throws IOException {
  
  	count = readLine(sin,buf, 0, buf.length);
  
  	if (count < 0 ) {
  	    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  	    return;
  	}
  	
  	processRequestLine(response  );
  
  	// for 0.9, we don't have headers!
  	if (protocol!=null) { // all HTTP versions with protocol also have headers ( 0.9 has no HTTP/0.9 !)
  	    readHeaders( headers, in  );
  	}
  
  	// XXX
  	// detect for real whether or not we have more requests
  	// coming
  	moreRequests = false;	
      }
  
  
      /**
       * Reads header fields from the specified servlet input stream until
       * a blank line is encountered.
       * @param in the servlet input stream
       * @exception IllegalArgumentException if the header format was invalid 
       * @exception IOException if an I/O error has occurred
       */
      public void readHeaders( MimeHeaders headers, ServletInputStream in )  throws IOException {
  	// use pre-allocated buffer if possible
  	off = count; // where the request line ended
  	
  	while (true) {
  	    int start = off;
  
  	    while (true) {
  		int len = buf.length - off;
  
  		if (len > 0) {
  		    len = readLine(sin,buf, off, len);
  
  		    if (len == -1) {
                          String msg =
                              sm.getString("mimeHeader.connection.ioe");
  
  			throw new IOException (msg);
  		    }
  		}
  
  		off += len;
  
  		if (len == 0 || buf[off-1] == '\n') {
  		    break;
  		}
  
  		// overflowed buffer, so temporarily expand and continue
  
  		// XXX DOS - if the length is too big - stop and throw exception
  		byte[] tmp = new byte[buf.length * 2];
  
  		System.arraycopy(buf, 0, tmp, 0, buf.length);
  		buf = tmp;
  	    }
  
  	    // strip off trailing "\r\n"
  	    if (--off > start && buf[off-1] == '\r') {
  		--off;
  	    }
  
  	    if (off == start) {
  		break;
  	    }
  	    
  	    // XXX this does not currently handle headers which
  	    // are folded to take more than one line.
  	    if( ! parseHeaderFiled(headers, buf, start, off - start) ) {
  		// error parsing header
  		return;
  	    }
  	}
      }
  
      /**
       * Parses a header field from a subarray of bytes.
       * @param b the bytes to parse
       * @param off the start offset of the bytes
       * @param len the length of the bytes
       * @exception IllegalArgumentException if the header format was invalid
       */
      public boolean parseHeaderFiled(MimeHeaders headers, byte[] b, int off,
  				    int len)
      {
  	int start = off;
  	byte c;
  
  	while ((c = b[off++]) != ':' && c != ' ') {
  	    if (c == '\n') {
  		loghelper.log("Parse error, empty line: " +
  			      new String( b, off, len ), Logger.ERROR);
  		return false;
  	    }
  	}
  
  	int nS=start;
  	int nE=off - start - 1;
  
  	while (c == ' ') {
  	    c = b[off++];
  	}
  
  	if (c != ':') {
  	    loghelper.log("Parse error, missing : in  " +
  			  new String( b, off, len ), Logger.ERROR);
  	    loghelper.log("Full  " + new String( b, 0, b.length ),
  			  Logger.ERROR);
  	    return false;
  	}
  
  	while ((c = b[off++]) == ' ');
  
  	headers.addValue( b, nS, nE).
  	    setBytes(b, off-1, len - (off - start - 1));
  	return true;
      }
  
      public int getServerPort() {
          return socket.getLocalPort();
      }
  
      public String getServerName() {
  	if(serverName!=null) return serverName;
  	
  	// XXX Move to interceptor!!!
  	String hostHeader = this.getHeader("host");
  	if (hostHeader != null) {
  	    int i = hostHeader.indexOf(':');
  	    if (i > -1) {
  		hostHeader = hostHeader.substring(0,i);
  	    }
  	    serverName=hostHeader;
  	    return serverName;
  	}
  
  	if (hostHeader == null) {
  		// XXX
  		// we need a better solution here
  		InetAddress localAddress = socket.getLocalAddress();
  		serverName = localAddress.getHostName();
  	}
  	return serverName;
      }
      
      
      public String getRemoteAddr() {
          return socket.getInetAddress().getHostAddress();
      }
      
      public String getRemoteHost() {
  	return socket.getInetAddress().getHostName();
      }    
  
      /** Advance to first non-whitespace
       */
      private  final int skipSpaces() {
  	while (off < count) {
  	    if ((buf[off] != (byte) ' ') 
  		&& (buf[off] != (byte) '\t')
  		&& (buf[off] != (byte) '\r')
  		&& (buf[off] != (byte) '\n')) {
  		return off;
  	    }
  	    off++;
  	}
  	return -1;
      }
  
      /** Advance to the first whitespace character
       */
      private  int findSpace() {
  	while (off < count) {
  	    if ((buf[off] == (byte) ' ') 
  		|| (buf[off] == (byte) '\t')
  		|| (buf[off] == (byte) '\r')
  		|| (buf[off] == (byte) '\n')) {
  		return off;
  	    }
  	    off++;
  	}
  	return -1;
      }
  
      /** Find a character, no side effects
       */
      private  int findChar( char c, int start, int end ) {
  	byte b=(byte)c;
  	int offset = start;
  	while (offset < end) {
  	    if (buf[offset] == b) {
  		return offset;
  	    }
  	    offset++;
  	}
  	return -1;
      }
  
      
      private void processRequestLine(Response response)
  	throws IOException
      {
  	off=0;
  
  	// if end of line is reached before we scan all 3 components -
  	// we're fine, off=count and remain unchanged
  	
  	if( buf[count-1]!= '\r' && buf[count-1]!= '\n' ) {
  	    response.setStatus(HttpServletResponse.SC_REQUEST_URI_TOO_LONG);
  	    return;
  	}	    
  	
  	int startMethod=skipSpaces();
  	int endMethod=findSpace();
  
  	int startReq=skipSpaces();
  	int endReq=findSpace();
  
  	int startProto=skipSpaces();
  	int endProto=findSpace();
  
  	if( startReq < 0   ) {
  	    // we don't have 2 "words", probably only method
  	    // startReq>0 => method is fine, request has at least one char
  	    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  	    return;
  	}
  
  	methodMB.setBytes( buf, startMethod, endMethod - startMethod );
  	method=null;
  	if( Ascii.toLower( buf[startMethod]) == 'g' ) {
  	    if( methodMB.equalsIgnoreCase( "get" ))
  		method="GET";
  	}
  	if( Ascii.toLower( buf[startMethod]) == 'p' ) {
  	    if( methodMB.equalsIgnoreCase( "post" ))
  		method="POST";
  	    if( methodMB.equalsIgnoreCase( "put" ))
  		method="PUT";
  	}
  
  	if( method==null )
  	    method= new String( buf, startMethod, endMethod - startMethod );
  
  	protocol=null;
  	if( endReq < 0 ) {
  	    endReq=count;
  	} else {
  	    if( startProto > 0 ) {
  		if( endProto < 0 ) endProto = count;
  		protoMB.setBytes( buf, startProto, endProto-startProto);
  		if( protoMB.equalsIgnoreCase( "http/1.0" ))
  		    protocol="HTTP/1.0";
  		if( protoMB.equalsIgnoreCase( "http/1.1" ))
  		    protocol="HTTP/1.1";
  		
  		if( protocol==null) 
  		    protocol=new String( buf, startProto, endProto-startProto );
  	    }
  	}
  
  	int qryIdx= findChar( '?', startReq, endReq );
  	if( qryIdx <0 ) {
  	    uriMB.setBytes(buf, startReq, endReq - startReq );
  	    //= new String( buf, startReq, endReq - startReq );
  	} else {
  	    uriMB.setBytes( buf, startReq, qryIdx - startReq );
  	    queryMB.setBytes( buf, qryIdx+1, endReq - qryIdx -1 );
  	}
  
  	// temp. fix until the rest of the code is changed
  	requestURI=uriMB.toString();
  	queryString=queryMB.toString();
  
  	// Perform URL decoding only if necessary
  	if ((uriMB.indexOf('%') >= 0) || (uriMB.indexOf('+') >= 0)) {
  
  	    try {
  		// XXX rewrite URLDecode to avoid allocation
  		requestURI = uriMB.toString();
  		requestURI = RequestUtil.URLDecode(requestURI);
  	    } catch (Exception e) {
  		response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  		return;
  	    }
  	}
  
  	//	loghelper.log("XXX " + method + " " + requestURI + " " + queryString + " " + protocol );
  
      }
  
      
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/HttpResponseAdapter.java
  
  Index: HttpResponseAdapter.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/HttpResponseAdapter.java,v 1.1 2000/09/17 06:37:53 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:53 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  import org.apache.tomcat.helper.*;
  import org.apache.tomcat.logging.*;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  // no "buffering" - we send the status and headers as soon as
  // the method is called.
  
  // this method is _not_ thread-safe. ( if 2 threads call ServletOutputStream.out
  
  /**
   */
  public class HttpResponseAdapter extends  Response {
      protected OutputStream sout;
  
      protected static final int DEFAULT_HEAD_BUFFER_SIZE = 1024;
      protected byte[] buffer = new byte[DEFAULT_HEAD_BUFFER_SIZE];
      protected int bufferCount = 0;
  
      Logger.Helper loghelper = new Logger.Helper("tc_log", this);
      
      public HttpResponseAdapter() {
          super();
      }
  
      public void recycle() {
  	super.recycle();
  	bufferCount=0;
      }
  
      public void setOutputStream(OutputStream os) {
  	sout = os;
      }
  
      static final byte CRLF[]= { (byte)'\r', (byte)'\n' };
      
      public void endHeaders()  throws IOException {
  	super.endHeaders();
  	
  	sendStatus( status, RequestUtil.getMessage( status ));
  
  	int count=headers.size();
  	for( int i=0; i<count; i++ ) {
  	    // response headers are set by the servlet, so probably we have only
  	    // Strings.
  	    // XXX date, cookies, etc shoud be extracted from response
  	    printHead( headers.getName( i ).toString() );
  	    printHead(": ");
  	    printHead( headers.getValue( i ).toString() );
  	    printHead("\r\n");
  	}
  	
  	printHead( "\r\n" );
  
  	sout.write( buffer, 0, bufferCount );
  	sout.flush();
      }
  
      /** Needed for AJP  support - the only difference between AJP response and
  	HTTP response is the status line
      */
      protected void sendStatus( int status, String message ) throws IOException {
  	printHead("HTTP/1.0 ");
  	switch( status ) {
  	case 200: printHead("200");
  	    break;
  	case 400: printHead("400");
  	    break;
  	case 404: printHead("404");
  	    break;
  	    
  	default:
  	    printHead(String.valueOf(status));
  	}
  	if(message!=null) {
  	    printHead(" ");
  	    printHead(message);
  	}
  	printHead("\r\n");
  	// Hack: set Date header.
  	// This method is overriden by ajp11, ajp12 - so date will not be set
  	// for any of those ( instead the server will generate the date )
  	// This avoids redundant setting of date ( very expensive ).
  	// XXX XXX Check if IIS, NES do generate the date
  	if( false ) {
  	    headers.setValue(  "Date" ).setTime( System.currentTimeMillis());
  	}
  	
  	// Servlet Engine header will be set per/adapter - smarter adapters will
  	// not send it every time ( have it in C side ), and we may also want
  	// to add informations about the adapter used 
  	if( request.getContext() != null)
  	    setHeader("Servlet-Engine", request.getContext().getEngineHeader());
      }
  
      public void doWrite( byte buffer[], int pos, int count) throws IOException {
  	sout.write( buffer, pos, count);
      }
  
      // From BufferedServletOutputStream
      // XXX will be moved in a new in/out system, temp. code
      // Right now it's not worse than BOS
      protected void printHead( String s ) {
  	if (s==null) s="null";
  
  	int len = s.length();
  	for (int i = 0; i < len; i++) {
  	    char c = s.charAt (i);
  	    
  	    //
  	    // XXX NOTE:  This is clearly incorrect for many strings,
  	    // but is the only consistent approach within the current
  	    // servlet framework.  It must suffice until servlet output
  	    // streams properly encode their output.
  	    //
  	    if ((c & 0xff00) != 0) {	// high order byte must be zero
  		// XXX will go away after we change the I/O system
  		loghelper.log("Header character is not iso8859_1, not supported yet: " + c, Logger.ERROR ) ;
  	    }
  	    if( bufferCount >= buffer.length ) {
  		byte bufferNew[]=new byte[ buffer.length * 2 ];
  		System.arraycopy( buffer,0, bufferNew, 0, buffer.length );
  		buffer=bufferNew;
  	    }
  	    buffer[bufferCount] = (byte)c;
  	    bufferCount++;
  	}
      }    
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/JNIConnectionHandler.java
  
  Index: JNIConnectionHandler.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/JNIConnectionHandler.java,v 1.1 2000/09/17 06:37:53 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:53 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import java.io.IOException;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  import org.apache.tomcat.helper.*;
  import javax.servlet.ServletInputStream;
  import java.util.Vector;
  import java.io.File;
  
  // we'll use the system.out/err until the code is stable, then
  // try to logger. Since this is a normal interceptor everything should
  // work
  
  /**
   * Connector for a JNI connections using the API in tomcat.service.
   * You need to set a "connection.handler" property with the class name of
   * the JNI connection handler
   * <br>
   * Based on <code>TcpEndpointConnector</code>
   *
   * @author Gal Shachor <sh...@il.ibm.com>
   */
  public class JNIConnectionHandler extends BaseInterceptor {
  
      public JNIConnectionHandler() {
      }
  
      // -------------------- Config -------------------- 
      boolean nativeLibLoaded=false;
      
      /** Location of the jni library
       */
      public void setNativeLibrary(String lib) {
          // First try to load from the library path
          try {
              System.loadLibrary(lib);
  	    nativeLibLoaded=true;
              System.out.println("Library " + lib +
  			       " was loaded from the lib path");
              return;
          } catch(UnsatisfiedLinkError usl) {
              //usl.printStackTrace();
              System.err.println("Failed to loadLibrary() " + lib);
          }
          
          // Loading from the library path failed
          // Try to load assuming lib is a complete pathname.
          try {
  	    System.load(lib);
  	    nativeLibLoaded=true;
  	    System.out.println("Library " + lib + " loaded");
              return;
          } catch(UnsatisfiedLinkError usl) {
              System.err.println("Failed to load() " + lib);
              //usl.printStackTrace();
          }
          
          // OK, try to load from the default libexec 
          // directory. 
          // libexec directory = tomcat.home + / + libexec
          File f = new File(System.getProperties().getProperty("tomcat.home"),
  			  "libexec");
  
  	String os=System.getProperty( "os.name" ).toLowerCase();
          if( os.indexOf("windows")>= 0) {
              f = new File(f, "jni_connect.dll");
          } else {
              f = new File(f, "jni_connect.so");
          }
          System.load(f.toString());
  	nativeLibLoaded=true;
          System.out.println("Library " + f.toString() + " loaded");
      }
  
      // ==================== hack for server startup  ====================
  
      // JNIEndpoint was called to start tomcat
      // Hack used to set the handler in JNIEndpoint.
      // This works - if we have problems we may take the time
      // and implement a better mechanism
      static JNIEndpoint ep;
      boolean running = true;
  
      public static void setEndpoint(JNIEndpoint jniep)
      {
          ep = jniep;
      }
  
      /** Called when the ContextManger is started
       */
      public void engineInit(ContextManager cm) throws TomcatException {
  	super.engineInit( cm );
  	if(! nativeLibLoaded ) {
  	    throw new TomcatException("Missing connector native library name");
  	}
  	try {
  	    // notify the jni side that jni is set up corectly
  	    ep.setConnectionHandler(this);
  	} catch( Exception ex ) {
  	    throw new TomcatException( ex );
  	}
      }
  
      public void engineShutdown(ContextManager cm) throws TomcatException {
  	try {
  	    // notify the jni side that the jni handler is no longer
  	    // in use ( we shut down )
  	    ep.setConnectionHandler(null);
  	} catch( Exception ex ) {
  	    throw new TomcatException( ex );
  	}
      }
  
      // ==================== callbacks from web server ====================
      
      static Vector pool=new Vector();
      static boolean reuse=true;
      /** Called from the web server for each request
       */
      public void processConnection(long s, long l) {
  	JNIRequestAdapter reqA=null;
  	JNIResponseAdapter resA=null;
  
          try {
  	    
  	    if( reuse ) {
  		synchronized( this ) {
  		    if( pool.size()==0 ) {
  			reqA=new JNIRequestAdapter( cm, this);
  			resA=new JNIResponseAdapter( this );
  			cm.initRequest( reqA, resA );
  		    } else {
  			reqA = (JNIRequestAdapter)pool.lastElement();
  			resA=(JNIResponseAdapter)reqA.getResponse();
  			pool.removeElement( reqA );
  		    }
  		}
  		reqA.recycle();
  		resA.recycle();
  	    } else  {
  		reqA = new JNIRequestAdapter(cm, this);
  		resA =new JNIResponseAdapter(this);
  		cm.initRequest( reqA , resA );
  	    }
  	    
              resA.setRequestAttr(s, l);
      	    reqA.readNextRequest(s, l);
  
  	    //     	    if(reqA.shutdown )
  	    //         		return;
      	    if(resA.getStatus() >= 400) {
          		resA.finish();
      		    return;
      	    }
  
      	    cm.service( reqA, resA );
      	} catch(Exception ex) {
      	    ex.printStackTrace();
      	}
  	if( reuse ) {
  	    synchronized( this ) {
  		pool.addElement( reqA );
  	    }
  	}
      }
  
      // -------------------- Native methods --------------------
      // Calls from tomcat to the web server
      
      native int readEnvironment(long s, long l, String []env);
  
      native int getNumberOfHeaders(long s, long l);
  
      native int readHeaders(long s,
                             long l,
                             String []names,
                             String []values);
  
      native int read(long s,
                      long l,
                      byte []buf,
                      int from,
                      int cnt);
  
      native int startReasponse(long s,
                                long l,
                                int sc,
                                String msg,
                                String []headerNames,
                                String []headerValues,
                                int headerCnt);
  
      native int write(long s,
                       long l,
                       byte []buf,
                       int from,
                       int cnt);
  }
  
  // ==================== Request/Response adapters ====================
  
  class JNIRequestAdapter extends Request {
      JNIConnectionHandler h;
      long s;
      long l;
  
      public JNIRequestAdapter(ContextManager cm,
                               JNIConnectionHandler h) {
      	this.contextM = cm;
      	this.h = h;
      }
  
      public  int doRead(byte b[], int off, int len) throws IOException {
          int rc = 0;
  
          while(0 == rc) {
  	        rc = h.read(s, l, b, off, len);
  	        if(0 == rc) {
  	            Thread.currentThread().yield();
  	        }
  	    }
  	    return rc;
      }
  
      protected void readNextRequest(long s, long l) throws IOException {
          String []env = new String[15];
          int i = 0;
  
      	this.s = s;
      	this.l = l;
  
          for(i = 0 ; i < 12 ; i++) {
              env[i] = null;
          }
  
          /*
           * Read the environment
           */
          if(h.readEnvironment(s, l, env) > 0) {
      		method      = env[0];
      		requestURI  = env[1];
      		queryString = env[2];
      		remoteAddr  = env[3];
      		remoteHost  = env[4];
      		serverName  = env[5];
              serverPort  = Integer.parseInt(env[6]);
              authType    = env[7];
              remoteUser  = env[8];
              schemeMB.setString(env[9]);
              protocol    = env[10];
              // response.setServerHeader(env[11]);
              
              if(schemeMB.equalsIgnoreCase("https")) {
                  if(null != env[12]) {
  		            attributes.put("javax.servlet.request.X509Certificate",
  	                               env[12]);
  	            }
  	            
                  if(null != env[13]) {
  		            attributes.put("javax.servlet.request.cipher_suite",
  	                               env[13]);
  	            }
  	            
                  if(null != env[14]) {
  		            attributes.put("javax.servlet.request.ssl_session",
  	                               env[14]);
  	            }
              }
              
              
          } else {
              throw new IOException("Error: JNI implementation error");
          }
  
          /*
           * Read the headers
           */
          int nheaders = h.getNumberOfHeaders(s, l);
          if(nheaders > 0) {
              String []names = new String[nheaders];
              String []values = new String[nheaders];
              if(h.readHeaders(s, l, names, values) > 0) {
                  for(i = 0 ; i < nheaders ; i++) {
                      headers.addValue(names[i]).setString(values[i]);
                  }
              } else {
                  throw new IOException("Error: JNI implementation error");
              }
          }
  
  	    // REQUEST_URI may include a query string
  	    int idQ= requestURI.indexOf("?");
  	    if ( idQ > -1) {
      	    requestURI = requestURI.substring(0, idQ);
          }
  
      }
  }
  
  
  // Ajp use Status: instead of Status
  class JNIResponseAdapter extends Response {
  
      JNIConnectionHandler h;
      long s;
      long l;
  
      public JNIResponseAdapter(JNIConnectionHandler h) {
      	this.h = h;
      }
  
      protected void setRequestAttr(long s, long l) throws IOException {
      	this.s = s;
      	this.l = l;
      }
  
      public void endHeaders() throws IOException {
  
      	if(request.getProtocol()==null) // HTTP/0.9 
  	        return;
  
          super.endHeaders();
          
  	// Servlet Engine header will be set per/adapter - smarter adapters
  	// will not send it every time ( have it in C side ), and we may also
  	// want to add informations about the adapter used 
  	// 	if( request.getContext() != null)
  	// 	    setHeader("Servlet-Engine",
  	// 		      request.getContext().getEngineHeader());
  
          int    hcnt = 0;
          String []headerNames = null;
          String []headerValues = null;
  	// Shouldn't be set - it's a bug if it is
          // headers.removeHeader("Status");
          hcnt = headers.size();
          headerNames = new String[hcnt];
          headerValues = new String[hcnt];
  
          for(int i = 0; i < hcnt; i++) {
              headerNames[i] = headers.getName(i).toString();
              headerValues[i] = headers.getValue(i).toString();
          }
  
          if(h.startReasponse(s, l, status,
  			    RequestUtil.getMessage(status),
  			    headerNames, headerValues, hcnt) <= 0) {
              throw new IOException("JNI startReasponse implementation error");
          }
      }
  
      public void doWrite(byte buf[], int pos, int count) throws IOException {
          if(h.write(s, l, buf, pos, count) <= 0) {
              throw new IOException("JNI implementation error");
          }
      }
  }
  
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/JNIEndpoint.java
  
  Index: JNIEndpoint.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/JNIEndpoint.java,v 1.1 2000/09/17 06:37:53 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:53 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import java.util.*;
  import java.io.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  
  /**
   * Handle incoming JNI connections. This class will be called from
   * native code to start tomcat and for each request. 
   *
   * @author Gal Shachor <sh...@il.ibm.com>
   */
  public class JNIEndpoint {
  
      JNIConnectionHandler handler;
  
      boolean running = false;
  
      // Note: I don't really understand JNI and its use of output
      // streams, but this should really be changed to use
      // tomcat.logging.Logger and not merely System.out  -Alex
      
      public JNIEndpoint() {
      }
  
      // -------------------- Configuration --------------------
  
      // Called back when the server is initializing the handler
      public void setConnectionHandler(JNIConnectionHandler handler ) {
  	this.handler=handler;
  	// the handler is no longer useable
      	if( handler==null ) {
  	    running=false;
  	    notify();
  	    return;
  	}
  
  	System.out.println("Running ...");
  	running=true;
          notify();
      }
  
      // -------------------- JNI Entry points
  
      /** Called by JNI to start up tomcat.
       */
      public int startup(String cmdLine,
                         String stdout,
                         String stderr)
      {
          try {
              if(null != stdout) {
                  System.setOut(new PrintStream(new FileOutputStream(stdout)));
              }
              if(null != stderr) {
                  System.setErr(new PrintStream(new FileOutputStream(stderr)));
              }
          } catch(Throwable t) {
          }
  
  	// We need to make sure tomcat did start successfully and
  	// report this back.
          try {
              JNIConnectionHandler.setEndpoint(this);
  	    // it will call back setHandler !!
              StartupThread startup = new StartupThread(cmdLine,
                                                        this);
              startup.start();
  	    System.out.println("Starting up StartupThread");
              synchronized (this) {
                  wait(60*1000);
              }
  	    System.out.println("End waiting");
          } catch(Throwable t) {
          }
  
          if(running) {
  	    System.out.println("Running fine ");
              return 1;
          }
  	System.out.println("Error - why doesn't run ??");
          return 0;
      }
  
      /** Called by JNI when a new request is received.
       */
      public int service(long s, long l)
      {
          if(running) {
              try {
                  handler.processConnection(s, l);
                  return 1;
              } catch(Throwable t) {
                  // Throwables are not allowed into the native code !!!
              }
          }
          return 0;
      }
  
      public void shutdown()
      {
          System.out.println("JNI In shutdown");
      }
  }
  
  /** Tomcat is started in a separate thread. It may be loaded on demand,
      and we can't take up the request thread, as it may be affect the server.
  
      During startup the JNIConnectionHandler will be initialized and
      will configure JNIEndpoint ( static - need better idea )
   */
  class StartupThread extends Thread {
      String []cmdLine = null;
      JNIEndpoint jniEp = null;
  
      public StartupThread(String cmdLine,
                           JNIEndpoint jniEp) {
          this.jniEp = jniEp;
  
          if(null == cmdLine) {
          	this.cmdLine = new String[0];
          } else {
              Vector v = new Vector();
              StringTokenizer st = new StringTokenizer(cmdLine);
              while (st.hasMoreTokens()) {
                  v.addElement(st.nextToken());
              }
              this.cmdLine = new String[v.size()];
              v.copyInto(this.cmdLine);
          }
      }
  
      public void run() {
          boolean failed = true;
          try {
  	    System.out.println("Calling main" );
              org.apache.tomcat.startup.Tomcat.main(cmdLine);
  	    System.out.println("Main returned" );
              failed = false;
          } catch(Throwable t) {
              t.printStackTrace(); // OK
          } finally {
              if(failed) {
  		System.out.println("Failed ??");
  		// stopEndpoint();
              }
          }
      }
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/MsgBuffer.java
  
  Index: MsgBuffer.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/MsgBuffer.java,v 1.1 2000/09/17 06:37:53 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:53 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  //import org.apache.tomcat.server.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  // XXX check limits?
  
  
  /** Encapsulated messages passed between Tomcat and Web servers
   */
  public class MsgBuffer {
      byte buff[];
      int len;
      int pos;
      int maxlen;
  
      public MsgBuffer( int size ) {
  	buff=new byte[size];
  	maxlen=size;
      }
  
      public MsgBuffer( byte b[] ) {
  	buff=b;
  	maxlen=b.length;
      }
      
      public byte[] getBuff() {
  	return buff;
      }
  
      public void setBuff(byte[] b) {
  	buff=b;
  	maxlen = b.length;
      }
  
      public int getLen() {
  	return len;
      }
      
      public int getMaxLen() {
  	return maxlen;
      }
      
      /** Verify the buffer and read the len
       */
      public int checkIn() {
  	pos=4;
  	int mark=BuffTool.getInt( buff,0 );
  	len=BuffTool.getInt( buff,2 );
  	if( mark != 0x1234 ) {
  	    System.out.println("BAD packet " + mark);
  	    dump( "In: " );
  	    return -1;
  	}
  	return len;
      }
  
      public void reset() {
  	len=4;
  	pos=4;
  	buff[0]=(byte)'A';
  	buff[1]=(byte)'B';
      }
  
      public void end() {
  	len=pos;
  	setInt( 2, len-4 );
      }
      
      public void setInt(int bpos, int val ) {
  	BuffTool.addInt( buff, bpos, val );
      }
  
      public void appendByte( byte val ) {
  	buff[pos] = val;
  	pos++;
      }
  
      public void appendInt( int val ) {
  	BuffTool.addInt( buff, pos, val );
  	pos+=2;
      }
  
      public void appendString( String val ) {
  	pos=BuffTool.addString( buff, pos, val );
      }
  
      public void appendBytes( byte b[], int off, int len ) {
  	BuffTool.addInt( buff, pos, len );
  	pos+=2;
  	if( pos + len > buff.length ) {
  	    System.out.println("Buffer overflow " + buff.length + " " + pos + " " + len );
  	}
  	System.arraycopy( b, off, buff, pos, len);
  	buff[pos+len]=0;
  	pos+=len;
  	pos++;
      }
  
      public int getInt() {
  	int res=BuffTool.getInt( buff, pos );
  	pos+=2;
  	return res;
      }
  
      public int peekInt() {
  	return BuffTool.getInt( buff, pos );
      }
  
      public byte getByte() {
  	byte res = buff[pos];
  	pos++;
  	return res;
      }
  
      public byte peekByte() {
  	return buff[pos];
      }
  
      public String getString() throws java.io.UnsupportedEncodingException {
  	int ll= getInt();
  	if( (ll == 0xFFFF) || (ll==-1) ) {
  	    //	    System.out.println("null string " + ll);
  	    return null;
  	}
  	String s=BuffTool.getString( buff, pos, ll );
  	pos +=ll;
  	pos++;
  	return s;
      }
  
      public int getBytes(byte dest[]) {
  	int ll= getInt();
  	if( ll > buff.length ) {
  	    System.out.println("XXX Assert failed, buff too small ");
  	}
  	
  	if( (ll == 0xFFFF) || (ll==-1) ) {
  	    System.out.println("null string " + ll);
  	    return 0;
  	}
  
  	System.arraycopy( buff, pos,  dest, 0, ll );
  	pos +=ll;
  	pos++; // ??? 
  	return ll;
      }
  
      private String hex( int x ) {
  	//	    if( x < 0) x=256 + x;
  	String h=Integer.toHexString( x );
  	if( h.length() == 1 ) h = "0" + h;
  	return h.substring( h.length() - 2 );
      }
  
      private void hexLine( int start ) {
  	for( int i=start; i< start+16; i++ ) {
  	    System.out.print( hex( buff[i] ) + " ");
  	}
  	System.out.print(" | ");
  	for( int i=start; i< start+16; i++ ) {
  	    if( Character.isLetterOrDigit( (char)buff[i] ))
  		System.out.print( new Character((char)buff[i]) );
  	    else
  		System.out.print( "." );
  	}
  	System.out.println();
      }
      
      public void dump(String msg) {
  	System.out.println( msg + ": " + buff + " " + pos +"/" + len + "/" + maxlen );
  
  	for( int j=0; j<len + 16; j+=16 )
  	    hexLine( j );
  	
  	System.out.println();
      }
  
      
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/PoolTcpConnector.java
  
  Index: PoolTcpConnector.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.tomcat.modules.server;
  
  import org.apache.tomcat.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.net.*;
  import org.apache.tomcat.logging.*;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  
  
  /* Similar with MPM module in Apache2.0. Handles all the details related with
     "tcp server" functionality - thread management, accept policy, etc.
     It should do nothing more - as soon as it get a socket (
     and all socket options are set, etc), it just handle the stream
     to ConnectionHandler.processConnection. (costin)
  */
  
  
  
  /**
   * Connector for a TCP-based connector using the API in tomcat.service.
   * You need to set a "connection.handler" property with the class name of
   * the TCP connection handler
   *
   * @author costin@eng.sun.com
   * @author Gal Shachor [shachor@il.ibm.com]
   */
  public abstract class PoolTcpConnector extends BaseInterceptor
  {
      protected PoolTcpEndpoint ep;
      protected ServerSocketFactory socketFactory;
      // socket factory attriubtes ( XXX replace with normal setters ) 
      protected Hashtable attributes = new Hashtable();
      protected boolean enabled=true;
      protected boolean secure=false;
      
      public PoolTcpConnector() {
      	ep = new PoolTcpEndpoint();
      }
  
      // -------------------- Start/stop --------------------
  
      /** Called when the ContextManger is started
       */
      public void engineInit(ContextManager cm) throws TomcatException {
  	super.engineInit( cm );
  
  	try {
  	    localInit();
  	    if( socketFactory!=null ) {
  		Enumeration attE=attributes.keys();
  		while( attE.hasMoreElements() ) {
  		    String key=(String)attE.nextElement();
  		    Object v=attributes.get( key );
  		    socketFactory.setAttribute( key, v );
  		}
  	    }
  	    ep.startEndpoint();
  	    log( "Starting on " + ep.getPort() );
  	} catch( Exception ex ) {
  	    throw new TomcatException( ex );
  	}
      }
  
      public void engineShutdown(ContextManager cm) throws TomcatException {
  	try {
  	    ep.stopEndpoint();
  	} catch( Exception ex ) {
  	    throw new TomcatException( ex );
  	}
      }
  
      
      protected abstract void localInit() throws Exception;
      
  // 	//    	setTcpHandler();
  
  // 	// Pass attributes to the socket factory
  // 	attE=attributes.keys();
  // 	while( attE.hasMoreElements() ) {
  // 	    String key=(String)attE.nextElement();
  // 	    Object v=attributes.get( key );
  // 	    socketFactory.setAttribute( key, v );
  // 	}
  
  // 	ep.startEndpoint();
  
  // 	loghelper.log("Starting " + getExtension(con.getClass().getName())
  // 		      + " on " + ep.getPort());
  //     }
  
  //     public void setTcpHandler() throws Exception {
  //     	if(con==null)
  //     	    throw new Exception( "Invalid ConnectionHandler");
  // 	con.setServer( cm );
  // 	con.setAttribute("context.manager",cm ); // old mechanism
  
  
  // 	// Pass properties to the handler
  // 	Enumeration attE=attributes.keys();
  // 	while( attE.hasMoreElements() ) {
  // 	    String key=(String)attE.nextElement();
  // 	    Object v=attributes.get( key );
  // 	    con.setAttribute( key, v );
  // 	}
  // 	ep.setConnectionHandler( con );
  //     }
  
      // -------------------- Pool setup --------------------
  
      public void setPools( boolean t ) {
  	ep.setPoolOn(t);
      }
  
      public void setMaxThreads( int maxThreads ) {
  	ep.setMaxThreads(maxThreads);
      }
  
      public void setMaxSpareThreads( int maxThreads ) {
  	ep.setMaxSpareThreads(maxThreads);
      }
  
      public void setMinSpareThreads( int minSpareThreads ) {
  	ep.setMinSpareThreads(minSpareThreads);
      }
  
      // -------------------- Tcp setup --------------------
  
      public void setBacklog( int i ) {
  	ep.setBacklog(i);
      }
      
      public void setPort( int port ) {
  	ep.setPort(port);
      	//this.port=port;
      }
  
      public void setAddress(InetAddress ia) {
  	ep.setAddress( ia );
      }
  
      public void setHostName( String name ) {
  	// ??? Doesn't seem to be used in existing or prev code
  	// vhost=name;
      }
  
      public void setSocketFactory( String valueS ) {
  	try {
  	    socketFactory= string2SocketFactory( valueS );
  	    ep.setServerSocketFactory( socketFactory );
  	}catch (Exception ex ) {
  	    ex.printStackTrace();
  	}
      }
  
      // -------------------- Getters --------------------
      
      public PoolTcpEndpoint getEndpoint() {
  	return ep;
      }
      
      public int getPort() {
      	return ep.getPort();
      }
  
      public InetAddress getAddress() {
  	return ep.getAddress();
      }
  
      // -------------------- SocketFactory attriubtes --------------------
      public void setKeystore( String k ) {
  	attributes.put( "keystore", k);
      }
  
      public void setKeyspass( String k ) {
  	attributes.put( "keypass", k);
      }
  
      public static final String SSL_CHECK=
  	"javax.net.ssl.SSLServerSocketFactory";
      public static final String SSL_FACT=
  	"org.apache.tomcat.util.net.SSLSocketFactory";
      
      
      public void setSecure( boolean b ) {
  	enabled=false;
  	secure=false;
  	if( b == true ) {
  	    // 	    if( keystore!=null && ! new File( keystore ).exists() ) {
  	    // 		log("Can't find keystore " + keystore );
  	    // 		return;
  	    // 	    }
  	    try {
  		Class c1=Class.forName( SSL_CHECK );
  	    } catch( Exception ex ) {
  		log( "Can't find JSSE, HTTPS will not be enabled");
  		return;
  	    }
  	    try {
  		Class chC=Class.forName( SSL_FACT );
  		socketFactory=(ServerSocketFactory)chC.newInstance();
  		ep.setServerSocketFactory( socketFactory );
  		log( "Setting ssl socket factory ");
  	    } catch(Exception ex ) {
  		log( "Error loading SSL socket factory ", ex);
  		return;
  	    }
  	}
      	secure=b;
  	enabled=true;
      }
      
      public void setAttribute( String prop, Object value) {
  	attributes.put( prop, value );
      }
  
  
      // -------------------- Handler ( deprecated ) --------------------
  //     String handlerClassName;
  //     TcpConnectionHandler con;
  
  //     public void setTcpConnectionHandler( TcpConnectionHandler handler) {
  //     	this.con=handler;
  //     }
  
  //     public void setTcpConnectionHandler( String s) {
  //     	this.con=string2ConnectionHandler( s );
  //     }
  
  //     public TcpConnectionHandler getTcpConnectionHandler() {
  // 	    return con;
  //     }
  
      // -------------------- Implementation methods --------------------
  
      // now they just throw exceptions, which are caught and logged by
      // the caller
  
  //     private static TcpConnectionHandler string2ConnectionHandler( String val)
  // 	throws ClassNotFoundException, IllegalAccessException,
  // 	InstantiationException
  //     {
  // 	Class chC=Class.forName( val );
  // 	return (TcpConnectionHandler)chC.newInstance();
  //     }
  
      private static ServerSocketFactory string2SocketFactory( String val)
  	throws ClassNotFoundException, IllegalAccessException,
  	InstantiationException
      {
  	Class chC=Class.forName( val );
  	return (ServerSocketFactory)chC.newInstance();
      }
  
      private static InetAddress string2Inet( String val)
  	throws UnknownHostException
      {
  	return InetAddress.getByName( val );
      }
      
      private static int string2Int( String val) {
  	return Integer.parseInt(val);
      }
  
  
      public static String getExtension( String classN ) {
  	int lidot=classN.lastIndexOf( "." );
  	if( lidot >0 ) classN=classN.substring( lidot + 1 );
  	return classN;
      }
  
  }
  
  
  
  
  
  
  
  
  
  
  // -- Removed code ( put it back if something goes wrong, remove it later)
  /*
    // Attributes we accept ( to support the old model of
      // configuration, will be deprecated )
      public static final String VHOST_PORT="vhost_port";
      public static final String VHOST_NAME="vhost_name";
      public static final String VHOST_ADDRESS="vhost_address";
      public static final String SOCKET_FACTORY="socketFactory";
  
  
      public static final String INET = "inet";
      public static final String PORT = "port";
      public static final String HANDLER = "handler";
  
  
      // Threading and mod_mpm style properties.
      public static final String THREAD_POOL = "thread_pool";
      public static final String MAX_THREADS = "max_threads";
      public static final String MAX_SPARE_THREADS = "max_spare_threads";
      public static final String MIN_SPARE_THREADS = "min_spare_threads";
      public static final String BACKLOG = "backlog";
  
      Object cm;
  
      ** Generic configure system - this allows Connector
       * 	configuration using name/value.
       *
       *  The "prefered" configuration is to call setters,
       * 	and tomcat using server.xml will do that, but
       *	this allows (minimal) integration with simpler
       *	systems.
       *
       *  Only a minimal number of properties can be set
       *  this way. This mechanism may be deprecated
       *  after we improve the startup system.
       *
       *  Supported attributes:
       *  "vhost_port" - port ( will act as a virtual host )
       *  "vhost_name" - virtual host name 
       *  "vhost_address" - virtual host binding address
       *  "socketFactory" - socket factory - for ssl.
       *  XXX add the others
       * 
       *  Note that the attributes are passed to the Endpoint.
       *
       public void setAttribute( String prop, Object value) {
  	if( debug > 0 ) 
  	    loghelper.log( "setAttribute( " + prop + " , " + value + ")");
  
  	try {
  	if( value instanceof String ) {
  	    String valueS=(String)value;
  	    
  	    if( PORT.equals(prop) ) {
  		setPort( valueS );
  	    } else if(HANDLER.equals(prop)) {
  		con=string2ConnectionHandler( valueS );
  	    } else if(THREAD_POOL.equals(prop)) {
  		usePools = ! valueS.equalsIgnoreCase("off");
  	    } else if(INET.equals(prop)) {
  		address=string2Inet( valueS );
  	    } else if( MAX_THREADS.equals(prop)) {
  		maxThreads = string2Int(valueS);
  	    } else if( MAX_SPARE_THREADS.equals(prop)) {
  		maxSpareThreads = string2Int(valueS);
  	    } else if( MIN_SPARE_THREADS.equals(prop)) {
  		minSpareThreads = string2Int(valueS);
  	    } else if(VHOST_NAME.equals(prop) ) {
  		vhost=valueS;
  	    } else if( BACKLOG.equals(prop)) {
  		backlog = string2Int(valueS);
  	    } else if(VHOST_PORT.equals(prop) ) {
  		port= string2Int( valueS );
  	    } else if(SOCKET_FACTORY.equals(prop)) {
  		socketFactory= string2SocketFactory( valueS );
  	    } else if(VHOST_ADDRESS.equals(prop)) {
  		address= string2Inet(valueS);
  	    } else {
  		if( valueS!=null)
  		    attributes.put( prop, valueS );
  	    }
  	} else {
  	    // Objects - avoids String-based "serialization" 
  	    if(VHOST_PORT.equals(prop) ) {
  		port=((Integer)value).intValue();
  	    } else if(VHOST_ADDRESS.equals(prop)) {
  		address=(InetAddress)value;
  	    } else if(SOCKET_FACTORY.equals(prop)) {
  		socketFactory=(ServerSocketFactory)value;
  	    } else {
  		if( value!=null)
  		    attributes.put( prop, value );
  	    }
  	}
  	}
  	catch (Exception e) {
  	    loghelper.log("setAttribute: " +prop + "=" + value, e, Logger.ERROR);
  	}
  	}
  
  	public void setProperty( String prop, String value) {
  	setAttribute( prop, value );
  	}
  
  
  	    // -------------------- Implementation methods --------------------
  
      public void setPort(  String portS ) {
  	this.port=string2Int( portS );
      }
  
      public void setAddress(String addressS) {
  	address= string2Inet( addressS );	
      }
  
  
  
  */
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/TcpConnector.java
  
  Index: TcpConnector.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/TcpConnector.java,v 1.1 2000/09/17 06:37:53 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/09/17 06:37:53 $
   *
   * ====================================================================
   *
   * 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.tomcat.modules.server;
  
  import org.apache.tomcat.service.*;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  import org.apache.tomcat.logging.*;
  //import org.apache.tomcat.server.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  class TcpConnector
  {
      public static final int MAX_PACKET_SIZE=8192;
      public static final int H_SIZE=4;
      OutputStream out;
      InputStream in;
      
      MsgBuffer msg;
      
      public TcpConnector() {
  	msg= new MsgBuffer( MAX_PACKET_SIZE );
      }
      
      public void setSocket( Socket socket ) throws IOException {
  	socket.setSoLinger( true, 100);
  	
  	out = socket.getOutputStream();
  	in = socket.getInputStream();
      }
  
      public void recycle() {
  
      }
      
      public MsgBuffer getMsgBuffer() {
  	msg.reset();
  	return msg;
      }
      
      public int receive(MsgBuffer msg) throws IOException {
  	// Read Packet
  
  	byte b[]=msg.getBuff();
  	
  	int rd=in.read( b, 0, H_SIZE );
  	if( rd<=0 ) {
  	    //	    System.out.println("Rd header returned: " + rd );
  	    return rd;
  	}
  	
  	int len=msg.checkIn();
  	
  	// XXX check if enough space - it's assert()-ed !!!
  	// Can we have only one read ( with unblocking, it can read all at once - but maybe more ) ?
  	//???	len-=4; // header
  
  	rd=in.read( b, 4, len );
  	if( rd != len ) {
  	    System.out.println( "Incomplete read, deal with it " + len + " " + rd);
  	    // ??? log
  	}
  	// 	msg.dump( "Incoming");
  	return rd;
  	//    System.out.println( "Incoming Packet len=" + len);
      }
  
      public void send( MsgBuffer msg ) throws IOException {
  	msg.end();
  	byte b[]=msg.getBuff();
  	int len=msg.getLen();
  	out.write( b, 0, len );
      }
      
      public void close() throws IOException {
  	if(null != out) {        
  	    out.close();
  	}
  	if(null !=in) {
  	    in.close();
  	}
      }
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/modules/server/package.html
  
  Index: package.html
  ===================================================================
  <html>
  <head>
  <title>Server connectors</title>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  </head>
  
  <body bgcolor="#FFFFFF">
  Interceptors that are used to connect with a web server, including the standalone http implementation.
  
  <h2>Todo</h2>
  
  <ul>
  <li>Refactor HTTP, AJP12, AJP13 so that the protocol implementation
   ( parsing, constants, etc) are separated from the Interceptor. 
  This will implement the design patterns used in interceptors and
  simplify portability.
  
  </ul>
  
  </body>
  </html>