Merge branch 'jetty-9.4.x' into jetty-9.4.x-2022-FineGrainedComplianceModes
This commit is contained in:
commit
54f49dec7d
10
VERSION.txt
10
VERSION.txt
|
@ -171,6 +171,16 @@ jetty-9.4.7.v20170914 - 14 September 2017
|
|||
+ 475546 ClosedChannelException when connection to HTTPS over HTTP proxy with
|
||||
CONNECT
|
||||
|
||||
jetty-9.2.23.v20171218 - 18 December 2017
|
||||
+ 1556 Remove a timing channel in Password matching
|
||||
+ 1685 Update ALPN support for Java 8u141
|
||||
+ 1702 Update ALPN support for Java 8u144
|
||||
+ 1914 HttpClient fails to parse Content-Type response header with RFC 2045
|
||||
charset="utf-8" syntax
|
||||
+ 2065 Backport #347 to Jetty 9.2.x
|
||||
+ 475546 ClosedChannelException when connecting to HTTPS over HTTP proxy with
|
||||
CONNECT
|
||||
|
||||
jetty-9.3.22.v20171030 - 30 October 2017
|
||||
+ 1213 Upgrade to ASM Version 6.0_ALPHA for JDK9
|
||||
+ 1692 Annotation scanning should ignore `module-info.class` files
|
||||
|
|
|
@ -45,13 +45,6 @@ public class JettyTldPreScanned extends TldPreScanned
|
|||
{
|
||||
private final Collection<URL> _jettyPreScannedURLs;
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param namespaceAware
|
||||
* @param validation
|
||||
* @param blockExternal
|
||||
* @param preScannedTlds
|
||||
*/
|
||||
public JettyTldPreScanned(ServletContext context, boolean namespaceAware, boolean validation, boolean blockExternal, Collection<URL> preScannedTlds)
|
||||
{
|
||||
super(context, namespaceAware, validation, blockExternal, preScannedTlds);
|
||||
|
|
|
@ -890,9 +890,11 @@ public class AnnotationParser
|
|||
*
|
||||
* @param handlers the handlers to look for classes in
|
||||
* @param entry the entry in the potentially MultiRelease jar resource to parse
|
||||
* @param jar the jar file
|
||||
* @throws Exception if unable to parse
|
||||
*/
|
||||
protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, MultiReleaseJarFile.VersionedJarEntry entry) throws Exception
|
||||
protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, MultiReleaseJarFile.VersionedJarEntry entry)
|
||||
throws Exception
|
||||
{
|
||||
if (jar == null || entry == null)
|
||||
return;
|
||||
|
|
|
@ -156,11 +156,6 @@
|
|||
<artifactId>cdi-core</artifactId>
|
||||
<version>9.4.9-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>cdi-full-servlet</artifactId>
|
||||
<version>9.4.9-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>cdi-servlet</artifactId>
|
||||
|
@ -206,6 +201,13 @@
|
|||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-home</artifactId>
|
||||
<version>9.4.9-SNAPSHOT</version>
|
||||
<type>zip</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-home</artifactId>
|
||||
<version>9.4.9-SNAPSHOT</version>
|
||||
<type>tar.gz</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -95,6 +95,11 @@ public abstract class HttpReceiver
|
|||
return channel.getHttpDestination();
|
||||
}
|
||||
|
||||
public boolean isFailed()
|
||||
{
|
||||
return responseState.get() == ResponseState.FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to be invoked when the response status code is available.
|
||||
* <p>
|
||||
|
|
|
@ -86,6 +86,11 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
return channel.getHttpExchange();
|
||||
}
|
||||
|
||||
public boolean isFailed()
|
||||
{
|
||||
return requestState.get() == RequestState.FAILURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContent()
|
||||
{
|
||||
|
|
|
@ -70,7 +70,7 @@ public class BasicAuthentication extends AbstractAuthentication
|
|||
* Basic authentication result.
|
||||
* <p>
|
||||
* Application may utilize this class directly via
|
||||
* {@link AuthenticationStore#addAuthenticationResult(Result)}
|
||||
* {@link org.eclipse.jetty.client.api.AuthenticationStore#addAuthenticationResult(Result)}
|
||||
* to perform preemptive authentication, that is immediately
|
||||
* sending the authorization header based on the fact that the
|
||||
* URI is known to require authentication and that username
|
||||
|
|
|
@ -263,10 +263,10 @@ public class HttpClientTimeoutTest extends AbstractHttpClientServerTest
|
|||
return new SslConnection(byteBufferPool, executor, endPoint, engine)
|
||||
{
|
||||
@Override
|
||||
protected boolean onReadTimeout()
|
||||
protected boolean onReadTimeout(Throwable timeout)
|
||||
{
|
||||
sslIdle.set(true);
|
||||
return super.onReadTimeout();
|
||||
return super.onReadTimeout(timeout);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -126,12 +126,12 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean onReadTimeout()
|
||||
protected boolean onReadTimeout(Throwable timeout)
|
||||
{
|
||||
final Runnable idleHook = SslBytesServerTest.this.idleHook;
|
||||
if (idleHook != null)
|
||||
idleHook.run();
|
||||
return super.onReadTimeout();
|
||||
return super.onReadTimeout(timeout);
|
||||
}
|
||||
}, connector, endPoint);
|
||||
}
|
||||
|
|
|
@ -38,18 +38,17 @@ public class HttpChannelOverFCGI extends HttpChannel
|
|||
{
|
||||
private final HttpConnectionOverFCGI connection;
|
||||
private final Flusher flusher;
|
||||
private final int request;
|
||||
private final HttpSenderOverFCGI sender;
|
||||
private final HttpReceiverOverFCGI receiver;
|
||||
private final FCGIIdleTimeout idle;
|
||||
private int request;
|
||||
private HttpVersion version;
|
||||
|
||||
public HttpChannelOverFCGI(final HttpConnectionOverFCGI connection, Flusher flusher, int request, long idleTimeout)
|
||||
public HttpChannelOverFCGI(final HttpConnectionOverFCGI connection, Flusher flusher, long idleTimeout)
|
||||
{
|
||||
super(connection.getHttpDestination());
|
||||
this.connection = connection;
|
||||
this.flusher = flusher;
|
||||
this.request = request;
|
||||
this.sender = new HttpSenderOverFCGI(this);
|
||||
this.receiver = new HttpReceiverOverFCGI(this);
|
||||
this.idle = new FCGIIdleTimeout(connection, idleTimeout);
|
||||
|
@ -60,6 +59,11 @@ public class HttpChannelOverFCGI extends HttpChannel
|
|||
return request;
|
||||
}
|
||||
|
||||
void setRequest(int request)
|
||||
{
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpSender getHttpSender()
|
||||
{
|
||||
|
@ -72,6 +76,11 @@ public class HttpChannelOverFCGI extends HttpChannel
|
|||
return receiver;
|
||||
}
|
||||
|
||||
public boolean isFailed()
|
||||
{
|
||||
return sender.isFailed() || receiver.isFailed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send()
|
||||
{
|
||||
|
|
|
@ -23,7 +23,9 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
@ -56,7 +58,8 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
private static final Logger LOG = Log.getLogger(HttpConnectionOverFCGI.class);
|
||||
|
||||
private final LinkedList<Integer> requests = new LinkedList<>();
|
||||
private final Map<Integer, HttpChannelOverFCGI> channels = new ConcurrentHashMap<>();
|
||||
private final Map<Integer, HttpChannelOverFCGI> activeChannels = new ConcurrentHashMap<>();
|
||||
private final Queue<HttpChannelOverFCGI> idleChannels = new ConcurrentLinkedQueue<>();
|
||||
private final AtomicBoolean closed = new AtomicBoolean();
|
||||
private final HttpDestination destination;
|
||||
private final Promise<Connection> promise;
|
||||
|
@ -184,7 +187,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
{
|
||||
// Close explicitly only if we are idle, since the request may still
|
||||
// be in progress, otherwise close only if we can fail the responses.
|
||||
if (channels.isEmpty())
|
||||
if (activeChannels.isEmpty())
|
||||
close();
|
||||
else
|
||||
failAndClose(new EOFException(String.valueOf(getEndPoint())));
|
||||
|
@ -204,8 +207,14 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
|
||||
protected void release(HttpChannelOverFCGI channel)
|
||||
{
|
||||
channels.remove(channel.getRequest());
|
||||
destination.release(this);
|
||||
if (activeChannels.remove(channel.getRequest()) != null)
|
||||
{
|
||||
channel.setRequest(0);
|
||||
// Recycle only non-failed channels.
|
||||
if (!channel.isFailed())
|
||||
idleChannels.offer(channel);
|
||||
destination.release(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -249,19 +258,20 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
|
||||
protected void abort(Throwable failure)
|
||||
{
|
||||
for (HttpChannelOverFCGI channel : channels.values())
|
||||
for (HttpChannelOverFCGI channel : activeChannels.values())
|
||||
{
|
||||
HttpExchange exchange = channel.getHttpExchange();
|
||||
if (exchange != null)
|
||||
exchange.getRequest().abort(failure);
|
||||
}
|
||||
channels.clear();
|
||||
activeChannels.clear();
|
||||
idleChannels.clear();
|
||||
}
|
||||
|
||||
private void failAndClose(Throwable failure)
|
||||
{
|
||||
boolean result = false;
|
||||
for (HttpChannelOverFCGI channel : channels.values())
|
||||
for (HttpChannelOverFCGI channel : activeChannels.values())
|
||||
result |= channel.responseFailure(failure);
|
||||
if (result)
|
||||
close(failure);
|
||||
|
@ -286,9 +296,18 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
}
|
||||
}
|
||||
|
||||
protected HttpChannelOverFCGI newHttpChannel(int id, Request request)
|
||||
protected HttpChannelOverFCGI provideHttpChannel(int id, Request request)
|
||||
{
|
||||
return new HttpChannelOverFCGI(this, getFlusher(), id, request.getIdleTimeout());
|
||||
HttpChannelOverFCGI channel = idleChannels.poll();
|
||||
if (channel == null)
|
||||
channel = newHttpChannel(request);
|
||||
channel.setRequest(id);
|
||||
return channel;
|
||||
}
|
||||
|
||||
protected HttpChannelOverFCGI newHttpChannel(Request request)
|
||||
{
|
||||
return new HttpChannelOverFCGI(this, getFlusher(), request.getIdleTimeout());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -314,10 +333,10 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
Request request = exchange.getRequest();
|
||||
normalizeRequest(request);
|
||||
|
||||
// FCGI may be multiplexed, so create one channel for each request.
|
||||
// FCGI may be multiplexed, so one channel for each exchange.
|
||||
int id = acquireRequest();
|
||||
HttpChannelOverFCGI channel = newHttpChannel(id, request);
|
||||
channels.put(id, channel);
|
||||
HttpChannelOverFCGI channel = provideHttpChannel(id, request);
|
||||
activeChannels.put(id, channel);
|
||||
|
||||
return send(channel, exchange);
|
||||
}
|
||||
|
@ -351,7 +370,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
@Override
|
||||
public void onBegin(int request, int code, String reason)
|
||||
{
|
||||
HttpChannelOverFCGI channel = channels.get(request);
|
||||
HttpChannelOverFCGI channel = activeChannels.get(request);
|
||||
if (channel != null)
|
||||
channel.responseBegin(code, reason);
|
||||
else
|
||||
|
@ -361,7 +380,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
@Override
|
||||
public void onHeader(int request, HttpField field)
|
||||
{
|
||||
HttpChannelOverFCGI channel = channels.get(request);
|
||||
HttpChannelOverFCGI channel = activeChannels.get(request);
|
||||
if (channel != null)
|
||||
channel.responseHeader(field);
|
||||
else
|
||||
|
@ -371,7 +390,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
@Override
|
||||
public void onHeaders(int request)
|
||||
{
|
||||
HttpChannelOverFCGI channel = channels.get(request);
|
||||
HttpChannelOverFCGI channel = activeChannels.get(request);
|
||||
if (channel != null)
|
||||
channel.responseHeaders();
|
||||
else
|
||||
|
@ -385,7 +404,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
{
|
||||
case STD_OUT:
|
||||
{
|
||||
HttpChannelOverFCGI channel = channels.get(request);
|
||||
HttpChannelOverFCGI channel = activeChannels.get(request);
|
||||
if (channel != null)
|
||||
{
|
||||
CompletableCallback callback = new CompletableCallback()
|
||||
|
@ -431,7 +450,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
@Override
|
||||
public void onEnd(int request)
|
||||
{
|
||||
HttpChannelOverFCGI channel = channels.get(request);
|
||||
HttpChannelOverFCGI channel = activeChannels.get(request);
|
||||
if (channel != null)
|
||||
{
|
||||
if (channel.responseSuccess())
|
||||
|
@ -446,7 +465,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec
|
|||
@Override
|
||||
public void onFailure(int request, Throwable failure)
|
||||
{
|
||||
HttpChannelOverFCGI channel = channels.get(request);
|
||||
HttpChannelOverFCGI channel = activeChannels.get(request);
|
||||
if (channel != null)
|
||||
{
|
||||
if (channel.responseFailure(failure))
|
||||
|
|
|
@ -838,12 +838,10 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
|
|||
/**
|
||||
* Check to see if indexes are available, in which case
|
||||
* we can do more performant queries.
|
||||
* @return
|
||||
* @return <code>true</code> if indexes are available
|
||||
*/
|
||||
protected boolean checkIndexes ()
|
||||
protected boolean checkIndexes()
|
||||
{
|
||||
long start =0;
|
||||
|
||||
try
|
||||
{
|
||||
Query<ProjectionEntity> query = Query.newProjectionEntityQueryBuilder()
|
||||
|
|
|
@ -121,6 +121,11 @@ public class HazelcastSessionDataStoreFactory
|
|||
return onlyClient;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param onlyClient if <code>true</code> the session manager will only connect to an external Hazelcast instance
|
||||
* and not use this JVM to start an Hazelcast instance
|
||||
*/
|
||||
public void setOnlyClient( boolean onlyClient )
|
||||
{
|
||||
this.onlyClient = onlyClient;
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-start</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>shaded</classifier>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
|
@ -403,6 +404,7 @@
|
|||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-start</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>shaded</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -400,6 +400,7 @@ public class GZIPContentDecoder implements Destroyable
|
|||
}
|
||||
|
||||
/**
|
||||
* @param capacity capacity capacity of the allocated ByteBuffer
|
||||
* @return An indirect buffer of the configured buffersize either from the pool or freshly allocated.
|
||||
*/
|
||||
public ByteBuffer acquire(int capacity)
|
||||
|
|
|
@ -61,6 +61,7 @@ public class MetaData implements Iterable<HttpField>
|
|||
|
||||
/**
|
||||
* @deprecated use {@link #getHttpVersion()} instead
|
||||
* @return the HTTP version of this MetaData object
|
||||
*/
|
||||
@Deprecated
|
||||
public HttpVersion getVersion()
|
||||
|
|
|
@ -678,6 +678,9 @@ public class StreamResetTest extends AbstractTest
|
|||
stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
|
||||
Assert.assertTrue(writeLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
// Give time to the server to process the reset and drain the flusher queue.
|
||||
Thread.sleep(500);
|
||||
|
||||
HTTP2Session session = connector.getConnectionFactory(AbstractHTTP2ServerConnectionFactory.class).getBean(HTTP2Session.class);
|
||||
HTTP2Flusher flusher = session.getBean(HTTP2Flusher.class);
|
||||
Assert.assertEquals(0, flusher.getFrameQueueSize());
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.eclipse.jetty.http2.parser.Parser;
|
|||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.WriteFlusher;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
|
@ -37,7 +38,7 @@ import org.eclipse.jetty.util.thread.ExecutionStrategy;
|
|||
import org.eclipse.jetty.util.thread.ReservedThreadExecutor;
|
||||
import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill;
|
||||
|
||||
public class HTTP2Connection extends AbstractConnection
|
||||
public class HTTP2Connection extends AbstractConnection implements WriteFlusher.Listener
|
||||
{
|
||||
protected static final Logger LOG = Log.getLogger(HTTP2Connection.class);
|
||||
|
||||
|
@ -176,6 +177,13 @@ public class HTTP2Connection extends AbstractConnection
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlushed(long bytes) throws IOException
|
||||
{
|
||||
// TODO: add method to ISession ?
|
||||
((HTTP2Session)session).onFlushed(bytes);
|
||||
}
|
||||
|
||||
protected class HTTP2Producer implements ExecutionStrategy.Producer
|
||||
{
|
||||
private final Callback fillableCallback = new FillableCallback();
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.http2.frames.Frame;
|
|||
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.WriteFlusher;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.IteratingCallback;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
@ -175,7 +176,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
{
|
||||
if (entry.generate(lease))
|
||||
{
|
||||
if (entry.dataRemaining() > 0)
|
||||
if (entry.getDataBytesRemaining() > 0)
|
||||
entries.offer(entry);
|
||||
}
|
||||
else
|
||||
|
@ -207,6 +208,31 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
return Action.SCHEDULED;
|
||||
}
|
||||
|
||||
void onFlushed(long bytes) throws IOException
|
||||
{
|
||||
// For the given flushed bytes, we want to only
|
||||
// forward those that belong to data frame content.
|
||||
for (Entry entry : actives)
|
||||
{
|
||||
int frameBytesLeft = entry.getFrameBytesRemaining();
|
||||
if (frameBytesLeft > 0)
|
||||
{
|
||||
int update = (int)Math.min(bytes, frameBytesLeft);
|
||||
entry.onFrameBytesFlushed(update);
|
||||
bytes -= update;
|
||||
IStream stream = entry.stream;
|
||||
if (stream != null && !entry.isControl())
|
||||
{
|
||||
Object channel = stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
|
||||
if (channel instanceof WriteFlusher.Listener)
|
||||
((WriteFlusher.Listener)channel).onFlushed(update - Frame.HEADER_LENGTH);
|
||||
}
|
||||
if (bytes == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
|
@ -234,13 +260,13 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
for (int i = index; i < actives.size(); ++i)
|
||||
{
|
||||
Entry entry = actives.get(i);
|
||||
if (entry.dataRemaining() > 0)
|
||||
if (entry.getDataBytesRemaining() > 0)
|
||||
append(entry);
|
||||
}
|
||||
for (int i = 0; i < index; ++i)
|
||||
{
|
||||
Entry entry = actives.get(i);
|
||||
if (entry.dataRemaining() > 0)
|
||||
if (entry.getDataBytesRemaining() > 0)
|
||||
append(entry);
|
||||
}
|
||||
stalled = null;
|
||||
|
@ -333,7 +359,11 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
this.stream = stream;
|
||||
}
|
||||
|
||||
public int dataRemaining()
|
||||
public abstract int getFrameBytesRemaining();
|
||||
|
||||
public abstract void onFrameBytesFlushed(int bytesFlushed);
|
||||
|
||||
public int getDataBytesRemaining()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -387,6 +417,17 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isControl()
|
||||
{
|
||||
switch (frame.getType())
|
||||
{
|
||||
case DATA:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -955,6 +955,11 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
{
|
||||
}
|
||||
|
||||
void onFlushed(long bytes) throws IOException
|
||||
{
|
||||
flusher.onFlushed(bytes);
|
||||
}
|
||||
|
||||
public void disconnect()
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -1132,15 +1137,28 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
private class ControlEntry extends HTTP2Flusher.Entry
|
||||
{
|
||||
private int bytes;
|
||||
private int frameBytes;
|
||||
|
||||
private ControlEntry(Frame frame, IStream stream, Callback callback)
|
||||
{
|
||||
super(frame, stream, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFrameBytesRemaining()
|
||||
{
|
||||
return frameBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameBytesFlushed(int bytesFlushed)
|
||||
{
|
||||
frameBytes -= bytesFlushed;
|
||||
}
|
||||
|
||||
protected boolean generate(ByteBufferPool.Lease lease)
|
||||
{
|
||||
bytes = generator.control(lease, frame);
|
||||
bytes = frameBytes = generator.control(lease, frame);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Generated {}", frame);
|
||||
prepare();
|
||||
|
@ -1238,7 +1256,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
private class DataEntry extends HTTP2Flusher.Entry
|
||||
{
|
||||
private int bytes;
|
||||
private int dataRemaining;
|
||||
private int frameBytes;
|
||||
private int dataBytes;
|
||||
private int dataWritten;
|
||||
|
||||
private DataEntry(DataFrame frame, IStream stream, Callback callback)
|
||||
|
@ -1249,35 +1268,47 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
// of data frames that cannot be completely written due to
|
||||
// the flow control window exhausting, since in that case
|
||||
// we would have to count the padding only once.
|
||||
dataRemaining = frame.remaining();
|
||||
dataBytes = frame.remaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dataRemaining()
|
||||
public int getFrameBytesRemaining()
|
||||
{
|
||||
return dataRemaining;
|
||||
return frameBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameBytesFlushed(int bytesFlushed)
|
||||
{
|
||||
frameBytes -= bytesFlushed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataBytesRemaining()
|
||||
{
|
||||
return dataBytes;
|
||||
}
|
||||
|
||||
protected boolean generate(ByteBufferPool.Lease lease)
|
||||
{
|
||||
int dataRemaining = dataRemaining();
|
||||
int dataBytes = getDataBytesRemaining();
|
||||
|
||||
int sessionSendWindow = getSendWindow();
|
||||
int streamSendWindow = stream.updateSendWindow(0);
|
||||
int window = Math.min(streamSendWindow, sessionSendWindow);
|
||||
if (window <= 0 && dataRemaining > 0)
|
||||
if (window <= 0 && dataBytes > 0)
|
||||
return false;
|
||||
|
||||
int length = Math.min(dataRemaining, window);
|
||||
int length = Math.min(dataBytes, window);
|
||||
|
||||
// Only one DATA frame is generated.
|
||||
bytes = generator.data(lease, (DataFrame)frame, length);
|
||||
bytes = frameBytes = generator.data(lease, (DataFrame)frame, length);
|
||||
int written = bytes - Frame.HEADER_LENGTH;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Generated {}, length/window/data={}/{}/{}", frame, written, window, dataRemaining);
|
||||
LOG.debug("Generated {}, length/window/data={}/{}/{}", frame, written, window, dataBytes);
|
||||
|
||||
this.dataWritten = written;
|
||||
this.dataRemaining -= written;
|
||||
this.dataBytes -= written;
|
||||
|
||||
flowControl.onDataSending(stream, written);
|
||||
|
||||
|
@ -1292,7 +1323,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
|
||||
// Do we have more to send ?
|
||||
DataFrame dataFrame = (DataFrame)frame;
|
||||
if (dataRemaining() == 0)
|
||||
if (getDataBytesRemaining() == 0)
|
||||
{
|
||||
// Only now we can update the close state
|
||||
// and eventually remove the stream.
|
||||
|
|
|
@ -117,6 +117,7 @@ public interface ISession extends Session
|
|||
*
|
||||
* @see #onShutdown()
|
||||
* @see #close(int, String, Callback)
|
||||
* @return <code>true</code> if the session has expired
|
||||
*/
|
||||
public boolean onIdleTimeout();
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ public interface IStream extends Stream, Closeable
|
|||
|
||||
/**
|
||||
* @return the {@link org.eclipse.jetty.http2.api.Stream.Listener} associated with this stream
|
||||
* @see #setListener(Listener)
|
||||
* @see #setListener(Stream.Listener)
|
||||
*/
|
||||
public Listener getListener();
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ public class PriorityFrame extends Frame
|
|||
|
||||
/**
|
||||
* @deprecated use {@link #getParentStreamId()} instead.
|
||||
* @return <code>int</code> of the Parent Stream
|
||||
*/
|
||||
@Deprecated
|
||||
public int getDependentStreamId()
|
||||
|
|
|
@ -34,17 +34,15 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
{
|
||||
private final HttpConnectionOverHTTP2 connection;
|
||||
private final Session session;
|
||||
private final boolean push;
|
||||
private final HttpSenderOverHTTP2 sender;
|
||||
private final HttpReceiverOverHTTP2 receiver;
|
||||
private Stream stream;
|
||||
|
||||
public HttpChannelOverHTTP2(HttpDestination destination, HttpConnectionOverHTTP2 connection, Session session, boolean push)
|
||||
public HttpChannelOverHTTP2(HttpDestination destination, HttpConnectionOverHTTP2 connection, Session session)
|
||||
{
|
||||
super(destination);
|
||||
this.connection = connection;
|
||||
this.session = session;
|
||||
this.push = push;
|
||||
this.sender = new HttpSenderOverHTTP2(this);
|
||||
this.receiver = new HttpReceiverOverHTTP2(this);
|
||||
}
|
||||
|
@ -86,6 +84,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
this.stream = stream;
|
||||
}
|
||||
|
||||
public boolean isFailed()
|
||||
{
|
||||
return sender.isFailed() || receiver.isFailed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send()
|
||||
{
|
||||
|
@ -103,10 +106,10 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
@Override
|
||||
public boolean abort(HttpExchange exchange, Throwable requestFailure, Throwable responseFailure)
|
||||
{
|
||||
Stream stream = getStream();
|
||||
boolean aborted = super.abort(exchange, requestFailure, responseFailure);
|
||||
if (aborted)
|
||||
{
|
||||
Stream stream = getStream();
|
||||
if (stream != null)
|
||||
stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
|
||||
}
|
||||
|
@ -117,7 +120,6 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
public void exchangeTerminated(HttpExchange exchange, Result result)
|
||||
{
|
||||
super.exchangeTerminated(exchange, result);
|
||||
if (!push)
|
||||
release();
|
||||
release();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,11 @@ public class HttpClientTransportOverHTTP2 extends AbstractHttpClientTransport
|
|||
});
|
||||
}
|
||||
|
||||
public HTTP2Client getHTTP2Client()
|
||||
{
|
||||
return client;
|
||||
}
|
||||
|
||||
@ManagedAttribute(value = "The number of selectors", readonly = true)
|
||||
public int getSelectors()
|
||||
{
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
package org.eclipse.jetty.http2.client.http;
|
||||
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
@ -29,6 +31,7 @@ import org.eclipse.jetty.client.HttpChannel;
|
|||
import org.eclipse.jetty.client.HttpConnection;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.client.HttpRequest;
|
||||
import org.eclipse.jetty.client.SendFailure;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http2.ErrorCode;
|
||||
|
@ -38,7 +41,8 @@ import org.eclipse.jetty.util.thread.Sweeper;
|
|||
|
||||
public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.Sweepable
|
||||
{
|
||||
private final Set<HttpChannel> channels = ConcurrentHashMap.newKeySet();
|
||||
private final Set<HttpChannel> activeChannels = ConcurrentHashMap.newKeySet();
|
||||
private final Queue<HttpChannelOverHTTP2> idleChannels = new ConcurrentLinkedQueue<>();
|
||||
private final AtomicBoolean closed = new AtomicBoolean();
|
||||
private final AtomicInteger sweeps = new AtomicInteger();
|
||||
private final Session session;
|
||||
|
@ -57,25 +61,41 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S
|
|||
@Override
|
||||
protected SendFailure send(HttpExchange exchange)
|
||||
{
|
||||
exchange.getRequest().version(HttpVersion.HTTP_2);
|
||||
normalizeRequest(exchange.getRequest());
|
||||
HttpRequest request = exchange.getRequest();
|
||||
request.version(HttpVersion.HTTP_2);
|
||||
normalizeRequest(request);
|
||||
|
||||
// One connection maps to N channels, so for each exchange we create a new channel.
|
||||
HttpChannel channel = newHttpChannel(false);
|
||||
channels.add(channel);
|
||||
// One connection maps to N channels, so one channel for each exchange.
|
||||
HttpChannelOverHTTP2 channel = provideHttpChannel();
|
||||
activeChannels.add(channel);
|
||||
|
||||
return send(channel, exchange);
|
||||
}
|
||||
|
||||
protected HttpChannelOverHTTP2 newHttpChannel(boolean push)
|
||||
protected HttpChannelOverHTTP2 provideHttpChannel()
|
||||
{
|
||||
return new HttpChannelOverHTTP2(getHttpDestination(), this, getSession(), push);
|
||||
HttpChannelOverHTTP2 channel = idleChannels.poll();
|
||||
if (channel == null)
|
||||
channel = newHttpChannel();
|
||||
return channel;
|
||||
}
|
||||
|
||||
protected void release(HttpChannel channel)
|
||||
protected HttpChannelOverHTTP2 newHttpChannel()
|
||||
{
|
||||
channels.remove(channel);
|
||||
getHttpDestination().release(this);
|
||||
return new HttpChannelOverHTTP2(getHttpDestination(), this, getSession());
|
||||
}
|
||||
|
||||
protected void release(HttpChannelOverHTTP2 channel)
|
||||
{
|
||||
// Only non-push channels are released.
|
||||
if (activeChannels.remove(channel))
|
||||
{
|
||||
channel.setStream(null);
|
||||
// Recycle only non-failed channels.
|
||||
if (!channel.isFailed())
|
||||
idleChannels.offer(channel);
|
||||
getHttpDestination().release(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -113,13 +133,14 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S
|
|||
|
||||
private void abort(Throwable failure)
|
||||
{
|
||||
for (HttpChannel channel : channels)
|
||||
for (HttpChannel channel : activeChannels)
|
||||
{
|
||||
HttpExchange exchange = channel.getHttpExchange();
|
||||
if (exchange != null)
|
||||
exchange.getRequest().abort(failure);
|
||||
}
|
||||
channels.clear();
|
||||
activeChannels.clear();
|
||||
idleChannels.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -64,6 +64,13 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen
|
|||
return (HttpChannelOverHTTP2)super.getHttpChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reset()
|
||||
{
|
||||
super.reset();
|
||||
contentNotifier.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeaders(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
|
@ -114,6 +121,7 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen
|
|||
HttpRequest request = exchange.getRequest();
|
||||
MetaData.Request metaData = (MetaData.Request)frame.getMetaData();
|
||||
HttpRequest pushRequest = (HttpRequest)getHttpDestination().getHttpClient().newRequest(metaData.getURIString());
|
||||
// TODO: copy PUSH_PROMISE headers into pushRequest.
|
||||
|
||||
BiFunction<Request, Request, Response.CompleteListener> pushListener = request.getPushListener();
|
||||
if (pushListener != null)
|
||||
|
@ -121,7 +129,7 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen
|
|||
Response.CompleteListener listener = pushListener.apply(request, pushRequest);
|
||||
if (listener != null)
|
||||
{
|
||||
HttpChannelOverHTTP2 pushChannel = getHttpChannel().getHttpConnection().newHttpChannel(true);
|
||||
HttpChannelOverHTTP2 pushChannel = getHttpChannel().getHttpConnection().provideHttpChannel();
|
||||
List<Response.ResponseListener> listeners = Collections.singletonList(listener);
|
||||
HttpExchange pushExchange = new HttpExchange(getHttpDestination(), pushRequest, listeners);
|
||||
pushChannel.associate(pushExchange);
|
||||
|
@ -187,16 +195,16 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen
|
|||
private final Queue<DataInfo> queue = new ArrayDeque<>();
|
||||
private DataInfo dataInfo;
|
||||
|
||||
private boolean offer(DataInfo dataInfo)
|
||||
private void offer(DataInfo dataInfo)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
return queue.offer(dataInfo);
|
||||
queue.offer(dataInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Action process() throws Exception
|
||||
protected Action process()
|
||||
{
|
||||
DataInfo dataInfo;
|
||||
synchronized (this)
|
||||
|
|
|
@ -247,16 +247,19 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
|||
return new HttpConnectionOverHTTP2(destination, session)
|
||||
{
|
||||
@Override
|
||||
protected HttpChannelOverHTTP2 newHttpChannel(boolean push)
|
||||
protected HttpChannelOverHTTP2 newHttpChannel()
|
||||
{
|
||||
return new HttpChannelOverHTTP2(getHttpDestination(), this, getSession(), push)
|
||||
return new HttpChannelOverHTTP2(getHttpDestination(), this, getSession())
|
||||
{
|
||||
@Override
|
||||
public void setStream(Stream stream)
|
||||
{
|
||||
super.setStream(stream);
|
||||
streamRef.set(stream);
|
||||
streamLatch.countDown();
|
||||
if (stream != null)
|
||||
{
|
||||
streamRef.set(stream);
|
||||
streamLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.eclipse.jetty.http2.frames.DataFrame;
|
|||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.WriteFlusher;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
|
@ -48,7 +49,7 @@ import org.eclipse.jetty.util.Callback;
|
|||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable
|
||||
public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, WriteFlusher.Listener
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpChannelOverHTTP2.class);
|
||||
private static final HttpField SERVER_VERSION = new PreEncodedHttpField(HttpHeader.SERVER, HttpConfiguration.SERVER_VERSION);
|
||||
|
@ -85,6 +86,12 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable
|
|||
return getStream().getIdleTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlushed(long bytes) throws IOException
|
||||
{
|
||||
getResponse().getHttpOutput().onFlushed(bytes);
|
||||
}
|
||||
|
||||
public Runnable onRequest(HeadersFrame frame)
|
||||
{
|
||||
try
|
||||
|
@ -308,16 +315,19 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable
|
|||
|
||||
public boolean onStreamTimeout(Throwable failure, Consumer<Runnable> consumer)
|
||||
{
|
||||
boolean result = false;
|
||||
if (isRequestIdle())
|
||||
{
|
||||
boolean delayed = _delayedUntilContent;
|
||||
_delayedUntilContent = false;
|
||||
|
||||
boolean result = isRequestIdle();
|
||||
if (result)
|
||||
consumeInput();
|
||||
result = true;
|
||||
}
|
||||
|
||||
getHttpTransport().onStreamTimeout(failure);
|
||||
if (getRequest().getHttpInput().onIdleTimeout(failure))
|
||||
if (getRequest().getHttpInput().onIdleTimeout(failure) || delayed)
|
||||
{
|
||||
consumer.accept(this::handleWithContext);
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ public abstract class AbstractConnection implements Connection
|
|||
{
|
||||
boolean close = true;
|
||||
if (cause instanceof TimeoutException)
|
||||
close = onReadTimeout();
|
||||
close = onReadTimeout(cause);
|
||||
if (close)
|
||||
{
|
||||
if (_endPoint.isOutputShutdown())
|
||||
|
@ -183,9 +183,11 @@ public abstract class AbstractConnection implements Connection
|
|||
|
||||
/**
|
||||
* <p>Callback method invoked when the endpoint failed to be ready to be read after a timeout</p>
|
||||
*
|
||||
* @param timeout the cause of the read timeout
|
||||
* @return true to signal that the endpoint must be closed, false to keep the endpoint open
|
||||
*/
|
||||
protected boolean onReadTimeout()
|
||||
protected boolean onReadTimeout(Throwable timeout)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26,13 +26,15 @@ import java.nio.channels.CancelledKeyException;
|
|||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
|
@ -64,7 +66,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
|
||||
private final Locker _locker = new Locker();
|
||||
private boolean _selecting = false;
|
||||
private final Queue<Runnable> _actions = new ArrayDeque<>();
|
||||
private final Deque<Runnable> _actions = new ArrayDeque<>();
|
||||
private final SelectorManager _selectorManager;
|
||||
private final int _id;
|
||||
private final ExecutionStrategy _strategy;
|
||||
|
@ -244,20 +246,31 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
super.dump(out, indent);
|
||||
Selector selector = _selector;
|
||||
List<String> keys = null;
|
||||
List<Runnable> actions = null;
|
||||
if (selector != null && selector.isOpen())
|
||||
{
|
||||
List<Runnable> actions;
|
||||
DumpKeys dump = new DumpKeys();
|
||||
String actionsAt;
|
||||
try (Locker.Lock lock = _locker.lock())
|
||||
{
|
||||
actionsAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now());
|
||||
actions = new ArrayList<>(_actions);
|
||||
_actions.addFirst(dump);
|
||||
_selecting = false;
|
||||
}
|
||||
List<Object> keys = new ArrayList<>(selector.keys().size());
|
||||
DumpKeys dumpKeys = new DumpKeys(keys);
|
||||
submit(dumpKeys);
|
||||
dumpKeys.await(5, TimeUnit.SECONDS);
|
||||
dump(out, indent, Arrays.asList(new DumpableCollection("keys", keys), new DumpableCollection("actions", actions)));
|
||||
selector.wakeup();
|
||||
keys = dump.get(5, TimeUnit.SECONDS);
|
||||
String keysAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now());
|
||||
if (keys==null)
|
||||
keys = Collections.singletonList("No dump keys retrieved");
|
||||
dumpBeans(out, indent, Arrays.asList(new DumpableCollection("actions @ "+actionsAt, actions),
|
||||
new DumpableCollection("keys @ "+keysAt, keys)));
|
||||
}
|
||||
else
|
||||
{
|
||||
dumpBeans(out, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,13 +508,8 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
|
||||
private class DumpKeys extends Invocable.NonBlocking
|
||||
{
|
||||
private final CountDownLatch latch = new CountDownLatch(1);
|
||||
private final List<Object> _dumps;
|
||||
|
||||
private DumpKeys(List<Object> dumps)
|
||||
{
|
||||
this._dumps = dumps;
|
||||
}
|
||||
private CountDownLatch latch = new CountDownLatch(1);
|
||||
private List<String> keys;
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
|
@ -509,33 +517,37 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
Selector selector = _selector;
|
||||
if (selector != null && selector.isOpen())
|
||||
{
|
||||
Set<SelectionKey> keys = selector.keys();
|
||||
_dumps.add(selector + " keys=" + keys.size());
|
||||
for (SelectionKey key : keys)
|
||||
Set<SelectionKey> selector_keys = selector.keys();
|
||||
List<String> list = new ArrayList<>(selector_keys.size()+1);
|
||||
list.add(selector + " keys=" + selector_keys.size());
|
||||
for (SelectionKey key : selector_keys)
|
||||
{
|
||||
try
|
||||
{
|
||||
_dumps.add(String.format("SelectionKey@%x{i=%d}->%s", key.hashCode(), key.interestOps(), key.attachment()));
|
||||
list.add(String.format("SelectionKey@%x{i=%d}->%s", key.hashCode(), key.interestOps(), key.attachment()));
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
_dumps.add(String.format("SelectionKey@%x[%s]->%s", key.hashCode(), x, key.attachment()));
|
||||
list.add(String.format("SelectionKey@%x[%s]->%s", key.hashCode(), x, key.attachment()));
|
||||
}
|
||||
}
|
||||
keys = list;
|
||||
}
|
||||
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
public boolean await(long timeout, TimeUnit unit)
|
||||
public List<String> get(long timeout, TimeUnit unit)
|
||||
{
|
||||
try
|
||||
{
|
||||
return latch.await(timeout, unit);
|
||||
latch.await(timeout, unit);
|
||||
}
|
||||
catch (InterruptedException x)
|
||||
{
|
||||
return false;
|
||||
LOG.ignore(x);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
import org.eclipse.jetty.util.thread.Invocable;
|
||||
import org.eclipse.jetty.util.thread.Invocable.InvocationType;
|
||||
|
||||
|
||||
/**
|
||||
* A Utility class to help implement {@link EndPoint#write(Callback, ByteBuffer...)} by calling
|
||||
* {@link EndPoint#flush(ByteBuffer...)} until all content is written.
|
||||
|
@ -60,7 +59,7 @@ abstract public class WriteFlusher
|
|||
// 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.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));
|
||||
}
|
||||
|
@ -104,29 +103,30 @@ abstract public class WriteFlusher
|
|||
|
||||
/**
|
||||
* Tries to update the current state to the given new state.
|
||||
*
|
||||
* @param previous the expected current state
|
||||
* @param next the desired new state
|
||||
* @param next 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)
|
||||
private boolean updateState(State previous, State next)
|
||||
{
|
||||
if (!isTransitionAllowed(previous,next))
|
||||
if (!isTransitionAllowed(previous, next))
|
||||
throw new IllegalStateException();
|
||||
|
||||
boolean updated = _state.compareAndSet(previous, next);
|
||||
if (DEBUG)
|
||||
LOG.debug("update {}:{}{}{}", this, previous, updated?"-->":"!->",next);
|
||||
LOG.debug("update {}:{}{}{}", this, previous, updated ? "-->" : "!->", next);
|
||||
return updated;
|
||||
}
|
||||
|
||||
private void fail(PendingState pending)
|
||||
{
|
||||
State current = _state.get();
|
||||
if (current.getType()==StateType.FAILED)
|
||||
if (current.getType() == StateType.FAILED)
|
||||
{
|
||||
FailedState failed=(FailedState)current;
|
||||
if (updateState(failed,__IDLE))
|
||||
FailedState failed = (FailedState)current;
|
||||
if (updateState(failed, __IDLE))
|
||||
{
|
||||
pending.fail(failed.getCause());
|
||||
return;
|
||||
|
@ -138,9 +138,9 @@ abstract public class WriteFlusher
|
|||
private void ignoreFail()
|
||||
{
|
||||
State current = _state.get();
|
||||
while (current.getType()==StateType.FAILED)
|
||||
while (current.getType() == StateType.FAILED)
|
||||
{
|
||||
if (updateState(current,__IDLE))
|
||||
if (updateState(current, __IDLE))
|
||||
return;
|
||||
current = _state.get();
|
||||
}
|
||||
|
@ -209,10 +209,11 @@ abstract public class WriteFlusher
|
|||
private static class FailedState extends State
|
||||
{
|
||||
private final Throwable _cause;
|
||||
|
||||
private FailedState(Throwable cause)
|
||||
{
|
||||
super(StateType.FAILED);
|
||||
_cause=cause;
|
||||
_cause = cause;
|
||||
}
|
||||
|
||||
public Throwable getCause()
|
||||
|
@ -257,7 +258,7 @@ abstract public class WriteFlusher
|
|||
|
||||
protected boolean fail(Throwable cause)
|
||||
{
|
||||
if (_callback!=null)
|
||||
if (_callback != null)
|
||||
{
|
||||
_callback.failed(cause);
|
||||
return true;
|
||||
|
@ -267,7 +268,7 @@ abstract public class WriteFlusher
|
|||
|
||||
protected void complete()
|
||||
{
|
||||
if (_callback!=null)
|
||||
if (_callback != null)
|
||||
_callback.succeeded();
|
||||
}
|
||||
|
||||
|
@ -286,8 +287,8 @@ abstract public class WriteFlusher
|
|||
{
|
||||
State s = _state.get();
|
||||
return (s instanceof PendingState)
|
||||
?((PendingState)s).getCallbackInvocationType()
|
||||
:Invocable.InvocationType.BLOCKING;
|
||||
? ((PendingState)s).getCallbackInvocationType()
|
||||
: Invocable.InvocationType.BLOCKING;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -300,13 +301,13 @@ abstract public class WriteFlusher
|
|||
* 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 <code>PendingState</code> object to preserve the state
|
||||
* If not all buffers can be written in one go it creates a new {@code PendingState} object to preserve the state
|
||||
* and then calls {@link #onIncompleteFlush()}. The remaining buffers will be written in {@link #completeWrite()}.
|
||||
*
|
||||
* If all buffers have been written it calls callback.complete().
|
||||
*
|
||||
* @param callback the callback to call on either failed or complete
|
||||
* @param buffers the buffers to flush to the endpoint
|
||||
* @param buffers the buffers to flush to the endpoint
|
||||
* @throws WritePendingException if unable to write due to prior pending write
|
||||
*/
|
||||
public void write(Callback callback, ByteBuffer... buffers) throws WritePendingException
|
||||
|
@ -314,20 +315,20 @@ abstract public class WriteFlusher
|
|||
if (DEBUG)
|
||||
LOG.debug("write: {} {}", this, BufferUtil.toDetailString(buffers));
|
||||
|
||||
if (!updateState(__IDLE,__WRITING))
|
||||
if (!updateState(__IDLE, __WRITING))
|
||||
throw new WritePendingException();
|
||||
|
||||
try
|
||||
{
|
||||
buffers=flush(buffers);
|
||||
buffers = flush(buffers);
|
||||
|
||||
// if we are incomplete?
|
||||
if (buffers!=null)
|
||||
if (buffers != null)
|
||||
{
|
||||
if (DEBUG)
|
||||
LOG.debug("flushed incomplete");
|
||||
PendingState pending=new PendingState(buffers, callback);
|
||||
if (updateState(__WRITING,pending))
|
||||
PendingState pending = new PendingState(buffers, callback);
|
||||
if (updateState(__WRITING, pending))
|
||||
onIncompleteFlush();
|
||||
else
|
||||
fail(pending);
|
||||
|
@ -335,18 +336,18 @@ abstract public class WriteFlusher
|
|||
}
|
||||
|
||||
// If updateState didn't succeed, we don't care as our buffers have been written
|
||||
if (!updateState(__WRITING,__IDLE))
|
||||
if (!updateState(__WRITING, __IDLE))
|
||||
ignoreFail();
|
||||
if (callback!=null)
|
||||
if (callback != null)
|
||||
callback.succeeded();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (DEBUG)
|
||||
LOG.debug("write exception", e);
|
||||
if (updateState(__WRITING,__IDLE))
|
||||
if (updateState(__WRITING, __IDLE))
|
||||
{
|
||||
if (callback!=null)
|
||||
if (callback != null)
|
||||
callback.failed(e);
|
||||
}
|
||||
else
|
||||
|
@ -354,7 +355,6 @@ abstract public class WriteFlusher
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Complete a write that has not completed and that called {@link #onIncompleteFlush()} to request a call to this
|
||||
* method when a call to {@link EndPoint#flush(ByteBuffer...)} is likely to be able to progress.
|
||||
|
@ -370,27 +370,27 @@ abstract public class WriteFlusher
|
|||
|
||||
State previous = _state.get();
|
||||
|
||||
if (previous.getType()!=StateType.PENDING)
|
||||
if (previous.getType() != StateType.PENDING)
|
||||
return; // failure already handled.
|
||||
|
||||
PendingState pending = (PendingState)previous;
|
||||
if (!updateState(pending,__COMPLETING))
|
||||
if (!updateState(pending, __COMPLETING))
|
||||
return; // failure already handled.
|
||||
|
||||
try
|
||||
{
|
||||
ByteBuffer[] buffers = pending.getBuffers();
|
||||
|
||||
buffers=flush(buffers);
|
||||
buffers = flush(buffers);
|
||||
|
||||
// if we are incomplete?
|
||||
if (buffers!=null)
|
||||
if (buffers != null)
|
||||
{
|
||||
if (DEBUG)
|
||||
LOG.debug("flushed incomplete {}",BufferUtil.toDetailString(buffers));
|
||||
if (buffers!=pending.getBuffers())
|
||||
pending=new PendingState(buffers, pending._callback);
|
||||
if (updateState(__COMPLETING,pending))
|
||||
LOG.debug("flushed incomplete {}", BufferUtil.toDetailString(buffers));
|
||||
if (buffers != pending.getBuffers())
|
||||
pending = new PendingState(buffers, pending._callback);
|
||||
if (updateState(__COMPLETING, pending))
|
||||
onIncompleteFlush();
|
||||
else
|
||||
fail(pending);
|
||||
|
@ -398,7 +398,7 @@ abstract public class WriteFlusher
|
|||
}
|
||||
|
||||
// If updateState didn't succeed, we don't care as our buffers have been written
|
||||
if (!updateState(__COMPLETING,__IDLE))
|
||||
if (!updateState(__COMPLETING, __IDLE))
|
||||
ignoreFail();
|
||||
pending.complete();
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ abstract public class WriteFlusher
|
|||
{
|
||||
if (DEBUG)
|
||||
LOG.debug("completeWrite exception", e);
|
||||
if(updateState(__COMPLETING,__IDLE))
|
||||
if (updateState(__COMPLETING, __IDLE))
|
||||
pending.fail(e);
|
||||
else
|
||||
fail(pending);
|
||||
|
@ -422,59 +422,84 @@ abstract public class WriteFlusher
|
|||
*/
|
||||
protected ByteBuffer[] flush(ByteBuffer[] buffers) throws IOException
|
||||
{
|
||||
boolean progress=true;
|
||||
while(progress && buffers!=null)
|
||||
boolean progress = true;
|
||||
while (progress && buffers != null)
|
||||
{
|
||||
int before=buffers.length==0?0:buffers[0].remaining();
|
||||
boolean flushed=_endPoint.flush(buffers);
|
||||
int r=buffers.length==0?0:buffers[0].remaining();
|
||||
long before = remaining(buffers);
|
||||
boolean flushed = _endPoint.flush(buffers);
|
||||
long after = remaining(buffers);
|
||||
long written = before - after;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Flushed={} {}/{}+{} {}",flushed,before-r,before,buffers.length-1,this);
|
||||
LOG.debug("Flushed={} written={} remaining={} {}", flushed, written, after, this);
|
||||
|
||||
if (written > 0)
|
||||
{
|
||||
Connection connection = _endPoint.getConnection();
|
||||
if (connection instanceof Listener)
|
||||
((Listener)connection).onFlushed(written);
|
||||
}
|
||||
|
||||
if (flushed)
|
||||
return null;
|
||||
|
||||
progress=before!=r;
|
||||
progress = written > 0;
|
||||
|
||||
int not_empty=0;
|
||||
while(r==0)
|
||||
int index = 0;
|
||||
while (true)
|
||||
{
|
||||
if (++not_empty==buffers.length)
|
||||
if (index == buffers.length)
|
||||
{
|
||||
buffers=null;
|
||||
not_empty=0;
|
||||
// All buffers consumed.
|
||||
buffers = null;
|
||||
index = 0;
|
||||
break;
|
||||
}
|
||||
progress=true;
|
||||
r=buffers[not_empty].remaining();
|
||||
else
|
||||
{
|
||||
int remaining = buffers[index].remaining();
|
||||
if (remaining > 0)
|
||||
break;
|
||||
++index;
|
||||
progress = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (not_empty>0)
|
||||
buffers=Arrays.copyOfRange(buffers,not_empty,buffers.length);
|
||||
if (index > 0)
|
||||
buffers = Arrays.copyOfRange(buffers, index, buffers.length);
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("!fully flushed {}",this);
|
||||
LOG.debug("!fully flushed {}", this);
|
||||
|
||||
// If buffers is null, then flush has returned false but has consumed all the data!
|
||||
// This is probably SSL being unable to flush the encrypted buffer, so return EMPTY_BUFFERS
|
||||
// and that will keep this WriteFlusher pending.
|
||||
return buffers==null?EMPTY_BUFFERS:buffers;
|
||||
return buffers == null ? EMPTY_BUFFERS : buffers;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Notify the flusher of a failure
|
||||
private long remaining(ByteBuffer[] buffers)
|
||||
{
|
||||
if (buffers == null)
|
||||
return 0;
|
||||
long result = 0;
|
||||
for (ByteBuffer buffer : buffers)
|
||||
result += buffer.remaining();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the flusher of a failure
|
||||
*
|
||||
* @param cause The cause of the failure
|
||||
* @return true if the flusher passed the failure to a {@link Callback} instance
|
||||
*/
|
||||
public boolean onFail(Throwable 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())
|
||||
State current = _state.get();
|
||||
switch (current.getType())
|
||||
{
|
||||
case IDLE:
|
||||
case FAILED:
|
||||
|
@ -487,7 +512,7 @@ abstract public class WriteFlusher
|
|||
LOG.debug("failed: " + this, cause);
|
||||
|
||||
PendingState pending = (PendingState)current;
|
||||
if (updateState(pending,__IDLE))
|
||||
if (updateState(pending, __IDLE))
|
||||
return pending.fail(cause);
|
||||
break;
|
||||
|
||||
|
@ -495,7 +520,7 @@ abstract public class WriteFlusher
|
|||
if (DEBUG)
|
||||
LOG.debug("failed: " + this, cause);
|
||||
|
||||
if (updateState(current,new FailedState(cause)))
|
||||
if (updateState(current, new FailedState(cause)))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
@ -512,29 +537,9 @@ abstract public class WriteFlusher
|
|||
return _state.get().getType() == StateType.IDLE;
|
||||
}
|
||||
|
||||
public boolean isInProgress()
|
||||
{
|
||||
switch(_state.get().getType())
|
||||
{
|
||||
case WRITING:
|
||||
case PENDING:
|
||||
case COMPLETING:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
State s = _state.get();
|
||||
return String.format("WriteFlusher@%x{%s}->%s", hashCode(), s,s instanceof PendingState?((PendingState)s).getCallback():null);
|
||||
}
|
||||
|
||||
public String toStateString()
|
||||
{
|
||||
switch(_state.get().getType())
|
||||
switch (_state.get().getType())
|
||||
{
|
||||
case WRITING:
|
||||
return "W";
|
||||
|
@ -550,4 +555,33 @@ abstract public class WriteFlusher
|
|||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
State s = _state.get();
|
||||
return String.format("WriteFlusher@%x{%s}->%s", hashCode(), s, s instanceof PendingState ? ((PendingState)s).getCallback() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A listener of {@link WriteFlusher} events.</p>
|
||||
*/
|
||||
public interface Listener
|
||||
{
|
||||
/**
|
||||
* <p>Invoked when a {@link WriteFlusher} flushed bytes in a non-blocking way,
|
||||
* as part of a - possibly larger - write.</p>
|
||||
* <p>This method may be invoked multiple times, for example when writing a large
|
||||
* buffer: a first flush of bytes, then the connection became TCP congested, and
|
||||
* a subsequent flush of bytes when the connection became writable again.</p>
|
||||
* <p>This method is never invoked concurrently, but may be invoked by different
|
||||
* threads, so implementations may not rely on thread-local variables.</p>
|
||||
* <p>Implementations may throw an {@link IOException} to signal that the write
|
||||
* should fail, for example if the implementation enforces a minimum data rate.</p>
|
||||
*
|
||||
* @param bytes the number of bytes flushed
|
||||
* @throws IOException if the write should fail
|
||||
*/
|
||||
void onFlushed(long bytes) throws IOException;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -184,8 +184,9 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
Attributes attributes;
|
||||
|
||||
/**
|
||||
* @param userName
|
||||
* @param credential
|
||||
* @param userName the user name
|
||||
* @param credential the credential
|
||||
* @param attributes the user {@link Attributes}
|
||||
*/
|
||||
public LDAPUserInfo(String userName, Credential credential, Attributes attributes)
|
||||
{
|
||||
|
@ -266,25 +267,21 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
* NOTE: this is not an user authenticated operation
|
||||
*
|
||||
* @param username
|
||||
* @return
|
||||
* @return the {@link Attributes} from the user
|
||||
* @throws LoginException
|
||||
*/
|
||||
private Attributes getUserAttributes(String username) throws LoginException
|
||||
{
|
||||
Attributes attributes = null;
|
||||
|
||||
SearchResult result;
|
||||
try
|
||||
{
|
||||
result = findUser(username);
|
||||
attributes = result.getAttributes();
|
||||
SearchResult result = findUser(username);
|
||||
Attributes attributes = result.getAttributes();
|
||||
return attributes;
|
||||
}
|
||||
catch (NamingException e)
|
||||
{
|
||||
throw new LoginException("Root context binding failure.");
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private String getUserCredentials(Attributes attributes) throws LoginException
|
||||
|
|
|
@ -42,9 +42,9 @@ public class UserInfo
|
|||
|
||||
|
||||
/**
|
||||
* @param userName
|
||||
* @param credential
|
||||
* @param roleNames
|
||||
* @param userName the user name
|
||||
* @param credential the credential
|
||||
* @param roleNames a {@link List} of role name
|
||||
*/
|
||||
public UserInfo (String userName, Credential credential, List<String> roleNames)
|
||||
{
|
||||
|
@ -52,18 +52,15 @@ public class UserInfo
|
|||
_credential = credential;
|
||||
if (roleNames != null)
|
||||
{
|
||||
synchronized (_roleNames)
|
||||
{
|
||||
_roleNames.addAll(roleNames);
|
||||
_rolesLoaded = true;
|
||||
}
|
||||
_roleNames.addAll(roleNames);
|
||||
_rolesLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param userName
|
||||
* @param credential
|
||||
* @param userName the user name
|
||||
* @param credential the credential
|
||||
*/
|
||||
public UserInfo (String userName, Credential credential)
|
||||
{
|
||||
|
@ -76,16 +73,16 @@ public class UserInfo
|
|||
* Should be overridden by subclasses to obtain
|
||||
* role info
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
* @return List of role associated to the user
|
||||
* @throws Exception if the roles cannot be retrieved
|
||||
*/
|
||||
public List<String> doFetchRoles ()
|
||||
public List<String> doFetchRoles()
|
||||
throws Exception
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public void fetchRoles () throws Exception
|
||||
public void fetchRoles() throws Exception
|
||||
{
|
||||
synchronized (_roleNames)
|
||||
{
|
||||
|
|
|
@ -310,7 +310,7 @@ public class JettyRunDistro extends JettyRunMojo
|
|||
* If jetty home does not exist, download it and
|
||||
* unpack to build dir.
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws Exception if jetty distribution cannot be found neither downloaded
|
||||
*/
|
||||
public void configureJettyHome() throws Exception
|
||||
{
|
||||
|
@ -341,7 +341,7 @@ public class JettyRunDistro extends JettyRunMojo
|
|||
* @param version the version of the artifact
|
||||
* @param extension the extension type of the artifact eg "zip", "jar"
|
||||
* @return the artifact from the local or remote repo
|
||||
* @throws ArtifactResolverException
|
||||
* @throws ArtifactResolverException in case of an error while resolving the artifact
|
||||
*/
|
||||
public Artifact resolveArtifact (String groupId, String artifactId, String version, String extension)
|
||||
throws ArtifactResolverException
|
||||
|
@ -363,7 +363,7 @@ public class JettyRunDistro extends JettyRunMojo
|
|||
/**
|
||||
* Create or configure a jetty base.
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws Exception if any error occured while copying files
|
||||
*/
|
||||
public void configureJettyBase() throws Exception
|
||||
{
|
||||
|
@ -372,8 +372,7 @@ public class JettyRunDistro extends JettyRunMojo
|
|||
|
||||
targetBase = new File(target, "jetty-base");
|
||||
Path targetBasePath = targetBase.toPath();
|
||||
if (Files.exists(targetBasePath))
|
||||
IO.delete(targetBase);
|
||||
Files.deleteIfExists(targetBase.toPath());
|
||||
|
||||
targetBase.mkdirs();
|
||||
|
||||
|
@ -483,7 +482,7 @@ public class JettyRunDistro extends JettyRunMojo
|
|||
* Convert webapp config to properties
|
||||
*
|
||||
* @param file the file to place the properties into
|
||||
* @throws Exception
|
||||
* @throws Exception if any I/O exception during generating the properties file
|
||||
*/
|
||||
public void createPropertiesFile (File file)
|
||||
throws Exception
|
||||
|
@ -496,10 +495,9 @@ public class JettyRunDistro extends JettyRunMojo
|
|||
* Make the command to spawn a process to
|
||||
* run jetty from a distro.
|
||||
*
|
||||
* @return
|
||||
* @return the command configured
|
||||
*/
|
||||
public ProcessBuilder configureCommand()
|
||||
throws Exception
|
||||
{
|
||||
List<String> cmd = new ArrayList<>();
|
||||
cmd.add("java");
|
||||
|
|
|
@ -183,7 +183,7 @@ public class ServerSupport
|
|||
if (files == null || files.isEmpty())
|
||||
return server;
|
||||
|
||||
Map<String,Object> lastMap = new HashMap<String,Object>();
|
||||
Map<String,Object> lastMap = new HashMap<>();
|
||||
|
||||
if (server != null)
|
||||
lastMap.put("Server", server);
|
||||
|
@ -231,7 +231,7 @@ public class ServerSupport
|
|||
* @param files the xml configs to apply
|
||||
* @return the Server after application of configs
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws Exception if unable to apply the xml configuration
|
||||
*/
|
||||
public static Server applyXmlConfigurations (Server server, List<File> files)
|
||||
throws Exception
|
||||
|
|
|
@ -240,7 +240,7 @@ public class Starter
|
|||
}
|
||||
|
||||
/**
|
||||
* @param args
|
||||
* @param args Starter arguments
|
||||
*/
|
||||
public static final void main(String[] args)
|
||||
{
|
||||
|
|
|
@ -20,11 +20,13 @@
|
|||
package org.eclipse.jetty.maven.plugin;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -51,7 +53,7 @@ public class WebAppPropertyConverter
|
|||
* @param webApp the webapp to convert
|
||||
* @param propsFile the file to put the properties into
|
||||
* @param contextXml the optional context xml file related to the webApp
|
||||
* @throws Exception
|
||||
* @throws Exception if any I/O exception occurs
|
||||
*/
|
||||
public static void toProperties(JettyWebAppContext webApp, File propsFile, String contextXml)
|
||||
throws Exception
|
||||
|
@ -112,7 +114,7 @@ public class WebAppPropertyConverter
|
|||
|
||||
//web-inf lib
|
||||
List<File> deps = webApp.getWebInfLib();
|
||||
StringBuffer strbuff = new StringBuffer();
|
||||
StringBuilder strbuff = new StringBuilder();
|
||||
if (deps != null)
|
||||
{
|
||||
for (int i=0; i<deps.size(); i++)
|
||||
|
@ -129,7 +131,8 @@ public class WebAppPropertyConverter
|
|||
if (contextXml != null)
|
||||
props.put("context.xml", contextXml);
|
||||
|
||||
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(propsFile)))
|
||||
|
||||
try (BufferedWriter out = Files.newBufferedWriter(propsFile.toPath()))
|
||||
{
|
||||
props.store(out, "properties for forked webapp");
|
||||
}
|
||||
|
@ -143,7 +146,7 @@ public class WebAppPropertyConverter
|
|||
* @param resource the properties file to apply
|
||||
* @param server the Server instance to use
|
||||
* @param jettyProperties jetty properties to use if there is a context xml file to apply
|
||||
* @throws Exception
|
||||
* @throws Exception if any I/O exception occurs
|
||||
*/
|
||||
public static void fromProperties (JettyWebAppContext webApp, String resource, Server server, Map<String,String> jettyProperties)
|
||||
throws Exception
|
||||
|
@ -161,7 +164,7 @@ public class WebAppPropertyConverter
|
|||
* @param propsFile the properties to apply
|
||||
* @param server the Server instance to use if there is a context xml file to apply
|
||||
* @param jettyProperties jetty properties to use if there is a context xml file to apply
|
||||
* @throws Exception
|
||||
* @throws Exception if any I/O exception occurs
|
||||
*/
|
||||
public static void fromProperties (JettyWebAppContext webApp, File propsFile, Server server, Map<String,String> jettyProperties)
|
||||
throws Exception
|
||||
|
@ -175,7 +178,7 @@ public class WebAppPropertyConverter
|
|||
throw new IllegalArgumentException (propsFile.getCanonicalPath()+" does not exist");
|
||||
|
||||
Properties props = new Properties();
|
||||
try (InputStream in = new FileInputStream(propsFile))
|
||||
try (InputStream in = Files.newInputStream(propsFile.toPath()))
|
||||
{
|
||||
props.load(in);
|
||||
}
|
||||
|
@ -248,7 +251,7 @@ public class WebAppPropertyConverter
|
|||
//the pom to override the context xml file, but as the other mojos all
|
||||
//configure a WebAppContext in the pom (the <webApp> element), it is
|
||||
//already configured by the time the context xml file is applied.
|
||||
str = (String)props.getProperty("context.xml");
|
||||
str = props.getProperty("context.xml");
|
||||
if (!StringUtil.isBlank(str))
|
||||
{
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.newResource(str).getURI().toURL());
|
||||
|
@ -275,7 +278,7 @@ public class WebAppPropertyConverter
|
|||
*/
|
||||
private static String toCSV (Resource[] resources)
|
||||
{
|
||||
StringBuffer rb = new StringBuffer();
|
||||
StringBuilder rb = new StringBuilder();
|
||||
|
||||
for (Resource r:resources)
|
||||
{
|
||||
|
|
|
@ -87,7 +87,7 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio
|
|||
|
||||
|
||||
/**
|
||||
* @param sec
|
||||
* @param sec the expiry to use in seconds
|
||||
*/
|
||||
public void setExpirySec (int sec)
|
||||
{
|
||||
|
|
|
@ -126,8 +126,7 @@ public class MongoSessionDataStoreFactory extends AbstractSessionDataStoreFactor
|
|||
|
||||
|
||||
/**
|
||||
* @throws MongoException
|
||||
* @throws UnknownHostException
|
||||
* @throws Exception {@link UnknownHostException} if any issue while resolving MongoDB Host
|
||||
* @see org.eclipse.jetty.server.session.SessionDataStoreFactory#getSessionDataStore(org.eclipse.jetty.server.session.SessionHandler)
|
||||
*/
|
||||
@Override
|
||||
|
|
|
@ -146,7 +146,7 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer
|
|||
|
||||
/**
|
||||
* Check that jsp is on the classpath
|
||||
* @return
|
||||
* @return <code>true</code> if jsp is available in the environment
|
||||
*/
|
||||
public boolean isJspAvailable()
|
||||
{
|
||||
|
@ -195,7 +195,7 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer
|
|||
/**
|
||||
* Find the bundle that contains a jstl implementation class, which assumes that
|
||||
* the jstl taglibs will be inside the same bundle.
|
||||
* @return
|
||||
* @return Bundle contains the jstl implementation class
|
||||
*/
|
||||
public Bundle findJstlBundle ()
|
||||
{
|
||||
|
|
|
@ -120,7 +120,7 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer
|
|||
* Unsupported: the bundle is a jar that embeds more jars.
|
||||
*
|
||||
* @return array of URLs
|
||||
* @throws Exception
|
||||
* @throws Exception In case of errors during resolving TLDs files
|
||||
*/
|
||||
public URL[] getUrlsForBundlesWithTlds(DeploymentManager deployer, BundleFileLocatorHelper locatorHelper) throws Exception
|
||||
{
|
||||
|
|
|
@ -39,7 +39,7 @@ public class WarUrlActivator implements BundleActivator
|
|||
/**
|
||||
* Register the url stream handler factory.
|
||||
*
|
||||
* @param context
|
||||
* @param context the {@link BundleContext} to use
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void start(BundleContext context) throws Exception
|
||||
|
|
|
@ -52,6 +52,7 @@ public class WarURLConnection extends URLConnection
|
|||
* a new temporary file ust to replace the manifest.
|
||||
* @param newmanifest The new manifest
|
||||
* @param rawIn The file input stream or equivalent. not the jar input stream.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public static InputStream substitueManifest(final Manifest newmanifest,
|
||||
final InputStream rawIn) throws IOException
|
||||
|
@ -106,6 +107,7 @@ public class WarURLConnection extends URLConnection
|
|||
* @param url The file url (for example)
|
||||
* @param mf The manifest to use as a replacement to the jar file inside
|
||||
* the file url.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public WarURLConnection(URL url, Manifest mf) throws IOException
|
||||
{
|
||||
|
|
|
@ -33,10 +33,10 @@ public interface TldBundleDiscoverer
|
|||
/**
|
||||
* Find bundles that contain tlds and convert into URL references to their location.
|
||||
*
|
||||
* @param manager
|
||||
* @param fileLocator
|
||||
* @param manager The {@link DeploymentManager} instance to use
|
||||
* @param fileLocator the {@link BundleFileLocatorHelper} instance to use
|
||||
* @return array of URLs representing locations of tld containing bundles
|
||||
* @throws Exception
|
||||
* @throws Exception In case of errors during resolving TLDs files
|
||||
*/
|
||||
URL[] getUrlsForBundlesWithTlds(DeploymentManager manager, BundleFileLocatorHelper fileLocator) throws Exception;
|
||||
|
||||
|
|
|
@ -42,12 +42,12 @@ public class Util
|
|||
/**
|
||||
* Create an osgi filter for the given classname and server name.
|
||||
*
|
||||
* @param bundleContext
|
||||
* @param bundleContext the {@link BundleContext} instance to use
|
||||
* @param classname the class to match on the filter
|
||||
* @param managedServerName the name of the jetty server instance
|
||||
* @return a new filter
|
||||
*
|
||||
* @throws InvalidSyntaxException
|
||||
* @throws InvalidSyntaxException If the filter contains an invalid string that cannot be parsed.
|
||||
*/
|
||||
public static Filter createFilter (BundleContext bundleContext, String classname, String managedServerName) throws InvalidSyntaxException
|
||||
{
|
||||
|
|
|
@ -60,7 +60,7 @@ public abstract class NamingEntry
|
|||
*
|
||||
* @param scope an object representing the scope of the name to be bound into jndi, where null means jvm scope.
|
||||
* @param jndiName the name that will be associated with an object bound into jndi
|
||||
* @throws NamingException
|
||||
* @throws NamingException if jndiName is null
|
||||
*/
|
||||
protected NamingEntry (Object scope, String jndiName)
|
||||
throws NamingException
|
||||
|
|
|
@ -96,8 +96,10 @@ public class QuickStartDescriptorGenerator
|
|||
/**
|
||||
* @param w the source WebAppContext
|
||||
* @param extraXML any extra xml snippet to append
|
||||
* @param originAttribute param value to use for the context param origin attribute
|
||||
* @param generateOrigin <code>true</code> to generate the origin attribute
|
||||
*/
|
||||
public QuickStartDescriptorGenerator (WebAppContext w, String extraXML, String originAttribute, boolean generateOrigin)
|
||||
public QuickStartDescriptorGenerator (WebAppContext w, String extraXML, String originAttribute, boolean generateOrigin)
|
||||
{
|
||||
_webApp = w;
|
||||
_extraXML = extraXML;
|
||||
|
|
|
@ -123,7 +123,7 @@ public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
* @param context the webapp
|
||||
* @param descriptor the xml file to process
|
||||
* @param node the context-param node in the xml file
|
||||
* @throws Exception
|
||||
* @throws Exception if some resources cannot be read
|
||||
*/
|
||||
public void visitContextParam (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
|
||||
throws Exception
|
||||
|
|
|
@ -30,12 +30,12 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* A Connection Listener that limits the number of Connections.
|
||||
* <p>A Connection Listener that limits the number of Connections.</p>
|
||||
* <p>This listener applies a limit to the number of connections, which when
|
||||
* exceeded results in a call to {@link AbstractConnector#setAccepting(boolean)}
|
||||
* to prevent further connections being received. It can be applied to an
|
||||
* entire server or to a specific connector.
|
||||
* <p>
|
||||
* </p>
|
||||
* @see Connection.Listener
|
||||
*/
|
||||
@ManagedObject
|
||||
|
|
|
@ -86,10 +86,10 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Configure to only support the RFC7239 Forwarded header and to
|
||||
* not support any {@code X-Forwarded-} headers. This convenience method
|
||||
* clears all the non RFC headers if passed true and sets them to
|
||||
* the default values (if not already set) if passed false.
|
||||
* @param rfc7239only Configure to only support the RFC7239 Forwarded header and to
|
||||
* not support any {@code X-Forwarded-} headers. This convenience method
|
||||
* clears all the non RFC headers if passed true and sets them to
|
||||
* the default values (if not already set) if passed false.
|
||||
*/
|
||||
public void setForwardedOnly(boolean rfc7239only)
|
||||
{
|
||||
|
|
|
@ -400,6 +400,17 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque
|
|||
return !_delayedForContent;
|
||||
}
|
||||
|
||||
boolean onIdleTimeout(Throwable timeout)
|
||||
{
|
||||
if (_delayedForContent)
|
||||
{
|
||||
_delayedForContent = false;
|
||||
getRequest().getHttpInput().onIdleTimeout(timeout);
|
||||
execute(this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Attempts to perform a HTTP/1.1 upgrade.</p>
|
||||
|
|
|
@ -1249,6 +1249,7 @@ public class HttpChannelState
|
|||
* Called to indicate that more content may be available,
|
||||
* but that a handling thread may need to produce (fill/parse)
|
||||
* it. Typically called by the async read success callback.
|
||||
* @return <code>true</code> if more content may be available
|
||||
*/
|
||||
public boolean onReadPossible()
|
||||
{
|
||||
|
@ -1279,7 +1280,7 @@ public class HttpChannelState
|
|||
/**
|
||||
* Called to signal that a read has read -1.
|
||||
* Will wake if the read was called while in ASYNC_WAIT state
|
||||
* @return true if woken
|
||||
* @return <code>true</code> if woken
|
||||
*/
|
||||
public boolean onReadEof()
|
||||
{
|
||||
|
|
|
@ -66,6 +66,7 @@ public class HttpConfiguration
|
|||
private boolean _persistentConnectionsEnabled = true;
|
||||
private int _maxErrorDispatches = 10;
|
||||
private long _minRequestDataRate;
|
||||
private long _minResponseDataRate;
|
||||
private CookieCompliance _cookieCompliance = CookieCompliance.RFC6265;
|
||||
private boolean _notifyRemoteAsyncErrors = true;
|
||||
|
||||
|
@ -127,6 +128,7 @@ public class HttpConfiguration
|
|||
_persistentConnectionsEnabled=config._persistentConnectionsEnabled;
|
||||
_maxErrorDispatches=config._maxErrorDispatches;
|
||||
_minRequestDataRate=config._minRequestDataRate;
|
||||
_minResponseDataRate=config._minResponseDataRate;
|
||||
_cookieCompliance=config._cookieCompliance;
|
||||
_notifyRemoteAsyncErrors=config._notifyRemoteAsyncErrors;
|
||||
}
|
||||
|
@ -497,6 +499,28 @@ public class HttpConfiguration
|
|||
_minRequestDataRate=bytesPerSecond;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The minimum response data rate in bytes per second; or <=0 for no limit
|
||||
*/
|
||||
@ManagedAttribute("The minimum response content data rate in bytes per second")
|
||||
public long getMinResponseDataRate()
|
||||
{
|
||||
return _minResponseDataRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets an minimum response content data rate.</p>
|
||||
* <p>The value is enforced only approximately - not precisely - due to the fact that
|
||||
* for efficiency reasons buffer writes may be comprised of both response headers and
|
||||
* response content.</p>
|
||||
*
|
||||
* @param bytesPerSecond The minimum response data rate in bytes per second; or <=0 for no limit
|
||||
*/
|
||||
public void setMinResponseDataRate(long bytesPerSecond)
|
||||
{
|
||||
_minResponseDataRate = bytesPerSecond;
|
||||
}
|
||||
|
||||
public CookieCompliance getCookieCompliance()
|
||||
{
|
||||
return _cookieCompliance;
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.eclipse.jetty.io.ByteBufferPool;
|
|||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.WriteFlusher;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.IteratingCallback;
|
||||
|
@ -49,7 +50,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/**
|
||||
* <p>A {@link Connection} that handles the HTTP protocol.</p>
|
||||
*/
|
||||
public class HttpConnection extends AbstractConnection implements Runnable, HttpTransport, Connection.UpgradeFrom
|
||||
public class HttpConnection extends AbstractConnection implements Runnable, HttpTransport, Connection.UpgradeFrom, WriteFlusher.Listener
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpConnection.class);
|
||||
public static final HttpField CONNECTION_CLOSE = new PreEncodedHttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE.asString());
|
||||
|
@ -195,6 +196,14 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlushed(long bytes) throws IOException
|
||||
{
|
||||
// Unfortunately cannot distinguish between header and content
|
||||
// bytes, and for content bytes whether they are chunked or not.
|
||||
_channel.getResponse().getHttpOutput().onFlushed(bytes);
|
||||
}
|
||||
|
||||
void releaseRequestBuffer()
|
||||
{
|
||||
if (_requestBuffer != null && !_requestBuffer.hasRemaining())
|
||||
|
@ -477,6 +486,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onReadTimeout(Throwable timeout)
|
||||
{
|
||||
return _channel.onIdleTimeout(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFillInterestedFailed(Throwable cause)
|
||||
{
|
||||
|
|
|
@ -44,23 +44,27 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/**
|
||||
* {@link HttpInput} provides an implementation of {@link ServletInputStream} for {@link HttpChannel}.
|
||||
* <p>
|
||||
* Content may arrive in patterns such as [content(), content(), messageComplete()] so that this class maintains two states: the content state that tells
|
||||
* whether there is content to consume and the EOF state that tells whether an EOF has arrived. Only once the content has been consumed the content state is
|
||||
* moved to the EOF state.
|
||||
* Content may arrive in patterns such as [content(), content(), messageComplete()]
|
||||
* so that this class maintains two states: the content state that tells
|
||||
* whether there is content to consume and the EOF state that tells whether an EOF has arrived.
|
||||
* Only once the content has been consumed the content state is moved to the EOF state.
|
||||
* </p>
|
||||
*/
|
||||
public class HttpInput extends ServletInputStream implements Runnable
|
||||
{
|
||||
/**
|
||||
* An interceptor for HTTP Request input.
|
||||
* <p>
|
||||
* Unlike inputstream wrappers that can be applied by filters, an interceptor
|
||||
* Unlike InputStream wrappers that can be applied by filters, an interceptor
|
||||
* is entirely transparent and works with async IO APIs.
|
||||
* </p>
|
||||
* <p>
|
||||
* An Interceptor may consume data from the passed content and the interceptor
|
||||
* will continue to be called for the same content until the interceptor returns
|
||||
* null or an empty content. Thus even if the passed content is completely consumed
|
||||
* null or an empty content. Thus even if the passed content is completely consumed
|
||||
* the interceptor will be called with the same content until it can no longer
|
||||
* produce more content.
|
||||
* </p>
|
||||
* @see HttpInput#setInterceptor(Interceptor)
|
||||
* @see HttpInput#addInterceptor(Interceptor)
|
||||
*/
|
||||
|
@ -77,8 +81,8 @@ public class HttpInput extends ServletInputStream implements Runnable
|
|||
|
||||
/**
|
||||
* An {@link Interceptor} that chains two other {@link Interceptor}s together.
|
||||
* The {@link #readFrom(Content)} calls the previous {@link Interceptor}'s
|
||||
* {@link #readFrom(Content)} and then passes any {@link Content} returned
|
||||
* The {@link Interceptor#readFrom(Content)} calls the previous {@link Interceptor}'s
|
||||
* {@link Interceptor#readFrom(Content)} and then passes any {@link Content} returned
|
||||
* to the next {@link Interceptor}.
|
||||
*/
|
||||
public static class ChainedInterceptor implements Interceptor, Destroyable
|
||||
|
@ -282,7 +286,7 @@ public class HttpInput extends ServletInputStream implements Runnable
|
|||
{
|
||||
long minimum_data = minRequestDataRate * TimeUnit.NANOSECONDS.toMillis(period) / TimeUnit.SECONDS.toMillis(1);
|
||||
if (_contentArrived < minimum_data)
|
||||
throw new BadMessageException(HttpStatus.REQUEST_TIMEOUT_408,String.format("Request data rate < %d B/s",minRequestDataRate));
|
||||
throw new BadMessageException(HttpStatus.REQUEST_TIMEOUT_408,String.format("Request content data rate < %d B/s",minRequestDataRate));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,6 +339,7 @@ public class HttpInput extends ServletInputStream implements Runnable
|
|||
/**
|
||||
* Called by channel when asynchronous IO needs to produce more content
|
||||
* @throws IOException
|
||||
* if unable to produce content
|
||||
*/
|
||||
public void asyncReadProduce() throws IOException
|
||||
{
|
||||
|
@ -782,7 +787,8 @@ public class HttpInput extends ServletInputStream implements Runnable
|
|||
{
|
||||
synchronized (_inputQ)
|
||||
{
|
||||
if (_waitingForContent && !isError())
|
||||
boolean neverDispatched = getHttpChannelState().isIdle();
|
||||
if ((_waitingForContent || neverDispatched) && !isError())
|
||||
{
|
||||
x.addSuppressed(new Throwable("HttpInput idle timeout"));
|
||||
_state = new ErrorState(x);
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.InputStream;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritePendingException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
|
@ -122,12 +123,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
private final HttpChannel _channel;
|
||||
private final SharedBlockingCallback _writeBlocker;
|
||||
private Interceptor _interceptor;
|
||||
|
||||
/**
|
||||
* Bytes written via the write API (excludes bytes written via sendContent). Used to autocommit once content length is written.
|
||||
*/
|
||||
private long _written;
|
||||
|
||||
private long _flushed;
|
||||
private long _firstByteTimeStamp = -1;
|
||||
private ByteBuffer _aggregate;
|
||||
private int _bufferSize;
|
||||
private int _commitSize;
|
||||
|
@ -231,6 +229,14 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
|
||||
protected void write(ByteBuffer content, boolean complete, Callback callback)
|
||||
{
|
||||
if (_firstByteTimeStamp == -1)
|
||||
{
|
||||
long minDataRate = getHttpChannel().getHttpConfiguration().getMinResponseDataRate();
|
||||
if (minDataRate > 0)
|
||||
_firstByteTimeStamp = System.nanoTime();
|
||||
else
|
||||
_firstByteTimeStamp = Long.MAX_VALUE;
|
||||
}
|
||||
_interceptor.write(content, complete, callback);
|
||||
}
|
||||
|
||||
|
@ -908,6 +914,30 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
_commitSize = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Invoked when bytes have been flushed to the network.</p>
|
||||
* <p>The number of flushed bytes may be different from the bytes written
|
||||
* by the application if an {@link Interceptor} changed them, for example
|
||||
* by compressing them.</p>
|
||||
*
|
||||
* @param bytes the number of bytes flushed
|
||||
* @throws IOException if the minimum data rate, when set, is not respected
|
||||
* @see org.eclipse.jetty.io.WriteFlusher.Listener
|
||||
*/
|
||||
public void onFlushed(long bytes) throws IOException
|
||||
{
|
||||
if (_firstByteTimeStamp == -1 || _firstByteTimeStamp == Long.MAX_VALUE)
|
||||
return;
|
||||
long minDataRate = getHttpChannel().getHttpConfiguration().getMinResponseDataRate();
|
||||
_flushed += bytes;
|
||||
long elapsed = System.nanoTime() - _firstByteTimeStamp;
|
||||
long minFlushed = minDataRate * TimeUnit.NANOSECONDS.toMillis(elapsed) / TimeUnit.SECONDS.toMillis(1);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Flushed bytes min/actual {}/{}", minFlushed, _flushed);
|
||||
if (_flushed < minFlushed)
|
||||
throw new IOException(String.format("Response content data rate < %d B/s", minDataRate));
|
||||
}
|
||||
|
||||
public void recycle()
|
||||
{
|
||||
_interceptor = _channel;
|
||||
|
@ -920,6 +950,8 @@ public class HttpOutput extends ServletOutputStream implements Runnable
|
|||
_written = 0;
|
||||
_writeListener = null;
|
||||
_onError = null;
|
||||
_firstByteTimeStamp = -1;
|
||||
_flushed = 0;
|
||||
reopen();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
import org.eclipse.jetty.util.JavaVersion;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
@ -370,7 +371,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
String gitHash = Jetty.GIT_HASH;
|
||||
String timestamp = Jetty.BUILD_TIMESTAMP;
|
||||
|
||||
LOG.info("jetty-{}, build timestamp: {}, git hash: {}", getVersion(), timestamp, gitHash);
|
||||
LOG.info("jetty-{}; built: {}; git: {}; jvm {}", getVersion(), timestamp, gitHash, JavaVersion.VERSION);
|
||||
if (!Jetty.STABLE)
|
||||
{
|
||||
LOG.warn("THIS IS NOT A STABLE RELEASE! DO NOT USE IN PRODUCTION!");
|
||||
|
|
|
@ -57,14 +57,18 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
* use all the commons services (eg {@link Executor}, {@link Scheduler}) of the
|
||||
* passed {@link Server} instance, but all services may also be constructor injected
|
||||
* into the connector so that it may operate with dedicated or otherwise shared services.
|
||||
* </p>
|
||||
* <h2>Connection Factories</h2>
|
||||
* <p>
|
||||
* Various convenience constructors are provided to assist with common configurations of
|
||||
* ConnectionFactories, whose generic use is described in {@link AbstractConnector}.
|
||||
* If no connection factories are passed, then the connector will
|
||||
* default to use a {@link HttpConnectionFactory}. If an non null {@link SslContextFactory}
|
||||
* instance is passed, then this used to instantiate a {@link SslConnectionFactory} which is
|
||||
* prepended to the other passed or default factories.
|
||||
* </p>
|
||||
* <h2>Selectors</h2>
|
||||
* <p>
|
||||
* The connector will use the {@link Executor} service to execute a number of Selector Tasks,
|
||||
* which are implemented to each use a NIO {@link Selector} instance to asynchronously
|
||||
* schedule a set of accepted connections. It is the selector thread that will call the
|
||||
|
@ -72,10 +76,12 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
* {@link EndPoint#write(Callback, java.nio.ByteBuffer...)} methods. It is expected
|
||||
* that these callbacks may do some non-blocking IO work, but will always dispatch to the
|
||||
* {@link Executor} service any blocking, long running or application tasks.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default number of selectors is equal to half of the number of processors available to the JVM,
|
||||
* which should allow optimal performance even if all the connections used are performing
|
||||
* significant non-blocking work in the callback tasks.
|
||||
* </p>
|
||||
*/
|
||||
@ManagedObject("HTTP connector using NIO ByteChannels and Selectors")
|
||||
public class ServerConnector extends AbstractNetworkConnector
|
||||
|
@ -281,7 +287,7 @@ public class ServerConnector extends AbstractNetworkConnector
|
|||
* This open method can be called before starting the connector to pass it a ServerSocketChannel
|
||||
* that will be used instead of one returned from {@link #openAcceptChannel()}
|
||||
* @param acceptChannel the channel to use
|
||||
* @throws IOException
|
||||
* @throws IOException if the server channel is not bound
|
||||
*/
|
||||
public void open(ServerSocketChannel acceptChannel) throws IOException
|
||||
{
|
||||
|
@ -311,7 +317,7 @@ public class ServerConnector extends AbstractNetworkConnector
|
|||
/**
|
||||
* Called by {@link #open()} to obtain the accepting channel.
|
||||
* @return ServerSocketChannel used to accept connections.
|
||||
* @throws IOException
|
||||
* @throws IOException if unable to obtain or configure the server channel
|
||||
*/
|
||||
protected ServerSocketChannel openAcceptChannel() throws IOException
|
||||
{
|
||||
|
|
|
@ -152,6 +152,8 @@ public class ErrorHandler extends AbstractHandler
|
|||
* @param baseRequest The base request
|
||||
* @param request The servlet request (may be wrapped)
|
||||
* @param response The response (may be wrapped)
|
||||
* @param code the http error code
|
||||
* @param message the http error message
|
||||
* @throws IOException if the response cannot be generated
|
||||
*/
|
||||
protected void generateAcceptableResponse(Request baseRequest, HttpServletRequest request, HttpServletResponse response, int code, String message)
|
||||
|
@ -230,6 +232,8 @@ public class ErrorHandler extends AbstractHandler
|
|||
* @param baseRequest The base request
|
||||
* @param request The servlet request (may be wrapped)
|
||||
* @param response The response (may be wrapped)
|
||||
* @param code the http error code
|
||||
* @param message the http error message
|
||||
* @param mimeType The mimetype to generate (may be */*or other wildcard)
|
||||
* @throws IOException if a response cannot be generated
|
||||
*/
|
||||
|
|
|
@ -24,7 +24,10 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -148,6 +151,22 @@ public abstract class ScopedHandler extends HandlerWrapper
|
|||
/**
|
||||
* Scope the handler
|
||||
* <p>Derived implementations should call {@link #nextScope(String, Request, HttpServletRequest, HttpServletResponse)}
|
||||
* @param target
|
||||
* The target of the request - either a URI or a name.
|
||||
* @param baseRequest
|
||||
* The original unwrapped request object.
|
||||
* @param request
|
||||
* The request either as the {@link Request} object or a wrapper of that request. The
|
||||
* <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getRequest() getRequest()}</code>
|
||||
* method can be used access the Request object if required.
|
||||
* @param response
|
||||
* The response as the {@link Response} object or a wrapper of that request. The
|
||||
* <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getResponse() getResponse()}</code>
|
||||
* method can be used access the Response object if required.
|
||||
* @throws IOException
|
||||
* if unable to handle the request or response processing
|
||||
* @throws ServletException
|
||||
* if unable to handle the request or response due to underlying servlet issue
|
||||
*/
|
||||
public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
|
@ -158,6 +177,22 @@ public abstract class ScopedHandler extends HandlerWrapper
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Scope the handler
|
||||
* @param target
|
||||
* The target of the request - either a URI or a name.
|
||||
* @param baseRequest
|
||||
* The original unwrapped request object.
|
||||
* @param request
|
||||
* The request either as the {@link Request} object or a wrapper of that request. The
|
||||
* <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getRequest() getRequest()}</code>
|
||||
* method can be used access the Request object if required.
|
||||
* @param response
|
||||
* The response as the {@link Response} object or a wrapper of that request. The
|
||||
* <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getResponse() getResponse()}</code>
|
||||
* method can be used access the Response object if required.
|
||||
* @throws IOException
|
||||
* if unable to handle the request or response processing
|
||||
* @throws ServletException
|
||||
* if unable to handle the request or response due to underlying servlet issue
|
||||
*/
|
||||
public final void nextScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
|
@ -174,6 +209,22 @@ public abstract class ScopedHandler extends HandlerWrapper
|
|||
/**
|
||||
* Do the handler work within the scope.
|
||||
* <p>Derived implementations should call {@link #nextHandle(String, Request, HttpServletRequest, HttpServletResponse)}
|
||||
* @param target
|
||||
* The target of the request - either a URI or a name.
|
||||
* @param baseRequest
|
||||
* The original unwrapped request object.
|
||||
* @param request
|
||||
* The request either as the {@link Request} object or a wrapper of that request. The
|
||||
* <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getRequest() getRequest()}</code>
|
||||
* method can be used access the Request object if required.
|
||||
* @param response
|
||||
* The response as the {@link Response} object or a wrapper of that request. The
|
||||
* <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getResponse() getResponse()}</code>
|
||||
* method can be used access the Response object if required.
|
||||
* @throws IOException
|
||||
* if unable to handle the request or response processing
|
||||
* @throws ServletException
|
||||
* if unable to handle the request or response due to underlying servlet issue
|
||||
*/
|
||||
public abstract void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException;
|
||||
|
@ -181,6 +232,22 @@ public abstract class ScopedHandler extends HandlerWrapper
|
|||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* Do the handler work within the scope.
|
||||
* @param target
|
||||
* The target of the request - either a URI or a name.
|
||||
* @param baseRequest
|
||||
* The original unwrapped request object.
|
||||
* @param request
|
||||
* The request either as the {@link Request} object or a wrapper of that request. The
|
||||
* <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getRequest() getRequest()}</code>
|
||||
* method can be used access the Request object if required.
|
||||
* @param response
|
||||
* The response as the {@link Response} object or a wrapper of that request. The
|
||||
* <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getResponse() getResponse()}</code>
|
||||
* method can be used access the Response object if required.
|
||||
* @throws IOException
|
||||
* if unable to handle the request or response processing
|
||||
* @throws ServletException
|
||||
* if unable to handle the request or response due to underlying servlet issue
|
||||
*/
|
||||
public final void nextHandle(String target, final Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package org.eclipse.jetty.server.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
@ -30,7 +29,6 @@ import org.eclipse.jetty.util.StringUtil;
|
|||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.DumpableCollection;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Locker.Lock;
|
||||
|
@ -177,7 +175,7 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
|||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param handler the {@link SessionHandler} to use
|
||||
*/
|
||||
public AbstractSessionCache (SessionHandler handler)
|
||||
{
|
||||
|
@ -309,7 +307,7 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
|||
* If a session's data cannot be loaded from the store without error, remove
|
||||
* it from the persistent store.
|
||||
*
|
||||
* @param removeUnloadableSessions
|
||||
* @param removeUnloadableSessions if <code>true</code> unloadable sessions will be removed from session store
|
||||
*/
|
||||
@Override
|
||||
public void setRemoveUnloadableSessions(boolean removeUnloadableSessions)
|
||||
|
|
|
@ -61,8 +61,8 @@ public class CachingSessionDataStore extends ContainerLifeCycle implements Sessi
|
|||
|
||||
|
||||
/**
|
||||
* @param cache
|
||||
* @param store
|
||||
* @param cache the front cache to use
|
||||
* @param store the actual store for the the session data
|
||||
*/
|
||||
public CachingSessionDataStore (SessionDataMap cache, SessionDataStore store)
|
||||
{
|
||||
|
|
|
@ -51,7 +51,7 @@ public class DefaultSessionCache extends AbstractSessionCache
|
|||
|
||||
|
||||
/**
|
||||
* @param manager
|
||||
* @param manager The SessionHandler related to this SessionCache
|
||||
*/
|
||||
public DefaultSessionCache (SessionHandler manager)
|
||||
{
|
||||
|
|
|
@ -56,7 +56,7 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory
|
|||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @return the removeUnloadableSessions
|
||||
*/
|
||||
public boolean isRemoveUnloadableSessions()
|
||||
{
|
||||
|
@ -67,7 +67,7 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory
|
|||
|
||||
|
||||
/**
|
||||
* @param removeUnloadableSessions
|
||||
* @param removeUnloadableSessions the removeUnloadableSessions to set
|
||||
*/
|
||||
public void setRemoveUnloadableSessions(boolean removeUnloadableSessions)
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory
|
|||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @return the evictionPolicy
|
||||
*/
|
||||
public int getEvictionPolicy()
|
||||
{
|
||||
|
@ -89,7 +89,7 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory
|
|||
|
||||
|
||||
/**
|
||||
* @param evictionPolicy
|
||||
* @param evictionPolicy the evictionPolicy to set
|
||||
*/
|
||||
public void setEvictionPolicy(int evictionPolicy)
|
||||
{
|
||||
|
@ -100,7 +100,7 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory
|
|||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @return the saveOnInactiveEvict
|
||||
*/
|
||||
public boolean isSaveOnInactiveEvict()
|
||||
{
|
||||
|
@ -111,7 +111,7 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory
|
|||
|
||||
|
||||
/**
|
||||
* @param saveOnInactiveEvict
|
||||
* @param saveOnInactiveEvict the saveOnInactiveEvict to set
|
||||
*/
|
||||
public void setSaveOnInactiveEvict(boolean saveOnInactiveEvict)
|
||||
{
|
||||
|
|
|
@ -107,9 +107,9 @@ public class HouseKeeper extends AbstractLifeCycle
|
|||
* Get a scheduler. First try a common scheduler, failing that
|
||||
* create our own.
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws Exception when the scheduler cannot be started
|
||||
*/
|
||||
protected void findScheduler () throws Exception
|
||||
protected void findScheduler() throws Exception
|
||||
{
|
||||
if (_scheduler == null)
|
||||
{
|
||||
|
@ -133,9 +133,9 @@ public class HouseKeeper extends AbstractLifeCycle
|
|||
|
||||
/**
|
||||
* If scavenging is not scheduled, schedule it.
|
||||
* @throws Exception
|
||||
* @throws Exception if any error during scheduling the scavenging
|
||||
*/
|
||||
protected void startScavenging() throws Exception
|
||||
protected void startScavenging() throws Exception
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -155,7 +155,7 @@ public class HouseKeeper extends AbstractLifeCycle
|
|||
/**
|
||||
* If scavenging is scheduled, stop it.
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws Exception if any error during stopping the scavenging
|
||||
*/
|
||||
protected void stopScavenging() throws Exception
|
||||
{
|
||||
|
@ -195,9 +195,9 @@ public class HouseKeeper extends AbstractLifeCycle
|
|||
/**
|
||||
* Set the period between scavenge cycles
|
||||
* @param sec the interval (in seconds)
|
||||
* @throws Exception
|
||||
* @throws Exception if any error during restarting the scavenging
|
||||
*/
|
||||
public void setIntervalSec (long sec) throws Exception
|
||||
public void setIntervalSec(long sec) throws Exception
|
||||
{
|
||||
if (isStarted() || isStarting())
|
||||
{
|
||||
|
|
|
@ -54,7 +54,7 @@ public class JDBCSessionDataStoreFactory extends AbstractSessionDataStoreFactory
|
|||
|
||||
|
||||
/**
|
||||
* @param adaptor
|
||||
* @param adaptor the {@link DatabaseAdaptor} to set
|
||||
*/
|
||||
public void setDatabaseAdaptor (DatabaseAdaptor adaptor)
|
||||
{
|
||||
|
@ -63,7 +63,7 @@ public class JDBCSessionDataStoreFactory extends AbstractSessionDataStoreFactory
|
|||
|
||||
|
||||
/**
|
||||
* @param schema
|
||||
* @param schema the {@link JDBCSessionDataStoreFactory} to set
|
||||
*/
|
||||
public void setSessionTableSchema (JDBCSessionDataStore.SessionTableSchema schema)
|
||||
{
|
||||
|
|
|
@ -32,7 +32,7 @@ public class NullSessionCache extends AbstractSessionCache
|
|||
{
|
||||
|
||||
/**
|
||||
* @param handler
|
||||
* @param handler The SessionHandler related to this SessionCache
|
||||
*/
|
||||
public NullSessionCache(SessionHandler handler)
|
||||
{
|
||||
|
|
|
@ -297,6 +297,7 @@ public class Session implements SessionHandler.SessionIf
|
|||
* @param name name of the attribute
|
||||
* @param newValue new value of the attribute
|
||||
* @param oldValue previous value of the attribute
|
||||
* @throws IllegalStateException if no session manager can be find
|
||||
*/
|
||||
protected void callSessionAttributeListeners (String name, Object newValue, Object oldValue)
|
||||
{
|
||||
|
@ -915,10 +916,10 @@ public class Session implements SessionHandler.SessionIf
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/** Call HttpSessionAttributeListeners as part of invalidating
|
||||
* a Session.
|
||||
/**
|
||||
* Call HttpSessionAttributeListeners as part of invalidating a Session.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* @throws IllegalStateException if no session manager can be find
|
||||
*/
|
||||
@Deprecated
|
||||
protected void doInvalidate() throws IllegalStateException
|
||||
|
@ -931,7 +932,7 @@ public class Session implements SessionHandler.SessionIf
|
|||
/** Call HttpSessionAttributeListeners as part of invalidating
|
||||
* a Session.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* @throws IllegalStateException if no session manager can be find
|
||||
*/
|
||||
protected void finishInvalidate() throws IllegalStateException
|
||||
{
|
||||
|
|
|
@ -63,7 +63,7 @@ public interface SessionCache extends LifeCycle
|
|||
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param context the {@link SessionContext} to use for this cache
|
||||
*/
|
||||
void initialize(SessionContext context);
|
||||
|
||||
|
@ -76,17 +76,17 @@ public interface SessionCache extends LifeCycle
|
|||
/**
|
||||
* Create an entirely new Session.
|
||||
*
|
||||
* @param request
|
||||
* @param id
|
||||
* @param time
|
||||
* @param maxInactiveMs
|
||||
* @param request the request
|
||||
* @param id the unique id associated to the session
|
||||
* @param time the timestamp of the session creation
|
||||
* @param maxInactiveMs the max inactive time in milliseconds
|
||||
* @return a new Session
|
||||
*/
|
||||
Session newSession (HttpServletRequest request, String id, long time, long maxInactiveMs);
|
||||
|
||||
/**
|
||||
* Re-materialize a Session that has previously existed.
|
||||
* @param data
|
||||
* @param data the data associated with the session
|
||||
* @return a Session object for the data supplied
|
||||
*/
|
||||
Session newSession (SessionData data);
|
||||
|
@ -95,10 +95,10 @@ public interface SessionCache extends LifeCycle
|
|||
/**
|
||||
* Change the id of a Session.
|
||||
*
|
||||
* @param oldId
|
||||
* @param newId
|
||||
* @param oldId the current session id
|
||||
* @param newId the new session id
|
||||
* @return the Session after changing its id
|
||||
* @throws Exception
|
||||
* @throws Exception if any error occurred
|
||||
*/
|
||||
Session renewSessionId (String oldId, String newId) throws Exception;
|
||||
|
||||
|
@ -107,9 +107,9 @@ public interface SessionCache extends LifeCycle
|
|||
* Get an existing Session. If necessary, the cache will load the data for
|
||||
* the session from the configured SessionDataStore.
|
||||
*
|
||||
* @param id
|
||||
* @param id the session id
|
||||
* @return the Session if one exists, null otherwise
|
||||
* @throws Exception
|
||||
* @throws Exception if any error occurred
|
||||
*/
|
||||
Session get(String id) throws Exception;
|
||||
|
||||
|
@ -120,9 +120,9 @@ public interface SessionCache extends LifeCycle
|
|||
* implementations may want to delay writing out Session contents
|
||||
* until the last request exits a Session.
|
||||
*
|
||||
* @param id
|
||||
* @param session
|
||||
* @throws Exception
|
||||
* @param id the session id
|
||||
* @param session the current session object
|
||||
* @throws Exception if any error occurred
|
||||
*/
|
||||
void put(String id, Session session) throws Exception;
|
||||
|
||||
|
@ -131,10 +131,10 @@ public interface SessionCache extends LifeCycle
|
|||
* Check to see if a Session is in the cache. Does NOT consult
|
||||
* the SessionDataStore.
|
||||
*
|
||||
* @param id
|
||||
* @param id the session id
|
||||
* @return true if a Session object matching the id is present
|
||||
* in the cache, false otherwise
|
||||
* @throws Exception
|
||||
* @throws Exception if any error occurred
|
||||
*/
|
||||
boolean contains (String id) throws Exception;
|
||||
|
||||
|
@ -143,9 +143,9 @@ public interface SessionCache extends LifeCycle
|
|||
* Check to see if a session exists: WILL consult the
|
||||
* SessionDataStore.
|
||||
*
|
||||
* @param id
|
||||
* @param id the session id
|
||||
* @return true if the session exists, false otherwise
|
||||
* @throws Exception
|
||||
* @throws Exception if any error occurred
|
||||
*/
|
||||
boolean exists (String id) throws Exception;
|
||||
|
||||
|
@ -154,9 +154,9 @@ public interface SessionCache extends LifeCycle
|
|||
* Remove a Session completely: from both this
|
||||
* cache and the SessionDataStore.
|
||||
*
|
||||
* @param id
|
||||
* @param id the session id
|
||||
* @return the Session that was removed, null otherwise
|
||||
* @throws Exception
|
||||
* @throws Exception if any error occurred
|
||||
*/
|
||||
Session delete (String id) throws Exception;
|
||||
|
||||
|
@ -177,7 +177,7 @@ public interface SessionCache extends LifeCycle
|
|||
* Check a Session to see if it might be appropriate to
|
||||
* evict or expire.
|
||||
*
|
||||
* @param session
|
||||
* @param session the session to check
|
||||
*/
|
||||
void checkInactiveSession(Session session);
|
||||
|
||||
|
@ -185,9 +185,14 @@ public interface SessionCache extends LifeCycle
|
|||
/**
|
||||
* A SessionDataStore that is the authoritative source
|
||||
* of session information.
|
||||
* @param sds
|
||||
* @param sds the {@link SessionDataStore} to use
|
||||
*/
|
||||
void setSessionDataStore(SessionDataStore sds);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the {@link SessionDataStore} used
|
||||
*/
|
||||
SessionDataStore getSessionDataStore();
|
||||
|
||||
|
||||
|
@ -204,15 +209,25 @@ public interface SessionCache extends LifeCycle
|
|||
* be evicted.
|
||||
*/
|
||||
void setEvictionPolicy (int policy);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the eviction policy
|
||||
*/
|
||||
int getEvictionPolicy ();
|
||||
|
||||
/**
|
||||
* Whether or not a a session that is about to be evicted should
|
||||
* be saved before being evicted.
|
||||
*
|
||||
* @param saveOnEvict
|
||||
* @param saveOnEvict <code>true</code> if the session should be saved before being evicted
|
||||
*/
|
||||
void setSaveOnInactiveEviction (boolean saveOnEvict);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <code>true</code> if the session should be saved before being evicted
|
||||
*/
|
||||
boolean isSaveOnInactiveEviction ();
|
||||
|
||||
|
||||
|
@ -221,9 +236,14 @@ public interface SessionCache extends LifeCycle
|
|||
* immediately saved. If false, a session that is created and
|
||||
* invalidated within a single request is never persisted.
|
||||
*
|
||||
* @param saveOnCreate
|
||||
* @param saveOnCreate <code>true</code> to immediately save the newly created session
|
||||
*/
|
||||
void setSaveOnCreate(boolean saveOnCreate);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return if <code>true</code> the newly created session will be saved immediately
|
||||
*/
|
||||
boolean isSaveOnCreate();
|
||||
|
||||
|
||||
|
@ -231,8 +251,13 @@ public interface SessionCache extends LifeCycle
|
|||
* If the data for a session exists but is unreadable,
|
||||
* the SessionCache can instruct the SessionDataStore to delete it.
|
||||
*
|
||||
* @param removeUnloadableSessions
|
||||
* @param removeUnloadableSessions <code>true</code> to delete session which cannot be loaded
|
||||
*/
|
||||
void setRemoveUnloadableSessions(boolean removeUnloadableSessions);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return if <code>true</code> unloadable session will be deleted
|
||||
*/
|
||||
boolean isRemoveUnloadableSessions();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ public interface SessionDataMap extends LifeCycle
|
|||
* be used by one context(/session manager).
|
||||
*
|
||||
* @param context context associated
|
||||
* @throws Exception if unable to initialize the
|
||||
*/
|
||||
void initialize(SessionContext context) throws Exception;
|
||||
|
||||
|
|
|
@ -1006,7 +1006,7 @@ public class SessionHandler extends ScopedHandler
|
|||
|
||||
|
||||
/**
|
||||
* @param cache
|
||||
* @param cache the session store to use
|
||||
*/
|
||||
public void setSessionCache (SessionCache cache)
|
||||
{
|
||||
|
@ -1294,7 +1294,7 @@ public class SessionHandler extends ScopedHandler
|
|||
* configurable amount of time, or the session itself
|
||||
* has passed its expiry.
|
||||
*
|
||||
* @param session
|
||||
* @param session the session
|
||||
*/
|
||||
public void sessionInactivityTimerExpired (Session session)
|
||||
{
|
||||
|
@ -1349,8 +1349,8 @@ public class SessionHandler extends ScopedHandler
|
|||
*
|
||||
* @param id identity of session to check
|
||||
*
|
||||
* @return true if this manager knows about this id
|
||||
* @throws Exception
|
||||
* @return <code>true</code> if this manager knows about this id
|
||||
* @throws Exception if any error occurred
|
||||
*/
|
||||
public boolean isIdInUse(String id) throws Exception
|
||||
{
|
||||
|
|
|
@ -52,14 +52,14 @@ public class UnreadableSessionDataException extends Exception
|
|||
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param contextId
|
||||
* @param t
|
||||
* @param id the session id
|
||||
* @param sessionContext the sessionContext
|
||||
* @param t the cause of the exception
|
||||
*/
|
||||
public UnreadableSessionDataException (String id, SessionContext contextId, Throwable t)
|
||||
public UnreadableSessionDataException (String id, SessionContext sessionContext, Throwable t)
|
||||
{
|
||||
super ("Unreadable session "+id+" for "+contextId, t);
|
||||
_sessionContext = contextId;
|
||||
super ("Unreadable session "+id+" for "+sessionContext, t);
|
||||
_sessionContext = sessionContext;
|
||||
_id = id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -601,7 +601,8 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
|||
long start = System.currentTimeMillis();
|
||||
try
|
||||
{
|
||||
IO.toString(is);
|
||||
String response = IO.toString(is);
|
||||
Assert.assertThat(response,Matchers.is(""));
|
||||
Assert.assertEquals(-1, is.read());
|
||||
}
|
||||
catch(SSLException e)
|
||||
|
@ -629,12 +630,13 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
|||
long start = System.currentTimeMillis();
|
||||
try
|
||||
{
|
||||
IO.toString(is);
|
||||
String response = IO.toString(is);
|
||||
Assert.assertThat(response,Matchers.is(""));
|
||||
Assert.assertEquals(-1, is.read());
|
||||
}
|
||||
catch(SSLException e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -644,6 +646,88 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
|||
|
||||
}
|
||||
|
||||
@Test(timeout=60000)
|
||||
public void testMaxIdleDelayedDispatch() throws Exception
|
||||
{
|
||||
configureServer(new EchoHandler());
|
||||
Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort());
|
||||
client.setSoTimeout(10000);
|
||||
InputStream is=client.getInputStream();
|
||||
Assert.assertFalse(client.isClosed());
|
||||
|
||||
OutputStream os=client.getOutputStream();
|
||||
os.write((
|
||||
"GET / HTTP/1.1\r\n"+
|
||||
"host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+
|
||||
"connection: keep-alive\r\n"+
|
||||
"Content-Length: 20\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n").getBytes("utf-8"));
|
||||
os.flush();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
try
|
||||
{
|
||||
String response = IO.toString(is);
|
||||
Assert.assertThat(response,Matchers.containsString("500"));
|
||||
Assert.assertEquals(-1, is.read());
|
||||
}
|
||||
catch(SSLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
int duration = (int)(System.currentTimeMillis() - start);
|
||||
Assert.assertThat(duration,Matchers.greaterThanOrEqualTo(MAX_IDLE_TIME));
|
||||
Assert.assertThat(duration,Matchers.lessThan(maximumTestRuntime));
|
||||
}
|
||||
|
||||
@Test(timeout=60000)
|
||||
public void testMaxIdleDispatch() throws Exception
|
||||
{
|
||||
configureServer(new EchoHandler());
|
||||
Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort());
|
||||
client.setSoTimeout(10000);
|
||||
InputStream is=client.getInputStream();
|
||||
Assert.assertFalse(client.isClosed());
|
||||
|
||||
OutputStream os=client.getOutputStream();
|
||||
os.write((
|
||||
"GET / HTTP/1.1\r\n"+
|
||||
"host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+
|
||||
"connection: keep-alive\r\n"+
|
||||
"Content-Length: 20\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n"+
|
||||
"1234567890").getBytes("utf-8"));
|
||||
os.flush();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
try
|
||||
{
|
||||
String response = IO.toString(is);
|
||||
Assert.assertThat(response,Matchers.containsString("500"));
|
||||
Assert.assertEquals(-1, is.read());
|
||||
}
|
||||
catch(SSLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
int duration = (int)(System.currentTimeMillis() - start);
|
||||
Assert.assertThat(duration,Matchers.greaterThanOrEqualTo(MAX_IDLE_TIME));
|
||||
Assert.assertThat(duration,Matchers.lessThan(maximumTestRuntime));
|
||||
}
|
||||
|
||||
|
||||
@Test(timeout=60000)
|
||||
public void testMaxIdleWithSlowRequest() throws Exception
|
||||
{
|
||||
|
|
|
@ -833,6 +833,9 @@ public class ServletHandler extends ScopedHandler
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Create a new CachedChain
|
||||
* @param filters the filter chain to be cached as a collection of {@link FilterHolder}
|
||||
* @param servletHolder the servletHolder
|
||||
* @return a new {@link CachedChain} instance
|
||||
*/
|
||||
public CachedChain newCachedChain(List<FilterHolder> filters, ServletHolder servletHolder)
|
||||
{
|
||||
|
@ -1590,7 +1593,7 @@ public class ServletHandler extends ScopedHandler
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param filters list of {@link FilterHolder} objects
|
||||
* @param servletHolder
|
||||
* @param servletHolder the current {@link ServletHolder}
|
||||
*/
|
||||
protected CachedChain(List<FilterHolder> filters, ServletHolder servletHolder)
|
||||
{
|
||||
|
|
|
@ -512,6 +512,9 @@ public class DoSFilter implements Filter
|
|||
|
||||
/**
|
||||
* @deprecated use {@link #onRequestTimeout(HttpServletRequest, HttpServletResponse, Thread)} instead
|
||||
* @param request the current request
|
||||
* @param response the current response
|
||||
* @param thread the handling thread
|
||||
*/
|
||||
@Deprecated
|
||||
protected void closeConnection(HttpServletRequest request, HttpServletResponse response, Thread thread)
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.start</bundle-symbolic-name>
|
||||
<start-jar-file-name>start.jar</start-jar-file-name>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
|
@ -32,9 +31,47 @@
|
|||
<onlyAnalyze>org.eclipse.jetty.start.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<createSourcesJar>true</createSourcesJar>
|
||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||
<shadedClassifierName>shaded</shadedClassifierName>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>org.eclipse.jetty:jetty-util</artifact>
|
||||
<includes>
|
||||
<include>org/eclipse/jetty/util/JavaVersion*</include>
|
||||
<include>org/eclipse/jetty/util/TopologicalSort*</include>
|
||||
</includes>
|
||||
</filter>
|
||||
</filters>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.eclipse.jetty.util</pattern>
|
||||
<shadedPattern>org.eclipse.jetty.start.shaded.util</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2017 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.start;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Java Version Utility class.
|
||||
* <p>Parses java versions to extract a consistent set of version parts</p>
|
||||
*/
|
||||
public class JavaVersion
|
||||
{
|
||||
// Copy of code in jetty-util
|
||||
|
||||
private static final Pattern PRE_JDK9 = Pattern.compile("1\\.(\\d)(\\.(\\d+)(_(\\d+))?)?(-.+)?");
|
||||
// Regexp from JEP 223 (http://openjdk.java.net/jeps/223).
|
||||
private static final Pattern JDK9 = Pattern.compile("(\\d+)(\\.(\\d+))?(\\.(\\d+))?((-.+)?(\\+(\\d+)?(-.+)?)?)");
|
||||
|
||||
public static JavaVersion parse(String version)
|
||||
{
|
||||
if (version.startsWith("1."))
|
||||
return parsePreJDK9(version);
|
||||
return parseJDK9(version);
|
||||
}
|
||||
|
||||
private static JavaVersion parsePreJDK9(String version)
|
||||
{
|
||||
Matcher matcher = PRE_JDK9.matcher(version);
|
||||
if (!matcher.matches())
|
||||
throw new IllegalArgumentException("Invalid Java version " + version);
|
||||
int major = 1;
|
||||
int minor = Integer.parseInt(matcher.group(1));
|
||||
String microGroup = matcher.group(3);
|
||||
int micro = microGroup == null || microGroup.isEmpty() ? 0 : Integer.parseInt(microGroup);
|
||||
String updateGroup = matcher.group(5);
|
||||
int update = updateGroup == null || updateGroup.isEmpty() ? 0 : Integer.parseInt(updateGroup);
|
||||
String suffix = matcher.group(6);
|
||||
return new JavaVersion(version, minor, major, minor, micro, update, suffix);
|
||||
}
|
||||
|
||||
private static JavaVersion parseJDK9(String version)
|
||||
{
|
||||
Matcher matcher = JDK9.matcher(version);
|
||||
if (!matcher.matches())
|
||||
throw new IllegalArgumentException("Invalid Java version " + version);
|
||||
int major = Integer.parseInt(matcher.group(1));
|
||||
String minorGroup = matcher.group(3);
|
||||
int minor = minorGroup == null || minorGroup.isEmpty() ? 0 : Integer.parseInt(minorGroup);
|
||||
String microGroup = matcher.group(5);
|
||||
int micro = microGroup == null || microGroup.isEmpty() ? 0 : Integer.parseInt(microGroup);
|
||||
String suffix = matcher.group(6);
|
||||
return new JavaVersion(version, major, major, minor, micro, 0, suffix);
|
||||
}
|
||||
|
||||
private final String version;
|
||||
private final int platform;
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int micro;
|
||||
private final int update;
|
||||
private final String suffix;
|
||||
|
||||
private JavaVersion(String version, int platform, int major, int minor, int micro, int update, String suffix)
|
||||
{
|
||||
this.version = version;
|
||||
this.platform = platform;
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.micro = micro;
|
||||
this.update = update;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the string from which this JavaVersion was created
|
||||
*/
|
||||
public String getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the Java Platform version, such as {@code 8} for JDK 1.8.0_92 and {@code 9} for JDK 9.2.4.</p>
|
||||
*
|
||||
* @return the Java Platform version
|
||||
*/
|
||||
public int getPlatform()
|
||||
{
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the major number version, such as {@code 1} for JDK 1.8.0_92 and {@code 9} for JDK 9.2.4.</p>
|
||||
*
|
||||
* @return the major number version
|
||||
*/
|
||||
public int getMajor()
|
||||
{
|
||||
return major;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the minor number version, such as {@code 8} for JDK 1.8.0_92 and {@code 2} for JDK 9.2.4.</p>
|
||||
*
|
||||
* @return the minor number version
|
||||
*/
|
||||
public int getMinor()
|
||||
{
|
||||
return minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the micro number version, such as {@code 0} for JDK 1.8.0_92 and {@code 4} for JDK 9.2.4.</p>
|
||||
*
|
||||
* @return the micro number version
|
||||
*/
|
||||
public int getMicro()
|
||||
{
|
||||
return micro;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the update number version, such as {@code 92} for JDK 1.8.0_92 and {@code 0} for JDK 9.2.4.</p>
|
||||
*
|
||||
* @return the update number version
|
||||
*/
|
||||
public int getUpdate()
|
||||
{
|
||||
return update;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the remaining string after the version numbers, such as {@code -internal} for
|
||||
* JDK 1.8.0_92-internal and {@code -ea} for JDK 9-ea, or {@code +13} for JDK 9.2.4+13.</p>
|
||||
*
|
||||
* @return the remaining string after the version numbers
|
||||
*/
|
||||
public String getSuffix()
|
||||
{
|
||||
return suffix;
|
||||
}
|
||||
}
|
|
@ -37,6 +37,8 @@ import java.util.function.Consumer;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.util.TopologicalSort;
|
||||
|
||||
/**
|
||||
* Access for all modules declared, as well as what is enabled.
|
||||
*/
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.eclipse.jetty.start.Props.Prop;
|
|||
import org.eclipse.jetty.start.config.ConfigSource;
|
||||
import org.eclipse.jetty.start.config.ConfigSources;
|
||||
import org.eclipse.jetty.start.config.DirConfigSource;
|
||||
import org.eclipse.jetty.util.JavaVersion;
|
||||
|
||||
/**
|
||||
* The Arguments required to start Jetty.
|
||||
|
|
|
@ -1,204 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2017 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.start;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Topological sort a list or array.
|
||||
* <p>A Topological sort is used when you have a partial ordering expressed as
|
||||
* dependencies between elements (also often represented as edges in a directed
|
||||
* acyclic graph). A Topological sort should not be used when you have a total
|
||||
* ordering expressed as a {@link Comparator} over the items. The algorithm has
|
||||
* the additional characteristic that dependency sets are sorted by the original
|
||||
* list order so that order is preserved when possible.</p>
|
||||
* <p>
|
||||
* The sort algorithm works by recursively visiting every item, once and
|
||||
* only once. On each visit, the items dependencies are first visited and then the
|
||||
* item is added to the sorted list. Thus the algorithm ensures that dependency
|
||||
* items are always added before dependent items.</p>
|
||||
*
|
||||
* @param <T> The type to be sorted. It must be able to be added to a {@link HashSet}
|
||||
*/
|
||||
public class TopologicalSort<T>
|
||||
{
|
||||
private final Map<T,Set<T>> _dependencies = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Add a dependency to be considered in the sort.
|
||||
* @param dependent The dependent item will be sorted after all its dependencies
|
||||
* @param dependency The dependency item, will be sorted before its dependent item
|
||||
*/
|
||||
public void addDependency(T dependent, T dependency)
|
||||
{
|
||||
Set<T> set = _dependencies.get(dependent);
|
||||
if (set==null)
|
||||
{
|
||||
set=new HashSet<>();
|
||||
_dependencies.put(dependent,set);
|
||||
}
|
||||
set.add(dependency);
|
||||
}
|
||||
|
||||
/** Sort the passed array according to dependencies previously set with
|
||||
* {@link #addDependency(Object, Object)}. Where possible, ordering will be
|
||||
* preserved if no dependency
|
||||
* @param array The array to be sorted.
|
||||
*/
|
||||
public void sort(T[] array)
|
||||
{
|
||||
List<T> sorted = new ArrayList<>();
|
||||
Set<T> visited = new HashSet<>();
|
||||
Comparator<T> comparator = new InitialOrderComparator<>(array);
|
||||
|
||||
// Visit all items in the array
|
||||
for (T t : array)
|
||||
visit(t,visited,sorted,comparator);
|
||||
|
||||
sorted.toArray(array);
|
||||
}
|
||||
|
||||
/** Sort the passed list according to dependencies previously set with
|
||||
* {@link #addDependency(Object, Object)}. Where possible, ordering will be
|
||||
* preserved if no dependency
|
||||
* @param list The list to be sorted.
|
||||
*/
|
||||
public void sort(Collection<T> list)
|
||||
{
|
||||
List<T> sorted = new ArrayList<>();
|
||||
Set<T> visited = new HashSet<>();
|
||||
Comparator<T> comparator = new InitialOrderComparator<>(list);
|
||||
|
||||
// Visit all items in the list
|
||||
for (T t : list)
|
||||
visit(t,visited,sorted,comparator);
|
||||
|
||||
list.clear();
|
||||
list.addAll(sorted);
|
||||
}
|
||||
|
||||
/** Visit an item to be sorted.
|
||||
* @param item The item to be visited
|
||||
* @param visited The Set of items already visited
|
||||
* @param sorted The list to sort items into
|
||||
* @param comparator A comparator used to sort dependencies.
|
||||
*/
|
||||
private void visit(T item, Set<T> visited, List<T> sorted,Comparator<T> comparator)
|
||||
{
|
||||
// If the item has not been visited
|
||||
if(!visited.contains(item))
|
||||
{
|
||||
// We are visiting it now, so add it to the visited set
|
||||
visited.add(item);
|
||||
|
||||
// Lookup the items dependencies
|
||||
Set<T> dependencies = _dependencies.get(item);
|
||||
if (dependencies!=null)
|
||||
{
|
||||
// Sort the dependencies
|
||||
SortedSet<T> ordered_deps = new TreeSet<>(comparator);
|
||||
ordered_deps.addAll(dependencies);
|
||||
|
||||
// recursively visit each dependency
|
||||
try
|
||||
{
|
||||
for (T d:ordered_deps)
|
||||
visit(d,visited,sorted,comparator);
|
||||
}
|
||||
catch (CyclicException e)
|
||||
{
|
||||
throw new CyclicException(item,e);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have visited all our dependencies, they and their
|
||||
// dependencies will have been added to the sorted list. So we can
|
||||
// now add the current item and it will be after its dependencies
|
||||
sorted.add(item);
|
||||
}
|
||||
else if (!sorted.contains(item))
|
||||
// If we have already visited an item, but it has not yet been put in the
|
||||
// sorted list, then we must be in a cycle!
|
||||
throw new CyclicException(item);
|
||||
}
|
||||
|
||||
|
||||
/** A comparator that is used to sort dependencies in the order they
|
||||
* were in the original list. This ensures that dependencies are visited
|
||||
* in the original order and no needless reordering takes place.
|
||||
* @param <T>
|
||||
*/
|
||||
private static class InitialOrderComparator<T> implements Comparator<T>
|
||||
{
|
||||
private final Map<T,Integer> _indexes = new HashMap<>();
|
||||
InitialOrderComparator(T[] initial)
|
||||
{
|
||||
int i=0;
|
||||
for (T t : initial)
|
||||
_indexes.put(t,i++);
|
||||
}
|
||||
|
||||
InitialOrderComparator(Collection<T> initial)
|
||||
{
|
||||
int i=0;
|
||||
for (T t : initial)
|
||||
_indexes.put(t,i++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(T o1, T o2)
|
||||
{
|
||||
Integer i1=_indexes.get(o1);
|
||||
Integer i2=_indexes.get(o2);
|
||||
if (i1==null || i2==null || i1.equals(o2))
|
||||
return 0;
|
||||
if (i1<i2)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "TopologicalSort "+_dependencies;
|
||||
}
|
||||
|
||||
private static class CyclicException extends IllegalStateException
|
||||
{
|
||||
CyclicException(Object item)
|
||||
{
|
||||
super("cyclic at "+item);
|
||||
}
|
||||
|
||||
CyclicException(Object item,CyclicException e)
|
||||
{
|
||||
super("cyclic at "+item,e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,55 +27,103 @@ import java.util.regex.Pattern;
|
|||
*/
|
||||
public class JavaVersion
|
||||
{
|
||||
|
||||
/**
|
||||
* Context attribute that can be set to target a different version of the jvm than the current runtime.
|
||||
* Acceptable values should correspond to those returned by JavaVersion.getPlatform().
|
||||
*/
|
||||
public static final String JAVA_TARGET_PLATFORM = "org.eclipse.jetty.javaTargetPlatform";
|
||||
|
||||
// Copy of version in jetty-start
|
||||
/** Regex for Java version numbers */
|
||||
private static final String VNUM = "(?<VNUM>[1-9][0-9]*(?:(?:\\.0)*\\.[0-9]+)*)";
|
||||
private static final String UPDATE = "(?:(?<UNDERSCORE>_)(?<UPDATE>[0-9]+))?";
|
||||
private static final String PRE = "(?:-(?<PRE>[a-zA-Z0-9]+))?";
|
||||
private static final String BUILD = "(?:(?<PLUS>\\+)(?<BUILD>[0-9]+))?";
|
||||
private static final String OPT = "(?:-(?<OPT>[-a-zA-Z0-9.]+))?";
|
||||
|
||||
private static final Pattern PRE_JDK9 = Pattern.compile("1\\.(\\d)(\\.(\\d+)(_(\\d+))?)?(-.+)?");
|
||||
// Regexp from JEP 223 (http://openjdk.java.net/jeps/223).
|
||||
private static final Pattern JDK9 = Pattern.compile("(\\d+)(\\.(\\d+))?(\\.(\\d+))?((-.+)?(\\+(\\d+)?(-.+)?)?)");
|
||||
private static final String VSTR_FORMAT = VNUM + UPDATE + PRE + BUILD + OPT;
|
||||
|
||||
public static final JavaVersion VERSION = parse(System.getProperty("java.version"));
|
||||
static final Pattern VSTR_PATTERN = Pattern.compile(VSTR_FORMAT);
|
||||
|
||||
public static JavaVersion parse(String version)
|
||||
public static final JavaVersion VERSION = parse(System.getProperty("java.runtime.version",System.getProperty("java.version")));
|
||||
|
||||
public static JavaVersion parse(String v)
|
||||
{
|
||||
if (version.startsWith("1."))
|
||||
return parsePreJDK9(version);
|
||||
return parseJDK9(version);
|
||||
Matcher m = VSTR_PATTERN.matcher(v);
|
||||
if (!m.matches())
|
||||
throw new IllegalArgumentException("Invalid version string: '" + v + "'");
|
||||
|
||||
// $VNUM is a dot-separated list of integers of arbitrary length
|
||||
String[] split = m.group("VNUM").split("\\.");
|
||||
int[] version = new int[split.length];
|
||||
for (int i = 0; i < split.length; i++)
|
||||
version[i] = Integer.parseInt(split[i]);
|
||||
|
||||
if (m.group("UNDERSCORE")!=null)
|
||||
{
|
||||
return new JavaVersion(
|
||||
v,
|
||||
(version[0]>=9 || version.length==1)?version[0]:version[1],
|
||||
version[0],
|
||||
version.length>1?version[1]:0,
|
||||
version.length>2?version[2]:0,
|
||||
Integer.parseInt(m.group("UPDATE")),
|
||||
suffix(version,m.group("PRE"),m.group("OPT"))
|
||||
);
|
||||
}
|
||||
|
||||
if (m.group("PLUS")!=null)
|
||||
{
|
||||
return new JavaVersion(
|
||||
v,
|
||||
(version[0]>=9 || version.length==1)?version[0]:version[1],
|
||||
version[0],
|
||||
version.length>1?version[1]:0,
|
||||
version.length>2?version[2]:0,
|
||||
Integer.parseInt(m.group("BUILD")),
|
||||
suffix(version,m.group("PRE"),m.group("OPT"))
|
||||
);
|
||||
}
|
||||
|
||||
return new JavaVersion(
|
||||
v,
|
||||
(version[0]>=9 || version.length==1)?version[0]:version[1],
|
||||
version[0],
|
||||
version.length>1?version[1]:0,
|
||||
version.length>2?version[2]:0,
|
||||
0,
|
||||
suffix(version,m.group("PRE"),m.group("OPT"))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private static JavaVersion parsePreJDK9(String version)
|
||||
private static String suffix(int[] version, String pre, String opt)
|
||||
{
|
||||
Matcher matcher = PRE_JDK9.matcher(version);
|
||||
if (!matcher.matches())
|
||||
throw new IllegalArgumentException("Invalid Java version " + version);
|
||||
int major = 1;
|
||||
int minor = Integer.parseInt(matcher.group(1));
|
||||
String microGroup = matcher.group(3);
|
||||
int micro = microGroup == null || microGroup.isEmpty() ? 0 : Integer.parseInt(microGroup);
|
||||
String updateGroup = matcher.group(5);
|
||||
int update = updateGroup == null || updateGroup.isEmpty() ? 0 : Integer.parseInt(updateGroup);
|
||||
String suffix = matcher.group(6);
|
||||
return new JavaVersion(version, minor, major, minor, micro, update, suffix);
|
||||
}
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (int i=3;i<version.length;i++)
|
||||
{
|
||||
if (i>3)
|
||||
buf.append(".");
|
||||
buf.append(version[i]);
|
||||
}
|
||||
|
||||
private static JavaVersion parseJDK9(String version)
|
||||
{
|
||||
Matcher matcher = JDK9.matcher(version);
|
||||
if (!matcher.matches())
|
||||
throw new IllegalArgumentException("Invalid Java version " + version);
|
||||
int major = Integer.parseInt(matcher.group(1));
|
||||
String minorGroup = matcher.group(3);
|
||||
int minor = minorGroup == null || minorGroup.isEmpty() ? 0 : Integer.parseInt(minorGroup);
|
||||
String microGroup = matcher.group(5);
|
||||
int micro = microGroup == null || microGroup.isEmpty() ? 0 : Integer.parseInt(microGroup);
|
||||
String suffix = matcher.group(6);
|
||||
return new JavaVersion(version, major, major, minor, micro, 0, suffix);
|
||||
if (pre!=null)
|
||||
{
|
||||
if (buf.length()>0)
|
||||
buf.append('-');
|
||||
buf.append(pre);
|
||||
}
|
||||
|
||||
if (opt!=null)
|
||||
{
|
||||
if (buf.length()>0)
|
||||
buf.append('-');
|
||||
buf.append(opt);
|
||||
}
|
||||
|
||||
if (buf.length()==0)
|
||||
return null;
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private final String version;
|
||||
|
@ -136,7 +184,7 @@ public class JavaVersion
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the micro number version, such as {@code 0} for JDK 1.8.0_92 and {@code 4} for JDK 9.2.4.</p>
|
||||
* <p>Returns the micro number version (aka security number), such as {@code 0} for JDK 1.8.0_92 and {@code 4} for JDK 9.2.4.</p>
|
||||
*
|
||||
* @return the micro number version
|
||||
*/
|
||||
|
|
|
@ -56,7 +56,10 @@ public class Jetty
|
|||
LOG.ignore( e );
|
||||
}
|
||||
|
||||
GIT_HASH = __buildProperties.getProperty( "buildNumber", "unknown" );
|
||||
String git_hash = __buildProperties.getProperty( "buildNumber", "unknown" );
|
||||
if (git_hash.startsWith("${"))
|
||||
git_hash = "unknown";
|
||||
GIT_HASH = git_hash;
|
||||
System.setProperty( "jetty.git.hash" , GIT_HASH );
|
||||
BUILD_TIMESTAMP = formatTimestamp( __buildProperties.getProperty( "timestamp", "unknown" ));
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ public class MultiReleaseJarFile implements Closeable
|
|||
/**
|
||||
* Construct a multi release jar file for the current JVM version, ignoring directories.
|
||||
* @param file The file to open
|
||||
* @throws IOException if the jar file cannot be read
|
||||
*/
|
||||
public MultiReleaseJarFile(File file) throws IOException
|
||||
{
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
//
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
|
@ -29,9 +28,6 @@ import java.util.Set;
|
|||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
|
||||
|
||||
/**
|
||||
* Topological sort a list or array.
|
||||
|
@ -49,7 +45,7 @@ import org.eclipse.jetty.util.component.Dumpable;
|
|||
*
|
||||
* @param <T> The type to be sorted. It must be able to be added to a {@link HashSet}
|
||||
*/
|
||||
public class TopologicalSort<T> implements Dumpable
|
||||
public class TopologicalSort<T>
|
||||
{
|
||||
private final Map<T,Set<T>> _dependencies = new HashMap<>();
|
||||
|
||||
|
@ -185,7 +181,6 @@ public class TopologicalSort<T> implements Dumpable
|
|||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -194,19 +189,6 @@ public class TopologicalSort<T> implements Dumpable
|
|||
return "TopologicalSort "+_dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dump()
|
||||
{
|
||||
return ContainerLifeCycle.dump(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
out.append(String.format("TopologicalSort@%x%n",hashCode()));
|
||||
ContainerLifeCycle.dump(out, indent,_dependencies.entrySet());
|
||||
}
|
||||
|
||||
private static class CyclicException extends IllegalStateException
|
||||
{
|
||||
CyclicException(Object item)
|
||||
|
|
|
@ -21,9 +21,6 @@ package org.eclipse.jetty.util.component;
|
|||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
|
||||
public class DumpableCollection implements Dumpable
|
||||
{
|
||||
private final String _name;
|
||||
|
@ -44,7 +41,7 @@ public class DumpableCollection implements Dumpable
|
|||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
out.append(_name).append("\n");
|
||||
out.append(_name).append(System.lineSeparator());
|
||||
if (_collection!=null)
|
||||
ContainerLifeCycle.dump(out,indent,_collection);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ public class Locker
|
|||
|
||||
/**
|
||||
* @deprecated use {@link #lock()} instead
|
||||
* @return the lock to unlock
|
||||
*/
|
||||
@Deprecated
|
||||
public Lock lockIfNotHeld()
|
||||
|
|
|
@ -89,8 +89,9 @@ public class ReservedThreadExecutor extends AbstractLifeCycle implements Executo
|
|||
/**
|
||||
* @param executor The executor to use to obtain threads
|
||||
* @param capacity The number of threads to preallocate. If less than 0 then capacity
|
||||
* is calculated based on a heuristic from the number of available processors and
|
||||
* thread pool size.
|
||||
* is calculated based on a heuristic from the number of available processors and
|
||||
* thread pool size.
|
||||
* @param owner the owner of the instance. Only used for debugging purpose withing the {@link #toString()} method
|
||||
*/
|
||||
public ReservedThreadExecutor(Executor executor,int capacity, Object owner)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2017 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.util;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for LazyList utility class.
|
||||
*/
|
||||
public class JavaVersionTest
|
||||
{
|
||||
@Test
|
||||
public void test9()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("9.0.1");
|
||||
assertThat(version.getPlatform(),is(9));
|
||||
assertThat(version.getMajor(),is(9));
|
||||
assertThat(version.getMinor(),is(0));
|
||||
assertThat(version.getMicro(),is(1));
|
||||
assertThat(version.getUpdate(),is(0));
|
||||
assertThat(version.getSuffix(),nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test9nano()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("9.0.1.3");
|
||||
assertThat(version.getPlatform(),is(9));
|
||||
assertThat(version.getMajor(),is(9));
|
||||
assertThat(version.getMinor(),is(0));
|
||||
assertThat(version.getMicro(),is(1));
|
||||
assertThat(version.getUpdate(),is(0));
|
||||
assertThat(version.getSuffix(),is("3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test9build()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("9.0.1+11");
|
||||
assertThat(version.getPlatform(),is(9));
|
||||
assertThat(version.getMajor(),is(9));
|
||||
assertThat(version.getMinor(),is(0));
|
||||
assertThat(version.getMicro(),is(1));
|
||||
assertThat(version.getUpdate(),is(11));
|
||||
assertThat(version.getSuffix(),nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test9all()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("9.0.1-ea+11-b01");
|
||||
assertThat(version.getPlatform(),is(9));
|
||||
assertThat(version.getMajor(),is(9));
|
||||
assertThat(version.getMinor(),is(0));
|
||||
assertThat(version.getMicro(),is(1));
|
||||
assertThat(version.getUpdate(),is(11));
|
||||
assertThat(version.getSuffix(),is("ea-b01"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test9yuck()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("9.0.1.2.3-ea+11-b01");
|
||||
assertThat(version.getPlatform(),is(9));
|
||||
assertThat(version.getMajor(),is(9));
|
||||
assertThat(version.getMinor(),is(0));
|
||||
assertThat(version.getMicro(),is(1));
|
||||
assertThat(version.getUpdate(),is(11));
|
||||
assertThat(version.getSuffix(),is("2.3-ea-b01"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test10ea()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("10-ea");
|
||||
assertThat(version.getPlatform(),is(10));
|
||||
assertThat(version.getMajor(),is(10));
|
||||
assertThat(version.getMinor(),is(0));
|
||||
assertThat(version.getMicro(),is(0));
|
||||
assertThat(version.getUpdate(),is(0));
|
||||
assertThat(version.getSuffix(),is("ea"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test8()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("1.8.0_152");
|
||||
assertThat(version.getPlatform(),is(8));
|
||||
assertThat(version.getMajor(),is(1));
|
||||
assertThat(version.getMinor(),is(8));
|
||||
assertThat(version.getMicro(),is(0));
|
||||
assertThat(version.getUpdate(),is(152));
|
||||
assertThat(version.getSuffix(),nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test8ea()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("1.8.1_03-ea");
|
||||
assertThat(version.getPlatform(),is(8));
|
||||
assertThat(version.getMajor(),is(1));
|
||||
assertThat(version.getMinor(),is(8));
|
||||
assertThat(version.getMicro(),is(1));
|
||||
assertThat(version.getUpdate(),is(3));
|
||||
assertThat(version.getSuffix(),is("ea"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3eaBuild()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("1.3.1_05-ea-b01");
|
||||
assertThat(version.getPlatform(),is(3));
|
||||
assertThat(version.getMajor(),is(1));
|
||||
assertThat(version.getMinor(),is(3));
|
||||
assertThat(version.getMicro(),is(1));
|
||||
assertThat(version.getUpdate(),is(5));
|
||||
assertThat(version.getSuffix(),is("ea-b01"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUbuntu()
|
||||
{
|
||||
JavaVersion version = JavaVersion.parse("9-Ubuntu+0-9b181-4");
|
||||
assertThat(version.getPlatform(),is(9));
|
||||
assertThat(version.getMajor(),is(9));
|
||||
assertThat(version.getMinor(),is(0));
|
||||
assertThat(version.getMicro(),is(0));
|
||||
assertThat(version.getUpdate(),is(0));
|
||||
assertThat(version.getSuffix(),is("Ubuntu-9b181-4"));
|
||||
}
|
||||
}
|
|
@ -113,7 +113,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
* @param context the context for the scan
|
||||
* @param jars the jars to scan
|
||||
* @param useCaches if true, the scanned info is cached
|
||||
* @throws Exception
|
||||
* @throws Exception if unable to scan the jars
|
||||
*/
|
||||
public void scanJars (final WebAppContext context, Collection<Resource> jars, boolean useCaches)
|
||||
throws Exception
|
||||
|
|
|
@ -177,7 +177,7 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
* look at the java.class.path, and the jdk.module.path.
|
||||
*
|
||||
* @param context the WebAppContext being deployed
|
||||
* @throws Exception
|
||||
* @throws Exception if unable to apply optional filtering on the container's classpath
|
||||
*/
|
||||
public void findAndFilterContainerPaths (final WebAppContext context)
|
||||
throws Exception
|
||||
|
@ -287,7 +287,7 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
* all jars are considered selected.
|
||||
*
|
||||
* @param context the WebAppContext being deployed
|
||||
* @throws Exception
|
||||
* @throws Exception if unable to find the jars or apply filtering
|
||||
*/
|
||||
public void findAndFilterWebAppPaths (WebAppContext context)
|
||||
throws Exception
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
|||
/**
|
||||
* Client {@link ContainerProvider} implementation.
|
||||
* <p>
|
||||
* <p>
|
||||
* Created by a {@link java.util.ServiceLoader} call in the
|
||||
* {@link javax.websocket.ContainerProvider#getWebSocketContainer()} call.
|
||||
* </p>
|
||||
|
@ -79,7 +78,6 @@ public class JettyClientContainerProvider extends ContainerProvider
|
|||
* find and return the {@code javax.websocket.server.ServerContainer} from the
|
||||
* active {@code javax.servlet.ServletContext}.
|
||||
* <p>
|
||||
* <p>
|
||||
* This will only work if the call to {@link ContainerProvider#getWebSocketContainer()}
|
||||
* occurs within a thread being processed by the Servlet container.
|
||||
* </p>
|
||||
|
|
|
@ -70,7 +70,7 @@ public interface IJsrMethod
|
|||
/**
|
||||
* The message decoder class to use.
|
||||
*
|
||||
* @param decoderClass
|
||||
* @param decoderClass the {@link Decoder} implementation to use
|
||||
*/
|
||||
void setMessageDecoder(Class<? extends Decoder> decoderClass);
|
||||
|
||||
|
|
|
@ -80,6 +80,8 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
|
|||
|
||||
/**
|
||||
* @deprecated use {@code ServerContainer(NativeWebSocketConfiguration, HttpClient)} instead
|
||||
* @param configuration the {@link NativeWebSocketConfiguration} to use
|
||||
* @param executor not used
|
||||
*/
|
||||
@Deprecated
|
||||
public ServerContainer(NativeWebSocketConfiguration configuration, Executor executor)
|
||||
|
@ -87,6 +89,11 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
|
|||
this(configuration, (HttpClient) null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param configuration the {@link NativeWebSocketConfiguration} to use
|
||||
* @param httpClient the {@link HttpClient} instance to use
|
||||
*/
|
||||
public ServerContainer(NativeWebSocketConfiguration configuration, HttpClient httpClient)
|
||||
{
|
||||
super(configuration.getFactory(), httpClient);
|
||||
|
|
|
@ -132,6 +132,9 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
|
|||
|
||||
/**
|
||||
* Embedded Jetty approach for non-bytecode scanning.
|
||||
* @param context the {@link ServletContextHandler} to use
|
||||
* @return a configured {@link ServerContainer} instance
|
||||
* @throws ServletException if the {@link WebSocketUpgradeFilter} cannot be configured
|
||||
*/
|
||||
public static ServerContainer configureContext(ServletContextHandler context) throws ServletException
|
||||
{
|
||||
|
@ -170,6 +173,10 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
|
|||
|
||||
/**
|
||||
* @deprecated use {@link #configureContext(ServletContextHandler)} instead
|
||||
* @param context not used
|
||||
* @param jettyContext the {@link ServletContextHandler} to use
|
||||
* @return a configured {@link ServerContainer} instance
|
||||
* @throws ServletException if the {@link WebSocketUpgradeFilter} cannot be configured
|
||||
*/
|
||||
@Deprecated
|
||||
public static ServerContainer configureContext(ServletContext context, ServletContextHandler jettyContext) throws ServletException
|
||||
|
|
|
@ -265,6 +265,8 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
* the EventDriver Factory to use
|
||||
* @param sessionFactory
|
||||
* the SessionFactory to use
|
||||
* @param httpClient
|
||||
* the httpClient to use
|
||||
*/
|
||||
public WebSocketClient(final WebSocketContainerScope scope, EventDriverFactory eventDriverFactory, SessionFactory sessionFactory, HttpClient httpClient)
|
||||
{
|
||||
|
@ -462,6 +464,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
|
||||
/**
|
||||
* @deprecated not used, no replacement
|
||||
* @return a {@link RandomMasker} instance
|
||||
*/
|
||||
@Deprecated
|
||||
public Masker getMasker()
|
||||
|
@ -634,6 +637,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
|
||||
/**
|
||||
* @deprecated not used, configure threading in HttpClient instead
|
||||
* @param daemon do nothing
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDaemon(boolean daemon)
|
||||
|
@ -654,6 +658,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
|
||||
/**
|
||||
* @deprecated not used, no replacement
|
||||
* @param masker do nothing
|
||||
*/
|
||||
@Deprecated
|
||||
public void setMasker(Masker masker)
|
||||
|
|
|
@ -364,6 +364,7 @@ public class WebSocketUpgradeRequest extends HttpRequest implements CompleteList
|
|||
* <p>
|
||||
* Maintained for Backward compatibility and also for JSR356 WebSocket ClientContainer use.
|
||||
*
|
||||
* @param wsClient the WebSocketClient that this request uses
|
||||
* @param httpClient the HttpClient that this request uses
|
||||
* @param request the ClientUpgradeRequest (backward compat) to base this request from
|
||||
*/
|
||||
|
@ -376,6 +377,7 @@ public class WebSocketUpgradeRequest extends HttpRequest implements CompleteList
|
|||
/**
|
||||
* Initiating a WebSocket Upgrade using HTTP/1.1
|
||||
*
|
||||
* @param wsClient the WebSocketClient that this request uses
|
||||
* @param httpClient the HttpClient that this request uses
|
||||
* @param localEndpoint the local endpoint (following Jetty WebSocket Client API rules) to use for incoming
|
||||
* WebSocket events
|
||||
|
|
|
@ -18,14 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
@ -78,6 +70,14 @@ import org.junit.Ignore;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class ClientCloseTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ClientCloseTest.class);
|
||||
|
@ -147,7 +147,7 @@ public class ClientCloseTest
|
|||
@Override
|
||||
public void onWebSocketError(Throwable cause)
|
||||
{
|
||||
LOG.warn("onWebSocketError",cause);
|
||||
LOG.debug("onWebSocketError",cause);
|
||||
assertThat("Unique Error Event", error.compareAndSet(null, cause), is(true));
|
||||
errorLatch.countDown();
|
||||
}
|
||||
|
@ -526,8 +526,7 @@ public class ClientCloseTest
|
|||
|
||||
// client idle timeout triggers close event on client ws-endpoint
|
||||
assertThat("OnError Latch", clientSocket.errorLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat("OnError", clientSocket.error.get(), instanceOf(SocketTimeoutException.class));
|
||||
assertThat("OnError", clientSocket.error.get().getMessage(), containsString("Timeout on Read"));
|
||||
assertThat("OnError", clientSocket.error.get(), instanceOf(TimeoutException.class));
|
||||
}
|
||||
|
||||
@Test(timeout = 5000L)
|
||||
|
|
|
@ -175,6 +175,8 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
|
|||
|
||||
/**
|
||||
* Aborts the active session abruptly.
|
||||
* @param statusCode the status code
|
||||
* @param reason the raw reason code
|
||||
*/
|
||||
public void abort(int statusCode, String reason)
|
||||
{
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.eclipse.jetty.websocket.common.io;
|
|||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -450,9 +449,10 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
|
||||
/**
|
||||
* Event for no activity on connection (read or write)
|
||||
* @return true to signal that the endpoint must be closed, false to keep the endpoint open
|
||||
*/
|
||||
@Override
|
||||
protected boolean onReadTimeout()
|
||||
protected boolean onReadTimeout(Throwable timeout)
|
||||
{
|
||||
IOState state = getIOState();
|
||||
ConnectionState cstate = state.getConnectionState();
|
||||
|
@ -470,7 +470,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
|
||||
try
|
||||
{
|
||||
notifyError(new SocketTimeoutException("Timeout on Read"));
|
||||
notifyError(timeout);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue