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...@apache.org on 2001/06/23 21:04:35 UTC

cvs commit: jakarta-tomcat-connectors/jk/java/org/apache/ajp/tomcat33 Ajp13.java Ajp14.java Ajp14Interceptor.java

costin      01/06/23 12:04:35

  Modified:    jk/java/org/apache/ajp/tomcat33 Ajp13.java Ajp14.java
                        Ajp14Interceptor.java
  Log:
  Few fixes on Ajp14.
  
  First, added many comments and make sure Ajp14Interceptor is fine. I
  plan few more changes to make it clearer, but it should be fine for now
  ( it's probably better than existing code in 3.3 )
  
  Added few debug statements ( including display of the command name ).
  
  Started to add code from Ajp13, to avoid getting lost in inheritance.
  Ajp14 will replace Ajp13 completely, there are many improvements that need
  to be done to make ajp14 much faster and better.
  
  Right now I get a failure on reading the credentials, I'll fix it later
  this afternoon ( have to go now ).
  
  Revision  Changes    Path
  1.3       +2 -0      jakarta-tomcat-connectors/jk/java/org/apache/ajp/tomcat33/Ajp13.java
  
  Index: Ajp13.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/tomcat33/Ajp13.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Ajp13.java	2001/06/22 10:32:21	1.2
  +++ Ajp13.java	2001/06/23 19:04:34	1.3
  @@ -239,6 +239,7 @@
        */
       public int receiveNextRequest(Request req) throws IOException 
       {
  +	System.out.println("XXX");
   	// XXX The return values are awful.
   
   	int err = receive(hBuf);
  @@ -650,6 +651,7 @@
        * was an error.
        **/
       protected int receive(AjpPacket msg) throws IOException {
  +	System.out.println("YYYY");
   	// XXX If the length in the packet header doesn't agree with the
   	// actual number of bytes read, it should probably return an error
   	// value.  Also, callers of this method never use the length
  
  
  
  1.2       +264 -146  jakarta-tomcat-connectors/jk/java/org/apache/ajp/tomcat33/Ajp14.java
  
  Index: Ajp14.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/tomcat33/Ajp14.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Ajp14.java	2001/06/22 10:35:45	1.1
  +++ Ajp14.java	2001/06/23 19:04:34	1.2
  @@ -96,167 +96,183 @@
    */
   public class Ajp14 extends Ajp13
   {
  -	// AJP14 commands
  -
  - 	// Initial Login Phase (web server -> servlet engine)
  -	public static final byte JK_AJP14_LOGINIT_CMD			= 0x10;
  - 
  - 	// Second Login Phase (servlet engine -> web server), md5 seed is received
  -	public static final byte JK_AJP14_LOGSEED_CMD			= 0x11;
  - 
  -	// Third Login Phase (web server -> servlet engine), md5 of seed + secret is sent
  -	public static final byte JK_AJP14_LOGCOMP_CMD			= 0x12;
  -
  -	// Login Accepted (servlet engine -> web server)
  -	public static final byte JK_AJP14_LOGOK_CMD         	= 0x13;
  +    // Original AJP13 commands    
  +    // Prefix codes for message types from server to container
  +    public static final byte JK_AJP13_FORWARD_REQUEST   = 2;
  +    public static final byte JK_AJP13_SHUTDOWN          = 7;
  +	
  +    // Prefix codes for message types from container to server
  +    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 byte JK_AJP13_GET_BODY_CHUNK    = 6;
  +    
  +
  +
  +    // New AJP14 commands
  +    
  +    // Initial Login Phase (web server -> servlet engine)
  +    public static final byte JK_AJP14_LOGINIT_CMD			= 0x10;
  +    
  +    // Second Login Phase (servlet engine -> web server), md5 seed is received
  +    public static final byte JK_AJP14_LOGSEED_CMD			= 0x11;
  +    
  +    // Third Login Phase (web server -> servlet engine), md5 of seed + secret is sent
  +    public static final byte JK_AJP14_LOGCOMP_CMD			= 0x12;
  +    
  +    // Login Accepted (servlet engine -> web server)
  +    public static final byte JK_AJP14_LOGOK_CMD         	= 0x13;
   
  -	// Login Rejected (servlet engine -> web server), will be logged
  +    // Login Rejected (servlet engine -> web server), will be logged
   	public static final byte JK_AJP14_LOGNOK_CMD        	= 0x14;
  -
  - 	// Context Query (web server -> servlet engine), which URI are handled by servlet engine ?
  -	public static final byte JK_AJP14_CONTEXT_QRY_CMD		= 0x15;
  -
  - 	// Context Info (servlet engine -> web server), URI handled response
  -	public static final byte JK_AJP14_CONTEXT_INFO_CMD		= 0x16;
  -
  -	// Context Update (servlet engine -> web server), status of context changed
  -	public static final byte JK_AJP14_CONTEXT_UPDATE_CMD	= 0x17;
  -
  -	// Servlet Engine Status (web server -> servlet engine), what's the status of the servlet engine ?
  -	public static final byte JK_AJP14_STATUS_CMD			= 0x18;
  -
  -	// Secure Shutdown command (web server -> servlet engine), please servlet stop yourself.
  -	public static final byte JK_AJP14_SHUTDOWN_CMD			= 0x19;
  -
  -	// Secure Shutdown command Accepted (servlet engine -> web server)
  -	public static final byte JK_AJP14_SHUTOK_CMD			= 0x1A;
  -
  -	// Secure Shutdown Rejected (servlet engine -> web server)
  -	public static final byte JK_AJP14_SHUTNOK_CMD           = 0x1B;
  -
  -	// Context Status (web server -> servlet engine), what's the status of the context ?
  -	public static final byte JK_AJP14_CONTEXT_STATE_CMD     = 0x1C;
  -
  -	// Context Status Reply (servlet engine -> web server), status of context
  -	public static final byte JK_AJP14_CONTEXT_STATE_REP_CMD = 0x1D;
  -
  -	// Unknown Packet Reply (web server <-> servlet engine), when a packet couldn't be decoded
  -	public static final byte JK_AJP14_UNKNOW_PACKET_CMD     = 0x1E;
  -
  -	// Entropy Packet Size
  -	public static final int	 AJP14_ENTROPY_SEED_LEN 		= 32;
  -	public static final int	 AJP14_COMPUTED_KEY_LEN 		= 32;
  -
  -	// web-server want context info after login
  -	public static final int	 AJP14_CONTEXT_INFO_NEG			= 0x80000000;
  -
  -	// web-server want context updates
  -	public static final int	 AJP14_CONTEXT_UPDATE_NEG		= 0x40000000;
  -
  -	// web-server want compressed stream
  -	public static final int  AJP14_GZIP_STREAM_NEG			= 0x20000000;
  -
  -	// web-server want crypted DES56 stream with secret key
  -	public static final int  AJP14_DES56_STREAM_NEG      	= 0x10000000;
  -
  -	// Extended info on server SSL vars
  -	public static final int  AJP14_SSL_VSERVER_NEG			= 0x08000000;
  -
  -	// Extended info on client SSL vars
  -	public static final int  AJP14_SSL_VCLIENT_NEG			= 0x04000000;
  -
  -	// Extended info on crypto SSL vars
  -	public static final int	 AJP14_SSL_VCRYPTO_NEG			= 0x02000000;
  -
  -	// Extended info on misc SSL vars
  -	public static final int  AJP14_SSL_VMISC_NEG         	= 0x01000000;
  -
  -	// mask of protocol supported
  -	public static final int  AJP14_PROTO_SUPPORT_AJPXX_NEG  = 0x00FF0000;
  -
  -	// communication could use AJP14
  -	public static final int  AJP14_PROTO_SUPPORT_AJP14_NEG  = 0x00010000;
  -
  -	// communication could use AJP15
  -	public static final int  AJP14_PROTO_SUPPORT_AJP15_NEG  = 0x00020000;
  -
  -	// communication could use AJP16
  -	public static final int  AJP14_PROTO_SUPPORT_AJP16_NEG  = 0x00040000;
  -
  -	// Some failure codes
  -	public static final int  AJP14_BAD_KEY_ERR				 = 0xFFFFFFFF;
  -	public static final int  AJP14_ENGINE_DOWN_ERR           = 0xFFFFFFFE;
  -	public static final int  AJP14_RETRY_LATER_ERR           = 0xFFFFFFFD;
  -	public static final int  AJP14_SHUT_AUTHOR_FAILED_ERR    = 0xFFFFFFFC;
  -
  -	// Some status codes
  -	public static final byte AJP14_CONTEXT_DOWN       		 = 0x01;
  -	public static final byte AJP14_CONTEXT_UP         		 = 0x02;
  -	public static final byte AJP14_CONTEXT_OK         		 = 0x03;
  -
  -	// AJP14 new header
  +    
  +    // Context Query (web server -> servlet engine), which URI are handled by servlet engine ?
  +    public static final byte JK_AJP14_CONTEXT_QRY_CMD		= 0x15;
  +    
  +    // Context Info (servlet engine -> web server), URI handled response
  +    public static final byte JK_AJP14_CONTEXT_INFO_CMD		= 0x16;
  +    
  +    // Context Update (servlet engine -> web server), status of context changed
  +    public static final byte JK_AJP14_CONTEXT_UPDATE_CMD	= 0x17;
  +    
  +    // Servlet Engine Status (web server -> servlet engine), what's the status of the servlet engine ?
  +    public static final byte JK_AJP14_STATUS_CMD			= 0x18;
  +    
  +    // Secure Shutdown command (web server -> servlet engine), please servlet stop yourself.
  +    public static final byte JK_AJP14_SHUTDOWN_CMD			= 0x19;
  +    
  +    // Secure Shutdown command Accepted (servlet engine -> web server)
  +    public static final byte JK_AJP14_SHUTOK_CMD			= 0x1A;
  +    
  +    // Secure Shutdown Rejected (servlet engine -> web server)
  +    public static final byte JK_AJP14_SHUTNOK_CMD           = 0x1B;
  +    
  +    // Context Status (web server -> servlet engine), what's the status of the context ?
  +    public static final byte JK_AJP14_CONTEXT_STATE_CMD     = 0x1C;
  +    
  +    // Context Status Reply (servlet engine -> web server), status of context
  +    public static final byte JK_AJP14_CONTEXT_STATE_REP_CMD = 0x1D;
  +    
  +    // Unknown Packet Reply (web server <-> servlet engine), when a packet couldn't be decoded
  +    public static final byte JK_AJP14_UNKNOW_PACKET_CMD     = 0x1E;
  +
  +
  +    // -------------------- Other constants -------------------- 
  +
  +    // Entropy Packet Size
  +    public static final int	 AJP14_ENTROPY_SEED_LEN 		= 32;
  +    public static final int	 AJP14_COMPUTED_KEY_LEN 		= 32;
  +    
  +    // web-server want context info after login
  +    public static final int	 AJP14_CONTEXT_INFO_NEG			= 0x80000000;
  +    
  +    // web-server want context updates
  +    public static final int	 AJP14_CONTEXT_UPDATE_NEG		= 0x40000000;
  +    
  +    // web-server want compressed stream
  +    public static final int  AJP14_GZIP_STREAM_NEG			= 0x20000000;
  +    
  +    // web-server want crypted DES56 stream with secret key
  +    public static final int  AJP14_DES56_STREAM_NEG      	= 0x10000000;
  +    
  +    // Extended info on server SSL vars
  +    public static final int  AJP14_SSL_VSERVER_NEG			= 0x08000000;
  +    
  +    // Extended info on client SSL vars
  +    public static final int  AJP14_SSL_VCLIENT_NEG			= 0x04000000;
  +    
  +    // Extended info on crypto SSL vars
  +    public static final int	 AJP14_SSL_VCRYPTO_NEG			= 0x02000000;
  +    
  +    // Extended info on misc SSL vars
  +    public static final int  AJP14_SSL_VMISC_NEG         	= 0x01000000;
  +    
  +    // mask of protocol supported
  +    public static final int  AJP14_PROTO_SUPPORT_AJPXX_NEG  = 0x00FF0000;
  +    
  +    // communication could use AJP14
  +    public static final int  AJP14_PROTO_SUPPORT_AJP14_NEG  = 0x00010000;
  +    
  +    // communication could use AJP15
  +    public static final int  AJP14_PROTO_SUPPORT_AJP15_NEG  = 0x00020000;
  +    
  +    // communication could use AJP16
  +    public static final int  AJP14_PROTO_SUPPORT_AJP16_NEG  = 0x00040000;
  +    
  +    // Some failure codes
  +    public static final int  AJP14_BAD_KEY_ERR				 = 0xFFFFFFFF;
  +    public static final int  AJP14_ENGINE_DOWN_ERR           = 0xFFFFFFFE;
  +    public static final int  AJP14_RETRY_LATER_ERR           = 0xFFFFFFFD;
  +    public static final int  AJP14_SHUT_AUTHOR_FAILED_ERR    = 0xFFFFFFFC;
  +    
  +    // Some status codes
  +    public static final byte AJP14_CONTEXT_DOWN       		 = 0x01;
  +    public static final byte AJP14_CONTEXT_UP         		 = 0x02;
  +    public static final byte AJP14_CONTEXT_OK         		 = 0x03;
  +    
  +    // AJP14 new header
       public static final byte SC_A_SSL_KEY_SIZE  = 11;
   
       // ============ Instance Properties ====================
   
  -	// AJP14 
  -	boolean		logged 					= false;
  -	int			webserverNegociation	= 0;
  -	String		webserverName;
  -	String		seed;
  -	String		password;
  -
  +    // AJP14 
  +    boolean		logged 					= false;
  +    int			webserverNegociation	= 0;
  +    String		webserverName;
  +    String		seed;
  +    String		password;
  +    
       public Ajp14() 
       {
           super();
   		setSeed("myveryrandomentropy");
   		setPassword("myverysecretkey");
       }
  -
  -	public void initBuf()
  -	{	
  -		outBuf = new Ajp14Packet( headersWriter );
  -		inBuf  = new Ajp14Packet( MAX_PACKET_SIZE );
  -		hBuf   = new Ajp14Packet( MAX_PACKET_SIZE );
  -	}
   
  -	/**
  -	 * Set the original entropy seed
  +    public void initBuf()
  +    {	
  +	outBuf = new Ajp14Packet( headersWriter );
  +	inBuf  = new Ajp14Packet( MAX_PACKET_SIZE );
  +	hBuf   = new Ajp14Packet( MAX_PACKET_SIZE );
  +    }
  +    
  +    /**
  +     * Set the original entropy seed
        */
  -	public void setSeed(String pseed) 
  -	{
  -		String[] credentials = new String[1];
  -		credentials[0] = pseed;
  -		seed = digest(credentials, "md5");
  -	}
  -
  -	/**
  -	 * Get the original entropy seed
  -	 */
  -	public String getSeed()
  -	{
  -		return seed;
  -	}
  +    public void setSeed(String pseed) 
  +    {
  +	String[] credentials = new String[1];
  +	credentials[0] = pseed;
  +	seed = digest(credentials, "md5");
  +    }
   
  -	/**
  -	 * Set the secret password
  +    /**
  +     * Get the original entropy seed
        */
  -	public void setPassword(String ppwd) 
  -	{
  -		password = ppwd;
  -	}
  -
  -	/**
  -	 * Get the secret password
  -	 */
  -	public String getPassword()
  -	{
  -		return password;
  -	}
  +    public String getSeed()
  +    {
  +	return seed;
  +    }
   
  -	/**
  -	 * Compute a digest (MD5 in AJP14) for an array of String
  -	 */
  +    /**
  +     * Set the secret password
  +     */
  +    public void setPassword(String ppwd) 
  +    {
  +	password = ppwd;
  +    }
  +    
  +    /**
  +     * Get the secret password
  +     */
  +    public String getPassword()
  +    {
  +	return password;
  +    }
  +    
  +    /**
  +     * Compute a digest (MD5 in AJP14) for an array of String
  +     */
       public final static String digest(String[] credentials, String algorithm) {
           try {
               // Obtain a new message digest with MD5 encryption
  @@ -275,6 +291,8 @@
           }
       }
   
  +    
  +    
       /**
        * Read a new packet from the web server and decode it.  If it's a
        * forwarded request, store its properties in the passed-in Request
  @@ -289,13 +307,15 @@
       public int receiveNextRequest(Request req) throws IOException 
       {
   	// XXX The return values are awful.
  -
   	int err = receive(hBuf);
   	if(err < 0) {
  +	    if(debug >0 ) log( "Error receiving message ");
   	    return 500;
   	}
   	
   	int type = (int)hBuf.getByte();
  +	if( debug > 0 ) log( "Received " + type + " " + MSG_NAME[type]);
  +	
   	switch(type) {
   	    
   	case JK_AJP13_FORWARD_REQUEST:
  @@ -550,7 +570,65 @@
   		return 500; // Error
   	}
   
  +    // ========= Internal Packet-Handling Methods =================
  +
  +    /**
  +     * Read in a packet from the web server and store it in the passed-in
  +     * <CODE>Ajp13Packet</CODE> object.
  +     *
  +     * @param msg The object into which to store the incoming packet -- any
  +     * current contents will be overwritten.
  +     *
  +     * @return The number of bytes read on a successful read or -1 if there 
  +     * was an error.
  +     **/
  +    protected int receive(AjpPacket msg) throws IOException {
  +	// XXX If the length in the packet header doesn't agree with the
  +	// actual number of bytes read, it should probably return an error
  +	// value.  Also, callers of this method never use the length
  +	// returned -- should probably return true/false instead.
  +	byte b[] = msg.getBuff();
  +
  +	if( debug > 5 ) log( "Reading head " );
  +	int rd = in.read( b, 0, H_SIZE );
  +	if(rd <= 0) {
  +	    if( debug > 5 ) log( "Error reading " + rd );
  +	    return rd; 
  +	}
  +	if( debug > 5 ) log( "Read " + rd );
  +	
  +	int len = msg.checkIn();
  +	
  +	// XXX check if enough space - it's assert()-ed !!!
  +
  + 	int total_read = 0;
  +  	while (total_read < len) {
  +	    rd = in.read( b, 4 + total_read, len - total_read);
  +            if (rd == -1) {
  + 		System.out.println( "Incomplete read, deal with it " + len + " " + rd);
  +                break;
  +		// XXX log
  +		// XXX Return an error code?
  +	    }
  +     	    total_read += rd;
  +	}
  +	return total_read;
  +    }
  +
       /**
  +     * Send a packet to the web server.  Works for any type of message.
  +     *
  +     * @param msg A packet with accumulated data to send to the server --
  +     * this method will write out the length in the header.  
  +     */
  +    protected void send( AjpPacket msg ) throws IOException {
  +	msg.end(); // Write the packet header
  +	byte b[] = msg.getBuff();
  +	int len  = msg.getLen();
  +	out.write( b, 0, len );
  +    }
  +	
  +    /**
        * Close the socket connection to the web server.  In general, sockets
        * are maintained across many requests, so this will not be called
        * after finish().  
  @@ -566,5 +644,45 @@
   	}
   
   	logged = false;	// no more logged now 
  +    }
  +
  +
  +    
  +    // -------------------- Debugging --------------------
  +    // Very usefull for develoment
  +    
  +    // Debugging names
  +    public final String MSG_NAME[]={
  +	null, // 0
  +	null, // 1
  +	"JK_AJP13_FORWARD_REQUEST", // 2
  +	"JK_AJP13_SEND_BODY_CHUNK", // 3
  +	"JK_AJP13_SEND_HEADERS", // 4
  +	"JK_AJP13_END_RESPONSE", // 5
  +	"JK_AJP13_GET_BODY_CHUNK", // 6
  +	"JK_AJP13_SHUTDOWN", // 7
  +	null, null, null, null, // 8, 9, A, B
  +	null, null, null, null,
  +	"JK_AJP14_LOGINIT_CMD", // 0x10
  +	"JK_AJP14_LOGSEED_CMD", // 0x11
  +	"JK_AJP14_LOGCOMP_CMD", // 0x12
  +	"JK_AJP14_LOGOK_CMD", // 0x13
  +	"JK_AJP14_LOGNOK_CMD", // 0x14
  +	"JK_AJP14_CONTEXT_QRY_CMD", // 0x15
  +	"JK_AJP14_CONTEXT_INFO_CMD", // 0x16
  +	"JK_AJP14_CONTEXT_UPDATE_CMD", // 0x17
  +	"JK_AJP14_STATUS_CMD", // 0x18
  +	"JK_AJP14_SHUTDOWN_CMD", // 0x19
  +	"JK_AJP14_SHUTOK_CMD", // 0x1A
  +	"JK_AJP14_SHUTNOK_CMD", // 0x1B
  +	"JK_AJP14_CONTEXT_STATE_CMD ", // 0x1C
  +	"JK_AJP14_CONTEXT_STATE_REP_CMD ", // 0x1D
  +	"JK_AJP14_UNKNOW_PACKET_CMD " // 0x1E,
  +    };
  +
  +    
  +    private static int debug=10;
  +    void log(String s) {
  +	System.out.println("Ajp14: " + s );
       }
  -}
  + }
  
  
  
  1.2       +128 -79   jakarta-tomcat-connectors/jk/java/org/apache/ajp/tomcat33/Ajp14Interceptor.java
  
  Index: Ajp14Interceptor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/tomcat33/Ajp14Interceptor.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Ajp14Interceptor.java	2001/06/22 10:35:45	1.1
  +++ Ajp14Interceptor.java	2001/06/23 19:04:34	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/tomcat33/Ajp14Interceptor.java,v 1.1 2001/06/22 10:35:45 hgomez Exp $
  - * $Revision: 1.1 $
  - * $Date: 2001/06/22 10:35:45 $
  + * $Header: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/tomcat33/Ajp14Interceptor.java,v 1.2 2001/06/23 19:04:34 costin Exp $
  + * $Revision: 1.2 $
  + * $Date: 2001/06/23 19:04:34 $
    *
    * ====================================================================
    *
  @@ -71,81 +71,119 @@
   import org.apache.tomcat.util.*;
   import org.apache.tomcat.util.log.*;
   
  +/** Note. PoolTcpConnector is a convenience base class used for
  +    TCP-based connectors in tomcat33. It allows all those modules
  +    to share the thread pool and listener code.
  +
  +    In future it's likely other optimizations will be implemented in
  +    the PoolTcpConnector, so it's better to use it if you don't have
  +    a good reason not to ( like a connector for J2ME, where you want
  +    minimal footprint and don't care about high load )
  +*/
  +
  +/** Tomcat 33 module implementing the Ajp14 protocol.
  + *
  + *  The actual protocol implementation is in Ajp14.java, this is just an
  + *  adapter to plug it into tomcat.
  + */
   public class Ajp14Interceptor extends PoolTcpConnector
       implements  TcpConnectionHandler
   {
  +    int ajp14_note=-1;
  +    
       public Ajp14Interceptor()
       {
           super();
       }
   
  +    // initialization
  +    public void engineInit(ContextManager cm) throws TomcatException {
  +	super.engineInit( cm );
  +	ajp14_note=cm.getNoteId( ContextManager.REQUEST_NOTE, "ajp14" );
  +    }
  +
  +    // -------------------- Ajp14 specific parameters --------------------
  +
  +
  +    
       // -------------------- PoolTcpConnector --------------------
   
  +    /** Called by PoolTcpConnector to allow childs to init.
  +     */
       protected void localInit() throws Exception {
   	ep.setConnectionHandler( this );
       }
   
       // -------------------- Handler implementation --------------------
  -    
  +
  +    /*  The TcpConnectionHandler interface is used by the PoolTcpConnector to
  +     *  handle incoming connections.
  +     */
  +
  +    /** Called by the thread pool when a new thread is added to the pool,
  +	in order to create the (expensive) objects that will be stored
  +	as thread data.
  +	XXX we should use a single object, not array ( several reasons ),
  +	XXX Ajp14 should be storead as a request note, to be available in
  +	all modules
  +    */
       public Object[] init()
       {
  -        Object thData[]=new Object[3];
  -        Ajp14Request req=new Ajp14Request();
  -        Ajp14Response res=new Ajp14Response();
  -        cm.initRequest(req, res);
  -        thData[0]=req;
  -        thData[1]=res;
  -        thData[2]=new Ajp14();
  -
  -        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 )
  +        Object thData[]=new Object[1];
  +	thData[0]=initRequest( null );
  +	return thData;
  +    }
  +
  +    /** Construct the request object, with probably unnecesary
  +	sanity tests ( should work without thread pool - but that is
  +	not supported in PoolTcpConnector, maybe in future )
  +    */
  +    private Ajp14Request initRequest(Object thData[] ) {
  +	if( ajp14_note < 0 ) throw new RuntimeException( "assert: ajp14_note>0" );
  +	Ajp14Request req=null;
  +	if( thData != null ) {
  +	    req=(Ajp14Request)thData[0];
  +	}
  +	if( req != null ) {
  +	    Response res=req.getResponse();
  +	    req.recycle();
  +	    res.recycle();
  +	    // make the note available to other modules
  +	    req.setNote( ajp14_note, req.ajp14);
  +	    return req;
  +	}
  +	// either thData==null or broken ( req==null)
  +	Ajp14 ajp14=new Ajp14();
  +	req=new Ajp14Request(ajp14);
  +	Ajp14Response res=new Ajp14Response(ajp14);
  +	cm.initRequest(req, res);
  +	return  req;
  +    }
  +    
  +    /** Called whenever a new TCP connection is received. The connection
  +	is reused.
  +     */
       public void processConnection(TcpConnection connection, Object thData[])
       {
           try {
  -            if(connection == null) {
  -                return;
  -            }
               Socket socket = connection.getSocket();
  -            if(socket == null) {
  -                return;
  -            }
  -
  +	    // assert: socket!=null, connection!=null ( checked by PoolTcpEndpoint )
  +	    
               socket.setSoLinger( true, 100);
   
  -            Ajp14 con=null;
  -            Ajp14Request req=null;
  -            Ajp14Response res=null;
  -
  -            if(thData != null) {
  -                req = (Ajp14Request)thData[0];
  -                res = (Ajp14Response)thData[1];
  -                con = (Ajp14)thData[2];
  -                if(req != null) req.recycle();
  -                if(res != null) res.recycle();
  -                if(con != null) con.recycle();
  -            }
  +            Ajp14Request req=initRequest( thData );
  +            Ajp14Response res= (Ajp14Response)req.getResponse();
  +            Ajp14 ajp14=req.ajp14;
   
  -            if(req == null || res == null || con == null) {
  -                req = new Ajp14Request();
  -                res = new Ajp14Response();
  -                con = new Ajp14();
  -                cm.initRequest( req, res );
  -            }
  -	    // XXX
  -	    req.ajp14=con;
  -	    res.ajp14=con;
  -	    
  -            con.setSocket(socket);
  +            ajp14.setSocket(socket);
   
  +	    if( debug>0)
  +		log( "Received ajp14 connection ");
  +	    
               boolean moreRequests = true;
               while(moreRequests) {
  -		int status=req.receiveNextRequest();
  +		// first request should be the logon.
  +		int status=ajp14.receiveNextRequest( req );
   
   		if( status==-2) {
   		    // special case - shutdown
  @@ -158,26 +196,24 @@
   		}
   		
   		if( status  == 200)
  -			cm.service(req, res);
  -		else if (status == 500)
  -			break;
  -
  +		    cm.service(req, res);
  +		else if (status == 500) {
  +		    log( "Invalid request received " + req );
  +		    break;
  +		}
  +		
   		req.recycle();
   		res.recycle();
               }
  -            log("Closing connection", Log.DEBUG);
  -            con.close();
  +            if( debug > 0 ) log("Closing ajp14 connection");
  +            ajp14.close();
   	    socket.close();
           } catch (Exception e) {
   	    log("Processing connection " + connection, e);
           }
       }
   
  -    public void setServer(Object contextM)
  -    {
  -        this.cm=(ContextManager)contextM;
  -    }
  -    
  +    // We don't need to check isSameAddress if we authenticate !!!
       protected boolean doShutdown(InetAddress serverAddr,
                                    InetAddress clientAddr)
       {
  @@ -189,6 +225,9 @@
   		// same behavior as in past, because it seems that
   		// stopping everything doesn't work - need to figure
   		// out what happens with the threads ( XXX )
  +
  +		// XXX It should work now - but will fail if servlets create
  +		// threads
   		System.exit(0);
   	    }
   	} catch(Exception ignored) {
  @@ -197,23 +236,33 @@
   	log("Shutdown command ignored");
   	return false;
       }
  +
  +    // legacy, should be removed 
  +    public void setServer(Object contextM)
  +    {
  +        this.cm=(ContextManager)contextM;
  +    }
       
  +
   }
   
  +
  +//-------------------- Glue code for request/response.
  +// Probably not needed ( or can be simplified ), but it's
  +// not that bad.
  +
   class Ajp14Request extends Request 
   {
  -    Ajp14 ajp14=new Ajp14();
  -    
  -    public Ajp14Request() 
  -    {
  -        super();
  -    }
  +    Ajp14 ajp14;
       
  -    protected int receiveNextRequest() throws IOException 
  +    public Ajp14Request(Ajp14 ajp14) 
       {
  -	return ajp14.receiveNextRequest( this );
  +        this.ajp14=ajp14;
       }
  -    
  +
  +    // XXX This should go away if we introduce an InputBuffer.
  +    // We almost have it as result of encoding fixes, but for now
  +    // just keep this here, doesn't hurt too much.
       public int doRead() throws IOException 
       {
   	if( available <= 0 )
  @@ -243,21 +292,19 @@
       Ajp14 ajp14;
       boolean finished=false;
       
  -    public Ajp14Response() 
  +    public Ajp14Response(Ajp14 ajp14) 
       {
   	super();
  +	this.ajp14=ajp14;
       }
   
       public void recycle() {
   	super.recycle();
   	finished=false;
       }
  -
  -    public void setSocket( Socket s ) {
  -	ajp14=((Ajp14Request)request).ajp14;
  -    }
   
  -    // XXX if more headers that MAX_SIZE, send 2 packets!   
  +    // XXX if more headers that MAX_SIZE, send 2 packets!
  +    // XXX Can be implemented using module notification, no need to extend
       public void endHeaders() throws IOException 
       {
           super.endHeaders();
  @@ -268,7 +315,8 @@
   
   	ajp14.sendHeaders(getStatus(), getMimeHeaders());
       } 
  -         
  +
  +    // XXX Can be implemented using module notification, no need to extend
       public void finish() throws IOException 
       {
   	if(!finished) {
  @@ -277,7 +325,8 @@
   	    ajp14.finish();
   	}
       }
  -    
  +
  +    // XXX Can be implemented using the buffers, no need to extend
       public void doWrite(  byte b[], int off, int len) throws IOException 
       {
   	ajp14.doWrite(b, off, len );