costin 01/11/21 12:49:55 Modified: jk/java/org/apache/ajp Ajp13.java Ajp14.java AjpHandler.java NegociationHandler.java RequestHandler.java jk/java/org/apache/ajp/test TestAjp13.java jk/java/org/apache/ajp/tomcat33 Ajp14Interceptor.java Log: Removing a lot of duplicated code, update everything. I tested with both 4.0.1 and 3.3 - it seems to work fine with both 13 and 14, but I probably left few debug statements in. This is not 'complete', there are still many things to clean up and make sure we can use mod_jk ajp14 with both 13 and 14 servers and to start integrating the 1.4 callbacks into 4.0.1. Based on the feedback on the 'jk_handler' proposal, the code will be greatly simplified and enhanced in the next few weeks. Revision Changes Path 1.19 +118 -622 jakarta-tomcat-connectors/jk/java/org/apache/ajp/Ajp13.java Index: Ajp13.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/Ajp13.java,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- Ajp13.java 2001/10/10 06:35:22 1.18 +++ Ajp13.java 2001/11/21 20:49:54 1.19 @@ -103,15 +103,8 @@ public static final int MAX_SEND_SIZE = MAX_PACKET_SIZE - H_SIZE - 4; // 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; - // Error code for Ajp13 public static final int JK_AJP13_BAD_HEADER = -100; public static final int JK_AJP13_NO_HEADER = -101; @@ -120,109 +113,18 @@ public static final int JK_AJP13_BAD_BODY = -104; public static final int JK_AJP13_INCOMPLETE_BODY = -105; - // Integer codes for common response header strings - 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; - - // Integer codes for common (optional) request attribute names - public static final byte SC_A_CONTEXT = 1; // XXX Unused - public static final byte SC_A_SERVLET_PATH = 2; // XXX Unused - 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_SSL_KEYSIZE = 11; - - // Used for attributes which are not in the list above - public static final byte SC_A_REQ_ATTRIBUTE = 10; - - // Terminates list of attributes - public static final byte SC_A_ARE_DONE = (byte)0xFF; - - // Translates integer codes to names of HTTP methods - public static final String []methodTransArray = { - "OPTIONS", - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "TRACE", - "PROPFIND", - "PROPPATCH", - "MKCOL", - "COPY", - "MOVE", - "LOCK", - "UNLOCK", - "ACL", - "REPORT", - "VERSION-CONTROL", - "CHECKIN", - "CHECKOUT", - "UNCHECKOUT", - "SEARCH" - }; - - // id's for common request headers - public static final int SC_REQ_ACCEPT = 1; - public static final int SC_REQ_ACCEPT_CHARSET = 2; - public static final int SC_REQ_ACCEPT_ENCODING = 3; - public static final int SC_REQ_ACCEPT_LANGUAGE = 4; - public static final int SC_REQ_AUTHORIZATION = 5; - public static final int SC_REQ_CONNECTION = 6; - public static final int SC_REQ_CONTENT_TYPE = 7; - public static final int SC_REQ_CONTENT_LENGTH = 8; - public static final int SC_REQ_COOKIE = 9; - public static final int SC_REQ_COOKIE2 = 10; - public static final int SC_REQ_HOST = 11; - public static final int SC_REQ_PRAGMA = 12; - public static final int SC_REQ_REFERER = 13; - public static final int SC_REQ_USER_AGENT = 14; - - // Translates integer codes to request header names - 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" - }; - - // ============ Instance Properties ==================== OutputStream out; InputStream in; // Buffer used of output body and headers - Ajp13Packet outBuf = new Ajp13Packet( MAX_PACKET_SIZE ); + public Ajp13Packet outBuf = new Ajp13Packet( MAX_PACKET_SIZE ); // Buffer used for input body Ajp13Packet inBuf = new Ajp13Packet( MAX_PACKET_SIZE ); // Buffer used for request head ( and headers ) Ajp13Packet hBuf=new Ajp13Packet( MAX_PACKET_SIZE ); - + // Holds incoming reads of request body data (*not* header data) byte []bodyBuff = new byte[MAX_READ_SIZE]; @@ -230,10 +132,14 @@ int pos; // Current read position within that buffer boolean end_of_stream; // true if we've received an empty packet - + + // Required handler - essential request processing + public RequestHandler reqHandler=new RequestHandler(); + public Ajp13() { super(); initBuf(); + reqHandler.init( this ); } /** Will be overriden @@ -269,6 +175,37 @@ pos = 0; } + // -------------------- Handlers registry -------------------- + + static final int MAX_HANDLERS=32; + static final int RESERVED=16; // reserved names, backward compat + + // Note that we don't make distinction between in and out + // messages ( i.e. one id is used only in one direction ) + AjpHandler handlers[]=new AjpHandler[MAX_HANDLERS]; + String handlerName[]=new String[MAX_HANDLERS]; + int currentId=RESERVED; + + public int registerMessageType( int id, String name, AjpHandler h, + String sig[] ) + { + if( id < 0 ) { + // try to find it by name + for( int i=0; i< handlerName.length; i++ ) + if( name.equals( handlerName[i] ) ) return i; + handlerName[currentId]=name; + handlers[currentId]=h; + currentId++; + return currentId; + } + // fixed id + handlerName[id]=name; + handlers[id]=h; + return id; + } + + // -------------------- Main dispatch -------------------- + /** * Read a new packet from the web server and decode it. If it's a * forwarded request, store its properties in the passed-in AjpRequest @@ -295,543 +232,99 @@ try { err = receive(hBuf); } catch (IOException ioe) { + if(debug >0 ) logger.log( "IOException receiving message "); return -1; // Indicate it's a disconnection from the remote end } if(err < 0) { + if(debug >0 ) logger.log( "Error receiving message "); return 500; } int type = (int)hBuf.getByte(); + // System.out.println("XXX " + this ); + return handleMessage( type, hBuf, req ); + } + + /** Override for ajp14, temporary + */ + public int handleMessage( int type, Ajp13Packet hBuf, AjpRequest req ) + throws IOException + { switch(type) { - case JK_AJP13_FORWARD_REQUEST: - return decodeRequest(req, hBuf); + case RequestHandler.JK_AJP13_FORWARD_REQUEST: + return reqHandler.decodeRequest(this, hBuf, req); case JK_AJP13_SHUTDOWN: return -2; } return 200; // XXX This is actually an error condition } - - /** - * Try to decode Headers - AJP13 will do nothing but descendant will - * override this method to handle new headers (ie SSL_KEY_SIZE in AJP14) - */ - int decodeMoreHeaders(AjpRequest req, byte attribute, Ajp13Packet msg) - { - return 500; - } - - /** - * Parse a FORWARD_REQUEST packet from the web server and store its - * properties in the passed-in request object. - * - * @param req An empty (newly-recycled) request object. - * @param msg Holds the packet which has just been sent by the web - * server, with its read position just past the packet header (which in - * this case includes the prefix code for FORWARD_REQUEST). - * - * @return 200 in case of a successful decoduing, 500 in case of error. - */ - protected int decodeRequest(AjpRequest req, Ajp13Packet msg) - throws IOException - { - - if (debug > 0) { - logger.log("decodeRequest()"); - } - - // XXX Awful return values - - boolean isSSL = false; - - // Translate the HTTP method code to a String. - byte methodCode = msg.getByte(); - req.method().setString(methodTransArray[(int)methodCode - 1]); - - msg.getMessageBytes(req.protocol()); - msg.getMessageBytes(req.requestURI()); - - msg.getMessageBytes(req.remoteAddr()); - msg.getMessageBytes(req.remoteHost()); - msg.getMessageBytes(req.serverName()); - req.setServerPort(msg.getInt()); - - isSSL = msg.getBool(); - - // Decode headers - MimeHeaders headers = req.headers(); - int hCount = msg.getInt(); - for(int i = 0 ; i < hCount ; i++) { - String hName = null; - - // Header names are encoded as either an integer code starting - // with 0xA0, or as a normal string (in which case the first - // two bytes are the length). - int isc = msg.peekInt(); - int hId = isc & 0xFF; - - MessageBytes vMB=null; - isc &= 0xFF00; - if(0xA000 == isc) { - msg.getInt(); // To advance the read position - hName = headerTransArray[hId - 1]; - vMB= headers.addValue(hName); - } else { - // XXX Not very elegant - vMB = msg.addHeader(headers); - if (vMB == null) { - return 500; // wrong packet - } - } - - msg.getMessageBytes(vMB); - - // set content length, if this is it... - if (hId == SC_REQ_CONTENT_LENGTH) { - int contentLength = (vMB == null) ? -1 : vMB.getInt(); - req.setContentLength(contentLength); - } else if (hId == SC_REQ_CONTENT_TYPE) { - ByteChunk bchunk = vMB.getByteChunk(); - req.contentType().setBytes(bchunk.getBytes(), - bchunk.getOffset(), - bchunk.getLength()); - } - } - byte attributeCode; - for(attributeCode = msg.getByte() ; - attributeCode != SC_A_ARE_DONE ; - attributeCode = msg.getByte()) { - switch(attributeCode) { - case SC_A_CONTEXT : - break; - - case SC_A_SERVLET_PATH : - break; - - case SC_A_REMOTE_USER : - msg.getMessageBytes(req.remoteUser()); - break; - - case SC_A_AUTH_TYPE : - msg.getMessageBytes(req.authType()); - break; - - case SC_A_QUERY_STRING : - msg.getMessageBytes(req.queryString()); - break; - - case SC_A_JVM_ROUTE : - msg.getMessageBytes(req.jvmRoute()); - break; - - case SC_A_SSL_CERT : - isSSL = true; - // Transform the string into certificate. - String certString = msg.getString(); - byte[] certData = certString.getBytes(); - ByteArrayInputStream bais = new ByteArrayInputStream(certData); - - // Fill the first element. - X509Certificate jsseCerts[] = null; - try { - CertificateFactory cf = - CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) - cf.generateCertificate(bais); - jsseCerts = new X509Certificate[1]; - jsseCerts[0] = cert; - } catch(java.security.cert.CertificateException e) { - logger.log("Certificate convertion failed" + e ); - } - - req.setAttribute("javax.servlet.request.X509Certificate", - jsseCerts); - break; - - case SC_A_SSL_CIPHER : - isSSL = true; - req.setAttribute("javax.servlet.request.cipher_suite", - msg.getString()); - break; - - case SC_A_SSL_SESSION : - isSSL = true; - req.setAttribute("javax.servlet.request.ssl_session", - msg.getString()); - break; - - case SC_A_REQ_ATTRIBUTE : - req.setAttribute(msg.getString(), - msg.getString()); - break; - - case SC_A_SSL_KEYSIZE : - req.setAttribute("javax.servlet.request.key_size", - new Integer (msg.getInt())); - break; - default: - if (decodeMoreHeaders(req, attributeCode, msg) != 500) - break; + // ==================== Servlet Input Support ================= - return 500; - } - } + /** @deprecated -- Will use reqHandler, make sure nobody else + calls this */ - if(isSSL) { - req.setScheme(req.SCHEME_HTTPS); - req.setSecure(true); - } - - // set cookies on request now that we have all headers - req.cookies().setHeaders(req.headers()); - - // Check to see if there should be a body packet coming along - // immediately after - if(req.getContentLength() != 0) { - - /* Read present data */ - int err = receive(inBuf); - if(err < 0) { - return 500; - } - - blen = inBuf.peekInt(); - pos = 0; - inBuf.getBytes(bodyBuff); - } - if (debug > 5) { - logger.log(req.toString()); - } - - return 200; // Success - } - - // ==================== Servlet Input Support ================= - public int available() throws IOException { - if (debug > 0) { - logger.log("available()"); - } - - if (pos >= blen) { - if( ! refillReadBuffer()) { - return 0; - } - } - return blen - pos; + return reqHandler.available(this); } - /** - * Return the next byte of request body data (to a servlet). - * - * @see Request#doRead - */ public int doRead() throws IOException { - if (debug > 0) { - logger.log("doRead()"); - } - - if(pos >= blen) { - if( ! refillReadBuffer()) { - return -1; - } - } - return (char) bodyBuff[pos++]; + return reqHandler.doRead( this ); } - /** - * Store a chunk of request data into the passed-in byte buffer. - * - * @param b A buffer to fill with data from the request. - * @param off The offset in the buffer at which to start filling. - * @param len The number of bytes to copy into the buffer. - * - * @return The number of bytes actually copied into the buffer, or -1 - * if the end of the stream has been reached. - * - * @see Request#doRead - */ public int doRead(byte[] b, int off, int len) throws IOException { - if (debug > 0) { - logger.log("doRead(byte[], int, int)"); - } - - if(pos >= blen) { - if( ! refillReadBuffer()) { - return -1; - } - } - - if(pos + len <= blen) { // Fear the off by one error - // Sanity check b.length > off + len? - System.arraycopy(bodyBuff, pos, b, off, len); - pos += len; - return len; - } - - // Not enough data (blen < pos + len) or chunked encoded - int toCopy = len; - while(toCopy > 0) { - int bytesRemaining = blen - pos; - if(bytesRemaining < 0) - bytesRemaining = 0; - int c = bytesRemaining < toCopy ? bytesRemaining : toCopy; - - System.arraycopy(bodyBuff, pos, b, off, c); - - toCopy -= c; - - off += c; - pos += c; // In case we exactly consume the buffer - - if(toCopy > 0) - if( ! refillReadBuffer()) { // Resets blen and pos - break; - } - } - - return len - toCopy; + return reqHandler.doRead( this, b, off, len ); } - /** - * Get more request body data from the web server and store it in the - * internal buffer. - * - * @return true if there is more data, false if not. - */ private boolean refillReadBuffer() throws IOException { - if (debug > 0) { - logger.log("refillReadBuffer()"); - } - - // If the server returns an empty packet, assume that that end of - // the stream has been reached (yuck -- fix protocol??). - if (end_of_stream) { - return false; - } - - // Why not use outBuf?? - inBuf.reset(); - inBuf.appendByte(JK_AJP13_GET_BODY_CHUNK); - inBuf.appendInt(MAX_READ_SIZE); - send(inBuf); - - int err = receive(inBuf); - if(err < 0) { - throw new IOException(); - } - - // No data received. - if( inBuf.getLen() == 0 ) { - pos=0; - blen=0; - end_of_stream = true; - return false; - } - - blen = inBuf.peekInt(); - pos = 0; - inBuf.getBytes(bodyBuff); - - return (blen > 0); + return reqHandler.refillReadBuffer(this); } - // ==================== Servlet Output Support ================= - - /** - */ public void beginSendHeaders(int status, String statusMessage, int numHeaders) throws IOException { + reqHandler.beginSendHeaders( this, outBuf, + status, statusMessage, + numHeaders); + } - if (debug > 0) { - logger.log("sendHeaders()"); - } - - // XXX if more headers that MAX_SIZE, send 2 packets! - - outBuf.reset(); - outBuf.appendByte(JK_AJP13_SEND_HEADERS); - - if (debug > 0) { - logger.log("status is: " + status + - "(" + statusMessage + ")"); - } - - // set status code and message - outBuf.appendInt(status); - outBuf.appendString(statusMessage); - - // write the number of headers... - outBuf.appendInt(numHeaders); - } - public void sendHeader(String name, String value) throws IOException { - int sc = headerNameToSc(name); - if(-1 != sc) { - outBuf.appendInt(sc); - } else { - outBuf.appendString(name); - } - outBuf.appendString(value); + reqHandler.sendHeader( outBuf, name, value ); } public void endSendHeaders() throws IOException { - outBuf.end(); - send(outBuf); + reqHandler.endSendHeaders(this, outBuf); } - /** - * Send the HTTP headers back to the web server and on to the browser. - * - * @param status The HTTP status code to send. - * @param headers The set of all headers. - */ public void sendHeaders(int status, MimeHeaders headers) - throws IOException { - sendHeaders(status, HttpMessages.getMessage(status), headers); + throws IOException + { + reqHandler.sendHeaders(this, outBuf, status, + HttpMessages.getMessage(status), + headers); } - - /** - * Send the HTTP headers back to the web server and on to the browser. - * - * @param status The HTTP status code to send. - * @param statusMessage the HTTP status message to send. - * @param headers The set of all headers. - */ - public void sendHeaders(int status, String statusMessage, MimeHeaders headers) - throws IOException { - // XXX if more headers that MAX_SIZE, send 2 packets! - - outBuf.reset(); - outBuf.appendByte(JK_AJP13_SEND_HEADERS); - outBuf.appendInt(status); - - outBuf.appendString(statusMessage); - - int numHeaders = headers.size(); - outBuf.appendInt(numHeaders); - - for( int i=0 ; i < numHeaders ; i++ ) { - String headerName = headers.getName(i).toString(); - int sc = headerNameToSc(headerName); - if(-1 != sc) { - outBuf.appendInt(sc); - } else { - outBuf.appendString(headerName); - } - outBuf.appendString(headers.getValue(i).toString() ); - } - outBuf.end(); - send(outBuf); - } - - /** - * Translate an HTTP response header name to an integer code if - * possible. Case is ignored. - * - * @param name The name of the response header to translate. - * - * @return The code for that header name, or -1 if no code exists. - */ - 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-Authenticate")) { - return SC_RESP_WWW_AUTHENTICATE; - } - break; - } - - return -1; + public void sendHeaders(int status, String statusMessage, + MimeHeaders headers) + throws IOException + { + reqHandler.sendHeaders( this, outBuf, status, + statusMessage, headers ); } - /** - * Signal the web server that the servlet has finished handling this - * request, and that the connection can be reused. - */ public void finish() throws IOException { - if (debug > 0) { - logger.log("finish()"); - } - - outBuf.reset(); - outBuf.appendByte(JK_AJP13_END_RESPONSE); - outBuf.appendBool(true); // Reuse this connection - outBuf.end(); - send(outBuf); + reqHandler.finish(this, outBuf ); } - /** - * Send a chunk of response body data to the web server and on to the - * browser. - * - * @param b A huffer of bytes to send. - * @param off The offset into the buffer from which to start sending. - * @param len The number of bytes to send. - */ public void doWrite(byte b[], int off, int len) throws IOException { - if (debug > 0) { - logger.log("doWrite(byte[], " + off + ", " + len + ")"); - } - - int sent = 0; - while(sent < len) { - int to_send = len - sent; - to_send = to_send > MAX_SEND_SIZE ? MAX_SEND_SIZE : to_send; - - outBuf.reset(); - outBuf.appendByte(JK_AJP13_SEND_BODY_CHUNK); - outBuf.appendBytes(b, off + sent, to_send); - send(outBuf); - sent += to_send; - } + reqHandler.doWrite( this, outBuf, b, off, len ); } @@ -901,49 +394,49 @@ // returned -- should probably return true/false instead. byte b[] = msg.getBuff(); - int rd = readN(in, b, 0, H_SIZE ); - - // XXX - connection closed (JK_AJP13_COMM_CLOSED) - // - connection broken (JK_AJP13_COMM_BROKEN) - // - if(rd < 0) { - logger.log("bad read: " + rd); - return rd; - } - + int rd = readN(in, b, 0, H_SIZE ); + + // XXX - connection closed (JK_AJP13_COMM_CLOSED) + // - connection broken (JK_AJP13_COMM_BROKEN) + // + if(rd < 0) { + logger.log("bad read: " + rd); + return rd; + } + int len = msg.checkIn(); - if (debug > 0) { - logger.log("receive: len = " + len); - } - + if( debug > 5 ) + logger.log( "Received " + rd + " " + len + " " + b[0] ); + // XXX check if enough space - it's assert()-ed !!! - + int total_read = 0; - - total_read = readN(in, b, H_SIZE, len); - - if (total_read < 0) { - logger.log("can't read body, waited #" + len); - return JK_AJP13_BAD_BODY; - } - - if (total_read != len) { - logger.log( "incomplete read, waited #" + len + " got only " + total_read); - return JK_AJP13_INCOMPLETE_BODY; - } - - if (debug > 0) - logger.log("receive: total read = " + total_read); + + total_read = readN(in, b, H_SIZE, len); + + if (total_read < 0) { + logger.log("can't read body, waited #" + len); + return JK_AJP13_BAD_BODY; + } + + if (total_read != len) { + logger.log( "incomplete read, waited #" + len + + " got only " + total_read); + return JK_AJP13_INCOMPLETE_BODY; + } + + if (debug > 0) + logger.log("receive: total read = " + total_read); 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. */ - private void send( Ajp13Packet msg ) throws IOException { + public void send( Ajp13Packet msg ) throws IOException { if (debug > 0) { logger.log("send()"); } @@ -952,9 +445,8 @@ byte b[] = msg.getBuff(); int len = msg.getLen(); - if (debug > 0) { - logger.log("sending msg, len = " + len); - } + if (debug > 5 ) + logger.log("send() " + len + " " + b[0] ); out.write( b, 0, len ); } @@ -980,17 +472,21 @@ } // -------------------- Debug -------------------- - private int debug = 0; - + protected int debug = 0; + public void setDebug(int debug) { this.debug = debug; } + public void setLogger(Logger l) { + this.logger = l; + } + /** * XXX place holder... */ Logger logger = new Logger(); - class Logger { + public static class Logger { void log(String msg) { System.out.println("[Ajp13] " + msg); } 1.5 +17 -198 jakarta-tomcat-connectors/jk/java/org/apache/ajp/Ajp14.java Index: Ajp14.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/Ajp14.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- Ajp14.java 2001/11/20 17:49:53 1.4 +++ Ajp14.java 2001/11/21 20:49:54 1.5 @@ -90,7 +90,7 @@ * @author Dan Milstein [[EMAIL PROTECTED]] * @author Keith Wannamaker [[EMAIL PROTECTED]] */ -public class Ajp14 +public class Ajp14 extends Ajp13 { // XXX The message id and name will be handled by a registry, and // will allow dynamic allocation, based on the intial negotiation. @@ -98,38 +98,12 @@ // XXX For now we'll just use the static final field, as before - public static final int MAX_PACKET_SIZE=8192; - public static final int H_SIZE=4; // Size of basic packet header - - public static final int MAX_READ_SIZE = MAX_PACKET_SIZE - H_SIZE - 2; - public static final int MAX_SEND_SIZE = MAX_PACKET_SIZE - H_SIZE - 4; - // ============ Instance Properties ==================== - // Ajp13 - OutputStream out; - InputStream in; - - // XXX public fields are temp. solutions until the API stabilizes - // Buffer used of output body and headers - public Ajp13Packet outBuf = new Ajp13Packet( MAX_PACKET_SIZE ); - // Buffer used for input body - Ajp13Packet inBuf = new Ajp13Packet( MAX_PACKET_SIZE ); - // Buffer used for request head ( and headers ) - Ajp13Packet hBuf=new Ajp13Packet( MAX_PACKET_SIZE ); - - // Holds incoming reads of request body data (*not* header data) - byte []bodyBuff = new byte[MAX_READ_SIZE]; - - int blen; // Length of current chunk of body data in buffer - int pos; // Current read position within that buffer // AJP14 // Required handler - detect protocol, // set communication parameters, login public NegociationHandler negHandler=new NegociationHandler(); - - // Required handler - essential request processing - public RequestHandler reqHandler=new RequestHandler(); public Ajp14() { @@ -137,40 +111,8 @@ setSeed("myveryrandomentropy"); setPassword("myverysecretkey"); negHandler.init( this ); - reqHandler.init( this ); - } - - public void initBuf() - { - outBuf = new Ajp13Packet( MAX_PACKET_SIZE ); - inBuf = new Ajp13Packet( MAX_PACKET_SIZE ); - hBuf = new Ajp13Packet( MAX_PACKET_SIZE ); } - public void recycle() { - if (debug > 0) { - log("recycle()"); - } - - // This is a touch cargo-cultish, but I think wise. - blen = 0; - pos = 0; - } - - /** - * Associate an open socket with this instance. - */ - public void setSocket( Socket socket ) throws IOException { - if (debug > 0) { - log("setSocket()"); - } - - socket.setSoLinger( true, 100); - out = socket.getOutputStream(); - in = socket.getInputStream(); - pos = 0; - } - // -------------------- Parameters -------------------- /** Set the server signature, to be sent in Servlet-Container header @@ -195,168 +137,45 @@ negHandler.setPassword( ppwd ); } - // -------------------- Handlers registry -------------------- - - static final int MAX_HANDLERS=32; - static final int RESERVED=16; // reserved names, backward compat - - // Note that we don't make distinction between in and out - // messages ( i.e. one id is used only in one direction ) - AjpHandler handlers[]=new AjpHandler[MAX_HANDLERS]; - String handlerName[]=new String[MAX_HANDLERS]; - int currentId=RESERVED; - - public int registerMessageType( int id, String name, AjpHandler h, - String sig[] ) - { - if( id < 0 ) { - // try to find it by name - for( int i=0; i< handlerName.length; i++ ) - if( name.equals( handlerName[i] ) ) return i; - handlerName[currentId]=name; - handlers[currentId]=h; - currentId++; - return currentId; - } - // fixed id - handlerName[id]=name; - handlers[id]=h; - return id; - } - - // -------------------- Main dispatch -------------------- - - /** - * 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 - * object. - * - * @param req An empty (newly-recycled) request object. - * - * @return 200 in case of a successful read of a forwarded request, 500 - * if there were errors in the reading of the request, and -2 if the - * server is asking the container to shut itself down. - */ - public int receiveNextRequest(BaseRequest req) throws IOException + public int handleMessage( int type, Ajp13Packet hBuf, AjpRequest 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( type > handlers.length ) { - log( "Invalid handler " + type ); + logger.log("ajp14 handle message " + type ); + if( type > handlers.length ) { + logger.log( "Invalid handler " + type ); return 500; } - if( debug > 0 ) log( "Received " + type + " " + handlerName[type]); + if( debug > 0 ) + logger.log( "Received " + type + " " + handlerName[type]); if( ! negHandler.isLogged() ) { if( type != NegociationHandler.JK_AJP14_LOGINIT_CMD && type != NegociationHandler.JK_AJP14_LOGCOMP_CMD ) { + + logger.log( "Ajp14 error: not logged " + + type + " " + handlerName[type]); + return 300; } // else continue } - + // logged || loging message AjpHandler handler=handlers[type]; if( handler==null ) { - log( "Unknown message " + type + handlerName[type] ); + logger.log( "Unknown message " + type + handlerName[type] ); return 200; } + if( debug > 0 ) + logger.log( "Ajp14 handler " + handler ); return handler.handleAjpMessage( type, this, hBuf, req ); } // ========= 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. - **/ - public int receive(Ajp13Packet 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; - } - - int len = msg.checkIn(); - - if( debug > 5 ) log( "Received " + rd + " " + len + " " + b[0] ); - - // 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) { - log( "Incomplete read, deal with it " + len + " " + rd); - break; - // XXX log - // XXX Return an error code? - } - total_read += rd; - } - if( debug > 10 ) log( "Received total: " + total_read ); - 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. - */ - public void send( Ajp13Packet msg ) throws IOException { - msg.end(); // Write the packet header - byte b[] = msg.getBuff(); - int len = msg.getLen(); - if (debug > 5 ) log("send() " + len + " " + b[0] ); - 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(). - * - * @see Ajp14Interceptor#processConnection - */ public void close() throws IOException { - if (debug > 0) log("close()"); - - if(null != out) { - out.close(); - } - if(null !=in) { - in.close(); - } - + super.close(); negHandler.setLogged( false ); // no more logged now - } - - // -------------------- Utils -------------------- - - private static int debug=10; - void log(String s) { - System.out.println("Ajp14: " + s ); } } 1.3 +2 -2 jakarta-tomcat-connectors/jk/java/org/apache/ajp/AjpHandler.java Index: AjpHandler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/AjpHandler.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- AjpHandler.java 2001/11/20 17:49:53 1.2 +++ AjpHandler.java 2001/11/21 20:49:54 1.3 @@ -93,8 +93,8 @@ /** Execute the callback */ - public int handleAjpMessage( int type, Ajp14 channel, - Ajp13Packet ajp, BaseRequest req ) + public int handleAjpMessage( int type, Ajp13 channel, + Ajp13Packet ajp, AjpRequest req ) throws IOException { return UNKNOWN; 1.4 +8 -6 jakarta-tomcat-connectors/jk/java/org/apache/ajp/NegociationHandler.java Index: NegociationHandler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/NegociationHandler.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- NegociationHandler.java 2001/11/20 17:49:53 1.3 +++ NegociationHandler.java 2001/11/21 20:49:54 1.4 @@ -254,8 +254,9 @@ // -------------------- Initialization -------------------- - public void init( Ajp14 ajp14 ) { + public void init( Ajp13 ajp14 ) { // register incoming message handlers + System.out.println("XXX register ajp 14 hooks"); ajp14.registerMessageType( JK_AJP14_LOGINIT_CMD,"JK_AJP14_LOGINIT_CMD", this, null); // ajp14.registerMessageType( JK_AJP14_LOGCOMP_CMD,"JK_AJP14_LOGCOMP_CMD", @@ -286,10 +287,11 @@ // -------------------- Dispatch -------------------- - public int handleAjpMessage( int type, Ajp14 ch, Ajp13Packet hBuf, - BaseRequest req ) + public int handleAjpMessage( int type, Ajp13 ch, Ajp13Packet hBuf, + AjpRequest req ) throws IOException { + System.out.println("handleAjpMessage: " + type ); Ajp13Packet outBuf=ch.outBuf; // Valid requests when not logged: switch( type ) { @@ -326,7 +328,7 @@ * * Send Login Seed (MD5 of seed) */ - private int handleLogInit( Ajp14 ch, Ajp13Packet msg, + private int handleLogInit( Ajp13 ch, Ajp13Packet msg, Ajp13Packet outBuf ) throws IOException { @@ -353,7 +355,7 @@ * If the authentification is valid send back LogOk * If the authentification failed send back LogNok */ - private int handleLogComp( Ajp14 ch, Ajp13Packet msg, + private int handleLogComp( Ajp13 ch, Ajp13Packet msg, Ajp13Packet outBuf ) throws IOException { @@ -403,7 +405,7 @@ return (304); } - private int handleContextQuery( Ajp14 ch, Ajp13Packet msg, + private int handleContextQuery( Ajp13 ch, Ajp13Packet msg, Ajp13Packet outBuf ) throws IOException { 1.6 +50 -30 jakarta-tomcat-connectors/jk/java/org/apache/ajp/RequestHandler.java Index: RequestHandler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/RequestHandler.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- RequestHandler.java 2001/11/20 17:49:53 1.5 +++ RequestHandler.java 2001/11/21 20:49:54 1.6 @@ -59,13 +59,11 @@ package org.apache.ajp; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import java.net.Socket; import java.util.Enumeration; import java.security.*; +import java.security.cert.*; import org.apache.tomcat.util.http.*; import org.apache.tomcat.util.buf.*; @@ -125,6 +123,7 @@ 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_SSL_KEYSIZE = 11; // Used for attributes which are not in the list above public static final byte SC_A_REQ_ATTRIBUTE = 10; @@ -197,7 +196,7 @@ { } - public void init( Ajp14 ajp14 ) { + public void init( Ajp13 ajp14 ) { // register incoming message handlers ajp14.registerMessageType( JK_AJP13_FORWARD_REQUEST, "JK_AJP13_FORWARD_REQUEST", @@ -218,8 +217,8 @@ } // -------------------- Incoming message -------------------- - public int handleAjpMessage( int type, Ajp14 channel, - Ajp13Packet ajp, BaseRequest req ) + public int handleAjpMessage( int type, Ajp13 channel, + Ajp13Packet ajp, AjpRequest req ) throws IOException { switch( type ) { @@ -241,7 +240,7 @@ * * @return 200 in case of a successful decoduing, 500 in case of error. */ - protected int decodeRequest(Ajp14 ch, Ajp13Packet msg, BaseRequest req) + protected int decodeRequest(Ajp13 ch, Ajp13Packet msg, BaseRequest req) throws IOException { @@ -336,8 +335,26 @@ case SC_A_SSL_CERT : isSSL = true; - req.setAttribute("javax.servlet.request.X509Certificate", - msg.getString()); + // Transform the string into certificate. + String certString = msg.getString(); + byte[] certData = certString.getBytes(); + ByteArrayInputStream bais = new ByteArrayInputStream(certData); + + // Fill the first element. + X509Certificate jsseCerts[] = null; + try { + CertificateFactory cf = + CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) + cf.generateCertificate(bais); + jsseCerts = new X509Certificate[1]; + jsseCerts[0] = cert; + } catch(java.security.cert.CertificateException e) { + log("Certificate convertion failed" + e ); + } + + req.setAttribute("javax.servlet.request.X509Certificate", + jsseCerts); break; case SC_A_SSL_CIPHER : @@ -357,7 +374,7 @@ msg.getString()); break; - case SC_A_SSL_KEY_SIZE: // Ajp14 ! + case SC_A_SSL_KEY_SIZE: // Ajp13 ! req.setAttribute("javax.servlet.request.key_size", Integer.toString(msg.getInt())); return 200; @@ -397,7 +414,7 @@ } - // -------------------- Messages from container to server -------------------- + // -------------------- Messages from container to server ------------------ /** * Send the HTTP headers back to the web server and on to the browser. @@ -406,8 +423,9 @@ * @param statusMessage the HTTP status message to send. * @param headers The set of all headers. */ - public void sendHeaders(Ajp14 ch, Ajp13Packet outBuf, - int status, String statusMessage, MimeHeaders headers) + public void sendHeaders(Ajp13 ch, Ajp13Packet outBuf, + int status, String statusMessage, + MimeHeaders headers) throws IOException { // XXX if more headers that MAX_SIZE, send 2 packets! @@ -441,7 +459,7 @@ * Signal the web server that the servlet has finished handling this * request, and that the connection can be reused. */ - public void finish(Ajp14 ch, Ajp13Packet outBuf) throws IOException { + public void finish(Ajp13 ch, Ajp13Packet outBuf) throws IOException { if (debug > 0) log("finish()"); outBuf.reset(); @@ -459,7 +477,7 @@ * @param off The offset into the buffer from which to start sending. * @param len The number of bytes to send. */ - public void doWrite(Ajp14 ch, Ajp13Packet outBuf, + public void doWrite(Ajp13 ch, Ajp13Packet outBuf, byte b[], int off, int len) throws IOException { @@ -468,7 +486,7 @@ int sent = 0; while(sent < len) { int to_send = len - sent; - to_send = to_send > Ajp14.MAX_SEND_SIZE ? Ajp14.MAX_SEND_SIZE : to_send; + to_send = to_send > Ajp13.MAX_SEND_SIZE ? Ajp13.MAX_SEND_SIZE : to_send; outBuf.reset(); outBuf.appendByte(JK_AJP13_SEND_BODY_CHUNK); @@ -538,15 +556,15 @@ return -1; } - private static int debug=10; + private static int debug=0; void log(String s) { - System.out.println("Ajp14RequestHandler: " + s ); + System.out.println("RequestHandler: " + s ); } // ==================== Servlet Input Support ================= // XXX DEPRECATED - public int available(Ajp14 ch) throws IOException { + public int available(Ajp13 ch) throws IOException { if (debug > 0) { log("available()"); } @@ -564,7 +582,7 @@ * * @see Request#doRead */ - public int doRead(Ajp14 ch) throws IOException + public int doRead(Ajp13 ch) throws IOException { if (debug > 0) { log("doRead()"); @@ -590,7 +608,7 @@ * * @see Request#doRead */ - public int doRead(Ajp14 ch, byte[] b, int off, int len) throws IOException + public int doRead(Ajp13 ch, byte[] b, int off, int len) throws IOException { if (debug > 0) { log("doRead(byte[], int, int)"); @@ -616,7 +634,7 @@ if(bytesRemaining < 0) bytesRemaining = 0; int c = bytesRemaining < toCopy ? bytesRemaining : toCopy; - + System.arraycopy(ch.bodyBuff, ch.pos, b, off, c); toCopy -= c; @@ -639,7 +657,7 @@ * * @return true if there is more data, false if not. */ - private boolean refillReadBuffer(Ajp14 ch) throws IOException + public boolean refillReadBuffer(Ajp13 ch) throws IOException { if (debug > 0) { log("refillReadBuffer()"); @@ -651,7 +669,7 @@ // Why not use outBuf?? ch.inBuf.reset(); ch.inBuf.appendByte(JK_AJP13_GET_BODY_CHUNK); - ch.inBuf.appendInt(Ajp14.MAX_READ_SIZE); + ch.inBuf.appendInt(Ajp13.MAX_READ_SIZE); ch.send(ch.inBuf); int err = ch.receive(ch.inBuf); @@ -670,7 +688,7 @@ /** */ - public void beginSendHeaders(Ajp14 ch, Ajp13Packet outBuf, + public void beginSendHeaders(Ajp13 ch, Ajp13Packet outBuf, int status, String statusMessage, int numHeaders) throws IOException { @@ -710,7 +728,7 @@ outBuf.appendString(value); } - public void endSendHeaders(Ajp14 ch, Ajp13Packet outBuf) + public void endSendHeaders(Ajp13 ch, Ajp13Packet outBuf) throws IOException { outBuf.end(); @@ -723,10 +741,12 @@ * @param status The HTTP status code to send. * @param headers The set of all headers. */ - public void sendHeaders(Ajp14 ch, Ajp13Packet outBuf, + public void sendHeaders(Ajp13 ch, Ajp13Packet outBuf, int status, MimeHeaders headers) - throws IOException { - sendHeaders(ch, outBuf, status, HttpMessages.getMessage(status), headers); + throws IOException + { + sendHeaders(ch, outBuf, status, HttpMessages.getMessage(status), + headers); } 1.6 +4 -4 jakarta-tomcat-connectors/jk/java/org/apache/ajp/test/TestAjp13.java Index: TestAjp13.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/ajp/test/TestAjp13.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- TestAjp13.java 2001/06/03 21:13:44 1.5 +++ TestAjp13.java 2001/11/21 20:49:55 1.6 @@ -44,7 +44,7 @@ p.appendInt(0x1234); p.appendInt(0); p.setByteOff(4); - p.appendByte(Ajp13.JK_AJP13_FORWARD_REQUEST); + p.appendByte(RequestHandler.JK_AJP13_FORWARD_REQUEST); p.appendByte((byte)2); p.appendString("http"); p.appendString("/test_uri"); @@ -56,11 +56,11 @@ p.appendInt(3); p.appendString("my header"); p.appendString("my header value"); - p.appendInt((0xA0 << 8) + Ajp13.SC_REQ_AUTHORIZATION); + p.appendInt((0xA0 << 8) + RequestHandler.SC_REQ_AUTHORIZATION); p.appendString("some auth string"); - p.appendInt((0xA0 << 8) + Ajp13.SC_REQ_USER_AGENT); + p.appendInt((0xA0 << 8) + RequestHandler.SC_REQ_USER_AGENT); p.appendString("TestAjp13 User Agent"); - p.appendByte(Ajp13.SC_A_ARE_DONE); + p.appendByte(RequestHandler.SC_A_ARE_DONE); int len = p.getByteOff() - 4; p.setByteOff(2); 1.8 +5 -5 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.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- Ajp14Interceptor.java 2001/10/26 21:19:35 1.7 +++ Ajp14Interceptor.java 2001/11/21 20:49:55 1.8 @@ -171,7 +171,7 @@ Ajp14 ajp14=new Ajp14(); ajp14.setContainerSignature( ContextManager.TOMCAT_NAME + " v" + ContextManager.TOMCAT_VERSION); - BaseRequest ajpreq=new BaseRequest(); + AjpRequest ajpreq=new AjpRequest(); ajp14.setPassword( password ); req=new Ajp14Request(ajp14, ajpreq); Ajp14Response res=new Ajp14Response(ajp14); @@ -195,7 +195,7 @@ Ajp14Request req=initRequest( thData ); Ajp14Response res= (Ajp14Response)req.getResponse(); Ajp14 ajp14=req.ajp14; - BaseRequest ajpReq=req.ajpReq; + AjpRequest ajpReq=req.ajpReq; ajp14.setSocket(socket); @@ -285,9 +285,9 @@ class Ajp14Request extends Request { Ajp14 ajp14; - BaseRequest ajpReq; + AjpRequest ajpReq; - public Ajp14Request(Ajp14 ajp14, BaseRequest ajpReq) + public Ajp14Request(Ajp14 ajp14, AjpRequest ajpReq) { headers = ajpReq.headers(); methodMB=ajpReq.method(); @@ -314,7 +314,7 @@ } // -------------------- Wrappers for changed method names, and to use the buffers - // XXX Move BaseRequest into util !!! ( it's just a stuct with some MessageBytes ) + // XXX Move AjpRequest into util !!! ( it's just a stuct with some MessageBytes ) public int getServerPort() { return ajpReq.getServerPort();
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>