/**
* Copyright (C) Zhang,Yuexiang (xfeep)
*
*For reuse some classes from tomcat8 we have to use this package
*/
package org.apache.coyote.http11;
import static nginx.clojure.MiniConstants.NGX_HTTP_OK;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Set;
import nginx.clojure.MiniConstants;
import nginx.clojure.java.ArrayMap;
import nginx.clojure.java.NginxJavaRequest;
import org.apache.coyote.ActionCode;
import org.apache.coyote.ErrorState;
import org.apache.coyote.RequestInfo;
import org.apache.juli.logging.Log;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.NioEndpoint;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapper;
public class NginxTomcatHttp11Processor extends AbstractHttp11Processor<NginxChannel> {
protected static final org.apache.juli.logging.Log log =
org.apache.juli.logging.LogFactory.getLog( NginxTomcatHttp11Processor.class );
protected NginxEndpoint.SendfileData sendfileData = null;
public NginxTomcatHttp11Processor(int maxHttpHeaderSize, NginxEndpoint endpoint,
int maxTrailerSize, Set<String> allowedTrailerHeaders, int maxExtensionSize, int maxSwallowSize) {
super(endpoint);
inputBuffer = new InternalNginxInputBuffer(request, maxHttpHeaderSize);
request.setInputBuffer(inputBuffer);
outputBuffer = new InternalNginxOutputBuffer(response, maxHttpHeaderSize);
response.setOutputBuffer(outputBuffer);
initializeFilters(maxTrailerSize, allowedTrailerHeaders, maxExtensionSize, maxSwallowSize);
}
@Override
public void setSslSupport(SSLSupport sslSupport) {
}
@Override
protected AbstractInputBuffer<NginxChannel> getInputBuffer() {
return inputBuffer;
}
@Override
protected AbstractOutputBuffer<NginxChannel> getOutputBuffer() {
return outputBuffer;
}
@Override
void actionInternal(ActionCode actionCode, Object param) {
switch (actionCode) {
case REQ_HOST_ADDR_ATTRIBUTE: {
if (socketWrapper == null) {
request.remoteAddr().recycle();
} else {
if (socketWrapper.getRemoteAddr() == null) {
NginxJavaRequest nreq = (NginxJavaRequest) socketWrapper.getSocket().getIOChannel().request();
socketWrapper.setRemoteAddr((String)nreq.get(MiniConstants.REMOTE_ADDR));
}
request.remoteAddr().setString(socketWrapper.getRemoteAddr());
}
break;
}
case REQ_LOCAL_NAME_ATTRIBUTE: {
if (socketWrapper == null) {
request.localName().recycle();
} else {
if (socketWrapper.getLocalName() == null) {
NginxJavaRequest nreq = (NginxJavaRequest) socketWrapper.getSocket().getIOChannel().request();
String serverAddr = nreq.getVariable("server_addr");
InetAddress inetAddr = null;
try {
inetAddr = InetAddress.getByName(serverAddr);
} catch (UnknownHostException e) {
log.error("can not get local server name", e);
}
if (inetAddr != null) {
socketWrapper.setLocalName(inetAddr.getHostName());
}
}
request.localName().setString(socketWrapper.getLocalName());
}
break;
}
case REQ_HOST_ATTRIBUTE: {
if (socketWrapper == null) {
request.remoteHost().recycle();
} else {
if (socketWrapper.getRemoteHost() == null) {
if (socketWrapper.getRemoteHost() == null) {
if (socketWrapper.getRemoteAddr() == null) {
NginxJavaRequest nreq = (NginxJavaRequest) socketWrapper.getSocket().getIOChannel().request();
socketWrapper.setRemoteAddr((String)nreq.get(MiniConstants.REMOTE_ADDR));
}
if (socketWrapper.getRemoteAddr() != null) {
socketWrapper.setRemoteHost(socketWrapper.getRemoteAddr());
}
}
}
request.remoteHost().setString(socketWrapper.getRemoteHost());
}
break;
}
case REQ_LOCAL_ADDR_ATTRIBUTE: {
if (socketWrapper == null) {
request.localAddr().recycle();
} else {
if (socketWrapper.getLocalAddr() == null) {
NginxJavaRequest nreq = (NginxJavaRequest) socketWrapper.getSocket().getIOChannel().request();
String serverAddr = nreq.getVariable("server_addr");
socketWrapper.setLocalAddr(serverAddr);
}
request.localAddr().setString(socketWrapper.getLocalAddr());
}
break;
}
case REQ_REMOTEPORT_ATTRIBUTE: {
if (socketWrapper == null) {
request.setRemotePort(0);
} else {
if (socketWrapper.getRemotePort() == -1) {
NginxJavaRequest nreq = (NginxJavaRequest) socketWrapper.getSocket().getIOChannel().request();
String remotePort = nreq.getVariable("remote_port");
socketWrapper.setRemotePort(Integer.parseInt(remotePort));
}
request.setRemotePort(socketWrapper.getRemotePort());
}
break;
}
case REQ_LOCALPORT_ATTRIBUTE: {
if (socketWrapper == null) {
request.setLocalPort(0);
} else {
if (socketWrapper.getLocalPort() == -1) {
NginxJavaRequest nreq = (NginxJavaRequest) socketWrapper.getSocket().getIOChannel().request();
String localPort = nreq.getVariable("server_port");
socketWrapper.setLocalPort(Integer.parseInt(localPort));
}
request.setLocalPort(socketWrapper.getLocalPort());
}
break;
}
case REQ_SSL_ATTRIBUTE: {
break;
}
case REQ_SSL_CERTIFICATE: {
break;
}
case COMET_BEGIN: {
comet = true;
break;
}
case COMET_END: {
comet = false;
break;
}
case COMET_CLOSE: {
if (socketWrapper==null || socketWrapper.getSocket().getAttachment()==null) {
return;
}
RequestInfo rp = request.getRequestProcessor();
if (rp.getStage() != org.apache.coyote.Constants.STAGE_SERVICE) {
// Close event for this processor triggered by request
// processing in another processor, a non-Tomcat thread (i.e.
// an application controlled thread) or similar.
// socketWrapper.getSocket().getPoller().add(socketWrapper.getSocket());
throw new UnsupportedOperationException("not support COMET_CLOSE yet!");
}
break;
}
case COMET_SETTIMEOUT: {
if (param==null) {
return;
}
if (socketWrapper==null || socketWrapper.getSocket().getAttachment()==null) {
return;
}
NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment)socketWrapper.getSocket().getAttachment();
long timeout = ((Long)param).longValue();
//if we are not piggy backing on a worker thread, set the timeout
RequestInfo rp = request.getRequestProcessor();
if ( rp.getStage() != org.apache.coyote.Constants.STAGE_SERVICE ) {
attach.setTimeout(timeout);
}
break;
}
}
}
@Override
protected boolean disableKeepAlive() {
// TODO Auto-generated method stub
return false;
}
@Override
protected void setRequestLineReadTimeout() throws IOException {
}
@Override
protected boolean handleIncompleteRequestLineRead() {
throw new IllegalStateException("nginx tomat won't have incomplete request line to read");
}
@Override
protected void setSocketTimeout(int timeout) throws IOException {
socketWrapper.getSocket().getIOChannel().setAsyncTimeout(timeout);
}
@Override
protected boolean breakKeepAliveLoop(
SocketWrapper<NginxChannel> socketWrapper) {
if (sendfileData != null && !getErrorState().isError()) {
try {
socketWrapper
.getSocket()
.getIOChannel()
.sendResponse(
new Object[] { NGX_HTTP_OK, null,
new File(sendfileData.fileName) });
sendfileInProgress = true;
} catch (IOException e) {
setErrorState(ErrorState.CLOSE_NOW, e);
}
}
return true;
}
@Override
protected void prepareRequestInternal() {
// TODO Auto-generated method stub
}
@Override
boolean prepareSendfile(OutputFilter[] outputFilters) {
String fileName = (String) request.getAttribute(
org.apache.coyote.Constants.SENDFILE_FILENAME_ATTR);
if (fileName != null) {
// No entity body sent here
outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
contentDelimitation = true;
sendfileData = new NginxEndpoint.SendfileData();
sendfileData.fileName = fileName;
sendfileData.pos = ((Long) request.getAttribute(
org.apache.coyote.Constants.SENDFILE_FILE_START_ATTR)).longValue();
sendfileData.length = ((Long) request.getAttribute(
org.apache.coyote.Constants.SENDFILE_FILE_END_ATTR)).longValue() - sendfileData.pos;
socketWrapper.getSocket().setSendFile(true);
return true;
}
return false;
}
@Override
protected void resetTimeouts() {
// TODO Auto-generated method stub
}
@Override
protected void setCometTimeouts(
SocketWrapper<NginxChannel> socketWrapper) {
// TODO Auto-generated method stub
}
@Override
protected void recycleInternal() {
socketWrapper = null;
sendfileData = null;
}
@Override
public SocketState event(SocketStatus status) throws IOException {
long soTimeout = endpoint.getSoTimeout();
RequestInfo rp = request.getRequestProcessor();
final NginxEndpoint.KeyAttachment attach = (NginxEndpoint.KeyAttachment)socketWrapper.getSocket().getAttachment();
try {
rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
if (!getAdapter().event(request, response, status)) {
setErrorState(ErrorState.CLOSE_NOW, null);
}
if (!getErrorState().isError()) {
if (attach != null) {
attach.setComet(comet);
if (comet) {
Integer comettimeout = (Integer) request.getAttribute(
org.apache.coyote.Constants.COMET_TIMEOUT_ATTR);
if (comettimeout != null) {
attach.setTimeout(comettimeout.longValue());
}
} else {
//reset the timeout
if (keepAlive) {
attach.setTimeout(keepAliveTimeout);
} else {
attach.setTimeout(soTimeout);
}
}
}
}
} catch (InterruptedIOException e) {
setErrorState(ErrorState.CLOSE_NOW, e);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
// 500 - Internal Server Error
response.setStatus(500);
setErrorState(ErrorState.CLOSE_NOW, t);
log.error(sm.getString("http11processor.request.process"), t);
getAdapter().log(request, response, 0);
}
rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
if (getErrorState().isError() || status==SocketStatus.STOP) {
return SocketState.CLOSED;
} else if (!comet) {
if (keepAlive) {
inputBuffer.nextRequest();
outputBuffer.nextRequest();
return SocketState.OPEN;
} else {
return SocketState.CLOSED;
}
} else {
return SocketState.LONG;
}
}
@Override
protected void registerForEvent(boolean read, boolean write) {
}
@Override
protected Log getLog() {
return log;
}
}