📄 handlerrequest.java
字号:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.jk.common;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.CharConversionException;
import java.net.InetAddress;
import java.util.Properties;
import org.apache.coyote.Request;
import org.apache.coyote.RequestInfo;
import org.apache.coyote.Response;
import org.apache.coyote.Constants;
import org.apache.jk.core.JkHandler;
import org.apache.jk.core.Msg;
import org.apache.jk.core.MsgContext;
import org.apache.jk.core.WorkerEnv;
import org.apache.jk.core.JkChannel;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.CharChunk;
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.threads.ThreadWithAttributes;
/**
* Handle messages related with basic request information.
*
* This object can handle the following incoming messages:
* - "FORWARD_REQUEST" input message ( sent when a request is passed from the
* web server )
* - "RECEIVE_BODY_CHUNK" input ( sent by container to pass more body, in
* response to GET_BODY_CHUNK )
*
* It can handle the following outgoing messages:
* - SEND_HEADERS. Pass the status code and headers.
* - SEND_BODY_CHUNK. Send a chunk of body
* - GET_BODY_CHUNK. Request a chunk of body data
* - END_RESPONSE. Notify the end of a request processing.
*
* @author Henri Gomez [hgomez@apache.org]
* @author Dan Milstein [danmil@shore.net]
* @author Keith Wannamaker [Keith@Wannamaker.org]
* @author Costin Manolache
*/
public class HandlerRequest extends JkHandler
{
private static org.apache.juli.logging.Log log=
org.apache.juli.logging.LogFactory.getLog( HandlerRequest.class );
/*
* Note for Host parsing.
*/
public static final int HOSTBUFFER = 10;
/**
* Thread lock.
*/
private static Object lock = new Object();
private HandlerDispatch dispatch;
private String ajpidDir="conf";
public HandlerRequest() {
}
public void init() {
dispatch=(HandlerDispatch)wEnv.getHandler( "dispatch" );
if( dispatch != null ) {
// register incoming message handlers
dispatch.registerMessageType( AjpConstants.JK_AJP13_FORWARD_REQUEST,
"JK_AJP13_FORWARD_REQUEST",
this, null); // 2
dispatch.registerMessageType( AjpConstants.JK_AJP13_SHUTDOWN,
"JK_AJP13_SHUTDOWN",
this, null); // 7
dispatch.registerMessageType( AjpConstants.JK_AJP13_CPING_REQUEST,
"JK_AJP13_CPING_REQUEST",
this, null); // 10
dispatch.registerMessageType( HANDLE_THREAD_END,
"HANDLE_THREAD_END",
this, null);
// register outgoing messages handler
dispatch.registerMessageType( AjpConstants.JK_AJP13_SEND_BODY_CHUNK, // 3
"JK_AJP13_SEND_BODY_CHUNK",
this,null );
}
tmpBufNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "tmpBuf" );
secretNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "secret" );
if( next==null )
next=wEnv.getHandler( "container" );
if( log.isDebugEnabled() )
log.debug( "Container handler " + next + " " + next.getName() +
" " + next.getClass().getName());
// should happen on start()
generateAjp13Id();
}
public void setSecret( String s ) {
requiredSecret=s;
}
public void setUseSecret( boolean b ) {
if(b) {
requiredSecret=Double.toString(Math.random());
}
}
public void setDecodedUri( boolean b ) {
decoded=b;
}
public boolean isTomcatAuthentication() {
return tomcatAuthentication;
}
public void setShutdownEnabled(boolean se) {
shutdownEnabled = se;
}
public boolean getShutdownEnabled() {
return shutdownEnabled;
}
public void setTomcatAuthentication(boolean newTomcatAuthentication) {
tomcatAuthentication = newTomcatAuthentication;
}
public void setAjpidDir( String path ) {
if( "".equals( path ) ) path=null;
ajpidDir=path;
}
/**
* Set the flag to tell if we JMX register requests.
*/
public void setRegisterRequests(boolean srr) {
registerRequests = srr;
}
/**
* Get the flag to tell if we JMX register requests.
*/
public boolean getRegisterRequests() {
return registerRequests;
}
/**
* Set the flag to delay the initial body read
*/
public void setDelayInitialRead(boolean dir) {
delayInitialRead = dir;
}
/**
* Get the flag to tell if we delay the initial body read
*/
public boolean getDelayInitialRead() {
return delayInitialRead;
}
// -------------------- Ajp13.id --------------------
private void generateAjp13Id() {
int portInt=8009; // tcpCon.getPort();
InetAddress address=null; // tcpCon.getAddress();
if( requiredSecret == null || !shutdownEnabled )
return;
File f1=new File( wEnv.getJkHome() );
File f2=new File( f1, "conf" );
if( ! f2.exists() ) {
log.error( "No conf dir for ajp13.id " + f2 );
return;
}
File sf=new File( f2, "ajp13.id");
if( log.isDebugEnabled())
log.debug( "Using stop file: "+sf);
try {
Properties props=new Properties();
props.put( "port", Integer.toString( portInt ));
if( address!=null ) {
props.put( "address", address.getHostAddress() );
}
if( requiredSecret !=null ) {
props.put( "secret", requiredSecret );
}
FileOutputStream stopF=new FileOutputStream( sf );
props.store( stopF, "Automatically generated, don't edit" );
} catch( IOException ex ) {
if(log.isDebugEnabled())
log.debug( "Can't create stop file: "+sf,ex );
}
}
// -------------------- Incoming message --------------------
private String requiredSecret=null;
private int secretNote;
private int tmpBufNote;
private boolean decoded=true;
private boolean tomcatAuthentication=true;
private boolean registerRequests=true;
private boolean shutdownEnabled=false;
private boolean delayInitialRead = true;
public int invoke(Msg msg, MsgContext ep )
throws IOException {
int type=msg.getByte();
ThreadWithAttributes twa = null;
if (Thread.currentThread() instanceof ThreadWithAttributes) {
twa = (ThreadWithAttributes) Thread.currentThread();
}
Object control=ep.getControl();
MessageBytes tmpMB=(MessageBytes)ep.getNote( tmpBufNote );
if( tmpMB==null ) {
tmpMB= MessageBytes.newInstance();
ep.setNote( tmpBufNote, tmpMB);
}
if( log.isDebugEnabled() )
log.debug( "Handling " + type );
switch( type ) {
case AjpConstants.JK_AJP13_FORWARD_REQUEST:
try {
if (twa != null) {
twa.setCurrentStage(control, "JkDecode");
}
decodeRequest( msg, ep, tmpMB );
if (twa != null) {
twa.setCurrentStage(control, "JkService");
twa.setParam(control,
((Request)ep.getRequest()).unparsedURI());
}
} catch( Exception ex ) {
log.error( "Error decoding request ", ex );
msg.dump( "Incomming message");
return ERROR;
}
if( requiredSecret != null ) {
String epSecret=(String)ep.getNote( secretNote );
if( epSecret==null || ! requiredSecret.equals( epSecret ) )
return ERROR;
}
/* XXX it should be computed from request, by workerEnv */
if(log.isDebugEnabled() )
log.debug("Calling next " + next.getName() + " " +
next.getClass().getName());
int err= next.invoke( msg, ep );
if (twa != null) {
twa.setCurrentStage(control, "JkDone");
}
if( log.isDebugEnabled() )
log.debug( "Invoke returned " + err );
return err;
case AjpConstants.JK_AJP13_SHUTDOWN:
String epSecret=null;
if( msg.getLen() > 3 ) {
// we have a secret
msg.getBytes( tmpMB );
epSecret=tmpMB.toString();
}
if( requiredSecret != null &&
requiredSecret.equals( epSecret ) ) {
if( log.isDebugEnabled() )
log.debug("Received wrong secret, no shutdown ");
return ERROR;
}
// XXX add isSameAddress check
JkChannel ch=ep.getSource();
if( !ch.isSameAddress(ep) ) {
log.error("Shutdown request not from 'same address' ");
return ERROR;
}
if( !shutdownEnabled ) {
log.warn("Ignoring shutdown request: shutdown not enabled");
return ERROR;
}
// forward to the default handler - it'll do the shutdown
checkRequest(ep);
next.invoke( msg, ep );
if(log.isInfoEnabled())
log.info("Exiting");
System.exit(0);
return OK;
// We got a PING REQUEST, quickly respond with a PONG
case AjpConstants.JK_AJP13_CPING_REQUEST:
msg.reset();
msg.appendByte(AjpConstants.JK_AJP13_CPONG_REPLY);
ep.getSource().send( msg, ep );
ep.getSource().flush( msg, ep ); // Server needs to get it
return OK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -