Merge branch 'jetty-9.3.x' of github.com:eclipse/jetty.project into jetty-9.3.x
This commit is contained in:
commit
36a649a66c
|
@ -15,13 +15,6 @@
|
|||
<bundle-symbolic-name>${project.groupId}.embedded</bundle-symbolic-name>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>18.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util-ajax</artifactId>
|
||||
|
|
|
@ -103,22 +103,22 @@
|
|||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>cdi-core</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>cdi-full-servlet</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>cdi-servlet</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>cdi-websocket</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
@ -130,21 +130,61 @@
|
|||
<artifactId>jetty-continuation</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.fcgi</groupId>
|
||||
<artifactId>fcgi-server</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.fcgi</groupId>
|
||||
<artifactId>fcgi-server</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-gcloud-memcached-session-manager</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-gcloud-session-manager</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-hazelcast</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-client</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-common</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-hpack</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-http-client-transport</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-server</artifactId>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http-spi</artifactId>
|
||||
|
@ -193,17 +233,17 @@
|
|||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-osgi-boot</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-osgi-boot-jsp</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-osgi-boot-warurl</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
@ -268,37 +308,37 @@
|
|||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>javax-websocket-client-impl</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>javax-websocket-server-impl</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>javax-websocket-api</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>javax-websocket-client</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>javax-websocket-common</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>javax-websocket-server</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>javax-websocket-servlet</artifactId>
|
||||
<version>9.3.20-SNAPSHOT</version>
|
||||
<version>9.3.22-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -60,6 +60,7 @@ public class HttpReceiverOverHTTPTest
|
|||
client = new HttpClient();
|
||||
client.start();
|
||||
destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
endPoint = new ByteArrayEndPoint();
|
||||
connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<>());
|
||||
endPoint.setConnection(connection);
|
||||
|
|
|
@ -67,6 +67,7 @@ public class HttpSenderOverHTTPTest
|
|||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
final CountDownLatch headersLatch = new CountDownLatch(1);
|
||||
|
@ -100,6 +101,7 @@ public class HttpSenderOverHTTPTest
|
|||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
connection.send(request, null);
|
||||
|
@ -129,6 +131,7 @@ public class HttpSenderOverHTTPTest
|
|||
// Shutdown output to trigger the exception on write
|
||||
endPoint.shutdownOutput();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
final CountDownLatch failureLatch = new CountDownLatch(2);
|
||||
|
@ -158,6 +161,7 @@ public class HttpSenderOverHTTPTest
|
|||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
final CountDownLatch failureLatch = new CountDownLatch(2);
|
||||
|
@ -193,6 +197,7 @@ public class HttpSenderOverHTTPTest
|
|||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
String content = "abcdef";
|
||||
|
@ -227,6 +232,7 @@ public class HttpSenderOverHTTPTest
|
|||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
String content1 = "0123456789";
|
||||
|
@ -262,6 +268,7 @@ public class HttpSenderOverHTTPTest
|
|||
{
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
|
||||
destination.start();
|
||||
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
|
||||
Request request = client.newRequest(URI.create("http://localhost/"));
|
||||
String content1 = "0123456789";
|
||||
|
|
|
@ -600,10 +600,6 @@ public class HttpGenerator
|
|||
for (int f=0;f<n;f++)
|
||||
{
|
||||
HttpField field = fields.getField(f);
|
||||
String v = field.getValue();
|
||||
if (v==null || v.length()==0)
|
||||
continue; // rfc7230 does not allow no value
|
||||
|
||||
HttpHeader h = field.getHeader();
|
||||
if (h==null)
|
||||
putTo(field,header);
|
||||
|
|
|
@ -66,7 +66,6 @@ import org.eclipse.jetty.util.Callback;
|
|||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.hamcrest.Matchers;
|
||||
|
@ -428,7 +427,6 @@ public class StreamResetTest extends AbstractTest
|
|||
@Override
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
Log.getLogger(StreamResetTest.class).info("SIMON: uri={}", request.getRequestURI());
|
||||
phaser.get().countDown();
|
||||
IO.copy(request.getInputStream(), response.getOutputStream());
|
||||
}
|
||||
|
@ -455,7 +453,6 @@ public class StreamResetTest extends AbstractTest
|
|||
@Override
|
||||
public void onHeaders(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
Log.getLogger(StreamResetTest.class).info("SIMON: response={}/{}", stream.getId(), frame.getMetaData());
|
||||
MetaData.Response response = (MetaData.Response)frame.getMetaData();
|
||||
if (response.getStatus() == HttpStatus.OK_200)
|
||||
latch.get().countDown();
|
||||
|
@ -464,7 +461,6 @@ public class StreamResetTest extends AbstractTest
|
|||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
Log.getLogger(StreamResetTest.class).info("SIMON: data={}/{}", stream.getId(), frame);
|
||||
callback.succeeded();
|
||||
if (frame.isEndStream())
|
||||
latch.get().countDown();
|
||||
|
|
|
@ -175,6 +175,7 @@ public class HTTP2Connection extends AbstractConnection
|
|||
{
|
||||
private final Callback fillCallback = new FillCallback();
|
||||
private ByteBuffer buffer;
|
||||
private boolean shutdown;
|
||||
|
||||
@Override
|
||||
public Runnable produce()
|
||||
|
@ -185,7 +186,7 @@ public class HTTP2Connection extends AbstractConnection
|
|||
if (task != null)
|
||||
return task;
|
||||
|
||||
if (isFillInterested())
|
||||
if (isFillInterested() || shutdown)
|
||||
return null;
|
||||
|
||||
if (buffer == null)
|
||||
|
@ -221,6 +222,7 @@ public class HTTP2Connection extends AbstractConnection
|
|||
else if (filled < 0)
|
||||
{
|
||||
release();
|
||||
shutdown = true;
|
||||
session.onShutdown();
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -421,8 +421,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
{
|
||||
// We received a GO_AWAY, so try to write
|
||||
// what's in the queue and then disconnect.
|
||||
notifyClose(this, frame);
|
||||
control(null, Callback.NOOP, new DisconnectFrame());
|
||||
notifyClose(this, frame, new DisconnectCallback());
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -462,8 +461,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
@Override
|
||||
public void onConnectionFailure(int error, String reason)
|
||||
{
|
||||
notifyFailure(this, new IOException(String.format("%d/%s", error, reason)));
|
||||
close(error, reason, Callback.NOOP);
|
||||
notifyFailure(this, new IOException(String.format("%d/%s", error, reason)), new CloseCallback(error, reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -991,8 +989,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
|
||||
protected void abort(Throwable failure)
|
||||
{
|
||||
notifyFailure(this, failure);
|
||||
terminate(failure);
|
||||
notifyFailure(this, failure, new TerminateCallback(failure));
|
||||
}
|
||||
|
||||
public boolean isDisconnected()
|
||||
|
@ -1054,11 +1051,11 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
}
|
||||
}
|
||||
|
||||
protected void notifyClose(Session session, GoAwayFrame frame)
|
||||
protected void notifyClose(Session session, GoAwayFrame frame, Callback callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
listener.onClose(session, frame);
|
||||
listener.onClose(session, frame, callback);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
|
@ -1079,11 +1076,11 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
}
|
||||
}
|
||||
|
||||
protected void notifyFailure(Session session, Throwable failure)
|
||||
protected void notifyFailure(Session session, Throwable failure, Callback callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
listener.onFailure(session, failure);
|
||||
listener.onFailure(session, failure, callback);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
|
@ -1322,4 +1319,81 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
promise.failed(x);
|
||||
}
|
||||
}
|
||||
|
||||
private class CloseCallback implements Callback.NonBlocking
|
||||
{
|
||||
private final int error;
|
||||
private final String reason;
|
||||
|
||||
private CloseCallback(int error, String reason)
|
||||
{
|
||||
this.error = error;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
complete();
|
||||
}
|
||||
|
||||
private void complete()
|
||||
{
|
||||
close(error, reason, Callback.NOOP);
|
||||
}
|
||||
}
|
||||
|
||||
private class DisconnectCallback implements Callback.NonBlocking
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
complete();
|
||||
}
|
||||
|
||||
private void complete()
|
||||
{
|
||||
control(null, Callback.NOOP, new DisconnectFrame());
|
||||
}
|
||||
}
|
||||
|
||||
private class TerminateCallback implements Callback.NonBlocking
|
||||
{
|
||||
private final Throwable failure;
|
||||
|
||||
private TerminateCallback(Throwable failure)
|
||||
{
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
failure.addSuppressed(x);
|
||||
complete();
|
||||
}
|
||||
|
||||
private void complete()
|
||||
{
|
||||
terminate(failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,9 +195,23 @@ public interface Session
|
|||
/**
|
||||
* <p>Callback method invoked when a GOAWAY frame has been received.</p>
|
||||
*
|
||||
* @param session the session
|
||||
* @param frame the GOAWAY frame received
|
||||
* @param session the session
|
||||
* @param frame the GOAWAY frame received
|
||||
* @param callback the callback to notify of the GOAWAY processing
|
||||
*/
|
||||
public default void onClose(Session session, GoAwayFrame frame, Callback callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
onClose(session, frame);
|
||||
callback.succeeded();
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
callback.failed(x);
|
||||
}
|
||||
}
|
||||
|
||||
public void onClose(Session session, GoAwayFrame frame);
|
||||
|
||||
/**
|
||||
|
@ -210,9 +224,23 @@ public interface Session
|
|||
/**
|
||||
* <p>Callback method invoked when a failure has been detected for this session.</p>
|
||||
*
|
||||
* @param session the session
|
||||
* @param failure the failure
|
||||
* @param session the session
|
||||
* @param failure the failure
|
||||
* @param callback the callback to notify of failure processing
|
||||
*/
|
||||
public default void onFailure(Session session, Throwable failure, Callback callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
onFailure(session, failure);
|
||||
callback.succeeded();
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
callback.failed(x);
|
||||
}
|
||||
}
|
||||
|
||||
public void onFailure(Session session, Throwable failure);
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Executor;
|
||||
|
@ -55,6 +56,7 @@ import org.eclipse.jetty.server.HttpConfiguration;
|
|||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.CountingCallback;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.thread.ExecutionStrategy;
|
||||
|
||||
|
@ -156,19 +158,27 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
|
|||
public boolean onStreamTimeout(IStream stream, Throwable failure)
|
||||
{
|
||||
HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
|
||||
boolean result = channel != null && channel.onStreamTimeout(failure);
|
||||
boolean result = channel != null && channel.onStreamTimeout(failure, task -> offerTask(task, true));
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} idle timeout on {}: {}", result ? "Processed" : "Ignored", stream, failure);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void onStreamFailure(IStream stream, Throwable failure)
|
||||
public void onStreamFailure(IStream stream, Throwable failure, Callback callback)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Processing failure on {}: {}", stream, failure);
|
||||
HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
|
||||
if (channel != null)
|
||||
channel.onFailure(failure);
|
||||
{
|
||||
Runnable task = channel.onFailure(failure, callback);
|
||||
if (task != null)
|
||||
offerTask(task, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback.succeeded();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onSessionTimeout(Throwable failure)
|
||||
|
@ -179,20 +189,29 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
|
|||
{
|
||||
HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
|
||||
if (channel != null)
|
||||
result &= !channel.isRequestExecuting();
|
||||
result &= channel.isRequestIdle();
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} idle timeout on {}: {}", result ? "Processed" : "Ignored", session, failure);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void onSessionFailure(Throwable failure)
|
||||
public void onSessionFailure(Throwable failure, Callback callback)
|
||||
{
|
||||
ISession session = getSession();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Processing failure on {}: {}", session, failure);
|
||||
for (Stream stream : session.getStreams())
|
||||
onStreamFailure((IStream)stream, failure);
|
||||
Collection<Stream> streams = session.getStreams();
|
||||
if (streams.isEmpty())
|
||||
{
|
||||
callback.succeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
CountingCallback counter = new CountingCallback(callback, streams.size());
|
||||
for (Stream stream : streams)
|
||||
onStreamFailure((IStream)stream, failure, counter);
|
||||
}
|
||||
}
|
||||
|
||||
public void push(Connector connector, IStream stream, MetaData.Request request)
|
||||
|
|
|
@ -123,7 +123,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Session session, GoAwayFrame frame)
|
||||
public void onClose(Session session, GoAwayFrame frame, Callback callback)
|
||||
{
|
||||
ErrorCode error = ErrorCode.from(frame.getError());
|
||||
if (error == null)
|
||||
|
@ -131,13 +131,13 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF
|
|||
String reason = frame.tryConvertPayload();
|
||||
if (reason != null && !reason.isEmpty())
|
||||
reason = " (" + reason + ")";
|
||||
getConnection().onSessionFailure(new EofException("HTTP/2 " + error + reason));
|
||||
getConnection().onSessionFailure(new EofException("HTTP/2 " + error + reason), callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Session session, Throwable failure)
|
||||
public void onFailure(Session session, Throwable failure, Callback callback)
|
||||
{
|
||||
getConnection().onSessionFailure(failure);
|
||||
getConnection().onSessionFailure(failure, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -167,7 +167,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF
|
|||
ErrorCode error = ErrorCode.from(frame.getError());
|
||||
if (error == null)
|
||||
error = ErrorCode.CANCEL_STREAM_ERROR;
|
||||
getConnection().onStreamFailure((IStream)stream, new EofException("HTTP/2 " + error));
|
||||
getConnection().onStreamFailure((IStream)stream, new EofException("HTTP/2 " + error), Callback.NOOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.server;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
|
@ -40,6 +41,7 @@ import org.eclipse.jetty.server.Connector;
|
|||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpInput;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -277,32 +279,33 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
return handle || wasDelayed ? this : null;
|
||||
}
|
||||
|
||||
public boolean isRequestExecuting()
|
||||
public boolean isRequestIdle()
|
||||
{
|
||||
return !getState().isIdle();
|
||||
return getState().isIdle();
|
||||
}
|
||||
|
||||
public boolean onStreamTimeout(Throwable failure)
|
||||
public boolean onStreamTimeout(Throwable failure, Consumer<Runnable> consumer)
|
||||
{
|
||||
boolean result = false;
|
||||
if (isRequestIdle())
|
||||
{
|
||||
consumeInput();
|
||||
result = true;
|
||||
}
|
||||
|
||||
getHttpTransport().onStreamTimeout(failure);
|
||||
if (getRequest().getHttpInput().onIdleTimeout(failure))
|
||||
handle();
|
||||
consumer.accept(this::handleWithContext);
|
||||
|
||||
if (isRequestExecuting())
|
||||
return false;
|
||||
|
||||
consumeInput();
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void onFailure(Throwable failure)
|
||||
public Runnable onFailure(Throwable failure, Callback callback)
|
||||
{
|
||||
getHttpTransport().onStreamFailure(failure);
|
||||
if (getRequest().getHttpInput().failed(failure))
|
||||
handle();
|
||||
else
|
||||
getState().asyncError(failure);
|
||||
boolean handle = getRequest().getHttpInput().failed(failure);
|
||||
consumeInput();
|
||||
return new FailureTask(failure, callback, handle);
|
||||
}
|
||||
|
||||
protected void consumeInput()
|
||||
|
@ -310,6 +313,15 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
getRequest().getHttpInput().consumeAll();
|
||||
}
|
||||
|
||||
private void handleWithContext()
|
||||
{
|
||||
ContextHandler context = getState().getContextHandler();
|
||||
if (context != null)
|
||||
context.handle(getRequest(), this);
|
||||
else
|
||||
handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the associated response has the Expect header set to 100 Continue,
|
||||
* then accessing the input stream indicates that the handler/servlet
|
||||
|
@ -348,4 +360,35 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
streamId = stream.getId();
|
||||
return String.format("%s#%d", super.toString(), getStream() == null ? -1 : streamId);
|
||||
}
|
||||
|
||||
private class FailureTask implements Runnable
|
||||
{
|
||||
private final Throwable failure;
|
||||
private final Callback callback;
|
||||
private final boolean handle;
|
||||
|
||||
public FailureTask(Throwable failure, Callback callback, boolean handle)
|
||||
{
|
||||
this.failure = failure;
|
||||
this.callback = callback;
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (handle)
|
||||
handleWithContext();
|
||||
else
|
||||
getState().asyncError(failure);
|
||||
callback.succeeded();
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
callback.failed(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1121,7 +1121,7 @@ public class SslConnection extends AbstractConnection
|
|||
@Override
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
return _sslEngine.isInboundDone();
|
||||
return getEndPoint().isInputShutdown() || _sslEngine.isInboundDone();
|
||||
}
|
||||
|
||||
private void notifyHandshakeSucceeded(SSLEngine sslEngine)
|
||||
|
|
|
@ -91,6 +91,7 @@ public class HttpInput extends ServletInputStream implements Runnable
|
|||
_contentConsumed = 0;
|
||||
_firstByteTimeStamp = -1;
|
||||
_blockUntil = 0;
|
||||
_waitingForContent = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ public interface Callback
|
|||
* Instance of Adapter that can be used when the callback methods need an empty
|
||||
* implementation without incurring in the cost of allocating a new Adapter object.
|
||||
*/
|
||||
Callback NOOP = new Callback()
|
||||
Callback NOOP = new Callback.NonBlocking()
|
||||
{
|
||||
};
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ public class CountingCallback extends Callback.Nested
|
|||
public CountingCallback(Callback callback, int count)
|
||||
{
|
||||
super(callback);
|
||||
if (count < 1)
|
||||
throw new IllegalArgumentException();
|
||||
this.count = new AtomicInteger(count);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,51 +72,47 @@ public abstract class Credential implements Serializable
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>Utility method that replaces String.equals() to avoid timing attacks.</p>
|
||||
* <p>Utility method that replaces String.equals() to avoid timing attacks.
|
||||
* The length of the loop executed will always be the length of the unknown credential</p>
|
||||
*
|
||||
* @param s1 the first string to compare
|
||||
* @param s2 the second string to compare
|
||||
* @param known the first string to compare (should be known string)
|
||||
* @param unknown the second string to compare (should be the unknown string)
|
||||
* @return whether the two strings are equal
|
||||
*/
|
||||
protected static boolean stringEquals(String s1, String s2)
|
||||
protected static boolean stringEquals(String known, String unknown)
|
||||
{
|
||||
if (s1 == s2)
|
||||
if (known == unknown)
|
||||
return true;
|
||||
if (s1 == null || s2 == null)
|
||||
if (known == null || unknown == null)
|
||||
return false;
|
||||
boolean result = true;
|
||||
int l1 = s1.length();
|
||||
int l2 = s2.length();
|
||||
if (l1 != l2)
|
||||
result = false;
|
||||
int l = Math.min(l1, l2);
|
||||
for (int i = 0; i < l; ++i)
|
||||
result &= s1.charAt(i) == s2.charAt(i);
|
||||
return result;
|
||||
int l1 = known.length();
|
||||
int l2 = unknown.length();
|
||||
for (int i = 0; i < l2; ++i)
|
||||
result &= known.charAt(i%l1) == unknown.charAt(i);
|
||||
return result && l1 == l2;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Utility method that replaces Arrays.equals() to avoid timing attacks.</p>
|
||||
* <p>Utility method that replaces Arrays.equals() to avoid timing attacks.
|
||||
* The length of the loop executed will always be the length of the unknown credential</p>
|
||||
*
|
||||
* @param b1 the first byte array to compare
|
||||
* @param b2 the second byte array to compare
|
||||
* @param known the first byte array to compare (should be known value)
|
||||
* @param unknown the second byte array to compare (should be unknown value)
|
||||
* @return whether the two byte arrays are equal
|
||||
*/
|
||||
protected static boolean byteEquals(byte[] b1, byte[] b2)
|
||||
protected static boolean byteEquals(byte[] known, byte[] unknown)
|
||||
{
|
||||
if (b1 == b2)
|
||||
if (known == unknown)
|
||||
return true;
|
||||
if (b1 == null || b2 == null)
|
||||
if (known == null || unknown == null)
|
||||
return false;
|
||||
boolean result = true;
|
||||
int l1 = b1.length;
|
||||
int l2 = b2.length;
|
||||
if (l1 != l2)
|
||||
result = false;
|
||||
int l = Math.min(l1, l2);
|
||||
for (int i = 0; i < l; ++i)
|
||||
result &= b1[i] == b2[i];
|
||||
return result;
|
||||
int l1 = known.length;
|
||||
int l2 = unknown.length;
|
||||
for (int i = 0; i < l2; ++i)
|
||||
result &= known[i%l1] == unknown[i];
|
||||
return result && l1 == l2;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,6 +51,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
import org.eclipse.jetty.util.ArrayQueue;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
|
@ -482,6 +483,8 @@ public class XmlConfiguration
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("XML " + (obj != null?obj.toString():oClass.getName()) + "." + name + "(" + value + ")");
|
||||
|
||||
MultiException me = new MultiException();
|
||||
|
||||
// Try for trivial match
|
||||
try
|
||||
{
|
||||
|
@ -492,6 +495,7 @@ public class XmlConfiguration
|
|||
catch (IllegalArgumentException | IllegalAccessException | NoSuchMethodException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
me.add(e);
|
||||
}
|
||||
|
||||
// Try for native match
|
||||
|
@ -506,6 +510,7 @@ public class XmlConfiguration
|
|||
catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
me.add(e);
|
||||
}
|
||||
|
||||
// Try a field
|
||||
|
@ -521,16 +526,19 @@ public class XmlConfiguration
|
|||
catch (NoSuchFieldException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
me.add(e);
|
||||
}
|
||||
|
||||
// Search for a match by trying all the set methods
|
||||
Method[] sets = oClass.getMethods();
|
||||
Method set = null;
|
||||
String types = null;
|
||||
for (int s = 0; sets != null && s < sets.length; s++)
|
||||
{
|
||||
Class<?>[] paramTypes = sets[s].getParameterTypes();
|
||||
if (name.equals(sets[s].getName()) && paramTypes.length == 1)
|
||||
{
|
||||
types = types==null?paramTypes[0].getName():(types+","+paramTypes[0].getName());
|
||||
// lets try it
|
||||
try
|
||||
{
|
||||
|
@ -541,6 +549,7 @@ public class XmlConfiguration
|
|||
catch (IllegalArgumentException | IllegalAccessException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
me.add(e);
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -555,6 +564,7 @@ public class XmlConfiguration
|
|||
catch (IllegalAccessException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
me.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -585,11 +595,21 @@ public class XmlConfiguration
|
|||
catch (NoSuchMethodException | IllegalAccessException | InstantiationException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
me.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// No Joy
|
||||
throw new NoSuchMethodException(oClass + "." + name + "(" + vClass[0] + ")");
|
||||
String message = oClass + "." + name + "(" + vClass[0] + ")";
|
||||
if (types!=null)
|
||||
message += ". Found setters for "+types;
|
||||
throw new NoSuchMethodException(message)
|
||||
{
|
||||
{
|
||||
for (int i=0; i<me.size(); i++)
|
||||
addSuppressed(me.getThrowable(i));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,8 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
@ -33,6 +35,7 @@ import org.junit.Test;
|
|||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -248,6 +251,23 @@ public class XmlConfigurationTest
|
|||
assertEquals("Set Type 3", 2, tc.testInt);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMeaningfullSetException() throws Exception
|
||||
{
|
||||
XmlConfiguration configuration =
|
||||
new XmlConfiguration("<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\"><Set name=\"PropertyTest\"><Property name=\"null\"/></Set></Configure>");
|
||||
TestConfiguration tc = new TestConfiguration();
|
||||
try
|
||||
{
|
||||
configuration.configure(tc);
|
||||
Assert.fail();
|
||||
}
|
||||
catch(NoSuchMethodException e)
|
||||
{
|
||||
assertThat(e.getMessage(),containsString("Found setters for int"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListConstructorArg() throws Exception
|
||||
{
|
||||
|
|
18
pom.xml
18
pom.xml
|
@ -496,7 +496,7 @@
|
|||
<plugin>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-version-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<version>2.5</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
|
@ -717,7 +717,7 @@
|
|||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<version>4.0</version>
|
||||
<version>4.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
|
@ -827,6 +827,20 @@
|
|||
<copyGenerated>true</copyGenerated>
|
||||
<attachArtifact>false</attachArtifact>
|
||||
<updateDate>true</updateDate>
|
||||
<versionTagHeader>Tag for release: jetty-${project.version}</versionTagHeader>
|
||||
<filenameExcludes>
|
||||
<filenameExclude>jetty-documentation/.*</filenameExclude>
|
||||
<filenameExclude>examples/.*</filenameExclude>
|
||||
<filenameExclude>aggregates/.*</filenameExclude>
|
||||
<filenameExclude>.*/test-.*</filenameExclude>
|
||||
<filenameExclude>.*/.*-test/.*</filenameExclude>
|
||||
<filenameExclude>.*/.*-tests/.*</filenameExclude>
|
||||
<filenameExclude>.*/src/test/.*</filenameExclude>
|
||||
<filenameExclude>\.git.*</filenameExclude>
|
||||
<filenameExclude>.*\.md$</filenameExclude>
|
||||
<filenameExclude>.*\.txt$</filenameExclude>
|
||||
<filenameExclude>Jenkinsfile</filenameExclude>
|
||||
</filenameExcludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -694,7 +694,7 @@ public class ServerTimeoutsTest extends AbstractTest
|
|||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(2 * idleTimeout);
|
||||
Thread.sleep(idleTimeout + idleTimeout / 2);
|
||||
IO.copy(request.getInputStream(), response.getOutputStream());
|
||||
}
|
||||
catch (InterruptedException x)
|
||||
|
@ -729,7 +729,7 @@ public class ServerTimeoutsTest extends AbstractTest
|
|||
});
|
||||
|
||||
// Wait for the server application to block reading.
|
||||
Thread.sleep(3 * idleTimeout);
|
||||
Thread.sleep(2 * idleTimeout);
|
||||
content.offer(ByteBuffer.wrap(data2));
|
||||
content.close();
|
||||
|
||||
|
|
Loading…
Reference in New Issue