001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.jk.common;
018:
019: import java.io.IOException;
020:
021: import org.apache.jk.core.Msg;
022: import org.apache.tomcat.util.buf.ByteChunk;
023: import org.apache.tomcat.util.buf.MessageBytes;
024:
025: /**
026: * A single packet for communication between the web server and the
027: * container. Designed to be reused many times with no creation of
028: * garbage. Understands the format of data types for these packets.
029: * Can be used (somewhat confusingly) for both incoming and outgoing
030: * packets.
031: *
032: * @see Ajp14/Ajp13Packet
033: *
034: * @author Henri Gomez [hgomez@apache.org]
035: * @author Dan Milstein [danmil@shore.net]
036: * @author Keith Wannamaker [Keith@Wannamaker.org]
037: * @author Kevin Seguin
038: * @author Costin Manolache
039: */
040: public class MsgAjp extends Msg {
041: private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
042: .getLog(MsgAjp.class);
043:
044: // that's the original buffer size in ajp13 - otherwise we'll get interoperability problems.
045: private byte buf[] = new byte[8 * 1024];
046: // The current read or write position in the buffer
047: private int pos;
048: /**
049: * This actually means different things depending on whether the
050: * packet is read or write. For read, it's the length of the
051: * payload (excluding the header). For write, it's the length of
052: * the packet as a whole (counting the header). Oh, well.
053: */
054: private int len;
055:
056: /**
057: * Prepare this packet for accumulating a message from the container to
058: * the web server. Set the write position to just after the header
059: * (but leave the length unwritten, because it is as yet unknown).
060: */
061: public void reset() {
062: len = 4;
063: pos = 4;
064: }
065:
066: /**
067: * For a packet to be sent to the web server, finish the process of
068: * accumulating data and write the length of the data payload into
069: * the header.
070: */
071: public void end() {
072: len = pos;
073: int dLen = len - 4;
074:
075: buf[0] = (byte) 0x41;
076: buf[1] = (byte) 0x42;
077: buf[2] = (byte) ((dLen >>> 8) & 0xFF);
078: buf[3] = (byte) (dLen & 0xFF);
079: }
080:
081: public byte[] getBuffer() {
082: return buf;
083: }
084:
085: public int getLen() {
086: return len;
087: }
088:
089: // ============ Data Writing Methods ===================
090:
091: /**
092: * Add an int.
093: *
094: * @param val The integer to write.
095: */
096: public void appendInt(int val) {
097: buf[pos++] = (byte) ((val >>> 8) & 0xFF);
098: buf[pos++] = (byte) (val & 0xFF);
099: }
100:
101: public void appendByte(int val) {
102: buf[pos++] = (byte) val;
103: }
104:
105: public void appendLongInt(int val) {
106: buf[pos++] = (byte) ((val >>> 24) & 0xFF);
107: buf[pos++] = (byte) ((val >>> 16) & 0xFF);
108: buf[pos++] = (byte) ((val >>> 8) & 0xFF);
109: buf[pos++] = (byte) (val & 0xFF);
110: }
111:
112: /**
113: * Write a String out at the current write position. Strings are
114: * encoded with the length in two bytes first, then the string, and
115: * then a terminating \0 (which is <B>not</B> included in the
116: * encoded length). The terminator is for the convenience of the C
117: * code, where it saves a round of copying. A null string is
118: * encoded as a string with length 0.
119: */
120: public void appendBytes(MessageBytes mb) throws IOException {
121: if (mb == null || mb.isNull()) {
122: appendInt(0);
123: appendByte(0);
124: return;
125: }
126:
127: // XXX Convert !!
128: ByteChunk bc = mb.getByteChunk();
129: appendByteChunk(bc);
130: }
131:
132: public void appendByteChunk(ByteChunk bc) throws IOException {
133: if (bc == null) {
134: log.error("appendByteChunk() null");
135: appendInt(0);
136: appendByte(0);
137: return;
138: }
139:
140: byte[] bytes = bc.getBytes();
141: int start = bc.getStart();
142: appendInt(bc.getLength());
143: cpBytes(bytes, start, bc.getLength());
144: appendByte(0);
145: }
146:
147: /**
148: * Copy a chunk of bytes into the packet, starting at the current
149: * write position. The chunk of bytes is encoded with the length
150: * in two bytes first, then the data itself, and finally a
151: * terminating \0 (which is <B>not</B> included in the encoded
152: * length).
153: *
154: * @param b The array from which to copy bytes.
155: * @param off The offset into the array at which to start copying
156: * @param len The number of bytes to copy.
157: */
158: public void appendBytes(byte b[], int off, int numBytes) {
159: appendInt(numBytes);
160: cpBytes(b, off, numBytes);
161: appendByte(0);
162: }
163:
164: private void cpBytes(byte b[], int off, int numBytes) {
165: if (pos + numBytes >= buf.length) {
166: log.error("Buffer overflow: buffer.len=" + buf.length
167: + " pos=" + pos + " data=" + numBytes);
168: dump("Overflow/coBytes");
169: log.error("Overflow ", new Throwable());
170: return;
171: }
172: System.arraycopy(b, off, buf, pos, numBytes);
173: pos += numBytes;
174: // buf[pos + numBytes] = 0; // Terminating \0
175: }
176:
177: // ============ Data Reading Methods ===================
178:
179: /**
180: * Read an integer from packet, and advance the read position past
181: * it. Integers are encoded as two unsigned bytes with the
182: * high-order byte first, and, as far as I can tell, in
183: * little-endian order within each byte.
184: */
185: public int getInt() {
186: int b1 = buf[pos++] & 0xFF; // No swap, Java order
187: int b2 = buf[pos++] & 0xFF;
188:
189: return (b1 << 8) + b2;
190: }
191:
192: public int peekInt() {
193: int b1 = buf[pos] & 0xFF; // No swap, Java order
194: int b2 = buf[pos + 1] & 0xFF;
195:
196: return (b1 << 8) + b2;
197: }
198:
199: public byte getByte() {
200: byte res = buf[pos++];
201: return res;
202: }
203:
204: public byte peekByte() {
205: byte res = buf[pos];
206: return res;
207: }
208:
209: public void getBytes(MessageBytes mb) {
210: int length = getInt();
211: if ((length == 0xFFFF) || (length == -1)) {
212: mb.setString(null);
213: return;
214: }
215: mb.setBytes(buf, pos, length);
216: pos += length;
217: pos++; // Skip the terminating \0
218: }
219:
220: /**
221: * Copy a chunk of bytes from the packet into an array and advance
222: * the read position past the chunk. See appendBytes() for details
223: * on the encoding.
224: *
225: * @return The number of bytes copied.
226: */
227: public int getBytes(byte dest[]) {
228: int length = getInt();
229: if (length > buf.length) {
230: // XXX Should be if(pos + length > buff.legth)?
231: log.error("getBytes() buffer overflow " + length + " "
232: + buf.length);
233: }
234:
235: if ((length == 0xFFFF) || (length == -1)) {
236: log.info("Null string " + length);
237: return 0;
238: }
239:
240: System.arraycopy(buf, pos, dest, 0, length);
241: pos += length;
242: pos++; // Skip terminating \0 XXX I believe this is wrong but harmless
243: return length;
244: }
245:
246: /**
247: * Read a 32 bits integer from packet, and advance the read position past
248: * it. Integers are encoded as four unsigned bytes with the
249: * high-order byte first, and, as far as I can tell, in
250: * little-endian order within each byte.
251: */
252: public int getLongInt() {
253: int b1 = buf[pos++] & 0xFF; // No swap, Java order
254: b1 <<= 8;
255: b1 |= (buf[pos++] & 0xFF);
256: b1 <<= 8;
257: b1 |= (buf[pos++] & 0xFF);
258: b1 <<= 8;
259: b1 |= (buf[pos++] & 0xFF);
260: return b1;
261: }
262:
263: public int getHeaderLength() {
264: return 4;
265: }
266:
267: public int processHeader() {
268: pos = 0;
269: int mark = getInt();
270: len = getInt();
271:
272: if (mark != 0x1234 && mark != 0x4142) {
273: // XXX Logging
274: log.error("BAD packet signature " + mark);
275: dump("In: ");
276: return -1;
277: }
278:
279: if (log.isDebugEnabled())
280: log.debug("Received " + len + " " + buf[0]);
281: return len;
282: }
283:
284: public void dump(String msg) {
285: log.debug(msg + ": " + buf + " " + pos + "/" + (len + 4));
286: int max = pos;
287: if (len + 4 > pos)
288: max = len + 4;
289: if (max > 1000)
290: max = 1000;
291: for (int j = 0; j < max; j += 16)
292: System.out.println(hexLine(buf, j, len));
293:
294: }
295:
296: /* -------------------- Utilities -------------------- */
297: // XXX Move to util package
298: public static String hexLine(byte buf[], int start, int len) {
299: StringBuffer sb = new StringBuffer();
300: for (int i = start; i < start + 16; i++) {
301: if (i < len + 4)
302: sb.append(hex(buf[i]) + " ");
303: else
304: sb.append(" ");
305: }
306: sb.append(" | ");
307: for (int i = start; i < start + 16 && i < len + 4; i++) {
308: if (!Character.isISOControl((char) buf[i]))
309: sb.append(new Character((char) buf[i]));
310: else
311: sb.append(".");
312: }
313: return sb.toString();
314: }
315:
316: private static String hex(int x) {
317: // if( x < 0) x=256 + x;
318: String h = Integer.toHexString(x);
319: if (h.length() == 1)
320: h = "0" + h;
321: return h.substring(h.length() - 2);
322: }
323:
324: }
|