diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
index 0ef01a78c2f..fcab2ac596a 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
@@ -559,6 +559,9 @@ public class AnnotationConfiguration extends AbstractConfiguration
}
boolean timeout = !latch.await(getMaxScanWait(context), TimeUnit.SECONDS);
+ long elapsedMs = TimeUnit.MILLISECONDS.convert(System.nanoTime()-start, TimeUnit.NANOSECONDS);
+
+ LOG.info("Scanning elapsed time={}ms",elapsedMs);
if (LOG.isDebugEnabled())
{
@@ -567,7 +570,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
LOG.debug("Scanned {} container path jars, {} WEB-INF/lib jars, {} WEB-INF/classes dirs in {}ms for context {}",
_containerPathStats.getTotal(), _webInfLibStats.getTotal(), _webInfClassesStats.getTotal(),
- (TimeUnit.MILLISECONDS.convert(System.nanoTime()-start, TimeUnit.NANOSECONDS)),
+ elapsedMs,
context);
}
diff --git a/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/config/etc/gcloud-memcached-session-context.xml b/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/config/etc/gcloud-memcached-session-context.xml
index 04a9cfcf4e1..b35daa8bd23 100644
--- a/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/config/etc/gcloud-memcached-session-context.xml
+++ b/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/config/etc/gcloud-memcached-session-context.xml
@@ -17,6 +17,12 @@
600
+
+
diff --git a/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/java/org/eclipse/jetty/gcloud/memcached/session/GCloudMemcachedSessionManager.java b/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/java/org/eclipse/jetty/gcloud/memcached/session/GCloudMemcachedSessionManager.java
index 5d97e599466..094c33c4533 100644
--- a/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/java/org/eclipse/jetty/gcloud/memcached/session/GCloudMemcachedSessionManager.java
+++ b/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/java/org/eclipse/jetty/gcloud/memcached/session/GCloudMemcachedSessionManager.java
@@ -52,6 +52,7 @@ public class GCloudMemcachedSessionManager extends GCloudSessionManager
protected String _port;
protected MemcachedClient _client;
protected int _expirySec = 0;
+ private boolean _heartbeats = true;
@@ -210,6 +211,15 @@ public class GCloudMemcachedSessionManager extends GCloudSessionManager
{
_expirySec = expirySec;
}
+
+
+ /**
+ * @param heartbeats if true memcached heartbeats are enabled. Default is true.
+ */
+ public void setHeartbeats (boolean heartbeats)
+ {
+ _heartbeats = heartbeats;
+ }
@Override
@@ -222,6 +232,8 @@ public class GCloudMemcachedSessionManager extends GCloudSessionManager
XMemcachedClientBuilder builder = new XMemcachedClientBuilder(_host+":"+_port);
_client = builder.build();
+ _client.setEnableHeartBeat(_heartbeats);
+
_client.setTranscoder(new ContextClassloaderSerializingTranscoder());
super.doStart();
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java
index 6e9684bf050..fd2a6b9c806 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java
@@ -282,7 +282,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint
try(Locker.Lock lock = _locker.lock())
{
- if (BufferUtil.isEmpty(_out))
+ if (BufferUtil.isEmpty(_out) && !_closed && !_oshut)
_hasOutput.await(time,unit);
b=_out;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java
index c00b0673338..348cf148de5 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java
@@ -38,11 +38,20 @@ import org.eclipse.jetty.util.ByteArrayOutputStream2;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.Scheduler;
+/**
+ * A local connector, mostly for testing purposes.
+ *
+ * HttpTester.Request request = HttpTester.newRequest();
+ * request.setURI("/some/resource");
+ * HttpTester.Response response =
+ * HttpTester.parseResponse(HttpTester.from(localConnector.getResponse(request.generate())));
+ *
+ *
+ */
public class LocalConnector extends AbstractConnector
{
private final BlockingQueue _connects = new LinkedBlockingQueue<>();
-
public LocalConnector(Server server, Executor executor, Scheduler scheduler, ByteBufferPool pool, int acceptors, ConnectionFactory... factories)
{
super(server,executor,scheduler,pool,acceptors,factories);
@@ -198,20 +207,36 @@ public class LocalConnector extends AbstractConnector
{
return getResponse(requestsBuffer,false,10,TimeUnit.SECONDS);
}
+
+ /** Get a single response using a parser to search for the end of the message.
+ * @param requestBuffer The request to send
+ * @param time The time to wait
+ * @param unit The units of the wait
+ * @return ByteBuffer containing response or null.
+ * @throws Exception If there is a problem
+ */
+ public ByteBuffer getResponse(ByteBuffer requestBuffer, long time,TimeUnit unit) throws Exception
+ {
+ boolean head = BufferUtil.toString(requestBuffer).toLowerCase().startsWith("head ");
+ if (LOG.isDebugEnabled())
+ LOG.debug("requests {}", BufferUtil.toUTF8String(requestBuffer));
+ LocalEndPoint endp = executeRequest(requestBuffer);
+ return endp.waitForResponse(head,time,unit);
+ }
/** Get a single response using a parser to search for the end of the message.
- * @param requestsBuffer The request to send
+ * @param requestBuffer The request to send
* @param head True if the response is for a head request
* @param time The time to wait
* @param unit The units of the wait
* @return ByteBuffer containing response or null.
* @throws Exception If there is a problem
*/
- public ByteBuffer getResponse(ByteBuffer requestsBuffer,boolean head, long time,TimeUnit unit) throws Exception
+ public ByteBuffer getResponse(ByteBuffer requestBuffer,boolean head, long time,TimeUnit unit) throws Exception
{
if (LOG.isDebugEnabled())
- LOG.debug("requests {}", BufferUtil.toUTF8String(requestsBuffer));
- LocalEndPoint endp = executeRequest(requestsBuffer);
+ LOG.debug("requests {}", BufferUtil.toUTF8String(requestBuffer));
+ LocalEndPoint endp = executeRequest(requestBuffer);
return endp.waitForResponse(head,time,unit);
}
@@ -225,6 +250,25 @@ public class LocalConnector extends AbstractConnector
{
return getResponse(rawRequest,false,30,TimeUnit.SECONDS);
}
+
+ /** Get a single response using a parser to search for the end of the message.
+ * @param rawRequest The request to send
+ * @param time The time to wait
+ * @param unit The units of the wait
+ * @return ByteBuffer containing response or null.
+ * @throws Exception If there is a problem
+ */
+ public String getResponse(String rawRequest,long time,TimeUnit unit) throws Exception
+ {
+ boolean head = rawRequest.toLowerCase().startsWith("head ");
+ ByteBuffer requestsBuffer = BufferUtil.toBuffer(rawRequest, StandardCharsets.ISO_8859_1);
+ if (LOG.isDebugEnabled())
+ LOG.debug("request {}", BufferUtil.toUTF8String(requestsBuffer));
+ LocalEndPoint endp = executeRequest(requestsBuffer);
+
+ return BufferUtil.toString(endp.waitForResponse(head,time,unit), StandardCharsets.ISO_8859_1);
+ }
+
/** Get a single response using a parser to search for the end of the message.
* @param rawRequest The request to send
@@ -244,8 +288,6 @@ public class LocalConnector extends AbstractConnector
return BufferUtil.toString(endp.waitForResponse(head,time,unit), StandardCharsets.ISO_8859_1);
}
-
-
/** Local EndPoint
*/
public class LocalEndPoint extends ByteArrayEndPoint
@@ -332,7 +374,30 @@ public class LocalConnector extends AbstractConnector
}
}
}
-
+
+ /** Wait for a response using a parser to detect the end of message
+ * @return Buffer containing full response or null for EOF;
+ * @throws Exception
+ */
+ public String getResponse() throws Exception
+ {
+ return getResponse(false,30,TimeUnit.SECONDS);
+ }
+
+ /** Wait for a response using a parser to detect the end of message
+ * @param head
+ * @param time
+ * @param unit
+ * @return Buffer containing full response or null for EOF;
+ * @throws Exception
+ */
+ public String getResponse(boolean head, long time,TimeUnit unit) throws Exception
+ {
+ ByteBuffer response = waitForResponse(head,time,unit);
+ if (response!=null)
+ return BufferUtil.toString(response);
+ return null;
+ }
/** Wait for a response using a parser to detect the end of message
* @param head
@@ -391,7 +456,6 @@ public class LocalConnector extends AbstractConnector
}
};
-
HttpParser parser = new HttpParser(handler);
parser.setHeadResponse(head);
try(ByteArrayOutputStream2 bout = new ByteArrayOutputStream2();)
@@ -399,10 +463,20 @@ public class LocalConnector extends AbstractConnector
loop: while(true)
{
// read a chunk of response
- ByteBuffer chunk = BufferUtil.hasContent(_responseData)
- ? _responseData : waitForOutput(time,unit);
- _responseData=null;
-
+ ByteBuffer chunk;
+ if (BufferUtil.hasContent(_responseData))
+ chunk = _responseData;
+ else
+ {
+ chunk = waitForOutput(time,unit);
+ if (BufferUtil.isEmpty(chunk) && (!isOpen() || isOutputShutdown()))
+ {
+ parser.atEOF();
+ parser.parseNext(BufferUtil.EMPTY_BUFFER);
+ break loop;
+ }
+ }
+
// Parse the content of this chunk
while (BufferUtil.hasContent(chunk))
{