001: /*
002: * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: */
007: package winstone.ajp13;
008:
009: import java.io.IOException;
010: import java.io.InputStream;
011: import java.io.UnsupportedEncodingException;
012: import java.util.Hashtable;
013: import java.util.Map;
014:
015: import winstone.Logger;
016: import winstone.RequestHandlerThread;
017: import winstone.WinstoneException;
018:
019: /**
020: * Models a single incoming ajp13 packet.
021: *
022: * Fixes by Cory Osborn 2007/4/3 - IIS related. Thanks
023: *
024: * @author mailto: <a href="rick_knowles@hotmail.com">Rick Knowles</a>
025: * @version $Id: Ajp13IncomingPacket.java,v 1.6 2007/04/03 01:23:19 rickknowles Exp $
026: */
027: public class Ajp13IncomingPacket {
028: // Server originated packet types
029: byte SERVER_FORWARD_REQUEST = 0x02;
030:
031: // public static byte SERVER_SHUTDOWN = 0x07; //not implemented
032: // public static byte SERVER_PING = 0x08; //not implemented
033: // public static byte SERVER_CPING = 0x10; //not implemented
034:
035: private int packetLength;
036: private byte packetBytes[];
037: private byte packetType;
038: private String method;
039: private String protocol;
040: private String uri;
041: private String remoteAddr;
042: private String remoteHost;
043: private String serverName;
044: private int serverPort;
045: private boolean isSSL;
046: private String headers[];
047: private Map attributes;
048:
049: /**
050: * Constructor
051: */
052: public Ajp13IncomingPacket(InputStream in,
053: RequestHandlerThread handler) throws IOException {
054: // Get the incoming packet flag
055: byte headerBuffer[] = new byte[4];
056: int headerBytesRead = in.read(headerBuffer);
057: handler.setRequestStartTime();
058: if (headerBytesRead != 4)
059: throw new WinstoneException(Ajp13Listener.AJP_RESOURCES
060: .getString("Ajp13IncomingPacket.InvalidHeader"));
061: else if ((headerBuffer[0] != 0x12) || (headerBuffer[1] != 0x34))
062: throw new WinstoneException(Ajp13Listener.AJP_RESOURCES
063: .getString("Ajp13IncomingPacket.InvalidHeader"));
064:
065: // Read in the whole packet
066: packetLength = ((headerBuffer[2] & 0xFF) << 8)
067: + (headerBuffer[3] & 0xFF);
068: packetBytes = new byte[packetLength];
069: int packetBytesRead = in.read(packetBytes);
070:
071: if (packetBytesRead < packetLength)
072: throw new WinstoneException(Ajp13Listener.AJP_RESOURCES
073: .getString("Ajp13IncomingPacket.ShortPacket"));
074: // Ajp13Listener.packetDump(packetBytes, packetBytesRead);
075: }
076:
077: public byte parsePacket(String encoding) throws IOException {
078: int position = 0;
079: this .packetType = packetBytes[position++];
080:
081: if (this .packetType != SERVER_FORWARD_REQUEST)
082: throw new WinstoneException(Ajp13Listener.AJP_RESOURCES
083: .getString("Ajp13IncomingPacket.UnknownPacketType",
084: this .packetType + ""));
085:
086: // Check for terminator
087: if (packetBytes[packetLength - 1] != (byte) 255)
088: throw new WinstoneException(Ajp13Listener.AJP_RESOURCES
089: .getString("Ajp13IncomingPacket.InvalidTerminator"));
090:
091: this .method = decodeMethodType(packetBytes[position++]);
092: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
093: "Ajp13IncomingPacket.Method", method);
094:
095: // Protocol
096: int protocolLength = readInteger(position, packetBytes, true);
097: position += 2;
098: this .protocol = (protocolLength > -1) ? readString(position,
099: packetBytes, encoding, protocolLength) : null;
100: position += protocolLength + 1;
101: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
102: "Ajp13IncomingPacket.Protocol", protocol);
103:
104: // URI
105: int uriLength = readInteger(position, packetBytes, true);
106: position += 2;
107: this .uri = (uriLength > -1) ? readString(position, packetBytes,
108: encoding, uriLength) : null;
109: position += uriLength + 1;
110: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
111: "Ajp13IncomingPacket.URI", uri);
112:
113: // Remote addr
114: int remoteAddrLength = readInteger(position, packetBytes, true);
115: position += 2;
116: this .remoteAddr = (remoteAddrLength > -1) ? readString(
117: position, packetBytes, encoding, remoteAddrLength)
118: : null;
119: position += remoteAddrLength + 1;
120: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
121: "Ajp13IncomingPacket.RemoteAddress", remoteAddr);
122:
123: // Remote host
124: int remoteHostLength = readInteger(position, packetBytes, true);
125: position += 2;
126: this .remoteHost = (remoteHostLength > -1) ? readString(
127: position, packetBytes, encoding, remoteHostLength)
128: : null;
129: position += remoteHostLength + 1;
130: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
131: "Ajp13IncomingPacket.RemoteHost", remoteHost);
132:
133: // Server name
134: int serverNameLength = readInteger(position, packetBytes, true);
135: position += 2;
136: this .serverName = (serverNameLength > -1) ? readString(
137: position, packetBytes, encoding, serverNameLength)
138: : null;
139: position += serverNameLength + 1;
140: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
141: "Ajp13IncomingPacket.ServerName", serverName);
142:
143: this .serverPort = readInteger(position, packetBytes, false);
144: position += 2;
145: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
146: "Ajp13IncomingPacket.ServerPort", "" + serverPort);
147:
148: this .isSSL = readBoolean(position++, packetBytes);
149: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
150: "Ajp13IncomingPacket.SSL", "" + isSSL);
151:
152: // Read headers
153: int headerCount = readInteger(position, packetBytes, false);
154: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
155: "Ajp13IncomingPacket.HeaderCount", "" + headerCount);
156: position += 2;
157: this .headers = new String[headerCount];
158: for (int n = 0; n < headerCount; n++) {
159: // Header name
160: int headerTypeOrLength = readInteger(position, packetBytes,
161: false);
162: position += 2;
163: String headerName = null;
164: if (packetBytes[position - 2] == (byte) 0xA0)
165: headerName = decodeHeaderType(headerTypeOrLength);
166: else {
167: headerName = readString(position, packetBytes,
168: encoding, headerTypeOrLength);
169: position += headerTypeOrLength + 1;
170: }
171:
172: // Header value
173: int headerValueLength = readInteger(position, packetBytes,
174: true);
175: position += 2;
176: this .headers[n] = headerName
177: + ": "
178: + ((headerValueLength > -1) ? readString(position,
179: packetBytes, encoding, headerValueLength)
180: : "");
181: position += headerValueLength + 1;
182: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
183: "Ajp13IncomingPacket.Header", this .headers[n]);
184: }
185:
186: // Attribute parsing
187: this .attributes = new Hashtable();
188: while (position < packetLength - 2) {
189: String attName = decodeAttributeType(packetBytes[position++]);
190: int attValueLength = readInteger(position, packetBytes,
191: true);
192: position += 2;
193: String attValue = (attValueLength > -1) ? readString(
194: position, packetBytes, encoding, attValueLength)
195: : null;
196: position += attValueLength + 1;
197:
198: this .attributes.put(attName, attValue);
199: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
200: "Ajp13IncomingPacket.Attribute", new String[] {
201: attName, attValue });
202: }
203: Logger.log(Logger.FULL_DEBUG, Ajp13Listener.AJP_RESOURCES,
204: "Ajp13IncomingPacket.SuccessfullyReadRequest", ""
205: + packetLength);
206: return this .packetType;
207: }
208:
209: public int getPacketLength() {
210: return this .packetLength;
211: }
212:
213: public String getMethod() {
214: return this .method;
215: }
216:
217: public String getProtocol() {
218: return this .protocol;
219: }
220:
221: public String getURI() {
222: return this .uri;
223: }
224:
225: public String getRemoteAddress() {
226: return this .remoteAddr;
227: }
228:
229: public String getRemoteHost() {
230: return this .remoteHost;
231: }
232:
233: public String getServerName() {
234: return this .serverName;
235: }
236:
237: public int getServerPort() {
238: return this .serverPort;
239: }
240:
241: public boolean isSSL() {
242: return this .isSSL;
243: }
244:
245: public String[] getHeaders() {
246: return this .headers;
247: }
248:
249: public Map getAttributes() {
250: return this .attributes;
251: }
252:
253: /**
254: * Read a single integer from the stream
255: */
256: private int readInteger(int position, byte packet[],
257: boolean forStringLength) {
258: if (forStringLength && (packet[position] == (byte) 0xFF)
259: && (packet[position + 1] == (byte) 0xFF))
260: return -1;
261: else
262: return ((packet[position] & 0xFF) << 8)
263: + (packet[position + 1] & 0xFF);
264: }
265:
266: /**
267: * Read a single boolean from the stream
268: */
269: private boolean readBoolean(int position, byte packet[]) {
270: return (packet[position] == (byte) 1);
271: }
272:
273: /**
274: * Read a single string from the stream
275: */
276: private String readString(int position, byte packet[],
277: String encoding, int length)
278: throws UnsupportedEncodingException {
279: // System.out.println("Reading string length: " + length +
280: // " position=" + position + " packetLength=" + packet.length);
281: return length == 0 ? "" : new String(packet, position, length,
282: encoding);
283: }
284:
285: /**
286: * Decodes the method types into Winstone HTTP method strings
287: */
288: private String decodeMethodType(byte methodType) {
289: switch (methodType) {
290: case 1:
291: return "OPTIONS";
292: case 2:
293: return "GET";
294: case 3:
295: return "HEAD";
296: case 4:
297: return "POST";
298: case 5:
299: return "PUT";
300: case 6:
301: return "DELETE";
302: case 7:
303: return "TRACE";
304: case 8:
305: return "PROPFIND";
306: case 9:
307: return "PROPPATCH";
308: case 10:
309: return "MKCOL";
310: case 11:
311: return "COPY";
312: case 12:
313: return "MOVE";
314: case 13:
315: return "LOCK";
316: case 14:
317: return "UNLOCK";
318: case 15:
319: return "ACL";
320: case 16:
321: return "REPORT";
322: case 17:
323: return "VERSION-CONTROL";
324: case 18:
325: return "CHECKIN";
326: case 19:
327: return "CHECKOUT";
328: case 20:
329: return "UNCHECKOUT";
330: case 21:
331: return "SEARCH";
332: case 22:
333: return "MKWORKSPACE";
334: case 23:
335: return "UPDATE";
336: case 24:
337: return "LABEL";
338: case 25:
339: return "MERGE";
340: case 26:
341: return "BASELINE_CONTROL";
342: case 27:
343: return "MKACTIVITY";
344: default:
345: return "UNKNOWN";
346: }
347: }
348:
349: /**
350: * Decodes the header types into Winstone HTTP header strings
351: */
352: private String decodeHeaderType(int headerType) {
353: switch (headerType) {
354: case 0xA001:
355: return "Accept";
356: case 0xA002:
357: return "Accept-Charset";
358: case 0xA003:
359: return "Accept-Encoding";
360: case 0xA004:
361: return "Accept-Language";
362: case 0xA005:
363: return "Authorization";
364: case 0xA006:
365: return "Connection";
366: case 0xA007:
367: return "Content-Type";
368: case 0xA008:
369: return "Content-Length";
370: case 0xA009:
371: return "Cookie";
372: case 0xA00A:
373: return "Cookie2";
374: case 0xA00B:
375: return "Host";
376: case 0xA00C:
377: return "Pragma";
378: case 0xA00D:
379: return "Referer";
380: case 0xA00E:
381: return "User-Agent";
382: default:
383: return null;
384: }
385: }
386:
387: /**
388: * Decodes the header types into Winstone HTTP header strings
389: */
390: private String decodeAttributeType(byte attributeType) {
391: switch (attributeType) {
392: case 0x01:
393: return "context";
394: case 0x02:
395: return "servlet_path";
396: case 0x03:
397: return "remote_user";
398: case 0x04:
399: return "auth_type";
400: case 0x05:
401: return "query_string";
402: case 0x06:
403: return "jvm_route";
404: case 0x07:
405: return "ssl_cert";
406: case 0x08:
407: return "ssl_cipher";
408: case 0x09:
409: return "ssl_session";
410: case 0x0A:
411: return "req_attribute";
412: default:
413: return null;
414: }
415: }
416: }
|