/**
* Copyright (C) Zhang,Yuexiang (xfeep)
*
*For reuse some classes from tomcat8 we have to use this package
*/
package org.apache.coyote.http11;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Iterator;
import javax.servlet.http.HttpUpgradeHandler;
import nginx.clojure.NginxClojureRT;
import nginx.clojure.NginxHttpServerChannel;
import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.Processor;
import org.apache.coyote.http11.NginxEndpoint.Handler;
import org.apache.coyote.http11.upgrade.NginxUpgradeProcessor;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapper;
public class NginxDirectProtocol extends AbstractHttp11JsseProtocol<NginxChannel> {
private static final Log log = LogFactory.getLog(NginxDirectProtocol.class);
private final Http11ConnectionHandler cHandler;
public NginxDirectProtocol() {
endpoint = new NginxEndpoint();
endpoint.setMaxConnections(-1);
cHandler = new Http11ConnectionHandler(this);
((NginxEndpoint)endpoint).setHandler(cHandler);
setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
}
public NginxEndpoint getEndpoint() {
return ((NginxEndpoint)endpoint);
}
@Override
protected Log getLog() {
return log;
}
@Override
protected String getNamePrefix() {
return "http-nginx";
}
@Override
protected Handler getHandler() {
return cHandler;
}
protected static class Http11ConnectionHandler extends
AbstractConnectionHandler<NginxChannel, NginxTomcatHttp11Processor> implements
Handler {
protected NginxDirectProtocol proto;
Http11ConnectionHandler(NginxDirectProtocol proto) {
this.proto = proto;
}
@Override
protected AbstractProtocol<NginxChannel> getProtocol() {
return proto;
}
@Override
protected Log getLog() {
return log;
}
/**
* Expected to be used by the Poller to release resources on socket
* close, errors etc.
*/
@Override
public void release(NginxHttpServerChannel socket) {
if (log.isDebugEnabled())
log.debug("Iterating through our connections to release a socket channel:"
+ socket);
boolean released = false;
Iterator<java.util.Map.Entry<NginxChannel, Processor<NginxChannel>>> it = connections
.entrySet().iterator();
while (it.hasNext()) {
java.util.Map.Entry<NginxChannel, Processor<NginxChannel>> entry = it
.next();
if (entry.getKey().getIOChannel() == socket) {
it.remove();
Processor<NginxChannel> result = entry.getValue();
result.recycle(true);
unregister(result);
released = true;
break;
}
}
if (log.isDebugEnabled())
log.debug("Done iterating through our connections to release a socket channel:"
+ socket + " released:" + released);
}
/**
* Expected to be used by the Poller to release resources on socket
* close, errors etc.
*/
@Override
public void release(SocketWrapper<NginxChannel> socket) {
Processor<NginxChannel> processor = connections.remove(socket
.getSocket());
if (processor != null) {
processor.recycle(true);
recycledProcessors.push(processor);
}
}
@Override
public SocketState process(SocketWrapper<NginxChannel> socket,
SocketStatus status) {
//tomcat 8.0.23 removed proto.npnHandler and nginx will do SPDY things so we do not need it
// if (proto.npnHandler != null) {
// SocketState ss = proto.npnHandler.process(socket, status);
// if (ss != SocketState.OPEN) {
// return ss;
// }
// }
return super.process(socket, status);
}
/**
* Expected to be used by the handler once the processor is no longer
* required.
*
* @param socket
* @param processor
* @param isSocketClosing
* Not used in HTTP
* @param addToPoller
*/
@Override
public void release(SocketWrapper<NginxChannel> socket,
Processor<NginxChannel> processor, boolean isSocketClosing,
boolean addToPoller) {
processor.recycle(isSocketClosing);
recycledProcessors.push(processor);
// if (addToPoller) {
//// socket.getSocket().getPoller().add(socket.getSocket());
// throw new UnsupportedOperationException("addToPoller = true is not supported at NginxDirectProtocol.release");
// }
}
@Override
protected void initSsl(SocketWrapper<NginxChannel> socket,
Processor<NginxChannel> processor) {
}
@Override
protected void longPoll(SocketWrapper<NginxChannel> socket,
Processor<NginxChannel> processor) {
if (processor.isAsync()) {
socket.setAsync(true);
} else {
// Either:
// - this is comet request
// - this is an upgraded connection
// - the request line/headers have not been completely
// read
// socket.getSocket().getPoller().add(socket.getSocket());
}
}
@Override
public NginxTomcatHttp11Processor createProcessor() {
NginxTomcatHttp11Processor processor = new NginxTomcatHttp11Processor(
proto.getMaxHttpHeaderSize(), (NginxEndpoint) proto.endpoint,
proto.getMaxTrailerSize(), proto.getAllowedTrailerHeadersAsSet(),
proto.getMaxExtensionSize(),proto.getMaxSwallowSize());
proto.configureProcessor(processor);
register(processor);
return processor;
}
@Override
protected Processor<NginxChannel> createUpgradeProcessor(
SocketWrapper<NginxChannel> socket, ByteBuffer leftoverInput,
HttpUpgradeHandler httpUpgradeProcessor) throws IOException {
NginxUpgradeProcessor processor = new NginxUpgradeProcessor(socket, leftoverInput, httpUpgradeProcessor);
if (socket.getSocket().ignoreNginxFilter) {
socket.getSocket().getIOChannel().turnOnEventHandler(true, true, true);
}
socket.getSocket().getIOChannel().addListener(socket, (NginxEndpoint)proto.endpoint);
return processor;
}
}
}