I thought I'd test out my new status as the resident Ajp13 expert by fixing this bug, and I think I've got it. I'm attaching patches to util/MimeHeaders.java and modules/server/Ajp13.java. I've done some minimal testing, and it seems to fix the problem. I also did a tiny bit of further cleanup in Ajp13 (in case you look at the patch in detail). -Dan Palle Girgensohn wrote: > > Hi! > > Just installed tomcat 3.2 final. > > I am forced to still use apj12 due to tomcat failing to create > multiple cookies at once when using ajp13 (and possibly also > redirect): > > > Cheers, > Palle > -- > Partitur Informationsteknik AB > Wenner-Gren Center +46 8 566 280 02 > 113 46 Stockholm +46 70 785 86 02 > Sweden [EMAIL PROTECTED] -- Dan Milstein // [EMAIL PROTECTED]
Index: MimeHeaders.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaders.java,v retrieving revision 1.17 diff -u -r1.17 MimeHeaders.java --- MimeHeaders.java 2000/11/20 21:37:45 1.17 +++ MimeHeaders.java 2000/12/06 05:11:38 @@ -210,18 +210,29 @@ // -------------------- -------------------- /** - * Returns an enumeration of strings representing the header field names. - * Field names may appear multiple times in this enumeration, indicating - * that multiple fields with that name exist in this header. + * Returns an enumeration of strings representing the header field + * names. Field names are unique in this enumeration (which is + * actually not that useful) */ public Enumeration names() { return new NamesEnumerator(this); } + /** + * Return an enumeration of header values for a given name. + */ public Enumeration values(String name) { return new ValuesEnumerator(this, name); } + /** + * Return an enumeration of 2-element String arrays representing pairs + * of header names and header values. + */ + public Enumeration getNamesValues() { + return new NamesValuesEnumerator(this); + } + // -------------------- Adding headers -------------------- @@ -419,6 +430,47 @@ findNext(); return current.toString(); } +} + +/** + * Enumerate the names and values together -- cleans up handling of + * multiple headers with identical names (Set-Cookie, say). Each element + * of the enumeration is an array of length two: { name, value } + **/ +class NamesValuesEnumerator implements Enumeration { + int pos; + int size; + MimeHeaders headers; + String[] nextNameValuePair = new String[2]; + String[] returnNameValuePair = new String[2]; // Reused -- safe? + + NamesValuesEnumerator(MimeHeaders headers) { + pos = 0; + this.headers = headers; + size = headers.size(); + findNext(); + } + + private void findNext() { + nextNameValuePair[0] = null; + if(pos < size) { + nextNameValuePair[0] = headers.getName( pos ).toString(); + nextNameValuePair[1] = headers.getValue( pos ).toString(); + pos++; + } + } + + public boolean hasMoreElements() { + return nextNameValuePair[0] != null; + } + + public Object nextElement() { + returnNameValuePair[0] = nextNameValuePair[0]; + returnNameValuePair[1] = nextNameValuePair[1]; + findNext(); + return returnNameValuePair; + } + } class MimeHeaderField {
Index: Ajp13.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/Ajp13.java,v retrieving revision 1.6 diff -u -r1.6 Ajp13.java --- Ajp13.java 2000/12/05 06:30:15 1.6 +++ Ajp13.java 2000/12/06 05:12:31 @@ -257,7 +257,7 @@ req.serverName().setString( msg.getString()); req.setServerPort( msg.getInt()); - isSSL = (msg.getByte() != 0); + isSSL = msg.getBool(); // Decode headers MimeHeaders headers = req.getMimeHeaders(); @@ -444,16 +444,18 @@ outBuf.appendInt(headers.size()); - Enumeration e = headers.names(); + Enumeration e = headers.getNamesValues(); while(e.hasMoreElements()) { - String headerName = (String)e.nextElement(); + String[] nameValuePair = (String[]) e.nextElement(); + String headerName = nameValuePair[0]; + String headerValue = nameValuePair[1]; int sc = headerNameToSc(headerName); if(-1 != sc) { outBuf.appendInt(sc); } else { outBuf.appendString(headerName); } - outBuf.appendString(headers.getHeader(headerName)); + outBuf.appendString(headerValue); } outBuf.end(); @@ -520,13 +522,13 @@ /** * Signal the web server that the servlet has finished handling this - * request. + * request, and that the connection can be reused. */ public void finish() throws IOException { outBuf.reset(); outBuf.appendByte(JK_AJP13_END_RESPONSE); - outBuf.appendByte((byte)1); + outBuf.appendBool(true); // Reuse this connection outBuf.end(); send(outBuf); } @@ -723,6 +725,10 @@ buff[pos++] = val; } + public void appendBool( boolean val) { + buff[pos++] = (byte) (val ? 1 : 0); + } + /** * Write a String out at the current write position. Strings are * encoded with the length in two bytes first, then the string, and @@ -754,7 +760,7 @@ * terminating \0 (which is <B>not</B> included in the encoded * length). * - * @param b The array from whcih to copy bytes. + * @param b The array from which to copy bytes. * @param off The offset into the array at which to start copying * @param len The number of bytes to copy. */ @@ -803,6 +809,10 @@ public byte peekByte() { return buff[pos]; + } + + public boolean getBool() { + return (getByte() == (byte) 1); } public static final String DEFAULT_CHAR_ENCODING = "8859_1";