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

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