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   package org.apache.coyote.http11;
   19   
   20   import java.io.IOException;
   21   import java.io.InterruptedIOException;
   22   import java.net.InetAddress;
   23   import java.net.Socket;
   24   import java.security.AccessController;
   25   import java.security.PrivilegedAction;
   26   import java.util.StringTokenizer;
   27   import java.util.regex.Pattern;
   28   import java.util.regex.PatternSyntaxException;
   29   
   30   import org.apache.coyote.ActionCode;
   31   import org.apache.coyote.ActionHook;
   32   import org.apache.coyote.Adapter;
   33   import org.apache.coyote.Request;
   34   import org.apache.coyote.RequestInfo;
   35   import org.apache.coyote.Response;
   36   import org.apache.coyote.http11.filters.BufferedInputFilter;
   37   import org.apache.coyote.http11.filters.ChunkedInputFilter;
   38   import org.apache.coyote.http11.filters.ChunkedOutputFilter;
   39   import org.apache.coyote.http11.filters.GzipOutputFilter;
   40   import org.apache.coyote.http11.filters.IdentityInputFilter;
   41   import org.apache.coyote.http11.filters.IdentityOutputFilter;
   42   import org.apache.coyote.http11.filters.SavedRequestInputFilter;
   43   import org.apache.coyote.http11.filters.VoidInputFilter;
   44   import org.apache.coyote.http11.filters.VoidOutputFilter;
   45   import org.apache.tomcat.util.buf.Ascii;
   46   import org.apache.tomcat.util.buf.ByteChunk;
   47   import org.apache.tomcat.util.buf.HexUtils;
   48   import org.apache.tomcat.util.buf.MessageBytes;
   49   import org.apache.tomcat.util.http.FastHttpDateFormat;
   50   import org.apache.tomcat.util.http.MimeHeaders;
   51   import org.apache.tomcat.util.net.JIoEndpoint;
   52   import org.apache.tomcat.util.net.SSLSupport;
   53   import org.apache.tomcat.util.res.StringManager;
   54   
   55   
   56   /**
   57    * Processes HTTP requests.
   58    *
   59    * @author Remy Maucherat
   60    */
   61   public class Http11Processor implements ActionHook {
   62   
   63   
   64       /**
   65        * Logger.
   66        */
   67       protected static org.apache.juli.logging.Log log
   68           = org.apache.juli.logging.LogFactory.getLog(Http11Processor.class);
   69   
   70       /**
   71        * The string manager for this package.
   72        */
   73       protected static StringManager sm =
   74           StringManager.getManager(Constants.Package);
   75   
   76   
   77       // ------------------------------------------------------------ Constructor
   78   
   79   
   80       public Http11Processor(int headerBufferSize, JIoEndpoint endpoint) {
   81   
   82           this.endpoint = endpoint;
   83           
   84           request = new Request();
   85           inputBuffer = new InternalInputBuffer(request, headerBufferSize);
   86           request.setInputBuffer(inputBuffer);
   87   
   88           response = new Response();
   89           response.setHook(this);
   90           outputBuffer = new InternalOutputBuffer(response, headerBufferSize);
   91           response.setOutputBuffer(outputBuffer);
   92           request.setResponse(response);
   93   
   94           initializeFilters();
   95   
   96           // Cause loading of HexUtils
   97           int foo = HexUtils.DEC[0];
   98   
   99       }
  100   
  101   
  102       // ----------------------------------------------------- Instance Variables
  103   
  104   
  105       /**
  106        * Associated adapter.
  107        */
  108       protected Adapter adapter = null;
  109   
  110   
  111       /**
  112        * Request object.
  113        */
  114       protected Request request = null;
  115   
  116   
  117       /**
  118        * Response object.
  119        */
  120       protected Response response = null;
  121   
  122   
  123       /**
  124        * Input.
  125        */
  126       protected InternalInputBuffer inputBuffer = null;
  127   
  128   
  129       /**
  130        * Output.
  131        */
  132       protected InternalOutputBuffer outputBuffer = null;
  133   
  134   
  135       /**
  136        * State flag.
  137        */
  138       protected boolean started = false;
  139   
  140   
  141       /**
  142        * Error flag.
  143        */
  144       protected boolean error = false;
  145   
  146   
  147       /**
  148        * Keep-alive.
  149        */
  150       protected boolean keepAlive = true;
  151   
  152   
  153       /**
  154        * HTTP/1.1 flag.
  155        */
  156       protected boolean http11 = true;
  157   
  158   
  159       /**
  160        * HTTP/0.9 flag.
  161        */
  162       protected boolean http09 = false;
  163   
  164   
  165       /**
  166        * Content delimitator for the request (if false, the connection will
  167        * be closed at the end of the request).
  168        */
  169       protected boolean contentDelimitation = true;
  170   
  171   
  172       /**
  173        * Is there an expectation ?
  174        */
  175       protected boolean expectation = false;
  176   
  177   
  178       /**
  179        * List of restricted user agents.
  180        */
  181       protected Pattern[] restrictedUserAgents = null;
  182   
  183   
  184       /**
  185        * Maximum number of Keep-Alive requests to honor.
  186        */
  187       protected int maxKeepAliveRequests = -1;
  188   
  189       /**
  190        * The number of seconds Tomcat will wait for a subsequent request
  191        * before closing the connection.
  192        */
  193       protected int keepAliveTimeout = -1;
  194   
  195   
  196       /**
  197        * SSL information.
  198        */
  199       protected SSLSupport sslSupport;
  200   
  201   
  202       /**
  203        * Socket associated with the current connection.
  204        */
  205       protected Socket socket;
  206   
  207   
  208       /**
  209        * Remote Address associated with the current connection.
  210        */
  211       protected String remoteAddr = null;
  212   
  213   
  214       /**
  215        * Remote Host associated with the current connection.
  216        */
  217       protected String remoteHost = null;
  218   
  219   
  220       /**
  221        * Local Host associated with the current connection.
  222        */
  223       protected String localName = null;
  224   
  225   
  226   
  227       /**
  228        * Local port to which the socket is connected
  229        */
  230       protected int localPort = -1;
  231   
  232   
  233       /**
  234        * Remote port to which the socket is connected
  235        */
  236       protected int remotePort = -1;
  237   
  238   
  239       /**
  240        * The local Host address.
  241        */
  242       protected String localAddr = null;
  243   
  244   
  245       /**
  246        * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server.
  247        */
  248       protected int timeout = 300000;
  249   
  250   
  251       /**
  252        * Flag to disable setting a different time-out on uploads.
  253        */
  254       protected boolean disableUploadTimeout = false;
  255   
  256   
  257       /**
  258        * Allowed compression level.
  259        */
  260       protected int compressionLevel = 0;
  261   
  262   
  263       /**
  264        * Minimum contentsize to make compression.
  265        */
  266       protected int compressionMinSize = 2048;
  267   
  268   
  269       /**
  270        * Socket buffering.
  271        */
  272       protected int socketBuffer = -1;
  273   
  274   
  275       /**
  276        * Max saved post size.
  277        */
  278       protected int maxSavePostSize = 4 * 1024;
  279   
  280   
  281       /**
  282        * List of user agents to not use gzip with
  283        */
  284       protected Pattern noCompressionUserAgents[] = null;
  285   
  286       /**
  287        * List of MIMES which could be gzipped
  288        */
  289       protected String[] compressableMimeTypes =
  290       { "text/html", "text/xml", "text/plain" };
  291   
  292   
  293       /**
  294        * Host name (used to avoid useless B2C conversion on the host name).
  295        */
  296       protected char[] hostNameC = new char[0];
  297   
  298   
  299       /**
  300        * Associated endpoint.
  301        */
  302       protected JIoEndpoint endpoint;
  303   
  304   
  305       /**
  306        * Allow a customized the server header for the tin-foil hat folks.
  307        */
  308       protected String server = null;
  309   
  310   
  311       // ------------------------------------------------------------- Properties
  312   
  313   
  314       /**
  315        * Return compression level.
  316        */
  317       public String getCompression() {
  318           switch (compressionLevel) {
  319           case 0:
  320               return "off";
  321           case 1:
  322               return "on";
  323           case 2:
  324               return "force";
  325           }
  326           return "off";
  327       }
  328   
  329   
  330       /**
  331        * Set compression level.
  332        */
  333       public void setCompression(String compression) {
  334           if (compression.equals("on")) {
  335               this.compressionLevel = 1;
  336           } else if (compression.equals("force")) {
  337               this.compressionLevel = 2;
  338           } else if (compression.equals("off")) {
  339               this.compressionLevel = 0;
  340           } else {
  341               try {
  342                   // Try to parse compression as an int, which would give the
  343                   // minimum compression size
  344                   compressionMinSize = Integer.parseInt(compression);
  345                   this.compressionLevel = 1;
  346               } catch (Exception e) {
  347                   this.compressionLevel = 0;
  348               }
  349           }
  350       }
  351   
  352       /**
  353        * Set Minimum size to trigger compression.
  354        */
  355       public void setCompressionMinSize(int compressionMinSize) {
  356           this.compressionMinSize = compressionMinSize;
  357       }
  358   
  359   
  360       /**
  361        * Add user-agent for which gzip compression didn't works
  362        * The user agent String given will be exactly matched
  363        * to the user-agent header submitted by the client.
  364        *
  365        * @param userAgent user-agent string
  366        */
  367       public void addNoCompressionUserAgent(String userAgent) {
  368           try {
  369               Pattern nRule = Pattern.compile(userAgent);
  370               noCompressionUserAgents =
  371                   addREArray(noCompressionUserAgents, nRule);
  372           } catch (PatternSyntaxException pse) {
  373               log.error(sm.getString("http11processor.regexp.error", userAgent), pse);
  374           }
  375       }
  376   
  377   
  378       /**
  379        * Set no compression user agent list (this method is best when used with
  380        * a large number of connectors, where it would be better to have all of
  381        * them referenced a single array).
  382        */
  383       public void setNoCompressionUserAgents(Pattern[] noCompressionUserAgents) {
  384           this.noCompressionUserAgents = noCompressionUserAgents;
  385       }
  386   
  387   
  388       /**
  389        * Set no compression user agent list.
  390        * List contains users agents separated by ',' :
  391        *
  392        * ie: "gorilla,desesplorer,tigrus"
  393        */
  394       public void setNoCompressionUserAgents(String noCompressionUserAgents) {
  395           if (noCompressionUserAgents != null) {
  396               StringTokenizer st = new StringTokenizer(noCompressionUserAgents, ",");
  397   
  398               while (st.hasMoreTokens()) {
  399                   addNoCompressionUserAgent(st.nextToken().trim());
  400               }
  401           }
  402       }
  403   
  404       /**
  405        * Add a mime-type which will be compressable
  406        * The mime-type String will be exactly matched
  407        * in the response mime-type header .
  408        *
  409        * @param mimeType mime-type string
  410        */
  411       public void addCompressableMimeType(String mimeType) {
  412           compressableMimeTypes =
  413               addStringArray(compressableMimeTypes, mimeType);
  414       }
  415   
  416   
  417       /**
  418        * Set compressable mime-type list (this method is best when used with
  419        * a large number of connectors, where it would be better to have all of
  420        * them referenced a single array).
  421        */
  422       public void setCompressableMimeTypes(String[] compressableMimeTypes) {
  423           this.compressableMimeTypes = compressableMimeTypes;
  424       }
  425   
  426   
  427       /**
  428        * Set compressable mime-type list
  429        * List contains users agents separated by ',' :
  430        *
  431        * ie: "text/html,text/xml,text/plain"
  432        */
  433       public void setCompressableMimeTypes(String compressableMimeTypes) {
  434           if (compressableMimeTypes != null) {
  435               StringTokenizer st = new StringTokenizer(compressableMimeTypes, ",");
  436   
  437               while (st.hasMoreTokens()) {
  438                   addCompressableMimeType(st.nextToken().trim());
  439               }
  440           }
  441       }
  442   
  443   
  444       /**
  445        * Return the list of restricted user agents.
  446        */
  447       public String[] findCompressableMimeTypes() {
  448           return (compressableMimeTypes);
  449       }
  450   
  451   
  452   
  453       // --------------------------------------------------------- Public Methods
  454   
  455   
  456       /**
  457        * Add input or output filter.
  458        *
  459        * @param className class name of the filter
  460        */
  461       protected void addFilter(String className) {
  462           try {
  463               Class clazz = Class.forName(className);
  464               Object obj = clazz.newInstance();
  465               if (obj instanceof InputFilter) {
  466                   inputBuffer.addFilter((InputFilter) obj);
  467               } else if (obj instanceof OutputFilter) {
  468                   outputBuffer.addFilter((OutputFilter) obj);
  469               } else {
  470                   log.warn(sm.getString("http11processor.filter.unknown", className));
  471               }
  472           } catch (Exception e) {
  473               log.error(sm.getString("http11processor.filter.error", className), e);
  474           }
  475       }
  476   
  477   
  478       /**
  479        * General use method
  480        *
  481        * @param sArray the StringArray
  482        * @param value string
  483        */
  484       private String[] addStringArray(String sArray[], String value) {
  485           String[] result = null;
  486           if (sArray == null) {
  487               result = new String[1];
  488               result[0] = value;
  489           }
  490           else {
  491               result = new String[sArray.length + 1];
  492               for (int i = 0; i < sArray.length; i++)
  493                   result[i] = sArray[i];
  494               result[sArray.length] = value;
  495           }
  496           return result;
  497       }
  498   
  499   
  500       /**
  501        * General use method
  502        *
  503        * @param rArray the REArray
  504        * @param value Obj
  505        */
  506       private Pattern[] addREArray(Pattern rArray[], Pattern value) {
  507           Pattern[] result = null;
  508           if (rArray == null) {
  509               result = new Pattern[1];
  510               result[0] = value;
  511           }
  512           else {
  513               result = new Pattern[rArray.length + 1];
  514               for (int i = 0; i < rArray.length; i++)
  515                   result[i] = rArray[i];
  516               result[rArray.length] = value;
  517           }
  518           return result;
  519       }
  520   
  521   
  522       /**
  523        * General use method
  524        *
  525        * @param sArray the StringArray
  526        * @param value string
  527        */
  528       private boolean inStringArray(String sArray[], String value) {
  529           for (int i = 0; i < sArray.length; i++) {
  530               if (sArray[i].equals(value)) {
  531                   return true;
  532               }
  533           }
  534           return false;
  535       }
  536   
  537   
  538       /**
  539        * Checks if any entry in the string array starts with the specified value
  540        *
  541        * @param sArray the StringArray
  542        * @param value string
  543        */
  544       private boolean startsWithStringArray(String sArray[], String value) {
  545           if (value == null)
  546              return false;
  547           for (int i = 0; i < sArray.length; i++) {
  548               if (value.startsWith(sArray[i])) {
  549                   return true;
  550               }
  551           }
  552           return false;
  553       }
  554   
  555   
  556       /**
  557        * Add restricted user-agent (which will downgrade the connector
  558        * to HTTP/1.0 mode). The user agent String given will be matched
  559        * via regexp to the user-agent header submitted by the client.
  560        *
  561        * @param userAgent user-agent string
  562        */
  563       public void addRestrictedUserAgent(String userAgent) {
  564           try {
  565               Pattern nRule = Pattern.compile(userAgent);
  566               restrictedUserAgents = addREArray(restrictedUserAgents, nRule);
  567           } catch (PatternSyntaxException pse) {
  568               log.error(sm.getString("http11processor.regexp.error", userAgent), pse);
  569           }
  570       }
  571   
  572   
  573       /**
  574        * Set restricted user agent list (this method is best when used with
  575        * a large number of connectors, where it would be better to have all of
  576        * them referenced a single array).
  577        */
  578       public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) {
  579           this.restrictedUserAgents = restrictedUserAgents;
  580       }
  581   
  582   
  583       /**
  584        * Set restricted user agent list (which will downgrade the connector
  585        * to HTTP/1.0 mode). List contains users agents separated by ',' :
  586        *
  587        * ie: "gorilla,desesplorer,tigrus"
  588        */
  589       public void setRestrictedUserAgents(String restrictedUserAgents) {
  590           if (restrictedUserAgents != null) {
  591               StringTokenizer st =
  592                   new StringTokenizer(restrictedUserAgents, ",");
  593               while (st.hasMoreTokens()) {
  594                   addRestrictedUserAgent(st.nextToken().trim());
  595               }
  596           }
  597       }
  598   
  599   
  600       /**
  601        * Return the list of restricted user agents.
  602        */
  603       public String[] findRestrictedUserAgents() {
  604           String[] sarr = new String [restrictedUserAgents.length];
  605   
  606           for (int i = 0; i < restrictedUserAgents.length; i++)
  607               sarr[i] = restrictedUserAgents[i].toString();
  608   
  609           return (sarr);
  610       }
  611   
  612   
  613       /**
  614        * Set the maximum number of Keep-Alive requests to honor.
  615        * This is to safeguard from DoS attacks.  Setting to a negative
  616        * value disables the check.
  617        */
  618       public void setMaxKeepAliveRequests(int mkar) {
  619           maxKeepAliveRequests = mkar;
  620       }
  621   
  622   
  623       /**
  624        * Return the number of Keep-Alive requests that we will honor.
  625        */
  626       public int getMaxKeepAliveRequests() {
  627           return maxKeepAliveRequests;
  628       }
  629   
  630       /**
  631        * Set the Keep-Alive timeout.
  632        */
  633       public void setKeepAliveTimeout(int timeout) {
  634           keepAliveTimeout = timeout;
  635       }
  636   
  637   
  638       /**
  639        * Return the number Keep-Alive timeout.
  640        */
  641       public int getKeepAliveTimeout() {
  642           return keepAliveTimeout;
  643       }
  644   
  645   
  646       /**
  647        * Set the maximum size of a POST which will be buffered in SSL mode.
  648        */
  649       public void setMaxSavePostSize(int msps) {
  650           maxSavePostSize = msps;
  651       }
  652   
  653   
  654       /**
  655        * Return the maximum size of a POST which will be buffered in SSL mode.
  656        */
  657       public int getMaxSavePostSize() {
  658           return maxSavePostSize;
  659       }
  660   
  661   
  662       /**
  663        * Set the SSL information for this HTTP connection.
  664        */
  665       public void setSSLSupport(SSLSupport sslSupport) {
  666           this.sslSupport = sslSupport;
  667       }
  668   
  669   
  670       /**
  671        * Set the flag to control upload time-outs.
  672        */
  673       public void setDisableUploadTimeout(boolean isDisabled) {
  674           disableUploadTimeout = isDisabled;
  675       }
  676   
  677       /**
  678        * Get the flag that controls upload time-outs.
  679        */
  680       public boolean getDisableUploadTimeout() {
  681           return disableUploadTimeout;
  682       }
  683   
  684       /**
  685        * Set the socket buffer flag.
  686        */
  687       public void setSocketBuffer(int socketBuffer) {
  688           this.socketBuffer = socketBuffer;
  689           outputBuffer.setSocketBuffer(socketBuffer);
  690       }
  691   
  692       /**
  693        * Get the socket buffer flag.
  694        */
  695       public int getSocketBuffer() {
  696           return socketBuffer;
  697       }
  698   
  699       /**
  700        * Set the upload timeout.
  701        */
  702       public void setTimeout( int timeouts ) {
  703           timeout = timeouts ;
  704       }
  705   
  706       /**
  707        * Get the upload timeout.
  708        */
  709       public int getTimeout() {
  710           return timeout;
  711       }
  712   
  713   
  714       /**
  715        * Set the server header name.
  716        */
  717       public void setServer( String server ) {
  718           if (server==null || server.equals("")) {
  719               this.server = null;
  720           } else {
  721               this.server = server;
  722           }
  723       }
  724   
  725       /**
  726        * Get the server header name.
  727        */
  728       public String getServer() {
  729           return server;
  730       }
  731   
  732   
  733       /** Get the request associated with this processor.
  734        *
  735        * @return The request
  736        */
  737       public Request getRequest() {
  738           return request;
  739       }
  740   
  741       /**
  742        * Process pipelined HTTP requests using the specified input and output
  743        * streams.
  744        *
  745        * @param input stream from which the HTTP requests will be read
  746        * @param output stream which will be used to output the HTTP
  747        * responses
  748        * @throws IOException error during an I/O operation
  749        */
  750       public void process(Socket socket)
  751           throws IOException {
  752           RequestInfo rp = request.getRequestProcessor();
  753           rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
  754   
  755           // Set the remote address
  756           remoteAddr = null;
  757           remoteHost = null;
  758           localAddr = null;
  759           localName = null;
  760           remotePort = -1;
  761           localPort = -1;
  762   
  763           // Setting up the I/O
  764           this.socket = socket;
  765           inputBuffer.setInputStream(socket.getInputStream());
  766           outputBuffer.setOutputStream(socket.getOutputStream());
  767   
  768           // Error flag
  769           error = false;
  770           keepAlive = true;
  771   
  772           int keepAliveLeft = maxKeepAliveRequests;
  773           int soTimeout = socket.getSoTimeout();
  774           int oldSoTimeout = soTimeout;
  775   
  776           int threadRatio = (endpoint.getCurrentThreadsBusy() * 100)
  777                   / endpoint.getMaxThreads();
  778           if (threadRatio > 75) {
  779               keepAliveLeft = 1;
  780           }
  781           
  782           if (soTimeout != oldSoTimeout) {
  783               try {
  784                   socket.setSoTimeout(soTimeout);
  785               } catch (Throwable t) {
  786                   log.debug(sm.getString("http11processor.socket.timeout"), t);
  787                   error = true;
  788               }
  789           }
  790   
  791           boolean keptAlive = false;
  792   
  793           while (started && !error && keepAlive) {
  794   
  795               // Parsing the request header
  796               try {
  797                   if (!disableUploadTimeout && keptAlive) {
  798                       if (keepAliveTimeout > 0) {
  799                           socket.setSoTimeout(keepAliveTimeout);
  800                       }
  801                       else if (soTimeout > 0) {
  802                           socket.setSoTimeout(soTimeout);
  803                       }
  804                   }
  805                   inputBuffer.parseRequestLine();
  806                   request.setStartTime(System.currentTimeMillis());
  807                   keptAlive = true;
  808                   if (!disableUploadTimeout) {
  809                       socket.setSoTimeout(timeout);
  810                   }
  811                   inputBuffer.parseHeaders();
  812               } catch (IOException e) {
  813                   error = true;
  814                   break;
  815               } catch (Throwable t) {
  816                   if (log.isDebugEnabled()) {
  817                       log.debug(sm.getString("http11processor.header.parse"), t);
  818                   }
  819                   // 400 - Bad Request
  820                   response.setStatus(400);
  821                   error = true;
  822               }
  823   
  824               // Setting up filters, and parse some request headers
  825               rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
  826               try {
  827                   prepareRequest();
  828               } catch (Throwable t) {
  829                   if (log.isDebugEnabled()) {
  830                       log.debug(sm.getString("http11processor.request.prepare"), t);
  831                   }
  832                   // 400 - Internal Server Error
  833                   response.setStatus(400);
  834                   error = true;
  835               }
  836   
  837               if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0)
  838                   keepAlive = false;
  839   
  840               // Process the request in the adapter
  841               if (!error) {
  842                   try {
  843                       rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
  844                       adapter.service(request, response);
  845                       // Handle when the response was committed before a serious
  846                       // error occurred.  Throwing a ServletException should both
  847                       // set the status to 500 and set the errorException.
  848                       // If we fail here, then the response is likely already
  849                       // committed, so we can't try and set headers.
  850                       if(keepAlive && !error) { // Avoid checking twice.
  851                           error = response.getErrorException() != null ||
  852                                   statusDropsConnection(response.getStatus());
  853                       }
  854   
  855                   } catch (InterruptedIOException e) {
  856                       error = true;
  857                   } catch (Throwable t) {
  858                       log.error(sm.getString("http11processor.request.process"), t);
  859                       // 500 - Internal Server Error
  860                       response.setStatus(500);
  861                       error = true;
  862                   }
  863               }
  864   
  865               // Finish the handling of the request
  866               try {
  867                   rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
  868                   inputBuffer.endRequest();
  869               } catch (IOException e) {
  870                   error = true;
  871               } catch (Throwable t) {
  872                   log.error(sm.getString("http11processor.request.finish"), t);
  873                   // 500 - Internal Server Error
  874                   response.setStatus(500);
  875                   error = true;
  876               }
  877               try {
  878                   rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
  879                   outputBuffer.endRequest();
  880               } catch (IOException e) {
  881                   error = true;
  882               } catch (Throwable t) {
  883                   log.error(sm.getString("http11processor.response.finish"), t);
  884                   error = true;
  885               }
  886   
  887               // If there was an error, make sure the request is counted as
  888               // and error, and update the statistics counter
  889               if (error) {
  890                   response.setStatus(500);
  891               }
  892               request.updateCounters();
  893   
  894               rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
  895   
  896               // Don't reset the param - we'll see it as ended. Next request
  897               // will reset it
  898               // thrA.setParam(null);
  899               // Next request
  900               inputBuffer.nextRequest();
  901               outputBuffer.nextRequest();
  902   
  903           }
  904   
  905           rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
  906   
  907           // Recycle
  908           inputBuffer.recycle();
  909           outputBuffer.recycle();
  910   
  911           // Recycle ssl info
  912           sslSupport = null;
  913       }
  914   
  915   
  916       // ----------------------------------------------------- ActionHook Methods
  917   
  918   
  919       /**
  920        * Send an action to the connector.
  921        *
  922        * @param actionCode Type of the action
  923        * @param param Action parameter
  924        */
  925       public void action(ActionCode actionCode, Object param) {
  926   
  927           if (actionCode == ActionCode.ACTION_COMMIT) {
  928               // Commit current response
  929   
  930               if (response.isCommitted())
  931                   return;
  932   
  933               // Validate and write response headers
  934               prepareResponse();
  935               try {
  936                   outputBuffer.commit();
  937               } catch (IOException e) {
  938                   // Set error flag
  939                   error = true;
  940               }
  941   
  942           } else if (actionCode == ActionCode.ACTION_ACK) {
  943   
  944               // Acknowlege request
  945   
  946               // Send a 100 status back if it makes sense (response not committed
  947               // yet, and client specified an expectation for 100-continue)
  948   
  949               if ((response.isCommitted()) || !expectation)
  950                   return;
  951   
  952               inputBuffer.setSwallowInput(true);
  953               try {
  954                   outputBuffer.sendAck();
  955               } catch (IOException e) {
  956                   // Set error flag
  957                   error = true;
  958               }
  959   
  960           } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
  961   
  962               try {
  963                   outputBuffer.flush();
  964               } catch (IOException e) {
  965                   // Set error flag
  966                   error = true;
  967                   response.setErrorException(e);
  968               }
  969   
  970           } else if (actionCode == ActionCode.ACTION_CLOSE) {
  971               // Close
  972   
  973               // End the processing of the current request, and stop any further
  974               // transactions with the client
  975   
  976               try {
  977                   outputBuffer.endRequest();
  978               } catch (IOException e) {
  979                   // Set error flag
  980                   error = true;
  981               }
  982   
  983           } else if (actionCode == ActionCode.ACTION_RESET) {
  984   
  985               // Reset response
  986   
  987               // Note: This must be called before the response is committed
  988   
  989               outputBuffer.reset();
  990   
  991           } else if (actionCode == ActionCode.ACTION_CUSTOM) {
  992   
  993               // Do nothing
  994   
  995           } else if (actionCode == ActionCode.ACTION_START) {
  996   
  997               started = true;
  998   
  999           } else if (actionCode == ActionCode.ACTION_STOP) {
 1000   
 1001               started = false;
 1002   
 1003           } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
 1004   
 1005               try {
 1006                   if (sslSupport != null) {
 1007                       Object sslO = sslSupport.getCipherSuite();
 1008                       if (sslO != null)
 1009                           request.setAttribute
 1010                               (SSLSupport.CIPHER_SUITE_KEY, sslO);
 1011                       sslO = sslSupport.getPeerCertificateChain(false);
 1012                       if (sslO != null)
 1013                           request.setAttribute
 1014                               (SSLSupport.CERTIFICATE_KEY, sslO);
 1015                       sslO = sslSupport.getKeySize();
 1016                       if (sslO != null)
 1017                           request.setAttribute
 1018                               (SSLSupport.KEY_SIZE_KEY, sslO);
 1019                       sslO = sslSupport.getSessionId();
 1020                       if (sslO != null)
 1021                           request.setAttribute
 1022                               (SSLSupport.SESSION_ID_KEY, sslO);
 1023                   }
 1024               } catch (Exception e) {
 1025                   log.warn(sm.getString("http11processor.socket.ssl"), e);
 1026               }
 1027   
 1028           } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) {
 1029   
 1030               if ((remoteAddr == null) && (socket != null)) {
 1031                   InetAddress inetAddr = socket.getInetAddress();
 1032                   if (inetAddr != null) {
 1033                       remoteAddr = inetAddr.getHostAddress();
 1034                   }
 1035               }
 1036               request.remoteAddr().setString(remoteAddr);
 1037   
 1038           } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) {
 1039   
 1040               if ((localName == null) && (socket != null)) {
 1041                   InetAddress inetAddr = socket.getLocalAddress();
 1042                   if (inetAddr != null) {
 1043                       localName = inetAddr.getHostName();
 1044                   }
 1045               }
 1046               request.localName().setString(localName);
 1047   
 1048           } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
 1049   
 1050               if ((remoteHost == null) && (socket != null)) {
 1051                   InetAddress inetAddr = socket.getInetAddress();
 1052                   if (inetAddr != null) {
 1053                       remoteHost = inetAddr.getHostName();
 1054                   }
 1055                   if(remoteHost == null) {
 1056                       if(remoteAddr != null) {
 1057                           remoteHost = remoteAddr;
 1058                       } else { // all we can do is punt
 1059                           request.remoteHost().recycle();
 1060                       }
 1061                   }
 1062               }
 1063               request.remoteHost().setString(remoteHost);
 1064   
 1065           } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
 1066   
 1067               if (localAddr == null)
 1068                  localAddr = socket.getLocalAddress().getHostAddress();
 1069   
 1070               request.localAddr().setString(localAddr);
 1071   
 1072           } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) {
 1073   
 1074               if ((remotePort == -1 ) && (socket !=null)) {
 1075                   remotePort = socket.getPort();
 1076               }
 1077               request.setRemotePort(remotePort);
 1078   
 1079           } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) {
 1080   
 1081               if ((localPort == -1 ) && (socket !=null)) {
 1082                   localPort = socket.getLocalPort();
 1083               }
 1084               request.setLocalPort(localPort);
 1085   
 1086           } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) {
 1087               if( sslSupport != null) {
 1088                   /*
 1089                    * Consume and buffer the request body, so that it does not
 1090                    * interfere with the client's handshake messages
 1091                    */
 1092                   InputFilter[] inputFilters = inputBuffer.getFilters();
 1093                   ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
 1094                       .setLimit(maxSavePostSize);
 1095                   inputBuffer.addActiveFilter
 1096                       (inputFilters[Constants.BUFFERED_FILTER]);
 1097                   try {
 1098                       Object sslO = sslSupport.getPeerCertificateChain(true);
 1099                       if( sslO != null) {
 1100                           request.setAttribute
 1101                               (SSLSupport.CERTIFICATE_KEY, sslO);
 1102                       }
 1103                   } catch (Exception e) {
 1104                       log.warn(sm.getString("http11processor.socket.ssl"), e);
 1105                   }
 1106               }
 1107           } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
 1108               ByteChunk body = (ByteChunk) param;
 1109               
 1110               InputFilter savedBody = new SavedRequestInputFilter(body);
 1111               savedBody.setRequest(request);
 1112   
 1113               InternalInputBuffer internalBuffer = (InternalInputBuffer)
 1114                   request.getInputBuffer();
 1115               internalBuffer.addActiveFilter(savedBody);
 1116           }
 1117   
 1118       }
 1119   
 1120   
 1121       // ------------------------------------------------------ Connector Methods
 1122   
 1123   
 1124       /**
 1125        * Set the associated adapter.
 1126        *
 1127        * @param adapter the new adapter
 1128        */
 1129       public void setAdapter(Adapter adapter) {
 1130           this.adapter = adapter;
 1131       }
 1132   
 1133   
 1134       /**
 1135        * Get the associated adapter.
 1136        *
 1137        * @return the associated adapter
 1138        */
 1139       public Adapter getAdapter() {
 1140           return adapter;
 1141       }
 1142   
 1143   
 1144       // ------------------------------------------------------ Protected Methods
 1145   
 1146   
 1147       /**
 1148        * After reading the request headers, we have to setup the request filters.
 1149        */
 1150       protected void prepareRequest() {
 1151   
 1152           http11 = true;
 1153           http09 = false;
 1154           contentDelimitation = false;
 1155           expectation = false;
 1156           if (sslSupport != null) {
 1157               request.scheme().setString("https");
 1158           }
 1159           MessageBytes protocolMB = request.protocol();
 1160           if (protocolMB.equals(Constants.HTTP_11)) {
 1161               http11 = true;
 1162               protocolMB.setString(Constants.HTTP_11);
 1163           } else if (protocolMB.equals(Constants.HTTP_10)) {
 1164               http11 = false;
 1165               keepAlive = false;
 1166               protocolMB.setString(Constants.HTTP_10);
 1167           } else if (protocolMB.equals("")) {
 1168               // HTTP/0.9
 1169               http09 = true;
 1170               http11 = false;
 1171               keepAlive = false;
 1172           } else {
 1173               // Unsupported protocol
 1174               http11 = false;
 1175               error = true;
 1176               // Send 505; Unsupported HTTP version
 1177               if (log.isDebugEnabled()) {
 1178                   log.debug(sm.getString("http11processor.request.prepare")+
 1179                             " Unsupported HTTP version \""+protocolMB+"\"");
 1180               }
 1181               response.setStatus(505);
 1182           }
 1183   
 1184           MessageBytes methodMB = request.method();
 1185           if (methodMB.equals(Constants.GET)) {
 1186               methodMB.setString(Constants.GET);
 1187           } else if (methodMB.equals(Constants.POST)) {
 1188               methodMB.setString(Constants.POST);
 1189           }
 1190   
 1191           MimeHeaders headers = request.getMimeHeaders();
 1192   
 1193           // Check connection header
 1194           MessageBytes connectionValueMB = headers.getValue("connection");
 1195           if (connectionValueMB != null) {
 1196               ByteChunk connectionValueBC = connectionValueMB.getByteChunk();
 1197               if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
 1198                   keepAlive = false;
 1199               } else if (findBytes(connectionValueBC,
 1200                                    Constants.KEEPALIVE_BYTES) != -1) {
 1201                   keepAlive = true;
 1202               }
 1203           }
 1204   
 1205           MessageBytes expectMB = null;
 1206           if (http11)
 1207               expectMB = headers.getValue("expect");
 1208           if ((expectMB != null)
 1209               && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) {
 1210               inputBuffer.setSwallowInput(false);
 1211               expectation = true;
 1212           }
 1213   
 1214           // Check user-agent header
 1215           if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) {
 1216               MessageBytes userAgentValueMB = headers.getValue("user-agent");
 1217               // Check in the restricted list, and adjust the http11
 1218               // and keepAlive flags accordingly
 1219               if(userAgentValueMB != null) {
 1220                   String userAgentValue = userAgentValueMB.toString();
 1221                   for (int i = 0; i < restrictedUserAgents.length; i++) {
 1222                       if (restrictedUserAgents[i].matcher(userAgentValue).matches()) {
 1223                           http11 = false;
 1224                           keepAlive = false;
 1225                           break;
 1226                       }
 1227                   }
 1228               }
 1229           }
 1230   
 1231           // Check for a full URI (including protocol://host:port/)
 1232           ByteChunk uriBC = request.requestURI().getByteChunk();
 1233           if (uriBC.startsWithIgnoreCase("http", 0)) {
 1234   
 1235               int pos = uriBC.indexOf("://", 0, 3, 4);
 1236               int uriBCStart = uriBC.getStart();
 1237               int slashPos = -1;
 1238               if (pos != -1) {
 1239                   byte[] uriB = uriBC.getBytes();
 1240                   slashPos = uriBC.indexOf('/', pos + 3);
 1241                   if (slashPos == -1) {
 1242                       slashPos = uriBC.getLength();
 1243                       // Set URI as "/"
 1244                       request.requestURI().setBytes
 1245                           (uriB, uriBCStart + pos + 1, 1);
 1246                   } else {
 1247                       request.requestURI().setBytes
 1248                           (uriB, uriBCStart + slashPos,
 1249                            uriBC.getLength() - slashPos);
 1250                   }
 1251                   MessageBytes hostMB = headers.setValue("host");
 1252                   hostMB.setBytes(uriB, uriBCStart + pos + 3,
 1253                                   slashPos - pos - 3);
 1254               }
 1255   
 1256           }
 1257   
 1258           // Input filter setup
 1259           InputFilter[] inputFilters = inputBuffer.getFilters();
 1260   
 1261           // Parse transfer-encoding header
 1262           MessageBytes transferEncodingValueMB = null;
 1263           if (http11)
 1264               transferEncodingValueMB = headers.getValue("transfer-encoding");
 1265           if (transferEncodingValueMB != null) {
 1266               String transferEncodingValue = transferEncodingValueMB.toString();
 1267               // Parse the comma separated list. "identity" codings are ignored
 1268               int startPos = 0;
 1269               int commaPos = transferEncodingValue.indexOf(',');
 1270               String encodingName = null;
 1271               while (commaPos != -1) {
 1272                   encodingName = transferEncodingValue.substring
 1273                       (startPos, commaPos).toLowerCase().trim();
 1274                   if (!addInputFilter(inputFilters, encodingName)) {
 1275                       // Unsupported transfer encoding
 1276                       error = true;
 1277                       // 501 - Unimplemented
 1278                       response.setStatus(501);
 1279                   }
 1280                   startPos = commaPos + 1;
 1281                   commaPos = transferEncodingValue.indexOf(',', startPos);
 1282               }
 1283               encodingName = transferEncodingValue.substring(startPos)
 1284                   .toLowerCase().trim();
 1285               if (!addInputFilter(inputFilters, encodingName)) {
 1286                   // Unsupported transfer encoding
 1287                   error = true;
 1288                   // 501 - Unimplemented
 1289                   if (log.isDebugEnabled()) {
 1290                       log.debug(sm.getString("http11processor.request.prepare")+
 1291                                 " Unsupported transfer encoding \""+encodingName+"\"");
 1292                   }
 1293                   response.setStatus(501);
 1294               }
 1295           }
 1296   
 1297           // Parse content-length header
 1298           long contentLength = request.getContentLengthLong();
 1299           if (contentLength >= 0 && !contentDelimitation) {
 1300               inputBuffer.addActiveFilter
 1301                   (inputFilters[Constants.IDENTITY_FILTER]);
 1302               contentDelimitation = true;
 1303           }
 1304   
 1305           MessageBytes valueMB = headers.getValue("host");
 1306   
 1307           // Check host header
 1308           if (http11 && (valueMB == null)) {
 1309               error = true;
 1310               // 400 - Bad request
 1311               if (log.isDebugEnabled()) {
 1312                   log.debug(sm.getString("http11processor.request.prepare")+
 1313                             " host header missing");
 1314               }
 1315               response.setStatus(400);
 1316           }
 1317   
 1318           parseHost(valueMB);
 1319   
 1320           if (!contentDelimitation) {
 1321               // If there's no content length 
 1322               // (broken HTTP/1.0 or HTTP/1.1), assume
 1323               // the client is not broken and didn't send a body
 1324               inputBuffer.addActiveFilter
 1325                       (inputFilters[Constants.VOID_FILTER]);
 1326               contentDelimitation = true;
 1327           }
 1328   
 1329       }
 1330   
 1331   
 1332       /**
 1333        * Parse host.
 1334        */
 1335       public void parseHost(MessageBytes valueMB) {
 1336   
 1337           if (valueMB == null || valueMB.isNull()) {
 1338               // HTTP/1.0
 1339               // Default is what the socket tells us. Overriden if a host is
 1340               // found/parsed
 1341               request.setServerPort(socket.getLocalPort());
 1342               InetAddress localAddress = socket.getLocalAddress();
 1343               // Setting the socket-related fields. The adapter doesn't know
 1344               // about socket.
 1345               request.serverName().setString(localAddress.getHostName());
 1346               return;
 1347           }
 1348   
 1349           ByteChunk valueBC = valueMB.getByteChunk();
 1350           byte[] valueB = valueBC.getBytes();
 1351           int valueL = valueBC.getLength();
 1352           int valueS = valueBC.getStart();
 1353           int colonPos = -1;
 1354           if (hostNameC.length < valueL) {
 1355               hostNameC = new char[valueL];
 1356           }
 1357   
 1358           boolean ipv6 = (valueB[valueS] == '[');
 1359           boolean bracketClosed = false;
 1360           for (int i = 0; i < valueL; i++) {
 1361               char b = (char) valueB[i + valueS];
 1362               hostNameC[i] = b;
 1363               if (b == ']') {
 1364                   bracketClosed = true;
 1365               } else if (b == ':') {
 1366                   if (!ipv6 || bracketClosed) {
 1367                       colonPos = i;
 1368                       break;
 1369                   }
 1370               }
 1371           }
 1372   
 1373           if (colonPos < 0) {
 1374               if (sslSupport == null) {
 1375                   // 80 - Default HTTP port
 1376                   request.setServerPort(80);
 1377               } else {
 1378                   // 443 - Default HTTPS port
 1379                   request.setServerPort(443);
 1380               }
 1381               request.serverName().setChars(hostNameC, 0, valueL);
 1382           } else {
 1383   
 1384               request.serverName().setChars(hostNameC, 0, colonPos);
 1385   
 1386               int port = 0;
 1387               int mult = 1;
 1388               for (int i = valueL - 1; i > colonPos; i--) {
 1389                   int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
 1390                   if (charValue == -1) {
 1391                       // Invalid character
 1392                       error = true;
 1393                       // 400 - Bad request
 1394                       response.setStatus(400);
 1395                       break;
 1396                   }
 1397                   port = port + (charValue * mult);
 1398                   mult = 10 * mult;
 1399               }
 1400               request.setServerPort(port);
 1401   
 1402           }
 1403   
 1404       }
 1405   
 1406   
 1407       /**
 1408        * Check for compression
 1409        */
 1410       private boolean isCompressable() {
 1411   
 1412           // Nope Compression could works in HTTP 1.0 also
 1413           // cf: mod_deflate
 1414   
 1415           // Compression only since HTTP 1.1
 1416           // if (! http11)
 1417           //    return false;
 1418   
 1419           // Check if browser support gzip encoding
 1420           MessageBytes acceptEncodingMB =
 1421               request.getMimeHeaders().getValue("accept-encoding");
 1422   
 1423           if ((acceptEncodingMB == null)
 1424               || (acceptEncodingMB.indexOf("gzip") == -1))
 1425               return false;
 1426   
 1427           // Check if content is not allready gzipped
 1428           MessageBytes contentEncodingMB =
 1429               response.getMimeHeaders().getValue("Content-Encoding");
 1430   
 1431           if ((contentEncodingMB != null)
 1432               && (contentEncodingMB.indexOf("gzip") != -1))
 1433               return false;
 1434   
 1435           // If force mode, allways compress (test purposes only)
 1436           if (compressionLevel == 2)
 1437              return true;
 1438   
 1439           // Check for incompatible Browser
 1440           if (noCompressionUserAgents != null) {
 1441               MessageBytes userAgentValueMB =
 1442                   request.getMimeHeaders().getValue("user-agent");
 1443               if(userAgentValueMB != null) {
 1444                   String userAgentValue = userAgentValueMB.toString();
 1445   
 1446                   // If one Regexp rule match, disable compression
 1447                   for (int i = 0; i < noCompressionUserAgents.length; i++)
 1448                       if (noCompressionUserAgents[i].matcher(userAgentValue).matches())
 1449                           return false;
 1450               }
 1451           }
 1452   
 1453           // Check if suffisant len to trig the compression
 1454           long contentLength = response.getContentLengthLong();
 1455           if ((contentLength == -1)
 1456               || (contentLength > compressionMinSize)) {
 1457               // Check for compatible MIME-TYPE
 1458               if (compressableMimeTypes != null) {
 1459                   return (startsWithStringArray(compressableMimeTypes,
 1460                                                 response.getContentType()));
 1461               }
 1462           }
 1463   
 1464           return false;
 1465       }
 1466   
 1467   
 1468       /**
 1469        * When committing the response, we have to validate the set of headers, as
 1470        * well as setup the response filters.
 1471        */
 1472       protected void prepareResponse() {
 1473   
 1474           boolean entityBody = true;
 1475           contentDelimitation = false;
 1476   
 1477           OutputFilter[] outputFilters = outputBuffer.getFilters();
 1478   
 1479           if (http09 == true) {
 1480               // HTTP/0.9
 1481               outputBuffer.addActiveFilter
 1482                   (outputFilters[Constants.IDENTITY_FILTER]);
 1483               return;
 1484           }
 1485   
 1486           int statusCode = response.getStatus();
 1487           if ((statusCode == 204) || (statusCode == 205)
 1488               || (statusCode == 304)) {
 1489               // No entity body
 1490               outputBuffer.addActiveFilter
 1491                   (outputFilters[Constants.VOID_FILTER]);
 1492               entityBody = false;
 1493               contentDelimitation = true;
 1494           }
 1495   
 1496           MessageBytes methodMB = request.method();
 1497           if (methodMB.equals("HEAD")) {
 1498               // No entity body
 1499               outputBuffer.addActiveFilter
 1500                   (outputFilters[Constants.VOID_FILTER]);
 1501               contentDelimitation = true;
 1502           }
 1503   
 1504           // Check for compression
 1505           boolean useCompression = false;
 1506           if (entityBody && (compressionLevel > 0)) {
 1507               useCompression = isCompressable();
 1508   
 1509               // Change content-length to -1 to force chunking
 1510               if (useCompression) {
 1511                   response.setContentLength(-1);
 1512               }
 1513           }
 1514   
 1515           MimeHeaders headers = response.getMimeHeaders();
 1516           if (!entityBody) {
 1517               response.setContentLength(-1);
 1518           } else {
 1519               String contentType = response.getContentType();
 1520               if (contentType != null) {
 1521                   headers.setValue("Content-Type").setString(contentType);
 1522               }
 1523               String contentLanguage = response.getContentLanguage();
 1524               if (contentLanguage != null) {
 1525                   headers.setValue("Content-Language")
 1526                       .setString(contentLanguage);
 1527               }
 1528           }
 1529   
 1530           long contentLength = response.getContentLengthLong();
 1531           if (contentLength != -1) {
 1532               headers.setValue("Content-Length").setLong(contentLength);
 1533               outputBuffer.addActiveFilter
 1534                   (outputFilters[Constants.IDENTITY_FILTER]);
 1535               contentDelimitation = true;
 1536           } else {
 1537               if (entityBody && http11 && keepAlive) {
 1538                   outputBuffer.addActiveFilter
 1539                       (outputFilters[Constants.CHUNKED_FILTER]);
 1540                   contentDelimitation = true;
 1541                   headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
 1542               } else {
 1543                   outputBuffer.addActiveFilter
 1544                       (outputFilters[Constants.IDENTITY_FILTER]);
 1545               }
 1546           }
 1547   
 1548           if (useCompression) {
 1549               outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
 1550               headers.setValue("Content-Encoding").setString("gzip");
 1551               // Make Proxies happy via Vary (from mod_deflate)
 1552               headers.setValue("Vary").setString("Accept-Encoding");
 1553           }
 1554   
 1555           // Add date header
 1556           String date = null;
 1557           if (org.apache.coyote.Constants.IS_SECURITY_ENABLED){
 1558               date = (String)AccessController.doPrivileged(
 1559                       new PrivilegedAction() {
 1560                           public Object run(){
 1561                               return FastHttpDateFormat.getCurrentDate();
 1562                           }
 1563                       }
 1564               );
 1565           } else {
 1566               date = FastHttpDateFormat.getCurrentDate();
 1567           }
 1568           headers.setValue("Date").setString(date);
 1569   
 1570           // FIXME: Add transfer encoding header
 1571   
 1572           if ((entityBody) && (!contentDelimitation)) {
 1573               // Mark as close the connection after the request, and add the
 1574               // connection: close header
 1575               keepAlive = false;
 1576           }
 1577   
 1578           // If we know that the request is bad this early, add the
 1579           // Connection: close header.
 1580           keepAlive = keepAlive && !statusDropsConnection(statusCode);
 1581           if (!keepAlive) {
 1582               headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
 1583           } else if (!http11 && !error) {
 1584               headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
 1585           }
 1586   
 1587           // Build the response header
 1588           outputBuffer.sendStatus();
 1589   
 1590           // Add server header
 1591           if (server != null) {
 1592               headers.setValue("Server").setString(server);
 1593           } else {
 1594               outputBuffer.write(Constants.SERVER_BYTES);
 1595           }
 1596   
 1597           int size = headers.size();
 1598           for (int i = 0; i < size; i++) {
 1599               outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
 1600           }
 1601           outputBuffer.endHeaders();
 1602   
 1603       }
 1604   
 1605   
 1606       /**
 1607        * Initialize standard input and output filters.
 1608        */
 1609       protected void initializeFilters() {
 1610   
 1611           // Create and add the identity filters.
 1612           inputBuffer.addFilter(new IdentityInputFilter());
 1613           outputBuffer.addFilter(new IdentityOutputFilter());
 1614   
 1615           // Create and add the chunked filters.
 1616           inputBuffer.addFilter(new ChunkedInputFilter());
 1617           outputBuffer.addFilter(new ChunkedOutputFilter());
 1618   
 1619           // Create and add the void filters.
 1620           inputBuffer.addFilter(new VoidInputFilter());
 1621           outputBuffer.addFilter(new VoidOutputFilter());
 1622   
 1623           // Create and add buffered input filter
 1624           inputBuffer.addFilter(new BufferedInputFilter());
 1625   
 1626           // Create and add the chunked filters.
 1627           //inputBuffer.addFilter(new GzipInputFilter());
 1628           outputBuffer.addFilter(new GzipOutputFilter());
 1629   
 1630       }
 1631   
 1632   
 1633       /**
 1634        * Add an input filter to the current request.
 1635        *
 1636        * @return false if the encoding was not found (which would mean it is
 1637        * unsupported)
 1638        */
 1639       protected boolean addInputFilter(InputFilter[] inputFilters,
 1640                                        String encodingName) {
 1641           if (encodingName.equals("identity")) {
 1642               // Skip
 1643           } else if (encodingName.equals("chunked")) {
 1644               inputBuffer.addActiveFilter
 1645                   (inputFilters[Constants.CHUNKED_FILTER]);
 1646               contentDelimitation = true;
 1647           } else {
 1648               for (int i = 2; i < inputFilters.length; i++) {
 1649                   if (inputFilters[i].getEncodingName()
 1650                       .toString().equals(encodingName)) {
 1651                       inputBuffer.addActiveFilter(inputFilters[i]);
 1652                       return true;
 1653                   }
 1654               }
 1655               return false;
 1656           }
 1657           return true;
 1658       }
 1659   
 1660   
 1661       /**
 1662        * Specialized utility method: find a sequence of lower case bytes inside
 1663        * a ByteChunk.
 1664        */
 1665       protected int findBytes(ByteChunk bc, byte[] b) {
 1666   
 1667           byte first = b[0];
 1668           byte[] buff = bc.getBuffer();
 1669           int start = bc.getStart();
 1670           int end = bc.getEnd();
 1671   
 1672       // Look for first char
 1673       int srcEnd = b.length;
 1674   
 1675       for (int i = start; i <= (end - srcEnd); i++) {
 1676           if (Ascii.toLower(buff[i]) != first) continue;
 1677           // found first char, now look for a match
 1678               int myPos = i+1;
 1679           for (int srcPos = 1; srcPos < srcEnd; ) {
 1680                   if (Ascii.toLower(buff[myPos++]) != b[srcPos++])
 1681               break;
 1682                   if (srcPos == srcEnd) return i - start; // found it
 1683           }
 1684       }
 1685       return -1;
 1686   
 1687       }
 1688   
 1689       /**
 1690        * Determine if we must drop the connection because of the HTTP status
 1691        * code.  Use the same list of codes as Apache/httpd.
 1692        */
 1693       protected boolean statusDropsConnection(int status) {
 1694           return status == 400 /* SC_BAD_REQUEST */ ||
 1695                  status == 408 /* SC_REQUEST_TIMEOUT */ ||
 1696                  status == 411 /* SC_LENGTH_REQUIRED */ ||
 1697                  status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ ||
 1698                  status == 414 /* SC_REQUEST_URI_TOO_LARGE */ ||
 1699                  status == 500 /* SC_INTERNAL_SERVER_ERROR */ ||
 1700                  status == 503 /* SC_SERVICE_UNAVAILABLE */ ||
 1701                  status == 501 /* SC_NOT_IMPLEMENTED */;
 1702       }
 1703   
 1704   }

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