You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by se...@apache.org on 2001/05/15 17:23:07 UTC
cvs commit: jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4 Ajp13Connector.java Ajp13InputStream.java Ajp13OutputStream.java Ajp13Processor.java Ajp13Request.java Ajp13Response.java Ajp13.java
seguin 01/05/15 08:23:07
Modified: jk/src/java/org/apache/ajp Ajp13Packet.java
jk/src/java/org/apache/ajp/tomcat4 Ajp13Connector.java
Ajp13InputStream.java Ajp13OutputStream.java
Ajp13Processor.java Ajp13Request.java
Ajp13Response.java
Added: jk/src/java/org/apache/ajp Ajp13.java AjpRequest.java
MessageBytes.java
jk/src/java/org/apache/ajp/test TestAjp13.java
Removed: jk/src/java/org/apache/ajp/tomcat4 Ajp13.java
Log:
refactoring... a work in progress...
Revision Changes Path
1.2 +14 -13 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/Ajp13Packet.java
Index: Ajp13Packet.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/Ajp13Packet.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Ajp13Packet.java 2001/05/12 05:52:39 1.1
+++ Ajp13Packet.java 2001/05/15 15:22:23 1.2
@@ -68,6 +68,9 @@
* packets.
*/
public class Ajp13Packet {
+
+ public static final String DEFAULT_CHAR_ENCODING = "8859_1";
+
byte buff[]; // Holds the bytes of the packet
int pos; // The current read or write position in the buffer
@@ -129,7 +132,7 @@
/**
* Prepare this packet for accumulating a message from the container to
* the web server. Set the write position to just after the header
- * (but leave the length unwritten, because it is as yet unknown).
+ * (but leave the length unwritten, because it is as yet unknown).
*/
public void reset() {
len = 4;
@@ -288,19 +291,17 @@
public boolean getBool() {
return (getByte() == (byte) 1);
}
-
- public static final String DEFAULT_CHAR_ENCODING = "8859_1";
-// public void getMessageBytes( MessageBytes mb ) {
-// int length = getInt();
-// if( (length == 0xFFFF) || (length == -1) ) {
-// mb.setString( null );
-// return;
-// }
-// mb.setBytes( buff, pos, length );
-// pos += length;
-// pos++; // Skip the terminating \0
-// }
+ public void getMessageBytes(MessageBytes mb) {
+ int length = getInt();
+ if( (length == 0xFFFF) || (length == -1) ) {
+ mb.setString( null );
+ return;
+ }
+ mb.setBytes( buff, pos, length );
+ pos += length;
+ pos++; // Skip the terminating \0
+ }
// public MessageBytes addHeader( MimeHeaders headers ) {
// int length = getInt();
1.1 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/Ajp13.java
Index: Ajp13.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.ajp;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Enumeration;
/**
* Represents a single, persistent connection between the web server and
* the servlet container. Uses the Apache JServ Protocol version 1.3 for
* communication. Because this protocal does not multiplex requests, this
* connection can only be associated with a single request-handling cycle
* at a time.<P>
*
* This class contains knowledge about how an individual packet is laid out
* (via the internal <CODE>Ajp13Packet</CODE> class), and also about the
* stages of communicaton between the server and the servlet container. It
* translates from Tomcat's internal servlet support methods
* (e.g. doWrite) to the correct packets to send to the web server.
*
* @see Ajp13Interceptor
*
* @author Dan Milstein [danmil@shore.net]
* @author Keith Wannamaker [Keith@Wannamaker.org]
* @author Kevin Seguin [seguin@motive.com]
*/
public class Ajp13 {
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;
// 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;
// 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;
// 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"
};
// 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 );
// 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
private int debug = 10;
/**
* XXX place holder...
*/
Logger logger = new Logger();
class Logger {
void log(String msg) {
System.out.println("[Ajp13] " + msg);
}
void log(String msg, Throwable t) {
System.out.println("[Ajp13] " + msg);
t.printStackTrace(System.out);
}
}
public void recycle() {
if (debug > 0) {
logger.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) {
logger.log("setSocket()");
}
socket.setSoLinger( true, 100);
out = socket.getOutputStream();
in = socket.getInputStream();
pos = 0;
}
/**
* 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
* 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(AjpRequest req) throws IOException {
if (debug > 0) {
logger.log("receiveNextRequest()");
}
// XXX The return values are awful.
int err = receive(hBuf);
if(err < 0) {
return 500;
}
int type = (int)hBuf.getByte();
switch(type) {
case JK_AJP13_FORWARD_REQUEST:
return decodeRequest(req, hBuf);
case JK_AJP13_SHUTDOWN:
return -2;
}
return 200; // XXX This is actually an error condition
}
/**
* 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.
*/
private int decodeRequest(AjpRequest req, Ajp13Packet msg)
throws IOException {
if (debug > 0) {
logger.log("decodeRequest()");
}
// XXX Awful return values
boolean isSSL = false;
int contentLength = -1;
// 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.serverPort = msg.getInt();
isSSL = msg.getBool();
// Decode headers
int hCount = msg.getInt();
for(int i = 0 ; i < hCount ; i++) {
MessageBytes hName = new MessageBytes();
MessageBytes hValue = new MessageBytes();
// 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;
isc &= 0xFF00;
if(0xA000 == isc) {
msg.getInt(); // To advance the read position
hName.setString(headerTransArray[hId - 1]);
} else {
msg.getMessageBytes(hName);
hId = -1;
}
switch (hId) {
case SC_REQ_CONTENT_TYPE:
msg.getMessageBytes(req.contentType);
break;
case SC_REQ_CONTENT_LENGTH:
try {
contentLength = Integer.parseInt(msg.getString());
} catch (Exception e) {
logger.log("parse content-length", e);
}
break;
case SC_REQ_COOKIE:
case SC_REQ_COOKIE2:
msg.getMessageBytes(hValue);
req.addCookies(hValue);
break;
default:
msg.getMessageBytes(hValue);
req.addHeader(hName.getString(), hValue);
break;
}
}
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;
req.setAttribute("javax.servlet.request.X509Certificate",
msg.getString());
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;
default:
return 500; // Error
}
}
req.secure = isSSL;
if(isSSL) {
req.scheme = req.SCHEME_HTTPS;
} else {
req.scheme = req.SCHEME_HTTP;
}
// Check to see if there should be a body packet coming along
// immediately after
if(contentLength > 0) {
if (debug > 0) {
logger.log("contentLength = " + contentLength +
", reading data ...");
}
req.contentLength = contentLength;
/* 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 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++];
}
/**
* 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)
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;
}
/**
* 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??).
// 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();
}
blen = inBuf.peekInt();
pos = 0;
inBuf.getBytes(bodyBuff);
return (blen > 0);
}
// ==================== Servlet Output Support =================
/**
*/
public void beginSendHeaders(int status,
String statusMessage,
int numHeaders) throws IOException {
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);
}
public void endSendHeaders() throws IOException {
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;
}
/**
* 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);
}
/**
* 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;
}
}
// ========= 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.
**/
private int receive(Ajp13Packet msg) throws IOException {
if (debug > 0) {
logger.log("receive()");
}
// 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();
int rd = in.read( b, 0, H_SIZE );
if(rd <= 0) {
logger.log("bad read: " + rd);
return rd;
}
int len = msg.checkIn();
logger.log("receive: len = " + len);
// 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;
}
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 {
if (debug > 0) {
logger.log("send()");
}
msg.end(); // Write the packet header
byte b[] = msg.getBuff();
int len = msg.getLen();
if (debug > 0) {
logger.log("sending msg, len = " + len);
}
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 Ajp13Interceptor#processConnection
*/
public void close() throws IOException {
if (debug > 0) {
logger.log("close()");
}
if(null != out) {
out.close();
}
if(null !=in) {
in.close();
}
}
}
1.1 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/AjpRequest.java
Index: AjpRequest.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.ajp;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Iterator;
public class AjpRequest {
public static final String SCHEME_HTTP = "http";
public static final String SCHEME_HTTPS = "https";
private final static Iterator emptyItr = new LinkedList().iterator();
MessageBytes method = new MessageBytes();
MessageBytes protocol = new MessageBytes();
MessageBytes requestURI = new MessageBytes();
MessageBytes remoteAddr = new MessageBytes();
MessageBytes remoteHost = new MessageBytes();
MessageBytes serverName = new MessageBytes();
int serverPort = 80;
MessageBytes remoteUser = new MessageBytes();
MessageBytes authType = new MessageBytes();
MessageBytes queryString = new MessageBytes();
MessageBytes jvmRoute = new MessageBytes();
String scheme = SCHEME_HTTP;
boolean secure = false;
int contentLength = 0;
MessageBytes contentType = new MessageBytes();
HashMap headers = new HashMap();
HashMap attributes = new HashMap();
LinkedList cookies = new LinkedList();
/**
* recylce this Request
*/
public void recycle() {
method.recycle();
protocol.recycle();
requestURI.recycle();
remoteAddr.recycle();
remoteHost.recycle();
serverName.recycle();
serverPort = 80;
remoteUser.recycle();
authType.recycle();
queryString.recycle();
jvmRoute.recycle();
scheme = SCHEME_HTTP;
secure = false;
contentLength = 0;
contentType.recycle();
headers.clear();
attributes.clear();
cookies.clear();
}
public MessageBytes getMethod() {
return method;
}
public MessageBytes getProtocol() {
return protocol;
}
public MessageBytes getRequestURI() {
return requestURI;
}
public MessageBytes getRemoteAddr() {
return remoteAddr;
}
public MessageBytes getRemoteHost() {
return remoteHost;
}
public MessageBytes getServerName() {
return serverName;
}
public int getServerPort() {
return serverPort;
}
public MessageBytes getRemoteUser() {
return remoteUser;
}
public MessageBytes getAuthType() {
return authType;
}
public MessageBytes getQueryString() {
return queryString;
}
public MessageBytes getJvmRoute() {
return jvmRoute;
}
public String getScheme() {
return scheme;
}
public boolean getSecure() {
return secure;
}
public int getContentLength() {
return contentLength;
}
public MessageBytes getContentType() {
return contentType;
}
public void addHeader(String name, MessageBytes value) {
if (name == null || value == null) {
return;
}
String lname = name.toLowerCase();
LinkedList values = (LinkedList)headers.get(lname);
if (values == null) {
values = new LinkedList();
headers.put(lname, values);
}
values.add(value);
}
public Iterator getHeaders(String name) {
if (name == null) {
return emptyItr;
}
String lname = name.toLowerCase();
LinkedList values = (LinkedList)headers.get(lname);
if (values == null) {
return emptyItr;
}
return values.iterator();
}
public Iterator getHeaderNames() {
return headers.keySet().iterator();
}
public void addCookies(MessageBytes cookies) {
this.cookies.add(cookies);
}
public Iterator getCookies() {
return cookies.iterator();
}
public void setAttribute(String name, Object value) {
if (name == null || value == null) {
return;
}
attributes.put(name, value);
}
public Object getAttribute(String name) {
if (name == null) {
return null;
}
return attributes.get(name);
}
public Iterator getAttributeNames() {
return attributes.keySet().iterator();
}
/**
* ** SLOW ** for debugging only!
*/
public String toString() {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println("=== AjpRequest ===");
pw.println("method = " + method.toString());
pw.println("protocol = " + protocol.toString());
pw.println("requestURI = " + requestURI.toString());
pw.println("remoteAddr = " + remoteAddr.toString());
pw.println("remoteHost = " + remoteHost.toString());
pw.println("serverName = " + serverName.toString());
pw.println("serverPort = " + serverPort);
pw.println("remoteUser = " + remoteUser.toString());
pw.println("authType = " + authType.toString());
pw.println("queryString = " + queryString.toString());
pw.println("jvmRoute = " + jvmRoute.toString());
pw.println("scheme = " + scheme.toString());
pw.println("secure = " + secure);
pw.println("contentLength = " + contentLength);
pw.println("contentType = " + contentType);
pw.println("attributes = " + attributes.toString());
pw.println("headers = " + headers.toString());
pw.println("cookies = " + cookies.toString());
return sw.toString();
}
}
1.1 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/MessageBytes.java
Index: MessageBytes.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.ajp;
import java.io.UnsupportedEncodingException;
/**
* a cheap rip-off of MessageBytes from tomcat 3
*/
public class MessageBytes {
private static final String DEFAULT_ENCODING = "ISO-8859-1";
private int off;
private int len;
private byte[] bytes;
private String str;
private boolean gotStr;
private String enc;
/**
* creates and uninitialized MessageBytes object
*/
public MessageBytes() {
recycle();
}
/**
* recycles this object.
*/
public void recycle() {
off = 0;
len = 0;
bytes = null;
str = null;
gotStr = false;
enc = DEFAULT_ENCODING;
}
public void setBytes(byte[] bytes, int off, int len) {
recycle();
this.bytes = bytes;
this.off = off;
this.len = len;
}
public byte[] getBytes() {
return bytes;
}
public int getOffset() {
return off;
}
public int getLength() {
return len;
}
public void setEncoding(String enc) {
this.enc = enc;
}
public String getEncoding() {
return enc;
}
public void setString(String str) {
this.str = str;
gotStr = true;
}
public String getString() throws UnsupportedEncodingException {
if (!gotStr) {
if (bytes == null || len == 0) {
setString(null);
} else {
setString(new String(bytes, off, len, enc));
}
}
return str;
}
public String toString() {
try {
return getString();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("root cause: " + e.toString());
}
}
}
1.1 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/test/TestAjp13.java
Index: TestAjp13.java
===================================================================
package org.apache.ajp.test;
import org.apache.ajp.*;
import java.io.*;
import java.net.*;
import java.util.*;
public class TestAjp13 {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(8009);
System.out.println("TestAjp13 running...");
Socket socket = server.accept();
Ajp13 ajp13 = new Ajp13();
AjpRequest request = new AjpRequest();
ajp13.setSocket(socket);
boolean moreRequests = true;
while (moreRequests) {
int status = 0;
try {
status = ajp13.receiveNextRequest(request);
} catch (IOException e) {
System.out.println("process: ajp13.receiveNextRequest -> " + e);
}
if( status==-2) {
// special case - shutdown
// XXX need better communication, refactor it
// if( !doShutdown(socket.getLocalAddress(),
// socket.getInetAddress())) {
// moreRequests = false;
// continue;
// }
break;
}
if( status != 200 )
break;
System.out.println(request);
String message =
"<html><body><pre>" +
"hello from ajp13: " +
System.getProperty("line.separator") +
request.toString() +
"</pre></body></html>";
ajp13.beginSendHeaders(200, "OK", 3);
ajp13.sendHeader("content-type", "text/html");
ajp13.sendHeader("content-length", String.valueOf(message.length()));
ajp13.sendHeader("my-header", "my value");
ajp13.endSendHeaders();
byte[] b = message.getBytes();
ajp13.doWrite(b, 0, b.length);
ajp13.finish();
request.recycle();
}
try {
ajp13.close();
} catch (IOException e) {
System.out.println("process: ajp13.close ->" + e);
}
try {
socket.close();
} catch (IOException e) {
System.out.println("process: socket.close ->" + e);
}
socket = null;
System.out.println("process: done");
}
}
1.3 +5 -5 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Connector.java
Index: Ajp13Connector.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Connector.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- Ajp13Connector.java 2001/05/12 06:16:39 1.2
+++ Ajp13Connector.java 2001/05/15 15:22:42 1.3
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Connector.java,v 1.2 2001/05/12 06:16:39 seguin Exp $
- * $Revision: 1.2 $
- * $Date: 2001/05/12 06:16:39 $
+ * $Header: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Connector.java,v 1.3 2001/05/15 15:22:42 seguin Exp $
+ * $Revision: 1.3 $
+ * $Date: 2001/05/15 15:22:42 $
*
* ====================================================================
*
@@ -92,7 +92,7 @@
* Implementation of an Ajp13 connector.
*
* @author Kevin Seguin
- * @version $Revision: 1.2 $ $Date: 2001/05/12 06:16:39 $
+ * @version $Revision: 1.3 $ $Date: 2001/05/15 15:22:42 $
*/
@@ -620,7 +620,7 @@
*/
public Request createRequest() {
- Ajp13Request request = new Ajp13Request();
+ Ajp13Request request = new Ajp13Request(this);
request.setConnector(this);
return (request);
1.2 +2 -0 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13InputStream.java
Index: Ajp13InputStream.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13InputStream.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Ajp13InputStream.java 2001/05/12 05:52:40 1.1
+++ Ajp13InputStream.java 2001/05/15 15:22:44 1.2
@@ -63,6 +63,8 @@
import javax.servlet.ServletInputStream;
+import org.apache.ajp.Ajp13;
+
public class Ajp13InputStream extends ServletInputStream {
private Ajp13 ajp13;
1.2 +2 -0 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13OutputStream.java
Index: Ajp13OutputStream.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13OutputStream.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Ajp13OutputStream.java 2001/05/12 05:52:40 1.1
+++ Ajp13OutputStream.java 2001/05/15 15:22:45 1.2
@@ -60,6 +60,8 @@
import java.io.*;
+import org.apache.ajp.Ajp13;
+
public class Ajp13OutputStream extends OutputStream {
private Ajp13 ajp13;
1.2 +11 -8 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Processor.java
Index: Ajp13Processor.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Processor.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Ajp13Processor.java 2001/05/12 05:52:41 1.1
+++ Ajp13Processor.java 2001/05/15 15:22:47 1.2
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Processor.java,v 1.1 2001/05/12 05:52:41 seguin Exp $
- * $Revision: 1.1 $
- * $Date: 2001/05/12 05:52:41 $
+ * $Header: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Processor.java,v 1.2 2001/05/15 15:22:47 seguin Exp $
+ * $Revision: 1.2 $
+ * $Date: 2001/05/15 15:22:47 $
*
* ====================================================================
*
@@ -97,10 +97,12 @@
import org.apache.catalina.util.StringManager;
import org.apache.catalina.util.StringParser;
+import org.apache.ajp.Ajp13;
+import org.apache.ajp.AjpRequest;
/**
* @author Kevin Seguin
- * @version $Revision: 1.1 $ $Date: 2001/05/12 05:52:41 $
+ * @version $Revision: 1.2 $ $Date: 2001/05/15 15:22:47 $
*/
final class Ajp13Processor
@@ -138,8 +140,8 @@
// ----------------------------------------------------- Instance Variables
private Ajp13Logger logger = new Ajp13Logger();
+ private AjpRequest ajpRequest = new AjpRequest();
-
/**
* Is there a new socket available?
*/
@@ -317,10 +319,9 @@
*/
private void process(Socket socket) {
- Ajp13 ajp13 = new Ajp13(connector, id);
+ Ajp13 ajp13 = new Ajp13();
Ajp13InputStream input = new Ajp13InputStream(ajp13);
Ajp13OutputStream output = new Ajp13OutputStream(ajp13);
- request.setAjp13(ajp13);
response.setAjp13(ajp13);
try {
@@ -334,7 +335,7 @@
int status = 0;
try {
- status = ajp13.receiveNextRequest(request);
+ status = ajp13.receiveNextRequest(ajpRequest);
} catch (IOException e) {
logger.log("process: ajp13.receiveNextRequest", e);
}
@@ -355,6 +356,7 @@
try {
// set up request
+ request.setAjpRequest(ajpRequest);
request.setResponse(response);
request.setStream(input);
@@ -375,6 +377,7 @@
}
// Recycling the request and the response objects
+ ajpRequest.recycle();
request.recycle();
response.recycle();
1.2 +174 -5 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Request.java
Index: Ajp13Request.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Request.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Ajp13Request.java 2001/05/12 05:52:41 1.1
+++ Ajp13Request.java 2001/05/15 15:22:50 1.2
@@ -59,23 +59,192 @@
package org.apache.ajp.tomcat4;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+import java.util.List;
+import java.util.Iterator;
+
import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.Cookie;
import org.apache.catalina.connector.HttpRequestBase;
+import org.apache.catalina.Globals;
+import org.apache.catalina.util.RequestUtil;
+
+import org.apache.ajp.AjpRequest;
+import org.apache.ajp.MessageBytes;
public class Ajp13Request extends HttpRequestBase {
+
+ private static final String match =
+ ";" + Globals.SESSION_PARAMETER_NAME + "=";
+
+ private static int id = 1;
+
+ private Ajp13Logger logger = new Ajp13Logger();
+ private int debug;
+
+ public Ajp13Request(Ajp13Connector connector) {
+ super();
+ this.debug = connector.getDebug();
+ this.logger.setConnector(connector);
+ this.logger.setName("Ajp13Request[" + (id++) + "]");
+ }
+
+ public void recycle() {
+ super.recycle();
+ }
+
+ void setAjpRequest(AjpRequest ajp) throws UnsupportedEncodingException {
+ // XXX make this guy wrap AjpRequest so
+ // we're more efficient (that's the whole point of
+ // all of the MessageBytes in AjpRequest)
+
+ setMethod(ajp.getMethod().getString());
+ setProtocol(ajp.getProtocol().getString());
+ setRequestURI(ajp.getRequestURI().getString());
+ setRemoteAddr(ajp.getRemoteAddr().getString());
+ setRemoteHost(ajp.getRemoteHost().getString());
+ setServerName(ajp.getServerName().getString());
+ setServerPort(ajp.getServerPort());
+
+ String remoteUser = ajp.getRemoteUser().getString();
+ if (remoteUser != null) {
+ setUserPrincipal(new Ajp13Principal(remoteUser));
+ }
+
+ setAuthType(ajp.getAuthType().getString());
+ setQueryString(ajp.getQueryString().getString());
+ setScheme(ajp.getScheme());
+ setSecure(ajp.getSecure());
+ setContentLength(ajp.getContentLength());
+
+ String contentType = ajp.getContentType().getString();
+ if (contentType != null) {
+ setContentType(contentType);
+ }
+
+ Iterator itr = ajp.getHeaderNames();
+ while (itr.hasNext()) {
+ String name = (String)itr.next();
+ Iterator itr2 = ajp.getHeaders(name);
+ while (itr2.hasNext()) {
+ MessageBytes value = (MessageBytes)itr2.next();
+ addHeader(name, value.getString());
+ }
+ }
+
+ itr = ajp.getAttributeNames();
+ while (itr.hasNext()) {
+ String name = (String)itr.next();
+ setAttribute(name, ajp.getAttribute(name));
+ }
+
+ itr = ajp.getCookies();
+ while (itr.hasNext()) {
+ MessageBytes cookies = (MessageBytes)itr.next();
+ addCookies(cookies.getString());
+ }
+ }
- private Ajp13 ajp13;
+// public Object getAttribute(String name) {
+// return ajp.getAttribute(name);
+// }
+
+// public Enumeration getAttributeNames() {
+// return new Enumerator(ajp.getAttributeNames());
+// }
+
+ public void setRequestURI(String uri) {
+ int semicolon = uri.indexOf(match);
+ if (semicolon >= 0) {
+ String rest = uri.substring(semicolon + match.length());
+ int semicolon2 = rest.indexOf(";");
+ if (semicolon2 >= 0) {
+ setRequestedSessionId(rest.substring(0, semicolon2));
+ rest = rest.substring(semicolon2);
+ } else {
+ setRequestedSessionId(rest);
+ rest = "";
+ }
+ setRequestedSessionURL(true);
+ uri = uri.substring(0, semicolon) + rest;
+ if (debug >= 1)
+ logger.log(" Requested URL session id is " +
+ ((HttpServletRequest) getRequest())
+ .getRequestedSessionId());
+ } else {
+ setRequestedSessionId(null);
+ setRequestedSessionURL(false);
+ }
- void setAjp13(Ajp13 ajp13) {
- this.ajp13 = ajp13;
+ super.setRequestURI(uri);
}
- Ajp13 getAjp13() {
- return this.ajp13;
+ private void addCookies(String cookiesHeader) {
+ Cookie cookies[] = RequestUtil.parseCookieHeader(cookiesHeader);
+ for (int j = 0; j < cookies.length; j++) {
+ Cookie cookie = cookies[j];
+ if (cookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
+ // Override anything requested in the URL
+ if (!isRequestedSessionIdFromCookie()) {
+ // Accept only the first session id cookie
+ setRequestedSessionId(cookie.getValue());
+ setRequestedSessionCookie(true);
+ setRequestedSessionURL(false);
+ if (debug > 0) {
+ logger.log(" Requested cookie session id is " +
+ ((HttpServletRequest) getRequest())
+ .getRequestedSessionId());
+ }
+ }
+ }
+ if (debug > 0) {
+ logger.log(" Adding cookie " + cookie.getName() + "=" +
+ cookie.getValue());
+ }
+ addCookie(cookie);
+ }
}
public ServletInputStream createInputStream() throws IOException {
return (ServletInputStream)getStream();
+ }
+}
+
+class Ajp13Principal implements java.security.Principal {
+ String user;
+
+ Ajp13Principal(String user) {
+ this.user = user;
+ }
+ public boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ } else if (!(o instanceof Ajp13Principal)) {
+ return false;
+ } else if (o == this) {
+ return true;
+ } else if (this.user == null && ((Ajp13Principal)o).user == null) {
+ return true;
+ } else if (user != null) {
+ return user.equals( ((Ajp13Principal)o).user);
+ } else {
+ return false;
+ }
+ }
+
+ public String getName() {
+ return user;
+ }
+
+ public int hashCode() {
+ if (user == null) return 0;
+ else return user.hashCode();
+ }
+
+ public String toString() {
+ return getName();
}
}
1.2 +49 -6 jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Response.java
Index: Ajp13Response.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/jk/src/java/org/apache/ajp/tomcat4/Ajp13Response.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Ajp13Response.java 2001/05/12 05:52:41 1.1
+++ Ajp13Response.java 2001/05/15 15:22:51 1.2
@@ -70,12 +70,15 @@
import org.apache.catalina.Globals;
import org.apache.catalina.util.CookieTools;
+import org.apache.ajp.Ajp13;
+
public class Ajp13Response extends HttpResponseBase {
private Ajp13 ajp13;
private boolean finished = false;
private boolean headersSent = false;
-
+ private StringBuffer cookieValue = new StringBuffer();
+
String getStatusMessage() {
return getStatusMessage(getStatus());
}
@@ -94,12 +97,14 @@
}
headersSent = true;
+ int numHeaders = 0;
+
if (getContentType() != null) {
- addHeader("Content-Type", getContentType());
+ numHeaders++;
}
if (getContentLength() >= 0) {
- addIntHeader("Content-Length", getContentLength());
+ numHeaders++;
}
// Add the session ID cookie if necessary
@@ -128,15 +133,53 @@
Iterator items = cookies.iterator();
while (items.hasNext()) {
Cookie cookie = (Cookie) items.next();
+
+ cookieValue.delete(0, cookieValue.length());
+ CookieTools.getCookieHeaderValue(cookie, cookieValue);
+
addHeader(CookieTools.getCookieHeaderName(cookie),
- CookieTools.getCookieHeaderValue(cookie));
+ cookieValue.toString());
}
}
+ // figure out how many headers...
+ // can have multiple headers of the same name...
+ // need to loop through headers once to get total
+ // count, once to add header to outBuf
+ String[] hnames = getHeaderNames();
+ Object[] hvalues = new Object[hnames.length];
+
+ int i;
+ for (i = 0; i < hnames.length; ++i) {
+ String[] tmp = getHeaderValues(hnames[i]);
+ numHeaders += tmp.length;
+ hvalues[i] = tmp;
+ }
+
+ ajp13.beginSendHeaders(getStatus(), getStatusMessage(getStatus()), numHeaders);
+
+ // send each header
+ if (getContentType() != null) {
+ ajp13.sendHeader("Content-Type", getContentType());
+ }
+
+ if (getContentLength() >= 0) {
+ ajp13.sendHeader("Content-Length", String.valueOf(getContentLength()));
+ }
+
+ for (i = 0; i < hnames.length; ++i) {
+ String name = hnames[i];
+ String[] values = (String[])hvalues[i];
+
+ for (int j = 0; j < values.length; ++j) {
+ ajp13.sendHeader(name, values[j]);
+ }
+ }
+
+ ajp13.endSendHeaders();
+
// The response is now committed
committed = true;
-
- this.ajp13.sendHeaders(this);
}
public void finishResponse() throws IOException {