view src/org/eclipse/jetty/server/Connector.java @ 1038:b71ad168fe34

rename Buffer.length() to remaining()
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 03 Nov 2016 22:16:11 -0600
parents 8c13b9224cff
children a8c92b0a08ed
line wrap: on
line source

//
//  ========================================================================
//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.server;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicLong;

import javax.servlet.ServletRequest;

import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.Buffers;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 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 abstract class Connector extends AggregateLifeCycle implements Dumpable, Runnable
{
	private static final Logger LOG = LoggerFactory.getLogger(Connector.class);

	private String _name;

	public final Server server;
	private String _host;
	public final int port;

	protected final int _maxIdleTime = 200000;
	protected int _soLingerTime = -1;

	// from child classes
	protected transient ServerSocketChannel _acceptChannel;

	protected Connector(Server server,int port) {
		this.server = server;
		this.port = port;
		server.connectors.add(this);
	}

	public final void setHost(String host)
	{
		_host = host;
	}

	public final String getHost()
	{
		return _host;
	}

	public final 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 final int getSoLingerTime()
	{
		return _soLingerTime;
	}

	/* ------------------------------------------------------------ */
	/**
	 * @param soLingerTime
	 *            The soLingerTime to set or -1 to disable.
	 */
	public final void setSoLingerTime(int soLingerTime)
	{
		_soLingerTime = soLingerTime;
	}

	@Override
	protected void doStart() throws Exception
	{
		super.doStart();

		// Start selector thread
		ThreadPoolExecutor _threadPool = server.threadPool;
		_threadPool.execute(this);
		if (server.isLowOnThreads())
			LOG.warn("insufficient threads configured for {}",this);

		LOG.info("Started {}",this);
	}

	@Override
	protected synchronized void doStop() throws Exception
	{
		try
		{
			if (_acceptChannel != null)
				_acceptChannel.close();
			_acceptChannel=null;
		}
		catch (IOException e)
		{
			LOG.warn("",e);
		}

		super.doStop();
	}


	protected final void configure(Socket socket) throws IOException
	{
		socket.setTcpNoDelay(true);
		if (_soLingerTime >= 0)
			socket.setSoLinger(true,_soLingerTime / 1000);
		else
			socket.setSoLinger(false,0);
	}

	public abstract void customize(AbstractHttpConnection con) throws IOException;

	public boolean isConfidential()
	{
		return false;
	}

	protected abstract void accept() throws IOException, InterruptedException;

	@Override
	public String toString()
	{
		return String.format("%s@%s:%d",
				getClass().getSimpleName(),
				getHost()==null?"0.0.0.0":getHost(),
				port);
	}


	@Override
	public void run()
	{
		Thread current = Thread.currentThread();
		String name = current.getName();
		current.setName(name + " Acceptor" + " " + Connector.this);

		try
		{
			while (isRunning() && _acceptChannel != null)
			{
				try
				{
					accept();
				}
				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.setName(name);
		}
	}

	public final String getName()
	{
		if (_name == null)
			_name = (getHost() == null?"0.0.0.0":getHost()) + ":" + port;
		return _name;
	}



	// from HttpBuffersImpl

	protected int _requestHeaderSize = 6*1024;
	protected int _requestBufferSize = 16*1024;
	private final int _responseHeaderSize = 6*1024;
	private final int _responseBufferSize = 32*1024;
	
	public final Buffers getRequestBuffers()
	{
		return new MyBuffers(_requestHeaderSize,_requestBufferSize);
	}
	
	public final Buffers getResponseBuffers()
	{
		return new MyBuffers(_responseHeaderSize,_responseBufferSize);
	}


	// my own buffers

	protected Buffer newBuffer(int size) {
		return new DirectNIOBuffer(size);
	}

	private class MyBuffers implements Buffers {
		private final int headerSize;
		private final int bufferSize;

		MyBuffers(int headerSize,int bufferSize) {
			this.headerSize = headerSize;
			this.bufferSize = bufferSize;
		}

		@Override
		public Buffer getHeader() {
			return new IndirectNIOBuffer(headerSize);
		}

		@Override
		public Buffer getBuffer() {
			return newBuffer(bufferSize);
		}

		@Override
		public Buffer getBuffer(int size) {
			return newBuffer(size);
		}
	}
}