Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » coyote » ajp » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package org.apache.coyote.ajp;
   19   
   20   import org.apache.tomcat.util.buf.ByteChunk;
   21   import org.apache.tomcat.util.buf.CharChunk;
   22   import org.apache.tomcat.util.buf.MessageBytes;
   23   import org.apache.tomcat.util.res.StringManager;
   24   
   25   /**
   26    * A single packet for communication between the web server and the
   27    * container.  Designed to be reused many times with no creation of
   28    * garbage.  Understands the format of data types for these packets.
   29    * Can be used (somewhat confusingly) for both incoming and outgoing
   30    * packets.  
   31    *
   32    * @author Henri Gomez
   33    * @author Dan Milstein
   34    * @author Keith Wannamaker
   35    * @author Kevin Seguin
   36    * @author Costin Manolache
   37    */
   38   public class AjpMessage {
   39   
   40   
   41       protected static org.apache.juli.logging.Log log =
   42           org.apache.juli.logging.LogFactory.getLog(AjpMessage.class);
   43   
   44       /**
   45        * The string manager for this package.
   46        */
   47       protected static StringManager sm =
   48           StringManager.getManager(Constants.Package);
   49   
   50   
   51       // ------------------------------------------------------------ Constructor
   52   
   53       
   54       public AjpMessage(int packetSize) {
   55           buf = new byte[packetSize];
   56       }
   57       
   58   
   59       // ----------------------------------------------------- Instance Variables
   60   
   61   
   62       /**
   63        * Fixed size buffer.
   64        */
   65       protected byte buf[] = null;
   66   
   67   
   68       /**
   69        * The current read or write position in the buffer.
   70        */
   71       protected int pos;
   72   
   73   
   74       /**
   75        * This actually means different things depending on whether the
   76        * packet is read or write.  For read, it's the length of the
   77        * payload (excluding the header).  For write, it's the length of
   78        * the packet as a whole (counting the header).  Oh, well.
   79        */
   80       protected int len; 
   81   
   82       
   83       // --------------------------------------------------------- Public Methods
   84   
   85   
   86       /**
   87        * Prepare this packet for accumulating a message from the container to
   88        * the web server.  Set the write position to just after the header
   89        * (but leave the length unwritten, because it is as yet unknown).
   90        */
   91       public void reset() {
   92           len = 4;
   93           pos = 4;
   94       }
   95   
   96   
   97       /**
   98        * For a packet to be sent to the web server, finish the process of
   99        * accumulating data and write the length of the data payload into
  100        * the header.  
  101        */
  102       public void end() {
  103           len = pos;
  104           int dLen = len - 4;
  105   
  106           buf[0] = (byte) 0x41;
  107           buf[1] = (byte) 0x42;
  108           buf[2] = (byte) ((dLen>>>8) & 0xFF);
  109           buf[3] = (byte) (dLen & 0xFF);
  110       }
  111   
  112   
  113       /**
  114        * Return the underlying byte buffer.
  115        */
  116       public byte[] getBuffer() {
  117           return buf;
  118       }
  119   
  120   
  121       /**
  122        * Return the current message length. For read, it's the length of the
  123        * payload (excluding the header).  For write, it's the length of
  124        * the packet as a whole (counting the header).
  125        */
  126       public int getLen() {
  127           return len;
  128       }
  129       
  130   
  131       /**
  132        * Add a short integer (2 bytes) to the message.
  133        */
  134       public void appendInt(int val) {
  135           buf[pos++] = (byte) ((val >>> 8) & 0xFF);
  136           buf[pos++] = (byte) (val & 0xFF);
  137       }
  138   
  139   
  140       /**
  141        * Append a byte (1 byte) to the message.
  142        */
  143       public void appendByte(int val) {
  144           buf[pos++] = (byte) val;
  145       }
  146   	
  147       
  148       /**
  149        * Append an int (4 bytes) to the message.
  150        */
  151       public void appendLongInt(int val) {
  152           buf[pos++] = (byte) ((val >>> 24) & 0xFF);
  153           buf[pos++] = (byte) ((val >>> 16) & 0xFF);
  154           buf[pos++] = (byte) ((val >>> 8) & 0xFF);
  155           buf[pos++] = (byte) (val & 0xFF);
  156       }
  157   
  158       
  159       /**
  160        * Write a MessageBytes out at the current write position.
  161        * A null MessageBytes is encoded as a string with length 0.  
  162        */
  163       public void appendBytes(MessageBytes mb) {
  164           if (mb == null) {
  165               log.error(sm.getString("ajpmessage.null"), 
  166                       new NullPointerException());
  167               appendInt(0);
  168               appendByte(0);
  169               return;
  170           }
  171           if (mb.getType() == MessageBytes.T_BYTES) {
  172               ByteChunk bc = mb.getByteChunk();
  173               appendByteChunk(bc);
  174           } else if (mb.getType() == MessageBytes.T_CHARS) {
  175               CharChunk cc = mb.getCharChunk();
  176               appendCharChunk(cc);
  177           } else {
  178               appendString(mb.toString());
  179           }
  180       }
  181   
  182       
  183       /**
  184        * Write a ByteChunk out at the current write position.
  185        * A null ByteChunk is encoded as a string with length 0.  
  186        */
  187       public void appendByteChunk(ByteChunk bc) {
  188           if (bc == null) {
  189               log.error(sm.getString("ajpmessage.null"), 
  190                       new NullPointerException());
  191               appendInt(0);
  192               appendByte(0);
  193               return;
  194           }
  195           appendBytes(bc.getBytes(), bc.getStart(), bc.getLength());
  196       }
  197   
  198       
  199       /**
  200        * Write a CharChunk out at the current write position.
  201        * A null CharChunk is encoded as a string with length 0.  
  202        */
  203       public void appendCharChunk(CharChunk cc) {
  204           if (cc == null) {
  205               log.error(sm.getString("ajpmessage.null"), 
  206                       new NullPointerException());
  207               appendInt(0);
  208               appendByte(0);
  209               return;
  210           }
  211           int start = cc.getStart();
  212           int end = cc.getEnd();
  213           appendInt(end - start);
  214           char[] cbuf = cc.getBuffer();
  215           for (int i = start; i < end; i++) {
  216               char c = cbuf[i];
  217               // Note:  This is clearly incorrect for many strings,
  218               // but is the only consistent approach within the current
  219               // servlet framework.  It must suffice until servlet output
  220               // streams properly encode their output.
  221               if ((c <= 31) && (c != 9)) {
  222                   c = ' ';
  223               } else if (c == 127) {
  224                   c = ' ';
  225               }
  226               appendByte(c);
  227           }
  228           appendByte(0);
  229       }
  230   
  231       
  232       /**
  233        * Write a String out at the current write position.  Strings are
  234        * encoded with the length in two bytes first, then the string, and
  235        * then a terminating \0 (which is <B>not</B> included in the
  236        * encoded length).  The terminator is for the convenience of the C
  237        * code, where it saves a round of copying.  A null string is
  238        * encoded as a string with length 0.  
  239        */
  240       public void appendString(String str) {
  241           if (str == null) {
  242               log.error(sm.getString("ajpmessage.null"), 
  243                       new NullPointerException());
  244               appendInt(0);
  245               appendByte(0);
  246               return;
  247           }
  248           int len = str.length();
  249           appendInt(len);
  250           for (int i = 0; i < len; i++) {
  251               char c = str.charAt (i);
  252               // Note:  This is clearly incorrect for many strings,
  253               // but is the only consistent approach within the current
  254               // servlet framework.  It must suffice until servlet output
  255               // streams properly encode their output.
  256               if ((c <= 31) && (c != 9)) {
  257                   c = ' ';
  258               } else if (c == 127) {
  259                   c = ' ';
  260               }
  261               appendByte(c);
  262           }
  263           appendByte(0);
  264       }
  265   
  266       
  267       /** 
  268        * Copy a chunk of bytes into the packet, starting at the current
  269        * write position.  The chunk of bytes is encoded with the length
  270        * in two bytes first, then the data itself, and finally a
  271        * terminating \0 (which is <B>not</B> included in the encoded
  272        * length).
  273        *
  274        * @param b The array from which to copy bytes.
  275        * @param off The offset into the array at which to start copying
  276        * @param numBytes The number of bytes to copy.  
  277        */
  278       public void appendBytes(byte[] b, int off, int numBytes) {
  279           if (pos + numBytes + 3 > buf.length) {
  280               log.error(sm.getString("ajpmessage.overflow", "" + numBytes, "" + pos),
  281                       new ArrayIndexOutOfBoundsException());
  282               if (log.isDebugEnabled()) {
  283                   dump("Overflow/coBytes");
  284               }
  285               return;
  286           }
  287           appendInt(numBytes);
  288           System.arraycopy(b, off, buf, pos, numBytes);
  289           pos += numBytes;
  290           appendByte(0);
  291       }
  292   
  293       
  294       /**
  295        * Read an integer from packet, and advance the read position past
  296        * it.  Integers are encoded as two unsigned bytes with the
  297        * high-order byte first, and, as far as I can tell, in
  298        * little-endian order within each byte.  
  299        */
  300       public int getInt() {
  301           int b1 = buf[pos++] & 0xFF;
  302           int b2 = buf[pos++] & 0xFF;
  303           return (b1<<8) + b2;
  304       }
  305   
  306   
  307       public int peekInt() {
  308           int b1 = buf[pos] & 0xFF;
  309           int b2 = buf[pos+1] & 0xFF;
  310           return (b1<<8) + b2;
  311       }
  312   
  313       
  314       public byte getByte() {
  315           byte res = buf[pos++];
  316           return res;
  317       }
  318   
  319       
  320       public byte peekByte() {
  321           byte res = buf[pos];
  322           return res;
  323       }
  324   
  325       
  326       public void getBytes(MessageBytes mb) {
  327           int length = getInt();
  328           if ((length == 0xFFFF) || (length == -1)) {
  329               mb.recycle();
  330               return;
  331           }
  332           mb.setBytes(buf, pos, length);
  333           pos += length;
  334           pos++; // Skip the terminating \0
  335       }
  336       
  337       
  338       /**
  339        * Copy a chunk of bytes from the packet into an array and advance
  340        * the read position past the chunk.  See appendBytes() for details
  341        * on the encoding.
  342        *
  343        * @return The number of bytes copied.
  344        */
  345       public int getBytes(byte[] dest) {
  346           int length = getInt();
  347           if (pos + length > buf.length) {
  348               log.error(sm.getString("ajpmessage.read", "" + length));
  349               return 0;
  350           }
  351   	
  352           if ((length == 0xFFFF) || (length == -1)) {
  353               return 0;
  354           }
  355   
  356           System.arraycopy(buf, pos, dest, 0, length);
  357           pos += length;
  358           pos++; // Skip terminating \0
  359           return length;
  360       }
  361   
  362       
  363       /**
  364        * Read a 32 bits integer from packet, and advance the read position past
  365        * it.  Integers are encoded as four unsigned bytes with the
  366        * high-order byte first, and, as far as I can tell, in
  367        * little-endian order within each byte.
  368        */
  369       public int getLongInt() {
  370           int b1 = buf[pos++] & 0xFF; // No swap, Java order
  371           b1 <<= 8;
  372           b1 |= (buf[pos++] & 0xFF);
  373           b1 <<= 8;
  374           b1 |= (buf[pos++] & 0xFF);
  375           b1 <<=8;
  376           b1 |= (buf[pos++] & 0xFF);
  377           return  b1;
  378       }
  379   
  380   
  381       public int getHeaderLength() {
  382           return 4;
  383       }
  384   
  385       
  386       public int getPacketSize() {
  387           return buf.length;
  388       }
  389       
  390       
  391       public int processHeader() {
  392           pos = 0;
  393           int mark = getInt();
  394           len = getInt();
  395           // Verify message signature
  396           if ((mark != 0x1234) && (mark != 0x4142)) {
  397               log.error(sm.getString("ajpmessage.invalid", "" + mark));
  398               if (log.isDebugEnabled()) {
  399                   dump("In: ");
  400               }
  401               return -1;
  402           }
  403           if (log.isDebugEnabled())  {
  404               log.debug("Received " + len + " " + buf[0]);
  405           }
  406           return len;
  407       }
  408       
  409   
  410       /**
  411        * Dump the contents of the message, prefixed with the given String.
  412        */
  413       public void dump(String msg) {
  414           if (log.isDebugEnabled()) {
  415               log.debug(msg + ": " + buf + " " + pos +"/" + (len + 4));
  416           }
  417           int max = pos;
  418           if (len + 4 > pos)
  419               max = len+4;
  420           if (max > 1000)
  421               max = 1000;
  422           if (log.isDebugEnabled()) {
  423               for (int j = 0; j < max; j += 16) { 
  424                   log.debug(hexLine(buf, j, len));
  425               }
  426           }
  427       }
  428   
  429   
  430       // ------------------------------------------------------ Protected Methods
  431   
  432   
  433       protected static String hexLine(byte buf[], int start, int len) {
  434           StringBuffer sb = new StringBuffer();
  435           for (int i = start; i < start + 16 ; i++) {
  436               if (i < len + 4) {
  437                   sb.append(hex(buf[i]) + " ");
  438               } else { 
  439                   sb.append("   ");
  440               }
  441           }
  442           sb.append(" | ");
  443           for (int i = start; i < start + 16 && i < len + 4; i++) {
  444               if (!Character.isISOControl((char) buf[i])) {
  445                   sb.append(new Character((char) buf[i]));
  446               } else {
  447                   sb.append(".");
  448               }
  449           }
  450           return sb.toString();
  451       }
  452   
  453   
  454       protected static String hex(int x) {
  455           String h = Integer.toHexString(x);
  456           if (h.length() == 1) {
  457               h = "0" + h;
  458           }
  459           return h.substring(h.length() - 2);
  460       }
  461   
  462   
  463   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » coyote » ajp » [javadoc | source]