Save This Page
Home » apache-tomcat-6.0.26-src » org.apache.jk » core » [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.jk.core;
   19   
   20   import java.io.IOException;
   21   import java.io.ByteArrayInputStream;
   22   import java.net.InetAddress;
   23   import java.security.cert.CertificateFactory;
   24   import java.security.cert.X509Certificate;
   25   
   26   import org.apache.coyote.ActionCode;
   27   import org.apache.coyote.ActionHook;
   28   import org.apache.coyote.Request;
   29   import org.apache.coyote.Response;
   30   
   31   import org.apache.tomcat.util.buf.C2BConverter;
   32   import org.apache.tomcat.util.buf.MessageBytes;
   33   import org.apache.tomcat.util.buf.ByteChunk;
   34   import org.apache.tomcat.util.net.SSLSupport;
   35   import org.apache.jk.common.JkInputStream;
   36   
   37   
   38   /**
   39    *
   40    * @author Henri Gomez [hgomez@apache.org]
   41    * @author Dan Milstein [danmil@shore.net]
   42    * @author Keith Wannamaker [Keith@Wannamaker.org]
   43    * @author Kevin Seguin
   44    * @author Costin Manolache
   45    */
   46   public class MsgContext implements ActionHook {
   47       private static org.apache.juli.logging.Log log =
   48           org.apache.juli.logging.LogFactory.getLog(MsgContext.class);
   49       private static org.apache.juli.logging.Log logTime=
   50           org.apache.juli.logging.LogFactory.getLog( "org.apache.jk.REQ_TIME" );
   51   
   52       private int type;
   53       private Object notes[]=new Object[32];
   54       private JkHandler next;
   55       private JkChannel source;
   56       private JkInputStream jkIS;
   57       private C2BConverter c2b;
   58       private Request req;
   59       private WorkerEnv wEnv;
   60       private Msg msgs[]=new Msg[10];
   61       private int status=0;
   62       // Control object
   63       private Object control;
   64   
   65       // Application managed, like notes
   66       private long timers[]=new long[20];
   67       
   68       // The context can be used by JNI components as well
   69       private long jkEndpointP;
   70       private long xEnvP;
   71   
   72       // Temp: use notes and dynamic strings
   73       public static final int TIMER_RECEIVED=0;
   74       public static final int TIMER_PRE_REQUEST=1;
   75       public static final int TIMER_POST_REQUEST=2;
   76   
   77       // Status codes
   78       public static final int JK_STATUS_NEW=0;
   79       public static final int JK_STATUS_HEAD=1;
   80       public static final int JK_STATUS_CLOSED=2;
   81       public static final int JK_STATUS_ERROR=3;
   82   
   83       public MsgContext(int bsize) {
   84           try {
   85               c2b = new C2BConverter("iso-8859-1");
   86           } catch(IOException iex) {
   87               log.warn("Can't happen", iex);
   88           }
   89           jkIS = new JkInputStream(this, bsize);
   90       }
   91       /**
   92        * @deprecated
   93        */
   94       public MsgContext() {
   95           this(8*1024);
   96       }
   97       
   98       public final Object getNote( int id ) {
   99           return notes[id];
  100       }
  101   
  102       public final void setNote( int id, Object o ) {
  103           notes[id]=o;
  104       }
  105   
  106       /** The id of the chain */
  107       public final int getType() {
  108           return type;
  109       }
  110   
  111       public final void setType(int i) {
  112           type=i;
  113       }
  114   
  115       public final void setLong( int i, long l) {
  116           timers[i]=l;
  117       }
  118       
  119       public final long getLong( int i) {
  120           return timers[i];
  121       }
  122       
  123       // Common attributes ( XXX should be notes for flexibility ? )
  124   
  125       public final WorkerEnv getWorkerEnv() {
  126           return wEnv;
  127       }
  128   
  129       public final void setWorkerEnv( WorkerEnv we ) {
  130           this.wEnv=we;
  131       }
  132       
  133       public final JkChannel getSource() {
  134           return source;
  135       }
  136       
  137       public final void setSource(JkChannel ch) {
  138           this.source=ch;
  139       }
  140   
  141       public final int getStatus() {
  142           return status;
  143       }
  144   
  145       public final void setStatus( int s ) {
  146           status=s;
  147       }
  148       
  149       public final JkHandler getNext() {
  150           return next;
  151       }
  152       
  153       public final void setNext(JkHandler ch) {
  154           this.next=ch;
  155       }
  156   
  157       /** The high level request object associated with this context
  158        */
  159       public final void setRequest( Request req ) {
  160           this.req=req;
  161           req.setInputBuffer(jkIS);
  162           Response res = req.getResponse();
  163           res.setOutputBuffer(jkIS);
  164           res.setHook(this);
  165       }
  166   
  167       public final Request getRequest() {
  168           return req;
  169       }
  170   
  171       /** The context may store a number of messages ( buffers + marshalling )
  172        */
  173       public final Msg getMsg(int i) {
  174           return msgs[i];
  175       }
  176   
  177       public final void setMsg(int i, Msg msg) {
  178           this.msgs[i]=msg;
  179       }
  180   
  181       public final C2BConverter getConverter() {
  182           return c2b;
  183       }
  184   
  185       public final void setConverter(C2BConverter c2b) {
  186           this.c2b = c2b;
  187       }
  188       
  189       public final boolean isLogTimeEnabled() {
  190           return logTime.isDebugEnabled();
  191       }
  192   
  193       public JkInputStream getInputStream() {
  194           return jkIS;
  195       }
  196   
  197       /** Each context contains a number of byte[] buffers used for communication.
  198        *  The C side will contain a char * equivalent - both buffers are long-lived
  199        *  and recycled.
  200        *
  201        *  This will be called at init time. A long-lived global reference to the byte[]
  202        *  will be stored in the C context.
  203        */
  204       public byte[] getBuffer( int id ) {
  205           // We use a single buffer right now. 
  206           if( msgs[id]==null ) {
  207               return null;
  208           }
  209           return msgs[id].getBuffer();
  210       }
  211   
  212       /** Invoke a java hook. The xEnv is the representation of the current execution
  213        *  environment ( the jni_env_t * )
  214        */
  215       public int execute() throws IOException {
  216           int status=next.invoke(msgs[0], this);
  217           return status;
  218       }
  219   
  220       // -------------------- Jni support --------------------
  221       
  222       /** Store native execution context data when this handler is called
  223        *  from JNI. This will change on each call, represent temproary
  224        *  call data.
  225        */
  226       public void setJniEnv( long xEnvP ) {
  227               this.xEnvP=xEnvP;
  228       }
  229   
  230       public long getJniEnv() {
  231           return xEnvP;
  232       }
  233       
  234       /** The long-lived JNI context associated with this java context.
  235        *  The 2 share pointers to buffers and cache data to avoid expensive
  236        *  jni calls.
  237        */
  238       public void setJniContext( long cContext ) {
  239           this.jkEndpointP=cContext;
  240       }
  241   
  242       public long getJniContext() {
  243           return jkEndpointP;
  244       }
  245   
  246       public Object getControl() {
  247           return control;
  248       }
  249   
  250       public void setControl(Object control) {
  251           this.control = control;
  252       }
  253   
  254       // -------------------- Coyote Action implementation --------------------
  255       
  256       public void action(ActionCode actionCode, Object param) {
  257           if( actionCode==ActionCode.ACTION_COMMIT ) {
  258               if( log.isDebugEnabled() ) log.debug("COMMIT " );
  259               Response res=(Response)param;
  260   
  261               if(  res.isCommitted() ) {
  262                   if( log.isDebugEnabled() )
  263                       log.debug("Response already committed " );
  264               } else {
  265                   try {
  266                       jkIS.appendHead( res );
  267                   } catch(IOException iex) {
  268                       log.warn("Unable to send headers",iex);
  269                       setStatus(JK_STATUS_ERROR);
  270                   }
  271               }
  272           } else if( actionCode==ActionCode.ACTION_RESET ) {
  273               if( log.isDebugEnabled() )
  274                   log.debug("RESET " );
  275               
  276           } else if( actionCode==ActionCode.ACTION_CLIENT_FLUSH ) {
  277               if( log.isDebugEnabled() ) log.debug("CLIENT_FLUSH " );
  278               Response res = (Response)param;
  279               if(!res.isCommitted()) {
  280                   action(ActionCode.ACTION_COMMIT, res);
  281               }
  282               try {
  283                   source.flush( null, this );
  284               } catch(IOException iex) {
  285                   // This is logged elsewhere, so debug only here
  286                   log.debug("Error during flush",iex);
  287                   res.setErrorException(iex);
  288                   setStatus(JK_STATUS_ERROR);
  289               }
  290               
  291           } else if( actionCode==ActionCode.ACTION_CLOSE ) {
  292               if( log.isDebugEnabled() ) log.debug("CLOSE " );
  293               
  294               Response res=(Response)param;
  295               if( getStatus()== JK_STATUS_CLOSED || getStatus() == JK_STATUS_ERROR) {
  296                   // Double close - it may happen with forward 
  297                   if( log.isDebugEnabled() ) log.debug("Double CLOSE - forward ? " + res.getRequest().requestURI() );
  298                   return;
  299               }
  300                    
  301               if( !res.isCommitted() )
  302                   this.action( ActionCode.ACTION_COMMIT, param );
  303               try {            
  304                   jkIS.endMessage();
  305               } catch(IOException iex) {
  306                   log.debug("Error sending end packet",iex);
  307                   setStatus(JK_STATUS_ERROR);
  308               }
  309               if(getStatus() != JK_STATUS_ERROR) {
  310                   setStatus(JK_STATUS_CLOSED );
  311               }
  312   
  313               if( logTime.isDebugEnabled() ) 
  314                   logTime(res.getRequest(), res);
  315           } else if( actionCode==ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
  316               Request req=(Request)param;
  317   
  318               // Extract SSL certificate information (if requested)
  319               MessageBytes certString = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE);
  320               if( certString != null && !certString.isNull() ) {
  321                   ByteChunk certData = certString.getByteChunk();
  322                   ByteArrayInputStream bais = 
  323                       new ByteArrayInputStream(certData.getBytes(),
  324                                                certData.getStart(),
  325                                                certData.getLength());
  326    
  327                   // Fill all elements.
  328                   X509Certificate jsseCerts[] = null;
  329                   try {
  330                       CertificateFactory cf =
  331                           CertificateFactory.getInstance("X.509");
  332                       int i = 0;
  333                       while (bais.available() > 0) {
  334                           X509Certificate cert = (X509Certificate)
  335                               cf.generateCertificate(bais);
  336                           if (jsseCerts == null) {
  337                               jsseCerts = new X509Certificate[1];
  338                           } else {
  339                               X509Certificate tmpJsseCerts[] =
  340                                   new X509Certificate[jsseCerts.length + 1];
  341                               System.arraycopy(jsseCerts, 0,
  342                                                tmpJsseCerts, 0,
  343                                                jsseCerts.length);
  344                               jsseCerts = tmpJsseCerts;
  345                           }
  346                           jsseCerts[i++] = cert;
  347                       }
  348                   } catch(java.security.cert.CertificateException e) {
  349                       log.error("Certificate convertion failed" , e );
  350                       return;
  351                   }
  352    
  353                   req.setAttribute(SSLSupport.CERTIFICATE_KEY, 
  354                                    jsseCerts);
  355               }
  356                   
  357           } else if( actionCode==ActionCode.ACTION_REQ_HOST_ATTRIBUTE ) {
  358               Request req=(Request)param;
  359   
  360               // If remoteHost not set by JK, get it's name from it's remoteAddr
  361               if( req.remoteHost().isNull()) {
  362                   try {
  363                       req.remoteHost().setString(InetAddress.getByName(
  364                                                  req.remoteAddr().toString()).
  365                                                  getHostName());
  366                   } catch(IOException iex) {
  367                       if(log.isDebugEnabled())
  368                           log.debug("Unable to resolve "+req.remoteAddr());
  369                   }
  370               }
  371           } else if( actionCode==ActionCode.ACTION_ACK ) {
  372               if( log.isTraceEnabled() )
  373                   log.trace("ACK " );
  374           } else if ( actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY ) {
  375               if( log.isTraceEnabled() )
  376                   log.trace("Replay ");
  377               ByteChunk bc = (ByteChunk)param;
  378               req.setContentLength(bc.getLength());
  379               jkIS.setReplay(bc);
  380           }
  381       }
  382       
  383   
  384       private void logTime(Request req, Response res ) {
  385           // called after the request
  386           //            org.apache.coyote.Request req=(org.apache.coyote.Request)param;
  387           //            Response res=req.getResponse();
  388           String uri=req.requestURI().toString();
  389           if( uri.indexOf( ".gif" ) >0 ) return;
  390           
  391           setLong( MsgContext.TIMER_POST_REQUEST, System.currentTimeMillis());
  392           long t1= getLong( MsgContext.TIMER_PRE_REQUEST ) -
  393               getLong( MsgContext.TIMER_RECEIVED );
  394           long t2= getLong( MsgContext.TIMER_POST_REQUEST ) -
  395               getLong( MsgContext.TIMER_PRE_REQUEST );
  396           
  397           logTime.debug("Time pre=" + t1 + "/ service=" + t2 + " " +
  398                         res.getContentLength() + " " + 
  399                         uri );
  400       }
  401   
  402       public void recycle() {
  403           jkIS.recycle();
  404       }
  405   }

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