Merge branch 'jetty-9' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project into jetty-9
This commit is contained in:
commit
03521a9a99
|
@ -30,7 +30,6 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
|
|||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
@ -42,7 +41,12 @@ public class LikeJettyXml
|
|||
String jetty_home = System.getProperty("jetty.home","../jetty-distribution/target/distribution");
|
||||
System.setProperty("jetty.home",jetty_home);
|
||||
|
||||
Server server = new Server();
|
||||
// Setup Threadpool
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
threadPool.setMaxThreads(500);
|
||||
|
||||
Server server = new Server(threadPool);
|
||||
server.manage(threadPool);
|
||||
server.setDumpAfterStart(true);
|
||||
server.setDumpBeforeStop(true);
|
||||
|
||||
|
@ -53,24 +57,19 @@ public class LikeJettyXml
|
|||
server.addBean(mbContainer,true);
|
||||
mbContainer.addBean(new Log());
|
||||
|
||||
// Setup Threadpool
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
threadPool.setMaxThreads(500);
|
||||
server.setThreadPool(threadPool);
|
||||
|
||||
// Setup Connectors
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(server);
|
||||
connector.setPort(8080);
|
||||
connector.setIdleTimeout(30000);
|
||||
connector.setConfidentialPort(8443);
|
||||
connector.getConnectionFactory().getHttpConfig().setConfidentialPort(8443);
|
||||
// TODO connector.setStatsOn(false);
|
||||
|
||||
server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
|
||||
SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector();
|
||||
SelectChannelConnector ssl_connector = new SelectChannelConnector(server,true);
|
||||
ssl_connector.setPort(8443);
|
||||
SslContextFactory cf = ssl_connector.getSslContextFactory();
|
||||
SslContextFactory cf = ssl_connector.getConnectionFactory().getSslContextFactory();
|
||||
cf.setKeyStorePath(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
cf.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
|
|
|
@ -16,9 +16,7 @@ package org.eclipse.jetty.embedded;
|
|||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -31,22 +29,20 @@ public class ManyConnectors
|
|||
{
|
||||
Server server = new Server();
|
||||
|
||||
SelectChannelConnector connector0 = new SelectChannelConnector();
|
||||
SelectChannelConnector connector0 = new SelectChannelConnector(server);
|
||||
connector0.setPort(8080);
|
||||
connector0.setIdleTimeout(30000);
|
||||
connector0.setRequestHeaderSize(8192);
|
||||
|
||||
SelectChannelConnector connector1 = new SelectChannelConnector();
|
||||
SelectChannelConnector connector1 = new SelectChannelConnector(server);
|
||||
connector1.setHost("127.0.0.1");
|
||||
connector1.setPort(8888);
|
||||
connector1.setExecutor(new QueuedThreadPool(20));
|
||||
connector1.setName("admin");
|
||||
|
||||
SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector();
|
||||
SelectChannelConnector ssl_connector = new SelectChannelConnector(server,true);
|
||||
String jetty_home = System.getProperty("jetty.home","../jetty-distribution/target/distribution");
|
||||
System.setProperty("jetty.home",jetty_home);
|
||||
ssl_connector.setPort(8443);
|
||||
SslContextFactory cf = ssl_connector.getSslContextFactory();
|
||||
SslContextFactory cf = ssl_connector.getConnectionFactory().getSslContextFactory();
|
||||
cf.setKeyStorePath(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
cf.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
|
|
|
@ -15,10 +15,10 @@ package org.eclipse.jetty.embedded;
|
|||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ public class ManyContexts
|
|||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(server);
|
||||
connector.setPort(8080);
|
||||
server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
|
|
|
@ -23,7 +23,6 @@ import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
|||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
||||
public class ManyServletContexts
|
||||
{
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
package org.eclipse.jetty.embedded;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
public class OneWebApp
|
||||
|
@ -24,7 +24,7 @@ public class OneWebApp
|
|||
{
|
||||
Server server = new Server();
|
||||
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(server);
|
||||
connector.setPort(Integer.getInteger("jetty.port",8080).intValue());
|
||||
server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
|
|
|
@ -27,13 +27,13 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.LocalHttpConnector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.GzipHandler;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
@ -56,14 +56,13 @@ public class GzipHandlerTest
|
|||
"et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
|
||||
|
||||
private Server _server;
|
||||
private LocalHttpConnector _connector;
|
||||
private LocalConnector _connector;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
|
||||
_connector = new LocalHttpConnector();
|
||||
_connector = new LocalConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
|
||||
Handler testHandler = new AbstractHandler()
|
||||
|
|
|
@ -21,6 +21,16 @@
|
|||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
|
|
@ -23,26 +23,26 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* <p>A convenience base implementation of {@link AsyncConnection}.</p>
|
||||
* <p>This class uses the capabilities of the {@link AsyncEndPoint} API to provide a
|
||||
* <p>A convenience base implementation of {@link Connection}.</p>
|
||||
* <p>This class uses the capabilities of the {@link EndPoint} API to provide a
|
||||
* more traditional style of async reading. A call to {@link #fillInterested()}
|
||||
* will schedule a callback to {@link #onFillable()} or {@link #onFillInterestedFailed(Throwable)}
|
||||
* as appropriate.</p>
|
||||
*/
|
||||
public abstract class AbstractAsyncConnection implements AsyncConnection
|
||||
public abstract class AbstractConnection implements Connection
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractAsyncConnection.class);
|
||||
private static final Logger LOG = Log.getLogger(AbstractConnection.class);
|
||||
|
||||
private final AtomicBoolean _readInterested = new AtomicBoolean();
|
||||
private final AsyncEndPoint _endp;
|
||||
private final EndPoint _endp;
|
||||
private final Callback<Void> _readCallback;
|
||||
|
||||
public AbstractAsyncConnection(AsyncEndPoint endp, Executor executor)
|
||||
public AbstractConnection(EndPoint endp, Executor executor)
|
||||
{
|
||||
this(endp, executor, false);
|
||||
}
|
||||
|
||||
public AbstractAsyncConnection(AsyncEndPoint endp, Executor executor, final boolean executeOnlyFailure)
|
||||
public AbstractConnection(EndPoint endp, Executor executor, final boolean executeOnlyFailure)
|
||||
{
|
||||
if (executor == null)
|
||||
throw new IllegalArgumentException("Executor must not be null!");
|
||||
|
@ -72,7 +72,7 @@ public abstract class AbstractAsyncConnection implements AsyncConnection
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x", getClass().getSimpleName(), AbstractAsyncConnection.this.hashCode());
|
||||
return String.format("%s@%x", getClass().getSimpleName(), AbstractConnection.this.hashCode());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -130,16 +130,16 @@ public abstract class AbstractAsyncConnection implements AsyncConnection
|
|||
public void onOpen()
|
||||
{
|
||||
LOG.debug("{} opened",this);
|
||||
fillInterested();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
LOG.debug("{} closed",this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncEndPoint getEndPoint()
|
||||
public EndPoint getEndPoint()
|
||||
{
|
||||
return _endp;
|
||||
}
|
|
@ -1,20 +1,67 @@
|
|||
package org.eclipse.jetty.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadPendingException;
|
||||
import java.nio.channels.WritePendingException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public abstract class AbstractEndPoint implements EndPoint
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractEndPoint.class);
|
||||
private final long _created=System.currentTimeMillis();
|
||||
private final InetSocketAddress _local;
|
||||
private final InetSocketAddress _remote;
|
||||
|
||||
private final ScheduledExecutorService _scheduler;
|
||||
private final AtomicReference<Future<?>> _timeout = new AtomicReference<>();
|
||||
private final Runnable _idleTask = new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
long idleLeft=checkIdleTimeout();
|
||||
if (idleLeft>=0)
|
||||
scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private volatile long _idleTimeout;
|
||||
private volatile long _idleTimestamp=System.currentTimeMillis();
|
||||
private volatile Connection _connection;
|
||||
|
||||
private final FillInterest _fillInterest = new FillInterest()
|
||||
{
|
||||
@Override
|
||||
protected boolean needsFill() throws IOException
|
||||
{
|
||||
return AbstractEndPoint.this.needsFill();
|
||||
}
|
||||
};
|
||||
private final WriteFlusher _writeFlusher = new WriteFlusher(this)
|
||||
{
|
||||
@Override
|
||||
protected void onIncompleteFlushed()
|
||||
{
|
||||
AbstractEndPoint.this.onIncompleteFlush();
|
||||
}
|
||||
};
|
||||
|
||||
protected AbstractEndPoint(InetSocketAddress local,InetSocketAddress remote)
|
||||
protected AbstractEndPoint(ScheduledExecutorService scheduler,InetSocketAddress local,InetSocketAddress remote)
|
||||
{
|
||||
_local=local;
|
||||
_remote=remote;
|
||||
_scheduler=scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,15 +105,117 @@ public abstract class AbstractEndPoint implements EndPoint
|
|||
_idleTimestamp=System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection()
|
||||
{
|
||||
return _connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConnection(Connection connection)
|
||||
{
|
||||
_connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
LOG.debug("onOpen {}",this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
LOG.debug("onClose {}",this);
|
||||
_writeFlusher.onClose();
|
||||
_fillInterest.onClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void fillInterested(C context, Callback<C> callback) throws IllegalStateException
|
||||
{
|
||||
_fillInterest.register(context, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws IllegalStateException
|
||||
{
|
||||
_writeFlusher.write(context, callback, buffers);
|
||||
}
|
||||
|
||||
protected abstract void onIncompleteFlush();
|
||||
|
||||
protected abstract boolean needsFill() throws IOException;
|
||||
|
||||
protected FillInterest getFillInterest()
|
||||
{
|
||||
return _fillInterest;
|
||||
}
|
||||
|
||||
protected WriteFlusher getWriteFlusher()
|
||||
{
|
||||
return _writeFlusher;
|
||||
}
|
||||
|
||||
protected void scheduleIdleTimeout(long delay)
|
||||
{
|
||||
Future<?> newTimeout = null;
|
||||
if (isOpen() && delay > 0 && _scheduler!=null)
|
||||
newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS);
|
||||
Future<?> oldTimeout = _timeout.getAndSet(newTimeout);
|
||||
if (oldTimeout != null)
|
||||
oldTimeout.cancel(false);
|
||||
}
|
||||
|
||||
protected long checkIdleTimeout()
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
long idleTimestamp = getIdleTimestamp();
|
||||
long idleTimeout = getIdleTimeout();
|
||||
long idleElapsed = System.currentTimeMillis() - idleTimestamp;
|
||||
long idleLeft = idleTimeout - idleElapsed;
|
||||
|
||||
LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
|
||||
|
||||
if (isOutputShutdown() || _fillInterest.isInterested() || _writeFlusher.isInProgress())
|
||||
{
|
||||
if (idleTimestamp != 0 && idleTimeout > 0)
|
||||
{
|
||||
if (idleLeft <= 0)
|
||||
{
|
||||
LOG.debug("{} idle timeout expired", this);
|
||||
|
||||
TimeoutException timeout = new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms");
|
||||
_fillInterest.onFail(timeout);
|
||||
_writeFlusher.onFail(timeout);
|
||||
|
||||
if (isOutputShutdown())
|
||||
close();
|
||||
notIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idleLeft>=0?idleLeft:0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{%s<r-l>%s,o=%b,os=%b}",
|
||||
|
||||
return String.format("%s@%x{%s<r-l>%s,o=%b,is=%b,os=%b,fi=%s,wf=%s}{%s}",
|
||||
getClass().getSimpleName(),
|
||||
hashCode(),
|
||||
getRemoteAddress(),
|
||||
getLocalAddress(),
|
||||
isOpen(),
|
||||
isOutputShutdown());
|
||||
isInputShutdown(),
|
||||
isOutputShutdown(),
|
||||
_fillInterest,
|
||||
_writeFlusher,
|
||||
getConnection());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
package org.eclipse.jetty.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class AsyncByteArrayEndPoint extends ByteArrayEndPoint implements AsyncEndPoint, Runnable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AsyncByteArrayEndPoint.class);
|
||||
|
||||
private final ReadInterest _readInterest = new ReadInterest()
|
||||
{
|
||||
@Override
|
||||
protected boolean needsFill() throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
throw new ClosedChannelException();
|
||||
return _in == null || BufferUtil.hasContent(_in);
|
||||
}
|
||||
};
|
||||
private final WriteFlusher _writeFlusher = new WriteFlusher(this)
|
||||
{
|
||||
@Override
|
||||
protected void onIncompleteFlushed()
|
||||
{
|
||||
// Don't need to do anything here as takeOutput does the signalling.
|
||||
}
|
||||
};
|
||||
private final AtomicReference<Future<?>> _timeout = new AtomicReference<>();
|
||||
private final ScheduledExecutorService _scheduler;
|
||||
private volatile AsyncConnection _connection;
|
||||
|
||||
public AsyncByteArrayEndPoint(ScheduledExecutorService scheduler, long idleTimeout)
|
||||
{
|
||||
_scheduler = scheduler;
|
||||
setIdleTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
public AsyncByteArrayEndPoint(ScheduledExecutorService timer, long idleTimeout, byte[] input, int outputSize)
|
||||
{
|
||||
super(input, outputSize);
|
||||
_scheduler = timer;
|
||||
setIdleTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
public AsyncByteArrayEndPoint(ScheduledExecutorService timer, long idleTimeout, String input, int outputSize)
|
||||
{
|
||||
super(input, outputSize);
|
||||
_scheduler = timer;
|
||||
setIdleTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdleTimeout(long idleTimeout)
|
||||
{
|
||||
super.setIdleTimeout(idleTimeout);
|
||||
scheduleIdleTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
private void scheduleIdleTimeout(long delay)
|
||||
{
|
||||
Future<?> newTimeout = isOpen() && delay > 0 ? _scheduler.schedule(this, delay, TimeUnit.MILLISECONDS) : null;
|
||||
Future<?> oldTimeout = _timeout.getAndSet(newTimeout);
|
||||
if (oldTimeout != null)
|
||||
oldTimeout.cancel(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
long idleTimestamp = getIdleTimestamp();
|
||||
long idleTimeout = getIdleTimeout();
|
||||
long idleElapsed = System.currentTimeMillis() - idleTimestamp;
|
||||
long idleLeft = idleTimeout - idleElapsed;
|
||||
|
||||
if (isOutputShutdown() || _readInterest.isInterested() || _writeFlusher.isWriting())
|
||||
{
|
||||
if (idleTimestamp != 0 && idleTimeout > 0)
|
||||
{
|
||||
if (idleLeft < 0)
|
||||
{
|
||||
if (isOutputShutdown())
|
||||
close();
|
||||
notIdle();
|
||||
|
||||
TimeoutException timeout = new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms");
|
||||
_readInterest.failed(timeout);
|
||||
_writeFlusher.failed(timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
scheduleIdleTimeout(idleLeft > 0 ? idleLeft : idleTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(ByteBuffer in)
|
||||
{
|
||||
super.setInput(in);
|
||||
if (in == null || BufferUtil.hasContent(in))
|
||||
_readInterest.readable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer takeOutput()
|
||||
{
|
||||
ByteBuffer b = super.takeOutput();
|
||||
_writeFlusher.completeWrite();
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOutput(ByteBuffer out)
|
||||
{
|
||||
super.setOutput(out);
|
||||
_writeFlusher.completeWrite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
_readInterest.close();
|
||||
_writeFlusher.close();
|
||||
super.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void fillInterested(C context, Callback<C> callback) throws IllegalStateException
|
||||
{
|
||||
_readInterest.register(context, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws IllegalStateException
|
||||
{
|
||||
_writeFlusher.write(context, callback, buffers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncConnection getAsyncConnection()
|
||||
{
|
||||
return _connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsyncConnection(AsyncConnection connection)
|
||||
{
|
||||
_connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2004-2012 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.io;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadPendingException;
|
||||
import java.nio.channels.WritePendingException;
|
||||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.ExecutorCallback;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
|
||||
/**
|
||||
* <p>{@link AsyncEndPoint} add asynchronous scheduling methods to {@link EndPoint}.</p>
|
||||
* <p>The design of these has been influenced by NIO.2 Futures and Completion
|
||||
* handlers, but does not use those actual interfaces because they have
|
||||
* some inefficiencies.</p>
|
||||
* <p>This class will frequently be used in conjunction with some of the utility
|
||||
* implementations of {@link Callback}, such as {@link FutureCallback} and
|
||||
* {@link ExecutorCallback}. Examples are:</p>
|
||||
*
|
||||
* <h3>Blocking Read</h3>
|
||||
* <p>A FutureCallback can be used to block until an endpoint is ready to be filled
|
||||
* from:
|
||||
* <blockquote><pre>
|
||||
* FutureCallback<String> future = new FutureCallback<>();
|
||||
* endpoint.fillInterested("ContextObj",future);
|
||||
* ...
|
||||
* String context = future.get(); // This blocks
|
||||
* int filled=endpoint.fill(mybuffer);
|
||||
* </pre></blockquote></p>
|
||||
*
|
||||
* <h3>Dispatched Read</h3>
|
||||
* <p>By using a different callback, the read can be done asynchronously in its own dispatched thread:
|
||||
* <blockquote><pre>
|
||||
* endpoint.fillInterested("ContextObj",new ExecutorCallback<String>(executor)
|
||||
* {
|
||||
* public void onCompleted(String context)
|
||||
* {
|
||||
* int filled=endpoint.fill(mybuffer);
|
||||
* ...
|
||||
* }
|
||||
* public void onFailed(String context,Throwable cause) {...}
|
||||
* });
|
||||
* </pre></blockquote></p>
|
||||
* <p>The executor callback can also be customized to not dispatch in some circumstances when
|
||||
* it knows it can use the callback thread and does not need to dispatch.</p>
|
||||
*
|
||||
* <h3>Blocking Write</h3>
|
||||
* <p>The write contract is that the callback complete is not called until all data has been
|
||||
* written or there is a failure. For blocking this looks like:
|
||||
* <blockquote><pre>
|
||||
* FutureCallback<String> future = new FutureCallback<>();
|
||||
* endpoint.write("ContextObj",future,headerBuffer,contentBuffer);
|
||||
* String context = future.get(); // This blocks
|
||||
* </pre></blockquote></p>
|
||||
*
|
||||
* <h3>Dispatched Write</h3>
|
||||
* <p>Note also that multiple buffers may be passed in write so that gather writes
|
||||
* can be done:
|
||||
* <blockquote><pre>
|
||||
* endpoint.write("ContextObj",new ExecutorCallback<String>(executor)
|
||||
* {
|
||||
* public void onCompleted(String context)
|
||||
* {
|
||||
* int filled=endpoint.fill(mybuffer);
|
||||
* ...
|
||||
* }
|
||||
* public void onFailed(String context,Throwable cause) {...}
|
||||
* },headerBuffer,contentBuffer);
|
||||
* </pre></blockquote></p>
|
||||
*/
|
||||
public interface AsyncEndPoint extends EndPoint
|
||||
{
|
||||
/**
|
||||
* <p>Requests callback methods to be invoked when a call to {@link #fill(ByteBuffer)} would return data or EOF.</p>
|
||||
*
|
||||
* @param context the context to return via the callback
|
||||
* @param callback the callback to call when an error occurs or we are readable.
|
||||
* @throws ReadPendingException if another read operation is concurrent.
|
||||
*/
|
||||
<C> void fillInterested(C context, Callback<C> callback) throws ReadPendingException;
|
||||
|
||||
/**
|
||||
* <p>Writes the given buffers via {@link #flush(ByteBuffer...)} and invokes callback methods when either
|
||||
* all the data has been flushed or an error occurs.</p>
|
||||
*
|
||||
* @param context the context to return via the callback
|
||||
* @param callback the callback to call when an error occurs or the write completed.
|
||||
* @param buffers one or more {@link ByteBuffer}s that will be flushed.
|
||||
* @throws WritePendingException if another write operation is concurrent.
|
||||
*/
|
||||
<C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws WritePendingException;
|
||||
|
||||
/**
|
||||
* @return the {@link AsyncConnection} associated with this {@link AsyncEndPoint}
|
||||
* @see #setAsyncConnection(AsyncConnection)
|
||||
*/
|
||||
AsyncConnection getAsyncConnection();
|
||||
|
||||
/**
|
||||
* @param connection the {@link AsyncConnection} associated with this {@link AsyncEndPoint}
|
||||
* @see #getAsyncConnection()
|
||||
*/
|
||||
void setAsyncConnection(AsyncConnection connection);
|
||||
|
||||
/**
|
||||
* <p>Callback method invoked when this {@link AsyncEndPoint} is opened.</p>
|
||||
* @see #onClose()
|
||||
*/
|
||||
void onOpen();
|
||||
|
||||
/**
|
||||
* <p>Callback method invoked when this {@link AsyncEndPoint} is close.</p>
|
||||
* @see #onOpen()
|
||||
*/
|
||||
void onClose();
|
||||
}
|
|
@ -16,10 +16,19 @@ package org.eclipse.jetty.io;
|
|||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -28,14 +37,16 @@ import org.eclipse.jetty.util.StringUtil;
|
|||
*/
|
||||
public class ByteArrayEndPoint extends AbstractEndPoint
|
||||
{
|
||||
static final Logger LOG = Log.getLogger(ByteArrayEndPoint.class);
|
||||
public final static InetSocketAddress NOIP=new InetSocketAddress(0);
|
||||
|
||||
|
||||
protected ByteBuffer _in;
|
||||
protected ByteBuffer _out;
|
||||
protected boolean _ishut;
|
||||
protected boolean _oshut;
|
||||
protected boolean _closed;
|
||||
protected boolean _growOutput;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -43,9 +54,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
*/
|
||||
public ByteArrayEndPoint()
|
||||
{
|
||||
super(NOIP,NOIP);
|
||||
_in=BufferUtil.EMPTY_BUFFER;
|
||||
_out=BufferUtil.allocate(1024);
|
||||
this(null,0,null,null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -54,9 +63,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
*/
|
||||
public ByteArrayEndPoint(byte[] input, int outputSize)
|
||||
{
|
||||
super(NOIP,NOIP);
|
||||
_in=input==null?null:ByteBuffer.wrap(input);
|
||||
_out=BufferUtil.allocate(outputSize);
|
||||
this(null,0,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -65,11 +72,55 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
*/
|
||||
public ByteArrayEndPoint(String input, int outputSize)
|
||||
{
|
||||
super(NOIP,NOIP);
|
||||
setInput(input);
|
||||
_out=BufferUtil.allocate(outputSize);
|
||||
this(null,0,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ByteArrayEndPoint(ScheduledExecutorService timer, long idleTimeoutMs)
|
||||
{
|
||||
this(timer,idleTimeoutMs,null,null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ByteArrayEndPoint(ScheduledExecutorService timer, long idleTimeoutMs, byte[] input, int outputSize)
|
||||
{
|
||||
this(timer,idleTimeoutMs,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ByteArrayEndPoint(ScheduledExecutorService timer, long idleTimeoutMs, String input, int outputSize)
|
||||
{
|
||||
this(timer,idleTimeoutMs,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ByteArrayEndPoint(ScheduledExecutorService timer, long idleTimeoutMs, ByteBuffer input, ByteBuffer output)
|
||||
{
|
||||
super(timer,NOIP,NOIP);
|
||||
_in=input==null?BufferUtil.EMPTY_BUFFER:input;
|
||||
_out=output==null?BufferUtil.allocate(1024):output;
|
||||
setIdleTimeout(idleTimeoutMs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void onIncompleteFlush()
|
||||
{
|
||||
// Don't need to do anything here as takeOutput does the signalling.
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected boolean needsFill() throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
throw new ClosedChannelException();
|
||||
return _in == null || BufferUtil.hasContent(_in);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -95,6 +146,8 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
public void setInput(ByteBuffer in)
|
||||
{
|
||||
_in = in;
|
||||
if (in == null || BufferUtil.hasContent(in))
|
||||
getFillInterest().fillable();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -135,6 +188,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
{
|
||||
ByteBuffer b=_out;
|
||||
_out=BufferUtil.allocate(b.capacity());
|
||||
getWriteFlusher().completeWrite();
|
||||
return b;
|
||||
}
|
||||
|
||||
|
@ -164,6 +218,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
public void setOutput(ByteBuffer out)
|
||||
{
|
||||
_out = out;
|
||||
getWriteFlusher().completeWrite();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -195,7 +250,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void shutdownInput() throws IOException
|
||||
private void shutdownInput()
|
||||
{
|
||||
_ishut=true;
|
||||
if (_oshut)
|
||||
|
@ -222,7 +277,6 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
public void close()
|
||||
{
|
||||
_closed=true;
|
||||
// TODO: for sbordet to fix - onClose(); Moved invocation to AsycnByteArrayEndPoint for now (GW)
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -299,6 +353,8 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
*/
|
||||
public void reset()
|
||||
{
|
||||
getFillInterest().onClose();
|
||||
getWriteFlusher().onClose();
|
||||
_ishut=false;
|
||||
_oshut=false;
|
||||
_closed=false;
|
||||
|
@ -334,5 +390,14 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
_growOutput=growOutput;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void setIdleTimeout(long idleTimeout)
|
||||
{
|
||||
super.setIdleTimeout(idleTimeout);
|
||||
scheduleIdleTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -22,10 +22,13 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.channels.ByteChannel;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.GatheringByteChannel;
|
||||
import java.nio.channels.ReadPendingException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.nio.channels.WritePendingException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
@ -42,10 +45,11 @@ public class ChannelEndPoint extends AbstractEndPoint
|
|||
private volatile boolean _ishut;
|
||||
private volatile boolean _oshut;
|
||||
|
||||
public ChannelEndPoint(SocketChannel channel) throws IOException
|
||||
public ChannelEndPoint(ScheduledExecutorService scheduler,SocketChannel channel) throws IOException
|
||||
{
|
||||
super((InetSocketAddress)channel.socket().getLocalSocketAddress(),
|
||||
(InetSocketAddress)channel.socket().getRemoteSocketAddress());
|
||||
super(scheduler,
|
||||
(InetSocketAddress)channel.socket().getLocalSocketAddress(),
|
||||
(InetSocketAddress)channel.socket().getRemoteSocketAddress());
|
||||
_channel = channel;
|
||||
_socket=channel.socket();
|
||||
}
|
||||
|
@ -195,4 +199,16 @@ public class ChannelEndPoint extends AbstractEndPoint
|
|||
{
|
||||
return _socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIncompleteFlush()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean needsFill() throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,27 +16,27 @@ package org.eclipse.jetty.io;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
|
||||
/**
|
||||
* <p>An {@link AsyncConnection} is associated to an {@link AsyncEndPoint} so that I/O events
|
||||
* happening on the {@link AsyncEndPoint} can be processed by the {@link AsyncConnection}.</p>
|
||||
* <p>A typical implementation of {@link AsyncConnection} overrides {@link #onOpen()} to
|
||||
* {@link AsyncEndPoint#fillInterested(Object, Callback) set read interest} on the {@link AsyncEndPoint},
|
||||
* and when the {@link AsyncEndPoint} signals read readyness, this {@link AsyncConnection} can
|
||||
* <p>An {@link Connection} is associated to an {@link EndPoint} so that I/O events
|
||||
* happening on the {@link EndPoint} can be processed by the {@link Connection}.</p>
|
||||
* <p>A typical implementation of {@link Connection} overrides {@link #onOpen()} to
|
||||
* {@link EndPoint#fillInterested(Object, Callback) set read interest} on the {@link EndPoint},
|
||||
* and when the {@link EndPoint} signals read readyness, this {@link Connection} can
|
||||
* read bytes from the network and interpret them.</p>
|
||||
*/
|
||||
public interface AsyncConnection
|
||||
public interface Connection
|
||||
{
|
||||
/**
|
||||
* <p>Callback method invoked when this {@link AsyncConnection} is opened.</p>
|
||||
* <p>Callback method invoked when this {@link Connection} is opened.</p>
|
||||
*/
|
||||
void onOpen();
|
||||
|
||||
/**
|
||||
* <p>Callback method invoked when this {@link AsyncConnection} is closed.</p>
|
||||
* <p>Callback method invoked when this {@link Connection} is closed.</p>
|
||||
*/
|
||||
void onClose();
|
||||
|
||||
/**
|
||||
* @return the {@link AsyncEndPoint} associated with this {@link AsyncConnection}
|
||||
* @return the {@link EndPoint} associated with this {@link Connection}
|
||||
*/
|
||||
AsyncEndPoint getEndPoint();
|
||||
EndPoint getEndPoint();
|
||||
}
|
|
@ -17,12 +17,78 @@ import java.io.Closeable;
|
|||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadPendingException;
|
||||
import java.nio.channels.WritePendingException;
|
||||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.ExecutorCallback;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* A transport EndPoint
|
||||
*
|
||||
* <h3>Asynchronous Methods</h3>
|
||||
* <p>The asynchronous scheduling methods of {@link EndPoint}
|
||||
* has been influenced by NIO.2 Futures and Completion
|
||||
* handlers, but does not use those actual interfaces because they have
|
||||
* some inefficiencies.</p>
|
||||
* <p>This class will frequently be used in conjunction with some of the utility
|
||||
* implementations of {@link Callback}, such as {@link FutureCallback} and
|
||||
* {@link ExecutorCallback}. Examples are:</p>
|
||||
*
|
||||
* <h3>Blocking Read</h3>
|
||||
* <p>A FutureCallback can be used to block until an endpoint is ready to be filled
|
||||
* from:
|
||||
* <blockquote><pre>
|
||||
* FutureCallback<String> future = new FutureCallback<>();
|
||||
* endpoint.fillInterested("ContextObj",future);
|
||||
* ...
|
||||
* String context = future.get(); // This blocks
|
||||
* int filled=endpoint.fill(mybuffer);
|
||||
* </pre></blockquote></p>
|
||||
*
|
||||
* <h3>Dispatched Read</h3>
|
||||
* <p>By using a different callback, the read can be done asynchronously in its own dispatched thread:
|
||||
* <blockquote><pre>
|
||||
* endpoint.fillInterested("ContextObj",new ExecutorCallback<String>(executor)
|
||||
* {
|
||||
* public void onCompleted(String context)
|
||||
* {
|
||||
* int filled=endpoint.fill(mybuffer);
|
||||
* ...
|
||||
* }
|
||||
* public void onFailed(String context,Throwable cause) {...}
|
||||
* });
|
||||
* </pre></blockquote></p>
|
||||
* <p>The executor callback can also be customized to not dispatch in some circumstances when
|
||||
* it knows it can use the callback thread and does not need to dispatch.</p>
|
||||
*
|
||||
* <h3>Blocking Write</h3>
|
||||
* <p>The write contract is that the callback complete is not called until all data has been
|
||||
* written or there is a failure. For blocking this looks like:
|
||||
* <blockquote><pre>
|
||||
* FutureCallback<String> future = new FutureCallback<>();
|
||||
* endpoint.write("ContextObj",future,headerBuffer,contentBuffer);
|
||||
* String context = future.get(); // This blocks
|
||||
* </pre></blockquote></p>
|
||||
*
|
||||
* <h3>Dispatched Write</h3>
|
||||
* <p>Note also that multiple buffers may be passed in write so that gather writes
|
||||
* can be done:
|
||||
* <blockquote><pre>
|
||||
* endpoint.write("ContextObj",new ExecutorCallback<String>(executor)
|
||||
* {
|
||||
* public void onCompleted(String context)
|
||||
* {
|
||||
* int filled=endpoint.fill(mybuffer);
|
||||
* ...
|
||||
* }
|
||||
* public void onFailed(String context,Throwable cause) {...}
|
||||
* },headerBuffer,contentBuffer);
|
||||
* </pre></blockquote></p>
|
||||
*/
|
||||
public interface EndPoint extends Closeable
|
||||
{
|
||||
|
@ -126,5 +192,48 @@ public interface EndPoint extends Closeable
|
|||
void setIdleTimeout(long idleTimeout);
|
||||
|
||||
|
||||
/**
|
||||
* <p>Requests callback methods to be invoked when a call to {@link #fill(ByteBuffer)} would return data or EOF.</p>
|
||||
*
|
||||
* @param context the context to return via the callback
|
||||
* @param callback the callback to call when an error occurs or we are readable.
|
||||
* @throws ReadPendingException if another read operation is concurrent.
|
||||
*/
|
||||
<C> void fillInterested(C context, Callback<C> callback) throws ReadPendingException;
|
||||
|
||||
/**
|
||||
* <p>Writes the given buffers via {@link #flush(ByteBuffer...)} and invokes callback methods when either
|
||||
* all the data has been flushed or an error occurs.</p>
|
||||
*
|
||||
* @param context the context to return via the callback
|
||||
* @param callback the callback to call when an error occurs or the write completed.
|
||||
* @param buffers one or more {@link ByteBuffer}s that will be flushed.
|
||||
* @throws WritePendingException if another write operation is concurrent.
|
||||
*/
|
||||
<C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws WritePendingException;
|
||||
|
||||
/**
|
||||
* @return the {@link Connection} associated with this {@link EndPoint}
|
||||
* @see #setConnection(Connection)
|
||||
*/
|
||||
Connection getConnection();
|
||||
|
||||
/**
|
||||
* @param connection the {@link Connection} associated with this {@link EndPoint}
|
||||
* @see #getConnection()
|
||||
*/
|
||||
void setConnection(Connection connection);
|
||||
|
||||
/**
|
||||
* <p>Callback method invoked when this {@link EndPoint} is opened.</p>
|
||||
* @see #onClose()
|
||||
*/
|
||||
void onOpen();
|
||||
|
||||
/**
|
||||
* <p>Callback method invoked when this {@link EndPoint} is close.</p>
|
||||
* @see #onOpen()
|
||||
*/
|
||||
void onClose();
|
||||
|
||||
}
|
||||
|
|
|
@ -10,25 +10,25 @@ import org.eclipse.jetty.util.Callback;
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* A Utility class to help implement {@link AsyncEndPoint#fillInterested(Object, Callback)}
|
||||
* A Utility class to help implement {@link EndPoint#fillInterested(Object, Callback)}
|
||||
* by keeping state and calling the context and callback objects.
|
||||
*
|
||||
*/
|
||||
public abstract class ReadInterest
|
||||
public abstract class FillInterest
|
||||
{
|
||||
private final AtomicBoolean _interested = new AtomicBoolean(false);
|
||||
private volatile Callback<Object> _callback;
|
||||
private Object _context;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected ReadInterest()
|
||||
protected FillInterest()
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Call to register interest in a callback when a read is possible.
|
||||
* The callback will be called either immediately if {@link #needsFill()}
|
||||
* returns true or eventually once {@link #readable()} is called.
|
||||
* returns true or eventually once {@link #fillable()} is called.
|
||||
* @param context
|
||||
* @param callback
|
||||
* @throws ReadPendingException
|
||||
|
@ -42,18 +42,18 @@ public abstract class ReadInterest
|
|||
try
|
||||
{
|
||||
if (needsFill())
|
||||
readable();
|
||||
fillable();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
failed(e);
|
||||
onFail(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Call to signal that a read is now possible.
|
||||
*/
|
||||
public void readable()
|
||||
public void fillable()
|
||||
{
|
||||
if (_interested.compareAndSet(true,false))
|
||||
{
|
||||
|
@ -77,7 +77,7 @@ public abstract class ReadInterest
|
|||
/* ------------------------------------------------------------ */
|
||||
/** Call to signal a failure to a registered interest
|
||||
*/
|
||||
public void failed(Throwable cause)
|
||||
public void onFail(Throwable cause)
|
||||
{
|
||||
if (_interested.compareAndSet(true,false))
|
||||
{
|
||||
|
@ -90,7 +90,7 @@ public abstract class ReadInterest
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void close()
|
||||
public void onClose()
|
||||
{
|
||||
if (_interested.compareAndSet(true,false))
|
||||
{
|
||||
|
@ -106,14 +106,14 @@ public abstract class ReadInterest
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("ReadInterest@%x{%b,%s,%s}",hashCode(),_interested.get(),_callback,_context);
|
||||
return String.format("FillInterest@%x{%b,%s,%s}",hashCode(),_interested.get(),_callback,_context);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Register the read interest
|
||||
* Abstract method to be implemented by the Specific ReadInterest to
|
||||
* enquire if a read is immediately possible and if not to schedule a future
|
||||
* call to {@link #readable()} or {@link #failed(Throwable)}
|
||||
* call to {@link #fillable()} or {@link #onFail(Throwable)}
|
||||
* @return true if a read is possible
|
||||
* @throws IOException
|
||||
*/
|
|
@ -32,43 +32,44 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/**
|
||||
* An ChannelEndpoint that can be scheduled by {@link SelectorManager}.
|
||||
*/
|
||||
public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, SelectorManager.SelectableAsyncEndPoint
|
||||
public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorManager.SelectableEndPoint
|
||||
{
|
||||
public static final Logger LOG = Log.getLogger(SelectChannelEndPoint.class);
|
||||
|
||||
private final AtomicReference<Future<?>> _timeout = new AtomicReference<>();
|
||||
private final Runnable _idleTask = new Runnable()
|
||||
private final Runnable _updateTask = new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
checkIdleTimeout();
|
||||
try
|
||||
{
|
||||
if (getChannel().isOpen())
|
||||
{
|
||||
int oldInterestOps = _key.interestOps();
|
||||
int newInterestOps = _interestOps;
|
||||
if (newInterestOps != oldInterestOps)
|
||||
setKeyInterests(oldInterestOps, newInterestOps);
|
||||
}
|
||||
}
|
||||
catch (CancelledKeyException x)
|
||||
{
|
||||
LOG.debug("Ignoring key update for concurrently closed channel {}", this);
|
||||
close();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.warn("Ignoring key update for " + this, x);
|
||||
close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* true if {@link ManagedSelector#destroyEndPoint(AsyncEndPoint)} has not been called
|
||||
* true if {@link ManagedSelector#destroyEndPoint(EndPoint)} has not been called
|
||||
*/
|
||||
private final AtomicBoolean _open = new AtomicBoolean();
|
||||
private final ReadInterest _readInterest = new ReadInterest()
|
||||
{
|
||||
@Override
|
||||
protected boolean needsFill()
|
||||
{
|
||||
return SelectChannelEndPoint.this.needsFill();
|
||||
}
|
||||
};
|
||||
private final WriteFlusher _writeFlusher = new WriteFlusher(this)
|
||||
{
|
||||
@Override
|
||||
protected void onIncompleteFlushed()
|
||||
{
|
||||
SelectChannelEndPoint.this.onIncompleteFlush();
|
||||
}
|
||||
};
|
||||
private final SelectorManager.ManagedSelector _selector;
|
||||
private final SelectionKey _key;
|
||||
private final ScheduledExecutorService _scheduler;
|
||||
private volatile AsyncConnection _connection;
|
||||
/**
|
||||
* The desired value for {@link SelectionKey#interestOps()}
|
||||
*/
|
||||
|
@ -76,10 +77,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable,
|
|||
|
||||
public SelectChannelEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey key, ScheduledExecutorService scheduler, long idleTimeout) throws IOException
|
||||
{
|
||||
super(channel);
|
||||
super(scheduler,channel);
|
||||
_selector = selector;
|
||||
_key = key;
|
||||
_scheduler = scheduler;
|
||||
setIdleTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
|
@ -90,57 +90,25 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable,
|
|||
scheduleIdleTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean needsFill()
|
||||
{
|
||||
updateLocalInterests(SelectionKey.OP_READ, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIncompleteFlush()
|
||||
{
|
||||
updateLocalInterests(SelectionKey.OP_WRITE, true);
|
||||
}
|
||||
|
||||
private void scheduleIdleTimeout(long delay)
|
||||
{
|
||||
Future<?> newTimeout = null;
|
||||
if (isOpen() && delay > 0)
|
||||
{
|
||||
LOG.debug("{} scheduling idle timeout in {} ms", this, delay);
|
||||
newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("{} skipped scheduling idle timeout ({} ms)", this, delay);
|
||||
}
|
||||
Future<?> oldTimeout = _timeout.getAndSet(newTimeout);
|
||||
if (oldTimeout != null)
|
||||
oldTimeout.cancel(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void fillInterested(C context, Callback<C> callback) throws IllegalStateException
|
||||
public void setConnection(Connection connection)
|
||||
{
|
||||
_readInterest.register(context, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws IllegalStateException
|
||||
{
|
||||
_writeFlusher.write(context, callback, buffers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncConnection getAsyncConnection()
|
||||
{
|
||||
return _connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsyncConnection(AsyncConnection connection)
|
||||
{
|
||||
AsyncConnection old = getAsyncConnection();
|
||||
_connection = connection;
|
||||
// TODO should this be on AbstractEndPoint?
|
||||
Connection old = getConnection();
|
||||
super.setConnection(connection);
|
||||
if (old != null && old != connection)
|
||||
_selector.getSelectorManager().connectionUpgraded(this, old);
|
||||
}
|
||||
|
@ -154,43 +122,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable,
|
|||
setKeyInterests(oldInterestOps, newInterestOps);
|
||||
updateLocalInterests(readyOps, false);
|
||||
if (_key.isReadable())
|
||||
_readInterest.readable();
|
||||
getFillInterest().fillable();
|
||||
if (_key.isWritable())
|
||||
_writeFlusher.completeWrite();
|
||||
getWriteFlusher().completeWrite();
|
||||
}
|
||||
|
||||
private void checkIdleTimeout()
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
long idleTimestamp = getIdleTimestamp();
|
||||
long idleTimeout = getIdleTimeout();
|
||||
long idleElapsed = System.currentTimeMillis() - idleTimestamp;
|
||||
long idleLeft = idleTimeout - idleElapsed;
|
||||
|
||||
LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
|
||||
|
||||
if (isOutputShutdown() || _readInterest.isInterested() || _writeFlusher.isWriting())
|
||||
{
|
||||
if (idleTimestamp != 0 && idleTimeout > 0)
|
||||
{
|
||||
if (idleLeft <= 0)
|
||||
{
|
||||
LOG.debug("{} idle timeout expired", this);
|
||||
|
||||
if (isOutputShutdown())
|
||||
close();
|
||||
notIdle();
|
||||
|
||||
TimeoutException timeout = new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms");
|
||||
_readInterest.failed(timeout);
|
||||
_writeFlusher.failed(timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
scheduleIdleTimeout(idleLeft > 0 ? idleLeft : idleTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLocalInterests(int operation, boolean add)
|
||||
{
|
||||
|
@ -210,7 +146,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable,
|
|||
{
|
||||
_interestOps = newInterestOps;
|
||||
LOG.debug("Local interests updated {} -> {} for {}", oldInterestOps, newInterestOps, this);
|
||||
_selector.submit(this);
|
||||
_selector.submit(_updateTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -218,30 +154,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable,
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (getChannel().isOpen())
|
||||
{
|
||||
int oldInterestOps = _key.interestOps();
|
||||
int newInterestOps = _interestOps;
|
||||
if (newInterestOps != oldInterestOps)
|
||||
setKeyInterests(oldInterestOps, newInterestOps);
|
||||
}
|
||||
}
|
||||
catch (CancelledKeyException x)
|
||||
{
|
||||
LOG.debug("Ignoring key update for concurrently closed channel {}", this);
|
||||
close();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.warn("Ignoring key update for " + this, x);
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
private void setKeyInterests(int oldInterestOps, int newInterestOps)
|
||||
{
|
||||
|
@ -260,14 +172,14 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable,
|
|||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
_open.compareAndSet(false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
_writeFlusher.close();
|
||||
_readInterest.close();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -288,8 +200,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable,
|
|||
{
|
||||
keyString += "!";
|
||||
}
|
||||
return String.format("SCEP@%x{l(%s)<->r(%s),open=%b,ishut=%b,oshut=%b,i=%d%s,r=%s,w=%s}-{%s}",
|
||||
hashCode(), getRemoteAddress(), getLocalAddress(), isOpen(), isInputShutdown(),
|
||||
isOutputShutdown(), _interestOps, keyString, _readInterest, _writeFlusher, getAsyncConnection());
|
||||
return String.format("%s{io=%d,k=%s}",_interestOps, keyString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* <p>{@link SelectorManager} manages a number of {@link ManagedSelector}s that
|
||||
* simplify the non-blocking primitives provided by the JVM via the {@code java.nio} package.</p>
|
||||
* <p>{@link SelectorManager} subclasses implement methods to return protocol-specific
|
||||
* {@link AsyncEndPoint}s and {@link AsyncConnection}s.</p>
|
||||
* {@link EndPoint}s and {@link Connection}s.</p>
|
||||
*/
|
||||
public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable
|
||||
{
|
||||
|
@ -152,7 +152,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
*
|
||||
* @param endpoint the endpoint being opened
|
||||
*/
|
||||
protected void endPointOpened(AsyncEndPoint endpoint)
|
||||
protected void endPointOpened(EndPoint endpoint)
|
||||
{
|
||||
endpoint.onOpen();
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
*
|
||||
* @param endpoint the endpoint being closed
|
||||
*/
|
||||
protected void endPointClosed(AsyncEndPoint endpoint)
|
||||
protected void endPointClosed(EndPoint endpoint)
|
||||
{
|
||||
endpoint.onClose();
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
*
|
||||
* @param connection the connection just opened
|
||||
*/
|
||||
public void connectionOpened(AsyncConnection connection)
|
||||
public void connectionOpened(Connection connection)
|
||||
{
|
||||
connection.onOpen();
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
*
|
||||
* @param connection the connection just closed
|
||||
*/
|
||||
public void connectionClosed(AsyncConnection connection)
|
||||
public void connectionClosed(Connection connection)
|
||||
{
|
||||
connection.onClose();
|
||||
}
|
||||
|
@ -193,10 +193,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
* @param endpoint the endpoint holding the new connection
|
||||
* @param oldConnection the previous connection
|
||||
*/
|
||||
public void connectionUpgraded(AsyncEndPoint endpoint, AsyncConnection oldConnection)
|
||||
public void connectionUpgraded(EndPoint endpoint, Connection oldConnection)
|
||||
{
|
||||
connectionClosed(oldConnection);
|
||||
connectionOpened(endpoint.getAsyncConnection());
|
||||
connectionOpened(endpoint.getConnection());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,7 +213,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>Factory method to create {@link AsyncEndPoint}.</p>
|
||||
* <p>Factory method to create {@link EndPoint}.</p>
|
||||
* <p>This method is invoked as a result of the registration of a channel via {@link #connect(SocketChannel, Object)}
|
||||
* or {@link #accept(SocketChannel)}.</p>
|
||||
*
|
||||
|
@ -222,20 +222,21 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
* @param selectionKey the selection key
|
||||
* @return a new endpoint
|
||||
* @throws IOException if the endPoint cannot be created
|
||||
* @see #newConnection(SocketChannel, AsyncEndPoint, Object)
|
||||
* @see #newConnection(SocketChannel, EndPoint, Object)
|
||||
*/
|
||||
protected abstract AsyncEndPoint newEndPoint(SocketChannel channel, SelectorManager.ManagedSelector selector, SelectionKey selectionKey) throws IOException;
|
||||
protected abstract EndPoint newEndPoint(SocketChannel channel, SelectorManager.ManagedSelector selector, SelectionKey selectionKey) throws IOException;
|
||||
|
||||
/**
|
||||
* <p>Factory method to create {@link AsyncConnection}.</p>
|
||||
* <p>Factory method to create {@link Connection}.</p>
|
||||
*
|
||||
* @param channel the channel associated to the connection
|
||||
* @param endpoint the endpoint
|
||||
* @param attachment the attachment
|
||||
* @return a new connection
|
||||
* @throws IOException
|
||||
* @see #newEndPoint(SocketChannel, ManagedSelector, SelectionKey)
|
||||
*/
|
||||
public abstract AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint, Object attachment);
|
||||
public abstract Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException;
|
||||
|
||||
@Override
|
||||
public String dump()
|
||||
|
@ -253,7 +254,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
/**
|
||||
* <p>{@link ManagedSelector} wraps a {@link Selector} simplifying non-blocking operations on channels.</p>
|
||||
* <p>{@link ManagedSelector} runs the select loop, which waits on {@link Selector#select()} until events
|
||||
* happen for registered channels. When events happen, it notifies the {@link AsyncEndPoint} associated
|
||||
* happen for registered channels. When events happen, it notifies the {@link EndPoint} associated
|
||||
* with the channel.</p>
|
||||
*/
|
||||
public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dumpable
|
||||
|
@ -412,9 +413,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
Object attachment = key.attachment();
|
||||
try
|
||||
{
|
||||
if (attachment instanceof SelectableAsyncEndPoint)
|
||||
if (attachment instanceof SelectableEndPoint)
|
||||
{
|
||||
((SelectableAsyncEndPoint)attachment).onSelected();
|
||||
((SelectableEndPoint)attachment).onSelected();
|
||||
}
|
||||
else if (key.isConnectable())
|
||||
{
|
||||
|
@ -426,7 +427,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
if (connected)
|
||||
{
|
||||
key.interestOps(0);
|
||||
AsyncEndPoint endpoint = createEndPoint(channel, key);
|
||||
EndPoint endpoint = createEndPoint(channel, key);
|
||||
key.attach(endpoint);
|
||||
}
|
||||
else
|
||||
|
@ -481,21 +482,21 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
_selector.wakeup();
|
||||
}
|
||||
|
||||
private AsyncEndPoint createEndPoint(SocketChannel channel, SelectionKey selectionKey) throws IOException
|
||||
private EndPoint createEndPoint(SocketChannel channel, SelectionKey selectionKey) throws IOException
|
||||
{
|
||||
AsyncEndPoint endPoint = newEndPoint(channel, this, selectionKey);
|
||||
EndPoint endPoint = newEndPoint(channel, this, selectionKey);
|
||||
endPointOpened(endPoint);
|
||||
AsyncConnection asyncConnection = newConnection(channel, endPoint, selectionKey.attachment());
|
||||
endPoint.setAsyncConnection(asyncConnection);
|
||||
Connection asyncConnection = newConnection(channel, endPoint, selectionKey.attachment());
|
||||
endPoint.setConnection(asyncConnection);
|
||||
connectionOpened(asyncConnection);
|
||||
LOG.debug("Created {}", endPoint);
|
||||
return endPoint;
|
||||
}
|
||||
|
||||
public void destroyEndPoint(AsyncEndPoint endPoint)
|
||||
public void destroyEndPoint(EndPoint endPoint)
|
||||
{
|
||||
LOG.debug("Destroyed {}", endPoint);
|
||||
connectionClosed(endPoint.getAsyncConnection());
|
||||
connectionClosed(endPoint.getConnection());
|
||||
endPointClosed(endPoint);
|
||||
}
|
||||
|
||||
|
@ -607,7 +608,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
try
|
||||
{
|
||||
SelectionKey key = _channel.register(_selector, 0, null);
|
||||
AsyncEndPoint endpoint = createEndPoint(_channel, key);
|
||||
EndPoint endpoint = createEndPoint(_channel, key);
|
||||
key.attach(endpoint);
|
||||
}
|
||||
catch (IOException x)
|
||||
|
@ -684,10 +685,10 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
}
|
||||
|
||||
/**
|
||||
* A {@link SelectableAsyncEndPoint} is an {@link AsyncEndPoint} that wish to be notified of
|
||||
* A {@link SelectableEndPoint} is an {@link EndPoint} that wish to be notified of
|
||||
* non-blocking events by the {@link ManagedSelector}.
|
||||
*/
|
||||
public interface SelectableAsyncEndPoint extends AsyncEndPoint
|
||||
public interface SelectableEndPoint extends EndPoint
|
||||
{
|
||||
/**
|
||||
* <p>Callback method invoked when a read or write events has been detected by the {@link ManagedSelector}
|
||||
|
|
|
@ -1,212 +1,438 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2012-2012 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.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.WritePendingException;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* A Utility class to help implement {@link AsyncEndPoint#write(Object, Callback, ByteBuffer...)}
|
||||
* by calling {@link EndPoint#flush(ByteBuffer...)} until all content is written.
|
||||
* The abstract method {@link #onIncompleteFlushed()} is called when not all content has been
|
||||
* written after a call to flush and should organise for the {@link #completeWrite()}
|
||||
* method to be called when a subsequent call to flush should be able to make more progress.
|
||||
*
|
||||
* TODO remove synchronisation
|
||||
* A Utility class to help implement {@link EndPoint#write(Object, Callback, ByteBuffer...)} by calling
|
||||
* {@link EndPoint#flush(ByteBuffer...)} until all content is written.
|
||||
* The abstract method {@link #onIncompleteFlushed()} is called when not all content has been written after a call to
|
||||
* flush and should organise for the {@link #completeWrite()} method to be called when a subsequent call to flush
|
||||
* should be able to make more progress.
|
||||
* <p>
|
||||
*/
|
||||
abstract public class WriteFlusher
|
||||
{
|
||||
private final static ByteBuffer[] NO_BUFFERS= new ByteBuffer[0];
|
||||
private final AtomicBoolean _writing = new AtomicBoolean(false);
|
||||
private final EndPoint _endp;
|
||||
private static final Logger LOG = Log.getLogger(WriteFlusher.class);
|
||||
private static final EnumMap<StateType, Set<StateType>> __stateTransitions = new EnumMap<>(StateType.class);
|
||||
private static final State __IDLE = new IdleState();
|
||||
private static final State __WRITING = new WritingState();
|
||||
private static final State __COMPLETING = new CompletingState();
|
||||
private final EndPoint _endPoint;
|
||||
private final AtomicReference<State> _state = new AtomicReference<>();
|
||||
|
||||
private ByteBuffer[] _buffers;
|
||||
private Object _context;
|
||||
private Callback<Object> _callback;
|
||||
|
||||
protected WriteFlusher(EndPoint endp)
|
||||
static
|
||||
{
|
||||
_endp=endp;
|
||||
// fill the state machine
|
||||
__stateTransitions.put(StateType.IDLE, EnumSet.of(StateType.WRITING));
|
||||
__stateTransitions.put(StateType.WRITING, EnumSet.of(StateType.IDLE, StateType.PENDING, StateType.FAILED));
|
||||
__stateTransitions.put(StateType.PENDING, EnumSet.of(StateType.COMPLETING,StateType.IDLE));
|
||||
__stateTransitions.put(StateType.COMPLETING, EnumSet.of(StateType.IDLE, StateType.PENDING, StateType.FAILED));
|
||||
__stateTransitions.put(StateType.FAILED, EnumSet.of(StateType.IDLE));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized <C> void write(C context, Callback<C> callback, ByteBuffer... buffers)
|
||||
// A write operation may either complete immediately:
|
||||
// IDLE-->WRITING-->IDLE
|
||||
// Or it may not completely flush and go via the PENDING state
|
||||
// IDLE-->WRITING-->PENDING-->COMPLETING-->IDLE
|
||||
// Or it may take several cycles to complete
|
||||
// IDLE-->WRITING-->PENDING-->COMPLETING-->PENDING-->COMPLETING-->IDLE
|
||||
//
|
||||
// If a failure happens while in IDLE, it is a noop since there is no operation to tell of the failure.
|
||||
// If a failure happens in PENDING state, then the fail method calls the pending callback and moves to IDLE state
|
||||
// Otherwise if a fail happens, the state is set to FAIL, so that a subsequent attempt to move out of WRITING or COMPLETING
|
||||
// will discover the failure and call the callbacks before returning to IDLE
|
||||
// Thus the possible paths for a failure are:
|
||||
//
|
||||
// IDLE--(fail)-->IDLE
|
||||
// IDLE-->WRITING--(fail)-->FAILED-->IDLE
|
||||
// IDLE-->WRITING-->PENDING--(fail)-->IDLE
|
||||
// IDLE-->WRITING-->PENDING-->COMPLETING--(fail)-->FAILED-->IDLE
|
||||
//
|
||||
// So a call to fail in the PENDING state will be directly handled and the state changed to IDLE
|
||||
// A call to fail in the WRITING or COMPLETING states will just set the state to FAILED and the failure will be
|
||||
// handled with the write or completeWrite methods try to move the state from what they thought it was.
|
||||
//
|
||||
|
||||
protected WriteFlusher(EndPoint endPoint)
|
||||
{
|
||||
if (callback==null)
|
||||
throw new IllegalArgumentException();
|
||||
if (!_writing.compareAndSet(false,true))
|
||||
_state.set(__IDLE);
|
||||
_endPoint = endPoint;
|
||||
}
|
||||
|
||||
private enum StateType
|
||||
{
|
||||
IDLE,
|
||||
WRITING,
|
||||
PENDING,
|
||||
COMPLETING,
|
||||
FAILED
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to update the current state to the given new state.
|
||||
* @param nextState the desired new state
|
||||
* @return the previous state or null if the state transition failed
|
||||
* @throws WritePendingException if currentState is WRITING and new state is WRITING (api usage error)
|
||||
*/
|
||||
private boolean updateState(State previous,State next)
|
||||
{
|
||||
if (!isTransitionAllowed(previous,next))
|
||||
throw new IllegalStateException();
|
||||
|
||||
return _state.compareAndSet(previous,next);
|
||||
}
|
||||
|
||||
private void fail(PendingState<?> pending)
|
||||
{
|
||||
State current = _state.get();
|
||||
if (current.getType()==StateType.FAILED)
|
||||
{
|
||||
FailedState failed=(FailedState)current;
|
||||
if (updateState(failed,__IDLE))
|
||||
{
|
||||
pending.fail(failed.getCause());
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
private void ignoreFail()
|
||||
{
|
||||
State current = _state.get();
|
||||
while (current.getType()==StateType.FAILED)
|
||||
{
|
||||
if (updateState(current,__IDLE))
|
||||
return;
|
||||
current = _state.get();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTransitionAllowed(State currentState, State newState)
|
||||
{
|
||||
Set<StateType> allowedNewStateTypes = __stateTransitions.get(currentState.getType());
|
||||
if (currentState.getType() == StateType.WRITING && newState.getType() == StateType.WRITING)
|
||||
{
|
||||
throw new WritePendingException();
|
||||
}
|
||||
if (!allowedNewStateTypes.contains(newState.getType()))
|
||||
{
|
||||
LOG.debug("StateType update: {} -> {} not allowed", currentState, newState);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* State represents a State of WriteFlusher.
|
||||
*/
|
||||
private static class State
|
||||
{
|
||||
private final StateType _type;
|
||||
|
||||
private State(StateType stateType)
|
||||
{
|
||||
_type = stateType;
|
||||
}
|
||||
|
||||
public StateType getType()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s", _type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In IdleState WriteFlusher is idle and accepts new writes
|
||||
*/
|
||||
private static class IdleState extends State
|
||||
{
|
||||
private IdleState()
|
||||
{
|
||||
super(StateType.IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In WritingState WriteFlusher is currently writing.
|
||||
*/
|
||||
private static class WritingState extends State
|
||||
{
|
||||
private WritingState()
|
||||
{
|
||||
super(StateType.WRITING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In FailedState no more operations are allowed. The current implementation will never recover from this state.
|
||||
*/
|
||||
private static class FailedState extends State
|
||||
{
|
||||
private final Throwable _cause;
|
||||
private FailedState(Throwable cause)
|
||||
{
|
||||
super(StateType.FAILED);
|
||||
_cause=cause;
|
||||
}
|
||||
|
||||
public Throwable getCause()
|
||||
{
|
||||
return _cause;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In CompletingState WriteFlusher is flushing buffers that have not been fully written in write(). If write()
|
||||
* didn't flush all buffers in one go, it'll switch the State to PendingState. completeWrite() will then switch to
|
||||
* this state and try to flush the remaining buffers.
|
||||
*/
|
||||
private static class CompletingState extends State
|
||||
{
|
||||
private CompletingState()
|
||||
{
|
||||
super(StateType.COMPLETING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In PendingState not all buffers could be written in one go. Then write() will switch to PendingState() and
|
||||
* preserve the state by creating a new PendingState object with the given parameters.
|
||||
*
|
||||
* @param <C>
|
||||
*/
|
||||
private class PendingState<C> extends State
|
||||
{
|
||||
private final C _context;
|
||||
private final Callback<C> _callback;
|
||||
private ByteBuffer[] _buffers;
|
||||
|
||||
private PendingState(ByteBuffer[] buffers, C context, Callback<C> callback)
|
||||
{
|
||||
super(StateType.PENDING);
|
||||
_buffers = buffers;
|
||||
_context = context;
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
public ByteBuffer[] getBuffers()
|
||||
{
|
||||
return _buffers;
|
||||
}
|
||||
|
||||
protected void fail(Throwable cause)
|
||||
{
|
||||
_callback.failed(_context, cause);
|
||||
}
|
||||
|
||||
protected void complete()
|
||||
{
|
||||
_callback.completed(_context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract call to be implemented by specific WriteFlushers. It should schedule a call to {@link #completeWrite()}
|
||||
* or {@link #onFail(Throwable)} when appropriate.
|
||||
*/
|
||||
abstract protected void onIncompleteFlushed();
|
||||
|
||||
/**
|
||||
* Tries to switch state to WRITING. If successful it writes the given buffers to the EndPoint. If state transition
|
||||
* fails it'll fail the callback.
|
||||
*
|
||||
* If not all buffers can be written in one go it creates a new {@link PendingState} object to preserve the state
|
||||
* and then calls {@link #onIncompleteFlushed()}. The remaining buffers will be written in {@link #completeWrite()}.
|
||||
*
|
||||
* If all buffers have been written it calls callback.complete().
|
||||
*
|
||||
* @param context context to pass to the callback
|
||||
* @param callback the callback to call on either failed or complete
|
||||
* @param buffers the buffers to flush to the endpoint
|
||||
* @param <C> type of the context
|
||||
*/
|
||||
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws WritePendingException
|
||||
{
|
||||
if (callback == null)
|
||||
throw new IllegalArgumentException();
|
||||
LOG.debug("write: {}", this);
|
||||
|
||||
if (!updateState(__IDLE,__WRITING))
|
||||
throw new WritePendingException();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
_endp.flush(buffers);
|
||||
_endPoint.flush(buffers);
|
||||
|
||||
// Are we complete?
|
||||
for (ByteBuffer b : buffers)
|
||||
{
|
||||
if (b.hasRemaining())
|
||||
{
|
||||
_buffers=buffers;
|
||||
_context=context;
|
||||
_callback=(Callback<Object>)callback;
|
||||
_writing.set(true); // Needed as memory barrier
|
||||
onIncompleteFlushed();
|
||||
PendingState<?> pending=new PendingState<>(buffers, context, callback);
|
||||
if (updateState(__WRITING,pending))
|
||||
onIncompleteFlushed();
|
||||
else
|
||||
fail(new PendingState<>(buffers, context, callback));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If updateState didn't succeed, we don't care as our buffers have been written
|
||||
if (!updateState(__WRITING,__IDLE))
|
||||
ignoreFail();
|
||||
callback.completed(context);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (updateState(__WRITING,__IDLE))
|
||||
callback.failed(context, e);
|
||||
else
|
||||
fail(new PendingState<>(buffers, context, callback));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Complete a write that has not completed and that called {@link #onIncompleteFlushed()} to request a call to this
|
||||
* method when a call to {@link EndPoint#flush(ByteBuffer...)} is likely to be able to progress.
|
||||
*
|
||||
* It tries to switch from PENDING to COMPLETING. If state transition fails, then it does nothing as the callback
|
||||
* should have been already failed. That's because the only way to switch from PENDING outside this method is
|
||||
* {@link #onFail(Throwable)} or {@link #onClose()}
|
||||
*/
|
||||
public void completeWrite()
|
||||
{
|
||||
State previous = _state.get();
|
||||
PendingState<?> pending=null;
|
||||
|
||||
if (previous.getType()!=StateType.PENDING)
|
||||
return; // failure already handled.
|
||||
|
||||
pending=(PendingState<?>)previous;
|
||||
if (!updateState(pending,__COMPLETING))
|
||||
return; // failure already handled.
|
||||
|
||||
try
|
||||
{
|
||||
ByteBuffer[] buffers = pending.getBuffers();
|
||||
|
||||
_endPoint.flush(buffers);
|
||||
|
||||
// Are we complete?
|
||||
for (ByteBuffer b : buffers)
|
||||
{
|
||||
if (b.hasRemaining())
|
||||
{
|
||||
if (updateState(__COMPLETING,pending))
|
||||
onIncompleteFlushed();
|
||||
else
|
||||
fail(pending);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_writing.compareAndSet(true,false))
|
||||
throw new ConcurrentModificationException();
|
||||
callback.completed(context);
|
||||
// If updateState didn't succeed, we don't care as our buffers have been written
|
||||
if (!updateState(__COMPLETING,__IDLE))
|
||||
ignoreFail();
|
||||
pending.complete();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (!_writing.compareAndSet(true,false))
|
||||
throw new ConcurrentModificationException(e);
|
||||
callback.failed(context,e);
|
||||
if(updateState(__COMPLETING,__IDLE))
|
||||
pending.fail(e);
|
||||
else
|
||||
fail(pending);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Abstract call to be implemented by specific WriteFlushers.
|
||||
* It should schedule a call to {@link #completeWrite()} or
|
||||
* {@link #failed(Throwable)} when appropriate.
|
||||
* @return true if a flush can proceed.
|
||||
*/
|
||||
abstract protected void onIncompleteFlushed();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* Remove empty buffers from the start of a multi buffer array
|
||||
*/
|
||||
private synchronized ByteBuffer[] compact(ByteBuffer[] buffers)
|
||||
public void onFail(Throwable cause)
|
||||
{
|
||||
if (buffers.length<2)
|
||||
return buffers;
|
||||
int b=0;
|
||||
while (b<buffers.length && BufferUtil.isEmpty(buffers[b]))
|
||||
b++;
|
||||
if (b==0)
|
||||
return buffers;
|
||||
if (b==buffers.length)
|
||||
return NO_BUFFERS;
|
||||
|
||||
ByteBuffer[] compact=new ByteBuffer[buffers.length-b];
|
||||
System.arraycopy(buffers,b,compact,0,compact.length);
|
||||
return compact;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Complete a write that has not completed and that called
|
||||
* {@link #onIncompleteFlushed()} to request a call to this
|
||||
* method when a call to {@link EndPoint#flush(ByteBuffer...)}
|
||||
* is likely to be able to progress.
|
||||
*/
|
||||
public synchronized void completeWrite()
|
||||
{
|
||||
if (!isWriting())
|
||||
return; // TODO throw?
|
||||
|
||||
try
|
||||
LOG.debug("failed: " + this, cause);
|
||||
|
||||
// Keep trying to handle the failure until we get to IDLE or FAILED state
|
||||
while(true)
|
||||
{
|
||||
while(true)
|
||||
State current=_state.get();
|
||||
switch(current.getType())
|
||||
{
|
||||
_buffers=compact(_buffers);
|
||||
_endp.flush(_buffers);
|
||||
|
||||
// Are we complete?
|
||||
for (ByteBuffer b : _buffers)
|
||||
{
|
||||
if (b.hasRemaining())
|
||||
case IDLE:
|
||||
return;
|
||||
|
||||
case PENDING:
|
||||
PendingState<?> pending = (PendingState<?>)current;
|
||||
if (updateState(pending,__IDLE))
|
||||
{
|
||||
onIncompleteFlushed();
|
||||
pending.fail(cause);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (updateState(current,new FailedState(cause)))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
// we are complete and ready
|
||||
Callback<Object> callback=_callback;
|
||||
Object context=_context;
|
||||
_buffers=null;
|
||||
_callback=null;
|
||||
_context=null;
|
||||
if (!_writing.compareAndSet(true,false))
|
||||
throw new ConcurrentModificationException();
|
||||
callback.completed(context);
|
||||
}
|
||||
catch (IOException e)
|
||||
}
|
||||
|
||||
public void onClose()
|
||||
{
|
||||
if (_state.get()==__IDLE)
|
||||
return;
|
||||
onFail(new ClosedChannelException());
|
||||
}
|
||||
|
||||
public boolean isIdle()
|
||||
{
|
||||
return _state.get().getType() == StateType.IDLE;
|
||||
}
|
||||
|
||||
public boolean isInProgress()
|
||||
{
|
||||
switch(_state.get().getType())
|
||||
{
|
||||
Callback<Object> callback=_callback;
|
||||
Object context=_context;
|
||||
_buffers=null;
|
||||
_callback=null;
|
||||
_context=null;
|
||||
if (!_writing.compareAndSet(true,false))
|
||||
throw new ConcurrentModificationException();
|
||||
callback.failed(context,e);
|
||||
case WRITING:
|
||||
case PENDING:
|
||||
case COMPLETING:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Fail the write in progress and cause any calls to get to throw
|
||||
* the cause wrapped as an execution exception.
|
||||
* @return true if a write was in progress
|
||||
*/
|
||||
public synchronized boolean failed(Throwable cause)
|
||||
{
|
||||
if (!_writing.compareAndSet(true,false))
|
||||
return false;
|
||||
Callback<Object> callback=_callback;
|
||||
Object context=_context;
|
||||
_buffers=null;
|
||||
_callback=null;
|
||||
_context=null;
|
||||
callback.failed(context,cause);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Fail the write with a {@link ClosedChannelException}. This is similar
|
||||
* to a call to {@link #failed(Throwable)}, except that the exception is
|
||||
* not instantiated unless a write was in progress.
|
||||
* @return true if a write was in progress
|
||||
*/
|
||||
public synchronized boolean close()
|
||||
{
|
||||
if (!_writing.compareAndSet(true,false))
|
||||
return false;
|
||||
Callback<Object> callback=_callback;
|
||||
Object context=_context;
|
||||
_buffers=null;
|
||||
_callback=null;
|
||||
_context=null;
|
||||
callback.failed(context,new ClosedChannelException());
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized boolean isWriting()
|
||||
{
|
||||
return _writing.get();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("WriteFlusher@%x{%b,%s,%s}",hashCode(),isWriting(),_callback,_context);
|
||||
return String.format("WriteFlusher@%x{%s}", hashCode(), _state.get());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,20 +17,20 @@ import java.io.IOException;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
import javax.net.ssl.SSLEngineResult.Status;
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.eclipse.jetty.io.AbstractAsyncConnection;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.AbstractEndPoint;
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.ReadInterest;
|
||||
import org.eclipse.jetty.io.FillInterest;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.io.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.WriteFlusher;
|
||||
|
@ -40,27 +40,27 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* An AsyncConnection that acts as an intercepter between an AsyncEndPoint providing SSL encrypted data
|
||||
* and another consumer of an AsyncEndPoint (typically an {@link AsyncConnection} like HttpConnection) that
|
||||
* A Connection that acts as an intercepter between an EndPoint providing SSL encrypted data
|
||||
* and another consumer of an EndPoint (typically an {@link Connection} like HttpConnection) that
|
||||
* wants unencrypted data.
|
||||
* <p>
|
||||
* The connector uses an {@link AsyncEndPoint} (typically {@link SelectChannelEndPoint}) as
|
||||
* it's source/sink of encrypted data. It then provides an endpoint via {@link #getSslEndPoint()} to
|
||||
* The connector uses an {@link EndPoint} (typically {@link SelectChannelEndPoint}) as
|
||||
* it's source/sink of encrypted data. It then provides an endpoint via {@link #getDecryptedEndPoint()} to
|
||||
* expose a source/sink of unencrypted data to another connection (eg HttpConnection).
|
||||
* <p>
|
||||
* The design of this class is based on a clear separation between the passive methods, which do not block nor schedule any
|
||||
* asynchronous callbacks, and active methods that do schedule asynchronous callbacks.
|
||||
* <p>
|
||||
* The passive methods are {@link DecryptedEndPoint#fill(ByteBuffer)} and {@link DecryptedEndPoint#flush(ByteBuffer...)}. They make best
|
||||
* effort attempts to progress the connection using only calls to the encrypted {@link AsyncEndPoint#fill(ByteBuffer)} and {@link AsyncEndPoint#flush(ByteBuffer...)}
|
||||
* effort attempts to progress the connection using only calls to the encrypted {@link EndPoint#fill(ByteBuffer)} and {@link EndPoint#flush(ByteBuffer...)}
|
||||
* methods. They will never block nor schedule any readInterest or write callbacks. If a fill/flush cannot progress either because
|
||||
* of network congestion or waiting for an SSL handshake message, then the fill/flush will simply return with zero bytes filled/flushed.
|
||||
* Specifically, if a flush cannot proceed because it needs to receive a handshake message, then the flush will attempt to fill bytes from the
|
||||
* encrypted endpoint, but if insufficient bytes are read it will NOT call {@link AsyncEndPoint#fillInterested(Object, Callback)}.
|
||||
* encrypted endpoint, but if insufficient bytes are read it will NOT call {@link EndPoint#fillInterested(Object, Callback)}.
|
||||
* <p>
|
||||
* It is only the active methods : {@link DecryptedEndPoint#fillInterested(Object, Callback)} and
|
||||
* {@link DecryptedEndPoint#write(Object, Callback, ByteBuffer...)} that may schedule callbacks by calling the encrypted
|
||||
* {@link AsyncEndPoint#fillInterested(Object, Callback)} and {@link AsyncEndPoint#write(Object, Callback, ByteBuffer...)}
|
||||
* {@link EndPoint#fillInterested(Object, Callback)} and {@link EndPoint#write(Object, Callback, ByteBuffer...)}
|
||||
* methods. For normal data handling, the decrypted fillInterest method will result in an encrypted fillInterest and a decrypted
|
||||
* write will result in an encrypted write. However, due to SSL handshaking requirements, it is also possible for a decrypted fill
|
||||
* to call the encrypted write and for the decrypted flush to call the encrypted fillInterested methods.
|
||||
|
@ -70,7 +70,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* be called again and make another best effort attempt to progress the connection.
|
||||
*
|
||||
*/
|
||||
public class SslConnection extends AbstractAsyncConnection
|
||||
public class SslConnection extends AbstractConnection
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SslConnection.class);
|
||||
private final ByteBufferPool _bufferPool;
|
||||
|
@ -82,7 +82,7 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
private final boolean _encryptedDirectBuffers = false;
|
||||
private final boolean _decryptedDirectBuffers = false;
|
||||
|
||||
public SslConnection(ByteBufferPool byteBufferPool, Executor executor, AsyncEndPoint endPoint, SSLEngine sslEngine)
|
||||
public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine)
|
||||
{
|
||||
super(endPoint, executor, true);
|
||||
this._bufferPool = byteBufferPool;
|
||||
|
@ -95,7 +95,7 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
return _sslEngine;
|
||||
}
|
||||
|
||||
public AsyncEndPoint getSslEndPoint()
|
||||
public EndPoint getDecryptedEndPoint()
|
||||
{
|
||||
return _decryptedEndPoint;
|
||||
}
|
||||
|
@ -112,6 +112,8 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
|
||||
if (_sslEngine.getUseClientMode())
|
||||
_decryptedEndPoint.write(null, new Callback.Empty<>(), BufferUtil.EMPTY_BUFFER);
|
||||
|
||||
getDecryptedEndPoint().getConnection().onOpen();
|
||||
}
|
||||
catch (SSLException x)
|
||||
{
|
||||
|
@ -136,14 +138,13 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
{
|
||||
// wake up whoever is doing the fill or the flush so they can
|
||||
// do all the filling, unwrapping ,wrapping and flushing
|
||||
if (_decryptedEndPoint._readInterest.isInterested())
|
||||
_decryptedEndPoint._readInterest.readable();
|
||||
_decryptedEndPoint.getFillInterest().fillable();
|
||||
|
||||
// If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
|
||||
if ( _decryptedEndPoint._flushRequiresFillToProgress)
|
||||
{
|
||||
_decryptedEndPoint._flushRequiresFillToProgress = false;
|
||||
_decryptedEndPoint._writeFlusher.completeWrite();
|
||||
_decryptedEndPoint.getWriteFlusher().completeWrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,13 +163,12 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
|
||||
synchronized(_decryptedEndPoint)
|
||||
{
|
||||
if (_decryptedEndPoint._readInterest.isInterested())
|
||||
_decryptedEndPoint._readInterest.failed(cause);
|
||||
_decryptedEndPoint.getFillInterest().onFail(cause);
|
||||
|
||||
if (_decryptedEndPoint._flushRequiresFillToProgress)
|
||||
{
|
||||
_decryptedEndPoint._flushRequiresFillToProgress = false;
|
||||
_decryptedEndPoint._writeFlusher.failed(cause);
|
||||
_decryptedEndPoint.getWriteFlusher().onFail(cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,33 +177,20 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("SslConnection@%x{%s,%s%s}",
|
||||
return String.format("%s{%s}",
|
||||
hashCode(),
|
||||
_sslEngine.getHandshakeStatus(),
|
||||
_decryptedEndPoint._readInterest.isInterested() ? "R" : "",
|
||||
_decryptedEndPoint._writeFlusher.isWriting() ? "W" : "");
|
||||
_sslEngine.getHandshakeStatus());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public class DecryptedEndPoint extends AbstractEndPoint implements AsyncEndPoint
|
||||
public class DecryptedEndPoint extends AbstractEndPoint
|
||||
{
|
||||
private AsyncConnection _connection;
|
||||
private boolean _fillRequiresFlushToProgress;
|
||||
private boolean _flushRequiresFillToProgress;
|
||||
private boolean _cannotAcceptMoreAppDataToFlush;
|
||||
private boolean _needToFillMoreDataToProgress;
|
||||
private boolean _ishut = false;
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
}
|
||||
|
||||
private final Callback<Void> _writeCallback = new Callback<Void>()
|
||||
{
|
||||
|
||||
|
@ -224,11 +211,10 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
if (_fillRequiresFlushToProgress)
|
||||
{
|
||||
_fillRequiresFlushToProgress = false;
|
||||
_readInterest.readable();
|
||||
getFillInterest().fillable();
|
||||
}
|
||||
|
||||
if (_writeFlusher.isWriting())
|
||||
_writeFlusher.completeWrite();
|
||||
getWriteFlusher().completeWrite();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,105 +236,112 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
if (_fillRequiresFlushToProgress)
|
||||
{
|
||||
_fillRequiresFlushToProgress = false;
|
||||
_readInterest.failed(x);
|
||||
getFillInterest().onFail(x);
|
||||
}
|
||||
|
||||
if (_writeFlusher.isWriting())
|
||||
_writeFlusher.failed(x);
|
||||
getWriteFlusher().onFail(x);
|
||||
|
||||
// TODO release all buffers??? or may in onClose
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final ReadInterest _readInterest = new ReadInterest()
|
||||
{
|
||||
@Override
|
||||
protected boolean needsFill() throws IOException
|
||||
{
|
||||
// This means that the decrypted data consumer has called the fillInterested
|
||||
// method on the DecryptedEndPoint, so we have to work out if there is
|
||||
// decrypted data to be filled or what callbacks to setup to be told when there
|
||||
// might be more encrypted data available to attempt another call to fill
|
||||
|
||||
synchronized (DecryptedEndPoint.this)
|
||||
{
|
||||
// Do we already have some app data, then app can fill now so return true
|
||||
if (BufferUtil.hasContent(_decryptedInput))
|
||||
return true;
|
||||
|
||||
// If we have no encrypted data to decrypt OR we have some, but it is not enough
|
||||
if (BufferUtil.isEmpty(_encryptedInput) || _needToFillMoreDataToProgress)
|
||||
{
|
||||
// We are not ready to read data
|
||||
|
||||
// Are we actually write blocked?
|
||||
if (_fillRequiresFlushToProgress)
|
||||
{
|
||||
// we must be blocked trying to write before we can read
|
||||
|
||||
// Do we have data to write
|
||||
if (BufferUtil.hasContent(_encryptedOutput))
|
||||
{
|
||||
// write it
|
||||
_cannotAcceptMoreAppDataToFlush = true;
|
||||
getEndPoint().write(null, _writeCallback, _encryptedOutput);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have already written the net data
|
||||
// pretend we are readable so the wrap is done by next readable callback
|
||||
_fillRequiresFlushToProgress = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
// Normal readable callback
|
||||
// Get called back on onfillable when then is more data to fill
|
||||
SslConnection.this.fillInterested();
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are ready to read data
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final WriteFlusher _writeFlusher = new WriteFlusher(this)
|
||||
{
|
||||
@Override
|
||||
protected void onIncompleteFlushed()
|
||||
{
|
||||
// This means that the decripted endpoint write method was called and not
|
||||
// all data could be wrapped. So either we need to write some encrypted data,
|
||||
// OR if we are handshaking we need to read some encrypted data OR
|
||||
// if neither than we should just try the flush again.
|
||||
synchronized (DecryptedEndPoint.this)
|
||||
{
|
||||
// If we have pending output data,
|
||||
if (BufferUtil.hasContent(_encryptedOutput))
|
||||
{
|
||||
// write it
|
||||
_cannotAcceptMoreAppDataToFlush = true;
|
||||
getEndPoint().write(null, _writeCallback, _encryptedOutput);
|
||||
}
|
||||
else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
|
||||
// we are actually read blocked in order to write
|
||||
SslConnection.this.fillInterested();
|
||||
else
|
||||
// try the flush again
|
||||
completeWrite();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public DecryptedEndPoint()
|
||||
{
|
||||
super(getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
|
||||
// TODO does this need idle timeouts
|
||||
super(null,getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FillInterest getFillInterest()
|
||||
{
|
||||
return super.getFillInterest();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected WriteFlusher getWriteFlusher()
|
||||
{
|
||||
return super.getWriteFlusher();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIncompleteFlush()
|
||||
{
|
||||
// This means that the decripted endpoint write method was called and not
|
||||
// all data could be wrapped. So either we need to write some encrypted data,
|
||||
// OR if we are handshaking we need to read some encrypted data OR
|
||||
// if neither than we should just try the flush again.
|
||||
synchronized (DecryptedEndPoint.this)
|
||||
{
|
||||
// If we have pending output data,
|
||||
if (BufferUtil.hasContent(_encryptedOutput))
|
||||
{
|
||||
// write it
|
||||
_cannotAcceptMoreAppDataToFlush = true;
|
||||
getEndPoint().write(null, _writeCallback, _encryptedOutput);
|
||||
}
|
||||
else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
|
||||
// we are actually read blocked in order to write
|
||||
SslConnection.this.fillInterested();
|
||||
else
|
||||
// try the flush again
|
||||
getWriteFlusher().completeWrite();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean needsFill() throws IOException
|
||||
{
|
||||
// This means that the decrypted data consumer has called the fillInterested
|
||||
// method on the DecryptedEndPoint, so we have to work out if there is
|
||||
// decrypted data to be filled or what callbacks to setup to be told when there
|
||||
// might be more encrypted data available to attempt another call to fill
|
||||
|
||||
synchronized (DecryptedEndPoint.this)
|
||||
{
|
||||
// Do we already have some app data, then app can fill now so return true
|
||||
if (BufferUtil.hasContent(_decryptedInput))
|
||||
return true;
|
||||
|
||||
// If we have no encrypted data to decrypt OR we have some, but it is not enough
|
||||
if (BufferUtil.isEmpty(_encryptedInput) || _needToFillMoreDataToProgress)
|
||||
{
|
||||
// We are not ready to read data
|
||||
|
||||
// Are we actually write blocked?
|
||||
if (_fillRequiresFlushToProgress)
|
||||
{
|
||||
// we must be blocked trying to write before we can read
|
||||
|
||||
// Do we have data to write
|
||||
if (BufferUtil.hasContent(_encryptedOutput))
|
||||
{
|
||||
// write it
|
||||
_cannotAcceptMoreAppDataToFlush = true;
|
||||
getEndPoint().write(null, _writeCallback, _encryptedOutput);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have already written the net data
|
||||
// pretend we are readable so the wrap is done by next readable callback
|
||||
_fillRequiresFlushToProgress = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
// Normal readable callback
|
||||
// Get called back on onfillable when then is more data to fill
|
||||
SslConnection.this.fillInterested();
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are ready to read data
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SslConnection getSslConnection()
|
||||
|
@ -356,18 +349,6 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
return SslConnection.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void fillInterested(C context, Callback<C> callback) throws IllegalStateException
|
||||
{
|
||||
_readInterest.register(context, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws IllegalStateException
|
||||
{
|
||||
_writeFlusher.write(context, callback, buffers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int fill(ByteBuffer buffer) throws IOException
|
||||
{
|
||||
|
@ -551,7 +532,7 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
// or busy handshaking, then zero bytes may be taken from appOuts and this method
|
||||
// will return 0 (even if some handshake bytes were flushed and filled).
|
||||
// it is the applications responsibility to call flush again - either in a busy loop
|
||||
// or better yet by using AsyncEndPoint#write to do the flushing.
|
||||
// or better yet by using EndPoint#write to do the flushing.
|
||||
|
||||
LOG.debug("{} flush enter {}", SslConnection.this, Arrays.toString(appOuts));
|
||||
try
|
||||
|
@ -628,7 +609,7 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
case NEED_UNWRAP:
|
||||
// Ah we need to fill some data so we can write.
|
||||
// So if we were not called from fill and the app is not reading anyway
|
||||
if (!_fillRequiresFlushToProgress && !_readInterest.isInterested())
|
||||
if (!_fillRequiresFlushToProgress && !getFillInterest().isInterested())
|
||||
{
|
||||
// Tell the onFillable method that there might be a write to complete
|
||||
// TODO move this to the writeFlusher?
|
||||
|
@ -711,24 +692,5 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
{
|
||||
return _ishut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncConnection getAsyncConnection()
|
||||
{
|
||||
return _connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsyncConnection(AsyncConnection connection)
|
||||
{
|
||||
_connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s{%s%s%s}", super.toString(), _readInterest.isInterested() ? "R" : "", _writeFlusher.isWriting() ? "W" : "", _cannotAcceptMoreAppDataToFlush ? "w" : "");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,192 +0,0 @@
|
|||
package org.eclipse.jetty.io;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class AsyncByteArrayEndPointTest
|
||||
{
|
||||
private ScheduledExecutorService _scheduler;
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
_scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after()
|
||||
{
|
||||
_scheduler.shutdownNow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadable() throws Exception
|
||||
{
|
||||
AsyncByteArrayEndPoint endp = new AsyncByteArrayEndPoint(_scheduler, 5000);
|
||||
endp.setInput("test input");
|
||||
|
||||
ByteBuffer buffer = BufferUtil.allocate(1024);
|
||||
FutureCallback<String> fcb = new FutureCallback<>();
|
||||
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(10, endp.fill(buffer));
|
||||
assertEquals("test input", BufferUtil.toString(buffer));
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertFalse(fcb.isDone());
|
||||
assertEquals(0, endp.fill(buffer));
|
||||
|
||||
endp.setInput(" more");
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(5, endp.fill(buffer));
|
||||
assertEquals("test input more", BufferUtil.toString(buffer));
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertFalse(fcb.isDone());
|
||||
assertEquals(0, endp.fill(buffer));
|
||||
|
||||
endp.setInput((ByteBuffer)null);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(-1, endp.fill(buffer));
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(-1, endp.fill(buffer));
|
||||
|
||||
endp.close();
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertTrue(fcb.isDone());
|
||||
try
|
||||
{
|
||||
fcb.get();
|
||||
fail();
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
assertThat(e.toString(), containsString("Closed"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrite() throws Exception
|
||||
{
|
||||
AsyncByteArrayEndPoint endp = new AsyncByteArrayEndPoint(_scheduler, 5000, (byte[])null, 15);
|
||||
endp.setGrowOutput(false);
|
||||
endp.setOutput(BufferUtil.allocate(10));
|
||||
|
||||
ByteBuffer data = BufferUtil.toBuffer("Data.");
|
||||
ByteBuffer more = BufferUtil.toBuffer(" Some more.");
|
||||
|
||||
FutureCallback<String> fcb = new FutureCallback<>();
|
||||
endp.write("CTX", fcb, data);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals("Data.", endp.getOutputString());
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.write("CTX", fcb, more);
|
||||
assertFalse(fcb.isDone());
|
||||
|
||||
assertEquals("Data. Some", endp.getOutputString());
|
||||
assertEquals("Data. Some", endp.takeOutputString());
|
||||
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(" more.", endp.getOutputString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdle() throws Exception
|
||||
{
|
||||
AsyncByteArrayEndPoint endp = new AsyncByteArrayEndPoint(_scheduler, 500);
|
||||
endp.setInput("test");
|
||||
endp.setGrowOutput(false);
|
||||
endp.setOutput(BufferUtil.allocate(5));
|
||||
|
||||
// no idle check
|
||||
assertTrue(endp.isOpen());
|
||||
Thread.sleep(1000);
|
||||
assertTrue(endp.isOpen());
|
||||
|
||||
// normal read
|
||||
ByteBuffer buffer = BufferUtil.allocate(1024);
|
||||
FutureCallback<Void> fcb = new FutureCallback<>();
|
||||
|
||||
endp.fillInterested(null, fcb);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals(null, fcb.get());
|
||||
assertEquals(4, endp.fill(buffer));
|
||||
assertEquals("test", BufferUtil.toString(buffer));
|
||||
|
||||
// read timeout
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested(null, fcb);
|
||||
long start = System.currentTimeMillis();
|
||||
try
|
||||
{
|
||||
fcb.get();
|
||||
fail();
|
||||
}
|
||||
catch (ExecutionException t)
|
||||
{
|
||||
assertThat(t.getCause(), Matchers.instanceOf(TimeoutException.class));
|
||||
}
|
||||
assertThat(System.currentTimeMillis() - start, Matchers.greaterThan(100L));
|
||||
assertTrue(endp.isOpen());
|
||||
|
||||
// write timeout
|
||||
fcb = new FutureCallback<>();
|
||||
start = System.currentTimeMillis();
|
||||
|
||||
endp.write(null, fcb, BufferUtil.toBuffer("This is too long"));
|
||||
try
|
||||
{
|
||||
fcb.get();
|
||||
fail();
|
||||
}
|
||||
catch (ExecutionException t)
|
||||
{
|
||||
assertThat(t.getCause(), Matchers.instanceOf(TimeoutException.class));
|
||||
}
|
||||
assertThat(System.currentTimeMillis() - start, Matchers.greaterThan(100L));
|
||||
assertTrue(endp.isOpen());
|
||||
|
||||
// Still no idle close
|
||||
Thread.sleep(1000);
|
||||
assertTrue(endp.isOpen());
|
||||
|
||||
// shutdown out
|
||||
endp.shutdownOutput();
|
||||
|
||||
// idle close
|
||||
Thread.sleep(1000);
|
||||
assertFalse(endp.isOpen());
|
||||
}
|
||||
}
|
|
@ -2,17 +2,41 @@ package org.eclipse.jetty.io;
|
|||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ByteArrayEndPointTest
|
||||
{
|
||||
private ScheduledExecutorService _scheduler;
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
_scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after()
|
||||
{
|
||||
_scheduler.shutdownNow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFill() throws Exception
|
||||
{
|
||||
|
@ -104,6 +128,159 @@ public class ByteArrayEndPointTest
|
|||
assertEquals("data.",BufferUtil.toString(endp.takeOutput()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testReadable() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endp = new ByteArrayEndPoint(_scheduler, 5000);
|
||||
endp.setInput("test input");
|
||||
|
||||
ByteBuffer buffer = BufferUtil.allocate(1024);
|
||||
FutureCallback<String> fcb = new FutureCallback<>();
|
||||
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(10, endp.fill(buffer));
|
||||
assertEquals("test input", BufferUtil.toString(buffer));
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertFalse(fcb.isDone());
|
||||
assertEquals(0, endp.fill(buffer));
|
||||
|
||||
endp.setInput(" more");
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(5, endp.fill(buffer));
|
||||
assertEquals("test input more", BufferUtil.toString(buffer));
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertFalse(fcb.isDone());
|
||||
assertEquals(0, endp.fill(buffer));
|
||||
|
||||
endp.setInput((ByteBuffer)null);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(-1, endp.fill(buffer));
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(-1, endp.fill(buffer));
|
||||
|
||||
endp.close();
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested("CTX", fcb);
|
||||
assertTrue(fcb.isDone());
|
||||
try
|
||||
{
|
||||
fcb.get();
|
||||
fail();
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
assertThat(e.toString(), containsString("Closed"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrite() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endp = new ByteArrayEndPoint(_scheduler, 5000, (byte[])null, 15);
|
||||
endp.setGrowOutput(false);
|
||||
endp.setOutput(BufferUtil.allocate(10));
|
||||
|
||||
ByteBuffer data = BufferUtil.toBuffer("Data.");
|
||||
ByteBuffer more = BufferUtil.toBuffer(" Some more.");
|
||||
|
||||
FutureCallback<String> fcb = new FutureCallback<>();
|
||||
endp.write("CTX", fcb, data);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals("Data.", endp.getOutputString());
|
||||
|
||||
fcb = new FutureCallback<>();
|
||||
endp.write("CTX", fcb, more);
|
||||
assertFalse(fcb.isDone());
|
||||
|
||||
assertEquals("Data. Some", endp.getOutputString());
|
||||
assertEquals("Data. Some", endp.takeOutputString());
|
||||
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals("CTX", fcb.get());
|
||||
assertEquals(" more.", endp.getOutputString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdle() throws Exception
|
||||
{
|
||||
ByteArrayEndPoint endp = new ByteArrayEndPoint(_scheduler, 500);
|
||||
endp.setInput("test");
|
||||
endp.setGrowOutput(false);
|
||||
endp.setOutput(BufferUtil.allocate(5));
|
||||
|
||||
// no idle check
|
||||
assertTrue(endp.isOpen());
|
||||
Thread.sleep(1000);
|
||||
assertTrue(endp.isOpen());
|
||||
|
||||
// normal read
|
||||
ByteBuffer buffer = BufferUtil.allocate(1024);
|
||||
FutureCallback<Void> fcb = new FutureCallback<>();
|
||||
|
||||
endp.fillInterested(null, fcb);
|
||||
assertTrue(fcb.isDone());
|
||||
assertEquals(null, fcb.get());
|
||||
assertEquals(4, endp.fill(buffer));
|
||||
assertEquals("test", BufferUtil.toString(buffer));
|
||||
|
||||
// read timeout
|
||||
fcb = new FutureCallback<>();
|
||||
endp.fillInterested(null, fcb);
|
||||
long start = System.currentTimeMillis();
|
||||
try
|
||||
{
|
||||
fcb.get();
|
||||
fail();
|
||||
}
|
||||
catch (ExecutionException t)
|
||||
{
|
||||
assertThat(t.getCause(), Matchers.instanceOf(TimeoutException.class));
|
||||
}
|
||||
assertThat(System.currentTimeMillis() - start, Matchers.greaterThan(100L));
|
||||
assertTrue(endp.isOpen());
|
||||
|
||||
// write timeout
|
||||
fcb = new FutureCallback<>();
|
||||
start = System.currentTimeMillis();
|
||||
|
||||
endp.write(null, fcb, BufferUtil.toBuffer("This is too long"));
|
||||
try
|
||||
{
|
||||
fcb.get();
|
||||
fail();
|
||||
}
|
||||
catch (ExecutionException t)
|
||||
{
|
||||
assertThat(t.getCause(), Matchers.instanceOf(TimeoutException.class));
|
||||
}
|
||||
assertThat(System.currentTimeMillis() - start, Matchers.greaterThan(100L));
|
||||
assertTrue(endp.isOpen());
|
||||
|
||||
// Still no idle close
|
||||
Thread.sleep(1000);
|
||||
assertTrue(endp.isOpen());
|
||||
|
||||
// shutdown out
|
||||
endp.shutdownOutput();
|
||||
|
||||
// idle close
|
||||
Thread.sleep(1000);
|
||||
assertFalse(endp.isOpen());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ public class ChannelEndPointTest extends EndPointTest<ChannelEndPoint>
|
|||
{
|
||||
EndPointPair<ChannelEndPoint> c = new EndPointPair<>();
|
||||
|
||||
c.client=new ChannelEndPoint(SocketChannel.open(connector.socket().getLocalSocketAddress()));
|
||||
c.server=new ChannelEndPoint(connector.accept());
|
||||
c.client=new ChannelEndPoint(null,SocketChannel.open(connector.socket().getLocalSocketAddress()));
|
||||
c.server=new ChannelEndPoint(null,connector.accept());
|
||||
return c;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class SelectChannelEndPointInterestsTest
|
|||
}
|
||||
|
||||
@Override
|
||||
protected AsyncEndPoint newEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException
|
||||
protected EndPoint newEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException
|
||||
{
|
||||
return new SelectChannelEndPoint(channel, selector, selectionKey, scheduler, 60000)
|
||||
{
|
||||
|
@ -76,10 +76,17 @@ public class SelectChannelEndPointInterestsTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public AsyncConnection newConnection(SocketChannel channel, final AsyncEndPoint endPoint, Object attachment)
|
||||
public Connection newConnection(SocketChannel channel, final EndPoint endPoint, Object attachment)
|
||||
{
|
||||
return new AbstractAsyncConnection(endPoint, threadPool)
|
||||
return new AbstractConnection(endPoint, threadPool)
|
||||
{
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
fillInterested();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFillable()
|
||||
{
|
||||
|
@ -102,7 +109,7 @@ public class SelectChannelEndPointInterestsTest
|
|||
init(new Interested()
|
||||
{
|
||||
@Override
|
||||
public void onFillable(AsyncEndPoint endPoint, AbstractAsyncConnection connection)
|
||||
public void onFillable(EndPoint endPoint, AbstractConnection connection)
|
||||
{
|
||||
ByteBuffer input = BufferUtil.allocate(2);
|
||||
int read = fill(endPoint, input);
|
||||
|
@ -136,7 +143,7 @@ public class SelectChannelEndPointInterestsTest
|
|||
writeBlocked.set(true);
|
||||
}
|
||||
|
||||
private int fill(AsyncEndPoint endPoint, ByteBuffer buffer)
|
||||
private int fill(EndPoint endPoint, ByteBuffer buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -184,7 +191,7 @@ public class SelectChannelEndPointInterestsTest
|
|||
|
||||
private interface Interested
|
||||
{
|
||||
void onFillable(AsyncEndPoint endPoint, AbstractAsyncConnection connection);
|
||||
void onFillable(EndPoint endPoint, AbstractConnection connection);
|
||||
|
||||
void onIncompleteFlush();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
package org.eclipse.jetty.io;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -7,6 +13,7 @@ import java.net.Socket;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
|
@ -21,12 +28,6 @@ import org.junit.BeforeClass;
|
|||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
|
||||
{
|
||||
|
@ -52,14 +53,14 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
|
|||
}
|
||||
|
||||
@Override
|
||||
protected AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint)
|
||||
protected Connection newConnection(SocketChannel channel, EndPoint endpoint)
|
||||
{
|
||||
SSLEngine engine = __sslCtxFactory.newSslEngine();
|
||||
engine.setUseClientMode(false);
|
||||
SslConnection sslConnection = new SslConnection(__byteBufferPool, _threadPool, endpoint, engine);
|
||||
|
||||
AsyncConnection appConnection = super.newConnection(channel,sslConnection.getSslEndPoint());
|
||||
sslConnection.getSslEndPoint().setAsyncConnection(appConnection);
|
||||
Connection appConnection = super.newConnection(channel,sslConnection.getDecryptedEndPoint());
|
||||
sslConnection.getDecryptedEndPoint().setConnection(appConnection);
|
||||
_manager.connectionOpened(appConnection);
|
||||
|
||||
return sslConnection;
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
|
||||
package org.eclipse.jetty.io;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -42,16 +48,10 @@ import org.junit.Assert;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SelectChannelEndPointTest
|
||||
{
|
||||
protected CountDownLatch _lastEndPointLatch;
|
||||
protected volatile AsyncEndPoint _lastEndPoint;
|
||||
protected volatile EndPoint _lastEndPoint;
|
||||
protected ServerSocketChannel _connector;
|
||||
protected QueuedThreadPool _threadPool = new QueuedThreadPool();
|
||||
protected ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
|
@ -64,7 +64,7 @@ public class SelectChannelEndPointTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint, Object attachment)
|
||||
public Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment)
|
||||
{
|
||||
return SelectChannelEndPointTest.this.newConnection(channel, endpoint);
|
||||
}
|
||||
|
@ -108,26 +108,33 @@ public class SelectChannelEndPointTest
|
|||
return new Socket(_connector.socket().getInetAddress(), _connector.socket().getLocalPort());
|
||||
}
|
||||
|
||||
protected AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint)
|
||||
protected Connection newConnection(SocketChannel channel, EndPoint endpoint)
|
||||
{
|
||||
return new TestConnection(endpoint);
|
||||
}
|
||||
|
||||
public class TestConnection extends AbstractAsyncConnection
|
||||
public class TestConnection extends AbstractConnection
|
||||
{
|
||||
ByteBuffer _in = BufferUtil.allocate(32 * 1024);
|
||||
ByteBuffer _out = BufferUtil.allocate(32 * 1024);
|
||||
long _last = -1;
|
||||
|
||||
public TestConnection(AsyncEndPoint endp)
|
||||
public TestConnection(EndPoint endp)
|
||||
{
|
||||
super(endp, _threadPool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
fillInterested();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onFillable()
|
||||
{
|
||||
AsyncEndPoint _endp = getEndPoint();
|
||||
EndPoint _endp = getEndPoint();
|
||||
try
|
||||
{
|
||||
_last = System.currentTimeMillis();
|
||||
|
@ -462,12 +469,11 @@ public class SelectChannelEndPointTest
|
|||
}
|
||||
|
||||
// But endpoint is still open.
|
||||
assertTrue(_lastEndPoint.isOpen());
|
||||
|
||||
// Wait for another idle callback
|
||||
Thread.sleep(idleTimeout * 2);
|
||||
if(_lastEndPoint.isOpen())
|
||||
// Wait for another idle callback
|
||||
Thread.sleep(idleTimeout * 2);
|
||||
|
||||
// endpoint is closed.
|
||||
|
||||
assertFalse(_lastEndPoint.isOpen());
|
||||
}
|
||||
|
||||
|
@ -540,7 +546,7 @@ public class SelectChannelEndPointTest
|
|||
System.err.println("time=" + (now - start));
|
||||
System.err.println("last=" + (now - last));
|
||||
System.err.println("endp=" + _lastEndPoint);
|
||||
System.err.println("conn=" + _lastEndPoint.getAsyncConnection());
|
||||
System.err.println("conn=" + _lastEndPoint.getConnection());
|
||||
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -13,10 +13,12 @@ import java.util.concurrent.CountDownLatch;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
@ -35,7 +37,7 @@ public class SslConnectionTest
|
|||
private static SslContextFactory __sslCtxFactory=new SslContextFactory();
|
||||
private static ByteBufferPool __byteBufferPool = new StandardByteBufferPool();
|
||||
|
||||
protected volatile AsyncEndPoint _lastEndp;
|
||||
protected volatile EndPoint _lastEndp;
|
||||
protected ServerSocketChannel _connector;
|
||||
protected QueuedThreadPool _threadPool = new QueuedThreadPool();
|
||||
protected ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
|
@ -48,14 +50,14 @@ public class SslConnectionTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint, Object attachment)
|
||||
public Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment)
|
||||
{
|
||||
SSLEngine engine = __sslCtxFactory.newSslEngine();
|
||||
engine.setUseClientMode(false);
|
||||
SslConnection sslConnection = new SslConnection(__byteBufferPool, _threadPool, endpoint, engine);
|
||||
|
||||
AsyncConnection appConnection = new TestConnection(sslConnection.getSslEndPoint());
|
||||
sslConnection.getSslEndPoint().setAsyncConnection(appConnection);
|
||||
Connection appConnection = new TestConnection(sslConnection.getDecryptedEndPoint());
|
||||
sslConnection.getDecryptedEndPoint().setConnection(appConnection);
|
||||
connectionOpened(appConnection);
|
||||
|
||||
return sslConnection;
|
||||
|
@ -103,24 +105,32 @@ public class SslConnectionTest
|
|||
_connector.close();
|
||||
}
|
||||
|
||||
public class TestConnection extends AbstractAsyncConnection
|
||||
public class TestConnection extends AbstractConnection
|
||||
{
|
||||
ByteBuffer _in = BufferUtil.allocate(8*1024);
|
||||
|
||||
public TestConnection(AsyncEndPoint endp)
|
||||
public TestConnection(EndPoint endp)
|
||||
{
|
||||
super(endp, _threadPool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
fillInterested();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onFillable()
|
||||
{
|
||||
AsyncEndPoint endp = getEndPoint();
|
||||
EndPoint endp = getEndPoint();
|
||||
try
|
||||
{
|
||||
boolean progress=true;
|
||||
|
|
|
@ -1,37 +1,62 @@
|
|||
package org.eclipse.jetty.io;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.WritePendingException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WriteFlusherTest
|
||||
{
|
||||
ByteArrayEndPoint _endp;
|
||||
final AtomicBoolean _flushIncomplete = new AtomicBoolean(false);
|
||||
WriteFlusher _flusher;
|
||||
final String _context = new String("Context");
|
||||
|
||||
@Mock
|
||||
private EndPoint _endPointMock;
|
||||
|
||||
private WriteFlusher _flusher;
|
||||
|
||||
private final AtomicBoolean _flushIncomplete = new AtomicBoolean(false);
|
||||
private final String _context = new String("Context");
|
||||
private ByteArrayEndPoint _endp;
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
_endp = new ByteArrayEndPoint(new byte[]{},10);
|
||||
_flushIncomplete.set(false);
|
||||
_flusher = new WriteFlusher(_endp)
|
||||
{
|
||||
{
|
||||
@Override
|
||||
protected void onIncompleteFlushed()
|
||||
{
|
||||
|
@ -39,35 +64,57 @@ public class WriteFlusherTest
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
@After
|
||||
public void after()
|
||||
|
||||
@Test
|
||||
public void testIgnorePreviousFailures() throws Exception
|
||||
{
|
||||
|
||||
_endp.setGrowOutput(true);
|
||||
|
||||
FutureCallback<String> callback = new FutureCallback<>();
|
||||
_flusher.onFail(new IOException("Ignored because no operation in progress"));
|
||||
_flusher.write(_context,callback,BufferUtil.toBuffer("How "),BufferUtil.toBuffer("now "),BufferUtil.toBuffer("brown "),BufferUtil.toBuffer("cow!"));
|
||||
assertCallbackIsDone(callback);
|
||||
assertFlushIsComplete();
|
||||
assertThat("context and callback.get() are equal", _context, equalTo(callback.get()));
|
||||
assertThat("string in endpoint matches expected string", "How now brown cow!",
|
||||
equalTo(_endp.takeOutputString()));
|
||||
assertTrue(_flusher.isIdle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompleteNoBlocking() throws Exception
|
||||
{
|
||||
_endp.setGrowOutput(true);
|
||||
|
||||
|
||||
FutureCallback<String> callback = new FutureCallback<>();
|
||||
_flusher.write(_context,callback,BufferUtil.toBuffer("How "),BufferUtil.toBuffer("now "),BufferUtil.toBuffer("brown "),BufferUtil.toBuffer("cow!"));
|
||||
assertTrue(callback.isDone());
|
||||
assertFalse(_flushIncomplete.get());
|
||||
assertEquals(_context,callback.get());
|
||||
assertEquals("How now brown cow!",_endp.takeOutputString());
|
||||
assertCallbackIsDone(callback);
|
||||
assertFlushIsComplete();
|
||||
assertThat("context and callback.get() are equal", _context, equalTo(callback.get()));
|
||||
assertThat("string in endpoint matches expected string", "How now brown cow!",
|
||||
equalTo(_endp.takeOutputString()));
|
||||
assertTrue(_flusher.isIdle());
|
||||
}
|
||||
|
||||
|
||||
private void assertFlushIsComplete()
|
||||
{
|
||||
assertThat("flush is complete", _flushIncomplete.get(), is(false));
|
||||
}
|
||||
|
||||
private void assertCallbackIsDone(FutureCallback<String> callback)
|
||||
{
|
||||
assertThat("callback is done", callback.isDone(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClosedNoBlocking() throws Exception
|
||||
{
|
||||
_endp.close();
|
||||
|
||||
|
||||
FutureCallback<String> callback = new FutureCallback<>();
|
||||
_flusher.write(_context,callback,BufferUtil.toBuffer("How "),BufferUtil.toBuffer("now "),BufferUtil.toBuffer("brown "),BufferUtil.toBuffer("cow!"));
|
||||
assertTrue(callback.isDone());
|
||||
assertFalse(_flushIncomplete.get());
|
||||
assertCallbackIsDone(callback);
|
||||
assertFlushIsComplete();
|
||||
try
|
||||
{
|
||||
assertEquals(_context,callback.get());
|
||||
|
@ -80,17 +127,18 @@ public class WriteFlusherTest
|
|||
Assert.assertThat(cause.getMessage(),Matchers.containsString("CLOSED"));
|
||||
}
|
||||
assertEquals("",_endp.takeOutputString());
|
||||
assertTrue(_flusher.isIdle());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testCompleteBlocking() throws Exception
|
||||
{
|
||||
{
|
||||
FutureCallback<String> callback = new FutureCallback<>();
|
||||
_flusher.write(_context,callback,BufferUtil.toBuffer("How "),BufferUtil.toBuffer("now "),BufferUtil.toBuffer("brown "),BufferUtil.toBuffer("cow!"));
|
||||
assertFalse(callback.isDone());
|
||||
assertFalse(callback.isCancelled());
|
||||
|
||||
|
||||
assertTrue(_flushIncomplete.get());
|
||||
try
|
||||
{
|
||||
|
@ -104,12 +152,13 @@ public class WriteFlusherTest
|
|||
|
||||
assertEquals("How now br",_endp.takeOutputString());
|
||||
_flusher.completeWrite();
|
||||
assertTrue(callback.isDone());
|
||||
assertCallbackIsDone(callback);
|
||||
assertEquals(_context,callback.get());
|
||||
assertEquals("own cow!",_endp.takeOutputString());
|
||||
assertFalse(_flushIncomplete.get());
|
||||
assertFlushIsComplete();
|
||||
assertTrue(_flusher.isIdle());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCloseWhileBlocking() throws Exception
|
||||
{
|
||||
|
@ -118,7 +167,7 @@ public class WriteFlusherTest
|
|||
|
||||
assertFalse(callback.isDone());
|
||||
assertFalse(callback.isCancelled());
|
||||
|
||||
|
||||
assertTrue(_flushIncomplete.get());
|
||||
try
|
||||
{
|
||||
|
@ -133,8 +182,8 @@ public class WriteFlusherTest
|
|||
assertEquals("How now br",_endp.takeOutputString());
|
||||
_endp.close();
|
||||
_flusher.completeWrite();
|
||||
assertTrue(callback.isDone());
|
||||
assertFalse(_flushIncomplete.get());
|
||||
assertCallbackIsDone(callback);
|
||||
assertFlushIsComplete();
|
||||
try
|
||||
{
|
||||
assertEquals(_context,callback.get());
|
||||
|
@ -147,6 +196,7 @@ public class WriteFlusherTest
|
|||
Assert.assertThat(cause.getMessage(),Matchers.containsString("CLOSED"));
|
||||
}
|
||||
assertEquals("",_endp.takeOutputString());
|
||||
assertTrue(_flusher.isIdle());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -157,7 +207,7 @@ public class WriteFlusherTest
|
|||
|
||||
assertFalse(callback.isDone());
|
||||
assertFalse(callback.isCancelled());
|
||||
|
||||
|
||||
assertTrue(_flushIncomplete.get());
|
||||
try
|
||||
{
|
||||
|
@ -169,11 +219,11 @@ public class WriteFlusherTest
|
|||
_flushIncomplete.set(false);
|
||||
}
|
||||
|
||||
assertEquals("How now br",_endp.takeOutputString());
|
||||
_flusher.failed(new IOException("Failure"));
|
||||
assertEquals("How now br", _endp.takeOutputString());
|
||||
_flusher.onFail(new IOException("Failure"));
|
||||
_flusher.completeWrite();
|
||||
assertTrue(callback.isDone());
|
||||
assertFalse(_flushIncomplete.get());
|
||||
assertCallbackIsDone(callback);
|
||||
assertFlushIsComplete();
|
||||
try
|
||||
{
|
||||
assertEquals(_context,callback.get());
|
||||
|
@ -185,7 +235,332 @@ public class WriteFlusherTest
|
|||
Assert.assertTrue(cause instanceof IOException);
|
||||
Assert.assertThat(cause.getMessage(),Matchers.containsString("Failure"));
|
||||
}
|
||||
assertEquals("",_endp.takeOutputString());
|
||||
assertEquals("", _endp.takeOutputString());
|
||||
|
||||
assertTrue(_flusher.isIdle());
|
||||
}
|
||||
|
||||
private static class ConcurrentFlusher extends WriteFlusher implements Runnable
|
||||
{
|
||||
final ByteArrayEndPoint _endp;
|
||||
final SecureRandom _random;
|
||||
final ScheduledThreadPoolExecutor _scheduler;
|
||||
final StringBuilder _content=new StringBuilder();
|
||||
|
||||
ConcurrentFlusher(ByteArrayEndPoint endp,SecureRandom random, ScheduledThreadPoolExecutor scheduler)
|
||||
{
|
||||
super(endp);
|
||||
_endp=endp;
|
||||
_random=random;
|
||||
_scheduler=scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIncompleteFlushed()
|
||||
{
|
||||
_scheduler.schedule(this,1+_random.nextInt(9),TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void run()
|
||||
{
|
||||
_content.append(_endp.takeOutputString());
|
||||
completeWrite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toString()
|
||||
{
|
||||
_content.append(_endp.takeOutputString());
|
||||
return _content.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrent() throws Exception
|
||||
{
|
||||
final SecureRandom random = new SecureRandom();
|
||||
final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(100);
|
||||
|
||||
|
||||
ConcurrentFlusher[] flushers = new ConcurrentFlusher[50000];
|
||||
FutureCallback<?>[] futures = new FutureCallback<?>[flushers.length];
|
||||
for (int i=0;i<flushers.length;i++)
|
||||
{
|
||||
int size=5+random.nextInt(15);
|
||||
ByteArrayEndPoint endp = new ByteArrayEndPoint(new byte[]{},size);
|
||||
|
||||
final ConcurrentFlusher flusher = new ConcurrentFlusher(endp,random,scheduler);
|
||||
flushers[i]=flusher;
|
||||
final FutureCallback<String> callback = new FutureCallback<>();
|
||||
futures[i]=callback;
|
||||
scheduler.schedule(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
flusher.onFail(new Throwable("THE CAUSE"));
|
||||
}
|
||||
}
|
||||
,random.nextInt(75)+1,TimeUnit.MILLISECONDS);
|
||||
flusher.write(_context,callback,BufferUtil.toBuffer("How Now Brown Cow."),BufferUtil.toBuffer(" The quick brown fox jumped over the lazy dog!"));
|
||||
}
|
||||
|
||||
int completed=0;
|
||||
int failed=0;
|
||||
|
||||
for (int i=0;i<flushers.length;i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
futures[i].get();
|
||||
assertEquals("How Now Brown Cow. The quick brown fox jumped over the lazy dog!",flushers[i].toString());
|
||||
completed++;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
assertThat(e.getMessage(),Matchers.containsString("THE CAUSE"));
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(completed,Matchers.greaterThan(0));
|
||||
assertThat(failed,Matchers.greaterThan(0));
|
||||
|
||||
scheduler.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testConcurrentAccessToWriteAndFailed() throws IOException, InterruptedException, ExecutionException
|
||||
{
|
||||
ExecutorService executor = Executors.newFixedThreadPool(16);
|
||||
final CountDownLatch failedCalledLatch = new CountDownLatch(1);
|
||||
final CountDownLatch writeCalledLatch = new CountDownLatch(1);
|
||||
final CountDownLatch writeCompleteLatch = new CountDownLatch(1);
|
||||
|
||||
final WriteFlusher writeFlusher = new WriteFlusher(_endPointMock)
|
||||
{
|
||||
@Override
|
||||
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers)
|
||||
{
|
||||
super.write(context, callback, buffers);
|
||||
writeCompleteLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIncompleteFlushed()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
endPointFlushExpectation(writeCalledLatch, failedCalledLatch);
|
||||
|
||||
ExposingStateCallback callback = new ExposingStateCallback();
|
||||
executor.submit(new Writer(writeFlusher, callback));
|
||||
assertThat("Write has been called.", writeCalledLatch.await(5, TimeUnit.SECONDS), is(true));
|
||||
executor.submit(new FailedCaller(writeFlusher, failedCalledLatch)).get();
|
||||
// callback failed is NOT called because in WRITING state failed() doesn't know about the callback. However
|
||||
// either the write succeeds or we get an IOException which will call callback.failed()
|
||||
assertThat("callback failed", callback.isFailed(), is(false));
|
||||
assertThat("write complete", writeCompleteLatch.await(5, TimeUnit.SECONDS), is(true));
|
||||
// in this testcase we more or less emulate that the write has successfully finished and we return from
|
||||
// EndPoint.flush() back to WriteFlusher.write(). Then someone calls failed. So the callback should have been
|
||||
// completed.
|
||||
assertThat("callback completed", callback.isCompleted(), is(true));
|
||||
}
|
||||
|
||||
private class ExposingStateCallback extends FutureCallback
|
||||
{
|
||||
private boolean failed = false;
|
||||
private boolean completed = false;
|
||||
|
||||
@Override
|
||||
public void completed(Object context)
|
||||
{
|
||||
completed = true;
|
||||
super.completed(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Object context, Throwable cause)
|
||||
{
|
||||
failed = true;
|
||||
super.failed(context, cause);
|
||||
}
|
||||
|
||||
public boolean isFailed()
|
||||
{
|
||||
return failed;
|
||||
}
|
||||
|
||||
public boolean isCompleted()
|
||||
{
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("Intermittent failures.") //TODO: fixme
|
||||
@Test(expected = WritePendingException.class)
|
||||
public void testConcurrentAccessToWrite() throws Throwable
|
||||
{
|
||||
ExecutorService executor = Executors.newFixedThreadPool(16);
|
||||
|
||||
final WriteFlusher writeFlusher = new WriteFlusher(_endPointMock)
|
||||
{
|
||||
@Override
|
||||
protected void onIncompleteFlushed()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// in this test we just want to make sure that we called write twice at the same time
|
||||
when(_endPointMock.flush(any(ByteBuffer[].class))).thenAnswer(new Answer<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable
|
||||
{
|
||||
// make sure we stay here, so write is called twice at the same time
|
||||
Thread.sleep(5000);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
executor.submit(new Writer(writeFlusher, new FutureCallback()));
|
||||
try
|
||||
{
|
||||
executor.submit(new Writer(writeFlusher, new FutureCallback())).get();
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
private void endPointFlushExpectation(final CountDownLatch writeCalledLatch,
|
||||
final CountDownLatch failedCalledLatch) throws IOException
|
||||
{
|
||||
when(_endPointMock.flush(any(ByteBuffer[].class))).thenAnswer(new Answer<Object>()
|
||||
{
|
||||
int called = 0;
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable
|
||||
{
|
||||
called++;
|
||||
Object[] arguments = invocation.getArguments();
|
||||
ByteBuffer byteBuffer = (ByteBuffer)arguments[0];
|
||||
BufferUtil.flipToFill(byteBuffer); // pretend everything has been written
|
||||
writeCalledLatch.countDown();
|
||||
failedCalledLatch.await(5, TimeUnit.SECONDS);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testConcurrentAccessToIncompleteWriteAndFailed() throws IOException, InterruptedException, ExecutionException
|
||||
{
|
||||
ExecutorService executor = Executors.newFixedThreadPool(16);
|
||||
final CountDownLatch failedCalledLatch = new CountDownLatch(1);
|
||||
final CountDownLatch onIncompleteFlushedCalledLatch = new CountDownLatch(1);
|
||||
final CountDownLatch writeCalledLatch = new CountDownLatch(1);
|
||||
final CountDownLatch completeWrite = new CountDownLatch(1);
|
||||
|
||||
final WriteFlusher writeFlusher = new WriteFlusher(_endPointMock)
|
||||
{
|
||||
protected void onIncompleteFlushed()
|
||||
{
|
||||
onIncompleteFlushedCalledLatch.countDown();
|
||||
completeWrite();
|
||||
completeWrite.countDown();
|
||||
}
|
||||
};
|
||||
|
||||
endPointFlushExpectationPendingWrite(writeCalledLatch, failedCalledLatch);
|
||||
|
||||
ExposingStateCallback callback = new ExposingStateCallback();
|
||||
executor.submit(new Writer(writeFlusher, callback));
|
||||
assertThat("Write has been called.", writeCalledLatch.await(5, TimeUnit.SECONDS), is(true));
|
||||
executor.submit(new FailedCaller(writeFlusher, failedCalledLatch));
|
||||
assertThat("Failed has been called.", failedCalledLatch.await(5, TimeUnit.SECONDS), is(true));
|
||||
writeFlusher.write(_context, new FutureCallback<String>(), BufferUtil.toBuffer("foobar"));
|
||||
assertThat("completeWrite done", completeWrite.await(5, TimeUnit.SECONDS), is(true));
|
||||
}
|
||||
|
||||
|
||||
//TODO: combine with endPointFlushExpectation
|
||||
private void endPointFlushExpectationPendingWrite(final CountDownLatch writeCalledLatch, final CountDownLatch
|
||||
failedCalledLatch)
|
||||
throws
|
||||
IOException
|
||||
{
|
||||
when(_endPointMock.flush(any(ByteBuffer[].class))).thenAnswer(new Answer<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable
|
||||
{
|
||||
writeCalledLatch.countDown();
|
||||
Object[] arguments = invocation.getArguments();
|
||||
ByteBuffer byteBuffer = (ByteBuffer)arguments[0];
|
||||
int oldPos = byteBuffer.position();
|
||||
if (byteBuffer.remaining() == 2)
|
||||
{
|
||||
// make sure failed is called before we go on
|
||||
failedCalledLatch.await(5, TimeUnit.SECONDS);
|
||||
BufferUtil.flipToFill(byteBuffer);
|
||||
}
|
||||
else if (byteBuffer.remaining() == 3)
|
||||
{
|
||||
byteBuffer.position(1); // pretend writing one byte
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBuffer.position(byteBuffer.limit());
|
||||
}
|
||||
return byteBuffer.limit() - oldPos;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class FailedCaller implements Callable
|
||||
{
|
||||
private final WriteFlusher writeFlusher;
|
||||
private CountDownLatch failedCalledLatch;
|
||||
|
||||
public FailedCaller(WriteFlusher writeFlusher, CountDownLatch failedCalledLatch)
|
||||
{
|
||||
this.writeFlusher = writeFlusher;
|
||||
this.failedCalledLatch = failedCalledLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureCallback call()
|
||||
{
|
||||
writeFlusher.onFail(new IllegalStateException());
|
||||
failedCalledLatch.countDown();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class Writer implements Callable
|
||||
{
|
||||
private final WriteFlusher writeFlusher;
|
||||
private FutureCallback<String> callback;
|
||||
|
||||
public Writer(WriteFlusher writeFlusher, FutureCallback callback)
|
||||
{
|
||||
this.writeFlusher = writeFlusher;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureCallback call()
|
||||
{
|
||||
writeFlusher.write(_context, callback, BufferUtil.toBuffer("foo"));
|
||||
return callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.io.LEVEL=WARN
|
|
@ -18,13 +18,10 @@ import static org.junit.Assert.assertTrue;
|
|||
import java.lang.management.ManagementFactory;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ public class ProxyServer
|
|||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(server);
|
||||
connector.setPort(8888);
|
||||
server.addConnector(connector);
|
||||
|
||||
|
|
|
@ -23,8 +23,9 @@ import org.eclipse.jetty.http.HttpCookie;
|
|||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.proxy.BalancerServlet;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.session.HashSessionIdManager;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
|
@ -103,7 +104,7 @@ public abstract class AbstractBalancerServletTest
|
|||
private Server createServer(ServletHolder servletHolder, String appContext, String servletUrlPattern)
|
||||
{
|
||||
Server server = new Server();
|
||||
SelectChannelConnector httpConnector = new SelectChannelConnector();
|
||||
SelectChannelConnector httpConnector = new SelectChannelConnector(server);
|
||||
server.addConnector(httpConnector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
|
@ -122,9 +123,9 @@ public abstract class AbstractBalancerServletTest
|
|||
node.setSessionIdManager(sessionIdManager);
|
||||
}
|
||||
|
||||
private int getServerPort(Server node)
|
||||
private int getServerPort(Server server)
|
||||
{
|
||||
return node.getConnectors()[0].getLocalPort();
|
||||
return ((Connector.NetConnector)server.getConnectors()[0]).getLocalPort();
|
||||
}
|
||||
|
||||
protected byte[] sendRequestToBalancer(String requestUri) throws IOException, InterruptedException
|
||||
|
|
|
@ -76,8 +76,8 @@
|
|||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
@ -26,7 +26,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpConnector;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
|
@ -355,7 +355,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
return true;
|
||||
}
|
||||
|
||||
HttpConnector connector = HttpChannel.getCurrentHttpChannel().getHttpConnector();
|
||||
HttpConfiguration connector = HttpChannel.getCurrentHttpChannel().getHttpConfiguration();
|
||||
|
||||
if (dataConstraint == UserDataConstraint.Integral)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.eclipse.jetty.security;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
|
|
|
@ -16,6 +16,7 @@ package org.eclipse.jetty.security.authentication;
|
|||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
package org.eclipse.jetty.security;
|
||||
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -32,7 +33,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.LocalHttpConnector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
|
@ -43,7 +44,9 @@ import org.eclipse.jetty.server.session.SessionHandler;
|
|||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Password;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
@ -54,16 +57,16 @@ import org.junit.Test;
|
|||
public class ConstraintTest
|
||||
{
|
||||
private static final String TEST_REALM = "TestRealm";
|
||||
private static Server _server;
|
||||
private static LocalHttpConnector _connector;
|
||||
private static SessionHandler _session;
|
||||
private Server _server;
|
||||
private LocalConnector _connector;
|
||||
private SessionHandler _session;
|
||||
private ConstraintSecurityHandler _security;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer()
|
||||
@Before
|
||||
public void startServer()
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalHttpConnector();
|
||||
_connector = new LocalConnector(_server);
|
||||
_server.setConnectors(new Connector[]{_connector});
|
||||
|
||||
ContextHandler _context = new ContextHandler();
|
||||
|
@ -79,11 +82,7 @@ public class ConstraintTest
|
|||
_context.setHandler(_session);
|
||||
|
||||
_server.addBean(_loginService);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupSecurity()
|
||||
{
|
||||
|
||||
_security = new ConstraintSecurityHandler();
|
||||
_session.setHandler(_security);
|
||||
RequestHandler _handler = new RequestHandler();
|
||||
|
@ -192,52 +191,52 @@ public class ConstraintTest
|
|||
|
||||
String response;
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: basic realm=\"TestRealm\""));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: basic realm=\"TestRealm\""));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
||||
// test admin
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: basic realm=\"TestRealm\""));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: basic realm=\"TestRealm\""));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 "));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403 "));
|
||||
assertThat(response,containsString("!role"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/relax/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -250,10 +249,10 @@ public class ConstraintTest
|
|||
String response;
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response,containsString("Cache-Control: no-cache"));
|
||||
|
@ -268,7 +267,7 @@ public class ConstraintTest
|
|||
"Content-Length: 31\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=wrong\r\n");
|
||||
assertTrue(response.indexOf("testErrorPage") > 0);
|
||||
assertThat(response,containsString("testErrorPage"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
|
@ -276,21 +275,22 @@ public class ConstraintTest
|
|||
"Content-Length: 35\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -303,21 +303,21 @@ public class ConstraintTest
|
|||
String response;
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.indexOf(" 302 Found") > 0);
|
||||
assertTrue(response.indexOf("/ctx/testLoginPage") > 0);
|
||||
assertThat(response,containsString(" 302 Found"));
|
||||
assertThat(response,containsString("/ctx/testLoginPage"));
|
||||
String session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/testLoginPage HTTP/1.0\r\n"+
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.indexOf(" 200 OK") > 0);
|
||||
assertTrue(response.indexOf("URI=/ctx/testLoginPage") > 0);
|
||||
assertThat(response,containsString(" 200 OK"));
|
||||
assertThat(response,containsString("URI=/ctx/testLoginPage"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
|
@ -325,7 +325,7 @@ public class ConstraintTest
|
|||
"Content-Length: 31\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=wrong\r\n");
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertThat(response,containsString("Location"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
|
@ -333,21 +333,21 @@ public class ConstraintTest
|
|||
"Content-Length: 35\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -360,25 +360,25 @@ public class ConstraintTest
|
|||
String response;
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/auth/info HTTP/1.0\r\n"+
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: 27\r\n" +
|
||||
"\r\n" +
|
||||
"test_parameter=test_value\r\n");
|
||||
assertTrue(response.indexOf(" 302 Found") > 0);
|
||||
assertTrue(response.indexOf("/ctx/testLoginPage") > 0);
|
||||
assertThat(response,containsString(" 302 Found"));
|
||||
assertThat(response,containsString("/ctx/testLoginPage"));
|
||||
String session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/testLoginPage HTTP/1.0\r\n"+
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.indexOf(" 200 OK") > 0);
|
||||
assertTrue(response.indexOf("URI=/ctx/testLoginPage") > 0);
|
||||
assertThat(response,containsString(" 200 OK"));
|
||||
assertThat(response,containsString("URI=/ctx/testLoginPage"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
|
@ -386,7 +386,7 @@ public class ConstraintTest
|
|||
"Content-Length: 31\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=wrong\r\n");
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertThat(response,containsString("Location"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
|
@ -394,30 +394,30 @@ public class ConstraintTest
|
|||
"Content-Length: 35\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
// sneak in other request
|
||||
response = _connector.getResponses("GET /ctx/auth/other HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
assertTrue(!response.contains("test_value"));
|
||||
|
||||
// retry post as GET
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
assertTrue(response.contains("test_value"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -430,47 +430,47 @@ public class ConstraintTest
|
|||
String response;
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.indexOf(" 302 Found") > 0);
|
||||
assertTrue(response.indexOf("/ctx/testLoginPage") > 0);
|
||||
assertThat(response,containsString(" 302 Found"));
|
||||
assertThat(response,containsString("/ctx/testLoginPage"));
|
||||
int jsession=response.indexOf(";jsessionid=");
|
||||
String session = response.substring(jsession + 12, response.indexOf("\r\n",jsession));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/testLoginPage;jsessionid="+session+";other HTTP/1.0\r\n"+
|
||||
"\r\n");
|
||||
assertTrue(response.indexOf(" 200 OK") > 0);
|
||||
assertTrue(response.indexOf("URI=/ctx/testLoginPage") > 0);
|
||||
assertThat(response,containsString(" 200 OK"));
|
||||
assertThat(response,containsString("URI=/ctx/testLoginPage"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check;jsessionid="+session+";other HTTP/1.0\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: 31\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=wrong\r\n");
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertThat(response,containsString("Location"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check;jsessionid="+session+";other HTTP/1.0\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: 35\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info;jsessionid="+session+";other HTTP/1.0\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info;jsessionid="+session+";other HTTP/1.0\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -481,58 +481,58 @@ public class ConstraintTest
|
|||
|
||||
String response;
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: basic realm=\"TestRealm\""));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: basic realm=\"TestRealm\""));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
||||
// test admin
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: basic realm=\"TestRealm\""));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertThat(response,containsString("WWW-Authenticate: basic realm=\"TestRealm\""));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 "));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403 "));
|
||||
assertThat(response,containsString("!role"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/relax/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -545,17 +545,17 @@ public class ConstraintTest
|
|||
String response;
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
// assertTrue(response.indexOf(" 302 Found") > 0);
|
||||
// assertTrue(response.indexOf("/ctx/testLoginPage") > 0);
|
||||
assertTrue(response.indexOf("Cache-Control: no-cache") > 0);
|
||||
assertTrue(response.indexOf("Expires") > 0);
|
||||
assertTrue(response.indexOf("URI=/ctx/testLoginPage") > 0);
|
||||
// assertThat(response,containsString(" 302 Found"));
|
||||
// assertThat(response,containsString("/ctx/testLoginPage"));
|
||||
assertThat(response,containsString("Cache-Control: no-cache"));
|
||||
assertThat(response,containsString("Expires"));
|
||||
assertThat(response,containsString("URI=/ctx/testLoginPage"));
|
||||
|
||||
String session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
|
@ -565,8 +565,8 @@ public class ConstraintTest
|
|||
"Content-Length: 31\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=wrong\r\n");
|
||||
// assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("testErrorPage") > 0);
|
||||
// assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("testErrorPage"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
|
@ -574,29 +574,29 @@ public class ConstraintTest
|
|||
"Content-Length: 35\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
|
||||
|
||||
|
||||
// log in again as user2
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
// assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
// assertTrue(response.indexOf("testLoginPage") > 0);
|
||||
// assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
// assertThat(response,containsString("testLoginPage"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
|
@ -605,28 +605,28 @@ public class ConstraintTest
|
|||
"Content-Length: 36\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user2&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
|
||||
|
||||
|
||||
// log in again as admin
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
// assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
// assertTrue(response.indexOf("testLoginPage") > 0);
|
||||
// assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
// assertThat(response,containsString("testLoginPage"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
|
@ -635,20 +635,20 @@ public class ConstraintTest
|
|||
"Content-Length: 36\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=admin&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -660,14 +660,14 @@ public class ConstraintTest
|
|||
String response;
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
assertThat(response,startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.indexOf(" 302 Found") > 0);
|
||||
assertTrue(response.indexOf("/ctx/testLoginPage") > 0);
|
||||
assertThat(response,containsString(" 302 Found"));
|
||||
assertThat(response,containsString("/ctx/testLoginPage"));
|
||||
|
||||
String session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
|
@ -677,7 +677,7 @@ public class ConstraintTest
|
|||
"Content-Length: 31\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=wrong\r\n");
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertThat(response,containsString("Location"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
|
@ -685,29 +685,29 @@ public class ConstraintTest
|
|||
"Content-Length: 35\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
|
||||
|
||||
|
||||
// log in again as user2
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("testLoginPage") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("testLoginPage"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
|
@ -716,29 +716,29 @@ public class ConstraintTest
|
|||
"Content-Length: 36\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user2&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||
assertTrue(response.indexOf("!role") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 403"));
|
||||
assertThat(response,containsString("!role"));
|
||||
|
||||
|
||||
|
||||
// log in again as admin
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
// assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
// assertTrue(response.indexOf("testLoginPage") > 0);
|
||||
// assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
// assertThat(response,containsString("testLoginPage"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
|
@ -747,20 +747,20 @@ public class ConstraintTest
|
|||
"Content-Length: 36\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=admin&j_password=password\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 302 "));
|
||||
assertTrue(response.indexOf("Location") > 0);
|
||||
assertTrue(response.indexOf("/ctx/auth/info") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response,containsString("Location"));
|
||||
assertThat(response,containsString("/ctx/auth/info"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -774,12 +774,12 @@ public class ConstraintTest
|
|||
|
||||
String response;
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 500 "));
|
||||
assertThat(response,startsWith("HTTP/1.1 500 "));
|
||||
|
||||
_server.stop();
|
||||
|
||||
|
@ -792,7 +792,7 @@ public class ConstraintTest
|
|||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -806,20 +806,20 @@ public class ConstraintTest
|
|||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n"+
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertTrue(response.indexOf("user=null") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,containsString("user=null"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n"+
|
||||
"Authorization: Basic " + B64Code.encode("admin:wrong") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertTrue(response.indexOf("user=null") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,containsString("user=null"));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n"+
|
||||
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertTrue(response.indexOf("user=admin") > 0);
|
||||
assertThat(response,startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response,containsString("user=admin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -831,13 +831,13 @@ public class ConstraintTest
|
|||
|
||||
String response;
|
||||
response = _connector.getResponses("GET /ctx/forbid/somethig HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 "));
|
||||
assertThat(response,startsWith("HTTP/1.1 403 "));
|
||||
|
||||
response = _connector.getResponses("POST /ctx/forbid/post HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 "));
|
||||
assertThat(response,startsWith("HTTP/1.1 200 "));
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/post HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 ")); // This is so stupid, but it is the S P E C
|
||||
assertThat(response,startsWith("HTTP/1.1 200 ")); // This is so stupid, but it is the S P E C
|
||||
}
|
||||
private class RequestHandler extends AbstractHandler
|
||||
{
|
||||
|
|
|
@ -13,8 +13,12 @@
|
|||
|
||||
package org.eclipse.jetty.security;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -23,7 +27,8 @@ import org.eclipse.jetty.http.HttpMethod;
|
|||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.LocalHttpConnector;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
|
@ -35,17 +40,14 @@ import org.junit.After;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1441 $ $Date: 2010-04-02 12:28:17 +0200 (Fri, 02 Apr 2010) $
|
||||
*/
|
||||
public class DataConstraintsTest
|
||||
{
|
||||
private Server _server;
|
||||
private LocalHttpConnector _connector;
|
||||
private LocalHttpConnector _connectorS;
|
||||
private LocalConnector _connector;
|
||||
private LocalConnector _connectorS;
|
||||
private SessionHandler _session;
|
||||
private ConstraintSecurityHandler _security;
|
||||
|
||||
|
@ -53,15 +55,15 @@ public class DataConstraintsTest
|
|||
public void startServer()
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalHttpConnector();
|
||||
_connector = new LocalConnector(_server);
|
||||
_connector.setIdleTimeout(300000);
|
||||
_connector.setIntegralPort(9998);
|
||||
_connector.setIntegralScheme("FTP");
|
||||
_connector.setConfidentialPort(9999);
|
||||
_connector.setConfidentialScheme("SPDY");
|
||||
_connectorS = new LocalHttpConnector()
|
||||
_connector.getConnectionFactory().getHttpConfig().setIntegralPort(9998);
|
||||
_connector.getConnectionFactory().getHttpConfig().setIntegralScheme("FTP");
|
||||
_connector.getConnectionFactory().getHttpConfig().setConfidentialPort(9999);
|
||||
_connector.getConnectionFactory().getHttpConfig().setConfidentialScheme("SPDY");
|
||||
_connectorS = new LocalConnector(_server,
|
||||
new HttpConfiguration(null,false)
|
||||
{
|
||||
|
||||
@Override
|
||||
public void customize(Request request) throws IOException
|
||||
{
|
||||
|
@ -81,7 +83,7 @@ public class DataConstraintsTest
|
|||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
_server.setConnectors(new Connector[]{_connector,_connectorS});
|
||||
|
||||
ContextHandler _context = new ContextHandler();
|
||||
|
|
|
@ -16,15 +16,23 @@ package org.eclipse.jetty.server;
|
|||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.StandardByteBufferPool;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
/**
|
||||
* Abstract Connector implementation. This abstract implementation of the Connector interface provides:
|
||||
|
@ -42,23 +50,57 @@ public abstract class AbstractConnector extends AggregateLifeCycle implements Co
|
|||
protected final Logger LOG = Log.getLogger(getClass());
|
||||
|
||||
private final Statistics _stats = new ConnectionStatistics();
|
||||
private final ConnectionFactory _connectionFactory;
|
||||
private final Thread[] _acceptors;
|
||||
private final Executor _executor;
|
||||
private final ScheduledExecutorService _scheduler;
|
||||
private final Server _server;
|
||||
private final ByteBufferPool _byteBufferPool;
|
||||
|
||||
private volatile String _name;
|
||||
private volatile Server _server;
|
||||
private volatile Executor _executor;
|
||||
private volatile int _acceptQueueSize = 128;
|
||||
private volatile boolean _reuseAddress = true;
|
||||
private volatile ByteBufferPool _byteBufferPool;
|
||||
private volatile long _idleTimeout = 200000;
|
||||
private volatile int _soLingerTime = -1;
|
||||
|
||||
public AbstractConnector()
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param server The server this connector will be added to. Must not be null.
|
||||
* @param connectionFactory ConnectionFactory or null for default
|
||||
* @param executor An executor for this connector or null to use the servers executor
|
||||
* @param scheduler A scheduler for this connector or null to use the servers scheduler
|
||||
* @param pool A buffer pool for this connector or null to use a default {@link ByteBufferPool}
|
||||
* @param acceptors the number of acceptor threads to use, or 0 for a default value.
|
||||
*/
|
||||
public AbstractConnector(
|
||||
Server server,
|
||||
ConnectionFactory connectionFactory,
|
||||
Executor executor,
|
||||
ScheduledExecutorService scheduler,
|
||||
ByteBufferPool pool, int acceptors)
|
||||
{
|
||||
this(Math.max(1, (Runtime.getRuntime().availableProcessors()) / 4));
|
||||
}
|
||||
_server=server;
|
||||
_executor=executor!=null?executor:_server.getThreadPool();
|
||||
_scheduler=scheduler!=null?scheduler:Executors.newSingleThreadScheduledExecutor(new ThreadFactory()
|
||||
{
|
||||
@Override
|
||||
public Thread newThread(Runnable r)
|
||||
{
|
||||
return new Thread(r, "Timer-" + getName());
|
||||
}
|
||||
});
|
||||
_byteBufferPool = pool!=null?pool:new StandardByteBufferPool();
|
||||
|
||||
_connectionFactory=connectionFactory!=null?connectionFactory:new ConnectionFactory();
|
||||
|
||||
addBean(_server,false);
|
||||
addBean(_executor,false);
|
||||
addBean(_scheduler,scheduler==null);
|
||||
addBean(_byteBufferPool,pool==null);
|
||||
addBean(_connectionFactory,connectionFactory!=null);
|
||||
|
||||
public AbstractConnector(@Name("acceptors") int acceptors)
|
||||
{
|
||||
if (acceptors<=0)
|
||||
acceptors=Math.max(1,(Runtime.getRuntime().availableProcessors()) / 4);
|
||||
if (acceptors > 2 * Runtime.getRuntime().availableProcessors())
|
||||
LOG.warn("Acceptors should be <= 2*availableProcessors: " + this);
|
||||
_acceptors = new Thread[acceptors];
|
||||
|
@ -75,45 +117,25 @@ public abstract class AbstractConnector extends AggregateLifeCycle implements Co
|
|||
{
|
||||
return _server;
|
||||
}
|
||||
|
||||
public void setServer(Server server)
|
||||
|
||||
@Override
|
||||
public ConnectionFactory getConnectionFactory()
|
||||
{
|
||||
_server = server;
|
||||
return _connectionFactory;
|
||||
}
|
||||
|
||||
public Executor findExecutor()
|
||||
{
|
||||
if (_executor == null && getServer() != null)
|
||||
return getServer().getThreadPool();
|
||||
return _executor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return _executor;
|
||||
}
|
||||
|
||||
public void setExecutor(Executor executor)
|
||||
{
|
||||
removeBean(_executor);
|
||||
_executor = executor;
|
||||
addBean(_executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufferPool getByteBufferPool()
|
||||
{
|
||||
return _byteBufferPool;
|
||||
}
|
||||
|
||||
public void setByteBufferPool(ByteBufferPool byteBufferPool)
|
||||
{
|
||||
removeBean(byteBufferPool);
|
||||
_byteBufferPool = byteBufferPool;
|
||||
addBean(_byteBufferPool);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the maxIdleTime.
|
||||
*/
|
||||
|
@ -190,18 +212,13 @@ public abstract class AbstractConnector extends AggregateLifeCycle implements Co
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (_server == null)
|
||||
throw new IllegalStateException("No server");
|
||||
|
||||
_byteBufferPool = new StandardByteBufferPool();
|
||||
|
||||
super.doStart();
|
||||
|
||||
// Start selector thread
|
||||
synchronized (this)
|
||||
{
|
||||
for (int i = 0; i < _acceptors.length; i++)
|
||||
findExecutor().execute(new Acceptor(i));
|
||||
getExecutor().execute(new Acceptor(i));
|
||||
}
|
||||
|
||||
LOG.info("Started {}", this);
|
||||
|
@ -217,10 +234,6 @@ public abstract class AbstractConnector extends AggregateLifeCycle implements Co
|
|||
if (thread != null)
|
||||
thread.interrupt();
|
||||
}
|
||||
|
||||
int i = _name.lastIndexOf("/");
|
||||
if (i > 0)
|
||||
_name = _name.substring(0, i);
|
||||
}
|
||||
|
||||
public void join() throws InterruptedException
|
||||
|
@ -317,19 +330,19 @@ public abstract class AbstractConnector extends AggregateLifeCycle implements Co
|
|||
_name = name;
|
||||
}
|
||||
|
||||
protected void connectionOpened(AsyncConnection connection)
|
||||
protected void connectionOpened(Connection connection)
|
||||
{
|
||||
_stats.connectionOpened();
|
||||
}
|
||||
|
||||
protected void connectionUpgraded(AsyncConnection oldConnection, AsyncConnection newConnection)
|
||||
protected void connectionUpgraded(Connection oldConnection, Connection newConnection)
|
||||
{
|
||||
long duration = System.currentTimeMillis() - oldConnection.getEndPoint().getCreatedTimeStamp();
|
||||
int requests = (oldConnection instanceof HttpConnection) ? ((HttpConnection)oldConnection).getHttpChannel().getRequests() : 0;
|
||||
_stats.connectionUpgraded(duration, requests, requests);
|
||||
}
|
||||
|
||||
protected void connectionClosed(AsyncConnection connection)
|
||||
protected void connectionClosed(Connection connection)
|
||||
{
|
||||
long duration = System.currentTimeMillis() - connection.getEndPoint().getCreatedTimeStamp();
|
||||
// TODO: remove casts to HttpConnection
|
||||
|
@ -352,4 +365,9 @@ public abstract class AbstractConnector extends AggregateLifeCycle implements Co
|
|||
{
|
||||
_reuseAddress = reuseAddress;
|
||||
}
|
||||
|
||||
public ScheduledExecutorService getScheduler()
|
||||
{
|
||||
return _scheduler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,19 +14,20 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public abstract class AbstractNetConnector extends AbstractConnector implements Connector.NetConnector
|
||||
{
|
||||
private volatile String _host;
|
||||
private volatile int _port = 0;
|
||||
|
||||
protected AbstractNetConnector()
|
||||
public AbstractNetConnector(Server server, ConnectionFactory connectionFactory, Executor executor, ScheduledExecutorService scheduler, ByteBufferPool pool, int acceptors)
|
||||
{
|
||||
}
|
||||
|
||||
protected AbstractNetConnector(int acceptors)
|
||||
{
|
||||
super(acceptors);
|
||||
super(server,connectionFactory,executor,scheduler,pool, acceptors);
|
||||
}
|
||||
|
||||
public void setHost(String host)
|
||||
|
@ -34,6 +35,7 @@ public abstract class AbstractNetConnector extends AbstractConnector implements
|
|||
_host = host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHost()
|
||||
{
|
||||
return _host;
|
||||
|
@ -44,11 +46,13 @@ public abstract class AbstractNetConnector extends AbstractConnector implements
|
|||
_port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort()
|
||||
{
|
||||
return _port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalPort()
|
||||
{
|
||||
return -1;
|
||||
|
@ -79,12 +83,18 @@ public abstract class AbstractNetConnector extends AbstractConnector implements
|
|||
LOG.warn(e);
|
||||
}
|
||||
super.doStop();
|
||||
|
||||
int i = getName().lastIndexOf("/");
|
||||
if (i > 0)
|
||||
setName(getName().substring(0, i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2004-2012 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 javax.net.ssl.SSLEngine;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
// TODO This is just a place holder for a real factory
|
||||
public class ConnectionFactory extends AggregateLifeCycle
|
||||
{
|
||||
private final boolean _ssl;
|
||||
private final SslContextFactory _sslContextFactory;
|
||||
|
||||
|
||||
// TODO Make this part of pluggable factory
|
||||
private final HttpConfiguration _httpConfig;
|
||||
|
||||
|
||||
ConnectionFactory()
|
||||
{
|
||||
this(null,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param sslContextFactory An SslContextFactory to use or null if no ssl is required or to use default {@link SslContextFactory}
|
||||
* @param ssl If true, then new connections will assumed to be SSL. If false, connections can only become SSL if they upgrade and a SslContextFactory is passed.
|
||||
*/
|
||||
ConnectionFactory(SslContextFactory sslContextFactory, boolean ssl)
|
||||
{
|
||||
this(null,sslContextFactory,ssl);
|
||||
}
|
||||
|
||||
ConnectionFactory(HttpConfiguration httpConfig, SslContextFactory sslContextFactory, boolean ssl)
|
||||
{
|
||||
_ssl=ssl;
|
||||
_sslContextFactory=sslContextFactory!=null?sslContextFactory:(ssl?new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH):null);
|
||||
|
||||
addBean(_sslContextFactory,sslContextFactory==null);
|
||||
|
||||
// TODO make this pluggable
|
||||
_httpConfig = httpConfig!=null?httpConfig:new HttpConfiguration(_sslContextFactory,ssl);
|
||||
addBean(_httpConfig,httpConfig==null);
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected Connection newConnection(Connector connector,EndPoint endp) throws IOException
|
||||
{
|
||||
|
||||
if (_ssl)
|
||||
{
|
||||
SSLEngine engine = _sslContextFactory.createSSLEngine(endp.getRemoteAddress());
|
||||
SslConnection ssl_connection = new SslConnection(connector.getByteBufferPool(), connector.getExecutor(), endp, engine);
|
||||
|
||||
Connection http_connection = new HttpConnection(_httpConfig,connector,ssl_connection.getDecryptedEndPoint());
|
||||
ssl_connection.getDecryptedEndPoint().setConnection(http_connection);
|
||||
return ssl_connection;
|
||||
}
|
||||
return new HttpConnection(_httpConfig,connector,endp);
|
||||
}
|
||||
|
||||
public SslContextFactory getSslContextFactory()
|
||||
{
|
||||
return _sslContextFactory;
|
||||
}
|
||||
|
||||
public HttpConfiguration getHttpConfig()
|
||||
{
|
||||
return _httpConfig;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,3 +1,16 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2004-2012 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.util.concurrent.atomic.AtomicLong;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
|
||||
// Copyright (c) 2004-2012 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
|
||||
|
@ -15,9 +15,11 @@ package org.eclipse.jetty.server;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
/** HTTP Connector.
|
||||
* Implementations of this interface provide connectors for the HTTP protocol.
|
||||
|
@ -42,14 +44,17 @@ public interface Connector extends LifeCycle
|
|||
Server getServer();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
Executor findExecutor();
|
||||
|
||||
ConnectionFactory getConnectionFactory();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
Executor getExecutor();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
ScheduledExecutorService getScheduler();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
ByteBufferPool getByteBufferPool();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Max Idle time for connections in milliseconds
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.io.PrintWriter;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
|
@ -36,8 +37,8 @@ import org.eclipse.jetty.http.HttpStatus;
|
|||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.UncheckedPrintWriter;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
@ -71,7 +72,7 @@ public abstract class HttpChannel
|
|||
|
||||
|
||||
private final Server _server;
|
||||
private final AsyncConnection _connection;
|
||||
private final Connection _connection;
|
||||
private final HttpURI _uri;
|
||||
|
||||
private final ChannelEventHandler _handler = new ChannelEventHandler();
|
||||
|
@ -99,7 +100,7 @@ public abstract class HttpChannel
|
|||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpChannel(Server server,AsyncConnection connection,HttpInput input)
|
||||
public HttpChannel(Server server,Connection connection,HttpInput input)
|
||||
{
|
||||
_server = server;
|
||||
_connection = connection;
|
||||
|
@ -126,7 +127,7 @@ public abstract class HttpChannel
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public AsyncEndPoint getEndPoint()
|
||||
public EndPoint getEndPoint()
|
||||
{
|
||||
return getConnection().getEndPoint();
|
||||
}
|
||||
|
@ -189,7 +190,7 @@ public abstract class HttpChannel
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public AsyncConnection getConnection()
|
||||
public Connection getConnection()
|
||||
{
|
||||
return _connection;
|
||||
}
|
||||
|
@ -330,7 +331,7 @@ public abstract class HttpChannel
|
|||
if (_state.isInitial())
|
||||
{
|
||||
_request.setDispatcherType(DispatcherType.REQUEST);
|
||||
getHttpConnector().customize(_request);
|
||||
getHttpConfiguration().customize(_request);
|
||||
getServer().handle(this);
|
||||
}
|
||||
else
|
||||
|
@ -380,6 +381,7 @@ public abstract class HttpChannel
|
|||
{
|
||||
try
|
||||
{
|
||||
_state.completed();
|
||||
if (_expect100Continue)
|
||||
{
|
||||
LOG.debug("100 continues not sent");
|
||||
|
@ -413,7 +415,6 @@ public abstract class HttpChannel
|
|||
}
|
||||
finally
|
||||
{
|
||||
_state.completed();
|
||||
_request.setHandled(true);
|
||||
completed();
|
||||
}
|
||||
|
@ -790,7 +791,9 @@ public abstract class HttpChannel
|
|||
}
|
||||
}
|
||||
|
||||
public abstract HttpConnector getHttpConnector();
|
||||
public abstract Connector getConnector();
|
||||
|
||||
public abstract HttpConfiguration getHttpConfiguration();
|
||||
|
||||
protected abstract int write(ByteBuffer content) throws IOException;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.List;
|
|||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
|
|
|
@ -2,26 +2,35 @@ package org.eclipse.jetty.server;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.server.ssl.SslCertificates;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
|
||||
public abstract class HttpConnector extends AbstractNetConnector
|
||||
public class HttpConfiguration extends AggregateLifeCycle
|
||||
{
|
||||
static final Logger LOG = Log.getLogger(HttpConfiguration.class);
|
||||
|
||||
private final SslContextFactory _sslContextFactory;
|
||||
private final boolean _ssl;
|
||||
|
||||
private String _integralScheme = HttpScheme.HTTPS.asString();
|
||||
private int _integralPort = 0;
|
||||
private String _confidentialScheme = HttpScheme.HTTPS.asString();
|
||||
private int _confidentialPort = 0;
|
||||
private boolean _forwarded;
|
||||
private String _hostHeader;
|
||||
private ScheduledExecutorService _scheduler;
|
||||
private boolean _shutdownScheduler;
|
||||
private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
|
||||
private String _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
|
||||
private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
|
||||
|
@ -32,51 +41,23 @@ public abstract class HttpConnector extends AbstractNetConnector
|
|||
private int _requestBufferSize=16*1024;
|
||||
private int _responseHeaderSize=6*1024;
|
||||
private int _responseBufferSize=16*1024;
|
||||
|
||||
public HttpConnector()
|
||||
|
||||
public HttpConfiguration(SslContextFactory sslContextFactory,boolean ssl)
|
||||
{
|
||||
_sslContextFactory=sslContextFactory!=null?sslContextFactory:ssl?new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH):null;
|
||||
_ssl=ssl;
|
||||
if (_sslContextFactory!=null)
|
||||
addBean(_sslContextFactory,sslContextFactory==null);
|
||||
}
|
||||
|
||||
public SslContextFactory getSslContextFactory()
|
||||
{
|
||||
return _sslContextFactory;
|
||||
}
|
||||
|
||||
public HttpConnector(int acceptors)
|
||||
public boolean isSecure()
|
||||
{
|
||||
super(acceptors);
|
||||
}
|
||||
|
||||
public ScheduledExecutorService getScheduler()
|
||||
{
|
||||
return _scheduler;
|
||||
}
|
||||
|
||||
public void setScheduler(ScheduledExecutorService scheduler)
|
||||
{
|
||||
_scheduler = scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
if (_scheduler == null)
|
||||
{
|
||||
_scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory()
|
||||
{
|
||||
@Override
|
||||
public Thread newThread(Runnable r)
|
||||
{
|
||||
return new Thread(r, "Timer-" + HttpConnector.this.getName());
|
||||
}
|
||||
});
|
||||
_shutdownScheduler = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
if (_shutdownScheduler)
|
||||
_scheduler.shutdownNow();
|
||||
_scheduler = null;
|
||||
super.doStop();
|
||||
return _ssl;
|
||||
}
|
||||
|
||||
public int getRequestHeaderSize()
|
||||
|
@ -120,8 +101,37 @@ public abstract class HttpConnector extends AbstractNetConnector
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* 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>
|
||||
*/
|
||||
public void customize(Request request) throws IOException
|
||||
{
|
||||
{
|
||||
if (isSecure())
|
||||
{
|
||||
request.setScheme(HttpScheme.HTTPS.asString());
|
||||
SslConnection.DecryptedEndPoint ssl_endp = (SslConnection.DecryptedEndPoint)request.getHttpChannel().getEndPoint();
|
||||
SslConnection sslConnection = ssl_endp.getSslConnection();
|
||||
SSLEngine sslEngine=sslConnection.getSSLEngine();
|
||||
SslCertificates.customize(sslEngine,request);
|
||||
}
|
||||
|
||||
request.setTimeStamp(System.currentTimeMillis());
|
||||
if (isForwarded())
|
||||
checkForwardedHeaders(request);
|
||||
}
|
||||
|
@ -230,12 +240,23 @@ public abstract class HttpConnector extends AbstractNetConnector
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see org.eclipse.jetty.server.Connector#isConfidential(org.eclipse.jetty.server .Request)
|
||||
/**
|
||||
* The request is integral IFF it is secure AND the server port
|
||||
* matches any configured {@link #getIntegralPort()}.
|
||||
* 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.
|
||||
* <p>
|
||||
* The request is secure if it is SSL or it {@link #isForwarded()} is true
|
||||
* and the scheme matches {@link #getIntegralScheme()()}
|
||||
*/
|
||||
public boolean isIntegral(Request request)
|
||||
{
|
||||
return false;
|
||||
boolean https = isSecure() || _forwarded && _integralScheme.equalsIgnoreCase(request.getScheme());
|
||||
int iPort=getIntegralPort();
|
||||
boolean port = iPort<=0||iPort==request.getServerPort();
|
||||
return https && port;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -257,12 +278,23 @@ public abstract class HttpConnector extends AbstractNetConnector
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see org.eclipse.jetty.server.Connector#isConfidential(org.eclipse.jetty.server.Request)
|
||||
/**
|
||||
* The request is confidential IFF it is secure AND the server port
|
||||
* matches any configured {@link #getConfidentialPort()}.
|
||||
* 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.
|
||||
* <p>
|
||||
* The request is secure if it is SSL or it {@link #isForwarded()} is true
|
||||
* and the scheme matches {@link #getConfidentialScheme()}
|
||||
*/
|
||||
public boolean isConfidential(Request request)
|
||||
{
|
||||
return _forwarded && request.getScheme().equalsIgnoreCase(HttpScheme.HTTPS.toString());
|
||||
boolean https = isSecure() || _forwarded && _confidentialScheme.equalsIgnoreCase(request.getScheme());
|
||||
int confidentialPort=getConfidentialPort();
|
||||
boolean port = confidentialPort<=0||confidentialPort==request.getServerPort();
|
||||
return https && port;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -478,4 +510,30 @@ public abstract class HttpConnector extends AbstractNetConnector
|
|||
{
|
||||
_forwardedSslSessionIdHeader = forwardedSslSessionId;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (_sslContextFactory!=null)
|
||||
{
|
||||
_sslContextFactory.checkKeyStore();
|
||||
|
||||
super.doStart();
|
||||
|
||||
SSLEngine sslEngine = _sslContextFactory.newSslEngine();
|
||||
|
||||
sslEngine.setUseClientMode(false);
|
||||
|
||||
SSLSession sslSession = sslEngine.getSession();
|
||||
|
||||
if (getRequestHeaderSize()<sslSession.getApplicationBufferSize())
|
||||
setRequestHeaderSize(sslSession.getApplicationBufferSize());
|
||||
if (getRequestBufferSize()<sslSession.getApplicationBufferSize())
|
||||
setRequestBufferSize(sslSession.getApplicationBufferSize());
|
||||
}
|
||||
else
|
||||
super.doStart();
|
||||
}
|
||||
}
|
|
@ -24,9 +24,9 @@ import org.eclipse.jetty.http.HttpGenerator.Action;
|
|||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.AbstractAsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
@ -37,7 +37,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/**
|
||||
* A Connection that handles the HTTP protocol
|
||||
*/
|
||||
public class HttpConnection extends AbstractAsyncConnection
|
||||
public class HttpConnection extends AbstractConnection
|
||||
{
|
||||
public static final Logger LOG = Log.getLogger(HttpConnection.class);
|
||||
|
||||
|
@ -46,7 +46,8 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
public static final String UPGRADE_CONNECTION_ATTR = "org.eclispe.jetty.server.HttpConnection.UPGRADE";
|
||||
|
||||
private final Server _server;
|
||||
private final HttpConnector _connector;
|
||||
private final HttpConfiguration _httpConfig;
|
||||
private final Connector _connector;
|
||||
private final HttpParser _parser;
|
||||
private final HttpGenerator _generator;
|
||||
private final HttpChannel _channel;
|
||||
|
@ -74,17 +75,18 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpConnection(HttpConnector connector, AsyncEndPoint endpoint, Server server)
|
||||
public HttpConnection(HttpConfiguration config, Connector connector, EndPoint endpoint)
|
||||
{
|
||||
super(endpoint,connector.findExecutor());
|
||||
super(endpoint,connector.getExecutor());
|
||||
|
||||
_httpConfig=config;
|
||||
_connector = connector;
|
||||
_bufferPool=_connector.getByteBufferPool();
|
||||
|
||||
_server = server;
|
||||
_server = connector.getServer();
|
||||
|
||||
_httpInput = new HttpHttpInput();
|
||||
_channel = new HttpChannelOverHttp(server);
|
||||
_channel = new HttpChannelOverHttp(connector.getServer());
|
||||
|
||||
_parser = new HttpParser(_channel.getEventHandler());
|
||||
_generator = new HttpGenerator();
|
||||
|
@ -193,7 +195,7 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
/* ------------------------------------------------------------ */
|
||||
/** Parse and handle HTTP messages.
|
||||
* <p>
|
||||
* This method is normally called as the {@link AbstractAsyncConnection} onReadable callback.
|
||||
* This method is normally called as the {@link AbstractConnection} onReadable callback.
|
||||
* However, it can also be called {@link HttpChannelOverHttp#completed()} if there is unconsumed
|
||||
* data in the _requestBuffer, as a result of resuming a suspended request when there is a pipelined
|
||||
* request already read into the buffer.
|
||||
|
@ -210,7 +212,7 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
{
|
||||
setCurrentConnection(this);
|
||||
|
||||
// TODO try to generalize this loop into AbstractAsyncConnection
|
||||
// TODO try to generalize this loop into AbstractConnection
|
||||
while (true)
|
||||
{
|
||||
// synchronized (_lock)
|
||||
|
@ -220,7 +222,7 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
if (BufferUtil.isEmpty(_requestBuffer))
|
||||
{
|
||||
if (_requestBuffer==null)
|
||||
_requestBuffer=_bufferPool.acquire(_connector.getRequestHeaderSize(),false);
|
||||
_requestBuffer=_bufferPool.acquire(_httpConfig.getRequestHeaderSize(),false);
|
||||
|
||||
int filled=getEndPoint().fill(_requestBuffer);
|
||||
|
||||
|
@ -277,10 +279,10 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
}
|
||||
|
||||
// return if the connection has been changed
|
||||
if (getEndPoint().getAsyncConnection()!=this)
|
||||
if (getEndPoint().getConnection()!=this)
|
||||
return;
|
||||
}
|
||||
else if (_headerBytes>= _connector.getRequestHeaderSize())
|
||||
else if (_headerBytes>= _httpConfig.getRequestHeaderSize())
|
||||
{
|
||||
_parser.reset();
|
||||
_parser.close();
|
||||
|
@ -306,14 +308,21 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
{
|
||||
setCurrentConnection(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
fillInterested();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
super.onClose();
|
||||
_channel.onClose();
|
||||
}
|
||||
|
||||
|
@ -346,7 +355,7 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
{
|
||||
if (_responseBuffer!=null && _responseBuffer.capacity()>=size)
|
||||
return;
|
||||
if (_responseBuffer==null && _connector.getResponseBufferSize()>=size)
|
||||
if (_responseBuffer==null && _httpConfig.getResponseBufferSize()>=size)
|
||||
return;
|
||||
|
||||
ByteBuffer r=_bufferPool.acquire(size,false);
|
||||
|
@ -365,14 +374,18 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
if (buffer!=null)
|
||||
return buffer.capacity();
|
||||
|
||||
return _connector.getResponseBufferSize();
|
||||
return _httpConfig.getResponseBufferSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpConnector getHttpConnector()
|
||||
public Connector getConnector()
|
||||
{
|
||||
return _connector;
|
||||
}
|
||||
|
||||
public HttpConfiguration getHttpConfiguration()
|
||||
{
|
||||
return _httpConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void flushResponse() throws IOException
|
||||
|
@ -424,11 +437,11 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
// Handle connection upgrades
|
||||
if (getResponse().getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101)
|
||||
{
|
||||
AsyncConnection connection=(AsyncConnection)getRequest().getAttribute(UPGRADE_CONNECTION_ATTR);
|
||||
Connection connection=(Connection)getRequest().getAttribute(UPGRADE_CONNECTION_ATTR);
|
||||
if (connection!=null)
|
||||
{
|
||||
LOG.debug("Upgrade from {} to {}",this,connection);
|
||||
getEndPoint().setAsyncConnection(connection);
|
||||
getEndPoint().setConnection(connection);
|
||||
HttpConnection.this.reset();
|
||||
return;
|
||||
}
|
||||
|
@ -522,15 +535,15 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
_info=_channel.getEventHandler().commit();
|
||||
LOG.debug("{} Gcommit {}",this,_info);
|
||||
if (_responseHeader==null)
|
||||
_responseHeader=_bufferPool.acquire(_connector.getResponseHeaderSize(),false);
|
||||
_responseHeader=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
continue;
|
||||
|
||||
case NEED_HEADER:
|
||||
_responseHeader=_bufferPool.acquire(_connector.getResponseHeaderSize(),false);
|
||||
_responseHeader=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
continue;
|
||||
|
||||
case NEED_BUFFER:
|
||||
_responseBuffer=_bufferPool.acquire(_connector.getResponseBufferSize(),false);
|
||||
_responseBuffer=_bufferPool.acquire(_httpConfig.getResponseBufferSize(),false);
|
||||
continue;
|
||||
|
||||
case NEED_CHUNK:
|
||||
|
@ -625,15 +638,15 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
case NEED_INFO:
|
||||
_info=_channel.getEventHandler().commit();
|
||||
if (_responseHeader==null)
|
||||
_responseHeader=_bufferPool.acquire(_connector.getResponseHeaderSize(),false);
|
||||
_responseHeader=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
break;
|
||||
|
||||
case NEED_HEADER:
|
||||
_responseHeader=_bufferPool.acquire(_connector.getResponseHeaderSize(),false);
|
||||
_responseHeader=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
break;
|
||||
|
||||
case NEED_BUFFER:
|
||||
_responseBuffer=_bufferPool.acquire(_connector.getResponseBufferSize(),false);
|
||||
_responseBuffer=_bufferPool.acquire(_httpConfig.getResponseBufferSize(),false);
|
||||
break;
|
||||
|
||||
case NEED_CHUNK:
|
||||
|
@ -694,7 +707,7 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
@Override
|
||||
protected void execute(Runnable task)
|
||||
{
|
||||
_connector.findExecutor().execute(task);
|
||||
_connector.getExecutor().execute(task);
|
||||
}
|
||||
|
||||
private FutureCallback<Void> write(ByteBuffer b0,ByteBuffer b1,ByteBuffer b2)
|
||||
|
@ -767,7 +780,7 @@ public class HttpConnection extends AbstractAsyncConnection
|
|||
|
||||
// We will need a buffer to read into
|
||||
if (_requestBuffer==null)
|
||||
_requestBuffer=_bufferPool.acquire(_connector.getRequestBufferSize(),false);
|
||||
_requestBuffer=_bufferPool.acquire(_httpConfig.getRequestBufferSize(),false);
|
||||
|
||||
int filled=getEndPoint().fill(_requestBuffer);
|
||||
LOG.debug("{} block filled {}",this,filled);
|
||||
|
|
|
@ -19,27 +19,54 @@ import java.util.concurrent.BlockingQueue;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.Phaser;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncByteArrayEndPoint;
|
||||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public class LocalHttpConnector extends HttpConnector
|
||||
public class LocalConnector extends AbstractConnector
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(LocalHttpConnector.class);
|
||||
private static final Logger LOG = Log.getLogger(LocalConnector.class);
|
||||
|
||||
private final BlockingQueue<LocalEndPoint> _connects = new LinkedBlockingQueue<>();
|
||||
private volatile LocalExecutor _executor;
|
||||
|
||||
public LocalHttpConnector()
|
||||
|
||||
public LocalConnector(Server server)
|
||||
{
|
||||
setIdleTimeout(30000);
|
||||
this(server,null,null,null,null, -1);
|
||||
}
|
||||
|
||||
public LocalConnector(Server server, boolean ssl)
|
||||
{
|
||||
this(server,new ConnectionFactory(null,ssl),null,null,null,0);
|
||||
manage(getConnectionFactory());
|
||||
}
|
||||
|
||||
public LocalConnector(Server server, HttpConfiguration httpConfig)
|
||||
{
|
||||
this(server,new ConnectionFactory(httpConfig,null,false),null,null,null,0);
|
||||
manage(getConnectionFactory());
|
||||
}
|
||||
|
||||
public LocalConnector(Server server, SslContextFactory sslContextFactory)
|
||||
{
|
||||
this(server,new ConnectionFactory(sslContextFactory,sslContextFactory!=null),null,null,null,0);
|
||||
manage(getConnectionFactory());
|
||||
}
|
||||
|
||||
public LocalConnector(Server server, ConnectionFactory connectionFactory, Executor executor, ScheduledExecutorService scheduler, ByteBufferPool pool,
|
||||
int acceptors)
|
||||
{
|
||||
super(server,connectionFactory,executor,scheduler,pool,acceptors);
|
||||
setIdleTimeout(30000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTransport()
|
||||
{
|
||||
|
@ -49,6 +76,9 @@ public class LocalHttpConnector extends HttpConnector
|
|||
/** Sends requests and get responses based on thread activity.
|
||||
* Returns all the responses received once the thread activity has
|
||||
* returned to the level it was before the requests.
|
||||
* <p>
|
||||
* This methods waits until the connection is closed or
|
||||
* is idle for 1s before returning the responses.
|
||||
* @param requests the requests
|
||||
* @return the responses
|
||||
* @throws Exception if the requests fail
|
||||
|
@ -59,23 +89,59 @@ public class LocalHttpConnector extends HttpConnector
|
|||
return result==null?null:BufferUtil.toString(result,StringUtil.__UTF8_CHARSET);
|
||||
}
|
||||
|
||||
/** Sends requests and get responses based on thread activity.
|
||||
* Returns all the responses received once the thread activity has
|
||||
* returned to the level it was before the requests.
|
||||
* <p>
|
||||
* This methods waits until the connection is closed or
|
||||
* an idle period before returning the responses.
|
||||
* @param requests the requests
|
||||
* @param idleFor The time the response stream must be idle for before returning
|
||||
* @param units The units of idleFor
|
||||
* @return the responses
|
||||
* @throws Exception if the requests fail
|
||||
*/
|
||||
public String getResponses(String requests,long idleFor,TimeUnit units) throws Exception
|
||||
{
|
||||
ByteBuffer result = getResponses(BufferUtil.toBuffer(requests,StringUtil.__UTF8_CHARSET),idleFor,units);
|
||||
return result==null?null:BufferUtil.toString(result,StringUtil.__UTF8_CHARSET);
|
||||
}
|
||||
|
||||
/** Sends requests and get's responses based on thread activity.
|
||||
* Returns all the responses received once the thread activity has
|
||||
* returned to the level it was before the requests.
|
||||
* <p>
|
||||
* This methods waits until the connection is closed or
|
||||
* is idle for 1s before returning the responses.
|
||||
* @param requestsBuffer the requests
|
||||
* @return the responses
|
||||
* @throws Exception if the requests fail
|
||||
*/
|
||||
public ByteBuffer getResponses(ByteBuffer requestsBuffer) throws Exception
|
||||
{
|
||||
return getResponses(requestsBuffer,1000,TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/** Sends requests and get's responses based on thread activity.
|
||||
* Returns all the responses received once the thread activity has
|
||||
* returned to the level it was before the requests.
|
||||
* <p>
|
||||
* This methods waits until the connection is closed or
|
||||
* an idle period before returning the responses.
|
||||
* @param requestsBuffer the requests
|
||||
* @param idleFor The time the response stream must be idle for before returning
|
||||
* @param units The units of idleFor
|
||||
* @return the responses
|
||||
* @throws Exception if the requests fail
|
||||
*/
|
||||
public ByteBuffer getResponses(ByteBuffer requestsBuffer,long idleFor,TimeUnit units) throws Exception
|
||||
{
|
||||
LOG.debug("getResponses");
|
||||
Phaser phaser=_executor._phaser;
|
||||
int phase = phaser.register(); // the corresponding arrival will be done by the acceptor thread when it takes
|
||||
LocalEndPoint request = new LocalEndPoint();
|
||||
request.setInput(requestsBuffer);
|
||||
_connects.add(request);
|
||||
phaser.awaitAdvance(phase);
|
||||
return request.takeOutput();
|
||||
LocalEndPoint endp = new LocalEndPoint();
|
||||
endp.setInput(requestsBuffer);
|
||||
_connects.add(endp);
|
||||
endp.waitUntilClosedOrIdleFor(idleFor,units);
|
||||
return endp.takeOutput();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,8 +152,6 @@ public class LocalHttpConnector extends HttpConnector
|
|||
*/
|
||||
public LocalEndPoint executeRequest(String rawRequest)
|
||||
{
|
||||
Phaser phaser=_executor._phaser;
|
||||
phaser.register(); // the corresponding arrival will be done by the acceptor thread when it takes
|
||||
LocalEndPoint endp = new LocalEndPoint();
|
||||
endp.setInput(BufferUtil.toBuffer(rawRequest,StringUtil.__UTF8_CHARSET));
|
||||
_connects.add(endp);
|
||||
|
@ -99,81 +163,21 @@ public class LocalHttpConnector extends HttpConnector
|
|||
{
|
||||
LOG.debug("accepting {}",acceptorID);
|
||||
LocalEndPoint endp = _connects.take();
|
||||
HttpConnection connection=new HttpConnection(this,endp,getServer());
|
||||
endp.setAsyncConnection(connection);
|
||||
Connection connection=getConnectionFactory().newConnection(LocalConnector.this,endp);
|
||||
endp.setConnection(connection);
|
||||
endp.onOpen();
|
||||
connection.onOpen();
|
||||
connectionOpened(connection);
|
||||
_executor._phaser.arriveAndDeregister(); // arrive for the register done in getResponses
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
_executor=new LocalExecutor(findExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
super.doStop();
|
||||
_executor=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor findExecutor()
|
||||
{
|
||||
return _executor==null?super.findExecutor():_executor;
|
||||
}
|
||||
|
||||
private class LocalExecutor implements Executor
|
||||
{
|
||||
private final Phaser _phaser=new Phaser()
|
||||
{
|
||||
@Override
|
||||
protected boolean onAdvance(int phase, int registeredParties)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
private final Executor _executor;
|
||||
|
||||
private LocalExecutor(Executor e)
|
||||
{
|
||||
_executor=e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final Runnable task)
|
||||
{
|
||||
_phaser.register();
|
||||
LOG.debug("{} execute {} {}",this,task,_phaser);
|
||||
_executor.execute(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
task.run();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_phaser.arriveAndDeregister();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class LocalEndPoint extends AsyncByteArrayEndPoint
|
||||
public class LocalEndPoint extends ByteArrayEndPoint
|
||||
{
|
||||
private CountDownLatch _closed = new CountDownLatch(1);
|
||||
|
||||
public LocalEndPoint()
|
||||
{
|
||||
super(getScheduler(), LocalHttpConnector.this.getIdleTimeout());
|
||||
super(getScheduler(), LocalConnector.this.getIdleTimeout());
|
||||
setGrowOutput(true);
|
||||
}
|
||||
|
||||
|
@ -192,7 +196,8 @@ public class LocalHttpConnector extends HttpConnector
|
|||
super.close();
|
||||
if (was_open)
|
||||
{
|
||||
connectionClosed(getAsyncConnection());
|
||||
connectionClosed(getConnection());
|
||||
getConnection().onClose();
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
@ -231,5 +236,28 @@ public class LocalHttpConnector extends HttpConnector
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void waitUntilClosedOrIdleFor(long idleFor,TimeUnit units)
|
||||
{
|
||||
Thread.yield();
|
||||
int size=getOutput().remaining();
|
||||
while (isOpen())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_closed.await(idleFor,units))
|
||||
{
|
||||
if (size==getOutput().remaining())
|
||||
return;
|
||||
size=getOutput().remaining();
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1358,7 +1358,7 @@ public class Request implements HttpServletRequest
|
|||
@Override
|
||||
public boolean isSecure()
|
||||
{
|
||||
return _channel.getHttpConnector().isConfidential(this);
|
||||
return _channel.getHttpConfiguration().isConfidential(this);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -16,17 +16,22 @@ package org.eclipse.jetty.server;
|
|||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jetty.continuation.Continuation;
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.SelectorManager;
|
||||
import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
|
||||
import org.eclipse.jetty.server.Connector.NetConnector;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
/**
|
||||
* Selecting NIO connector.
|
||||
|
@ -51,27 +56,85 @@ import org.eclipse.jetty.server.Connector.NetConnector;
|
|||
* associated object of the Continuation instance.
|
||||
* </p>
|
||||
*/
|
||||
public class SelectChannelConnector extends HttpConnector implements NetConnector
|
||||
public class SelectChannelConnector extends AbstractNetConnector
|
||||
{
|
||||
private final SelectorManager _manager;
|
||||
protected ServerSocketChannel _acceptChannel;
|
||||
protected boolean _inheritChannel;
|
||||
private int _localPort=-1;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
*/
|
||||
public SelectChannelConnector()
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectChannelConnector(Server server)
|
||||
{
|
||||
this(Math.max(1,(Runtime.getRuntime().availableProcessors())/4),
|
||||
Math.max(1,(Runtime.getRuntime().availableProcessors())/4));
|
||||
this(server,null,null,null,null,0,0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectChannelConnector(Server server, boolean ssl)
|
||||
{
|
||||
this(server,new ConnectionFactory(null,ssl));
|
||||
manage(getConnectionFactory());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectChannelConnector(Server server, SslContextFactory sslContextFactory)
|
||||
{
|
||||
this(server,new ConnectionFactory(sslContextFactory,sslContextFactory!=null));
|
||||
manage(getConnectionFactory());
|
||||
}
|
||||
|
||||
public SelectChannelConnector(int acceptors, int selectors)
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectChannelConnector(Server server, ConnectionFactory connectionFactory)
|
||||
{
|
||||
super(acceptors);
|
||||
_manager=new ConnectorSelectorManager(selectors);
|
||||
this(server,connectionFactory,null,null,null,0,0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param server The server this connector will be added to. Must not be null.
|
||||
* @param executor An executor for this connector or null to use the servers executor
|
||||
* @param scheduler A scheduler for this connector or null to use the servers scheduler
|
||||
* @param pool A buffer pool for this connector or null to use a default {@link ByteBufferPool}
|
||||
* @param acceptors the number of acceptor threads to use, or 0 for a default value.
|
||||
*/
|
||||
public SelectChannelConnector(
|
||||
@Name("server") Server server,
|
||||
@Name("connectionFactory") ConnectionFactory connectionFactory,
|
||||
@Name("executor") Executor executor,
|
||||
@Name("scheduler") ScheduledExecutorService scheduler,
|
||||
@Name("bufferPool") ByteBufferPool pool,
|
||||
@Name("acceptors") int acceptors,
|
||||
@Name("selectors") int selectors)
|
||||
{
|
||||
super(server,connectionFactory,executor,scheduler,pool,acceptors);
|
||||
_manager=new ConnectorSelectorManager(selectors!=0?selectors:Math.max(1,(Runtime.getRuntime().availableProcessors())/4));
|
||||
addBean(_manager,true);
|
||||
|
||||
// TODO yuck
|
||||
if (getConnectionFactory().getSslContextFactory()!=null)
|
||||
setSoLingerTime(30000);
|
||||
}
|
||||
|
||||
|
||||
public boolean isInheritChannel()
|
||||
{
|
||||
return _inheritChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, the connector first tries to inherit from a channel provided by the system.
|
||||
* If there is no inherited channel available, or if the inherited channel provided not usable,
|
||||
* then it will fall back upon normal ServerSocketChannel creation.
|
||||
* <p>
|
||||
* Use it with xinetd/inetd, to launch an instance of Jetty on demand. The port
|
||||
* used to access pages on the Jetty instance is the same as the port used to
|
||||
* launch Jetty.
|
||||
*
|
||||
*/
|
||||
public void setInheritChannel(boolean inheritChannel)
|
||||
{
|
||||
_inheritChannel = inheritChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,13 +172,6 @@ public class SelectChannelConnector extends HttpConnector implements NetConnecto
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(Request request) throws IOException
|
||||
{
|
||||
request.setTimeStamp(System.currentTimeMillis());
|
||||
super.customize(request);
|
||||
}
|
||||
|
||||
public SelectorManager getSelectorManager()
|
||||
{
|
||||
return _manager;
|
||||
|
@ -143,25 +199,39 @@ public class SelectChannelConnector extends HttpConnector implements NetConnecto
|
|||
{
|
||||
if (_acceptChannel == null)
|
||||
{
|
||||
// Create a new server socket
|
||||
_acceptChannel = ServerSocketChannel.open();
|
||||
// Set to blocking mode
|
||||
if (_inheritChannel)
|
||||
{
|
||||
Channel channel = System.inheritedChannel();
|
||||
if ( channel instanceof ServerSocketChannel )
|
||||
_acceptChannel = (ServerSocketChannel)channel;
|
||||
else
|
||||
LOG.warn("Unable to use System.inheritedChannel() [" +channel+ "]. Trying a new ServerSocketChannel at " + getHost() + ":" + getPort());
|
||||
}
|
||||
|
||||
if (_acceptChannel == null)
|
||||
{
|
||||
// Create a new server socket
|
||||
_acceptChannel = ServerSocketChannel.open();
|
||||
|
||||
// Bind the server socket to the local host and port
|
||||
_acceptChannel.socket().setReuseAddress(getReuseAddress());
|
||||
InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort());
|
||||
_acceptChannel.socket().bind(addr,getAcceptQueueSize());
|
||||
|
||||
_localPort=_acceptChannel.socket().getLocalPort();
|
||||
if (_localPort<=0)
|
||||
throw new IOException("Server channel not bound");
|
||||
|
||||
addBean(_acceptChannel);
|
||||
}
|
||||
|
||||
_acceptChannel.configureBlocking(true);
|
||||
|
||||
// Bind the server socket to the local host and port
|
||||
_acceptChannel.socket().setReuseAddress(getReuseAddress());
|
||||
InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort());
|
||||
_acceptChannel.socket().bind(addr,getAcceptQueueSize());
|
||||
|
||||
_localPort=_acceptChannel.socket().getLocalPort();
|
||||
if (_localPort<=0)
|
||||
throw new IOException("Server channel not bound");
|
||||
|
||||
addBean(_acceptChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jetty.server.server.AbstractConnector#doStart()
|
||||
*/
|
||||
|
@ -176,17 +246,11 @@ public class SelectChannelConnector extends HttpConnector implements NetConnecto
|
|||
return new SelectChannelEndPoint(channel,selectSet,key, getScheduler(), getIdleTimeout());
|
||||
}
|
||||
|
||||
protected void endPointClosed(AsyncEndPoint endpoint)
|
||||
protected void endPointClosed(EndPoint endpoint)
|
||||
{
|
||||
connectionClosed(endpoint.getAsyncConnection());
|
||||
connectionClosed(endpoint.getConnection());
|
||||
}
|
||||
|
||||
protected AsyncConnection newConnection(SocketChannel channel,final AsyncEndPoint endpoint)
|
||||
{
|
||||
return new HttpConnection(SelectChannelConnector.this,endpoint,getServer());
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private final class ConnectorSelectorManager extends SelectorManager
|
||||
{
|
||||
|
@ -198,29 +262,29 @@ public class SelectChannelConnector extends HttpConnector implements NetConnecto
|
|||
@Override
|
||||
protected void execute(Runnable task)
|
||||
{
|
||||
findExecutor().execute(task);
|
||||
getExecutor().execute(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endPointClosed(AsyncEndPoint endpoint)
|
||||
protected void endPointClosed(EndPoint endpoint)
|
||||
{
|
||||
SelectChannelConnector.this.connectionClosed(endpoint.getAsyncConnection());
|
||||
SelectChannelConnector.this.connectionClosed(endpoint.getConnection());
|
||||
super.endPointClosed(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endPointOpened(AsyncEndPoint endpoint)
|
||||
protected void endPointOpened(EndPoint endpoint)
|
||||
{
|
||||
// TODO handle max connections and low resources
|
||||
super.endPointOpened(endpoint);
|
||||
SelectChannelConnector.this.connectionOpened(endpoint.getAsyncConnection());
|
||||
SelectChannelConnector.this.connectionOpened(endpoint.getConnection());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionUpgraded(AsyncEndPoint endpoint, AsyncConnection oldConnection)
|
||||
public void connectionUpgraded(EndPoint endpoint, Connection oldConnection)
|
||||
{
|
||||
super.connectionUpgraded(endpoint, oldConnection);
|
||||
SelectChannelConnector.this.connectionUpgraded(oldConnection, endpoint.getAsyncConnection());
|
||||
SelectChannelConnector.this.connectionUpgraded(oldConnection, endpoint.getConnection());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -230,9 +294,9 @@ public class SelectChannelConnector extends HttpConnector implements NetConnecto
|
|||
}
|
||||
|
||||
@Override
|
||||
public AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint, Object attachment)
|
||||
public Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException
|
||||
{
|
||||
return SelectChannelConnector.this.newConnection(channel, endpoint);
|
||||
return getConnectionFactory().newConnection(SelectChannelConnector.this,endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
|
||||
private final Container _container=new Container();
|
||||
private final AttributesMap _attributes = new AttributesMap();
|
||||
private ThreadPool _threadPool;
|
||||
private final ThreadPool _threadPool;
|
||||
private Connector[] _connectors;
|
||||
private SessionIdManager _sessionIdManager;
|
||||
private boolean _sendServerVersion = true; //send Server: header
|
||||
|
@ -81,7 +81,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
/* ------------------------------------------------------------ */
|
||||
public Server()
|
||||
{
|
||||
setServer(this);
|
||||
this((ThreadPool)null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -90,9 +90,8 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
*/
|
||||
public Server(int port)
|
||||
{
|
||||
setServer(this);
|
||||
|
||||
SelectChannelConnector connector=new SelectChannelConnector();
|
||||
this((ThreadPool)null);
|
||||
SelectChannelConnector connector=new SelectChannelConnector(this);
|
||||
connector.setPort(port);
|
||||
setConnectors(new Connector[]{connector});
|
||||
}
|
||||
|
@ -103,15 +102,23 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
*/
|
||||
public Server(InetSocketAddress addr)
|
||||
{
|
||||
setServer(this);
|
||||
|
||||
SelectChannelConnector connector=new SelectChannelConnector();
|
||||
this((ThreadPool)null);
|
||||
SelectChannelConnector connector=new SelectChannelConnector(this);
|
||||
connector.setHost(addr.getHostName());
|
||||
connector.setPort(addr.getPort());
|
||||
setConnectors(new Connector[]{connector});
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Server(ThreadPool pool)
|
||||
{
|
||||
_threadPool=pool!=null?pool:new QueuedThreadPool();
|
||||
addBean(_threadPool,pool==null);
|
||||
setServer(this);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static String getVersion()
|
||||
{
|
||||
|
@ -189,9 +196,8 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
{
|
||||
for (int i=0;i<connectors.length;i++)
|
||||
{
|
||||
// TODO review
|
||||
if (connectors[i] instanceof AbstractConnector)
|
||||
((AbstractConnector)connectors[i]).setServer(this);
|
||||
if (connectors[i].getServer()!=this)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,20 +214,6 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
return _threadPool;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param threadPool The threadPool to set.
|
||||
*/
|
||||
public void setThreadPool(ThreadPool threadPool)
|
||||
{
|
||||
if (_threadPool!=null)
|
||||
removeBean(_threadPool);
|
||||
_container.update(this, _threadPool, threadPool, "threadpool",false);
|
||||
_threadPool = threadPool;
|
||||
if (_threadPool!=null)
|
||||
addBean(_threadPool);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if {@link #dumpStdErr()} is called after starting
|
||||
*/
|
||||
|
@ -267,9 +259,6 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
HttpGenerator.setServerVersion(__version);
|
||||
MultiException mex=new MultiException();
|
||||
|
||||
if (_threadPool==null)
|
||||
setThreadPool(new QueuedThreadPool());
|
||||
|
||||
try
|
||||
{
|
||||
super.doStart();
|
||||
|
|
|
@ -904,7 +904,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
|
|||
// Check the connector
|
||||
if (_connectors != null && _connectors.size() > 0)
|
||||
{
|
||||
String connector = HttpChannel.getCurrentHttpChannel().getHttpConnector().getName();
|
||||
String connector = HttpChannel.getCurrentHttpChannel().getConnector().getName();
|
||||
if (connector == null || !_connectors.contains(connector))
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2008-2009 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.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* An implementation of the SelectChannelConnector which first tries to
|
||||
* inherit from a channel provided by the system. If there is no inherited
|
||||
* channel available, or if the inherited channel provided not usable, then
|
||||
* it will fall back upon normal ServerSocketChannel creation.
|
||||
* <p>
|
||||
* Note that System.inheritedChannel() is only available from Java 1.5 onwards.
|
||||
* Trying to use this class under Java 1.4 will be the same as using a normal
|
||||
* SelectChannelConnector.
|
||||
* <p>
|
||||
* Use it with xinetd/inetd, to launch an instance of Jetty on demand. The port
|
||||
* used to access pages on the Jetty instance is the same as the port used to
|
||||
* launch Jetty.
|
||||
*
|
||||
* @author athena
|
||||
*/
|
||||
public class InheritedChannelConnector extends SelectChannelConnector
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(InheritedChannelConnector.class);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void open() throws IOException
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
try
|
||||
{
|
||||
Channel channel = System.inheritedChannel();
|
||||
if ( channel instanceof ServerSocketChannel )
|
||||
_acceptChannel = (ServerSocketChannel)channel;
|
||||
else
|
||||
LOG.warn("Unable to use System.inheritedChannel() [" +channel+ "]. Trying a new ServerSocketChannel at " + getHost() + ":" + getPort());
|
||||
|
||||
if ( _acceptChannel != null )
|
||||
_acceptChannel.configureBlocking(true);
|
||||
}
|
||||
catch(NoSuchMethodError e)
|
||||
{
|
||||
LOG.warn("Need at least Java 5 to use socket inherited from xinetd/inetd.");
|
||||
}
|
||||
|
||||
if (_acceptChannel == null)
|
||||
super.open();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -19,13 +19,18 @@ import java.nio.channels.SocketChannel;
|
|||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.NetworkTrafficListener;
|
||||
import org.eclipse.jetty.io.NetworkTrafficSelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.SelectorManager;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
/**
|
||||
* <p>A specialized version of {@link SelectChannelConnector} that supports {@link NetworkTrafficListener}s.</p>
|
||||
|
@ -36,6 +41,12 @@ public class NetworkTrafficSelectChannelConnector extends SelectChannelConnector
|
|||
{
|
||||
private final List<NetworkTrafficListener> listeners = new CopyOnWriteArrayList<NetworkTrafficListener>();
|
||||
|
||||
|
||||
public NetworkTrafficSelectChannelConnector(Server server)
|
||||
{
|
||||
super(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
|
@ -61,7 +72,7 @@ public class NetworkTrafficSelectChannelConnector extends SelectChannelConnector
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void endPointClosed(AsyncEndPoint endpoint)
|
||||
protected void endPointClosed(EndPoint endpoint)
|
||||
{
|
||||
super.endPointClosed(endpoint);
|
||||
((NetworkTrafficSelectChannelEndPoint)endpoint).notifyClosed();
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
package org.eclipse.jetty.server.nio;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link org.eclipse.jetty.server.SelectChannelConnector}
|
||||
*/
|
||||
public class SelectChannelConnector extends org.eclipse.jetty.server.SelectChannelConnector
|
||||
{
|
||||
}
|
|
@ -21,7 +21,6 @@ import javax.net.ssl.SSLContext;
|
|||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
|
||||
|
@ -29,7 +28,8 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
|
|||
/** The interface for SSL connectors and their configuration methods.
|
||||
*
|
||||
*/
|
||||
public interface SslConnector extends Connector.NetConnector
|
||||
@Deprecated
|
||||
interface SslConnector
|
||||
{
|
||||
@Deprecated
|
||||
public static final String DEFAULT_KEYSTORE_ALGORITHM=(Security.getProperty("ssl.KeyManagerFactory.algorithm")==null?"SunX509":Security.getProperty("ssl.KeyManagerFactory.algorithm"));
|
||||
|
|
|
@ -13,607 +13,21 @@
|
|||
|
||||
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 org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* SslSelectChannelConnector.
|
||||
*
|
||||
* @deprecated use SelectChannelConnector with {@link SslContextFactory}
|
||||
* @org.apache.xbean.XBean element="sslConnector" description="Creates an NIO ssl connector"
|
||||
*/
|
||||
public class SslSelectChannelConnector extends SelectChannelConnector implements SslConnector
|
||||
public class SslSelectChannelConnector extends SelectChannelConnector
|
||||
{
|
||||
private final SslContextFactory _sslContextFactory;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SslSelectChannelConnector()
|
||||
public SslSelectChannelConnector(Server server)
|
||||
{
|
||||
this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH));
|
||||
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)
|
||||
{
|
||||
_sslContextFactory = sslContextFactory;
|
||||
addBean(_sslContextFactory);
|
||||
setSoLingerTime(30000);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* 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 request
|
||||
* HttpRequest to be customised.
|
||||
*/
|
||||
@Override
|
||||
public void customize(Request request) throws IOException
|
||||
{
|
||||
request.setScheme(HttpScheme.HTTPS.asString());
|
||||
super.customize(request);
|
||||
|
||||
SslConnection.DecryptedEndPoint ssl_endp = (SslConnection.DecryptedEndPoint)request.getHttpChannel().getEndPoint();
|
||||
SslConnection sslConnection = ssl_endp.getSslConnection();
|
||||
SSLEngine sslEngine=sslConnection.getSSLEngine();
|
||||
SslCertificates.customize(sslEngine,request);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if SSL re-negotiation is allowed (default false)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isAllowRenegotiate()
|
||||
{
|
||||
return _sslContextFactory.isAllowRenegotiate();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
|
||||
* a vulnerability in SSL/TLS with re-negotiation. If your JVM
|
||||
* does not have CVE-2009-3555 fixed, then re-negotiation should
|
||||
* not be allowed. CVE-2009-3555 was fixed in Sun java 1.6 with a ban
|
||||
* of renegotiate in u19 and with RFC5746 in u22.
|
||||
* @param allowRenegotiate true if re-negotiation is allowed (default false)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setAllowRenegotiate(boolean allowRenegotiate)
|
||||
{
|
||||
_sslContextFactory.setAllowRenegotiate(allowRenegotiate);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String[] getExcludeCipherSuites()
|
||||
{
|
||||
return _sslContextFactory.getExcludeCipherSuites();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setExcludeCipherSuites(String[] cipherSuites)
|
||||
{
|
||||
_sslContextFactory.setExcludeCipherSuites(cipherSuites);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String[] getIncludeCipherSuites()
|
||||
{
|
||||
return _sslContextFactory.getIncludeCipherSuites();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setIncludeCipherSuites(String[] cipherSuites)
|
||||
{
|
||||
_sslContextFactory.setIncludeCipherSuites(cipherSuites);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setPassword(String password)
|
||||
{
|
||||
_sslContextFactory.setKeyStorePassword(password);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTrustPassword(String password)
|
||||
{
|
||||
_sslContextFactory.setTrustStorePassword(password);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setKeyPassword(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setKeyPassword(String password)
|
||||
{
|
||||
_sslContextFactory.setKeyManagerPassword(password);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Unsupported.
|
||||
*
|
||||
* TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getAlgorithm()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Unsupported.
|
||||
*
|
||||
* TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setAlgorithm(String algorithm)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getProtocol()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getProtocol()
|
||||
{
|
||||
return _sslContextFactory.getProtocol();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setProtocol(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProtocol(String protocol)
|
||||
{
|
||||
_sslContextFactory.setProtocol(protocol);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setKeystore(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setKeystore(String keystore)
|
||||
{
|
||||
_sslContextFactory.setKeyStorePath(keystore);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getKeystore()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getKeystore()
|
||||
{
|
||||
return _sslContextFactory.getKeyStorePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getKeystoreType()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getKeystoreType()
|
||||
{
|
||||
return _sslContextFactory.getKeyStoreType();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getNeedClientAuth()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean getNeedClientAuth()
|
||||
{
|
||||
return _sslContextFactory.getNeedClientAuth();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getWantClientAuth()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean getWantClientAuth()
|
||||
{
|
||||
return _sslContextFactory.getWantClientAuth();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setNeedClientAuth(boolean)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setNeedClientAuth(boolean needClientAuth)
|
||||
{
|
||||
_sslContextFactory.setNeedClientAuth(needClientAuth);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setWantClientAuth(boolean)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setWantClientAuth(boolean wantClientAuth)
|
||||
{
|
||||
_sslContextFactory.setWantClientAuth(wantClientAuth);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setKeystoreType(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setKeystoreType(String keystoreType)
|
||||
{
|
||||
_sslContextFactory.setKeyStoreType(keystoreType);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getProvider()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getProvider()
|
||||
{
|
||||
return _sslContextFactory.getProvider();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getSecureRandomAlgorithm()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getSecureRandomAlgorithm()
|
||||
{
|
||||
return _sslContextFactory.getSecureRandomAlgorithm();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getSslKeyManagerFactoryAlgorithm()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getSslKeyManagerFactoryAlgorithm()
|
||||
{
|
||||
return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getSslTrustManagerFactoryAlgorithm()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getSslTrustManagerFactoryAlgorithm()
|
||||
{
|
||||
return _sslContextFactory.getTrustManagerFactoryAlgorithm();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getTruststore()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getTruststore()
|
||||
{
|
||||
return _sslContextFactory.getTrustStore();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#getTruststoreType()
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public String getTruststoreType()
|
||||
{
|
||||
return _sslContextFactory.getTrustStoreType();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setProvider(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProvider(String provider)
|
||||
{
|
||||
_sslContextFactory.setProvider(provider);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setSecureRandomAlgorithm(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSecureRandomAlgorithm(String algorithm)
|
||||
{
|
||||
_sslContextFactory.setSecureRandomAlgorithm(algorithm);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setSslKeyManagerFactoryAlgorithm(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSslKeyManagerFactoryAlgorithm(String algorithm)
|
||||
{
|
||||
_sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSslTrustManagerFactoryAlgorithm(String algorithm)
|
||||
{
|
||||
_sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setTruststore(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTruststore(String truststore)
|
||||
{
|
||||
_sslContextFactory.setTrustStore(truststore);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTruststoreType(String truststoreType)
|
||||
{
|
||||
_sslContextFactory.setTrustStoreType(truststoreType);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSslContext(SSLContext sslContext)
|
||||
{
|
||||
_sslContextFactory.setSslContext(sslContext);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public SSLContext getSslContext()
|
||||
{
|
||||
return _sslContextFactory.getSslContext();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @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(Request request)
|
||||
{
|
||||
final int confidentialPort=getConfidentialPort();
|
||||
return confidentialPort==0||confidentialPort==request.getServerPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* By default, we're integral, given we speak SSL. But, if we've been told
|
||||
* about an integral 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 isIntegral(Request request)
|
||||
{
|
||||
final int integralPort=getIntegralPort();
|
||||
return integralPort==0||integralPort==request.getServerPort();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
@Override
|
||||
protected AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint)
|
||||
{
|
||||
try
|
||||
{
|
||||
SSLEngine engine = createSSLEngine(channel);
|
||||
SslConnection connection = newSslConnection(endpoint, engine);
|
||||
AsyncConnection delegate = newPlainConnection(channel, connection.getSslEndPoint());
|
||||
connection.getSslEndPoint().setAsyncConnection(delegate);
|
||||
getSelectorManager().connectionOpened(delegate);
|
||||
return connection;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected AsyncConnection newPlainConnection(SocketChannel channel, AsyncEndPoint endPoint)
|
||||
{
|
||||
return super.newConnection(channel, endPoint);
|
||||
}
|
||||
|
||||
protected SslConnection newSslConnection(AsyncEndPoint endpoint, SSLEngine engine)
|
||||
{
|
||||
return new SslConnection(getByteBufferPool(), findExecutor(), endpoint, engine);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException
|
||||
{
|
||||
SSLEngine engine;
|
||||
if (channel != null)
|
||||
{
|
||||
String peerHost = channel.socket().getInetAddress().getHostAddress();
|
||||
int peerPort = channel.socket().getPort();
|
||||
engine = _sslContextFactory.newSslEngine(peerHost, peerPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine = _sslContextFactory.newSslEngine();
|
||||
}
|
||||
|
||||
engine.setUseClientMode(false);
|
||||
return engine;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.SelectChannelConnector#doStart()
|
||||
*/
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
_sslContextFactory.checkKeyStore();
|
||||
_sslContextFactory.start();
|
||||
|
||||
SSLEngine sslEngine = _sslContextFactory.newSslEngine();
|
||||
|
||||
sslEngine.setUseClientMode(false);
|
||||
|
||||
SSLSession sslSession = sslEngine.getSession();
|
||||
|
||||
if (getRequestHeaderSize()<sslSession.getApplicationBufferSize())
|
||||
setRequestHeaderSize(sslSession.getApplicationBufferSize());
|
||||
if (getRequestBufferSize()<sslSession.getApplicationBufferSize())
|
||||
setRequestBufferSize(sslSession.getApplicationBufferSize());
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.SelectChannelConnector#doStop()
|
||||
*/
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
super.doStop();
|
||||
super(server,true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ public class AsyncRequestReadTest
|
|||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new SelectChannelConnector();
|
||||
connector = new SelectChannelConnector(server);
|
||||
connector.setIdleTimeout(10000);
|
||||
server.addConnector(connector);
|
||||
server.setHandler(new EmptyHandler());
|
||||
|
|
|
@ -46,13 +46,13 @@ public class AsyncStressTest
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(AsyncStressTest.class);
|
||||
|
||||
protected Server _server = new Server();
|
||||
protected QueuedThreadPool _threads=new QueuedThreadPool();
|
||||
protected Server _server = new Server(_threads);
|
||||
protected SuspendHandler _handler = new SuspendHandler();
|
||||
protected SelectChannelConnector _connector;
|
||||
protected InetAddress _addr;
|
||||
protected int _port;
|
||||
protected Random _random = new Random();
|
||||
protected QueuedThreadPool _threads=new QueuedThreadPool();
|
||||
private final static String[][] __paths =
|
||||
{
|
||||
{"/path","NORMAL"},
|
||||
|
@ -66,9 +66,9 @@ public class AsyncStressTest
|
|||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
_server.manage(_threads);
|
||||
_threads.setMaxThreads(50);
|
||||
_server.setThreadPool(_threads);
|
||||
_connector = new SelectChannelConnector();
|
||||
_connector = new SelectChannelConnector(_server);
|
||||
_connector.setIdleTimeout(120000);
|
||||
_server.setConnectors(new Connector[]{ _connector });
|
||||
_server.setHandler(_handler);
|
||||
|
|
|
@ -9,7 +9,7 @@ public class ChannelHttpServer
|
|||
System.setProperty("org.eclipse.jetty.LEVEL","DEBUG");
|
||||
Log.getRootLogger().setDebugEnabled(true);
|
||||
Server server = new Server();
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(server);
|
||||
connector.setPort(8080);
|
||||
server.addConnector(connector);
|
||||
server.setHandler(new DumpHandler());
|
||||
|
|
|
@ -93,10 +93,10 @@ public class CheckReverseProxyHeadersTest
|
|||
private void testRequest(String headers, RequestValidator requestValidator) throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
LocalHttpConnector connector = new LocalHttpConnector();
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
|
||||
// Activate reverse proxy headers checking
|
||||
connector.setForwarded(true);
|
||||
connector.getConnectionFactory().getHttpConfig().setForwarded(true);
|
||||
|
||||
server.setConnectors(new Connector[] {connector});
|
||||
ValidationHandler validationHandler = new ValidationHandler(requestValidator);
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
//========================================================================
|
||||
//Copyright (c) Webtide LLC
|
||||
//Copyright 2011-2012 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.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
|||
// Get the server side endpoint
|
||||
EndPoint endp = endpoint.exchange(null,10,TimeUnit.SECONDS);
|
||||
if (endp instanceof SslConnection.DecryptedEndPoint)
|
||||
endp=((SslConnection.DecryptedEndPoint)endp).getAsyncConnection().getEndPoint();
|
||||
endp=((SslConnection.DecryptedEndPoint)endp).getConnection().getEndPoint();
|
||||
|
||||
// read the response
|
||||
String result=IO.toString(is);
|
||||
|
@ -223,7 +223,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
|||
// Get the server side endpoint
|
||||
EndPoint endp = endpoint.exchange(null,10,TimeUnit.SECONDS);
|
||||
if (endp instanceof SslConnection.DecryptedEndPoint)
|
||||
endp=((SslConnection.DecryptedEndPoint)endp).getAsyncConnection().getEndPoint();
|
||||
endp=((SslConnection.DecryptedEndPoint)endp).getConnection().getEndPoint();
|
||||
|
||||
// read the response
|
||||
String result=IO.toString(is);
|
||||
|
|
|
@ -27,6 +27,7 @@ import static org.junit.Assert.fail;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -52,16 +53,16 @@ public class HttpConnectionTest
|
|||
private static final Logger LOG = Log.getLogger(HttpConnectionTest.class);
|
||||
|
||||
private Server server;
|
||||
private LocalHttpConnector connector;
|
||||
private LocalConnector connector;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new LocalHttpConnector();
|
||||
connector = new LocalConnector(server);
|
||||
server.addConnector(connector);
|
||||
connector.setRequestHeaderSize(1024);
|
||||
connector.setResponseHeaderSize(1024);
|
||||
connector.getConnectionFactory().getHttpConfig().setRequestHeaderSize(1024);
|
||||
connector.getConnectionFactory().getHttpConfig().setResponseHeaderSize(1024);
|
||||
server.setHandler(new DumpHandler());
|
||||
server.start();
|
||||
}
|
||||
|
@ -87,6 +88,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"12345\015\012"+
|
||||
|
@ -100,6 +102,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"ABCDE\015\012"+
|
||||
|
@ -124,6 +127,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"0\015\012\015\012");
|
||||
|
||||
|
@ -137,10 +141,12 @@ public class HttpConnectionTest
|
|||
{
|
||||
String responsePOST=connector.getResponses("POST /R1 HTTP/1.1\015\012"+
|
||||
"Host: localhost\015\012"+
|
||||
"Connection: close\015\012"+
|
||||
"\015\012");
|
||||
|
||||
String responseHEAD=connector.getResponses("HEAD /R1 HTTP/1.1\015\012"+
|
||||
"Host: localhost\015\012"+
|
||||
"Connection: close\015\012"+
|
||||
"\015\012");
|
||||
|
||||
assertThat(responsePOST,startsWith(responseHEAD.substring(0,responseHEAD.length()-2)));
|
||||
|
@ -148,6 +154,7 @@ public class HttpConnectionTest
|
|||
|
||||
responsePOST=connector.getResponses("POST /R1 HTTP/1.1\015\012"+
|
||||
"Host: localhost\015\012"+
|
||||
"Connection: close\015\012"+
|
||||
"\015\012");
|
||||
|
||||
assertThat(responsePOST,startsWith(responseHEAD.substring(0,responseHEAD.length()-2)));
|
||||
|
@ -162,16 +169,19 @@ public class HttpConnectionTest
|
|||
|
||||
response=connector.getResponses("GET http://localhost:EXPECTED_NUMBER_FORMAT_EXCEPTION/ HTTP/1.1\n"+
|
||||
"Host: localhost\n"+
|
||||
"Connection: close\015\012"+
|
||||
"\015\012");
|
||||
checkContains(response,0,"HTTP/1.1 400");
|
||||
|
||||
response=connector.getResponses("GET /bad/encoding%1 HTTP/1.1\n"+
|
||||
"Host: localhost\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012");
|
||||
checkContains(response,0,"HTTP/1.1 400");
|
||||
|
||||
response=connector.getResponses("GET % HTTP/1.1\n"+
|
||||
"Host: localhost\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012");
|
||||
checkContains(response,0,"HTTP/1.1 400");
|
||||
}
|
||||
|
@ -180,21 +190,22 @@ public class HttpConnectionTest
|
|||
public void testAutoFlush() throws Exception
|
||||
{
|
||||
String response=null;
|
||||
int offset=0;
|
||||
int offset=0;
|
||||
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+
|
||||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"12345\015\012"+
|
||||
"0;\015\012\015\012");
|
||||
offset = checkContains(response,offset,"HTTP/1.1 200");
|
||||
checkNotContained(response,offset,"IgnoreMe");
|
||||
offset = checkContains(response,offset,"/R1");
|
||||
offset = checkContains(response,offset,"12345");
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+
|
||||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"12345\015\012"+
|
||||
"0;\015\012\015\012");
|
||||
offset = checkContains(response,offset,"HTTP/1.1 200");
|
||||
checkNotContained(response,offset,"IgnoreMe");
|
||||
offset = checkContains(response,offset,"/R1");
|
||||
offset = checkContains(response,offset,"12345");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -211,6 +222,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain; charset=utf-8\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"12345\015\012"+
|
||||
|
@ -225,6 +237,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain; charset = iso-8859-1 ; other=value\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"12345\015\012"+
|
||||
|
@ -239,6 +252,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain; charset=unknown\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"12345\015\012"+
|
||||
|
@ -281,6 +295,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Content-Type: text/plain; charset=utf-8\n"+
|
||||
"Content-Length: 10\n"+
|
||||
"Connection: close\n"+
|
||||
"\n"+
|
||||
"abcdefghij\n";
|
||||
|
||||
|
@ -527,6 +542,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain; charset=utf-8\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"12345\015\012"+
|
||||
|
@ -543,6 +559,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain; charset=utf-8\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"12345\015\012"+
|
||||
|
@ -554,6 +571,7 @@ public class HttpConnectionTest
|
|||
"Host: localhost\n"+
|
||||
"Transfer-Encoding: chunked\n"+
|
||||
"Content-Type: text/plain; charset=utf-8\n"+
|
||||
"Connection: close\n"+
|
||||
"\015\012"+
|
||||
"5;\015\012"+
|
||||
"12345\015\012"+
|
||||
|
@ -585,7 +603,7 @@ public class HttpConnectionTest
|
|||
|
||||
response=connector.getResponses("CONNECT www.webtide.com:8080 HTTP/1.1\n"+
|
||||
"Host: myproxy:8888\015\012"+
|
||||
"\015\012");
|
||||
"\015\012",200,TimeUnit.MILLISECONDS);
|
||||
checkContains(response,offset,"HTTP/1.1 200");
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
import org.eclipse.jetty.toolchain.test.Stress;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
|
||||
public class HttpServerTestFixture
|
||||
|
@ -52,9 +53,14 @@ public class HttpServerTestFixture
|
|||
return socket;
|
||||
}
|
||||
|
||||
protected static void startServer(Connector.NetConnector connector) throws Exception
|
||||
@BeforeClass
|
||||
public static void before()
|
||||
{
|
||||
_server = new Server();
|
||||
}
|
||||
|
||||
protected static void startServer(Connector.NetConnector connector) throws Exception
|
||||
{
|
||||
_connector = connector;
|
||||
_server.addConnector(_connector);
|
||||
_server.setHandler(new HandlerWrapper());
|
||||
|
|
|
@ -12,6 +12,8 @@ package org.eclipse.jetty.server;
|
|||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
@ -24,8 +26,6 @@ import org.eclipse.jetty.util.Utf8StringBuilder;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class HttpWriterTest
|
||||
{
|
||||
private HttpWriter _writer;
|
||||
|
@ -39,7 +39,7 @@ public class HttpWriterTest
|
|||
HttpChannel channel = new HttpChannel(null,null,null)
|
||||
{
|
||||
@Override
|
||||
public HttpConnector getHttpConnector()
|
||||
public HttpConfiguration getHttpConfiguration()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -98,6 +98,12 @@ public class HttpWriterTest
|
|||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connector getConnector()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ public class LocalAsyncContextTest
|
|||
|
||||
protected Connector initConnector()
|
||||
{
|
||||
return new LocalHttpConnector();
|
||||
return new LocalConnector(_server);
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -247,8 +247,8 @@ public class LocalAsyncContextTest
|
|||
|
||||
protected String getResponse(String request) throws Exception
|
||||
{
|
||||
LocalHttpConnector connector=(LocalHttpConnector)_connector;
|
||||
LocalHttpConnector.LocalEndPoint endp = connector.executeRequest(request);
|
||||
LocalConnector connector=(LocalConnector)_connector;
|
||||
LocalConnector.LocalEndPoint endp = connector.executeRequest(request);
|
||||
endp.waitUntilClosed();
|
||||
return endp.takeOutputString();
|
||||
}
|
||||
|
|
|
@ -10,13 +10,13 @@ import org.junit.Test;
|
|||
public class LocalHttpConnectorTest
|
||||
{
|
||||
private Server _server;
|
||||
private LocalHttpConnector _connector;
|
||||
private LocalConnector _connector;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalHttpConnector();
|
||||
_connector = new LocalConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
_server.setHandler(new DumpHandler());
|
||||
_server.start();
|
||||
|
|
|
@ -54,7 +54,7 @@ public class NetworkTrafficListenerTest
|
|||
server.setSendDateHeader(false);
|
||||
server.setSendServerVersion(false);
|
||||
|
||||
connector = new NetworkTrafficSelectChannelConnector();
|
||||
connector = new NetworkTrafficSelectChannelConnector(server);
|
||||
server.addConnector(connector);
|
||||
server.setHandler(handler);
|
||||
server.start();
|
||||
|
|
|
@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue;
|
|||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
|
@ -42,13 +43,13 @@ import org.junit.Test;
|
|||
public class RFC2616Test
|
||||
{
|
||||
private Server server;
|
||||
private LocalHttpConnector connector;
|
||||
private LocalConnector connector;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new LocalHttpConnector();
|
||||
connector = new LocalConnector(server);
|
||||
connector.setIdleTimeout(10000);
|
||||
server.addConnector(connector);
|
||||
|
||||
|
@ -360,7 +361,7 @@ public class RFC2616Test
|
|||
|
||||
// Default Host
|
||||
offset=0;
|
||||
response=connector.getResponses("GET http://VirtualHost:8888/path/R1 HTTP/1.1\n"+"Host: wronghost\n"+"\n");
|
||||
response=connector.getResponses("GET http://VirtualHost:8888/path/R1 HTTP/1.1\n"+"Host: wronghost\n"+"Connection: close\n"+"\n");
|
||||
offset=checkContains(response,offset,"HTTP/1.1 200","Default host")+1;
|
||||
offset=checkContains(response,offset,"Virtual Dump","virtual host")+1;
|
||||
offset=checkContains(response,offset,"pathInfo=/path/R1","Default host")+1;
|
||||
|
@ -374,14 +375,14 @@ public class RFC2616Test
|
|||
|
||||
// Default Host
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /path/R1 HTTP/1.1\n"+"Host: localhost\n"+"\n");
|
||||
response=connector.getResponses("GET /path/R1 HTTP/1.1\n"+"Host: localhost\n"+"Connection: close\n"+"\n");
|
||||
offset=checkContains(response,offset,"HTTP/1.1 200","Default host")+1;
|
||||
offset=checkContains(response,offset,"Dump HttpHandler","Default host")+1;
|
||||
offset=checkContains(response,offset,"pathInfo=/path/R1","Default host")+1;
|
||||
|
||||
// Virtual Host
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /path/R2 HTTP/1.1\n"+"Host: VirtualHost\n"+"\n");
|
||||
response=connector.getResponses("GET /path/R2 HTTP/1.1\n"+"Host: VirtualHost\n"+"Connection: close\n"+"\n");
|
||||
offset=checkContains(response,offset,"HTTP/1.1 200","Default host")+1;
|
||||
offset=checkContains(response,offset,"Virtual Dump","virtual host")+1;
|
||||
offset=checkContains(response,offset,"pathInfo=/path/R2","Default host")+1;
|
||||
|
@ -395,14 +396,14 @@ public class RFC2616Test
|
|||
|
||||
// Virtual Host
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /path/R1 HTTP/1.1\n"+"Host: VirtualHost\n"+"\n");
|
||||
response=connector.getResponses("GET /path/R1 HTTP/1.1\n"+"Host: VirtualHost\n"+"Connection: close\n"+"\n");
|
||||
offset=checkContains(response,offset,"HTTP/1.1 200","2. virtual host field")+1;
|
||||
offset=checkContains(response,offset,"Virtual Dump","2. virtual host field")+1;
|
||||
offset=checkContains(response,offset,"pathInfo=/path/R1","2. virtual host field")+1;
|
||||
|
||||
// Virtual Host case insensitive
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /path/R1 HTTP/1.1\n"+"Host: ViRtUalhOst\n"+"\n");
|
||||
response=connector.getResponses("GET /path/R1 HTTP/1.1\n"+"Host: ViRtUalhOst\n"+"Connection: close\n"+"\n");
|
||||
offset=checkContains(response,offset,"HTTP/1.1 200","2. virtual host field")+1;
|
||||
offset=checkContains(response,offset,"Virtual Dump","2. virtual host field")+1;
|
||||
offset=checkContains(response,offset,"pathInfo=/path/R1","2. virtual host field")+1;
|
||||
|
@ -422,7 +423,7 @@ public class RFC2616Test
|
|||
int offset=0;
|
||||
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+"Host: localhost\n"+"\n");
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+"Host: localhost\n"+"\n",250,TimeUnit.MILLISECONDS);
|
||||
offset=checkContains(response,offset,"HTTP/1.1 200 OK\015\012","8.1.2 default")+10;
|
||||
checkContains(response,offset,"Content-Length: ","8.1.2 default");
|
||||
|
||||
|
@ -490,7 +491,7 @@ public class RFC2616Test
|
|||
{
|
||||
int offset=0;
|
||||
// Expect 100
|
||||
LocalHttpConnector.LocalEndPoint endp =connector.executeRequest("GET /R1 HTTP/1.1\n"+
|
||||
LocalConnector.LocalEndPoint endp =connector.executeRequest("GET /R1 HTTP/1.1\n"+
|
||||
"Host: localhost\n"+
|
||||
"Connection: close\n"+
|
||||
"Expect: 100-continue\n"+
|
||||
|
@ -754,19 +755,19 @@ public class RFC2616Test
|
|||
|
||||
// HTTP/1.0 OK with no host
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /R1 HTTP/1.0\n"+"\n");
|
||||
response=connector.getResponses("GET /R1 HTTP/1.0\n"+"Connection: close\n"+"\n");
|
||||
offset=checkContains(response,offset,"HTTP/1.1 200","200")+1;
|
||||
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+"\n");
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+"Connection: close\n"+"\n");
|
||||
offset=checkContains(response,offset,"HTTP/1.1 400","400")+1;
|
||||
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+"Host: localhost\n"+"\n");
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+"Host: localhost\n"+"Connection: close\n"+"\n");
|
||||
offset=checkContains(response,offset,"HTTP/1.1 200","200")+1;
|
||||
|
||||
offset=0;
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+"Host:\n"+"\n");
|
||||
response=connector.getResponses("GET /R1 HTTP/1.1\n"+"Host:\n"+"Connection: close\n"+"\n");
|
||||
offset=checkContains(response,offset,"HTTP/1.1 200","200")+1;
|
||||
|
||||
}
|
||||
|
@ -898,7 +899,7 @@ public class RFC2616Test
|
|||
}
|
||||
}
|
||||
|
||||
private void checkContentRange(LocalHttpConnector listener, String tname, String path, String reqRanges, int expectedStatus, String expectedRange, String expectedData)
|
||||
private void checkContentRange(LocalConnector listener, String tname, String path, String reqRanges, int expectedStatus, String expectedRange, String expectedData)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -13,7 +13,13 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
|
@ -25,6 +31,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
|
@ -49,19 +56,19 @@ public class RequestTest
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(RequestTest.class);
|
||||
private Server _server;
|
||||
private LocalHttpConnector _connector;
|
||||
private LocalConnector _connector;
|
||||
private RequestHandler _handler;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalHttpConnector();
|
||||
_connector.setRequestHeaderSize(512);
|
||||
_connector.setRequestBufferSize(1024);
|
||||
_connector.setResponseHeaderSize(512);
|
||||
_connector.setResponseBufferSize(2048);
|
||||
_connector.setForwarded(true);
|
||||
_connector = new LocalConnector(_server);
|
||||
_connector.getConnectionFactory().getHttpConfig().setRequestHeaderSize(512);
|
||||
_connector.getConnectionFactory().getHttpConfig().setRequestBufferSize(1024);
|
||||
_connector.getConnectionFactory().getHttpConfig().setResponseHeaderSize(512);
|
||||
_connector.getConnectionFactory().getHttpConfig().setResponseBufferSize(2048);
|
||||
_connector.getConnectionFactory().getHttpConfig().setForwarded(true);
|
||||
_server.addConnector(_connector);
|
||||
_handler = new RequestHandler();
|
||||
_server.setHandler(_handler);
|
||||
|
@ -80,6 +87,7 @@ public class RequestTest
|
|||
{
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
Map map = null;
|
||||
|
@ -110,6 +118,7 @@ public class RequestTest
|
|||
String request="GET /?param=%ZZaaa HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Content-Type: text/html;charset=utf8\n"+
|
||||
"Connection: close\n"+
|
||||
"\n";
|
||||
|
||||
String responses=_connector.getResponses(request);
|
||||
|
@ -122,6 +131,7 @@ public class RequestTest
|
|||
{
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
try
|
||||
|
@ -155,6 +165,7 @@ public class RequestTest
|
|||
"Host: whatever\r\n"+
|
||||
"Content-Type: multipart/form-data; boundary=\"AaB03x\"\r\n"+
|
||||
"Content-Length: "+multipart.getBytes().length+"\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n"+
|
||||
multipart;
|
||||
|
||||
|
@ -167,6 +178,7 @@ public class RequestTest
|
|||
{
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
String value=request.getParameter("param");
|
||||
|
@ -179,6 +191,7 @@ public class RequestTest
|
|||
String request="GET /?param=aaa%E7bbb HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Content-Type: text/html;charset=utf8\n"+
|
||||
"Connection: close\n"+
|
||||
"\n";
|
||||
|
||||
String responses=_connector.getResponses(request);
|
||||
|
@ -199,6 +212,7 @@ public class RequestTest
|
|||
String request="GET / HTTP/1.1\r\n"+
|
||||
"Host: whatever.com:\r\n"+
|
||||
"Content-Type: text/html;charset=utf8\n"+
|
||||
"Connection: close\n"+
|
||||
"\n";
|
||||
|
||||
String responses=_connector.getResponses(request);
|
||||
|
@ -213,6 +227,7 @@ public class RequestTest
|
|||
final ArrayList<String> results = new ArrayList<String>();
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
results.add(request.getContentType());
|
||||
|
@ -240,6 +255,7 @@ public class RequestTest
|
|||
"GET / HTTP/1.1\n"+
|
||||
"Host: whatever\n"+
|
||||
"Content-Type: text/html; other=foo ; blah=\"charset=wrong;\" ; charset = \" x=z; \" ; more=values \n"+
|
||||
"Connection: close\n"+
|
||||
"\n"
|
||||
);
|
||||
|
||||
|
@ -263,6 +279,7 @@ public class RequestTest
|
|||
final ArrayList<String> results = new ArrayList<String>();
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
results.add(request.getRemoteAddr());
|
||||
|
@ -305,10 +322,11 @@ public class RequestTest
|
|||
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: [::1]:8888\n"+
|
||||
"Connection: close\n"+
|
||||
"x-forwarded-for: remote\n"+
|
||||
"x-forwarded-proto: https\n"+
|
||||
"\n"
|
||||
);
|
||||
"\n",10,TimeUnit.SECONDS);
|
||||
|
||||
|
||||
int i=0;
|
||||
assertEquals("0.0.0.0",results.get(i++));
|
||||
|
@ -345,6 +363,7 @@ public class RequestTest
|
|||
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
//assertEquals(request.getContentLength(), ((Request)request).getContentRead());
|
||||
|
@ -377,6 +396,7 @@ public class RequestTest
|
|||
{
|
||||
Handler handler = new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException,
|
||||
ServletException
|
||||
{
|
||||
|
@ -422,6 +442,7 @@ public class RequestTest
|
|||
{
|
||||
Handler handler = new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException,
|
||||
ServletException
|
||||
{
|
||||
|
@ -506,6 +527,7 @@ public class RequestTest
|
|||
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException
|
||||
{
|
||||
response.getOutputStream().println("Hello World");
|
||||
|
@ -573,6 +595,7 @@ public class RequestTest
|
|||
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException
|
||||
{
|
||||
response.setHeader("Connection","TE");
|
||||
|
@ -609,6 +632,7 @@ public class RequestTest
|
|||
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException
|
||||
{
|
||||
javax.servlet.http.Cookie[] ca = request.getCookies();
|
||||
|
@ -625,6 +649,7 @@ public class RequestTest
|
|||
response=_connector.getResponses(
|
||||
"GET / HTTP/1.1\n"+
|
||||
"Host: whatever\n"+
|
||||
"Connection: close\n"+
|
||||
"\n"
|
||||
);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
@ -636,6 +661,7 @@ public class RequestTest
|
|||
"GET / HTTP/1.1\n"+
|
||||
"Host: whatever\n"+
|
||||
"Cookie: name=quoted=\\\"value\\\"\n" +
|
||||
"Connection: close\n"+
|
||||
"\n"
|
||||
);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
@ -648,6 +674,7 @@ public class RequestTest
|
|||
"GET / HTTP/1.1\n"+
|
||||
"Host: whatever\n"+
|
||||
"Cookie: name=value; other=\"quoted=;value\"\n" +
|
||||
"Connection: close\n"+
|
||||
"\n"
|
||||
);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
@ -669,6 +696,7 @@ public class RequestTest
|
|||
"Host: whatever\n"+
|
||||
"Other: header\n"+
|
||||
"Cookie: name=value; other=\"quoted=;value\"\n" +
|
||||
"Connection: close\n"+
|
||||
"\n"
|
||||
);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
@ -692,6 +720,7 @@ public class RequestTest
|
|||
"Host: whatever\n"+
|
||||
"Other: header\n"+
|
||||
"Cookie: name=value; other=\"othervalue\"\n" +
|
||||
"Connection: close\n"+
|
||||
"\n"
|
||||
);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
@ -743,6 +772,7 @@ public class RequestTest
|
|||
"Host: whatever\n"+
|
||||
"Other: header\n"+
|
||||
"Cookie: __utmz=14316.133020.1.1.utr=gna.de|ucn=(real)|utd=reral|utct=/games/hen-one,gnt-50-ba-keys:key,2072262.html\n"+
|
||||
"Connection: close\n"+
|
||||
"\n"
|
||||
);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
@ -759,6 +789,7 @@ public class RequestTest
|
|||
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
for (int i=0;i<cookie.length; i++)
|
||||
|
@ -851,6 +882,7 @@ public class RequestTest
|
|||
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
@Override
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
return "b".equals(request.getParameter("a")) && request.getParameter("c")==null;
|
||||
|
@ -883,6 +915,7 @@ public class RequestTest
|
|||
private RequestTester _checker;
|
||||
private String _content;
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
((Request)request).setHandled(true);
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
|
@ -24,6 +29,7 @@ import java.util.Locale;
|
|||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -32,9 +38,10 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.io.AbstractAsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncByteArrayEndPoint;
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.AbstractEndPoint;
|
||||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.session.HashSessionIdManager;
|
||||
|
@ -45,18 +52,13 @@ import org.junit.Before;
|
|||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ResponseTest
|
||||
{
|
||||
private Server _server;
|
||||
private LocalHttpConnector _connector;
|
||||
private LocalConnector _connector;
|
||||
private HttpChannel _channel;
|
||||
private ScheduledExecutorService _timer;
|
||||
|
||||
|
@ -64,15 +66,15 @@ public class ResponseTest
|
|||
public void init() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalHttpConnector();
|
||||
_connector = new LocalConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
_server.setHandler(new DumpHandler());
|
||||
_server.start();
|
||||
_timer=new ScheduledThreadPoolExecutor(1);
|
||||
|
||||
AsyncByteArrayEndPoint endp = new AsyncByteArrayEndPoint(_timer,5000);
|
||||
AbstractEndPoint endp = new ByteArrayEndPoint(_timer,5000);
|
||||
HttpInput input = new HttpInput();
|
||||
AsyncConnection connection = new AbstractAsyncConnection(endp,new Executor()
|
||||
Connection connection = new AbstractConnection(endp,new Executor()
|
||||
{
|
||||
@Override
|
||||
public void execute(Runnable command)
|
||||
|
@ -81,6 +83,13 @@ public class ResponseTest
|
|||
}
|
||||
})
|
||||
{
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
fillInterested();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFillable()
|
||||
{
|
||||
|
@ -100,35 +109,28 @@ public class ResponseTest
|
|||
@Override
|
||||
protected void resetBuffer()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void increaseContentBufferSize(int size)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledExecutorService getScheduler()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpConnector getHttpConnector()
|
||||
public HttpConfiguration getHttpConfiguration()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getContentBufferSize()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -142,29 +144,27 @@ public class ResponseTest
|
|||
@Override
|
||||
protected void execute(Runnable task)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completed()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeResponse() throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void commitResponse(ResponseInfo info, ByteBuffer content) throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connector getConnector()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ public class SelectChannelAsyncContextTest extends LocalAsyncContextTest
|
|||
@Override
|
||||
protected Connector initConnector()
|
||||
{
|
||||
return new SelectChannelConnector();
|
||||
return new SelectChannelConnector(_server);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
|
||||
|
@ -25,6 +26,12 @@ public class SelectChannelConnectorCloseTest extends ConnectorCloseTestBase
|
|||
public void init() throws Exception
|
||||
{
|
||||
System.setProperty("org.eclipse.jetty.util.log.DEBUG","true");
|
||||
startServer(new SelectChannelConnector());
|
||||
startServer(new SelectChannelConnector(_server));
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public class SelectChannelServerTest extends HttpServerTestBase
|
|||
@BeforeClass
|
||||
public static void init() throws Exception
|
||||
{
|
||||
startServer(new SelectChannelConnector());
|
||||
startServer(new SelectChannelConnector(_server));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -20,12 +23,13 @@ import java.io.PrintWriter;
|
|||
import java.net.Socket;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -36,9 +40,6 @@ import org.junit.Before;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SelectChannelStatisticsTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SelectChannelStatisticsTest.class);
|
||||
|
@ -58,17 +59,17 @@ public class SelectChannelStatisticsTest
|
|||
_connect = new CyclicBarrier(2);
|
||||
|
||||
_server = new Server();
|
||||
_connector = new SelectChannelConnector()
|
||||
_connector = new SelectChannelConnector(_server)
|
||||
{
|
||||
@Override
|
||||
protected void endPointClosed(AsyncEndPoint endpoint)
|
||||
protected void endPointClosed(EndPoint endpoint)
|
||||
{
|
||||
//System.err.println("Endpoint closed "+endpoint);
|
||||
super.endPointClosed(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed(AsyncConnection connection)
|
||||
public void connectionClosed(Connection connection)
|
||||
{
|
||||
//System.err.println("Connection closed "+connection);
|
||||
super.connectionClosed(connection);
|
||||
|
|
|
@ -31,7 +31,7 @@ public class SelectChannelTimeoutTest extends ConnectorTimeoutTest
|
|||
@BeforeClass
|
||||
public static void init() throws Exception
|
||||
{
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(_server);
|
||||
connector.setIdleTimeout(MAX_IDLE_TIME); // 250 msec max idle
|
||||
startServer(connector);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
@ -27,8 +26,8 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
|
@ -44,12 +43,12 @@ public class SlowClientWithPipelinedRequestTest
|
|||
public void startServer(Handler handler) throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new SelectChannelConnector()
|
||||
connector = new SelectChannelConnector(server,new ConnectionFactory()
|
||||
{
|
||||
@Override
|
||||
protected AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint)
|
||||
protected Connection newConnection(Connector connector,EndPoint endpoint)
|
||||
{
|
||||
return new HttpConnection(this,endpoint,getServer())
|
||||
return new HttpConnection(getHttpConfig(),connector,endpoint)
|
||||
{
|
||||
@Override
|
||||
public synchronized void onFillable()
|
||||
|
@ -57,10 +56,10 @@ public class SlowClientWithPipelinedRequestTest
|
|||
handles.incrementAndGet();
|
||||
super.onFillable();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
};
|
||||
},null,null,null,0,0);
|
||||
|
||||
server.addConnector(connector);
|
||||
connector.setPort(0);
|
||||
server.setHandler(handler);
|
||||
|
|
|
@ -85,10 +85,9 @@ public class StressTest
|
|||
_threads = new QueuedThreadPool();
|
||||
_threads.setMaxThreads(200);
|
||||
|
||||
_server = new Server();
|
||||
_server.setThreadPool(_threads);
|
||||
|
||||
_connector = new SelectChannelConnector(1,1);
|
||||
_server = new Server(_threads);
|
||||
_server.manage(_threads);
|
||||
_connector = new SelectChannelConnector(_server,null,null,null,null,1,1);
|
||||
_connector.setAcceptQueueSize(5000);
|
||||
_connector.setIdleTimeout(30000);
|
||||
_server.addConnector(_connector);
|
||||
|
|
|
@ -24,7 +24,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.LocalHttpConnector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.junit.Test;
|
||||
|
@ -35,7 +35,7 @@ public class ContextHandlerCollectionTest
|
|||
public void testVirtualHostNormalization() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
LocalHttpConnector connector = new LocalHttpConnector();
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
|
||||
|
@ -93,7 +93,7 @@ public class ContextHandlerCollectionTest
|
|||
public void testVirtualHostWildcard() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
LocalHttpConnector connector = new LocalHttpConnector();
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.setConnectors(new Connector[] { connector });
|
||||
|
||||
ContextHandler context = new ContextHandler("/");
|
||||
|
@ -133,7 +133,7 @@ public class ContextHandlerCollectionTest
|
|||
|
||||
private void checkWildcardHost(boolean succeed, Server server, String[] contextHosts, String[] requestHosts) throws Exception
|
||||
{
|
||||
LocalHttpConnector connector = (LocalHttpConnector)server.getConnectors()[0];
|
||||
LocalConnector connector = (LocalConnector)server.getConnectors()[0];
|
||||
ContextHandlerCollection handlerCollection = (ContextHandlerCollection)server.getHandler();
|
||||
ContextHandler context = (ContextHandler)handlerCollection.getHandlers()[0];
|
||||
IsHandledHandler handler = (IsHandledHandler)context.getHandler();
|
||||
|
@ -144,7 +144,7 @@ public class ContextHandlerCollectionTest
|
|||
|
||||
for(String host : requestHosts)
|
||||
{
|
||||
connector.getResponses("GET / HTTP/1.1\n" + "Host: "+host+"\n\n");
|
||||
connector.getResponses("GET / HTTP/1.1\n" + "Host: "+host+"\nConnection:close\n\n");
|
||||
if(succeed)
|
||||
assertTrue("'"+host+"' should have been handled.",handler.isHandled());
|
||||
else
|
||||
|
|
|
@ -31,7 +31,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.LocalHttpConnector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -58,7 +58,7 @@ public class ContextHandlerTest
|
|||
public void testVirtualHostNormalization() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
LocalHttpConnector connector = new LocalHttpConnector();
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
|
||||
|
@ -117,7 +117,7 @@ public class ContextHandlerTest
|
|||
public void testContextGetContext() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
LocalHttpConnector connector = new LocalHttpConnector();
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.setConnectors(new Connector[] { connector });
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
server.setHandler(contexts);
|
||||
|
@ -149,7 +149,7 @@ public class ContextHandlerTest
|
|||
public void testContextVirtualGetContext() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
LocalHttpConnector connector = new LocalHttpConnector();
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.setConnectors(new Connector[] { connector });
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
server.setHandler(contexts);
|
||||
|
@ -196,7 +196,7 @@ public class ContextHandlerTest
|
|||
public void testVirtualHostWildcard() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
LocalHttpConnector connector = new LocalHttpConnector();
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.setConnectors(new Connector[] { connector });
|
||||
|
||||
ContextHandler context = new ContextHandler("/");
|
||||
|
@ -365,7 +365,7 @@ public class ContextHandlerTest
|
|||
{
|
||||
Server server = new Server();
|
||||
server.setUncheckedPrintWriter(true);
|
||||
LocalHttpConnector connector = new LocalHttpConnector();
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.setConnectors(new Connector[] { connector });
|
||||
ContextHandler context = new ContextHandler("/");
|
||||
WriterHandler handler = new WriterHandler();
|
||||
|
@ -376,10 +376,11 @@ public class ContextHandlerTest
|
|||
{
|
||||
server.start();
|
||||
|
||||
String response = connector.getResponses("GET / HTTP/1.1\n" + "Host: www.example.com.\n\n");
|
||||
String response = connector.getResponses("GET / HTTP/1.1\n" + "Host: www.example.com.\nConnection:close\n\n");
|
||||
|
||||
Assert.assertTrue(response.indexOf("Goodbye")>0);
|
||||
Assert.assertTrue(response.indexOf("dead")<0);
|
||||
Thread.sleep(100);
|
||||
Assert.assertTrue(handler.error);
|
||||
Assert.assertTrue(handler.throwable!=null);
|
||||
}
|
||||
|
@ -391,14 +392,14 @@ public class ContextHandlerTest
|
|||
|
||||
private void checkWildcardHost(boolean succeed, Server server, String[] contextHosts, String[] requestHosts) throws Exception
|
||||
{
|
||||
LocalHttpConnector connector = (LocalHttpConnector)server.getConnectors()[0];
|
||||
LocalConnector connector = (LocalConnector)server.getConnectors()[0];
|
||||
ContextHandler context = (ContextHandler)server.getHandler();
|
||||
context.setVirtualHosts(contextHosts);
|
||||
|
||||
IsHandledHandler handler = (IsHandledHandler)context.getHandler();
|
||||
for(String host : requestHosts)
|
||||
{
|
||||
connector.getResponses("GET / HTTP/1.1\n" + "Host: "+host+"\n\n");
|
||||
connector.getResponses("GET / HTTP/1.1\n" + "Host: "+host+"\nConnection:close\n\n");
|
||||
if(succeed)
|
||||
assertTrue("'"+host+"' should have been handled.",handler.isHandled());
|
||||
else
|
||||
|
@ -431,8 +432,8 @@ public class ContextHandlerTest
|
|||
|
||||
private static final class WriterHandler extends AbstractHandler
|
||||
{
|
||||
boolean error;
|
||||
Throwable throwable;
|
||||
volatile boolean error;
|
||||
volatile Throwable throwable;
|
||||
|
||||
|
||||
public void handle(String s, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
|
|
|
@ -63,7 +63,7 @@ public class IPAccessHandlerTest
|
|||
throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new SelectChannelConnector();
|
||||
_connector = new SelectChannelConnector(_server);
|
||||
_server.setConnectors(new Connector[] { _connector });
|
||||
|
||||
_handler = new IPAccessHandler();
|
||||
|
|
|
@ -43,7 +43,7 @@ public class ResourceHandlerTest extends TestCase
|
|||
public void setUp() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new SelectChannelConnector();
|
||||
_connector = new SelectChannelConnector(_server);
|
||||
_server.setConnectors(new Connector[] { _connector });
|
||||
|
||||
_resourceHandler = new ResourceHandler();
|
||||
|
|
|
@ -31,7 +31,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.continuation.Continuation;
|
||||
import org.eclipse.jetty.continuation.ContinuationListener;
|
||||
import org.eclipse.jetty.continuation.ContinuationSupport;
|
||||
import org.eclipse.jetty.server.LocalHttpConnector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.junit.After;
|
||||
|
@ -41,7 +41,7 @@ import org.junit.Test;
|
|||
public class StatisticsHandlerTest
|
||||
{
|
||||
private Server _server;
|
||||
private LocalHttpConnector _connector;
|
||||
private LocalConnector _connector;
|
||||
private LatchHandler _latchHandler;
|
||||
private StatisticsHandler _statsHandler;
|
||||
|
||||
|
@ -50,7 +50,7 @@ public class StatisticsHandlerTest
|
|||
{
|
||||
_server = new Server();
|
||||
|
||||
_connector = new LocalHttpConnector();
|
||||
_connector = new LocalConnector(_server);
|
||||
_server.addConnector(_connector);
|
||||
_connector.getStatistics().start();
|
||||
|
||||
|
|
|
@ -11,11 +11,6 @@
|
|||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
// JettyTest.java --
|
||||
//
|
||||
// Junit test that shows the Jetty SSL bug.
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.ssl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
@ -36,9 +31,10 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
|
||||
|
@ -47,7 +43,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
|
|||
*/
|
||||
public class SSLCloseTest extends TestCase
|
||||
{
|
||||
private static AsyncEndPoint __endp;
|
||||
private static EndPoint __endp;
|
||||
private static class CredulousTM implements TrustManager, X509TrustManager
|
||||
{
|
||||
public X509Certificate[] getAcceptedIssuers()
|
||||
|
@ -77,14 +73,14 @@ public class SSLCloseTest extends TestCase
|
|||
public void testClose() throws Exception
|
||||
{
|
||||
Server server=new Server();
|
||||
SslSelectChannelConnector connector=new SslSelectChannelConnector();
|
||||
SelectChannelConnector connector=new SelectChannelConnector(server,true);
|
||||
|
||||
String keystore = System.getProperty("user.dir")+File.separator+"src"+File.separator+"test"+File.separator+"resources"+File.separator+"keystore";
|
||||
|
||||
connector.setPort(0);
|
||||
connector.getSslContextFactory().setKeyStorePath(keystore);
|
||||
connector.getSslContextFactory().setKeyStorePassword("storepwd");
|
||||
connector.getSslContextFactory().setKeyManagerPassword("keypwd");
|
||||
connector.getConnectionFactory().getSslContextFactory().setKeyStorePath(keystore);
|
||||
connector.getConnectionFactory().getSslContextFactory().setKeyStorePassword("storepwd");
|
||||
connector.getConnectionFactory().getSslContextFactory().setKeyManagerPassword("keypwd");
|
||||
|
||||
server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
|
@ -98,11 +94,13 @@ public class SSLCloseTest extends TestCase
|
|||
|
||||
int port=connector.getLocalPort();
|
||||
|
||||
// System.err.println("write:"+i);
|
||||
Socket socket=ctx.getSocketFactory().createSocket("localhost",port);
|
||||
OutputStream os=socket.getOutputStream();
|
||||
|
||||
os.write("GET /test HTTP/1.1\r\nHost:test\r\nConnection:close\r\n\r\n".getBytes());
|
||||
os.write((
|
||||
"GET /test HTTP/1.1\r\n"+
|
||||
"Host:test\r\n"+
|
||||
"Connection:close\r\n\r\n").getBytes());
|
||||
os.flush();
|
||||
|
||||
BufferedReader in =new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
@ -110,18 +108,14 @@ public class SSLCloseTest extends TestCase
|
|||
String line;
|
||||
while ((line=in.readLine())!=null)
|
||||
{
|
||||
// System.err.println(line);
|
||||
if (line.trim().length()==0)
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.sleep(2000);
|
||||
// System.err.println(__endp);
|
||||
|
||||
while ((line=in.readLine())!=null)
|
||||
//System.err.println(line);
|
||||
Thread.yield();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -45,11 +45,13 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -81,23 +83,23 @@ public class SSLEngineTest
|
|||
private static final int BODY_SIZE=300;
|
||||
|
||||
private Server server;
|
||||
private SslSelectChannelConnector connector;
|
||||
private SelectChannelConnector connector;
|
||||
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
{
|
||||
server=new Server();
|
||||
connector=new SslSelectChannelConnector();
|
||||
connector=new SelectChannelConnector(server,true);
|
||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
|
||||
connector.setPort(0);
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
SslContextFactory cf = connector.getConnectionFactory().getSslContextFactory();
|
||||
cf.setKeyStorePath(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
connector.setRequestBufferSize(512);
|
||||
connector.setRequestHeaderSize(512);
|
||||
connector.getConnectionFactory().getHttpConfig().setRequestBufferSize(512);
|
||||
connector.getConnectionFactory().getHttpConfig().setRequestHeaderSize(512);
|
||||
|
||||
server.setConnectors(new Connector[]{connector });
|
||||
}
|
||||
|
@ -108,8 +110,38 @@ public class SSLEngineTest
|
|||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testHelloWorld() throws Exception
|
||||
{
|
||||
server.setHandler(new HelloWorldHandler());
|
||||
server.start();
|
||||
server.dumpStdErr();
|
||||
|
||||
SSLContext ctx=SSLContext.getInstance("TLS");
|
||||
ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
|
||||
|
||||
int port=connector.getLocalPort();
|
||||
|
||||
Socket client=ctx.getSocketFactory().createSocket("localhost",port);
|
||||
OutputStream os=client.getOutputStream();
|
||||
|
||||
String request =
|
||||
"GET / HTTP/1.1\r\n"+
|
||||
"Host: localhost:"+port+"\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n";
|
||||
|
||||
os.write(request.getBytes());
|
||||
os.flush();
|
||||
|
||||
String response = IO.toString(client.getInputStream());
|
||||
|
||||
assertThat(response,Matchers.containsString("200 OK"));
|
||||
assertThat(response,Matchers.containsString(HELLO_WORLD));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigResponse() throws Exception
|
||||
{
|
||||
|
|
|
@ -40,7 +40,6 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
|
|||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SSLSelectChannelConnectorLoadTest
|
||||
|
@ -53,11 +52,11 @@ public class SSLSelectChannelConnectorLoadTest
|
|||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new SslSelectChannelConnector();
|
||||
connector = new SslSelectChannelConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
String keystorePath = System.getProperty("basedir", ".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
SslContextFactory cf = connector.getConnectionFactory().getSslContextFactory();
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
@ -69,7 +68,7 @@ public class SSLSelectChannelConnectorLoadTest
|
|||
server.start();
|
||||
|
||||
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
||||
keystore.load(new FileInputStream(connector.getConnectionFactory().getSslContextFactory().getKeyStorePath()), "storepwd".toCharArray());
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
trustManagerFactory.init(keystore);
|
||||
sslContext = SSLContext.getInstance("SSL");
|
||||
|
|
|
@ -25,6 +25,7 @@ import javax.net.ssl.SSLContext;
|
|||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import org.eclipse.jetty.server.HttpServerTestBase;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
|
@ -49,10 +50,10 @@ public class SelectChannelServerSslTest extends HttpServerTestBase
|
|||
@BeforeClass
|
||||
public static void init() throws Exception
|
||||
{
|
||||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(_server,true);
|
||||
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
SslContextFactory cf = connector.getConnectionFactory().getSslContextFactory();
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
@ -62,7 +63,7 @@ public class SelectChannelServerSslTest extends HttpServerTestBase
|
|||
|
||||
|
||||
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
||||
keystore.load(new FileInputStream(connector.getConnectionFactory().getSslContextFactory().getKeyStorePath()), "storepwd".toCharArray());
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
trustManagerFactory.init(keystore);
|
||||
__sslContext = SSLContext.getInstance("TLS");
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.io.IOException;
|
|||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Callable;
|
||||
|
@ -34,7 +35,6 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
|
@ -42,11 +42,11 @@ import javax.servlet.ServletOutputStream;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.io.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
|
@ -73,7 +73,6 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
private int serverPort;
|
||||
private SSLContext sslContext;
|
||||
private SimpleProxy proxy;
|
||||
private Runnable idleHook;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
|
@ -81,76 +80,26 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
threadPool = Executors.newCachedThreadPool();
|
||||
server = new Server();
|
||||
|
||||
SslSelectChannelConnector connector = new SslSelectChannelConnector()
|
||||
SelectChannelConnector connector = new SelectChannelConnector(server,true)
|
||||
{
|
||||
@Override
|
||||
protected SslConnection newSslConnection(AsyncEndPoint endPoint, SSLEngine engine)
|
||||
protected SelectChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
|
||||
{
|
||||
serverEndPoint.set(endPoint);
|
||||
return super.newSslConnection(endPoint, engine);
|
||||
// return new SslConnection(engine, endPoint)
|
||||
// {
|
||||
// @Override
|
||||
// public Connection handle() throws IOException
|
||||
// {
|
||||
// sslHandles.incrementAndGet();
|
||||
// return super.handle();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected SslEndPoint newSslEndPoint()
|
||||
// {
|
||||
// return new SslEndPoint()
|
||||
// {
|
||||
// @Override
|
||||
// public int flush(ByteBuffer buffer) throws IOException
|
||||
// {
|
||||
// sslFlushes.incrementAndGet();
|
||||
// return super.flush(buffer);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onIdleExpired(long idleForMs)
|
||||
// {
|
||||
// final Runnable idleHook = SslBytesServerTest.this.idleHook;
|
||||
// if (idleHook != null)
|
||||
// idleHook.run();
|
||||
// super.onIdleExpired(idleForMs);
|
||||
// }
|
||||
// };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AsyncConnection newPlainConnection(SocketChannel channel, AsyncEndPoint endPoint)
|
||||
{
|
||||
return super.newPlainConnection(channel, endPoint);
|
||||
// return new HttpConnection(this, endPoint, getServer())
|
||||
// {
|
||||
// @Override
|
||||
// protected HttpParser newHttpParser(Buffers requestBuffers, EndPoint endPoint, HttpParser.EventHandler requestHandler)
|
||||
// {
|
||||
// return new HttpParser(requestBuffers, endPoint, requestHandler)
|
||||
// {
|
||||
// @Override
|
||||
// public int parseNext() throws IOException
|
||||
// {
|
||||
// httpParses.incrementAndGet();
|
||||
// return super.parseNext();
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// };
|
||||
SelectChannelEndPoint endp = super.newEndPoint(channel,selectSet,key);
|
||||
serverEndPoint.set(endp);
|
||||
return endp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
connector.setIdleTimeout(idleTimeout);
|
||||
|
||||
// connector.setPort(5870);
|
||||
connector.setPort(0);
|
||||
|
||||
File keyStore = MavenTestingUtils.getTestResourceFile("keystore");
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
SslContextFactory cf = connector.getConnectionFactory().getSslContextFactory();
|
||||
cf.setKeyStorePath(keyStore.getAbsolutePath());
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
@ -1573,33 +1522,8 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
public void testRequestConcurrentWithIdleExpiration() throws Exception
|
||||
{
|
||||
final SSLSocket client = newClient();
|
||||
final OutputStream clientOutput = client.getOutputStream();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
idleHook = new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
if (latch.getCount() == 0)
|
||||
return;
|
||||
try
|
||||
{
|
||||
// Send request
|
||||
clientOutput.write(("" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n").getBytes("UTF-8"));
|
||||
clientOutput.flush();
|
||||
latch.countDown();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
// Latch won't trigger and test will fail
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
client.startHandshake();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
|
|
@ -1,262 +0,0 @@
|
|||
package org.eclipse.jetty.server.ssl;
|
||||
//========================================================================
|
||||
//Copyright 2011-2012 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.
|
||||
//========================================================================
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
import javax.net.ssl.SSLProtocolException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SslRenegotiateTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SslRenegotiateTest.class);
|
||||
|
||||
private ByteBuffer _outAppB;
|
||||
private ByteBuffer _outPacketB;
|
||||
private ByteBuffer _inAppB;
|
||||
private ByteBuffer _inPacketB;
|
||||
private SocketChannel _socket;
|
||||
private SSLEngine _engine;
|
||||
|
||||
@Test
|
||||
public void testRenegNIO() throws Exception
|
||||
{
|
||||
// TODO This test breaks on JVMs with the fix
|
||||
// doRequests(new SslSelectChannelConnector(),true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testNoRenegNIO() throws Exception
|
||||
{
|
||||
doRequests(new SslSelectChannelConnector(),false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenegBIO() throws Exception
|
||||
{
|
||||
// TODO - this test is too non deterministic due to call back timing
|
||||
// doRequests(new SslSocketConnector(),true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoRenegBIO() throws Exception
|
||||
{
|
||||
// TODO - this test is too non deterministic due to call back timing
|
||||
// doRequests(new SslSocketConnector(),false);
|
||||
}
|
||||
|
||||
private void doRequests(SslConnector connector, boolean reneg) throws Exception
|
||||
{
|
||||
Server server=new Server();
|
||||
try
|
||||
{
|
||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStorePath(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setAllowRenegotiate(reneg);
|
||||
|
||||
server.setConnectors(new Connector[] { connector });
|
||||
server.setHandler(new HelloWorldHandler());
|
||||
|
||||
server.start();
|
||||
|
||||
SocketAddress addr = new InetSocketAddress("localhost",connector.getLocalPort());
|
||||
_socket = SocketChannel.open(addr);
|
||||
_socket.configureBlocking(true);
|
||||
|
||||
SSLContext context=SSLContext.getInstance("SSL");
|
||||
context.init( null, SslContextFactory.TRUST_ALL_CERTS, new java.security.SecureRandom() );
|
||||
|
||||
_engine = context.createSSLEngine();
|
||||
_engine.setUseClientMode(true);
|
||||
SSLSession session=_engine.getSession();
|
||||
|
||||
_outAppB = ByteBuffer.allocate(session.getApplicationBufferSize());
|
||||
_outPacketB = ByteBuffer.allocate(session.getPacketBufferSize());
|
||||
_inAppB = ByteBuffer.allocate(session.getApplicationBufferSize());
|
||||
_inPacketB = ByteBuffer.allocate(session.getPacketBufferSize());
|
||||
|
||||
|
||||
_outAppB.put("GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n".getBytes(StringUtil.__ISO_8859_1));
|
||||
_outAppB.flip();
|
||||
|
||||
_engine.beginHandshake();
|
||||
|
||||
runHandshake();
|
||||
|
||||
doWrap();
|
||||
doUnwrap();
|
||||
_inAppB.flip();
|
||||
String response=BufferUtil.toString(_inAppB);
|
||||
// System.err.println(response);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
if (response.indexOf("HELLO WORLD")<0)
|
||||
{
|
||||
_inAppB.clear();
|
||||
doUnwrap();
|
||||
_inAppB.flip();
|
||||
response=BufferUtil.toString(_inAppB);
|
||||
}
|
||||
|
||||
assertTrue(response.indexOf("HELLO WORLD")>=0);
|
||||
|
||||
_inAppB.clear();
|
||||
_outAppB.clear();
|
||||
_outAppB.put("GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n".getBytes(StringUtil.__ISO_8859_1));
|
||||
_outAppB.flip();
|
||||
|
||||
try
|
||||
{
|
||||
session.invalidate();
|
||||
_engine.beginHandshake();
|
||||
runHandshake();
|
||||
|
||||
doWrap();
|
||||
doUnwrap();
|
||||
_inAppB.flip();
|
||||
response=BufferUtil.toString(_inAppB);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertTrue(response.indexOf("HELLO WORLD")>0);
|
||||
|
||||
assertTrue(reneg);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
if (!(e instanceof SSLProtocolException))
|
||||
{
|
||||
if (reneg)
|
||||
LOG.warn(e);
|
||||
assertFalse(reneg);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
}
|
||||
|
||||
void runHandshake() throws Exception
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
switch(_engine.getHandshakeStatus())
|
||||
{
|
||||
case NEED_TASK:
|
||||
{
|
||||
//System.err.println("running task");
|
||||
_engine.getDelegatedTask().run();
|
||||
break;
|
||||
}
|
||||
|
||||
case NEED_WRAP:
|
||||
{
|
||||
doWrap();
|
||||
break;
|
||||
}
|
||||
|
||||
case NEED_UNWRAP:
|
||||
{
|
||||
doUnwrap();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doWrap() throws Exception
|
||||
{
|
||||
_engine.wrap(_outAppB,_outPacketB);
|
||||
// System.err.println("wrapped "+result.bytesConsumed()+" to "+result.bytesProduced());
|
||||
_outPacketB.flip();
|
||||
while (_outPacketB.hasRemaining())
|
||||
{
|
||||
int p = _outPacketB.remaining();
|
||||
int l =_socket.write(_outPacketB);
|
||||
// System.err.println("wrote "+l+" of "+p);
|
||||
}
|
||||
_outPacketB.clear();
|
||||
}
|
||||
|
||||
private void doUnwrap() throws Exception
|
||||
{
|
||||
_inPacketB.clear();
|
||||
int l=_socket.read(_inPacketB);
|
||||
// System.err.println("read "+l);
|
||||
if (l<0)
|
||||
throw new IOException("EOF");
|
||||
|
||||
_inPacketB.flip();
|
||||
|
||||
SSLEngineResult result;
|
||||
do
|
||||
{
|
||||
result =_engine.unwrap(_inPacketB,_inAppB);
|
||||
// System.err.println("unwrapped "+result.bytesConsumed()+" to "+result.bytesProduced()+" "+_engine.getHandshakeStatus());
|
||||
|
||||
}
|
||||
while(result.bytesConsumed()>0 &&
|
||||
_inPacketB.remaining()>0 &&
|
||||
(_engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP || _engine.getHandshakeStatus()==HandshakeStatus.NOT_HANDSHAKING));
|
||||
}
|
||||
|
||||
private static class HelloWorldHandler extends AbstractHandler
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
//System.err.println("HELLO WORLD HANDLING");
|
||||
|
||||
// System.err.println("hello "+baseRequest.getUri());
|
||||
byte[] b=("HELLO WORLD "+baseRequest.getUri()).getBytes(StringUtil.__UTF8);
|
||||
response.setContentLength(b.length);
|
||||
response.getOutputStream().write(b);
|
||||
response.getOutputStream().flush();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import javax.net.ssl.SSLContext;
|
|||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import org.eclipse.jetty.server.ConnectorTimeoutTest;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
|
@ -37,10 +38,10 @@ public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
|
|||
@BeforeClass
|
||||
public static void init() throws Exception
|
||||
{
|
||||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(_server,true);
|
||||
connector.setIdleTimeout(MAX_IDLE_TIME); //250 msec max idle
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
SslContextFactory cf = connector.getConnectionFactory().getSslContextFactory();
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
@ -49,7 +50,7 @@ public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
|
|||
startServer(connector);
|
||||
|
||||
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
||||
keystore.load(new FileInputStream(connector.getConnectionFactory().getSslContextFactory().getKeyStorePath()), "storepwd".toCharArray());
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
trustManagerFactory.init(keystore);
|
||||
__sslContext = SSLContext.getInstance("SSL");
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
@ -33,6 +32,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
|
@ -48,18 +48,18 @@ import org.junit.Test;
|
|||
public class SslUploadTest
|
||||
{
|
||||
private static Server server;
|
||||
private static SslSelectChannelConnector connector;
|
||||
private static SelectChannelConnector connector;
|
||||
private static int total;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new SslSelectChannelConnector();
|
||||
connector = new SelectChannelConnector(server,true);
|
||||
server.addConnector(connector);
|
||||
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
SslContextFactory cf = connector.getConnectionFactory().getSslContextFactory();
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
@ -83,7 +83,7 @@ public class SslUploadTest
|
|||
public void test() throws Exception
|
||||
{
|
||||
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keystore.load(new FileInputStream(connector.getKeystore()), "storepwd".toCharArray());
|
||||
keystore.load(new FileInputStream(connector.getConnectionFactory().getSslContextFactory().getKeyStorePath()), "storepwd".toCharArray());
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
trustManagerFactory.init(keystore);
|
||||
SSLContext sslContext = SSLContext.getInstance("SSL");
|
||||
|
|
|
@ -34,22 +34,17 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.io.WriterOutputStream;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Dispatcher;
|
||||
import org.eclipse.jetty.server.HttpConnector;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpOutput;
|
||||
import org.eclipse.jetty.server.InclusiveByteRange;
|
||||
import org.eclipse.jetty.server.ResourceCache;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.ssl.SslConnector;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.MultiPartOutputStream;
|
||||
|
@ -779,9 +774,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
}
|
||||
else
|
||||
{
|
||||
HttpConnector connector = HttpChannel.getCurrentHttpChannel().getHttpConnector();
|
||||
// TODO either make this more targeted and/or configurable or just get rid of the choice
|
||||
direct=!(connector instanceof SslConnector);
|
||||
// TODO sometimes we should be direct!
|
||||
Connector connector = HttpChannel.getCurrentHttpChannel().getConnector();
|
||||
direct=false;
|
||||
content_length=content.getContentLength();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ import javax.servlet.FilterConfig;
|
|||
import javax.servlet.FilterRegistration;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.eclipse.jetty.servlet.Holder.Source;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.io.IOException;
|
|||
import java.util.EnumSet;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
|
|
|
@ -28,9 +28,9 @@ import java.util.Stack;
|
|||
import javax.servlet.MultipartConfigElement;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.ServletSecurityElement;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package org.eclipse.jetty.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
|
@ -12,24 +10,18 @@ import javax.servlet.DispatcherType;
|
|||
import javax.servlet.Filter;
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.LocalHttpConnector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
public class ServletTester extends AggregateLifeCycle
|
||||
{
|
||||
private final Server _server=new Server();
|
||||
private final LocalHttpConnector _connector=new LocalHttpConnector();
|
||||
private final LocalConnector _connector=new LocalConnector(_server);
|
||||
private final ServletContextHandler _context;
|
||||
public void setVirtualHosts(String[] vhosts)
|
||||
{
|
||||
|
@ -184,7 +176,7 @@ public class ServletTester extends AggregateLifeCycle
|
|||
*/
|
||||
public String createConnector(boolean localhost) throws Exception
|
||||
{
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(_server);
|
||||
if (localhost)
|
||||
connector.setHost("127.0.0.1");
|
||||
_server.addConnector(connector);
|
||||
|
@ -198,9 +190,9 @@ public class ServletTester extends AggregateLifeCycle
|
|||
)+":"+connector.getLocalPort();
|
||||
}
|
||||
|
||||
public LocalHttpConnector createLocalConnector()
|
||||
public LocalConnector createLocalConnector()
|
||||
{
|
||||
LocalHttpConnector connector = new LocalHttpConnector();
|
||||
LocalConnector connector = new LocalConnector(_server);
|
||||
_server.addConnector(connector);
|
||||
return connector;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,11 @@ package org.eclipse.jetty.servlet;
|
|||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -23,7 +27,7 @@ import org.eclipse.jetty.continuation.ContinuationSupport;
|
|||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpChannelState;
|
||||
import org.eclipse.jetty.server.LocalHttpConnector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
|
@ -31,9 +35,6 @@ import org.junit.After;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* This tests verifies that merging of queryStrings works when dispatching
|
||||
* Requests via {@link Continuation} multiple times.
|
||||
|
@ -45,7 +46,7 @@ public class AsyncContextDispatchWithQueryStrings {
|
|||
|
||||
private Server _server = new Server();
|
||||
private ServletContextHandler _contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
|
||||
private LocalHttpConnector _connector = new LocalHttpConnector();
|
||||
private LocalConnector _connector = new LocalConnector(_server);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
|
|
@ -12,9 +12,15 @@ package org.eclipse.jetty.servlet;
|
|||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -24,9 +30,10 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.LocalHttpConnector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
|
@ -35,11 +42,6 @@ import org.junit.After;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* This tests the correct functioning of the AsyncContext
|
||||
*
|
||||
|
@ -50,14 +52,14 @@ public class AsyncContextTest
|
|||
|
||||
private Server _server;
|
||||
private ServletContextHandler _contextHandler;
|
||||
private LocalHttpConnector _connector;
|
||||
private LocalConnector _connector;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
_server = new Server();
|
||||
_contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
|
||||
_connector = new LocalHttpConnector();
|
||||
_connector = new LocalConnector(_server);
|
||||
_connector.setIdleTimeout(30000);
|
||||
_server.setConnectors(new Connector[]
|
||||
{ _connector });
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue