280 lines
9.0 KiB
Java
280 lines
9.0 KiB
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.coyote.ajp;
|
|
|
|
import java.net.InetAddress;
|
|
import java.util.regex.Pattern;
|
|
|
|
import org.apache.coyote.AbstractProtocol;
|
|
import org.apache.coyote.Processor;
|
|
import org.apache.coyote.UpgradeProtocol;
|
|
import org.apache.coyote.UpgradeToken;
|
|
import org.apache.tomcat.util.net.AbstractEndpoint;
|
|
import org.apache.tomcat.util.net.SSLHostConfig;
|
|
import org.apache.tomcat.util.net.SocketWrapperBase;
|
|
import org.apache.tomcat.util.res.StringManager;
|
|
|
|
/**
|
|
* The is the base implementation for the AJP protocol handlers. Implementations
|
|
* typically extend this base class rather than implement {@link
|
|
* org.apache.coyote.ProtocolHandler}. All of the implementations that ship with
|
|
* Tomcat are implemented this way.
|
|
*
|
|
* @param <S> The type of socket used by the implementation
|
|
*/
|
|
public abstract class AbstractAjpProtocol<S> extends AbstractProtocol<S> {
|
|
|
|
/**
|
|
* The string manager for this package.
|
|
*/
|
|
protected static final StringManager sm = StringManager.getManager(AbstractAjpProtocol.class);
|
|
|
|
|
|
public AbstractAjpProtocol(AbstractEndpoint<S> endpoint) {
|
|
super(endpoint);
|
|
setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
|
|
// AJP does not use Send File
|
|
getEndpoint().setUseSendfile(false);
|
|
// AJP listens on loopback by default
|
|
getEndpoint().setAddress(InetAddress.getLoopbackAddress());
|
|
ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
|
|
setHandler(cHandler);
|
|
getEndpoint().setHandler(cHandler);
|
|
}
|
|
|
|
|
|
@Override
|
|
protected String getProtocolName() {
|
|
return "Ajp";
|
|
}
|
|
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*
|
|
* Overridden to make getter accessible to other classes in this package.
|
|
*/
|
|
@Override
|
|
protected AbstractEndpoint<S> getEndpoint() {
|
|
return super.getEndpoint();
|
|
}
|
|
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*
|
|
* AJP does not support protocol negotiation so this always returns null.
|
|
*/
|
|
@Override
|
|
protected UpgradeProtocol getNegotiatedProtocol(String name) {
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*
|
|
* AJP does not support protocol upgrade so this always returns null.
|
|
*/
|
|
@Override
|
|
protected UpgradeProtocol getUpgradeProtocol(String name) {
|
|
return null;
|
|
}
|
|
|
|
// ------------------------------------------------- AJP specific properties
|
|
// ------------------------------------------ managed in the ProtocolHandler
|
|
|
|
protected boolean ajpFlush = true;
|
|
public boolean getAjpFlush() { return ajpFlush; }
|
|
/**
|
|
* Configure whether to aend an AJP flush packet when flushing. A flush
|
|
* packet is a zero byte AJP13 SEND_BODY_CHUNK packet. mod_jk and
|
|
* mod_proxy_ajp interpret this as a request to flush data to the client.
|
|
* AJP always does flush at the and of the response, so if it is not
|
|
* important, that the packets get streamed up to the client, do not use
|
|
* extra flush packets. For compatibility and to stay on the safe side,
|
|
* flush packets are enabled by default.
|
|
*
|
|
* @param ajpFlush The new flush setting
|
|
*/
|
|
public void setAjpFlush(boolean ajpFlush) {
|
|
this.ajpFlush = ajpFlush;
|
|
}
|
|
|
|
|
|
private boolean tomcatAuthentication = true;
|
|
/**
|
|
* Should authentication be done in the native web server layer,
|
|
* or in the Servlet container ?
|
|
*
|
|
* @return {@code true} if authentication should be performed by Tomcat,
|
|
* otherwise {@code false}
|
|
*/
|
|
public boolean getTomcatAuthentication() { return tomcatAuthentication; }
|
|
public void setTomcatAuthentication(boolean tomcatAuthentication) {
|
|
this.tomcatAuthentication = tomcatAuthentication;
|
|
}
|
|
|
|
|
|
private boolean tomcatAuthorization = false;
|
|
/**
|
|
* Should authentication be done in the native web server layer and
|
|
* authorization in the Servlet container?
|
|
*
|
|
* @return {@code true} if authorization should be performed by Tomcat,
|
|
* otherwise {@code false}
|
|
*/
|
|
public boolean getTomcatAuthorization() { return tomcatAuthorization; }
|
|
public void setTomcatAuthorization(boolean tomcatAuthorization) {
|
|
this.tomcatAuthorization = tomcatAuthorization;
|
|
}
|
|
|
|
|
|
private String secret = null;
|
|
/**
|
|
* Set the secret that must be included with every request.
|
|
*
|
|
* @param secret The required secret
|
|
*/
|
|
public void setSecret(String secret) {
|
|
this.secret = secret;
|
|
}
|
|
protected String getSecret() {
|
|
return secret;
|
|
}
|
|
/**
|
|
* Set the required secret that must be included with every request.
|
|
*
|
|
* @param requiredSecret The required secret
|
|
*
|
|
* @deprecated Replaced by {@link #setSecret(String)}.
|
|
* Will be removed in Tomcat 11 onwards
|
|
*/
|
|
@Deprecated
|
|
public void setRequiredSecret(String requiredSecret) {
|
|
setSecret(requiredSecret);
|
|
}
|
|
/**
|
|
* @return The current secret
|
|
*
|
|
* @deprecated Replaced by {@link #getSecret()}.
|
|
* Will be removed in Tomcat 11 onwards
|
|
*/
|
|
@Deprecated
|
|
protected String getRequiredSecret() {
|
|
return getSecret();
|
|
}
|
|
|
|
|
|
private boolean secretRequired = true;
|
|
public void setSecretRequired(boolean secretRequired) {
|
|
this.secretRequired = secretRequired;
|
|
}
|
|
public boolean getSecretRequired() {
|
|
return secretRequired;
|
|
}
|
|
|
|
|
|
private Pattern allowedRequestAttributesPattern;
|
|
public void setAllowedRequestAttributesPattern(String allowedRequestAttributesPattern) {
|
|
this.allowedRequestAttributesPattern = Pattern.compile(allowedRequestAttributesPattern);
|
|
}
|
|
public String getAllowedRequestAttributesPattern() {
|
|
return allowedRequestAttributesPattern.pattern();
|
|
}
|
|
protected Pattern getAllowedRequestAttributesPatternInternal() {
|
|
return allowedRequestAttributesPattern;
|
|
}
|
|
|
|
|
|
/**
|
|
* AJP packet size.
|
|
*/
|
|
private int packetSize = Constants.MAX_PACKET_SIZE;
|
|
public int getPacketSize() { return packetSize; }
|
|
public void setPacketSize(int packetSize) {
|
|
if(packetSize < Constants.MAX_PACKET_SIZE) {
|
|
this.packetSize = Constants.MAX_PACKET_SIZE;
|
|
} else {
|
|
this.packetSize = packetSize;
|
|
}
|
|
}
|
|
|
|
|
|
// --------------------------------------------- SSL is not supported in AJP
|
|
|
|
@Override
|
|
public void addSslHostConfig(SSLHostConfig sslHostConfig) {
|
|
getLog().warn(sm.getString("ajpprotocol.noSSL", sslHostConfig.getHostName()));
|
|
}
|
|
|
|
|
|
@Override
|
|
public SSLHostConfig[] findSslHostConfigs() {
|
|
return new SSLHostConfig[0];
|
|
}
|
|
|
|
|
|
@Override
|
|
public void addUpgradeProtocol(UpgradeProtocol upgradeProtocol) {
|
|
getLog().warn(sm.getString("ajpprotocol.noUpgrade", upgradeProtocol.getClass().getName()));
|
|
}
|
|
|
|
|
|
@Override
|
|
public UpgradeProtocol[] findUpgradeProtocols() {
|
|
return new UpgradeProtocol[0];
|
|
}
|
|
|
|
|
|
@SuppressWarnings("deprecation")
|
|
@Override
|
|
protected Processor createProcessor() {
|
|
AjpProcessor processor = new AjpProcessor(getPacketSize(), getEndpoint());
|
|
processor.setAdapter(getAdapter());
|
|
processor.setAjpFlush(getAjpFlush());
|
|
processor.setTomcatAuthentication(getTomcatAuthentication());
|
|
processor.setTomcatAuthorization(getTomcatAuthorization());
|
|
processor.setSecret(secret);
|
|
processor.setKeepAliveTimeout(getKeepAliveTimeout());
|
|
processor.setClientCertProvider(getClientCertProvider());
|
|
processor.setSendReasonPhrase(getSendReasonPhrase());
|
|
processor.setAllowedRequestAttributesPattern(getAllowedRequestAttributesPatternInternal());
|
|
return processor;
|
|
}
|
|
|
|
|
|
@Override
|
|
protected Processor createUpgradeProcessor(SocketWrapperBase<?> socket,
|
|
UpgradeToken upgradeToken) {
|
|
throw new IllegalStateException(sm.getString("ajpprotocol.noUpgradeHandler",
|
|
upgradeToken.getHttpUpgradeHandler().getClass().getName()));
|
|
}
|
|
|
|
|
|
@Override
|
|
public void start() throws Exception {
|
|
if (getSecretRequired()) {
|
|
String secret = getSecret();
|
|
if (secret == null || secret.length() == 0) {
|
|
throw new IllegalArgumentException(sm.getString("ajpprotocol.nosecret"));
|
|
}
|
|
}
|
|
super.start();
|
|
}
|
|
}
|