Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java45
-rw-r--r--jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java27
-rw-r--r--jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java3
-rw-r--r--jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java12
-rw-r--r--jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java34
-rw-r--r--jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java92
-rw-r--r--jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java14
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java30
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java4
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java61
-rw-r--r--jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestGetPartsTest.java146
-rw-r--r--jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java200
-rw-r--r--jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java12
-rw-r--r--jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java6
-rw-r--r--jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java32
-rw-r--r--tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java46
16 files changed, 411 insertions, 353 deletions
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java
index e5a69b15c4..7022c37d7c 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java
@@ -21,21 +21,66 @@ package org.eclipse.jetty.http2;
import java.util.HashMap;
import java.util.Map;
+/**
+ * Standard HTTP/2 error codes.
+ */
public enum ErrorCode
{
+ /**
+ * Indicates no errors.
+ */
NO_ERROR(0),
+ /**
+ * Indicates a generic HTTP/2 protocol violation.
+ */
PROTOCOL_ERROR(1),
+ /**
+ * Indicates an internal error.
+ */
INTERNAL_ERROR(2),
+ /**
+ * Indicates a HTTP/2 flow control violation.
+ */
FLOW_CONTROL_ERROR(3),
+ /**
+ * Indicates that a SETTINGS frame did not receive a reply in a timely manner.
+ */
SETTINGS_TIMEOUT_ERROR(4),
+ /**
+ * Indicates that a stream frame has been received after the stream was closed.
+ */
STREAM_CLOSED_ERROR(5),
+ /**
+ * Indicates that a frame has an invalid length.
+ */
FRAME_SIZE_ERROR(6),
+ /**
+ * Indicates that a stream was rejected before application processing.
+ */
REFUSED_STREAM_ERROR(7),
+ /**
+ * Indicates that a stream is no longer needed.
+ */
CANCEL_STREAM_ERROR(8),
+ /**
+ * Indicates inability to maintain the HPACK compression context.
+ */
COMPRESSION_ERROR(9),
+ /**
+ * Indicates that the connection established by a HTTP CONNECT was abnormally closed.
+ */
HTTP_CONNECT_ERROR(10),
+ /**
+ * Indicates that the other peer might be generating excessive load.
+ */
ENHANCE_YOUR_CALM_ERROR(11),
+ /**
+ * Indicates that the transport properties do not meet minimum security requirements.
+ */
INADEQUATE_SECURITY_ERROR(12),
+ /**
+ * Indicates that HTTP/1.1 must be used rather than HTTP/2.
+ */
HTTP_1_1_REQUIRED_ERROR(13);
public final int code;
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java
index 92e1158e9d..df999131b7 100644
--- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java
@@ -24,8 +24,11 @@ import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.client.HttpReceiver;
import org.eclipse.jetty.client.HttpSender;
import org.eclipse.jetty.client.api.Result;
+import org.eclipse.jetty.http2.ErrorCode;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.util.Callback;
public class HttpChannelOverHTTP2 extends HttpChannel
{
@@ -33,6 +36,7 @@ public class HttpChannelOverHTTP2 extends HttpChannel
private final Session session;
private final HttpSenderOverHTTP2 sender;
private final HttpReceiverOverHTTP2 receiver;
+ private Stream stream;
public HttpChannelOverHTTP2(HttpDestination destination, HttpConnectionOverHTTP2 connection, Session session)
{
@@ -65,6 +69,16 @@ public class HttpChannelOverHTTP2 extends HttpChannel
return receiver;
}
+ public Stream getStream()
+ {
+ return stream;
+ }
+
+ public void setStream(Stream stream)
+ {
+ this.stream = stream;
+ }
+
@Override
public void send()
{
@@ -80,6 +94,19 @@ public class HttpChannelOverHTTP2 extends HttpChannel
}
@Override
+ public boolean abort(HttpExchange exchange, Throwable requestFailure, Throwable responseFailure)
+ {
+ boolean aborted = super.abort(exchange, requestFailure, responseFailure);
+ if (aborted)
+ {
+ Stream stream = getStream();
+ if (stream != null)
+ stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
+ }
+ return aborted;
+ }
+
+ @Override
public void exchangeTerminated(HttpExchange exchange, Result result)
{
super.exchangeTerminated(exchange, result);
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java
index 827a8740cc..51453e822a 100644
--- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java
@@ -89,7 +89,10 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen
{
HttpExchange exchange = getHttpExchange();
if (exchange == null)
+ {
+ callback.failed(new IOException("terminated"));
return;
+ }
if (responseContent(exchange, frame.getData(), callback))
{
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java
index db01d33c17..b13e68e097 100644
--- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java
@@ -33,8 +33,6 @@ import org.eclipse.jetty.util.Promise;
public class HttpSenderOverHTTP2 extends HttpSender
{
- private Stream stream;
-
public HttpSenderOverHTTP2(HttpChannelOverHTTP2 channel)
{
super(channel);
@@ -59,7 +57,7 @@ public class HttpSenderOverHTTP2 extends HttpSender
@Override
public void succeeded(Stream stream)
{
- HttpSenderOverHTTP2.this.stream = stream;
+ getHttpChannel().setStream(stream);
stream.setIdleTimeout(request.getIdleTimeout());
if (content.hasContent() && !expects100Continue(request))
@@ -95,15 +93,9 @@ public class HttpSenderOverHTTP2 extends HttpSender
}
else
{
+ Stream stream = getHttpChannel().getStream();
DataFrame frame = new DataFrame(stream.getId(), content.getByteBuffer(), content.isLast());
stream.data(frame, callback);
}
}
-
- @Override
- protected void reset()
- {
- super.reset();
- stream = null;
- }
}
diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java
index d4214dd29f..812253992b 100644
--- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java
+++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java
@@ -19,8 +19,11 @@
package org.eclipse.jetty.http2.client.http;
import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Server;
@@ -38,25 +41,38 @@ public class AbstractTest
protected ServerConnector connector;
protected HttpClient client;
- protected void start(int maxConcurrentStreams, Handler handler) throws Exception
+ protected void start(ServerSessionListener listener) throws Exception
+ {
+ prepareServer(new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener));
+ server.start();
+ prepareClient();
+ client.start();
+ }
+
+ protected void start(Handler handler) throws Exception
+ {
+ prepareServer(new HTTP2ServerConnectionFactory(new HttpConfiguration()));
+ server.setHandler(handler);
+ server.start();
+ prepareClient();
+ client.start();
+ }
+
+ protected void prepareServer(ConnectionFactory connectionFactory)
{
QueuedThreadPool serverExecutor = new QueuedThreadPool();
serverExecutor.setName("server");
server = new Server(serverExecutor);
-
- HTTP2ServerConnectionFactory http2 = new HTTP2ServerConnectionFactory(new HttpConfiguration());
- http2.setMaxConcurrentStreams(maxConcurrentStreams);
- connector = new ServerConnector(server, 1, 1, http2);
+ connector = new ServerConnector(server, 1, 1, connectionFactory);
server.addConnector(connector);
+ }
- server.setHandler(handler);
- server.start();
-
+ protected void prepareClient() throws Exception
+ {
client = new HttpClient(new HttpClientTransportOverHTTP2(new HTTP2Client()), null);
QueuedThreadPool clientExecutor = new QueuedThreadPool();
clientExecutor.setName("client");
client.setExecutor(clientExecutor);
- client.start();
}
@After
diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
index c2334eafac..1dcd6066d0 100644
--- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
+++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
@@ -18,19 +18,32 @@
package org.eclipse.jetty.http2.client.http;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
-public class HttpClientTransportOverHTTP2Test
+public class HttpClientTransportOverHTTP2Test extends AbstractTest
{
@Test
public void testPropertiesAreForwarded() throws Exception
@@ -56,6 +69,83 @@ public class HttpClientTransportOverHTTP2Test
Assert.assertTrue(http2Client.isStopped());
}
+ @Test
+ public void testRequestAbortSendsResetFrame() throws Exception
+ {
+ CountDownLatch resetLatch = new CountDownLatch(1);
+ start(new ServerSessionListener.Adapter()
+ {
+ @Override
+ public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+ {
+ return new Stream.Listener.Adapter()
+ {
+ @Override
+ public void onReset(Stream stream, ResetFrame frame)
+ {
+ resetLatch.countDown();
+ }
+ };
+ }
+ });
+
+ try
+ {
+ client.newRequest("localhost", connector.getLocalPort())
+ .onRequestCommit(request -> request.abort(new Exception("explicitly_aborted_by_test")))
+ .send();
+ Assert.fail();
+ }
+ catch (ExecutionException x)
+ {
+ Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
+ }
+ }
+
+ @Test
+ public void testResponseAbortSendsResetFrame() throws Exception
+ {
+ CountDownLatch resetLatch = new CountDownLatch(1);
+ start(new ServerSessionListener.Adapter()
+ {
+ @Override
+ public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+ {
+ MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
+ stream.headers(new HeadersFrame(stream.getId(), metaData, null, false), new Callback()
+ {
+ @Override
+ public void succeeded()
+ {
+ ByteBuffer data = ByteBuffer.allocate(1024);
+ stream.data(new DataFrame(stream.getId(), data, false), NOOP);
+ }
+ });
+
+ return new Stream.Listener.Adapter()
+ {
+ @Override
+ public void onReset(Stream stream, ResetFrame frame)
+ {
+ resetLatch.countDown();
+ }
+ };
+ }
+ });
+
+ try
+ {
+ client.newRequest("localhost", connector.getLocalPort())
+ .onResponseContent((response, buffer) -> response.abort(new Exception("explicitly_aborted_by_test")))
+ .send();
+ Assert.fail();
+ }
+ catch (ExecutionException x)
+ {
+ Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
+ }
+ }
+
@Ignore
@Test
public void testExternalServer() throws Exception
diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java
index 78b421969c..c456d0261a 100644
--- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java
+++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java
@@ -28,6 +28,9 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.junit.Assert;
@@ -35,6 +38,17 @@ import org.junit.Test;
public class MaxConcurrentStreamsTest extends AbstractTest
{
+ private void start(int maxConcurrentStreams, Handler handler) throws Exception
+ {
+ HTTP2ServerConnectionFactory http2 = new HTTP2ServerConnectionFactory(new HttpConfiguration());
+ http2.setMaxConcurrentStreams(maxConcurrentStreams);
+ prepareServer(http2);
+ server.setHandler(handler);
+ server.start();
+ prepareClient();
+ client.start();
+ }
+
@Test
public void testOneConcurrentStream() throws Exception
{
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java
index 1b6c4a8339..1f8c8b4857 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
+import java.util.Deque;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.TimeoutException;
@@ -51,7 +52,7 @@ public class HttpInput extends ServletInputStream implements Runnable
private final static Content EARLY_EOF_CONTENT = new EofContent("EARLY_EOF");
private final byte[] _oneByteBuffer = new byte[1];
- private final Queue<Content> _inputQ = new ArrayDeque<>();
+ private final Deque<Content> _inputQ = new ArrayDeque<>();
private final HttpChannelState _channelState;
private ReadListener _listener;
private State _state = STREAM;
@@ -370,6 +371,33 @@ public class HttpInput extends ServletInputStream implements Runnable
}
/**
+ * Adds some content to the start of this input stream.
+ * <p>Typically used to push back content that has
+ * been read, perhaps mutated. The bytes prepended are
+ * deducted for the contentConsumed total</p>
+ * @param item the content to add
+ * @return true if content channel woken for read
+ */
+ public boolean prependContent(Content item)
+ {
+ boolean woken=false;
+ synchronized (_inputQ)
+ {
+ _inputQ.push(item);
+ _contentConsumed-=item.remaining();
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} prependContent {}", this, item);
+
+ if (_listener==null)
+ _inputQ.notify();
+ else
+ woken=_channelState.onReadPossible();
+ }
+
+ return woken;
+ }
+
+ /**
* Adds some content to this input stream.
*
* @param item the content to add
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
index 07c316c3c4..c594d245f8 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
@@ -768,6 +768,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
old_context = __context.get();
__context.set(_scontext);
+ enterScope(null, getState());
+
// defers the calling of super.doStart()
startContext();
@@ -855,7 +857,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
ClassLoader old_classloader = null;
ClassLoader old_webapploader = null;
Thread current_thread = null;
-
+ exitScope(null);
Context old_context = __context.get();
__context.set(_scontext);
try
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java
index 5e7454c984..5a404f3076 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java
@@ -221,6 +221,67 @@ public class HttpInputTest
assertThat(_history.poll(),nullValue());
}
+
+ @Test
+ public void testReRead() throws Exception
+ {
+ _in.addContent(new TContent("AB"));
+ _in.addContent(new TContent("CD"));
+ _fillAndParseSimulate.offer("EF");
+ _fillAndParseSimulate.offer("GH");
+ assertThat(_in.available(),equalTo(2));
+ assertThat(_in.isFinished(),equalTo(false));
+ assertThat(_in.isReady(),equalTo(true));
+
+ assertThat(_in.getContentConsumed(),equalTo(0L));
+ assertThat(_in.read(),equalTo((int)'A'));
+ assertThat(_in.getContentConsumed(),equalTo(1L));
+ assertThat(_in.read(),equalTo((int)'B'));
+ assertThat(_in.getContentConsumed(),equalTo(2L));
+
+ assertThat(_history.poll(),equalTo("Content succeeded AB"));
+ assertThat(_history.poll(),nullValue());
+ assertThat(_in.read(),equalTo((int)'C'));
+ assertThat(_in.read(),equalTo((int)'D'));
+
+ assertThat(_history.poll(),equalTo("Content succeeded CD"));
+ assertThat(_history.poll(),nullValue());
+ assertThat(_in.read(),equalTo((int)'E'));
+
+ _in.prependContent(new HttpInput.Content(BufferUtil.toBuffer("abcde")));
+
+ assertThat(_in.available(),equalTo(5));
+ assertThat(_in.isFinished(),equalTo(false));
+ assertThat(_in.isReady(),equalTo(true));
+
+ assertThat(_in.getContentConsumed(),equalTo(0L));
+ assertThat(_in.read(),equalTo((int)'a'));
+ assertThat(_in.getContentConsumed(),equalTo(1L));
+ assertThat(_in.read(),equalTo((int)'b'));
+ assertThat(_in.getContentConsumed(),equalTo(2L));
+ assertThat(_in.read(),equalTo((int)'c'));
+ assertThat(_in.read(),equalTo((int)'d'));
+ assertThat(_in.read(),equalTo((int)'e'));
+
+
+
+ assertThat(_in.read(),equalTo((int)'F'));
+
+ assertThat(_history.poll(),equalTo("produceContent 2"));
+ assertThat(_history.poll(),equalTo("Content succeeded EF"));
+ assertThat(_history.poll(),nullValue());
+
+ assertThat(_in.read(),equalTo((int)'G'));
+ assertThat(_in.read(),equalTo((int)'H'));
+
+ assertThat(_history.poll(),equalTo("Content succeeded GH"));
+ assertThat(_history.poll(),nullValue());
+
+ assertThat(_in.getContentConsumed(),equalTo(8L));
+
+ assertThat(_history.poll(),nullValue());
+ }
+
@Test
public void testBlockingRead() throws Exception
{
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestGetPartsTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestGetPartsTest.java
deleted file mode 100644
index 55de8d851f..0000000000
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestGetPartsTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2016 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.servlet;
-
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.file.Path;
-
-import javax.servlet.MultipartConfigElement;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.Part;
-
-import org.eclipse.jetty.http.HttpTester;
-import org.eclipse.jetty.server.LocalConnector;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.toolchain.test.FS;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-public class RequestGetPartsTest
-{
- @SuppressWarnings("serial")
- public static class DumpPartInfoServlet extends HttpServlet
- {
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- {
- resp.setContentType("text/plain");
- PrintWriter out = resp.getWriter();
-
- for(Part part: req.getParts())
- {
- out.printf("Got part: name=%s, size=%,d, filename=%s%n",part.getName(), part.getSize(), part.getSubmittedFileName());
- }
- }
- }
-
- private static Server server;
- private static LocalConnector connector;
- private static File locationDir;
-
- @BeforeClass
- public static void startServer() throws Exception
- {
- Path tmpDir = MavenTestingUtils.getTargetTestingPath("testrequest_getparts");
- FS.ensureEmpty(tmpDir);
-
- locationDir = tmpDir.toFile();
-
- server = new Server();
- connector = new LocalConnector(server);
- server.addConnector(connector);
-
- ServletContextHandler context = new ServletContextHandler();
- context.setContextPath("/");
- server.setHandler(context);
-
- ServletHolder holder = context.addServlet(DumpPartInfoServlet.class,"/dump/*");
- String location = locationDir.getAbsolutePath();
- long maxFileSize = 1024*1024*5;
- long maxRequestSize = 1024*1024*10;
- int fileSizeThreshold = 1;
- MultipartConfigElement multipartConfig = new MultipartConfigElement(location,maxFileSize,maxRequestSize,fileSizeThreshold);
- ((ServletHolder.Registration) holder.getRegistration()).setMultipartConfig(multipartConfig);
-
- server.start();
- }
-
- @AfterClass
- public static void stopServer() throws Exception
- {
- server.stop();
- }
-
- @Test
- public void testMultiFileUpload_SameName() throws Exception
- {
- // generated and parsed test
- HttpTester.Request request = HttpTester.newRequest();
- HttpTester.Response response;
-
- // test GET
- request.setMethod("POST");
- request.setURI("/dump/");
- request.setVersion("HTTP/1.1");
- request.setHeader("Host","tester");
- request.setHeader("Connection","close");
-
- String boundary="XyXyXy";
- request.setHeader("Content-Type","multipart/form-data; boundary=" + boundary);
-
- String crocMsg = "See ya later, aligator.";
- String aligMsg = "In a while, crocodile.";
-
- StringBuilder content = new StringBuilder();
- content.append("--").append(boundary).append("\r\n");
- content.append("Content-Disposition: form-data; name=\"same\"; filename=\"crocodile.dat\"\r\n");
- content.append("Content-Type: application/octet-stream\r\n");
- content.append("\r\n");
- content.append(crocMsg).append("\r\n");
- content.append("--").append(boundary).append("\r\n");
- content.append("Content-Disposition: form-data; name=\"same\"; filename=\"aligator.dat\"\r\n");
- content.append("Content-Type: application/octet-stream\r\n");
- content.append("\r\n");
- content.append(aligMsg).append("\r\n");
- content.append("--").append(boundary).append("--\r\n");
- content.append("\r\n");
-
- request.setContent(content.toString());
-
- response = HttpTester.parseResponse(connector.getResponses(request.generate()));
- assertThat("Response status", response.getStatus(), is(HttpServletResponse.SC_OK));
- assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-
- String responseContents = response.getContent();
- assertThat("response.contents", responseContents, containsString(String.format("Got part: name=same, size=%d, filename=crocodile.dat",crocMsg.length())));
- assertThat("response.contents", responseContents, containsString(String.format("Got part: name=same, size=%d, filename=aligator.dat",aligMsg.length())));
- }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
index c2ce682774..c3b43e4750 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
@@ -18,10 +18,9 @@
package org.eclipse.jetty.servlets;
+
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -31,15 +30,10 @@ import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
-import java.io.Reader;
import java.nio.charset.StandardCharsets;
-import java.nio.file.Path;
import java.util.EnumSet;
-import java.util.Enumeration;
import java.util.Map;
import javax.servlet.DispatcherType;
@@ -51,12 +45,9 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletTester;
-import org.eclipse.jetty.toolchain.test.FS;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.IO;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
public class MultipartFilterTest
@@ -65,45 +56,16 @@ public class MultipartFilterTest
private ServletTester tester;
FilterHolder multipartFilter;
- @SuppressWarnings("serial")
public static class FilenameServlet extends TestServlet
{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
- assertThat(req.getAttribute("fileup"), notNullValue());
+ assertNotNull(req.getAttribute("fileup"));
super.doPost(req, resp);
}
}
-
- @SuppressWarnings("serial")
- public static class ParameterListServlet extends TestServlet
- {
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- {
- resp.setContentType("text/plain");
- PrintWriter out = resp.getWriter();
-
- Enumeration<String> pnames = req.getParameterNames();
- while (pnames.hasMoreElements())
- {
- String pname = pnames.nextElement();
- Object param = req.getParameter(pname);
- out.printf("Parameter[%s] = ",pname);
- if (param == null)
- {
- out.println(" <null>");
- }
- else
- {
- out.printf("(%s) %s%n",param.getClass().getName(),param);
- }
- }
- }
- }
- @SuppressWarnings("serial")
public static class BoundaryServlet extends TestServlet
{
@Override
@@ -111,11 +73,9 @@ public class MultipartFilterTest
{
//we have configured the multipart filter to always store to disk (file size threshold == 1)
//but fileName has no filename param, so only the attribute should be set
- assertThat("getParameter('fileName')", req.getParameter("fileName"), nullValue());
- assertThat("getAttribute('fileName')", req.getAttribute("fileName"), notNullValue());
-
+ assertNull(req.getParameter("fileName"));
+ assertNotNull(req.getAttribute("fileName"));
File f = (File)req.getAttribute("fileName");
- assertThat("File exists", f.exists(), is(true));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IO.copy(new FileInputStream(f), baos);
assertEquals(getServletContext().getAttribute("fileName"), baos.toString());
@@ -133,36 +93,34 @@ public class MultipartFilterTest
}
}
- @SuppressWarnings("serial")
public static class TestServlet extends DumpServlet
{
- @SuppressWarnings("deprecation")
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
- String fileup = req.getParameter("fileup");
- assertThat("getParameter('fileup')",fileup,notNullValue());
-
- System.err.println("Fileup=" + req.getParameter("fileup"));
-
- String fileupType = req.getParameter("fileup" + MultiPartFilter.CONTENT_TYPE_SUFFIX);
- assertThat("req.getParameter('fileup'+CONTENT_TYPE_SUFFIX)",fileupType,is("application/octet-stream"));
+ assertNotNull(req.getParameter("fileup"));
+ System.err.println("Fileup="+req.getParameter("fileup"));
+ assertNotNull(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX));
+ assertEquals(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX), "application/octet-stream");
super.doPost(req, resp);
}
+
}
- @SuppressWarnings("deprecation")
+
+
@Before
public void setUp() throws Exception
{
- Path tmpDir = MavenTestingUtils.getTargetTestingPath("testmultupart");
- FS.ensureEmpty(tmpDir);
-
- _dir = tmpDir.toFile();
+ _dir = File.createTempFile("testmultupart",null);
+ assertTrue(_dir.delete());
+ assertTrue(_dir.mkdir());
+ _dir.deleteOnExit();
+ assertTrue(_dir.isDirectory());
tester=new ServletTester("/context");
- tester.getContext().setResourceBase(tmpDir.toString());
+ tester.getContext().setResourceBase(_dir.getCanonicalPath());
tester.getContext().addServlet(TestServlet.class, "/");
tester.getContext().setAttribute("javax.servlet.context.tempdir", _dir);
multipartFilter = tester.getContext().addFilter(MultiPartFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST));
@@ -832,7 +790,6 @@ public class MultipartFilterTest
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
}
- @SuppressWarnings("serial")
public static class TestServletParameterMap extends DumpServlet
{
@Override
@@ -843,7 +800,7 @@ public class MultipartFilterTest
super.doPost(req, resp);
}
}
-
+
/**
* Validate that the getParameterMap() call is correctly unencoding the parameters in the
* map that it returns.
@@ -873,7 +830,7 @@ public class MultipartFilterTest
"Content-Type: application/octet-stream\r\n\r\n"+
"How now brown cow."+
"\r\n--" + boundary + "\r\n"+
- "Content-Disposition: form-data; name=\"strup\""+ // FIXME: this is missing a "\r\n"??
+ "Content-Disposition: form-data; name=\"strup\""+
"Content-Type: application/octet-stream\r\n\r\n"+
"How now brown cow."+
"\r\n--" + boundary + "--\r\n\r\n";
@@ -884,119 +841,6 @@ public class MultipartFilterTest
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
assertTrue(response.getContent().indexOf("brown cow")>=0);
}
-
- /**
- * Validate that the uploaded file can be accessed on the name it was given
- * @throws Exception on test failure
- */
- @Test
- @Ignore("Fails for Bug #486394")
- public void testFileUpload_AccessViaFilename() throws Exception
- {
- tester.addServlet(ParameterListServlet.class,"/paramlist");
-
- multipartFilter.setInitParameter("fileOutputBuffer", "1");
- multipartFilter.setInitParameter("deleteFiles", "false");
- multipartFilter.setInitParameter("writeFilesWithFilenames", "true");
-
- // generated and parsed test
- HttpTester.Request request = HttpTester.newRequest();
- HttpTester.Response response;
-
- // test GET
- request.setMethod("POST");
- request.setURI("/context/paramlist");
- request.setVersion("HTTP/1.1");
- request.setHeader("Host","tester");
- request.setHeader("Connection","close");
- String boundary="XyXyXy";
- request.setHeader("Content-Type","multipart/form-data; boundary=" + boundary);
-
- StringBuilder content = new StringBuilder();
- content.append("--").append(boundary).append("\r\n");
- content.append("Content-Disposition: form-data; name=\"file\"; filename=\"tiny.dat\"\r\n");
- content.append("Content-Type: application/octet-stream\r\n");
- content.append("\r\n");
- content.append("How now brown cow.\r\n");
- content.append("--").append(boundary).append("--\r\n");
- content.append("\r\n");
-
- request.setContent(content.toString());
-
- response = HttpTester.parseResponse(tester.getResponses(request.generate()));
- assertThat("Response status", response.getStatus(), is(HttpServletResponse.SC_OK));
- assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-
- String contents = assertUploadedFileExists("tiny.dat");
- assertThat("contents", contents, containsString("How now brown cow."));
- }
-
- /**
- * Validate that the two upload files, with the same name="" on two different parts,
- * can be accessed with the filename="" portions.
- * @throws Exception on test failure
- */
- @Test
- @Ignore("Fails for Bug #486394")
- public void testTwoFileUploads_AccessViaFilename() throws Exception
- {
- tester.addServlet(ParameterListServlet.class,"/paramlist");
-
- multipartFilter.setInitParameter("fileOutputBuffer", "1");
- multipartFilter.setInitParameter("deleteFiles", "false");
- multipartFilter.setInitParameter("writeFilesWithFilenames", "true");
-
- // generated and parsed test
- HttpTester.Request request = HttpTester.newRequest();
- HttpTester.Response response;
-
- // test GET
- request.setMethod("POST");
- request.setURI("/context/paramlist");
- request.setVersion("HTTP/1.1");
- request.setHeader("Host","tester");
- request.setHeader("Connection","close");
-
- String boundary="XyXyXy";
- request.setHeader("Content-Type","multipart/form-data; boundary=" + boundary);
-
- StringBuilder content = new StringBuilder();
- content.append("--").append(boundary).append("\r\n");
- content.append("Content-Disposition: form-data; name=\"same\"; filename=\"crocodile.dat\"\r\n");
- content.append("Content-Type: application/octet-stream\r\n");
- content.append("\r\n");
- content.append("See ya later, aligator.\r\n");
- content.append("--").append(boundary).append("\r\n");
- content.append("Content-Disposition: form-data; name=\"same\"; filename=\"aligator.dat\"\r\n");
- content.append("Content-Type: application/octet-stream\r\n");
- content.append("\r\n");
- content.append("In a while, crocodile.\r\n");
- content.append("--").append(boundary).append("--\r\n");
- content.append("\r\n");
-
- request.setContent(content.toString());
-
- response = HttpTester.parseResponse(tester.getResponses(request.generate()));
- assertThat("Response status", response.getStatus(), is(HttpServletResponse.SC_OK));
- assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-
- String contents = assertUploadedFileExists("crocodile.dat");
- assertThat("contents", contents, containsString("See ya later, aligator."));
-
- contents = assertUploadedFileExists("aligator.dat");
- assertThat("contents", contents, containsString("In a while, crocodile."));
- }
-
- private String assertUploadedFileExists(String filename) throws IOException
- {
- File uploadedFile = new File(_dir,filename);
- assertThat("Uploaded File[" + uploadedFile + "].exists",uploadedFile.exists(),is(true));
-
- try (Reader reader = new FileReader(uploadedFile))
- {
- return IO.toString(reader);
- }
- }
public static class TestServletCharSet extends HttpServlet
{
@@ -1103,9 +947,13 @@ public class MultipartFilterTest
assertTrue(response.getContent().indexOf("000")>=0);
}
- @SuppressWarnings("serial")
+
+
public static class DumpServlet extends HttpServlet
{
+ private static final long serialVersionUID = 201012011130L;
+
+ /* ------------------------------------------------------------ */
/**
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java
index 58e8c90db6..f1abf1e49f 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java
@@ -23,7 +23,9 @@ import java.io.IOException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.BatchMode;
@@ -38,7 +40,7 @@ import org.eclipse.jetty.websocket.common.LogicalConnection;
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
@ManagedObject("Abstract Extension")
-public abstract class AbstractExtension extends ContainerLifeCycle implements Extension
+public abstract class AbstractExtension extends AbstractLifeCycle implements Dumpable, Extension
{
private final Logger log;
private WebSocketPolicy policy;
@@ -52,11 +54,15 @@ public abstract class AbstractExtension extends ContainerLifeCycle implements Ex
{
log = Log.getLogger(this.getClass());
}
-
+
@Override
+ public String dump()
+ {
+ return ContainerLifeCycle.dump(this);
+ }
+
public void dump(Appendable out, String indent) throws IOException
{
- super.dump(out, indent);
// incoming
dumpWithHeading(out, indent, "incoming", this.nextIncoming);
dumpWithHeading(out, indent, "outgoing", this.nextOutgoing);
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java
index 720e98146b..2cde3a5ab3 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java
@@ -29,6 +29,7 @@ import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.BatchMode;
@@ -89,6 +90,11 @@ public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames
Extension ext = exts.next();
ext.setNextOutgoingFrames(nextOutgoing);
nextOutgoing = ext;
+
+ if (ext instanceof LifeCycle)
+ {
+ addBean(ext,true);
+ }
}
// Connect incomings
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java
index ac32ad6d72..517f714203 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java
@@ -74,28 +74,34 @@ public abstract class CompressExtension extends AbstractExtension
private final Queue<FrameEntry> entries = new ConcurrentArrayQueue<>();
private final IteratingCallback flusher = new Flusher();
- private final Deflater deflater;
- private final Inflater inflater;
+ private Deflater deflaterImpl;
+ private Inflater inflaterImpl;
protected AtomicInteger decompressCount = new AtomicInteger(0);
private int tailDrop = TAIL_DROP_NEVER;
private int rsvUse = RSV_USE_ALWAYS;
protected CompressExtension()
{
- deflater = new Deflater(Deflater.DEFAULT_COMPRESSION,NOWRAP);
- inflater = new Inflater(NOWRAP);
tailDrop = getTailDropMode();
rsvUse = getRsvUseMode();
}
public Deflater getDeflater()
{
- return deflater;
+ if (deflaterImpl == null)
+ {
+ deflaterImpl = new Deflater(Deflater.DEFAULT_COMPRESSION,NOWRAP);
+ }
+ return deflaterImpl;
}
public Inflater getInflater()
{
- return inflater;
+ if (inflaterImpl == null)
+ {
+ inflaterImpl = new Inflater(NOWRAP);
+ }
+ return inflaterImpl;
}
/**
@@ -155,6 +161,8 @@ public abstract class CompressExtension extends AbstractExtension
}
byte[] output = new byte[DECOMPRESS_BUF_SIZE];
+ Inflater inflater = getInflater();
+
while(buf.hasRemaining() && inflater.needsInput())
{
if (!supplyInput(inflater,buf))
@@ -346,6 +354,16 @@ public abstract class CompressExtension extends AbstractExtension
}
return true;
}
+
+ @Override
+ protected void doStop() throws Exception
+ {
+ if(deflaterImpl != null)
+ deflaterImpl.end();
+ if(inflaterImpl != null)
+ inflaterImpl.end();
+ super.doStop();
+ }
@Override
public String toString()
@@ -429,6 +447,8 @@ public abstract class CompressExtension extends AbstractExtension
LOG.debug("Compressing {}: {} bytes in {} bytes chunk",entry,remaining,outputLength);
boolean needsCompress = true;
+
+ Deflater deflater = getDeflater();
if (deflater.needsInput() && !supplyInput(deflater,data))
{
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java
index c9d3a03015..415bbe3700 100644
--- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java
@@ -21,6 +21,7 @@ package org.eclipse.jetty.http.client;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Random;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
@@ -35,6 +36,7 @@ import org.eclipse.jetty.client.util.BytesContentProvider;
import org.eclipse.jetty.client.util.FutureResponseListener;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http2.FlowControlStrategy;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.junit.Assert;
@@ -239,6 +241,50 @@ public class HttpClientTest extends AbstractTest
Assert.assertEquals(chunks * chunkSize, Integer.parseInt(response.getContentAsString()));
}
+ @Test
+ public void testRequestAfterFailedRequest() throws Exception
+ {
+ int length = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
+ start(new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ baseRequest.setHandled(true);
+ response.getOutputStream().write(new byte[length]);
+ }
+ });
+
+ // Make a request with a large enough response buffer.
+ org.eclipse.jetty.client.api.Request request = client.newRequest(newURI());
+ FutureResponseListener listener = new FutureResponseListener(request, length);
+ request.send(listener);
+ ContentResponse response = listener.get(5, TimeUnit.SECONDS);
+ Assert.assertEquals(response.getStatus(), 200);
+
+ // Make a request with a small response buffer, should fail.
+ try
+ {
+ request = client.newRequest(newURI());
+ listener = new FutureResponseListener(request, length / 10);
+ request.send(listener);
+ listener.get(5, TimeUnit.SECONDS);
+ Assert.fail();
+ }
+ catch (ExecutionException x)
+ {
+ // Buffering capacity exceeded.
+ x.printStackTrace();
+ }
+
+ // Verify that we can make another request.
+ request = client.newRequest(newURI());
+ listener = new FutureResponseListener(request, length);
+ request.send(listener);
+ response = listener.get(5, TimeUnit.SECONDS);
+ Assert.assertEquals(response.getStatus(), 200);
+ }
+
private void sleep(long time) throws IOException
{
try

Back to the top