1 7 package winstone.ajp13; 8 9 import java.io.ByteArrayOutputStream ; 10 import java.io.IOException ; 11 import java.io.OutputStream ; 12 import java.io.UnsupportedEncodingException ; 13 import java.util.Hashtable ; 14 import java.util.Iterator ; 15 import java.util.Map ; 16 17 import javax.servlet.http.Cookie ; 18 19 import winstone.Logger; 20 import winstone.WinstoneException; 21 import winstone.WinstoneOutputStream; 22 23 30 public class Ajp13OutputStream extends WinstoneOutputStream { 31 byte CONTAINER_SEND_BODY_CHUNK = 0x03; 33 byte CONTAINER_SEND_HEADERS = 0x04; 34 byte CONTAINER_END_RESPONSE = 0x05; 35 36 39 static Map headerCodes = null; 40 41 static { 42 headerCodes = new Hashtable (); 43 headerCodes.put("content-type", new byte[] { (byte) 0xA0, 0x01 }); 44 headerCodes.put("content-language", new byte[] { (byte) 0xA0, 0x02 }); 45 headerCodes.put("content-length", new byte[] { (byte) 0xA0, 0x03 }); 46 headerCodes.put("date", new byte[] { (byte) 0xA0, 0x04 }); 47 headerCodes.put("last-modified", new byte[] { (byte) 0xA0, 0x05 }); 48 headerCodes.put("location", new byte[] { (byte) 0xA0, 0x06 }); 49 headerCodes.put("set-cookie", new byte[] { (byte) 0xA0, 0x07 }); 50 headerCodes.put("set-cookie2", new byte[] { (byte) 0xA0, 0x08 }); 51 headerCodes.put("servlet-engine", new byte[] { (byte) 0xA0, 0x09 }); 52 headerCodes.put("server", new byte[] { (byte) 0xA0, 0x09 }); 53 headerCodes.put("status", new byte[] { (byte) 0xA0, 0x0A }); 54 headerCodes.put("www-authenticate", new byte[] { (byte) 0xA0, 0x0B }); 55 } 56 57 private String headerEncoding; 58 59 public Ajp13OutputStream(OutputStream outStream, String headerEncoding) { 60 super(outStream, false); 61 this.headerEncoding = headerEncoding; 62 } 63 64 public void commit() throws IOException { 65 Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES, 66 "WinstoneOutputStream.CommittedBytes", "" + this.bytesCommitted); 67 this.buffer.flush(); 68 69 if (!this.committed) { 71 this.owner.validateHeaders(); 72 this.committed = true; 73 74 ByteArrayOutputStream headerArrayStream = new ByteArrayOutputStream (); 75 for (Iterator i = this.owner.getHeaders().iterator(); i.hasNext();) { 76 String header = (String ) i.next(); 77 int colonPos = header.indexOf(':'); 78 if (colonPos == -1) 79 throw new WinstoneException(Ajp13Listener.AJP_RESOURCES.getString( 80 "Ajp13OutputStream.NoColonHeader", header)); 81 String headerName = header.substring(0, colonPos).trim(); 82 String headerValue = header.substring(colonPos + 1).trim(); 83 byte headerCode[] = (byte[]) headerCodes.get(headerName 84 .toLowerCase()); 85 if (headerCode == null) { 86 headerArrayStream.write(getStringBlock(headerName)); 87 } else { 88 headerArrayStream.write(headerCode); 89 } 90 headerArrayStream.write(getStringBlock(headerValue)); 91 } 92 93 for (Iterator i = this.owner.getCookies().iterator(); i.hasNext();) { 94 Cookie cookie = (Cookie ) i.next(); 95 String cookieText = this.owner.writeCookie(cookie); 96 int colonPos = cookieText.indexOf(':'); 97 if (colonPos == -1) 98 throw new WinstoneException(Ajp13Listener.AJP_RESOURCES.getString( 99 "Ajp13OutputStream.NoColonHeader", cookieText)); 100 String headerName = cookieText.substring(0, colonPos).trim(); 101 String headerValue = cookieText.substring(colonPos + 1).trim(); 102 byte headerCode[] = (byte[]) headerCodes.get(headerName.toLowerCase()); 103 if (headerCode == null) { 104 headerArrayStream.write(getStringBlock(headerName)); 105 } else { 106 headerArrayStream.write(headerCode); 107 } 108 headerArrayStream.write(getStringBlock(headerValue)); 109 } 110 111 byte headerArray[] = headerArrayStream.toByteArray(); 114 byte headerPacket[] = new byte[12]; 115 headerPacket[0] = (byte) 0x41; 116 headerPacket[1] = (byte) 0x42; 117 setIntBlock(headerArray.length + 8, headerPacket, 2); 118 headerPacket[4] = CONTAINER_SEND_HEADERS; 119 setIntBlock(this.owner.getStatus(), headerPacket, 5); 120 setIntBlock(0, headerPacket, 7); headerPacket[9] = (byte) 0x00; 122 setIntBlock(this.owner.getHeaders().size() 123 + this.owner.getCookies().size(), headerPacket, 10); 124 125 128 this.outStream.write(headerPacket); 129 this.outStream.write(headerArray); 130 } 131 132 byte bufferContents[] = this.buffer.toByteArray(); 134 int position = 0; 135 while (position < bufferContents.length) { 136 int packetLength = Math.min(bufferContents.length - position, 8184); 137 byte responsePacket[] = new byte[packetLength + 8]; 138 responsePacket[0] = 0x41; 139 responsePacket[1] = 0x42; 140 setIntBlock(packetLength + 4, responsePacket, 2); 141 responsePacket[4] = CONTAINER_SEND_BODY_CHUNK; 142 setIntBlock(packetLength, responsePacket, 5); 143 System.arraycopy(bufferContents, position, responsePacket, 7, packetLength); 144 responsePacket[packetLength + 7] = 0x00; 145 position += packetLength; 146 147 this.outStream.write(responsePacket); 149 } 150 151 this.buffer.reset(); 152 this.bufferPosition = 0; 153 } 154 155 public void finishResponse() throws IOException { 156 byte endResponse[] = new byte[] { 0x41, 0x42, 0x00, 0x02, 158 CONTAINER_END_RESPONSE, 1 }; 159 this.outStream.write(endResponse); 161 } 162 163 166 public byte[] getIntBlock(int integer) { 167 byte hi = (byte) (0xFF & (integer >> 8)); 168 byte lo = (byte) (0xFF & (integer - (hi << 8))); 169 return new byte[] { hi, lo }; 170 } 171 172 175 public static void setIntBlock(int integer, byte packet[], int offset) { 176 byte hi = (byte) (0xFF & (integer >> 8)); 177 byte lo = (byte) (0xFF & (integer - (hi << 8))); 178 packet[offset] = hi; 179 packet[offset + 1] = lo; 180 } 181 182 185 public byte[] getStringBlock(String text) 186 throws UnsupportedEncodingException { 187 byte textBytes[] = text.getBytes(headerEncoding); 188 byte outArray[] = new byte[textBytes.length + 3]; 189 System.arraycopy(getIntBlock(textBytes.length), 0, outArray, 0, 2); 190 System.arraycopy(textBytes, 0, outArray, 2, textBytes.length); 191 outArray[textBytes.length + 2] = 0x00; 192 return outArray; 193 } 194 195 } 196 | Popular Tags |