|
What this is
Other links
The source code/* * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/server/Ajp13Interceptor.java,v 1.24 2004/02/25 07:18:35 billbarker Exp $ * $Revision: 1.24 $ * $Date: 2004/02/25 07:18:35 $ * * * Copyright 1999-2004 The Apache Sofware Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.tomcat.modules.server; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.util.Properties; import org.apache.tomcat.core.ContextManager; import org.apache.tomcat.core.Request; import org.apache.tomcat.core.Response; import org.apache.tomcat.core.TomcatException; import org.apache.tomcat.util.io.FileUtil; import org.apache.tomcat.util.log.Log; import org.apache.tomcat.util.net.TcpConnection; import org.apache.tomcat.util.net.TcpConnectionHandler; /* Frozen, bug fixes only: all active development goes in jakarta-tomcat-connectors/jk/org/apache/ajp/Ajp14* */ public class Ajp13Interceptor extends PoolTcpConnector implements TcpConnectionHandler { private boolean tomcatAuthentication=true; private boolean shutdownEnable=false; // true if the incloming uri is encoded. private boolean decoded=true; private int decodedNote; private String secret=null; private File ajpidFile=null; private boolean authenticateConnection=false; public Ajp13Interceptor() { super(); super.setSoLinger( 100 ); super.setTcpNoDelay( true ); } // -------------------- PoolTcpConnector -------------------- /** Enable shutdown command. By default it is disabled, since * ajp12 has an improved version with password checking. * * In future we'll enable shutdown in ajp13/14 and deprecate ajp12, * and merge various improvements from ajp12. * * Note that this you can use ajp13 for communication with the server * and ajp12 only for shutdown - that would allow some extra flexibility, * especially if you use firewall rules. */ public void setShutdownEnable(boolean b ) { shutdownEnable=b; } /** Legacy version */ public void setShutDownEnable(boolean b ) { shutdownEnable=b; } /** Enable the use of a secret. The secret will be * randomly generated. mod_jk must read the secret to * communicate with tomcat. * * Note that we don't use the secret only for shutdown, but * for normal request processing. A 'bad' request may forge * auth, etc. */ public void setUseSecret(boolean b ) { secret=Double.toString(Math.random()); shutdownEnable=true; } /** Set the 'secret'. If this is set, all sensitive operations * will be disabled unless the request includes a password. * * This requires a recent version of mod_jk and the * worker.NAME.secret property in workers.properties. */ public void setSecret( String s ) { secret=s; shutdownEnable=true; } /** Specify ajpid file used when shutting down tomcat */ public void setAjpidFile( String path ) { ajpidFile=( path==null?null:new File(path)); } /** Specify if Ajp13 requests must be authenticated */ public void setAuthenticateConnection( boolean b ) { authenticateConnection=b; } public void setDecodedUri( boolean b ) { decoded=b; } protected void localInit() throws Exception { ep.setConnectionHandler( this ); } public void engineInit( ContextManager cm ) throws TomcatException { super.engineInit( cm ); decodedNote=cm.getNoteId(ContextManager.REQUEST_NOTE, "req.decoded" ); String ajpid13 = cm.getProperty("ajpid13"); if( ajpid13 != null ) { if( ajpidFile != null ) { log( "Overriding ajpidFile with " + ajpid13 ); } ajpidFile = new File(ajpid13); } } public void engineState(ContextManager cm, int state ) throws TomcatException { if( state==ContextManager.STATE_START ) { // the engine is now started, create the ajp13.id // file that will allow us to stop the server and // know that the server is started ok. Ajp13Interceptor tcpCon=this; int portInt=tcpCon.getPort(); InetAddress address=tcpCon.getAddress(); File sf=FileUtil.getConfigFile(ajpidFile, new File(cm.getHome()), "conf/ajp13.id"); Properties props=new Properties(); if( ajpidFile != null || debug > 0) log( "Using stop file: "+sf); try { // PrintWriter stopF=new PrintWriter // (new FileWriter(sf)); FileOutputStream stopF=new FileOutputStream( sf ); props.put( "port", Integer.toString( portInt )); // stopF.println( portInt ); if( address==null ) { // stopF.println( "" ); } else { //stopF.println( address.getHostAddress() ); props.put( "address", address.getHostAddress() ); } if( secret !=null ) { //stopF.println( secret ); props.put( "secret", secret ); } else { // stopF.println(); } if( shutdownEnable ) props.put( "shutdown", "enabled" ); // stopF.close(); props.save( stopF, "Automatically generated, don't edit" ); } catch( IOException ex ) { log( "Can't create stop file: "+sf, ex ); } } } // -------------------- Handler implementation -------------------- public Object[] init() { Object thData[]=new Object[3]; Ajp13Request req=new Ajp13Request(); Ajp13Response res=new Ajp13Response(); Ajp13 con=new Ajp13(); con.setDebug(debug); req.setDebug(debug); con.setTomcatAuthentication(isTomcatAuthentication()); cm.initRequest(req, res); thData[0]=req; thData[1]=res; thData[2]=con; return thData; } // XXX // Nothing overriden, right now AJPRequest implment AJP and read // everything. // "Shortcuts" to be added here ( Vhost and context set by Apache, etc) // XXX handleEndpoint( Endpoint x ) public void processConnection(TcpConnection connection, Object thData[]) { try { if(connection == null) { return; } Socket socket = connection.getSocket(); if(socket == null) { return; } Ajp13 con=null; Ajp13Request req=null; Ajp13Response res=null; if(thData != null) { req = (Ajp13Request)thData[0]; res = (Ajp13Response)thData[1]; con = (Ajp13)thData[2]; if(req != null) req.recycle(); if(res != null) res.recycle(); if(con != null) con.recycle(); } if(req == null || res == null || con == null) { req = new Ajp13Request(); res = new Ajp13Response(); con = new Ajp13(); con.setTomcatAuthentication(isTomcatAuthentication()); cm.initRequest( req, res ); } // XXX req.ajp13=con; res.ajp13=con; con.setSocket(socket); boolean moreRequests = true; boolean authenticated = false; // If we are not configured with a secret or we are // not authenticating the connection, assume // we trust the remote party ( as we did before ) if( secret == null || !authenticateConnection ) authenticated=true; while(moreRequests) { int status=req.receiveNextRequest(); if( !authenticated ) { // we need to authenticate - the user set a // secret and expects the web server to send it String conSecret=con.getSecret(); if( conSecret == null ) { log("Unauthenticated server"); break; } if( ! secret.equals( conSecret )) { log("Bad server secret"); break; } // allow further requests without checking authenticated=true; } if( status==-2) { // check secret if set if( secret != null && ! secret.equals(con.getSecret())) { log("Shutdown command ignored. Secret didn't match."); continue; } // special case - shutdown // XXX need better communication, refactor it if( !doShutdown(con, socket.getLocalAddress(), socket.getInetAddress())) { moreRequests = false; continue; } } // special case - low level AJP13 packet, like // PING/PONG ... if( status == 999 ) { req.recycle(); continue; } // special case - invalid AJP13 packet, error // decoding packet ... // we drop the connection rigth now if( status != 200 ) break; if( decoded ) req.setNote( decodedNote, this ); cm.service(req, res); req.recycle(); res.recycle(); } log("Closing connection", Log.DEBUG); con.close(); socket.close(); } catch (Exception e) { log("Processing connection " + connection, e); } } public void setServer(Object contextM) { this.cm=(ContextManager)contextM; } protected boolean doShutdown(Ajp13 con, InetAddress serverAddr, InetAddress clientAddr) { try { // continue with the other checks. XXX We may allow shutdown // with the right secret from a different address. // close the socket connection before handling any signal // but get the addresses first so they are not corrupted if(shutdownEnable && Ajp12.isSameAddress(serverAddr, clientAddr)) { cm.shutdown(); log( "Exiting" ); // same behavior as in past, because it seems that // stopping everything doesn't work - need to figure // out what happens with the threads ( XXX ) System.exit(0); } } catch(Exception ignored) { log("Ignored " + ignored); } log("Shutdown command ignored"); return false; } public boolean isTomcatAuthentication() { return tomcatAuthentication; } public void setTomcatAuthentication(boolean newTomcatAuthentication) { tomcatAuthentication = newTomcatAuthentication; } } class Ajp13Request extends Request { Ajp13 ajp13 = new Ajp13(); int dL = 0; public Ajp13Request() { super(); } public void setDebug(int level) { dL = level; } protected int receiveNextRequest() throws IOException { return ajp13.receiveNextRequest( this ); } public int doRead() throws IOException { if( contentLength == -1 ) { return ajp13.doRead(); } if( available <= 0 ) return -1; available--; return ajp13.doRead(); } public int doRead(byte[] b, int off, int len) throws IOException { int rd=-1; if( contentLength == -1 ) { rd=ajp13.doRead(b,off,len); return rd; } if( available <= 0 ) return -1; rd=ajp13.doRead( b,off, len ); available -= rd; if( dL > 0 ) d("Read: " + new String( b,off, len )); return rd; } public void recycle() { super.recycle(); if( ajp13!=null) ajp13.recycle(); } private void d(String s ) { System.err.println( "Ajp13Request: " + s ); } } class Ajp13Response extends Response { Ajp13 ajp13; boolean finished=false; public Ajp13Response() { super(); } public void recycle() { super.recycle(); finished=false; } public void setSocket( Socket s ) { ajp13=((Ajp13Request)request).ajp13; } // XXX if more headers that MAX_SIZE, send 2 packets! public void endHeaders() throws IOException { super.endHeaders(); if (request.protocol().isNull()) { return; } ajp13.sendHeaders(getStatus(), getMimeHeaders()); } public void finish() throws IOException { if(!finished) { super.finish(); finished = true; // Avoid END_OF_RESPONSE sent 2 times ajp13.finish(); } } public void doWrite( byte b[], int off, int len) throws IOException { ajp13.doWrite(b, off, len ); } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.