KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > winstone > ajp13 > Ajp13OutputStream


1 /*
2  * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
3  * Distributed under the terms of either:
4  * - the common development and distribution license (CDDL), v1.0; or
5  * - the GNU Lesser General Public License, v2.1 or later
6  */

7 package winstone.ajp13;
8
9 import java.io.ByteArrayOutputStream JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.io.OutputStream JavaDoc;
12 import java.io.UnsupportedEncodingException JavaDoc;
13 import java.util.Hashtable JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.Map JavaDoc;
16
17 import javax.servlet.http.Cookie JavaDoc;
18
19 import winstone.Logger;
20 import winstone.WinstoneException;
21 import winstone.WinstoneOutputStream;
22
23 /**
24  * Extends the winstone output stream, so that the ajp13 protocol requirements
25  * can be fulfilled.
26  *
27  * @author mailto: <a HREF="rick_knowles@hotmail.com">Rick Knowles</a>
28  * @version $Id: Ajp13OutputStream.java,v 1.6 2006/02/28 07:32:48 rickknowles Exp $
29  */

30 public class Ajp13OutputStream extends WinstoneOutputStream {
31     // Container originated packet types
32
byte CONTAINER_SEND_BODY_CHUNK = 0x03;
33     byte CONTAINER_SEND_HEADERS = 0x04;
34     byte CONTAINER_END_RESPONSE = 0x05;
35
36     // byte CONTAINER_GET_BODY_CHUNK = 0x06;
37
// byte CONTAINER_CPONG_REPLY = 0x09;
38

39     static Map JavaDoc headerCodes = null;
40
41     static {
42         headerCodes = new Hashtable JavaDoc();
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 JavaDoc headerEncoding;
58
59     public Ajp13OutputStream(OutputStream JavaDoc outStream, String JavaDoc headerEncoding) {
60         super(outStream, false);
61         this.headerEncoding = headerEncoding;
62     }
63
64     public void commit() throws IOException JavaDoc {
65         Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
66                 "WinstoneOutputStream.CommittedBytes", "" + this.bytesCommitted);
67         this.buffer.flush();
68
69         // If we haven't written the headers yet, write them out
70
if (!this.committed) {
71             this.owner.validateHeaders();
72             this.committed = true;
73
74             ByteArrayOutputStream JavaDoc headerArrayStream = new ByteArrayOutputStream JavaDoc();
75             for (Iterator JavaDoc i = this.owner.getHeaders().iterator(); i.hasNext();) {
76                 String JavaDoc header = (String JavaDoc) 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 JavaDoc headerName = header.substring(0, colonPos).trim();
82                 String JavaDoc 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 JavaDoc i = this.owner.getCookies().iterator(); i.hasNext();) {
94                 Cookie JavaDoc cookie = (Cookie JavaDoc) i.next();
95                 String JavaDoc 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 JavaDoc headerName = cookieText.substring(0, colonPos).trim();
101                 String JavaDoc 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             // Write packet header + prefix + status code + status msg + header
112
// count
113
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); // empty msg
121
headerPacket[9] = (byte) 0x00;
122             setIntBlock(this.owner.getHeaders().size()
123                     + this.owner.getCookies().size(), headerPacket, 10);
124
125             // Ajp13Listener.packetDump(headerPacket, headerPacket.length);
126
// Ajp13Listener.packetDump(headerArray, headerArray.length);
127

128             this.outStream.write(headerPacket);
129             this.outStream.write(headerArray);
130         }
131
132         // Write out the contents of the buffer in max 8k chunks
133
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             // Ajp13Listener.packetDump(responsePacket, responsePacket.length);
148
this.outStream.write(responsePacket);
149         }
150
151         this.buffer.reset();
152         this.bufferPosition = 0;
153     }
154
155     public void finishResponse() throws IOException JavaDoc {
156         // Send end response packet
157
byte endResponse[] = new byte[] { 0x41, 0x42, 0x00, 0x02,
158                 CONTAINER_END_RESPONSE, 1 };
159         // Ajp13Listener.packetDump(endResponse, endResponse.length);
160
this.outStream.write(endResponse);
161     }
162
163     /**
164      * Useful generic method for getting ajp13 format integers in a packet.
165      */

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     /**
173      * Useful generic method for setting ajp13 format integers in a packet.
174      */

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     /**
183      * Useful generic method for getting ajp13 format strings in a packet.
184      */

185     public byte[] getStringBlock(String JavaDoc text)
186             throws UnsupportedEncodingException JavaDoc {
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