Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » coyote » http11 » [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   
   19   package org.apache.coyote.http11;
   20   
   21   import java.io.IOException;
   22   import java.io.EOFException;
   23   import java.net.SocketTimeoutException;
   24   import java.nio.ByteBuffer;
   25   
   26   import org.apache.tomcat.jni.Socket;
   27   import org.apache.tomcat.jni.Status;
   28   import org.apache.tomcat.util.buf.ByteChunk;
   29   import org.apache.tomcat.util.buf.MessageBytes;
   30   import org.apache.tomcat.util.http.MimeHeaders;
   31   import org.apache.tomcat.util.res.StringManager;
   32   
   33   import org.apache.coyote.InputBuffer;
   34   import org.apache.coyote.Request;
   35   
   36   /**
   37    * Implementation of InputBuffer which provides HTTP request header parsing as
   38    * well as transfer decoding.
   39    *
   40    * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
   41    */
   42   public class InternalAprInputBuffer implements InputBuffer {
   43   
   44   
   45       // -------------------------------------------------------------- Constants
   46   
   47   
   48       // ----------------------------------------------------------- Constructors
   49   
   50   
   51       /**
   52        * Alternate constructor.
   53        */
   54       public InternalAprInputBuffer(Request request, int headerBufferSize) {
   55   
   56           this.request = request;
   57           headers = request.getMimeHeaders();
   58   
   59           buf = new byte[headerBufferSize];
   60           if (headerBufferSize < (8 * 1024)) {
   61               bbuf = ByteBuffer.allocateDirect(6 * 1500);
   62           } else {
   63               bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500);
   64           }
   65   
   66           inputStreamInputBuffer = new SocketInputBuffer();
   67   
   68           filterLibrary = new InputFilter[0];
   69           activeFilters = new InputFilter[0];
   70           lastActiveFilter = -1;
   71   
   72           parsingHeader = true;
   73           swallowInput = true;
   74           
   75       }
   76   
   77   
   78       // -------------------------------------------------------------- Variables
   79   
   80   
   81       /**
   82        * The string manager for this package.
   83        */
   84       protected static StringManager sm =
   85           StringManager.getManager(Constants.Package);
   86   
   87   
   88       // ----------------------------------------------------- Instance Variables
   89   
   90   
   91       /**
   92        * Associated Coyote request.
   93        */
   94       protected Request request;
   95   
   96   
   97       /**
   98        * Headers of the associated request.
   99        */
  100       protected MimeHeaders headers;
  101   
  102   
  103       /**
  104        * State.
  105        */
  106       protected boolean parsingHeader;
  107   
  108   
  109       /**
  110        * Swallow input ? (in the case of an expectation)
  111        */
  112       protected boolean swallowInput;
  113   
  114   
  115       /**
  116        * Pointer to the current read buffer.
  117        */
  118       protected byte[] buf;
  119   
  120   
  121       /**
  122        * Last valid byte.
  123        */
  124       protected int lastValid;
  125   
  126   
  127       /**
  128        * Position in the buffer.
  129        */
  130       protected int pos;
  131   
  132   
  133       /**
  134        * Pos of the end of the header in the buffer, which is also the
  135        * start of the body.
  136        */
  137       protected int end;
  138   
  139   
  140       /**
  141        * Direct byte buffer used to perform actual reading.
  142        */
  143       protected ByteBuffer bbuf;
  144   
  145   
  146       /**
  147        * Underlying socket.
  148        */
  149       protected long socket;
  150   
  151   
  152       /**
  153        * Underlying input buffer.
  154        */
  155       protected InputBuffer inputStreamInputBuffer;
  156   
  157   
  158       /**
  159        * Filter library.
  160        * Note: Filter[0] is always the "chunked" filter.
  161        */
  162       protected InputFilter[] filterLibrary;
  163   
  164   
  165       /**
  166        * Active filters (in order).
  167        */
  168       protected InputFilter[] activeFilters;
  169   
  170   
  171       /**
  172        * Index of the last active filter.
  173        */
  174       protected int lastActiveFilter;
  175   
  176   
  177       // ------------------------------------------------------------- Properties
  178   
  179   
  180       /**
  181        * Set the underlying socket.
  182        */
  183       public void setSocket(long socket) {
  184           this.socket = socket;
  185           Socket.setrbb(this.socket, bbuf);
  186       }
  187   
  188   
  189       /**
  190        * Get the underlying socket input stream.
  191        */
  192       public long getSocket() {
  193           return socket;
  194       }
  195   
  196   
  197       /**
  198        * Add an input filter to the filter library.
  199        */
  200       public void addFilter(InputFilter filter) {
  201   
  202           InputFilter[] newFilterLibrary = 
  203               new InputFilter[filterLibrary.length + 1];
  204           for (int i = 0; i < filterLibrary.length; i++) {
  205               newFilterLibrary[i] = filterLibrary[i];
  206           }
  207           newFilterLibrary[filterLibrary.length] = filter;
  208           filterLibrary = newFilterLibrary;
  209   
  210           activeFilters = new InputFilter[filterLibrary.length];
  211   
  212       }
  213   
  214   
  215       /**
  216        * Get filters.
  217        */
  218       public InputFilter[] getFilters() {
  219   
  220           return filterLibrary;
  221   
  222       }
  223   
  224   
  225       /**
  226        * Clear filters.
  227        */
  228       public void clearFilters() {
  229   
  230           filterLibrary = new InputFilter[0];
  231           lastActiveFilter = -1;
  232   
  233       }
  234   
  235   
  236       /**
  237        * Add an input filter to the filter library.
  238        */
  239       public void addActiveFilter(InputFilter filter) {
  240   
  241           if (lastActiveFilter == -1) {
  242               filter.setBuffer(inputStreamInputBuffer);
  243           } else {
  244               for (int i = 0; i <= lastActiveFilter; i++) {
  245                   if (activeFilters[i] == filter)
  246                       return;
  247               }
  248               filter.setBuffer(activeFilters[lastActiveFilter]);
  249           }
  250   
  251           activeFilters[++lastActiveFilter] = filter;
  252   
  253           filter.setRequest(request);
  254   
  255       }
  256   
  257   
  258       /**
  259        * Set the swallow input flag.
  260        */
  261       public void setSwallowInput(boolean swallowInput) {
  262           this.swallowInput = swallowInput;
  263       }
  264   
  265   
  266       // --------------------------------------------------------- Public Methods
  267   
  268   
  269       /**
  270        * Recycle the input buffer. This should be called when closing the 
  271        * connection.
  272        */
  273       public void recycle() {
  274   
  275           // Recycle Request object
  276           request.recycle();
  277   
  278           socket = 0;
  279           lastValid = 0;
  280           pos = 0;
  281           lastActiveFilter = -1;
  282           parsingHeader = true;
  283           swallowInput = true;
  284   
  285       }
  286   
  287   
  288       /**
  289        * End processing of current HTTP request.
  290        * Note: All bytes of the current request should have been already 
  291        * consumed. This method only resets all the pointers so that we are ready
  292        * to parse the next HTTP request.
  293        */
  294       public void nextRequest() {
  295   
  296           // Recycle Request object
  297           request.recycle();
  298   
  299           // Copy leftover bytes to the beginning of the buffer
  300           if (lastValid - pos > 0) {
  301               int npos = 0;
  302               int opos = pos;
  303               while (lastValid - opos > opos - npos) {
  304                   System.arraycopy(buf, opos, buf, npos, opos - npos);
  305                   npos += pos;
  306                   opos += pos;
  307               }
  308               System.arraycopy(buf, opos, buf, npos, lastValid - opos);
  309           }
  310           
  311           // Recycle filters
  312           for (int i = 0; i <= lastActiveFilter; i++) {
  313               activeFilters[i].recycle();
  314           }
  315   
  316           // Reset pointers
  317           lastValid = lastValid - pos;
  318           pos = 0;
  319           lastActiveFilter = -1;
  320           parsingHeader = true;
  321           swallowInput = true;
  322   
  323       }
  324   
  325   
  326       /**
  327        * End request (consumes leftover bytes).
  328        * 
  329        * @throws IOException an undelying I/O error occured
  330        */
  331       public void endRequest()
  332           throws IOException {
  333   
  334           if (swallowInput && (lastActiveFilter != -1)) {
  335               int extraBytes = (int) activeFilters[lastActiveFilter].end();
  336               pos = pos - extraBytes;
  337           }
  338   
  339       }
  340   
  341   
  342       /**
  343        * Read the request line. This function is meant to be used during the 
  344        * HTTP request header parsing. Do NOT attempt to read the request body 
  345        * using it.
  346        *
  347        * @throws IOException If an exception occurs during the underlying socket
  348        * read operations, or if the given buffer is not big enough to accomodate
  349        * the whole line.
  350        * @return true if data is properly fed; false if no data is available 
  351        * immediately and thread should be freed
  352        */
  353       public boolean parseRequestLine(boolean useAvailableData)
  354           throws IOException {
  355   
  356           int start = 0;
  357   
  358           //
  359           // Skipping blank lines
  360           //
  361   
  362           byte chr = 0;
  363           do {
  364   
  365               // Read new bytes if needed
  366               if (pos >= lastValid) {
  367                   if (useAvailableData) {
  368                       return false;
  369                   }
  370                   if (!fill())
  371                       throw new EOFException(sm.getString("iib.eof.error"));
  372               }
  373   
  374               chr = buf[pos++];
  375   
  376           } while ((chr == Constants.CR) || (chr == Constants.LF));
  377   
  378           pos--;
  379   
  380           // Mark the current buffer position
  381           start = pos;
  382   
  383           if (pos >= lastValid) {
  384               if (useAvailableData) {
  385                   return false;
  386               }
  387               if (!fill())
  388                   throw new EOFException(sm.getString("iib.eof.error"));
  389           }
  390   
  391           //
  392           // Reading the method name
  393           // Method name is always US-ASCII
  394           //
  395   
  396           boolean space = false;
  397   
  398           while (!space) {
  399   
  400               // Read new bytes if needed
  401               if (pos >= lastValid) {
  402                   if (!fill())
  403                       throw new EOFException(sm.getString("iib.eof.error"));
  404               }
  405   
  406               if (buf[pos] == Constants.SP) {
  407                   space = true;
  408                   request.method().setBytes(buf, start, pos - start);
  409               }
  410   
  411               pos++;
  412   
  413           }
  414   
  415           // Mark the current buffer position
  416           start = pos;
  417           int end = 0;
  418           int questionPos = -1;
  419   
  420           //
  421           // Reading the URI
  422           //
  423   
  424           space = false;
  425           boolean eol = false;
  426   
  427           while (!space) {
  428   
  429               // Read new bytes if needed
  430               if (pos >= lastValid) {
  431                   if (!fill())
  432                       throw new EOFException(sm.getString("iib.eof.error"));
  433               }
  434   
  435               if (buf[pos] == Constants.SP) {
  436                   space = true;
  437                   end = pos;
  438               } else if ((buf[pos] == Constants.CR) 
  439                          || (buf[pos] == Constants.LF)) {
  440                   // HTTP/0.9 style request
  441                   eol = true;
  442                   space = true;
  443                   end = pos;
  444               } else if ((buf[pos] == Constants.QUESTION) 
  445                          && (questionPos == -1)) {
  446                   questionPos = pos;
  447               }
  448   
  449               pos++;
  450   
  451           }
  452   
  453           request.unparsedURI().setBytes(buf, start, end - start);
  454           if (questionPos >= 0) {
  455               request.queryString().setBytes(buf, questionPos + 1, 
  456                                              end - questionPos - 1);
  457               request.requestURI().setBytes(buf, start, questionPos - start);
  458           } else {
  459               request.requestURI().setBytes(buf, start, end - start);
  460           }
  461   
  462           // Mark the current buffer position
  463           start = pos;
  464           end = 0;
  465   
  466           //
  467           // Reading the protocol
  468           // Protocol is always US-ASCII
  469           //
  470   
  471           while (!eol) {
  472   
  473               // Read new bytes if needed
  474               if (pos >= lastValid) {
  475                   if (!fill())
  476                       throw new EOFException(sm.getString("iib.eof.error"));
  477               }
  478   
  479               if (buf[pos] == Constants.CR) {
  480                   end = pos;
  481               } else if (buf[pos] == Constants.LF) {
  482                   if (end == 0)
  483                       end = pos;
  484                   eol = true;
  485               }
  486   
  487               pos++;
  488   
  489           }
  490   
  491           if ((end - start) > 0) {
  492               request.protocol().setBytes(buf, start, end - start);
  493           } else {
  494               request.protocol().setString("");
  495           }
  496           
  497           return true;
  498   
  499       }
  500   
  501   
  502       /**
  503        * Parse the HTTP headers.
  504        */
  505       public void parseHeaders()
  506           throws IOException {
  507   
  508           while (parseHeader()) {
  509           }
  510   
  511           parsingHeader = false;
  512           end = pos;
  513   
  514       }
  515   
  516   
  517       /**
  518        * Parse an HTTP header.
  519        * 
  520        * @return false after reading a blank line (which indicates that the
  521        * HTTP header parsing is done
  522        */
  523       public boolean parseHeader()
  524           throws IOException {
  525   
  526           //
  527           // Check for blank line
  528           //
  529   
  530           byte chr = 0;
  531           while (true) {
  532   
  533               // Read new bytes if needed
  534               if (pos >= lastValid) {
  535                   if (!fill())
  536                       throw new EOFException(sm.getString("iib.eof.error"));
  537               }
  538   
  539               chr = buf[pos];
  540   
  541               if ((chr == Constants.CR) || (chr == Constants.LF)) {
  542                   if (chr == Constants.LF) {
  543                       pos++;
  544                       return false;
  545                   }
  546               } else {
  547                   break;
  548               }
  549   
  550               pos++;
  551   
  552           }
  553   
  554           // Mark the current buffer position
  555           int start = pos;
  556   
  557           //
  558           // Reading the header name
  559           // Header name is always US-ASCII
  560           //
  561   
  562           boolean colon = false;
  563           MessageBytes headerValue = null;
  564   
  565           while (!colon) {
  566   
  567               // Read new bytes if needed
  568               if (pos >= lastValid) {
  569                   if (!fill())
  570                       throw new EOFException(sm.getString("iib.eof.error"));
  571               }
  572   
  573               if (buf[pos] == Constants.COLON) {
  574                   colon = true;
  575                   headerValue = headers.addValue(buf, start, pos - start);
  576               }
  577               chr = buf[pos];
  578               if ((chr >= Constants.A) && (chr <= Constants.Z)) {
  579                   buf[pos] = (byte) (chr - Constants.LC_OFFSET);
  580               }
  581   
  582               pos++;
  583   
  584           }
  585   
  586           // Mark the current buffer position
  587           start = pos;
  588           int realPos = pos;
  589   
  590           //
  591           // Reading the header value (which can be spanned over multiple lines)
  592           //
  593   
  594           boolean eol = false;
  595           boolean validLine = true;
  596   
  597           while (validLine) {
  598   
  599               boolean space = true;
  600   
  601               // Skipping spaces
  602               while (space) {
  603   
  604                   // Read new bytes if needed
  605                   if (pos >= lastValid) {
  606                       if (!fill())
  607                           throw new EOFException(sm.getString("iib.eof.error"));
  608                   }
  609   
  610                   if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) {
  611                       pos++;
  612                   } else {
  613                       space = false;
  614                   }
  615   
  616               }
  617   
  618               int lastSignificantChar = realPos;
  619   
  620               // Reading bytes until the end of the line
  621               while (!eol) {
  622   
  623                   // Read new bytes if needed
  624                   if (pos >= lastValid) {
  625                       if (!fill())
  626                           throw new EOFException(sm.getString("iib.eof.error"));
  627                   }
  628   
  629                   if (buf[pos] == Constants.CR) {
  630                   } else if (buf[pos] == Constants.LF) {
  631                       eol = true;
  632                   } else if (buf[pos] == Constants.SP) {
  633                       buf[realPos] = buf[pos];
  634                       realPos++;
  635                   } else {
  636                       buf[realPos] = buf[pos];
  637                       realPos++;
  638                       lastSignificantChar = realPos;
  639                   }
  640   
  641                   pos++;
  642   
  643               }
  644   
  645               realPos = lastSignificantChar;
  646   
  647               // Checking the first character of the new line. If the character
  648               // is a LWS, then it's a multiline header
  649   
  650               // Read new bytes if needed
  651               if (pos >= lastValid) {
  652                   if (!fill())
  653                       throw new EOFException(sm.getString("iib.eof.error"));
  654               }
  655   
  656               chr = buf[pos];
  657               if ((chr != Constants.SP) && (chr != Constants.HT)) {
  658                   validLine = false;
  659               } else {
  660                   eol = false;
  661                   // Copying one extra space in the buffer (since there must
  662                   // be at least one space inserted between the lines)
  663                   buf[realPos] = chr;
  664                   realPos++;
  665               }
  666   
  667           }
  668   
  669           // Set the header value
  670           headerValue.setBytes(buf, start, realPos - start);
  671   
  672           return true;
  673   
  674       }
  675   
  676       
  677       /**
  678        * Available bytes (note that due to encoding, this may not correspond )
  679        */
  680       public int available() {
  681           int result = (lastValid - pos);
  682           if ((result == 0) && (lastActiveFilter >= 0)) {
  683               for (int i = 0; (result == 0) && (i <= lastActiveFilter); i++) {
  684                   result = activeFilters[i].available();
  685               }
  686           }
  687           return result;
  688       }
  689   
  690   
  691       // ---------------------------------------------------- InputBuffer Methods
  692   
  693   
  694       /**
  695        * Read some bytes.
  696        */
  697       public int doRead(ByteChunk chunk, Request req) 
  698           throws IOException {
  699   
  700           if (lastActiveFilter == -1)
  701               return inputStreamInputBuffer.doRead(chunk, req);
  702           else
  703               return activeFilters[lastActiveFilter].doRead(chunk,req);
  704   
  705       }
  706   
  707   
  708       // ------------------------------------------------------ Protected Methods
  709   
  710   
  711       /**
  712        * Fill the internal buffer using data from the undelying input stream.
  713        * 
  714        * @return false if at end of stream
  715        */
  716       protected boolean fill()
  717           throws IOException {
  718   
  719           int nRead = 0;
  720   
  721           if (parsingHeader) {
  722   
  723               if (lastValid == buf.length) {
  724                   throw new IOException
  725                       (sm.getString("iib.requestheadertoolarge.error"));
  726               }
  727   
  728               bbuf.clear();
  729               nRead = Socket.recvbb(socket, 0, buf.length - lastValid);
  730               if (nRead > 0) {
  731                   bbuf.limit(nRead);
  732                   bbuf.get(buf, pos, nRead);
  733                   lastValid = pos + nRead;
  734               } else {
  735                   if ((-nRead) == Status.EAGAIN) {
  736                       return false;
  737                   } else {
  738                       throw new IOException(sm.getString("iib.failedread"));
  739                   }
  740               }
  741   
  742           } else {
  743   
  744               if (buf.length - end < 4500) {
  745                   // In this case, the request header was really large, so we allocate a 
  746                   // brand new one; the old one will get GCed when subsequent requests
  747                   // clear all references
  748                   buf = new byte[buf.length];
  749                   end = 0;
  750               }
  751               pos = end;
  752               lastValid = pos;
  753               bbuf.clear();
  754               nRead = Socket.recvbb(socket, 0, buf.length - lastValid);
  755               if (nRead > 0) {
  756                   bbuf.limit(nRead);
  757                   bbuf.get(buf, pos, nRead);
  758                   lastValid = pos + nRead;
  759               } else {
  760                   if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) {
  761                       throw new SocketTimeoutException(sm.getString("iib.failedread"));
  762                   } else {
  763                       throw new IOException(sm.getString("iib.failedread"));
  764                   }
  765               }
  766   
  767           }
  768   
  769           return (nRead > 0);
  770   
  771       }
  772   
  773   
  774       // ------------------------------------- InputStreamInputBuffer Inner Class
  775   
  776   
  777       /**
  778        * This class is an input buffer which will read its data from an input
  779        * stream.
  780        */
  781       protected class SocketInputBuffer 
  782           implements InputBuffer {
  783   
  784   
  785           /**
  786            * Read bytes into the specified chunk.
  787            */
  788           public int doRead(ByteChunk chunk, Request req ) 
  789               throws IOException {
  790   
  791               if (pos >= lastValid) {
  792                   if (!fill())
  793                       return -1;
  794               }
  795   
  796               int length = lastValid - pos;
  797               chunk.setBytes(buf, pos, length);
  798               pos = lastValid;
  799   
  800               return (length);
  801   
  802           }
  803   
  804   
  805       }
  806   
  807   
  808   }

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