Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » coyote » ajp » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package org.apache.coyote.ajp;
   19   
   20   import java.io.ByteArrayInputStream;
   21   import java.io.IOException;
   22   import java.io.InputStream;
   23   import java.io.InterruptedIOException;
   24   import java.io.OutputStream;
   25   import java.net.InetAddress;
   26   import java.net.Socket;
   27   import java.security.cert.CertificateFactory;
   28   import java.security.cert.X509Certificate;
   29   
   30   import org.apache.coyote.ActionCode;
   31   import org.apache.coyote.ActionHook;
   32   import org.apache.coyote.Adapter;
   33   import org.apache.coyote.InputBuffer;
   34   import org.apache.coyote.OutputBuffer;
   35   import org.apache.coyote.Request;
   36   import org.apache.coyote.RequestInfo;
   37   import org.apache.coyote.Response;
   38   import org.apache.tomcat.util.buf.ByteChunk;
   39   import org.apache.tomcat.util.buf.HexUtils;
   40   import org.apache.tomcat.util.buf.MessageBytes;
   41   import org.apache.tomcat.util.http.HttpMessages;
   42   import org.apache.tomcat.util.http.MimeHeaders;
   43   import org.apache.tomcat.util.net.JIoEndpoint;
   44   import org.apache.tomcat.util.res.StringManager;
   45   
   46   
   47   /**
   48    * Processes HTTP requests.
   49    *
   50    * @author Remy Maucherat
   51    * @author Henri Gomez
   52    * @author Dan Milstein
   53    * @author Keith Wannamaker
   54    * @author Kevin Seguin
   55    * @author Costin Manolache
   56    * @author Bill Barker
   57    */
   58   public class AjpProcessor implements ActionHook {
   59   
   60   
   61       /**
   62        * Logger.
   63        */
   64       protected static org.apache.juli.logging.Log log
   65           = org.apache.juli.logging.LogFactory.getLog(AjpProcessor.class);
   66   
   67       /**
   68        * The string manager for this package.
   69        */
   70       protected static StringManager sm =
   71           StringManager.getManager(Constants.Package);
   72   
   73   
   74       // ----------------------------------------------------------- Constructors
   75   
   76   
   77       public AjpProcessor(int packetSize, JIoEndpoint endpoint) {
   78   
   79           this.endpoint = endpoint;
   80   
   81           request = new Request();
   82           request.setInputBuffer(new SocketInputBuffer());
   83   
   84           response = new Response();
   85           response.setHook(this);
   86           response.setOutputBuffer(new SocketOutputBuffer());
   87           request.setResponse(response);
   88   
   89           requestHeaderMessage = new AjpMessage(packetSize);
   90           responseHeaderMessage = new AjpMessage(packetSize);
   91           bodyMessage = new AjpMessage(packetSize);
   92           
   93           // Cause loading of HexUtils
   94           int foo = HexUtils.DEC[0];
   95   
   96           // Cause loading of HttpMessages
   97           HttpMessages.getMessage(200);
   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        * Header message. Note that this header is merely the one used during the
  125        * processing of the first message of a "request", so it might not be a request
  126        * header. It will stay unchanged during the processing of the whole request.
  127        */
  128       protected AjpMessage requestHeaderMessage = null;
  129   
  130   
  131       /**
  132        * Message used for response header composition.
  133        */
  134       protected AjpMessage responseHeaderMessage = null;
  135   
  136   
  137       /**
  138        * Body message.
  139        */
  140       protected AjpMessage bodyMessage = null;
  141   
  142   
  143       /**
  144        * Body message.
  145        */
  146       protected MessageBytes bodyBytes = MessageBytes.newInstance();
  147   
  148   
  149       /**
  150        * State flag.
  151        */
  152       protected boolean started = false;
  153   
  154   
  155       /**
  156        * Error flag.
  157        */
  158       protected boolean error = false;
  159   
  160   
  161       /**
  162        * Socket associated with the current connection.
  163        */
  164       protected Socket socket;
  165   
  166       
  167       /**
  168        * Input stream.
  169        */
  170       protected InputStream input;
  171       
  172       
  173       /**
  174        * Output stream.
  175        */
  176       protected OutputStream output;
  177       
  178   
  179       /**
  180        * Host name (used to avoid useless B2C conversion on the host name).
  181        */
  182       protected char[] hostNameC = new char[0];
  183   
  184   
  185       /**
  186        * Associated endpoint.
  187        */
  188       protected JIoEndpoint endpoint;
  189   
  190   
  191       /**
  192        * The socket timeout used when reading the first block of the request
  193        * header.
  194        */
  195       protected long readTimeout;
  196   
  197   
  198       /**
  199        * Temp message bytes used for processing.
  200        */
  201       protected MessageBytes tmpMB = MessageBytes.newInstance();
  202   
  203   
  204       /**
  205        * Byte chunk for certs.
  206        */
  207       protected MessageBytes certificates = MessageBytes.newInstance();
  208   
  209   
  210       /**
  211        * End of stream flag.
  212        */
  213       protected boolean endOfStream = false;
  214   
  215   
  216       /**
  217        * Body empty flag.
  218        */
  219       protected boolean empty = true;
  220   
  221   
  222       /**
  223        * First read.
  224        */
  225       protected boolean first = true;
  226   
  227   
  228       /**
  229        * Replay read.
  230        */
  231       protected boolean replay = false;
  232   
  233   
  234       /**
  235        * Finished response.
  236        */
  237       protected boolean finished = false;
  238   
  239   
  240       /**
  241        * Direct buffer used for sending right away a get body message.
  242        */
  243       protected static final byte[] getBodyMessageArray;
  244   
  245   
  246       /**
  247        * Direct buffer used for sending right away a pong message.
  248        */
  249       protected static final byte[] pongMessageArray;
  250   
  251   
  252       /**
  253        * End message array.
  254        */
  255       protected static final byte[] endMessageArray;
  256   
  257       /**
  258        * Flush message array.
  259        */
  260       protected static final byte[] flushMessageArray;
  261   
  262   
  263       // ----------------------------------------------------- Static Initializer
  264   
  265   
  266       static {
  267   
  268           // Set the get body message buffer
  269   
  270           AjpMessage getBodyMessage = new AjpMessage(16);
  271           getBodyMessage.reset();
  272           getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK);
  273           getBodyMessage.appendInt(Constants.MAX_READ_SIZE);
  274           getBodyMessage.end();
  275           getBodyMessageArray = new byte[getBodyMessage.getLen()];
  276           System.arraycopy(getBodyMessage.getBuffer(), 0, getBodyMessageArray, 
  277                   0, getBodyMessage.getLen());
  278   
  279           // Set the read body message buffer
  280           AjpMessage pongMessage = new AjpMessage(16);
  281           pongMessage.reset();
  282           pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY);
  283           pongMessage.end();
  284           pongMessageArray = new byte[pongMessage.getLen()];
  285           System.arraycopy(pongMessage.getBuffer(), 0, pongMessageArray, 
  286                   0, pongMessage.getLen());
  287   
  288           // Allocate the end message array
  289           AjpMessage endMessage = new AjpMessage(16);
  290           endMessage.reset();
  291           endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE);
  292           endMessage.appendByte(1);
  293           endMessage.end();
  294           endMessageArray = new byte[endMessage.getLen()];
  295           System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0,
  296                   endMessage.getLen());
  297   
  298           // Allocate the flush message array
  299           AjpMessage flushMessage = new AjpMessage(16);
  300           flushMessage.reset();
  301           flushMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
  302           flushMessage.appendInt(0);
  303           flushMessage.appendByte(0);
  304           flushMessage.end();
  305           flushMessageArray = new byte[flushMessage.getLen()];
  306           System.arraycopy(flushMessage.getBuffer(), 0, flushMessageArray, 0,
  307                   flushMessage.getLen());
  308   
  309       }
  310   
  311   
  312       // ------------------------------------------------------------- Properties
  313   
  314   
  315       /**
  316        * Use Tomcat authentication ?
  317        */
  318       protected boolean tomcatAuthentication = true;
  319       public boolean getTomcatAuthentication() { return tomcatAuthentication; }
  320       public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; }
  321   
  322   
  323       /**
  324        * Required secret.
  325        */
  326       protected String requiredSecret = null;
  327       public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; }
  328   
  329   
  330       /**
  331        * The number of milliseconds Tomcat will wait for a subsequent request
  332        * before closing the connection. The default is the same as for
  333        * Apache HTTP Server (15 000 milliseconds).
  334        */
  335       protected int keepAliveTimeout = -1;
  336       public int getKeepAliveTimeout() { return keepAliveTimeout; }
  337       public void setKeepAliveTimeout(int timeout) { keepAliveTimeout = timeout; }
  338   
  339   
  340       // --------------------------------------------------------- Public Methods
  341   
  342   
  343       /** Get the request associated with this processor.
  344        *
  345        * @return The request
  346        */
  347       public Request getRequest() {
  348           return request;
  349       }
  350   
  351   
  352       /**
  353        * Process pipelined HTTP requests using the specified input and output
  354        * streams.
  355        *
  356        * @throws IOException error during an I/O operation
  357        */
  358       public void process(Socket socket)
  359           throws IOException {
  360           RequestInfo rp = request.getRequestProcessor();
  361           rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
  362   
  363           // Setting up the socket
  364           this.socket = socket;
  365           input = socket.getInputStream();
  366           output = socket.getOutputStream();
  367           int soTimeout = -1;
  368           if (keepAliveTimeout > 0) {
  369               soTimeout = socket.getSoTimeout();
  370           }
  371   
  372           // Error flag
  373           error = false;
  374   
  375           while (started && !error) {
  376   
  377               // Parsing the request header
  378               try {
  379                   // Set keep alive timeout if enabled
  380                   if (keepAliveTimeout > 0) {
  381                       socket.setSoTimeout(keepAliveTimeout);
  382                   }
  383                   // Get first message of the request
  384                   if (!readMessage(requestHeaderMessage)) {
  385                       // This means a connection timeout
  386                       rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
  387                       break;
  388                   }
  389                   // Set back timeout if keep alive timeout is enabled
  390                   if (keepAliveTimeout > 0) {
  391                       socket.setSoTimeout(soTimeout);
  392                   }
  393                   // Check message type, process right away and break if
  394                   // not regular request processing
  395                   int type = requestHeaderMessage.getByte();
  396                   if (type == Constants.JK_AJP13_CPING_REQUEST) {
  397                       try {
  398                           output.write(pongMessageArray);
  399                       } catch (IOException e) {
  400                           error = true;
  401                       }
  402                       continue;
  403                   } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) {
  404                       // Usually the servlet didn't read the previous request body
  405                       if(log.isDebugEnabled()) {
  406                           log.debug("Unexpected message: "+type);
  407                       }
  408                       continue;
  409                   }
  410   
  411                   request.setStartTime(System.currentTimeMillis());
  412               } catch (IOException e) {
  413                   error = true;
  414                   break;
  415               } catch (Throwable t) {
  416                   log.debug(sm.getString("ajpprocessor.header.error"), t);
  417                   // 400 - Bad Request
  418                   response.setStatus(400);
  419                   error = true;
  420               }
  421   
  422               // Setting up filters, and parse some request headers
  423               rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
  424               try {
  425                   prepareRequest();
  426               } catch (Throwable t) {
  427                   log.debug(sm.getString("ajpprocessor.request.prepare"), t);
  428                   // 400 - Internal Server Error
  429                   response.setStatus(400);
  430                   error = true;
  431               }
  432   
  433               // Process the request in the adapter
  434               if (!error) {
  435                   try {
  436                       rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
  437                       adapter.service(request, response);
  438                   } catch (InterruptedIOException e) {
  439                       error = true;
  440                   } catch (Throwable t) {
  441                       log.error(sm.getString("ajpprocessor.request.process"), t);
  442                       // 500 - Internal Server Error
  443                       response.setStatus(500);
  444                       error = true;
  445                   }
  446               }
  447   
  448               // Finish the response if not done yet
  449               if (!finished) {
  450                   try {
  451                       finish();
  452                   } catch (Throwable t) {
  453                       error = true;
  454                   }
  455               }
  456   
  457               // If there was an error, make sure the request is counted as
  458               // and error, and update the statistics counter
  459               if (error) {
  460                   response.setStatus(500);
  461               }
  462               request.updateCounters();
  463   
  464               rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
  465               recycle();
  466   
  467           }
  468   
  469           rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
  470           recycle();
  471           input = null;
  472           output = null;
  473           
  474       }
  475   
  476   
  477       // ----------------------------------------------------- ActionHook Methods
  478   
  479   
  480       /**
  481        * Send an action to the connector.
  482        *
  483        * @param actionCode Type of the action
  484        * @param param Action parameter
  485        */
  486       public void action(ActionCode actionCode, Object param) {
  487   
  488           if (actionCode == ActionCode.ACTION_COMMIT) {
  489   
  490               if (response.isCommitted())
  491                   return;
  492   
  493               // Validate and write response headers
  494               try {
  495                   prepareResponse();
  496               } catch (IOException e) {
  497                   // Set error flag
  498                   error = true;
  499               }
  500   
  501           } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
  502   
  503               if (!response.isCommitted()) {
  504                   // Validate and write response headers
  505                   try {
  506                       prepareResponse();
  507                   } catch (IOException e) {
  508                       // Set error flag
  509                       error = true;
  510                       return;
  511                   }
  512               }
  513   
  514               try {
  515                   flush();
  516               } catch (IOException e) {
  517                   // Set error flag
  518                   error = true;
  519               }
  520   
  521           } else if (actionCode == ActionCode.ACTION_CLOSE) {
  522               // Close
  523   
  524               // End the processing of the current request, and stop any further
  525               // transactions with the client
  526   
  527               try {
  528                   finish();
  529               } catch (IOException e) {
  530                   // Set error flag
  531                   error = true;
  532               }
  533   
  534           } else if (actionCode == ActionCode.ACTION_START) {
  535   
  536               started = true;
  537   
  538           } else if (actionCode == ActionCode.ACTION_STOP) {
  539   
  540               started = false;
  541   
  542           } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
  543   
  544               if (!certificates.isNull()) {
  545                   ByteChunk certData = certificates.getByteChunk();
  546                   X509Certificate jsseCerts[] = null;
  547                   ByteArrayInputStream bais =
  548                       new ByteArrayInputStream(certData.getBytes(),
  549                               certData.getStart(),
  550                               certData.getLength());
  551                   // Fill the first element.
  552                   try {
  553                       CertificateFactory cf =
  554                           CertificateFactory.getInstance("X.509");
  555                       X509Certificate cert = (X509Certificate)
  556                       cf.generateCertificate(bais);
  557                       jsseCerts = new X509Certificate[1];
  558                       jsseCerts[0] = cert;
  559                       request.setAttribute(JIoEndpoint.CERTIFICATE_KEY, jsseCerts);
  560                   } catch (java.security.cert.CertificateException e) {
  561                       log.error(sm.getString("ajpprocessor.certs.fail"), e);
  562                       return;
  563                   }
  564               }
  565   
  566           } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
  567   
  568               // Get remote host name using a DNS resolution
  569               if (request.remoteHost().isNull()) {
  570                   try {
  571                       request.remoteHost().setString(InetAddress.getByName
  572                               (request.remoteAddr().toString()).getHostName());
  573                   } catch (IOException iex) {
  574                       // Ignore
  575                   }
  576               }
  577   
  578           } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
  579   
  580               // Copy from local name for now, which should simply be an address
  581               request.localAddr().setString(request.localName().toString());
  582   
  583           } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
  584   
  585               // Set the given bytes as the content
  586               ByteChunk bc = (ByteChunk) param;
  587               int length = bc.getLength();
  588               bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length);
  589               request.setContentLength(length);
  590               first = false;
  591               empty = false;
  592               replay = true;
  593   
  594           }
  595   
  596   
  597       }
  598   
  599   
  600       // ------------------------------------------------------ Connector Methods
  601   
  602   
  603       /**
  604        * Set the associated adapter.
  605        *
  606        * @param adapter the new adapter
  607        */
  608       public void setAdapter(Adapter adapter) {
  609           this.adapter = adapter;
  610       }
  611   
  612   
  613       /**
  614        * Get the associated adapter.
  615        *
  616        * @return the associated adapter
  617        */
  618       public Adapter getAdapter() {
  619           return adapter;
  620       }
  621   
  622   
  623       // ------------------------------------------------------ Protected Methods
  624   
  625   
  626       /**
  627        * After reading the request headers, we have to setup the request filters.
  628        */
  629       protected void prepareRequest() {
  630   
  631           // Translate the HTTP method code to a String.
  632           byte methodCode = requestHeaderMessage.getByte();
  633           if (methodCode != Constants.SC_M_JK_STORED) {
  634               String methodName = Constants.methodTransArray[(int)methodCode - 1];
  635               request.method().setString(methodName);
  636           }
  637   
  638           requestHeaderMessage.getBytes(request.protocol());
  639           requestHeaderMessage.getBytes(request.requestURI());
  640   
  641           requestHeaderMessage.getBytes(request.remoteAddr());
  642           requestHeaderMessage.getBytes(request.remoteHost());
  643           requestHeaderMessage.getBytes(request.localName());
  644           request.setLocalPort(requestHeaderMessage.getInt());
  645   
  646           boolean isSSL = requestHeaderMessage.getByte() != 0;
  647           if (isSSL) {
  648               request.scheme().setString("https");
  649           }
  650   
  651           // Decode headers
  652           MimeHeaders headers = request.getMimeHeaders();
  653   
  654           int hCount = requestHeaderMessage.getInt();
  655           for(int i = 0 ; i < hCount ; i++) {
  656               String hName = null;
  657   
  658               // Header names are encoded as either an integer code starting
  659               // with 0xA0, or as a normal string (in which case the first
  660               // two bytes are the length).
  661               int isc = requestHeaderMessage.peekInt();
  662               int hId = isc & 0xFF;
  663   
  664               MessageBytes vMB = null;
  665               isc &= 0xFF00;
  666               if(0xA000 == isc) {
  667                   requestHeaderMessage.getInt(); // To advance the read position
  668                   hName = Constants.headerTransArray[hId - 1];
  669                   vMB = headers.addValue(hName);
  670               } else {
  671                   // reset hId -- if the header currently being read
  672                   // happens to be 7 or 8 bytes long, the code below
  673                   // will think it's the content-type header or the
  674                   // content-length header - SC_REQ_CONTENT_TYPE=7,
  675                   // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
  676                   // behaviour.  see bug 5861 for more information.
  677                   hId = -1;
  678                   requestHeaderMessage.getBytes(tmpMB);
  679                   ByteChunk bc = tmpMB.getByteChunk();
  680                   vMB = headers.addValue(bc.getBuffer(),
  681                           bc.getStart(), bc.getLength());
  682               }
  683   
  684               requestHeaderMessage.getBytes(vMB);
  685   
  686               if (hId == Constants.SC_REQ_CONTENT_LENGTH ||
  687                       (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
  688                   // just read the content-length header, so set it
  689                   long cl = vMB.getLong();
  690                   if(cl < Integer.MAX_VALUE)
  691                       request.setContentLength( (int)cl );
  692               } else if (hId == Constants.SC_REQ_CONTENT_TYPE ||
  693                       (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
  694                   // just read the content-type header, so set it
  695                   ByteChunk bchunk = vMB.getByteChunk();
  696                   request.contentType().setBytes(bchunk.getBytes(),
  697                           bchunk.getOffset(),
  698                           bchunk.getLength());
  699               }
  700           }
  701   
  702           // Decode extra attributes
  703           boolean secret = false;
  704           byte attributeCode;
  705           while ((attributeCode = requestHeaderMessage.getByte())
  706                   != Constants.SC_A_ARE_DONE) {
  707   
  708               switch (attributeCode) {
  709   
  710               case Constants.SC_A_REQ_ATTRIBUTE :
  711                   requestHeaderMessage.getBytes(tmpMB);
  712                   String n = tmpMB.toString();
  713                   requestHeaderMessage.getBytes(tmpMB);
  714                   String v = tmpMB.toString();
  715                   request.setAttribute(n, v);
  716                   break;
  717   
  718               case Constants.SC_A_CONTEXT :
  719                   requestHeaderMessage.getBytes(tmpMB);
  720                   // nothing
  721                   break;
  722   
  723               case Constants.SC_A_SERVLET_PATH :
  724                   requestHeaderMessage.getBytes(tmpMB);
  725                   // nothing
  726                   break;
  727   
  728               case Constants.SC_A_REMOTE_USER :
  729                   if (tomcatAuthentication) {
  730                       // ignore server
  731                       requestHeaderMessage.getBytes(tmpMB);
  732                   } else {
  733                       requestHeaderMessage.getBytes(request.getRemoteUser());
  734                   }
  735                   break;
  736   
  737               case Constants.SC_A_AUTH_TYPE :
  738                   if (tomcatAuthentication) {
  739                       // ignore server
  740                       requestHeaderMessage.getBytes(tmpMB);
  741                   } else {
  742                       requestHeaderMessage.getBytes(request.getAuthType());
  743                   }
  744                   break;
  745   
  746               case Constants.SC_A_QUERY_STRING :
  747                   requestHeaderMessage.getBytes(request.queryString());
  748                   break;
  749   
  750               case Constants.SC_A_JVM_ROUTE :
  751                   requestHeaderMessage.getBytes(request.instanceId());
  752                   break;
  753   
  754               case Constants.SC_A_SSL_CERT :
  755                   request.scheme().setString("https");
  756                   // SSL certificate extraction is lazy, moved to JkCoyoteHandler
  757                   requestHeaderMessage.getBytes(certificates);
  758                   break;
  759   
  760               case Constants.SC_A_SSL_CIPHER :
  761                   request.scheme().setString("https");
  762                   requestHeaderMessage.getBytes(tmpMB);
  763                   request.setAttribute(JIoEndpoint.CIPHER_SUITE_KEY,
  764                                        tmpMB.toString());
  765                   break;
  766   
  767               case Constants.SC_A_SSL_SESSION :
  768                   request.scheme().setString("https");
  769                   requestHeaderMessage.getBytes(tmpMB);
  770                   request.setAttribute(JIoEndpoint.SESSION_ID_KEY,
  771                                        tmpMB.toString());
  772                   break;
  773   
  774               case Constants.SC_A_SSL_KEY_SIZE :
  775                   request.setAttribute(JIoEndpoint.KEY_SIZE_KEY,
  776                                        new Integer(requestHeaderMessage.getInt()));
  777                   break;
  778   
  779               case Constants.SC_A_STORED_METHOD:
  780                   requestHeaderMessage.getBytes(request.method());
  781                   break;
  782   
  783               case Constants.SC_A_SECRET:
  784                   requestHeaderMessage.getBytes(tmpMB);
  785                   if (requiredSecret != null) {
  786                       secret = true;
  787                       if (!tmpMB.equals(requiredSecret)) {
  788                           response.setStatus(403);
  789                           error = true;
  790                       }
  791                   }
  792                   break;
  793   
  794               default:
  795                   // Ignore unknown attribute for backward compatibility
  796                   break;
  797   
  798               }
  799   
  800           }
  801   
  802           // Check if secret was submitted if required
  803           if ((requiredSecret != null) && !secret) {
  804               response.setStatus(403);
  805               error = true;
  806           }
  807   
  808           // Check for a full URI (including protocol://host:port/)
  809           ByteChunk uriBC = request.requestURI().getByteChunk();
  810           if (uriBC.startsWithIgnoreCase("http", 0)) {
  811   
  812               int pos = uriBC.indexOf("://", 0, 3, 4);
  813               int uriBCStart = uriBC.getStart();
  814               int slashPos = -1;
  815               if (pos != -1) {
  816                   byte[] uriB = uriBC.getBytes();
  817                   slashPos = uriBC.indexOf('/', pos + 3);
  818                   if (slashPos == -1) {
  819                       slashPos = uriBC.getLength();
  820                       // Set URI as "/"
  821                       request.requestURI().setBytes
  822                           (uriB, uriBCStart + pos + 1, 1);
  823                   } else {
  824                       request.requestURI().setBytes
  825                           (uriB, uriBCStart + slashPos,
  826                            uriBC.getLength() - slashPos);
  827                   }
  828                   MessageBytes hostMB = headers.setValue("host");
  829                   hostMB.setBytes(uriB, uriBCStart + pos + 3,
  830                                   slashPos - pos - 3);
  831               }
  832   
  833           }
  834   
  835           MessageBytes valueMB = request.getMimeHeaders().getValue("host");
  836           parseHost(valueMB);
  837   
  838       }
  839   
  840   
  841       /**
  842        * Parse host.
  843        */
  844       public void parseHost(MessageBytes valueMB) {
  845   
  846           if (valueMB == null || (valueMB != null && valueMB.isNull()) ) {
  847               // HTTP/1.0
  848               // Default is what the socket tells us. Overriden if a host is
  849               // found/parsed
  850               request.setServerPort(endpoint.getPort());
  851               return;
  852           }
  853   
  854           ByteChunk valueBC = valueMB.getByteChunk();
  855           byte[] valueB = valueBC.getBytes();
  856           int valueL = valueBC.getLength();
  857           int valueS = valueBC.getStart();
  858           int colonPos = -1;
  859           if (hostNameC.length < valueL) {
  860               hostNameC = new char[valueL];
  861           }
  862   
  863           boolean ipv6 = (valueB[valueS] == '[');
  864           boolean bracketClosed = false;
  865           for (int i = 0; i < valueL; i++) {
  866               char b = (char) valueB[i + valueS];
  867               hostNameC[i] = b;
  868               if (b == ']') {
  869                   bracketClosed = true;
  870               } else if (b == ':') {
  871                   if (!ipv6 || bracketClosed) {
  872                       colonPos = i;
  873                       break;
  874                   }
  875               }
  876           }
  877   
  878           if (colonPos < 0) {
  879               if (request.scheme().equalsIgnoreCase("https")) {
  880                   // 443 - Default HTTPS port
  881                   request.setServerPort(443);
  882               } else {
  883                   // 80 - Default HTTTP port
  884                   request.setServerPort(80);
  885               }
  886               request.serverName().setChars(hostNameC, 0, valueL);
  887           } else {
  888   
  889               request.serverName().setChars(hostNameC, 0, colonPos);
  890   
  891               int port = 0;
  892               int mult = 1;
  893               for (int i = valueL - 1; i > colonPos; i--) {
  894                   int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
  895                   if (charValue == -1) {
  896                       // Invalid character
  897                       error = true;
  898                       // 400 - Bad request
  899                       response.setStatus(400);
  900                       break;
  901                   }
  902                   port = port + (charValue * mult);
  903                   mult = 10 * mult;
  904               }
  905               request.setServerPort(port);
  906   
  907           }
  908   
  909       }
  910   
  911   
  912       /**
  913        * When committing the response, we have to validate the set of headers, as
  914        * well as setup the response filters.
  915        */
  916       protected void prepareResponse()
  917           throws IOException {
  918   
  919           response.setCommitted(true);
  920   
  921           responseHeaderMessage.reset();
  922           responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS);
  923   
  924           // HTTP header contents
  925           responseHeaderMessage.appendInt(response.getStatus());
  926           String message = response.getMessage();
  927           if (message == null){
  928               message = HttpMessages.getMessage(response.getStatus());
  929           } else {
  930               message = message.replace('\n', ' ').replace('\r', ' ');
  931           }
  932           tmpMB.setString(message);
  933           responseHeaderMessage.appendBytes(tmpMB);
  934   
  935           // Special headers
  936           MimeHeaders headers = response.getMimeHeaders();
  937           String contentType = response.getContentType();
  938           if (contentType != null) {
  939               headers.setValue("Content-Type").setString(contentType);
  940           }
  941           String contentLanguage = response.getContentLanguage();
  942           if (contentLanguage != null) {
  943               headers.setValue("Content-Language").setString(contentLanguage);
  944           }
  945           long contentLength = response.getContentLengthLong();
  946           if (contentLength >= 0) {
  947               headers.setValue("Content-Length").setLong(contentLength);
  948           }
  949   
  950           // Other headers
  951           int numHeaders = headers.size();
  952           responseHeaderMessage.appendInt(numHeaders);
  953           for (int i = 0; i < numHeaders; i++) {
  954               MessageBytes hN = headers.getName(i);
  955               int hC = Constants.getResponseAjpIndex(hN.toString());
  956               if (hC > 0) {
  957                   responseHeaderMessage.appendInt(hC);
  958               }
  959               else {
  960                   responseHeaderMessage.appendBytes(hN);
  961               }
  962               MessageBytes hV=headers.getValue(i);
  963               responseHeaderMessage.appendBytes(hV);
  964           }
  965   
  966           // Write to buffer
  967           responseHeaderMessage.end();
  968           output.write(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen());
  969   
  970       }
  971   
  972   
  973       /**
  974        * Finish AJP response.
  975        */
  976       protected void finish()
  977           throws IOException {
  978   
  979           if (!response.isCommitted()) {
  980               // Validate and write response headers
  981               try {
  982                   prepareResponse();
  983               } catch (IOException e) {
  984                   // Set error flag
  985                   error = true;
  986               }
  987           }
  988   
  989           if (finished)
  990               return;
  991   
  992           finished = true;
  993   
  994           // Add the end message
  995           output.write(endMessageArray);
  996   
  997       }
  998   
  999   
 1000       /**
 1001        * Read at least the specified amount of bytes, and place them
 1002        * in the input buffer.
 1003        */
 1004       protected boolean read(byte[] buf, int pos, int n)
 1005           throws IOException {
 1006   
 1007           int read = 0;
 1008           int res = 0;
 1009           while (read < n) {
 1010               res = input.read(buf, read + pos, n - read);
 1011               if (res > 0) {
 1012                   read += res;
 1013               } else {
 1014                   throw new IOException(sm.getString("ajpprotocol.failedread"));
 1015               }
 1016           }
 1017           
 1018           return true;
 1019   
 1020       }
 1021   
 1022   
 1023       /** Receive a chunk of data. Called to implement the
 1024        *  'special' packet in ajp13 and to receive the data
 1025        *  after we send a GET_BODY packet
 1026        */
 1027       public boolean receive() throws IOException {
 1028   
 1029           first = false;
 1030           bodyMessage.reset();
 1031           readMessage(bodyMessage);
 1032   
 1033           // No data received.
 1034           if (bodyMessage.getLen() == 0) {
 1035               // just the header
 1036               // Don't mark 'end of stream' for the first chunk.
 1037               return false;
 1038           }
 1039           int blen = bodyMessage.peekInt();
 1040           if (blen == 0) {
 1041               return false;
 1042           }
 1043   
 1044           bodyMessage.getBytes(bodyBytes);
 1045           empty = false;
 1046           return true;
 1047       }
 1048   
 1049       /**
 1050        * Get more request body data from the web server and store it in the
 1051        * internal buffer.
 1052        *
 1053        * @return true if there is more data, false if not.
 1054        */
 1055       private boolean refillReadBuffer() throws IOException {
 1056           // If the server returns an empty packet, assume that that end of
 1057           // the stream has been reached (yuck -- fix protocol??).
 1058           // FORM support
 1059           if (replay) {
 1060               endOfStream = true; // we've read everything there is
 1061           }
 1062           if (endOfStream) {
 1063               return false;
 1064           }
 1065   
 1066           // Request more data immediately
 1067           output.write(getBodyMessageArray);
 1068   
 1069           boolean moreData = receive();
 1070           if( !moreData ) {
 1071               endOfStream = true;
 1072           }
 1073           return moreData;
 1074       }
 1075   
 1076   
 1077       /**
 1078        * Read an AJP message.
 1079        *
 1080        * @return true if the message has been read, false if the short read
 1081        *         didn't return anything
 1082        * @throws IOException any other failure, including incomplete reads
 1083        */
 1084       protected boolean readMessage(AjpMessage message)
 1085           throws IOException {
 1086   
 1087           byte[] buf = message.getBuffer();
 1088   
 1089           read(buf, 0, message.getHeaderLength());
 1090   
 1091           message.processHeader();
 1092           read(buf, message.getHeaderLength(), message.getLen());
 1093   
 1094           return true;
 1095   
 1096       }
 1097   
 1098   
 1099       /**
 1100        * Recycle the processor.
 1101        */
 1102       public void recycle() {
 1103   
 1104           // Recycle Request object
 1105           first = true;
 1106           endOfStream = false;
 1107           empty = true;
 1108           replay = false;
 1109           finished = false;
 1110           request.recycle();
 1111           response.recycle();
 1112           certificates.recycle();
 1113   
 1114       }
 1115   
 1116   
 1117       /**
 1118        * Callback to write data from the buffer.
 1119        */
 1120       protected void flush()
 1121           throws IOException {
 1122           // Send the flush message
 1123           output.write(flushMessageArray);
 1124       }
 1125   
 1126   
 1127       // ------------------------------------- InputStreamInputBuffer Inner Class
 1128   
 1129   
 1130       /**
 1131        * This class is an input buffer which will read its data from an input
 1132        * stream.
 1133        */
 1134       protected class SocketInputBuffer
 1135           implements InputBuffer {
 1136   
 1137   
 1138           /**
 1139            * Read bytes into the specified chunk.
 1140            */
 1141           public int doRead(ByteChunk chunk, Request req )
 1142               throws IOException {
 1143   
 1144               if (endOfStream) {
 1145                   return -1;
 1146               }
 1147               if (first && req.getContentLengthLong() > 0) {
 1148                   // Handle special first-body-chunk
 1149                   if (!receive()) {
 1150                       return 0;
 1151                   }
 1152               } else if (empty) {
 1153                   if (!refillReadBuffer()) {
 1154                       return -1;
 1155                   }
 1156               }
 1157               ByteChunk bc = bodyBytes.getByteChunk();
 1158               chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength());
 1159               empty = true;
 1160               return chunk.getLength();
 1161   
 1162           }
 1163   
 1164       }
 1165   
 1166   
 1167       // ----------------------------------- OutputStreamOutputBuffer Inner Class
 1168   
 1169   
 1170       /**
 1171        * This class is an output buffer which will write data to an output
 1172        * stream.
 1173        */
 1174       protected class SocketOutputBuffer
 1175           implements OutputBuffer {
 1176   
 1177   
 1178           /**
 1179            * Write chunk.
 1180            */
 1181           public int doWrite(ByteChunk chunk, Response res)
 1182               throws IOException {
 1183   
 1184               if (!response.isCommitted()) {
 1185                   // Validate and write response headers
 1186                   try {
 1187                       prepareResponse();
 1188                   } catch (IOException e) {
 1189                       // Set error flag
 1190                       error = true;
 1191                   }
 1192               }
 1193   
 1194               int len = chunk.getLength();
 1195               // 4 - hardcoded, byte[] marshalling overhead
 1196               int chunkSize = Constants.MAX_SEND_SIZE;
 1197               int off = 0;
 1198               while (len > 0) {
 1199                   int thisTime = len;
 1200                   if (thisTime > chunkSize) {
 1201                       thisTime = chunkSize;
 1202                   }
 1203                   len -= thisTime;
 1204                   responseHeaderMessage.reset();
 1205                   responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
 1206                   responseHeaderMessage.appendBytes(chunk.getBytes(), chunk.getOffset() + off, thisTime);
 1207                   responseHeaderMessage.end();
 1208                   output.write(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen());
 1209   
 1210                   off += thisTime;
 1211               }
 1212   
 1213               return chunk.getLength();
 1214   
 1215           }
 1216   
 1217   
 1218       }
 1219   
 1220   
 1221   }

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