1 16 17 package org.apache.jk.server; 18 19 import java.io.ByteArrayInputStream ; 20 import java.io.IOException ; 21 import java.net.InetAddress ; 22 import java.security.cert.CertificateFactory ; 23 import java.security.cert.X509Certificate ; 24 import java.security.PrivilegedExceptionAction ; 25 import java.security.AccessController ; 26 import java.security.PrivilegedActionException ; 27 import java.security.PrivilegedAction ; 28 import java.util.Iterator ; 29 30 import javax.management.MBeanServer ; 31 import javax.management.ObjectName ; 32 33 import org.apache.commons.modeler.Registry; 34 import org.apache.coyote.ActionCode; 35 import org.apache.coyote.ActionHook; 36 import org.apache.coyote.Adapter; 37 import org.apache.coyote.ProtocolHandler; 38 import org.apache.coyote.Request; 39 import org.apache.coyote.Response; 40 import org.apache.coyote.RequestInfo; 41 import org.apache.coyote.Constants; 42 import org.apache.jk.common.HandlerRequest; 43 import org.apache.jk.common.JkInputStream; 44 import org.apache.jk.common.MsgAjp; 45 import org.apache.jk.core.JkHandler; 46 import org.apache.jk.core.Msg; 47 import org.apache.jk.core.MsgContext; 48 import org.apache.jk.core.WorkerEnv; 49 import org.apache.tomcat.util.buf.ByteChunk; 50 import org.apache.tomcat.util.buf.C2BConverter; 51 import org.apache.tomcat.util.buf.MessageBytes; 52 import org.apache.tomcat.util.http.HttpMessages; 53 import org.apache.tomcat.util.http.MimeHeaders; 54 import org.apache.tomcat.util.net.SSLSupport; 55 56 61 public class JkCoyoteHandler extends JkHandler implements 62 ProtocolHandler, 63 ActionHook, 64 org.apache.coyote.OutputBuffer, 65 org.apache.coyote.InputBuffer 66 { 67 protected static org.apache.commons.logging.Log log 68 = org.apache.commons.logging.LogFactory.getLog(JkCoyoteHandler.class); 69 private static org.apache.commons.logging.Log logTime= 71 org.apache.commons.logging.LogFactory.getLog( "org.apache.jk.REQ_TIME" ); 72 73 private final class StatusLinePrivilegedAction implements PrivilegedAction { 75 int status; 76 StatusLinePrivilegedAction(int status) { 77 this.status = status; 78 } 79 public Object run() { 80 return HttpMessages.getMessage(status); 81 } 82 } 83 84 int headersMsgNote; 85 int c2bConvertersNote; 86 int tmpMessageBytesNote; 87 int utfC2bNote; 88 int obNote; 89 int epNote; 90 int inputStreamNote; 91 private boolean paused = false; 92 93 Adapter adapter; 94 protected JkMain jkMain=null; 95 96 public final int JK_STATUS_NEW=0; 97 public final int JK_STATUS_HEAD=1; 98 public final int JK_STATUS_CLOSED=2; 99 public final int JK_STATUS_ERROR=3; 100 101 104 public void setProperty( String name, String value ) { 105 if( log.isTraceEnabled()) 106 log.trace("setProperty " + name + " " + value ); 107 getJkMain().setProperty( name, value ); 108 properties.put( name, value ); 109 } 110 111 public String getProperty( String name ) { 112 return properties.getProperty(name) ; 113 } 114 115 public Iterator getAttributeNames() { 116 return properties.keySet().iterator(); 117 } 118 119 121 public void setAttribute( String name, Object value ) { 122 if( log.isDebugEnabled()) 123 log.debug("setAttribute " + name + " " + value ); 124 if( value instanceof String ) 125 this.setProperty( name, (String )value ); 126 } 127 128 132 public Object getAttribute( String name ) { 133 return getJkMain().getProperty(name); 134 } 135 136 138 public void setAdapter(Adapter adapter) { 139 this.adapter=adapter; 140 } 141 142 public Adapter getAdapter() { 143 return adapter; 144 } 145 146 public JkMain getJkMain() { 147 if( jkMain == null ) { 148 jkMain=new JkMain(); 149 jkMain.setWorkerEnv(wEnv); 150 151 } 152 return jkMain; 153 } 154 155 boolean started=false; 156 157 159 public void init() { 160 if( started ) return; 161 162 started=true; 163 164 if( wEnv==null ) { 165 wEnv=getJkMain().getWorkerEnv(); 167 wEnv.addHandler("container", this ); 168 } 169 170 try { 171 173 getJkMain().init(); 174 175 headersMsgNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "headerMsg" ); 176 tmpMessageBytesNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "tmpMessageBytes" ); 177 utfC2bNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "utfC2B" ); 178 epNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "ep" ); 179 obNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "coyoteBuffer" ); 180 inputStreamNote= wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, 181 "jkInputStream"); 182 183 } catch( Exception ex ) { 184 log.error("Error during init",ex); 185 } 186 } 187 188 public void start() { 189 try { 190 if( oname != null && getJkMain().getDomain() == null) { 191 try { 192 ObjectName jkmainOname = 193 new ObjectName (oname.getDomain() + ":type=JkMain"); 194 Registry.getRegistry(null, null) 195 .registerComponent(getJkMain(), jkmainOname, "JkMain"); 196 } catch (Exception e) { 197 log.error( "Error registering jkmain " + e ); 198 } 199 } 200 getJkMain().start(); 201 } catch( Exception ex ) { 202 log.error("Error during startup",ex); 203 } 204 } 205 206 public void pause() throws Exception { 207 if(!paused) { 208 paused = true; 209 getJkMain().pause(); 210 } 211 } 212 213 public void resume() throws Exception { 214 if(paused) { 215 paused = false; 216 getJkMain().resume(); 217 } 218 } 219 220 public void destroy() { 221 if( !started ) return; 222 223 started = false; 224 getJkMain().stop(); 225 } 226 227 229 230 public int doWrite(ByteChunk chunk, Response res) 231 throws IOException 232 { 233 if (!res.isCommitted()) { 234 res.sendHeaders(); 238 } 239 MsgContext ep=(MsgContext)res.getNote( epNote ); 240 241 MsgAjp msg=(MsgAjp)ep.getNote( headersMsgNote ); 242 243 int len=chunk.getLength(); 244 byte buf[]=msg.getBuffer(); 245 int chunkSize=buf.length - msg.getHeaderLength() - 4; 247 int off=0; 248 while( len > 0 ) { 249 int thisTime=len; 250 if( thisTime > chunkSize ) { 251 thisTime=chunkSize; 252 } 253 len-=thisTime; 254 255 msg.reset(); 256 msg.appendByte( HandlerRequest.JK_AJP13_SEND_BODY_CHUNK); 257 if( log.isDebugEnabled() ) log.debug("doWrite " + off + " " + thisTime + " " + len ); 258 msg.appendBytes( chunk.getBytes(), chunk.getOffset() + off, thisTime ); 259 off+=thisTime; 260 ep.setType( JkHandler.HANDLE_SEND_PACKET ); 261 ep.getSource().send( msg, ep ); 262 } 263 return 0; 264 } 265 266 public int doRead(ByteChunk chunk, Request req) 267 throws IOException 268 { 269 Response res=req.getResponse(); 270 if( log.isDebugEnabled() ) 271 log.debug("doRead " + chunk.getBytes() + " " + chunk.getOffset() + " " + chunk.getLength()); 272 MsgContext ep=(MsgContext)res.getNote( epNote ); 273 274 JkInputStream jkIS=(JkInputStream)ep.getNote( inputStreamNote ); 275 return jkIS.doRead( chunk ); 277 } 278 279 public int invoke( Msg msg, MsgContext ep ) 282 throws IOException 283 { 284 if( logTime.isDebugEnabled() ) 285 ep.setLong( MsgContext.TIMER_PRE_REQUEST, System.currentTimeMillis()); 286 287 org.apache.coyote.Request req=(org.apache.coyote.Request)ep.getRequest(); 288 org.apache.coyote.Response res=req.getResponse(); 289 res.setHook( this ); 290 291 if( log.isDebugEnabled() ) 292 log.debug( "Invoke " + req + " " + res + " " + req.requestURI().toString()); 293 294 res.setOutputBuffer( this ); 295 req.setInputBuffer( this ); 296 297 if( ep.getNote( headersMsgNote ) == null ) { 298 Msg msg2=new MsgAjp(); 299 ep.setNote( headersMsgNote, msg2 ); 300 } 301 302 res.setNote( epNote, ep ); 303 ep.setStatus( JK_STATUS_HEAD ); 304 RequestInfo rp = req.getRequestProcessor(); 305 rp.setStage(Constants.STAGE_SERVICE); 306 try { 307 adapter.service( req, res ); 308 } catch( Exception ex ) { 309 log.info("Error servicing request " + req,ex); 310 } 311 if(ep.getStatus() != JK_STATUS_CLOSED) { 312 res.finish(); 313 } 314 315 req.recycle(); 316 req.updateCounters(); 317 res.recycle(); 318 if( ep.getStatus() == JK_STATUS_ERROR ) { 319 return ERROR; 320 } 321 ep.setStatus( JK_STATUS_NEW ); 322 rp.setStage(Constants.STAGE_KEEPALIVE); 323 return OK; 324 } 325 326 private void appendHead(org.apache.coyote.Response res) 327 throws IOException 328 { 329 if( log.isDebugEnabled() ) 330 log.debug("COMMIT sending headers " + res + " " + res.getMimeHeaders() ); 331 332 C2BConverter c2b=(C2BConverter)res.getNote( utfC2bNote ); 333 if( c2b==null ) { 334 if(System.getSecurityManager() != null) { 335 try { 336 c2b = (C2BConverter) 337 AccessController.doPrivileged( 338 new PrivilegedExceptionAction () { 339 public Object run() 340 throws IOException { 341 return new C2BConverter( "iso-8859-1" ); 342 } 343 }); 344 } catch(PrivilegedActionException pae) { 345 Exception ex = pae.getException(); 346 if(ex instanceof IOException ) 347 throw (IOException )ex; 348 } 349 } else { 350 c2b=new C2BConverter( "iso-8859-1" ); 351 } 352 res.setNote( utfC2bNote, c2b ); 353 } 354 355 MsgContext ep=(MsgContext)res.getNote( epNote ); 356 MsgAjp msg=(MsgAjp)ep.getNote( headersMsgNote ); 357 msg.reset(); 358 msg.appendByte(HandlerRequest.JK_AJP13_SEND_HEADERS); 359 msg.appendInt( res.getStatus() ); 360 361 MessageBytes mb=(MessageBytes)ep.getNote( tmpMessageBytesNote ); 362 if( mb==null ) { 363 mb=MessageBytes.newInstance(); 364 ep.setNote( tmpMessageBytesNote, mb ); 365 } 366 String message=res.getMessage(); 367 if( message==null ){ 368 if( System.getSecurityManager() != null ) { 369 message = (String )AccessController.doPrivileged( 370 new StatusLinePrivilegedAction(res.getStatus())); 371 } else { 372 message= HttpMessages.getMessage(res.getStatus()); 373 } 374 } else { 375 message = message.replace('\n', ' ').replace('\r', ' '); 376 } 377 mb.setString( message ); 378 c2b.convert( mb ); 379 msg.appendBytes(mb); 380 381 383 MimeHeaders headers=res.getMimeHeaders(); 384 String contentType = res.getContentType(); 385 if( contentType != null ) { 386 headers.setValue("Content-Type").setString(contentType); 387 } 388 String contentLanguage = res.getContentLanguage(); 389 if( contentLanguage != null ) { 390 headers.setValue("Content-Language").setString(contentLanguage); 391 } 392 int contentLength = res.getContentLength(); 393 if( contentLength >= 0 ) { 394 headers.setValue("Content-Length").setInt(contentLength); 395 } 396 int numHeaders = headers.size(); 397 msg.appendInt(numHeaders); 398 for( int i=0; i<numHeaders; i++ ) { 399 MessageBytes hN=headers.getName(i); 400 c2b.convert ( hN ); 403 msg.appendBytes( hN ); 404 405 MessageBytes hV=headers.getValue(i); 406 c2b.convert( hV ); 407 msg.appendBytes( hV ); 408 } 409 ep.setType( JkHandler.HANDLE_SEND_PACKET ); 410 ep.getSource().send( msg, ep ); 411 } 412 413 415 public void action(ActionCode actionCode, Object param) { 416 if( actionCode==ActionCode.ACTION_COMMIT ) { 417 if( log.isDebugEnabled() ) log.debug("COMMIT " ); 418 org.apache.coyote.Response res=(org.apache.coyote.Response)param; 419 420 if( res.isCommitted() ) { 421 if( log.isInfoEnabled() ) 422 log.info("Response already committed " ); 423 } else { 424 try { 425 appendHead( res ); 426 } catch(IOException iex) { 427 log.warn("Unable to send headers",iex); 428 MsgContext ep=(MsgContext)res.getNote( epNote ); 429 ep.setStatus(JK_STATUS_ERROR); 430 } 431 } 432 } else if( actionCode==ActionCode.ACTION_RESET ) { 433 if( log.isDebugEnabled() ) 434 log.debug("RESET " ); 435 436 } else if( actionCode==ActionCode.ACTION_CLIENT_FLUSH ) { 437 if( log.isDebugEnabled() ) log.debug("CLIENT_FLUSH " ); 438 org.apache.coyote.Response res=(org.apache.coyote.Response)param; 439 MsgContext ep=(MsgContext)res.getNote( epNote ); 440 ep.setType( JkHandler.HANDLE_FLUSH ); 441 try { 442 ep.getSource().flush( null, ep ); 443 } catch(IOException iex) { 444 log.debug("Error during flush",iex); 446 res.setErrorException(iex); 447 ep.setStatus(JK_STATUS_ERROR); 448 } 449 450 } else if( actionCode==ActionCode.ACTION_CLOSE ) { 451 if( log.isDebugEnabled() ) log.debug("CLOSE " ); 452 453 org.apache.coyote.Response res=(org.apache.coyote.Response)param; 454 MsgContext ep=(MsgContext)res.getNote( epNote ); 455 if( ep.getStatus()== JK_STATUS_CLOSED ) { 456 if( log.isDebugEnabled() ) log.debug("Double CLOSE - forward ? " + res.getRequest().requestURI() ); 458 return; 459 } 460 461 if( !res.isCommitted() ) 462 this.action( ActionCode.ACTION_COMMIT, param ); 463 464 MsgAjp msg=(MsgAjp)ep.getNote( headersMsgNote ); 465 msg.reset(); 466 msg.appendByte( HandlerRequest.JK_AJP13_END_RESPONSE ); 467 msg.appendByte( 1 ); 468 469 try { 470 ep.setType( JkHandler.HANDLE_SEND_PACKET ); 471 ep.getSource().send( msg, ep ); 472 473 ep.setType( JkHandler.HANDLE_FLUSH ); 474 ep.getSource().flush( msg, ep ); 475 } catch(IOException iex) { 476 log.debug("Connection error ending request.",iex); 477 ep.setStatus(JK_STATUS_ERROR); 478 } 479 if(ep.getStatus() != JK_STATUS_ERROR) { 480 ep.setStatus(JK_STATUS_CLOSED ); 481 } 482 483 if( logTime.isDebugEnabled() ) 484 logTime(res.getRequest(), res); 485 } else if( actionCode==ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { 486 org.apache.coyote.Request req=(org.apache.coyote.Request)param; 487 488 MessageBytes certString = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE); 490 if( certString != null && !certString.isNull() ) { 491 ByteChunk certData = certString.getByteChunk(); 492 ByteArrayInputStream bais = 493 new ByteArrayInputStream (certData.getBytes(), 494 certData.getStart(), 495 certData.getLength()); 496 497 X509Certificate jsseCerts[] = null; 499 try { 500 CertificateFactory cf = 501 CertificateFactory.getInstance("X.509"); 502 X509Certificate cert = (X509Certificate ) 503 cf.generateCertificate(bais); 504 jsseCerts = new X509Certificate [1]; 505 jsseCerts[0] = cert; 506 } catch(java.security.cert.CertificateException e) { 507 log.error("Certificate convertion failed" , e ); 508 return; 509 } 510 511 req.setAttribute(SSLSupport.CERTIFICATE_KEY, 512 jsseCerts); 513 } 514 515 } else if( actionCode==ActionCode.ACTION_REQ_HOST_ATTRIBUTE ) { 516 org.apache.coyote.Request req=(org.apache.coyote.Request)param; 517 518 if( req.remoteHost().isNull()) { 520 try { 521 req.remoteHost().setString(InetAddress.getByName( 522 req.remoteAddr().toString()). 523 getHostName()); 524 } catch(IOException iex) { 525 if(log.isDebugEnabled()) 526 log.debug("Unable to resolve "+req.remoteAddr()); 527 } 528 } 529 531 } else if( actionCode==ActionCode.ACTION_ACK ) { 532 if( log.isDebugEnabled() ) 533 log.debug("ACK " ); 534 } 536 } 537 538 private void logTime(Request req, Response res ) { 539 MsgContext ep=(MsgContext)res.getNote( epNote ); 543 String uri=req.requestURI().toString(); 544 if( uri.indexOf( ".gif" ) >0 ) return; 545 546 ep.setLong( MsgContext.TIMER_POST_REQUEST, System.currentTimeMillis()); 547 long t1= ep.getLong( MsgContext.TIMER_PRE_REQUEST ) - 548 ep.getLong( MsgContext.TIMER_RECEIVED ); 549 long t2= ep.getLong( MsgContext.TIMER_POST_REQUEST ) - 550 ep.getLong( MsgContext.TIMER_PRE_REQUEST ); 551 552 logTime.debug("Time pre=" + t1 + "/ service=" + t2 + " " + 553 res.getContentLength() + " " + 554 uri ); 555 } 556 557 public ObjectName preRegister(MBeanServer server, 558 ObjectName oname) throws Exception 559 { 560 this.name="container"; 562 return super.preRegister(server, oname); 563 } 564 } 565 | Popular Tags |