view src/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java @ 1022:3718afd99988

HttpHeaders uses StringCache
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 01 Nov 2016 01:04:46 -0600
parents 4dc1e1a18661
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.ssl;

import java.io.IOException;
import java.nio.channels.SocketChannel;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.Buffers;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.io.nio.AsyncConnection;
import org.eclipse.jetty.io.nio.SslConnection;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.AsyncHttpConnection;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory;

/* ------------------------------------------------------------ */
/**
 * SslSelectChannelConnector.
 *
 * @org.apache.xbean.XBean element="sslConnector" description="Creates an NIO ssl connector"
 */
public final class SslSelectChannelConnector extends SelectChannelConnector
{
	private final SslContextFactory _sslContextFactory;

	/* ------------------------------------------------------------ */
	public SslSelectChannelConnector(Server server,int port)
	{
		this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH),server,port);
		setSoLingerTime(30000);
	}

	/* ------------------------------------------------------------ */
	/** Construct with explicit SslContextFactory.
	 * The SslContextFactory passed is added via {@link #addBean(Object)} so that 
	 * it's lifecycle may be managed with {@link AggregateLifeCycle}.
	 * @param sslContextFactory
	 */
	public SslSelectChannelConnector(SslContextFactory sslContextFactory,Server server,int port)
	{
		super(server,port);
		_sslContextFactory = sslContextFactory;
		addBean(_sslContextFactory);
		setSoLingerTime(30000);
	}

	@Override
	protected Buffer newBuffer(int size) {
		return new IndirectNIOBuffer(size);
	}


	/* ------------------------------------------------------------ */
	/**
	 * Allow the Listener a chance to customise the request. before the server
	 * does its stuff. <br>
	 * This allows the required attributes to be set for SSL requests. <br>
	 * The requirements of the Servlet specs are:
	 * <ul>
	 * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
	 * String (since Servlet Spec 3.0).</li>
	 * <li> an attribute named "javax.servlet.request.cipher_suite" of type
	 * String.</li>
	 * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
	 * <li> an attribute named "javax.servlet.request.X509Certificate" of type
	 * java.security.cert.X509Certificate[]. This is an array of objects of type
	 * X509Certificate, the order of this array is defined as being in ascending
	 * order of trust. The first certificate in the chain is the one set by the
	 * client, the next is the one used to authenticate the first, and so on.
	 * </li>
	 * </ul>
	 *
	 * @param endpoint
	 *                The Socket the request arrived on.
	 * @param request
	 *                HttpRequest to be customised.
	 */
	@Override
	public void customize(AbstractHttpConnection con) throws IOException
	{
		con._request.setScheme("https");
		super.customize(con);

		SslConnection.SslEndPoint sslEndpoint=(SslConnection.SslEndPoint)con._endp;
		SSLEngine sslEngine = sslEndpoint.getSslEngine();
		SSLSession sslSession = sslEngine.getSession();

		SslCertificates.customize(sslSession,con._endp,con._request);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslContextFactory()
	 */
	public SslContextFactory getSslContextFactory()
	{
		return _sslContextFactory;
	}

	/* ------------------------------------------------------------ */
	/**
	 * By default, we're confidential, given we speak SSL. But, if we've been
	 * told about an confidential port, and said port is not our port, then
	 * we're not. This allows separation of listeners providing INTEGRAL versus
	 * CONFIDENTIAL constraints, such as one SSL listener configured to require
	 * client certs providing CONFIDENTIAL, whereas another SSL listener not
	 * requiring client certs providing mere INTEGRAL constraints.
	 */
	@Override
	public boolean isConfidential()
	{
		return true;
	}

	@Override
	public AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint)
	{
		try
		{
			SSLEngine engine = createSSLEngine(channel);
			SslConnection connection = new SslConnection(engine, endpoint);
			AsyncHttpConnection delegate = (AsyncHttpConnection)super.newConnection(channel, connection.getSslEndPoint());
			connection.getSslEndPoint().setConnection(delegate);
			connection.setAllowRenegotiate(_sslContextFactory.isAllowRenegotiate());
			return connection;
		}
		catch (IOException e)
		{
			throw new RuntimeIOException(e);
		}
	}

	/* ------------------------------------------------------------ */
	/**
	 * @param channel A channel which if passed is used as to extract remote
	 * host and port for the purposes of SSL session caching
	 * @return A SSLEngine for a new or cached SSL Session
	 * @throws IOException if the SSLEngine cannot be created
	 */
	private SSLEngine createSSLEngine(SocketChannel channel) throws IOException
	{
		String peerHost = channel.socket().getInetAddress().getHostAddress();
		int peerPort = channel.socket().getPort();
		SSLEngine engine = _sslContextFactory.newSslEngine(peerHost, peerPort);
		engine.setUseClientMode(false);
		return engine;
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.nio.SelectChannelConnector#doStart()
	 */
	@Override
	protected void doStart() throws Exception
	{
		_sslContextFactory.checkKeyStore();
		_sslContextFactory.start();

		SSLEngine sslEngine = _sslContextFactory.newSslEngine();

		sslEngine.setUseClientMode(false);

		SSLSession sslSession = sslEngine.getSession();

		if (_requestHeaderSize < sslSession.getApplicationBufferSize())
			_requestHeaderSize = sslSession.getApplicationBufferSize();
		if (_requestBufferSize < sslSession.getApplicationBufferSize())
			_requestBufferSize = sslSession.getApplicationBufferSize();

		super.doStart();
	}

}