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

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