Mercurial Hosting > luan
diff src/org/eclipse/jetty/server/Connector.java @ 885:150092cebf3e
remove AbstractConnector
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 04 Oct 2016 20:11:48 -0600 |
parents | 6b210bb66c63 |
children | df84a1741687 |
line wrap: on
line diff
--- a/src/org/eclipse/jetty/server/Connector.java Tue Oct 04 16:30:02 2016 -0600 +++ b/src/org/eclipse/jetty/server/Connector.java Tue Oct 04 20:11:48 2016 -0600 @@ -19,269 +19,1013 @@ package org.eclipse.jetty.server; import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicLong; -import org.eclipse.jetty.io.Buffers; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.util.component.LifeCycle; +import javax.servlet.ServletRequest; -/** HTTP Connector. - * Implementations of this interface provide connectors for the HTTP protocol. - * A connector receives requests (normally from a socket) and calls the - * handle method of the Handler object. These operations are performed using - * threads from the ThreadPool set on the connector. - * - * When a connector is registered with an instance of Server, then the server - * will set itself as both the ThreadPool and the Handler. Note that a connector - * can be used without a Server if a thread pool and handler are directly provided. - * - * - * - */ +import org.eclipse.jetty.http.HttpBuffers; +import org.eclipse.jetty.http.HttpBuffersImpl; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeaders; +import org.eclipse.jetty.http.HttpSchemes; +import org.eclipse.jetty.io.Buffers; +import org.eclipse.jetty.io.Buffers.Type; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.util.component.AggregateLifeCycle; +import org.eclipse.jetty.util.component.Dumpable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** - * @author gregw - * + * Abstract Connector implementation. This abstract implementation of the Connector interface provides: + * <ul> + * <li>AbstractLifeCycle implementation</li> + * <li>Implementations for connector getters and setters</li> + * <li>Buffer management</li> + * <li>Socket configuration</li> + * <li>Base acceptor thread</li> + * <li>Optional reverse proxy headers checking</li> + * </ul> */ -public interface Connector extends LifeCycle -{ - /* ------------------------------------------------------------ */ - /** - * @return the name of the connector. Defaults to the HostName:port - */ - String getName(); - - /* ------------------------------------------------------------ */ - /** - * Opens the connector - * @throws IOException - */ - void open() throws IOException; +public abstract class Connector extends AggregateLifeCycle implements HttpBuffers, Dumpable +{ + private static final Logger LOG = LoggerFactory.getLogger(Connector.class); + + private String _name; - /* ------------------------------------------------------------ */ - void close() throws IOException; + private Server _server; + private String _host; + private int _port = 0; + private String _integralScheme = HttpSchemes.HTTPS; + private int _integralPort = 0; + private String _confidentialScheme = HttpSchemes.HTTPS; + private int _confidentialPort = 0; + private int _acceptQueueSize = 0; + private int _acceptors = 1; + private int _acceptorPriorityOffset = 0; + private boolean _useDNS; + private boolean _forwarded; + private String _hostHeader; - /* ------------------------------------------------------------ */ - void setServer(Server server); - - /* ------------------------------------------------------------ */ - Server getServer(); + private String _forwardedHostHeader = HttpHeaders.X_FORWARDED_HOST; + private String _forwardedServerHeader = HttpHeaders.X_FORWARDED_SERVER; + private String _forwardedForHeader = HttpHeaders.X_FORWARDED_FOR; + private String _forwardedProtoHeader = HttpHeaders.X_FORWARDED_PROTO; + private String _forwardedCipherSuiteHeader; + private String _forwardedSslSessionIdHeader; + private boolean _reuseAddress = true; + + protected int _maxIdleTime = 200000; + protected int _lowResourceMaxIdleTime = -1; + protected int _soLingerTime = -1; + + private transient Thread[] _acceptorThreads; + + protected final HttpBuffersImpl _buffers = new HttpBuffersImpl(); /* ------------------------------------------------------------ */ /** - * @return Returns the request header buffer size in bytes. */ - int getRequestHeaderSize(); - + public Connector() + { + addBean(_buffers); + } + /* ------------------------------------------------------------ */ - /** - * Set the size of the buffer to be used for request headers. - * @param size The size in bytes. + /* */ - void setRequestHeaderSize(int size); + public Server getServer() + { + return _server; + } + + /* ------------------------------------------------------------ */ + public void setServer(Server server) + { + _server = server; + } + + /* ------------------------------------------------------------ */ + public ThreadPoolExecutor getThreadPool() + { + return _server.threadPool; + } /* ------------------------------------------------------------ */ /** - * @return Returns the response header buffer size in bytes. */ - int getResponseHeaderSize(); - + public void setHost(String host) + { + _host = host; + } + /* ------------------------------------------------------------ */ - /** - * Set the size of the buffer to be used for request headers. - * @param size The size in bytes. + /* */ - void setResponseHeaderSize(int size); - + public String getHost() + { + return _host; + } + + /* ------------------------------------------------------------ */ + public void setPort(int port) + { + _port = port; + } + + /* ------------------------------------------------------------ */ + public int getPort() + { + return _port; + } /* ------------------------------------------------------------ */ /** - * @return factory for request buffers + * @return Returns the maxIdleTime. */ - Buffers getRequestBuffers(); + public int getMaxIdleTime() + { + return _maxIdleTime; + } + + /* ------------------------------------------------------------ */ + /** + * Set the maximum Idle time for a connection, which roughly translates to the {@link Socket#setSoTimeout(int)} call, although with NIO implementations + * other mechanisms may be used to implement the timeout. The max idle time is applied: + * <ul> + * <li>When waiting for a new request to be received on a connection</li> + * <li>When reading the headers and content of a request</li> + * <li>When writing the headers and content of a response</li> + * </ul> + * Jetty interprets this value as the maximum time between some progress being made on the connection. So if a single byte is read or written, then the + * timeout (if implemented by jetty) is reset. However, in many instances, the reading/writing is delegated to the JVM, and the semantic is more strictly + * enforced as the maximum time a single read/write operation can take. Note, that as Jetty supports writes of memory mapped file buffers, then a write may + * take many 10s of seconds for large content written to a slow device. + * <p> + * Previously, Jetty supported separate idle timeouts and IO operation timeouts, however the expense of changing the value of soTimeout was significant, so + * these timeouts were merged. With the advent of NIO, it may be possible to again differentiate these values (if there is demand). + * + * @param maxIdleTime + * The maxIdleTime to set. + */ + public void setMaxIdleTime(int maxIdleTime) + { + _maxIdleTime = maxIdleTime; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the maxIdleTime when resources are low. + */ + public int getLowResourcesMaxIdleTime() + { + return _lowResourceMaxIdleTime; + } /* ------------------------------------------------------------ */ /** - * @return factory for response buffers + * @param maxIdleTime + * The maxIdleTime to set when resources are low. */ - Buffers getResponseBuffers(); - - - /* ------------------------------------------------------------ */ - /** - * @return Returns the requestBufferSize. - */ - int getRequestBufferSize(); - + public void setLowResourcesMaxIdleTime(int maxIdleTime) + { + _lowResourceMaxIdleTime = maxIdleTime; + } + /* ------------------------------------------------------------ */ /** - * Set the size of the content buffer for receiving requests. - * These buffers are only used for active connections that have - * requests with bodies that will not fit within the header buffer. - * @param requestBufferSize The requestBufferSize to set. + * @return Returns the maxIdleTime when resources are low. + * @deprecated */ - void setRequestBufferSize(int requestBufferSize); - + @Deprecated + public final int getLowResourceMaxIdleTime() + { + return getLowResourcesMaxIdleTime(); + } + /* ------------------------------------------------------------ */ /** - * @return Returns the responseBufferSize. + * @param maxIdleTime + * The maxIdleTime to set when resources are low. + * @deprecated */ - int getResponseBufferSize(); - - /* ------------------------------------------------------------ */ - /** - * Set the size of the content buffer for sending responses. - * These buffers are only used for active connections that are sending - * responses with bodies that will not fit within the header buffer. - * @param responseBufferSize The responseBufferSize to set. - */ - void setResponseBufferSize(int responseBufferSize); - + @Deprecated + public final void setLowResourceMaxIdleTime(int maxIdleTime) + { + setLowResourcesMaxIdleTime(maxIdleTime); + } /* ------------------------------------------------------------ */ /** - * @return The port to use when redirecting a request if a data constraint of integral is - * required. See {@link org.eclipse.jetty.util.security.Constraint#getDataConstraint()} + * @return Returns the soLingerTime. */ - int getIntegralPort(); + public int getSoLingerTime() + { + return _soLingerTime; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the acceptQueueSize. + */ + public int getAcceptQueueSize() + { + return _acceptQueueSize; + } /* ------------------------------------------------------------ */ /** - * @return The schema to use when redirecting a request if a data constraint of integral is - * required. See {@link org.eclipse.jetty.util.security.Constraint#getDataConstraint()} + * @param acceptQueueSize + * The acceptQueueSize to set. + */ + public void setAcceptQueueSize(int acceptQueueSize) + { + _acceptQueueSize = acceptQueueSize; + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the number of acceptor threads. */ - String getIntegralScheme(); + public int getAcceptors() + { + return _acceptors; + } + + /* ------------------------------------------------------------ */ + /** + * @param acceptors + * The number of acceptor threads to set. + */ + public void setAcceptors(int acceptors) + { + if (acceptors > 2 * Runtime.getRuntime().availableProcessors()) + LOG.warn("Acceptors should be <=2*availableProcessors: " + this); + _acceptors = acceptors; + } /* ------------------------------------------------------------ */ /** - * @param request A request - * @return true if the request is integral. This normally means the https schema has been used. + * @param soLingerTime + * The soLingerTime to set or -1 to disable. */ - boolean isIntegral(Request request); + public void setSoLingerTime(int soLingerTime) + { + _soLingerTime = soLingerTime; + } + + /* ------------------------------------------------------------ */ + @Override + protected void doStart() throws Exception + { + if (_server == null) + throw new IllegalStateException("No server"); + + // open listener port + open(); + + super.doStart(); + + // Start selector thread + synchronized (this) + { + _acceptorThreads = new Thread[getAcceptors()]; + + ThreadPoolExecutor _threadPool = getThreadPool(); + for (int i = 0; i < _acceptorThreads.length; i++) + _threadPool.execute(new Acceptor(i)); + if (_server.isLowOnThreads()) + LOG.warn("insufficient threads configured for {}",this); + } + + LOG.info("Started {}",this); + } + + /* ------------------------------------------------------------ */ + @Override + protected void doStop() throws Exception + { + try + { + close(); + } + catch (IOException e) + { + LOG.warn("",e); + } + + super.doStop(); + + Thread[] acceptors; + synchronized (this) + { + acceptors = _acceptorThreads; + _acceptorThreads = null; + } + if (acceptors != null) + { + for (Thread thread : acceptors) + { + if (thread != null) + thread.interrupt(); + } + } + } + + /* ------------------------------------------------------------ */ + public void join() throws InterruptedException + { + Thread[] threads; + synchronized(this) + { + threads=_acceptorThreads; + } + if (threads != null) + for (Thread thread : threads) + if (thread != null) + thread.join(); + } + + /* ------------------------------------------------------------ */ + protected void configure(Socket socket) throws IOException + { + try + { + socket.setTcpNoDelay(true); + if (_soLingerTime >= 0) + socket.setSoLinger(true,_soLingerTime / 1000); + else + socket.setSoLinger(false,0); + } + catch (Exception e) + { + LOG.trace("",e); + } + } + + /* ------------------------------------------------------------ */ + public void customize(EndPoint endpoint, Request request) throws IOException + { + if (isForwarded()) + checkForwardedHeaders(endpoint,request); + } /* ------------------------------------------------------------ */ - /** - * @return The port to use when redirecting a request if a data constraint of confidential is - * required. See {@link org.eclipse.jetty.util.security.Constraint#getDataConstraint()} + protected void checkForwardedHeaders(EndPoint endpoint, Request request) throws IOException + { + HttpFields httpFields = request.getConnection().getRequestFields(); + + // Do SSL first + if (getForwardedCipherSuiteHeader()!=null) + { + String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader()); + if (cipher_suite!=null) + request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite); + } + if (getForwardedSslSessionIdHeader()!=null) + { + String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader()); + if(ssl_session_id!=null) + { + request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id); + request.setScheme(HttpSchemes.HTTPS); + } + } + + // Retrieving headers from the request + String forwardedHost = getLeftMostFieldValue(httpFields,getForwardedHostHeader()); + String forwardedServer = getLeftMostFieldValue(httpFields,getForwardedServerHeader()); + String forwardedFor = getLeftMostFieldValue(httpFields,getForwardedForHeader()); + String forwardedProto = getLeftMostFieldValue(httpFields,getForwardedProtoHeader()); + + if (_hostHeader != null) + { + // Update host header + httpFields.put(HttpHeaders.HOST_BUFFER,_hostHeader); + request.setServerName(null); + request.setServerPort(-1); + request.getServerName(); + } + else if (forwardedHost != null) + { + // Update host header + httpFields.put(HttpHeaders.HOST_BUFFER,forwardedHost); + request.setServerName(null); + request.setServerPort(-1); + request.getServerName(); + } + else if (forwardedServer != null) + { + // Use provided server name + request.setServerName(forwardedServer); + } + + if (forwardedFor != null) + { + request.setRemoteAddr(forwardedFor); + InetAddress inetAddress = null; + + if (_useDNS) + { + try + { + inetAddress = InetAddress.getByName(forwardedFor); + } + catch (UnknownHostException e) + { + LOG.trace("",e); + } + } + + request.setRemoteHost(inetAddress == null?forwardedFor:inetAddress.getHostName()); + } + + if (forwardedProto != null) + { + request.setScheme(forwardedProto); + } + } + + /* ------------------------------------------------------------ */ + protected String getLeftMostFieldValue(HttpFields fields, String header) + { + if (header == null) + return null; + + String headerValue = fields.getStringField(header); + + if (headerValue == null) + return null; + + int commaIndex = headerValue.indexOf(','); + + if (commaIndex == -1) + { + // Single value + return headerValue; + } + + // The left-most value is the farthest downstream client + return headerValue.substring(0,commaIndex); + } + + /* ------------------------------------------------------------ */ + public void persist(EndPoint endpoint) throws IOException + { + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#getConfidentialPort() */ - int getConfidentialPort(); - + public int getConfidentialPort() + { + return _confidentialPort; + } + + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#getConfidentialScheme() + */ + public String getConfidentialScheme() + { + return _confidentialScheme; + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#isConfidential(org.eclipse.jetty.server .Request) + */ + public boolean isIntegral(Request request) + { + return false; + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#getConfidentialPort() + */ + public int getIntegralPort() + { + return _integralPort; + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#getIntegralScheme() + */ + public String getIntegralScheme() + { + return _integralScheme; + } + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.server.Connector#isConfidential(org.eclipse.jetty.server.Request) + */ + public boolean isConfidential(Request request) + { + return _forwarded && request.getScheme().equalsIgnoreCase(HttpSchemes.HTTPS); + } /* ------------------------------------------------------------ */ /** - * @return The schema to use when redirecting a request if a data constraint of confidential is - * required. See {@link org.eclipse.jetty.util.security.Constraint#getDataConstraint()} + * @param confidentialPort + * The confidentialPort to set. */ - String getConfidentialScheme(); - + public void setConfidentialPort(int confidentialPort) + { + _confidentialPort = confidentialPort; + } + + /* ------------------------------------------------------------ */ + /** + * @param confidentialScheme + * The confidentialScheme to set. + */ + public void setConfidentialScheme(String confidentialScheme) + { + _confidentialScheme = confidentialScheme; + } + /* ------------------------------------------------------------ */ /** - * @param request A request - * @return true if the request is confidential. This normally means the https schema has been used. + * @param integralPort + * The integralPort to set. + */ + public void setIntegralPort(int integralPort) + { + _integralPort = integralPort; + } + + /* ------------------------------------------------------------ */ + /** + * @param integralScheme + * The integralScheme to set. */ - boolean isConfidential(Request request); + public void setIntegralScheme(String integralScheme) + { + _integralScheme = integralScheme; + } + + /* ------------------------------------------------------------ */ + protected abstract void accept(int acceptorID) throws IOException, InterruptedException; + + /* ------------------------------------------------------------ */ + public void stopAccept(int acceptorID) throws Exception + { + } /* ------------------------------------------------------------ */ - /** Customize a request for an endpoint. - * Called on every request to allow customization of the request for - * the particular endpoint (eg security properties from a SSL connection). - * @param endpoint - * @param request - * @throws IOException + public boolean getResolveNames() + { + return _useDNS; + } + + /* ------------------------------------------------------------ */ + public void setResolveNames(boolean resolve) + { + _useDNS = resolve; + } + + /* ------------------------------------------------------------ */ + /** + * Is reverse proxy handling on? + * + * @return true if this connector is checking the x-forwarded-for/host/server headers */ - void customize(EndPoint endpoint, Request request) throws IOException; + public boolean isForwarded() + { + return _forwarded; + } /* ------------------------------------------------------------ */ - /** Persist an endpoint. - * Called after every request if the connection is to remain open. - * @param endpoint - * @throws IOException + /** + * Set reverse proxy handling. If set to true, then the X-Forwarded headers (or the headers set in their place) are looked for to set the request protocol, + * host, server and client ip. + * + * @param check + * true if this connector is checking the x-forwarded-for/host/server headers + * @see #setForwardedForHeader(String) + * @see #setForwardedHostHeader(String) + * @see #setForwardedProtoHeader(String) + * @see #setForwardedServerHeader(String) */ - void persist(EndPoint endpoint) throws IOException; - + public void setForwarded(boolean check) + { + if (check) + LOG.debug("{} is forwarded",this); + _forwarded = check; + } + /* ------------------------------------------------------------ */ - /** - * @return The hostname representing the interface to which - * this connector will bind, or null for all interfaces. - */ - String getHost(); - - /* ------------------------------------------------------------ */ - /** - * Set the hostname of the interface to bind to. - * @param hostname The hostname representing the interface to which - * this connector will bind, or null for all interfaces. - */ - void setHost(String hostname); + public String getHostHeader() + { + return _hostHeader; + } /* ------------------------------------------------------------ */ /** - * @param port The port to listen of for connections or 0 if any available - * port may be used. + * Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}. + * This value is only used if {@link #isForwarded()} is true. + * + * @param hostHeader + * The value of the host header to force. */ - void setPort(int port); - + public void setHostHeader(String hostHeader) + { + _hostHeader = hostHeader; + } + + /* ------------------------------------------------------------ */ + /* + * + * @see #setForwarded(boolean) + */ + public String getForwardedHostHeader() + { + return _forwardedHostHeader; + } + /* ------------------------------------------------------------ */ /** - * @return The configured port for the connector or 0 if any available - * port may be used. + * @param forwardedHostHeader + * The header name for forwarded hosts (default x-forwarded-host) + * @see #setForwarded(boolean) + */ + public void setForwardedHostHeader(String forwardedHostHeader) + { + _forwardedHostHeader = forwardedHostHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @return the header name for forwarded server. + * @see #setForwarded(boolean) */ - int getPort(); - + public String getForwardedServerHeader() + { + return _forwardedServerHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @param forwardedServerHeader + * The header name for forwarded server (default x-forwarded-server) + * @see #setForwarded(boolean) + */ + public void setForwardedServerHeader(String forwardedServerHeader) + { + _forwardedServerHeader = forwardedServerHeader; + } + /* ------------------------------------------------------------ */ /** - * @return The actual port the connector is listening on or - * -1 if it has not been opened, or -2 if it has been closed. + * @see #setForwarded(boolean) + */ + public String getForwardedForHeader() + { + return _forwardedForHeader; + } + + /* ------------------------------------------------------------ */ + /** + * @param forwardedRemoteAddressHeader + * The header name for forwarded for (default x-forwarded-for) + * @see #setForwarded(boolean) */ - int getLocalPort(); - + public void setForwardedForHeader(String forwardedRemoteAddressHeader) + { + _forwardedForHeader = forwardedRemoteAddressHeader; + } + + /* ------------------------------------------------------------ */ + /** + * Get the forwardedProtoHeader. + * + * @return the forwardedProtoHeader (default X-Forwarded-For) + * @see #setForwarded(boolean) + */ + public String getForwardedProtoHeader() + { + return _forwardedProtoHeader; + } + /* ------------------------------------------------------------ */ /** - * @return Max Idle time for connections in milliseconds + * Set the forwardedProtoHeader. + * + * @param forwardedProtoHeader + * the forwardedProtoHeader to set (default X-Forwarded-For) + * @see #setForwarded(boolean) */ - int getMaxIdleTime(); - + public void setForwardedProtoHeader(String forwardedProtoHeader) + { + _forwardedProtoHeader = forwardedProtoHeader; + } + + /* ------------------------------------------------------------ */ /** - * @param ms Max Idle time for connections in milliseconds + * @return The header name holding a forwarded cipher suite (default null) */ - void setMaxIdleTime(int ms); - + public String getForwardedCipherSuiteHeader() + { + return _forwardedCipherSuiteHeader; + } + /* ------------------------------------------------------------ */ - int getLowResourceMaxIdleTime(); - void setLowResourceMaxIdleTime(int ms); - + /** + * @param forwardedCipherSuite + * The header name holding a forwarded cipher suite (default null) + */ + public void setForwardedCipherSuiteHeader(String forwardedCipherSuite) + { + _forwardedCipherSuiteHeader = forwardedCipherSuite; + } + + /* ------------------------------------------------------------ */ + /** + * @return The header name holding a forwarded SSL Session ID (default null) + */ + public String getForwardedSslSessionIdHeader() + { + return _forwardedSslSessionIdHeader; + } + /* ------------------------------------------------------------ */ /** - * @return the underlying socket, channel, buffer etc. for the connector. + * @param forwardedSslSessionId + * The header name holding a forwarded SSL Session ID (default null) */ - Object getConnection(); - - + public void setForwardedSslSessionIdHeader(String forwardedSslSessionId) + { + _forwardedSslSessionIdHeader = forwardedSslSessionId; + } + + public int getRequestBufferSize() + { + return _buffers.getRequestBufferSize(); + } + + public void setRequestBufferSize(int requestBufferSize) + { + _buffers.setRequestBufferSize(requestBufferSize); + } + + public int getRequestHeaderSize() + { + return _buffers.getRequestHeaderSize(); + } + + public void setRequestHeaderSize(int requestHeaderSize) + { + _buffers.setRequestHeaderSize(requestHeaderSize); + } + + public int getResponseBufferSize() + { + return _buffers.getResponseBufferSize(); + } + + public void setResponseBufferSize(int responseBufferSize) + { + _buffers.setResponseBufferSize(responseBufferSize); + } + + public int getResponseHeaderSize() + { + return _buffers.getResponseHeaderSize(); + } + + public void setResponseHeaderSize(int responseHeaderSize) + { + _buffers.setResponseHeaderSize(responseHeaderSize); + } + + public Type getRequestBufferType() + { + return _buffers.getRequestBufferType(); + } + + public Type getRequestHeaderType() + { + return _buffers.getRequestHeaderType(); + } + + public Type getResponseBufferType() + { + return _buffers.getResponseBufferType(); + } + + public Type getResponseHeaderType() + { + return _buffers.getResponseHeaderType(); + } + + public void setRequestBuffers(Buffers requestBuffers) + { + _buffers.setRequestBuffers(requestBuffers); + } + + public void setResponseBuffers(Buffers responseBuffers) + { + _buffers.setResponseBuffers(responseBuffers); + } + + public Buffers getRequestBuffers() + { + return _buffers.getRequestBuffers(); + } + + public Buffers getResponseBuffers() + { + return _buffers.getResponseBuffers(); + } + + public int getMaxBuffers() + { + return _buffers.getMaxBuffers(); + } + /* ------------------------------------------------------------ */ - /** - * @return true if names resolution should be done. - */ - boolean getResolveNames(); - - + @Override + public String toString() + { + return String.format("%s@%s:%d", + getClass().getSimpleName(), + getHost()==null?"0.0.0.0":getHost(), + getLocalPort()<=0?getPort():getLocalPort()); + } /* ------------------------------------------------------------ */ - /** Check if low on resources. - * For most connectors, low resources is measured by calling - * {@link Server#isLowOnThreads()} on the connector threadpool - * or the server threadpool if there is no connector threadpool. - * <p> - * For blocking connectors, low resources is used to trigger - * usage of {@link #getLowResourceMaxIdleTime()} for the timeout - * of an idle connection. - * <p> - * for non-blocking connectors, the number of connections is - * used instead of this method, to select the timeout of an - * idle connection. - * <p> - * For all connectors, low resources is used to trigger the - * usage of {@link #getLowResourceMaxIdleTime()} for read and - * write operations. - * - * @return true if this connector is low on resources. + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + private class Acceptor implements Runnable + { + int _acceptor = 0; + + Acceptor(int id) + { + _acceptor = id; + } + + /* ------------------------------------------------------------ */ + public void run() + { + Thread current = Thread.currentThread(); + String name; + synchronized (Connector.this) + { + if (_acceptorThreads == null) + return; + + _acceptorThreads[_acceptor] = current; + name = _acceptorThreads[_acceptor].getName(); + current.setName(name + " Acceptor" + _acceptor + " " + Connector.this); + } + int old_priority = current.getPriority(); + + try + { + current.setPriority(old_priority - _acceptorPriorityOffset); + while (isRunning() && getConnection() != null) + { + try + { + accept(_acceptor); + } + catch (EofException e) + { + LOG.trace("",e); + } + catch (IOException e) + { + LOG.trace("",e); + } + catch (InterruptedException x) + { + // Connector has been stopped + LOG.trace("",x); + } + catch (Throwable e) + { + LOG.warn("",e); + } + } + } + finally + { + current.setPriority(old_priority); + current.setName(name); + + synchronized (Connector.this) + { + if (_acceptorThreads != null) + _acceptorThreads[_acceptor] = null; + } + } + } + } + + /* ------------------------------------------------------------ */ + public String getName() + { + if (_name == null) + _name = (getHost() == null?"0.0.0.0":getHost()) + ":" + (getLocalPort() <= 0?getPort():getLocalPort()); + return _name; + } + + /* ------------------------------------------------------------ */ + public void setName(String name) + { + _name = name; + } + + /* ------------------------------------------------------------ */ + protected void connectionOpened(Connection connection) + { + } + + /* ------------------------------------------------------------ */ + protected void connectionUpgraded(Connection oldConnection, Connection newConnection) + { + } + + /* ------------------------------------------------------------ */ + protected void connectionClosed(Connection connection) + { + connection.onClose(); + } + + /* ------------------------------------------------------------ */ + /** + * @return the acceptorPriority */ - public boolean isLowResources(); + public int getAcceptorPriorityOffset() + { + return _acceptorPriorityOffset; + } + + /* ------------------------------------------------------------ */ + /** + * Set the priority offset of the acceptor threads. The priority is adjusted by this amount (default 0) to either favour the acceptance of new threads and + * newly active connections or to favour the handling of already dispatched connections. + * + * @param offset + * the amount to alter the priority of the acceptor threads. + */ + public void setAcceptorPriorityOffset(int offset) + { + _acceptorPriorityOffset = offset; + } + + /* ------------------------------------------------------------ */ + /** + * @return True if the the server socket will be opened in SO_REUSEADDR mode. + */ + public boolean getReuseAddress() + { + return _reuseAddress; + } + + /* ------------------------------------------------------------ */ + /** + * @param reuseAddress + * True if the the server socket will be opened in SO_REUSEADDR mode. + */ + public void setReuseAddress(boolean reuseAddress) + { + _reuseAddress = reuseAddress; + } + + /* ------------------------------------------------------------ */ + public final boolean isLowResources() + { + return _server.isLowOnThreads(); + } + + /* ------------------------------------------------------------ */ + private void updateNotEqual(AtomicLong valueHolder, long compare, long value) + { + long oldValue = valueHolder.get(); + while (compare != oldValue) + { + if (valueHolder.compareAndSet(oldValue,value)) + break; + oldValue = valueHolder.get(); + } + } + + // from old interface + public abstract void open() throws IOException; + public abstract void close() throws IOException; + public abstract int getLocalPort(); + public abstract Object getConnection(); }