Merge remote-tracking branch 'origin/master' into session-refactor
This commit is contained in:
commit
bf2a1fa29e
33
VERSION.txt
33
VERSION.txt
|
@ -1,4 +1,35 @@
|
|||
jetty-9.3.3-SNAPSHOT
|
||||
jetty-9.3.4-SNAPSHOT
|
||||
|
||||
jetty-9.3.3.v20150827 - 27 August 2015
|
||||
+ 470311 Introduce a proxy-protocol module.
|
||||
+ 471055 Restore legacy/experimental WebSocket extensions (deflate-frame)
|
||||
+ 472411 PathResource.checkAliasPath() typo
|
||||
+ 473321 Overriding SSL context KeyStoreType requires explicit override of
|
||||
TrustStoreType
|
||||
+ 474025 SslContextFactory does not work with JCEKS Keystore
|
||||
+ 474068 Update WebSocket Extension for permessage-deflate draft-22
|
||||
+ 474319 Reintroduce blocking connect().
|
||||
+ 474321 Allow synchronous address resolution.
|
||||
+ 474344 apache-jstl includes test dependencies
|
||||
+ 474358 DefaultServlet bad Content-Type on compressed content
|
||||
+ 474361 Handle JVM version extensions like -internal
|
||||
+ 474453 Tiny buffers (under 7 bytes) fail to compress in permessage-deflate
|
||||
+ 474454 Backport permessage-deflate from Jetty 9.3.x to 9.2.x
|
||||
+ 474455 Enable permessage-deflate WebSocket extension
|
||||
+ 474558 Debug log ServletContainerInitializer @HandlesTypes contents
|
||||
+ 474617 AsyncListener.onError not called for errors
|
||||
+ 474618 AsyncListener.onComplete not called when error occurs
|
||||
+ 474634 AsyncListener.onError() handling.
|
||||
+ 474685 GzipHandler configuration supports csv paths and mimetypes.
|
||||
+ 474888 HttpClient JMX support.
|
||||
+ 474936 WebSocketSessions are not always cleaned out from openSessions
|
||||
+ 474961 Close input stream for classes in AnnotationParser after scanning
|
||||
+ 475195 SNI matching fails when keystore does not contain wild certificates.
|
||||
+ 475483 Starting Jetty with [exec] should use properties file.
|
||||
+ 475546 ClosedChannelException when connecting to HTTPS over HTTP proxy with
|
||||
CONNECT.
|
||||
+ 475605 Add support for multi-homed destinations.
|
||||
+ 475927 SecureRequestCustomizer fails to match host.
|
||||
|
||||
jetty-9.3.2.v20150730 - 30 July 2015
|
||||
+ 470351 Fixed SNI matching of wildcard certificates
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>apache-jsp</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>apache-jstl</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>example-async-rest</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.example-async-rest</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>example-async-rest</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.example-async-rest</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.examples</groupId>
|
||||
<artifactId>examples-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.examples</groupId>
|
||||
<artifactId>examples-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>org.eclipse.jetty.examples</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-alpn-client</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-alpn-server</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-alpn-parent</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-ant</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cdi-core</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cdi-full-servlet</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cdi-servlet</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cdi-websocket</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
<artifactId>jetty-cdi-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-cdi-webapp</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -21,9 +21,9 @@ package org.eclipse.jetty.client;
|
|||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingDeque;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
@ -44,15 +44,15 @@ import org.eclipse.jetty.util.thread.Sweeper;
|
|||
@ManagedObject("The connection pool")
|
||||
public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
||||
{
|
||||
protected static final Logger LOG = Log.getLogger(ConnectionPool.class);
|
||||
private static final Logger LOG = Log.getLogger(ConnectionPool.class);
|
||||
|
||||
private final AtomicInteger connectionCount = new AtomicInteger();
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final Destination destination;
|
||||
private final int maxConnections;
|
||||
private final Callback requester;
|
||||
private final BlockingDeque<Connection> idleConnections;
|
||||
private final BlockingQueue<Connection> activeConnections;
|
||||
private final Deque<Connection> idleConnections;
|
||||
private final Queue<Connection> activeConnections;
|
||||
|
||||
public ConnectionPool(Destination destination, int maxConnections, Callback requester)
|
||||
{
|
||||
|
@ -81,12 +81,12 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
return activeConnections.size();
|
||||
}
|
||||
|
||||
public BlockingQueue<Connection> getIdleConnections()
|
||||
public Queue<Connection> getIdleConnections()
|
||||
{
|
||||
return idleConnections;
|
||||
}
|
||||
|
||||
public BlockingQueue<Connection> getActiveConnections()
|
||||
public Queue<Connection> getActiveConnections()
|
||||
{
|
||||
return activeConnections;
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
|
||||
idleCreated(connection);
|
||||
|
||||
requester.succeeded();
|
||||
proceed();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -150,11 +150,15 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
}
|
||||
}
|
||||
|
||||
protected void proceed()
|
||||
{
|
||||
requester.succeeded();
|
||||
}
|
||||
|
||||
protected void idleCreated(Connection connection)
|
||||
{
|
||||
boolean idle;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
// Use "cold" new connections as last.
|
||||
|
@ -162,7 +166,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
|
||||
idle(connection, idle);
|
||||
|
@ -172,8 +176,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
{
|
||||
boolean acquired;
|
||||
Connection connection;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
connection = idleConnections.pollFirst();
|
||||
|
@ -183,7 +186,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
|
||||
if (acquired)
|
||||
|
@ -209,24 +212,28 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
public boolean release(Connection connection)
|
||||
{
|
||||
boolean idle;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
if (!activeConnections.remove(connection))
|
||||
return false;
|
||||
// Make sure we use "hot" connections first.
|
||||
idle = idleConnections.offerFirst(connection);
|
||||
idle = offerIdle(connection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
|
||||
released(connection);
|
||||
return idle(connection, idle);
|
||||
}
|
||||
|
||||
protected boolean offerIdle(Connection connection)
|
||||
{
|
||||
return idleConnections.offerFirst(connection);
|
||||
}
|
||||
|
||||
protected boolean idle(Connection connection, boolean idle)
|
||||
{
|
||||
if (idle)
|
||||
|
@ -249,11 +256,15 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
}
|
||||
|
||||
public boolean remove(Connection connection)
|
||||
{
|
||||
return remove(connection, false);
|
||||
}
|
||||
|
||||
protected boolean remove(Connection connection, boolean force)
|
||||
{
|
||||
boolean activeRemoved;
|
||||
boolean idleRemoved;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
activeRemoved = activeConnections.remove(connection);
|
||||
|
@ -261,12 +272,12 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
|
||||
if (activeRemoved)
|
||||
released(connection);
|
||||
boolean removed = activeRemoved || idleRemoved;
|
||||
boolean removed = activeRemoved || idleRemoved || force;
|
||||
if (removed)
|
||||
{
|
||||
int pooled = connectionCount.decrementAndGet();
|
||||
|
@ -278,29 +289,27 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
|
||||
public boolean isActive(Connection connection)
|
||||
{
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
return activeConnections.contains(connection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isIdle(Connection connection)
|
||||
{
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
return idleConnections.contains(connection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,8 +322,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
{
|
||||
List<Connection> idles = new ArrayList<>();
|
||||
List<Connection> actives = new ArrayList<>();
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
idles.addAll(idleConnections);
|
||||
|
@ -324,7 +332,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
|
||||
connectionCount.set(0);
|
||||
|
@ -348,8 +356,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
{
|
||||
List<Connection> actives = new ArrayList<>();
|
||||
List<Connection> idles = new ArrayList<>();
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
actives.addAll(activeConnections);
|
||||
|
@ -357,7 +364,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
|
||||
ContainerLifeCycle.dumpObject(out, this);
|
||||
|
@ -368,8 +375,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
public boolean sweep()
|
||||
{
|
||||
List<Sweeper.Sweepable> toSweep = new ArrayList<>();
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
for (Connection connection : getActiveConnections())
|
||||
|
@ -380,7 +386,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
|
||||
for (Sweeper.Sweepable candidate : toSweep)
|
||||
|
@ -400,13 +406,22 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
return false;
|
||||
}
|
||||
|
||||
protected void lock()
|
||||
{
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
protected void unlock()
|
||||
{
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
int activeSize;
|
||||
int idleSize;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
lock();
|
||||
try
|
||||
{
|
||||
activeSize = activeConnections.size();
|
||||
|
@ -414,7 +429,7 @@ public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
|
|||
}
|
||||
finally
|
||||
{
|
||||
lock.unlock();
|
||||
unlock();
|
||||
}
|
||||
|
||||
return String.format("%s[c=%d/%d,a=%d,i=%d]",
|
||||
|
|
|
@ -22,9 +22,13 @@ import org.eclipse.jetty.client.api.Connection;
|
|||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.LeakDetector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class LeakTrackingConnectionPool extends ConnectionPool
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(LeakTrackingConnectionPool.class);
|
||||
|
||||
private final LeakDetector<Connection> leakDetector = new LeakDetector<Connection>()
|
||||
{
|
||||
@Override
|
||||
|
|
|
@ -71,9 +71,7 @@ public abstract class PoolingHttpDestination<C extends Connection> extends HttpD
|
|||
{
|
||||
if (getHttpExchanges().isEmpty())
|
||||
return;
|
||||
C connection = acquire();
|
||||
if (connection != null)
|
||||
process(connection);
|
||||
process();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -82,6 +80,13 @@ public abstract class PoolingHttpDestination<C extends Connection> extends HttpD
|
|||
return (C)connectionPool.acquire();
|
||||
}
|
||||
|
||||
private void process()
|
||||
{
|
||||
C connection = acquire();
|
||||
if (connection != null)
|
||||
process(connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Processes a new connection making it idle or active depending on whether requests are waiting to be sent.</p>
|
||||
* <p>A new connection is created when a request needs to be executed; it is possible that the request that
|
||||
|
@ -137,18 +142,21 @@ public abstract class PoolingHttpDestination<C extends Connection> extends HttpD
|
|||
@SuppressWarnings("unchecked")
|
||||
C connection = (C)c;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} released", connection);
|
||||
LOG.debug("Released {}", connection);
|
||||
HttpClient client = getHttpClient();
|
||||
if (client.isRunning())
|
||||
{
|
||||
if (connectionPool.isActive(connection))
|
||||
{
|
||||
process(connection);
|
||||
if (connectionPool.release(connection))
|
||||
send();
|
||||
else
|
||||
connection.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} explicit", connection);
|
||||
LOG.debug("Released explicit {}", connection);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -184,9 +192,7 @@ public abstract class PoolingHttpDestination<C extends Connection> extends HttpD
|
|||
// We need to execute queued requests even if this connection failed.
|
||||
// We may create a connection that is not needed, but it will eventually
|
||||
// idle timeout, so no worries.
|
||||
C newConnection = acquire();
|
||||
if (newConnection != null)
|
||||
process(newConnection);
|
||||
process();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2015 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.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.client.api.Connection;
|
||||
import org.eclipse.jetty.client.api.Destination;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
/**
|
||||
* <p>A {@link ConnectionPool} that validates connections before
|
||||
* making them available for use.</p>
|
||||
* <p>Connections that have just been opened are not validated.
|
||||
* Connections that are {@link #release(Connection) released} will
|
||||
* be validated.</p>
|
||||
* <p>Validation by reading from the EndPoint is not reliable,
|
||||
* since the TCP FIN may arrive just after the validation read.</p>
|
||||
* <p>This class validates connections by putting them in a
|
||||
* "quarantine" for a configurable timeout, where they cannot
|
||||
* be used to send requests. When the timeout expires, the
|
||||
* quarantined connection is made idle and therefore available
|
||||
* to send requests.</p>
|
||||
* <p>The existing HttpClient mechanism to detect server closes
|
||||
* will trigger and close quarantined connections, before they
|
||||
* are made idle (and reusable) again.</p>
|
||||
* <p>There still is a small chance that the timeout expires,
|
||||
* the connection is made idle and available again, it is used
|
||||
* to send a request exactly when the server decides to close.
|
||||
* This case is however unavoidable and may be mitigated by
|
||||
* tuning the idle timeout of the servers to be larger than
|
||||
* that of the client.</p>
|
||||
*/
|
||||
public class ValidatingConnectionPool extends ConnectionPool
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ValidatingConnectionPool.class);
|
||||
|
||||
private final Scheduler scheduler;
|
||||
private final long timeout;
|
||||
private final Map<Connection, Holder> quarantine;
|
||||
|
||||
public ValidatingConnectionPool(Destination destination, int maxConnections, Callback requester, Scheduler scheduler, long timeout)
|
||||
{
|
||||
super(destination, maxConnections, requester);
|
||||
this.scheduler = scheduler;
|
||||
this.timeout = timeout;
|
||||
this.quarantine = new HashMap<>(maxConnections);
|
||||
}
|
||||
|
||||
@ManagedAttribute(value = "The number of validating connections", readonly = true)
|
||||
public int getValidatingConnectionCount()
|
||||
{
|
||||
return quarantine.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(Connection connection)
|
||||
{
|
||||
lock();
|
||||
try
|
||||
{
|
||||
if (!getActiveConnections().remove(connection))
|
||||
return false;
|
||||
Holder holder = new Holder(connection);
|
||||
holder.task = scheduler.schedule(holder, timeout, TimeUnit.MILLISECONDS);
|
||||
quarantine.put(connection, holder);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Validating for {}ms {}", timeout, connection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
released(connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Connection connection)
|
||||
{
|
||||
Holder holder;
|
||||
lock();
|
||||
try
|
||||
{
|
||||
holder = quarantine.remove(connection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
if (holder == null)
|
||||
return super.remove(connection);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Removed while validating {}", connection);
|
||||
|
||||
boolean cancelled = holder.cancel();
|
||||
if (cancelled)
|
||||
return remove(connection, true);
|
||||
|
||||
return super.remove(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
super.dump(out, indent);
|
||||
ContainerLifeCycle.dump(out, indent, quarantine.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
int size;
|
||||
lock();
|
||||
try
|
||||
{
|
||||
size = quarantine.size();
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
return String.format("%s[v=%d]", super.toString(), size);
|
||||
}
|
||||
|
||||
private class Holder implements Runnable
|
||||
{
|
||||
private final long timestamp = System.nanoTime();
|
||||
private final AtomicBoolean latch = new AtomicBoolean();
|
||||
private final Connection connection;
|
||||
public Scheduler.Task task;
|
||||
|
||||
public Holder(Connection connection)
|
||||
{
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (latch.compareAndSet(false, true))
|
||||
{
|
||||
boolean idle;
|
||||
lock();
|
||||
try
|
||||
{
|
||||
quarantine.remove(connection);
|
||||
idle = offerIdle(connection);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Validated {}", connection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
if (idle(connection, idle))
|
||||
proceed();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean cancel()
|
||||
{
|
||||
if (latch.compareAndSet(false, true))
|
||||
{
|
||||
task.cancel();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[validationLeft=%dms]",
|
||||
connection,
|
||||
timeout - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - timestamp)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -98,7 +98,7 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
|
|||
protected boolean onReadTimeout()
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} idle timeout", this);
|
||||
LOG.debug("Idle timeout {}", this);
|
||||
close(new TimeoutException());
|
||||
return false;
|
||||
}
|
||||
|
@ -141,10 +141,10 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
|
|||
getHttpDestination().close(this);
|
||||
getEndPoint().shutdownOutput();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} oshut", this);
|
||||
LOG.debug("Shutdown {}", this);
|
||||
getEndPoint().close();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} closed", this);
|
||||
LOG.debug("Closed {}", this);
|
||||
|
||||
abort(failure);
|
||||
}
|
||||
|
@ -166,10 +166,8 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
|
|||
{
|
||||
if (!closed.get())
|
||||
return false;
|
||||
|
||||
if (sweeps.incrementAndGet() < 4)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.client;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.NetworkConnector;
|
||||
|
@ -84,10 +85,15 @@ public abstract class AbstractHttpClientServerTest
|
|||
}
|
||||
|
||||
protected void startClient() throws Exception
|
||||
{
|
||||
startClient(new HttpClientTransportOverHTTP(1));
|
||||
}
|
||||
|
||||
protected void startClient(HttpClientTransport transport) throws Exception
|
||||
{
|
||||
QueuedThreadPool clientThreads = new QueuedThreadPool();
|
||||
clientThreads.setName("client");
|
||||
client = new HttpClient(sslContextFactory);
|
||||
client = new HttpClient(transport, sslContextFactory);
|
||||
client.setExecutor(clientThreads);
|
||||
client.start();
|
||||
}
|
||||
|
|
|
@ -881,9 +881,16 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
|||
@Test
|
||||
public void testConnectHostWithMultipleAddresses() throws Exception
|
||||
{
|
||||
// Likely that the DNS for google.com returns multiple addresses.
|
||||
String host = "google.com";
|
||||
Assume.assumeTrue(InetAddress.getAllByName(host).length > 1);
|
||||
try
|
||||
{
|
||||
// Likely that the DNS for google.com returns multiple addresses.
|
||||
Assume.assumeTrue(InetAddress.getAllByName(host).length > 1);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
Assume.assumeNoException(x);
|
||||
}
|
||||
|
||||
startClient();
|
||||
client.setFollowRedirects(false); // Avoid redirects from 80 to 443.
|
||||
|
|
|
@ -21,7 +21,7 @@ package org.eclipse.jetty.client;
|
|||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -71,10 +71,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
ConnectionPool connectionPool = destination.getConnectionPool();
|
||||
|
||||
final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
|
||||
final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
|
@ -132,10 +132,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
ConnectionPool connectionPool = destination.getConnectionPool();
|
||||
|
||||
final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
|
||||
final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
final CountDownLatch beginLatch = new CountDownLatch(1);
|
||||
|
@ -183,10 +183,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
ConnectionPool connectionPool = destination.getConnectionPool();
|
||||
|
||||
final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
|
||||
final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
final CountDownLatch successLatch = new CountDownLatch(3);
|
||||
|
@ -243,10 +243,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
ConnectionPool connectionPool = destination.getConnectionPool();
|
||||
|
||||
final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
|
||||
final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
final long delay = 1000;
|
||||
|
@ -316,10 +316,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
ConnectionPool connectionPool = destination.getConnectionPool();
|
||||
|
||||
final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
|
||||
final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
server.stop();
|
||||
|
@ -369,10 +369,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
ConnectionPool connectionPool = destination.getConnectionPool();
|
||||
|
||||
final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
|
||||
final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
@ -419,10 +419,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
ConnectionPool connectionPool = destination.getConnectionPool();
|
||||
|
||||
final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
|
||||
final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
Log.getLogger(HttpConnection.class).info("Expecting java.lang.IllegalStateException: HttpParser{s=CLOSED,...");
|
||||
|
@ -449,7 +449,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
|
||||
server.stop();
|
||||
}
|
||||
finally
|
||||
|
@ -469,10 +469,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
ConnectionPool connectionPool = destination.getConnectionPool();
|
||||
|
||||
final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
|
||||
final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
ContentResponse response = client.newRequest(host, port)
|
||||
|
@ -501,10 +501,10 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
|
|||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
|
||||
ConnectionPool connectionPool = destination.getConnectionPool();
|
||||
|
||||
final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
|
||||
Assert.assertEquals(0, idleConnections.size());
|
||||
|
||||
final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
|
||||
Assert.assertEquals(0, activeConnections.size());
|
||||
|
||||
client.setStrictEventOrdering(false);
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2015 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.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
|
||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ValidatingConnectionPoolTest extends AbstractHttpClientServerTest
|
||||
{
|
||||
public ValidatingConnectionPoolTest(SslContextFactory sslContextFactory)
|
||||
{
|
||||
super(sslContextFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startClient() throws Exception
|
||||
{
|
||||
startClient(new ValidatingHttpClientTransportOverHTTP(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestAfterValidation() throws Exception
|
||||
{
|
||||
start(new EmptyServerHandler());
|
||||
|
||||
client.setMaxConnectionsPerDestination(1);
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.send();
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
|
||||
// The second request should be sent after the validating timeout.
|
||||
response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.send();
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerClosesConnectionAfterRedirectWithoutConnectionCloseHeader() throws Exception
|
||||
{
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
if (target.endsWith("/redirect"))
|
||||
{
|
||||
response.setStatus(HttpStatus.TEMPORARY_REDIRECT_307);
|
||||
response.setContentLength(0);
|
||||
response.setHeader(HttpHeader.LOCATION.asString(), scheme + "://localhost:" + connector.getLocalPort() + "/");
|
||||
response.flushBuffer();
|
||||
baseRequest.getHttpChannel().getEndPoint().shutdownOutput();
|
||||
}
|
||||
else
|
||||
{
|
||||
response.setStatus(HttpStatus.OK_200);
|
||||
response.setContentLength(0);
|
||||
response.setHeader(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.path("/redirect")
|
||||
.send();
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnectionsWithConnectionCloseHeader() throws Exception
|
||||
{
|
||||
testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnections(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(HttpStatus.OK_200);
|
||||
response.setContentLength(0);
|
||||
response.setHeader(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnectionsWithoutConnectionCloseHeader() throws Exception
|
||||
{
|
||||
testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnections(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(HttpStatus.OK_200);
|
||||
response.setContentLength(0);
|
||||
response.flushBuffer();
|
||||
baseRequest.getHttpChannel().getEndPoint().shutdownOutput();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnections(Handler handler) throws Exception
|
||||
{
|
||||
start(handler);
|
||||
client.setMaxConnectionsPerDestination(1);
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
Request request1 = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.path("/one")
|
||||
.onRequestBegin(r ->
|
||||
{
|
||||
try
|
||||
{
|
||||
latch.await();
|
||||
}
|
||||
catch (InterruptedException x)
|
||||
{
|
||||
r.abort(x);
|
||||
}
|
||||
});
|
||||
FutureResponseListener listener1 = new FutureResponseListener(request1);
|
||||
request1.send(listener1);
|
||||
|
||||
Request request2 = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(scheme)
|
||||
.path("/two");
|
||||
FutureResponseListener listener2 = new FutureResponseListener(request2);
|
||||
request2.send(listener2);
|
||||
|
||||
// Now we have one request about to be sent, and one queued.
|
||||
|
||||
latch.countDown();
|
||||
|
||||
ContentResponse response1 = listener1.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(200, response1.getStatus());
|
||||
|
||||
ContentResponse response2 = listener2.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(200, response2.getStatus());
|
||||
}
|
||||
|
||||
private static class ValidatingHttpClientTransportOverHTTP extends HttpClientTransportOverHTTP
|
||||
{
|
||||
private final long timeout;
|
||||
|
||||
public ValidatingHttpClientTransportOverHTTP(long timeout)
|
||||
{
|
||||
super(1);
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpDestination newHttpDestination(Origin origin)
|
||||
{
|
||||
return new HttpDestinationOverHTTP(getHttpClient(), origin)
|
||||
{
|
||||
@Override
|
||||
protected ConnectionPool newConnectionPool(HttpClient client)
|
||||
{
|
||||
return new ValidatingConnectionPool(this, client.getMaxConnectionsPerDestination(), this, client.getScheduler(), timeout);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.client.http;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -62,7 +63,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
if (connection == null)
|
||||
{
|
||||
// There are no queued requests, so the newly created connection will be idle
|
||||
connection = destination.getConnectionPool().getIdleConnections().poll(5, TimeUnit.SECONDS);
|
||||
connection = timedPoll(destination.getConnectionPool().getIdleConnections(), 5, TimeUnit.SECONDS);
|
||||
}
|
||||
Assert.assertNotNull(connection);
|
||||
}
|
||||
|
@ -133,9 +134,10 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
latch.countDown();
|
||||
|
||||
// There must be 2 idle connections.
|
||||
Connection connection = destination.getConnectionPool().getIdleConnections().poll(5, TimeUnit.SECONDS);
|
||||
Queue<Connection> idleConnections = destination.getConnectionPool().getIdleConnections();
|
||||
Connection connection = timedPoll(idleConnections, 5, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(connection);
|
||||
connection = destination.getConnectionPool().getIdleConnections().poll(5, TimeUnit.SECONDS);
|
||||
connection = timedPoll(idleConnections, 5, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(connection);
|
||||
}
|
||||
|
||||
|
@ -272,4 +274,17 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest
|
|||
destinationAfter = client.getDestination(scheme, host, port);
|
||||
Assert.assertNotSame(destinationBefore, destinationAfter);
|
||||
}
|
||||
|
||||
private Connection timedPoll(Queue<Connection> connections, long time, TimeUnit unit) throws InterruptedException
|
||||
{
|
||||
long start = System.nanoTime();
|
||||
while (unit.toNanos(time) > System.nanoTime() - start)
|
||||
{
|
||||
Connection connection = connections.poll();
|
||||
if (connection != null)
|
||||
return connection;
|
||||
TimeUnit.MILLISECONDS.sleep(5);
|
||||
}
|
||||
return connections.poll();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jetty-distribution</artifactId>
|
||||
<name>Jetty :: Distribution Assemblies</name>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.fcgi</groupId>
|
||||
<artifactId>fcgi-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.fcgi</groupId>
|
||||
<artifactId>fcgi-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-http-spi</artifactId>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
|
|
|
@ -86,6 +86,19 @@ public class HttpParserTest
|
|||
assertEquals(HttpMethod.GET,HttpMethod.lookAheadGet(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLineParse_Mock_IP() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer("POST /mock/127.0.0.1 HTTP/1.1\015\012" + "\015\012");
|
||||
|
||||
HttpParser.RequestHandler handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
assertEquals("POST", _methodOrVersion);
|
||||
assertEquals("/mock/127.0.0.1", _uriOrStatus);
|
||||
assertEquals("HTTP/1.1", _versionOrReason);
|
||||
assertEquals(-1, _headers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLineParse0() throws Exception
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-infinispan</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jaas</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jaspi</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jndi</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jspc-maven-plugin</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-monitor</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-nosql</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-alpn</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-boot-jsp</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-boot</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-httpservice</artifactId>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-jetty-osgi-context</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-proxy</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-runner</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
@ -79,23 +78,26 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>Customizes the request attributes to be set for SSL requests.</p>
|
||||
* <p>The requirements of the Servlet specs are:</p>
|
||||
* <p>
|
||||
* Customizes the request attributes to be set for SSL requests.
|
||||
* </p>
|
||||
* <p>
|
||||
* The requirements of the Servlet specs are:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li> an attribute named "javax.servlet.request.ssl_session_id" of type
|
||||
* String (since Servlet Spec 3.0).</li>
|
||||
* <li> an attribute named "javax.servlet.request.cipher_suite" of type
|
||||
* String.</li>
|
||||
* <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
|
||||
* <li> an attribute named "javax.servlet.request.X509Certificate" of type
|
||||
* java.security.cert.X509Certificate[]. This is an array of objects of type
|
||||
* X509Certificate, the order of this array is defined as being in ascending
|
||||
* order of trust. The first certificate in the chain is the one set by the
|
||||
* client, the next is the one used to authenticate the first, and so on.
|
||||
* </li>
|
||||
* <li>an attribute named "javax.servlet.request.ssl_session_id" of type String (since Servlet Spec 3.0).</li>
|
||||
* <li>an attribute named "javax.servlet.request.cipher_suite" of type String.</li>
|
||||
* <li>an attribute named "javax.servlet.request.key_size" of type Integer.</li>
|
||||
* <li>an attribute named "javax.servlet.request.X509Certificate" of type java.security.cert.X509Certificate[]. This
|
||||
* is an array of objects of type X509Certificate, the order of this array is defined as being in ascending order of
|
||||
* trust. The first certificate in the chain is the one set by the client, the next is the one used to authenticate
|
||||
* the first, and so on.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param request HttpRequest to be customized.
|
||||
*
|
||||
* @param sslEngine
|
||||
* the sslEngine to be customized.
|
||||
* @param request
|
||||
* HttpRequest to be customized.
|
||||
*/
|
||||
public void customize(SSLEngine sslEngine, Request request)
|
||||
{
|
||||
|
@ -105,16 +107,14 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
|||
if (_sniHostCheck)
|
||||
{
|
||||
String name = request.getServerName();
|
||||
@SuppressWarnings("unchecked")
|
||||
X509 x509 = (X509)sslSession.getValue(SniX509ExtendedKeyManager.SNI_X509);
|
||||
|
||||
|
||||
if (x509!=null && !x509.matches(name))
|
||||
{
|
||||
LOG.warn("Host {} does not match SNI {}",name,x509);
|
||||
throw new BadMessageException(400,"Host does not match SNI");
|
||||
}
|
||||
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Host {} matched SNI {}",name,x509);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-spring</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-start</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-util-ajax</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
|
|
|
@ -299,7 +299,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
{
|
||||
return _aliasX509.get(alias);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the SSLContext object and start the lifecycle
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
||||
|
@ -359,7 +359,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
}
|
||||
X509 x509 = new X509(alias,x509C);
|
||||
_aliasX509.put(alias,x509);
|
||||
|
||||
|
||||
if (_validateCerts)
|
||||
{
|
||||
CertificateValidator validator = new CertificateValidator(trustStore, crls);
|
||||
|
@ -371,7 +371,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
}
|
||||
|
||||
LOG.info("x509={} for {}",x509,this);
|
||||
|
||||
|
||||
for (String h:x509.getHosts())
|
||||
_certHosts.put(h,x509);
|
||||
for (String w:x509.getWilds())
|
||||
|
@ -405,7 +405,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
LOG.debug("Selected Ciphers {} of {}",Arrays.asList(_selectedCipherSuites),Arrays.asList(sslEngine.getSupportedCipherSuites()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
|
@ -1710,15 +1710,15 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
{
|
||||
String host = _host = ((SNIHostName)serverName).getAsciiName();
|
||||
host=StringUtil.asciiToLowerCase(host);
|
||||
|
||||
|
||||
// Try an exact match
|
||||
_x509 = _certHosts.get(host);
|
||||
|
||||
|
||||
// Else try an exact wild match
|
||||
if (_x509==null)
|
||||
{
|
||||
_x509 = _certWilds.get(host);
|
||||
|
||||
|
||||
// Else try an 1 deep wild match
|
||||
if (_x509==null)
|
||||
{
|
||||
|
@ -1733,10 +1733,12 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("SNI matched {}->{}",host,_x509);
|
||||
|
||||
}
|
||||
else if (LOG.isDebugEnabled())
|
||||
LOG.debug("SNI no match for {}", serverName);
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("SNI no match for {}", serverName);
|
||||
}
|
||||
|
||||
// Return true and allow the KeyManager to accept or reject when choosing a certificate.
|
||||
// If we don't have a SNI host, or didn't see any certificate aliases,
|
||||
|
|
|
@ -32,14 +32,13 @@ import javax.naming.ldap.Rdn;
|
|||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class X509
|
||||
{
|
||||
static final Logger LOG = Log.getLogger(X509.class);
|
||||
|
||||
private static final Logger LOG = Log.getLogger(X509.class);
|
||||
|
||||
/*
|
||||
* @see {@link X509Certificate#getKeyUsage()}
|
||||
*/
|
||||
|
@ -51,26 +50,22 @@ public class X509
|
|||
*/
|
||||
private static final int SUBJECT_ALTERNATIVE_NAMES__DNS_NAME=2;
|
||||
|
||||
|
||||
public static boolean isCertSign(X509Certificate x509)
|
||||
{
|
||||
boolean[] key_usage=x509.getKeyUsage();
|
||||
return key_usage!=null && key_usage[KEY_USAGE__KEY_CERT_SIGN];
|
||||
}
|
||||
|
||||
|
||||
|
||||
private final X509Certificate _x509;
|
||||
private final String _alias;
|
||||
private final List<String> _hosts=new ArrayList<>();
|
||||
private final List<String> _wilds=new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
public X509(String alias,X509Certificate x509) throws CertificateParsingException, InvalidNameException
|
||||
{
|
||||
_alias=alias;
|
||||
_x509 = x509;
|
||||
|
||||
|
||||
// Look for alternative name extensions
|
||||
boolean named=false;
|
||||
Collection<List<?>> altNames = x509.getSubjectAlternativeNames();
|
||||
|
@ -82,7 +77,7 @@ public class X509
|
|||
{
|
||||
String cn = list.get(1).toString();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Certificate SAN alias={} cn={} in {}",alias,cn,this);
|
||||
LOG.debug("Certificate SAN alias={} CN={} in {}",alias,cn,this);
|
||||
if (cn!=null)
|
||||
{
|
||||
named=true;
|
||||
|
@ -92,28 +87,27 @@ public class X509
|
|||
}
|
||||
}
|
||||
|
||||
// If no names found, look up the cn from the subject
|
||||
// If no names found, look up the CN from the subject
|
||||
if (!named)
|
||||
{
|
||||
LdapName name=new LdapName(x509.getSubjectX500Principal().getName(X500Principal.RFC2253));
|
||||
for (Rdn rdn : name.getRdns())
|
||||
{
|
||||
if (rdn.getType().equalsIgnoreCase("cn"))
|
||||
if (rdn.getType().equalsIgnoreCase("CN"))
|
||||
{
|
||||
String cn = rdn.getValue().toString();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Certificate cn alias={} cn={} in {}",alias,cn,this);
|
||||
LOG.debug("Certificate CN alias={} CN={} in {}",alias,cn,this);
|
||||
if (cn!=null && cn.contains(".") && !cn.contains(" "))
|
||||
addName(cn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void addName(String cn)
|
||||
{
|
||||
cn=StringUtil.asciiToLowerCase(cn);
|
||||
cn.toLowerCase();
|
||||
if (cn.startsWith("*."))
|
||||
_wilds.add(cn.substring(2));
|
||||
else
|
||||
|
@ -124,17 +118,17 @@ public class X509
|
|||
{
|
||||
return _alias;
|
||||
}
|
||||
|
||||
|
||||
public X509Certificate getCertificate()
|
||||
{
|
||||
return _x509;
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getHosts()
|
||||
{
|
||||
return new HashSet<>(_hosts);
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getWilds()
|
||||
{
|
||||
return new HashSet<>(_wilds);
|
||||
|
@ -156,7 +150,6 @@ public class X509
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
|
|
|
@ -470,7 +470,10 @@ public class WebAppClassLoader extends URLClassLoader
|
|||
c= _parent.loadClass(name);
|
||||
|
||||
if (c == null && ex!=null)
|
||||
{
|
||||
LOG.debug("not found {} from {}",name,this,ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
if (resolve)
|
||||
resolveClass(c);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -18,33 +18,38 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.api;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class CloseStatus
|
||||
{
|
||||
private static final int MAX_CONTROL_PAYLOAD = 125;
|
||||
private static final int MAX_REASON_PHRASE = MAX_CONTROL_PAYLOAD - 2;
|
||||
public static final int MAX_REASON_PHRASE = MAX_CONTROL_PAYLOAD - 2;
|
||||
|
||||
/**
|
||||
* Convenience method for trimming a long reason phrase at the maximum reason phrase length.
|
||||
* Convenience method for trimming a long reason phrase at the maximum reason phrase length of 123 UTF-8 bytes (per WebSocket spec).
|
||||
*
|
||||
* @param reason
|
||||
* the proposed reason phrase
|
||||
* @return the reason phrase (trimmed if needed)
|
||||
* @deprecated use of this method is strongly discouraged, as it creates too many new objects that are just thrown away to accomplish its goals.
|
||||
*/
|
||||
@Deprecated
|
||||
public static String trimMaxReasonLength(String reason)
|
||||
{
|
||||
if (reason == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] reasonBytes = reason.getBytes(StandardCharsets.UTF_8);
|
||||
if (reasonBytes.length > MAX_REASON_PHRASE)
|
||||
{
|
||||
byte[] trimmed = new byte[MAX_REASON_PHRASE];
|
||||
System.arraycopy(reasonBytes,0,trimmed,0,MAX_REASON_PHRASE);
|
||||
return new String(trimmed,StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
if (reason.length() > MAX_REASON_PHRASE)
|
||||
{
|
||||
return reason.substring(0,MAX_REASON_PHRASE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return reason;
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
|
||||
private int code;
|
||||
|
|
|
@ -152,6 +152,15 @@ public interface RemoteEndpoint
|
|||
*/
|
||||
BatchMode getBatchMode();
|
||||
|
||||
/**
|
||||
* Set the batch mode with which messages are sent.
|
||||
*
|
||||
* @param mode
|
||||
* the batch mode to use
|
||||
* @see #flush()
|
||||
*/
|
||||
void setBatchMode(BatchMode mode);
|
||||
|
||||
/**
|
||||
* Flushes messages that may have been batched by the implementation.
|
||||
*
|
||||
|
|
|
@ -24,6 +24,8 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
|
||||
/**
|
||||
* Tags a POJO as being a WebSocket class.
|
||||
*/
|
||||
|
@ -40,4 +42,6 @@ public @interface WebSocket
|
|||
int maxIdleTime() default -2;
|
||||
|
||||
int maxTextMessageSize() default -2;
|
||||
|
||||
BatchMode batchMode() default BatchMode.AUTO;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-parent</artifactId>
|
||||
<version>9.3.3-SNAPSHOT</version>
|
||||
<version>9.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -19,14 +19,13 @@
|
|||
package org.eclipse.jetty.websocket.common;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.websocket.api.BadPayloadException;
|
||||
import org.eclipse.jetty.websocket.api.CloseStatus;
|
||||
import org.eclipse.jetty.websocket.api.ProtocolException;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
@ -34,19 +33,23 @@ import org.eclipse.jetty.websocket.common.frames.CloseFrame;
|
|||
|
||||
public class CloseInfo
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(CloseInfo.class);
|
||||
private int statusCode;
|
||||
private String reason;
|
||||
private byte[] reasonBytes;
|
||||
|
||||
public CloseInfo()
|
||||
{
|
||||
this(StatusCode.NO_CODE,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the Close Frame payload.
|
||||
*
|
||||
* @param payload the raw close frame payload.
|
||||
* @param validate true if payload should be validated per WebSocket spec.
|
||||
*/
|
||||
public CloseInfo(ByteBuffer payload, boolean validate)
|
||||
{
|
||||
this.statusCode = StatusCode.NO_CODE;
|
||||
this.reason = null;
|
||||
|
||||
if ((payload == null) || (payload.remaining() == 0))
|
||||
{
|
||||
|
@ -77,34 +80,24 @@ public class CloseInfo
|
|||
|
||||
if (data.remaining() > 0)
|
||||
{
|
||||
// Reason
|
||||
try
|
||||
// Reason (trimmed to max reason size)
|
||||
int len = Math.min(data.remaining(), CloseStatus.MAX_REASON_PHRASE);
|
||||
reasonBytes = new byte[len];
|
||||
data.get(reasonBytes,0,len);
|
||||
|
||||
// Spec Requirement : throw BadPayloadException on invalid UTF8
|
||||
if(validate)
|
||||
{
|
||||
Utf8StringBuilder utf = new Utf8StringBuilder();
|
||||
utf.append(data);
|
||||
reason = utf.toString();
|
||||
}
|
||||
catch (NotUtf8Exception e)
|
||||
{
|
||||
if (validate)
|
||||
try
|
||||
{
|
||||
Utf8StringBuilder utf = new Utf8StringBuilder();
|
||||
// if this throws, we know we have bad UTF8
|
||||
utf.append(reasonBytes,0,reasonBytes.length);
|
||||
}
|
||||
catch (NotUtf8Exception e)
|
||||
{
|
||||
throw new BadPayloadException("Invalid Close Reason",e);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
if (validate)
|
||||
{
|
||||
throw new ProtocolException("Invalid Close Reason",e);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,10 +118,28 @@ public class CloseInfo
|
|||
this(statusCode,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a CloseInfo, trimming the reason to {@link CloseStatus#MAX_REASON_PHRASE} UTF-8 bytes if needed.
|
||||
*
|
||||
* @param statusCode the status code
|
||||
* @param reason the raw reason code
|
||||
*/
|
||||
public CloseInfo(int statusCode, String reason)
|
||||
{
|
||||
this.statusCode = statusCode;
|
||||
this.reason = reason;
|
||||
if (reason != null)
|
||||
{
|
||||
byte[] utf8Bytes = reason.getBytes(StandardCharsets.UTF_8);
|
||||
if (utf8Bytes.length > CloseStatus.MAX_REASON_PHRASE)
|
||||
{
|
||||
this.reasonBytes = new byte[CloseStatus.MAX_REASON_PHRASE];
|
||||
System.arraycopy(utf8Bytes,0,this.reasonBytes,0,CloseStatus.MAX_REASON_PHRASE);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.reasonBytes = utf8Bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ByteBuffer asByteBuffer()
|
||||
|
@ -140,11 +151,10 @@ public class CloseInfo
|
|||
}
|
||||
|
||||
int len = 2; // status code
|
||||
byte utf[] = null;
|
||||
if (StringUtil.isNotBlank(reason))
|
||||
boolean hasReason = (this.reasonBytes != null) && (this.reasonBytes.length > 0);
|
||||
if (hasReason)
|
||||
{
|
||||
utf = StringUtil.getUtf8Bytes(reason);
|
||||
len += utf.length;
|
||||
len += this.reasonBytes.length;
|
||||
}
|
||||
|
||||
ByteBuffer buf = BufferUtil.allocate(len);
|
||||
|
@ -152,9 +162,9 @@ public class CloseInfo
|
|||
buf.put((byte)((statusCode >>> 8) & 0xFF));
|
||||
buf.put((byte)((statusCode >>> 0) & 0xFF));
|
||||
|
||||
if (utf != null)
|
||||
if (hasReason)
|
||||
{
|
||||
buf.put(utf,0,utf.length);
|
||||
buf.put(this.reasonBytes,0,this.reasonBytes.length);
|
||||
}
|
||||
BufferUtil.flipToFlush(buf,0);
|
||||
|
||||
|
@ -178,7 +188,11 @@ public class CloseInfo
|
|||
|
||||
public String getReason()
|
||||
{
|
||||
return reason;
|
||||
if (this.reasonBytes == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new String(this.reasonBytes,StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public int getStatusCode()
|
||||
|
@ -199,6 +213,6 @@ public class CloseInfo
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("CloseInfo[code=%d,reason=%s]",statusCode,reason);
|
||||
return String.format("CloseInfo[code=%d,reason=%s]",statusCode,getReason());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -436,9 +436,7 @@ public class WebSocketRemoteEndpoint implements RemoteEndpoint
|
|||
return batchMode;
|
||||
}
|
||||
|
||||
// Only the JSR needs to have this method exposed.
|
||||
// In the Jetty implementation the batching is set
|
||||
// at the moment of opening the session.
|
||||
@Override
|
||||
public void setBatchMode(BatchMode batchMode)
|
||||
{
|
||||
this.batchMode = batchMode;
|
||||
|
|
|
@ -98,7 +98,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web
|
|||
@Override
|
||||
public void close()
|
||||
{
|
||||
this.close(StatusCode.NORMAL,null);
|
||||
connection.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.eclipse.jetty.util.BufferUtil;
|
|||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.CloseException;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
|
@ -208,6 +209,12 @@ public abstract class AbstractEventDriver implements IncomingFrames, EventDriver
|
|||
{
|
||||
/* TODO: provide annotation in future */
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatchMode getBatchMode()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openSession(WebSocketSession session)
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.io.InputStream;
|
|||
import java.io.Reader;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
|
@ -34,6 +35,8 @@ public interface EventDriver extends IncomingFrames
|
|||
public WebSocketPolicy getPolicy();
|
||||
|
||||
public WebSocketSession getSession();
|
||||
|
||||
public BatchMode getBatchMode();
|
||||
|
||||
public void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.io.InputStream;
|
|||
import java.io.Reader;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
@ -40,6 +41,7 @@ public class JettyAnnotatedEventDriver extends AbstractEventDriver
|
|||
{
|
||||
private final JettyAnnotatedMetadata events;
|
||||
private boolean hasCloseBeenCalled = false;
|
||||
private BatchMode batchMode;
|
||||
|
||||
public JettyAnnotatedEventDriver(WebSocketPolicy policy, Object websocket, JettyAnnotatedMetadata events)
|
||||
{
|
||||
|
@ -64,6 +66,13 @@ public class JettyAnnotatedEventDriver extends AbstractEventDriver
|
|||
{
|
||||
this.policy.setIdleTimeout(anno.maxIdleTime());
|
||||
}
|
||||
this.batchMode = anno.batchMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatchMode getBatchMode()
|
||||
{
|
||||
return this.batchMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -244,10 +244,14 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
return super.getExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close without a close code or reason
|
||||
*/
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
close(StatusCode.NORMAL,null);
|
||||
CloseInfo close = new CloseInfo();
|
||||
this.outgoingFrame(close.asFrame(),new OnCloseLocalCallback(close),BatchMode.OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue