The default implementation handles "text/html", "text/*" and "*/*".
+ * The method can be overridden to handle other types. Implementations must
+ * immediate produce a response and may not be async.
+ *
*
* @param baseRequest The base request
* @param request The servlet request (may be wrapped)
* @param response The response (may be wrapped)
* @param code the http error code
* @param message the http error message
- * @param mimeType The mimetype to generate (may be */*or other wildcard)
+ * @param contentType The mimetype to generate (may be */*or other wildcard)
* @throws IOException if a response cannot be generated
*/
- protected void generateAcceptableResponse(Request baseRequest, HttpServletRequest request, HttpServletResponse response, int code, String message, String mimeType)
+ protected void generateAcceptableResponse(Request baseRequest, HttpServletRequest request, HttpServletResponse response, int code, String message, String contentType)
throws IOException
{
- switch (mimeType)
+ // We can generate an acceptable contentType, but can we generate an acceptable charset?
+ // TODO refactor this in jetty-10 to be done in the other calling loop
+ Charset charset = null;
+ List acceptable = baseRequest.getHttpFields().getQualityCSV(HttpHeader.ACCEPT_CHARSET);
+ if (!acceptable.isEmpty())
+ {
+ for (String name : acceptable)
+ {
+ if ("*".equals(name))
+ {
+ charset = StandardCharsets.UTF_8;
+ break;
+ }
+
+ try
+ {
+ charset = Charset.forName(name);
+ }
+ catch (Exception e)
+ {
+ LOG.ignore(e);
+ }
+ }
+ if (charset == null)
+ return;
+ }
+
+ MimeTypes.Type type;
+ switch (contentType)
{
case "text/html":
case "text/*":
case "*/*":
+ type = MimeTypes.Type.TEXT_HTML;
+ if (charset == null)
+ charset = StandardCharsets.ISO_8859_1;
+ break;
+
+ case "text/json":
+ case "application/json":
+ type = MimeTypes.Type.TEXT_JSON;
+ if (charset == null)
+ charset = StandardCharsets.UTF_8;
+ break;
+
+ case "text/plain":
+ type = MimeTypes.Type.TEXT_PLAIN;
+ if (charset == null)
+ charset = StandardCharsets.ISO_8859_1;
+ break;
+
+ default:
+ return;
+ }
+
+ // write into the response aggregate buffer and flush it asynchronously.
+ while (true)
+ {
+ try
{
- baseRequest.setHandled(true);
- Writer writer = getAcceptableWriter(baseRequest, request, response);
- if (writer != null)
+ // TODO currently the writer used here is of fixed size, so a large
+ // TODO error page may cause a BufferOverflow. In which case we try
+ // TODO again with stacks disabled. If it still overflows, it is
+ // TODO written without a body.
+ ByteBuffer buffer = baseRequest.getResponse().getHttpOutput().acquireBuffer();
+ ByteBufferOutputStream out = new ByteBufferOutputStream(buffer);
+ PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, charset));
+
+ switch (type)
{
- response.setContentType(MimeTypes.Type.TEXT_HTML.asString());
- handleErrorPage(request, writer, code, message);
+ case TEXT_HTML:
+ response.setContentType(MimeTypes.Type.TEXT_HTML.asString());
+ response.setCharacterEncoding(charset.name());
+ handleErrorPage(request, writer, code, message);
+ break;
+ case TEXT_JSON:
+ response.setContentType(contentType);
+ writeErrorJson(request, writer, code, message);
+ break;
+ case TEXT_PLAIN:
+ response.setContentType(MimeTypes.Type.TEXT_PLAIN.asString());
+ response.setCharacterEncoding(charset.name());
+ writeErrorPlain(request, writer, code, message);
+ break;
+ default:
+ throw new IllegalStateException();
}
+
+ writer.flush();
+ break;
+ }
+ catch (BufferOverflowException e)
+ {
+ LOG.warn("Error page too large: {} {} {}", code, message, request);
+ if (LOG.isDebugEnabled())
+ LOG.warn(e);
+ baseRequest.getResponse().resetContent();
+ if (!_disableStacks)
+ {
+ LOG.info("Disabling showsStacks for " + this);
+ _disableStacks = true;
+ continue;
+ }
+ break;
}
}
+
+ // Do an asynchronous completion.
+ baseRequest.getHttpChannel().sendResponseAndComplete();
}
protected void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message)
@@ -278,12 +343,13 @@ public class ErrorHandler extends AbstractHandler
{
writer.write(" \n");
writer.write("Error ");
- writer.write(Integer.toString(code));
-
- if (_showMessageInTitle)
+ // TODO this code is duplicated in writeErrorPageMessage
+ String status = Integer.toString(code);
+ writer.write(status);
+ if (message != null && !message.equals(status))
{
writer.write(' ');
- write(writer, message);
+ writer.write(StringUtil.sanitizeXmlString(message));
}
writer.write(" \n");
}
@@ -294,7 +360,7 @@ public class ErrorHandler extends AbstractHandler
String uri = request.getRequestURI();
writeErrorPageMessage(request, writer, code, message, uri);
- if (showStacks)
+ if (showStacks && !_disableStacks)
writeErrorPageStacks(request, writer);
Request.getBaseRequest(request).getHttpChannel().getHttpConfiguration()
@@ -305,29 +371,97 @@ public class ErrorHandler extends AbstractHandler
throws IOException
{
writer.write("HTTP ERROR ");
+ String status = Integer.toString(code);
+ writer.write(status);
+ if (message != null && !message.equals(status))
+ {
+ writer.write(' ');
+ writer.write(StringUtil.sanitizeXmlString(message));
+ }
+ writer.write(" \n");
+ writer.write("\n");
+ htmlRow(writer, "URI", uri);
+ htmlRow(writer, "STATUS", status);
+ htmlRow(writer, "MESSAGE", message);
+ htmlRow(writer, "SERVLET", request.getAttribute(Dispatcher.ERROR_SERVLET_NAME));
+ Throwable cause = (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
+ while (cause != null)
+ {
+ htmlRow(writer, "CAUSED BY", cause);
+ cause = cause.getCause();
+ }
+ writer.write("
\n");
+ }
+
+ private void htmlRow(Writer writer, String tag, Object value)
+ throws IOException
+ {
+ writer.write("");
+ writer.write(tag);
+ writer.write(": ");
+ if (value == null)
+ writer.write("-");
+ else
+ writer.write(StringUtil.sanitizeXmlString(value.toString()));
+ writer.write(" \n");
+ }
+
+ private void writeErrorPlain(HttpServletRequest request, PrintWriter writer, int code, String message)
+ {
+ writer.write("HTTP ERROR ");
writer.write(Integer.toString(code));
- writer.write("\nProblem accessing ");
- write(writer, uri);
- writer.write(". Reason:\n
");
- write(writer, message);
- writer.write(" ");
+ writer.write(' ');
+ writer.write(StringUtil.sanitizeXmlString(message));
+ writer.write("\n");
+ writer.printf("URI: %s%n", request.getRequestURI());
+ writer.printf("STATUS: %s%n", code);
+ writer.printf("MESSAGE: %s%n", message);
+ writer.printf("SERVLET: %s%n", request.getAttribute(Dispatcher.ERROR_SERVLET_NAME));
+ Throwable cause = (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
+ while (cause != null)
+ {
+ writer.printf("CAUSED BY %s%n", cause);
+ if (_showStacks && !_disableStacks)
+ cause.printStackTrace(writer);
+ cause = cause.getCause();
+ }
+ }
+
+ private void writeErrorJson(HttpServletRequest request, PrintWriter writer, int code, String message)
+ {
+ writer
+ .append("{\n")
+ .append(" url: \"").append(request.getRequestURI()).append("\",\n")
+ .append(" status: \"").append(Integer.toString(code)).append("\",\n")
+ .append(" message: ").append(QuotedStringTokenizer.quote(message)).append(",\n");
+ Object servlet = request.getAttribute(Dispatcher.ERROR_SERVLET_NAME);
+ if (servlet != null)
+ writer.append("servlet: \"").append(servlet.toString()).append("\",\n");
+ Throwable cause = (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
+ int c = 0;
+ while (cause != null)
+ {
+ writer.append(" cause").append(Integer.toString(c++)).append(": ")
+ .append(QuotedStringTokenizer.quote(cause.toString())).append(",\n");
+ cause = cause.getCause();
+ }
+ writer.append("}");
}
protected void writeErrorPageStacks(HttpServletRequest request, Writer writer)
throws IOException
{
Throwable th = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
- while (th != null)
+ if (_showStacks && th != null)
{
- writer.write("Caused by: ");
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- th.printStackTrace(pw);
- pw.flush();
- write(writer, sw.getBuffer().toString());
+ PrintWriter pw = writer instanceof PrintWriter ? (PrintWriter)writer : new PrintWriter(writer);
+ pw.write("");
+ while (th != null)
+ {
+ th.printStackTrace(pw);
+ th = th.getCause();
+ }
writer.write(" \n");
-
- th = th.getCause();
}
}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java
index 24a1258b61d..ed5affa51c9 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java
@@ -197,8 +197,9 @@ public class ShutdownHandler extends HandlerWrapper
connector.shutdown();
}
- response.sendError(200, "Connectors closed, commencing full shutdown");
baseRequest.setHandled(true);
+ response.setStatus(200);
+ response.flushBuffer();
final Server server = getServer();
new Thread()
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java
index ce95a87b203..d554043205c 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java
@@ -43,9 +43,7 @@ import static org.hamcrest.Matchers.is;
public abstract class AbstractHttpTest
{
- private static final Set __noBodyCodes = new HashSet<>(Arrays.asList(new String[]{
- "100", "101", "102", "204", "304"
- }));
+ private static final Set __noBodyCodes = new HashSet<>(Arrays.asList("100", "101", "102", "204", "304"));
protected static Server server;
protected static ServerConnector connector;
@@ -87,10 +85,10 @@ public abstract class AbstractHttpTest
HttpTester.parseResponse(input, response);
if (httpVersion.is("HTTP/1.1") &&
- response.isComplete() &&
- response.get("content-length") == null &&
- response.get("transfer-encoding") == null &&
- !__noBodyCodes.contains(response.getStatus()))
+ response.isComplete() &&
+ response.get("content-length") == null &&
+ response.get("transfer-encoding") == null &&
+ !__noBodyCodes.contains(response.getStatus()))
assertThat("If HTTP/1.1 response doesn't contain transfer-encoding or content-length headers, " +
"it should contain connection:close", response.get("connection"), is("close"));
return response;
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java
new file mode 100644
index 00000000000..a14a6bcd09f
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java
@@ -0,0 +1,221 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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.server;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Exchanger;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Stream;
+
+import org.eclipse.jetty.http.HttpCompliance;
+import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.io.ChannelEndPoint;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ManagedSelector;
+import org.eclipse.jetty.io.SocketChannelEndPoint;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.thread.Scheduler;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Extended Server Tester.
+ */
+public class AsyncCompletionTest extends HttpServerTestFixture
+{
+ private static final Exchanger X = new Exchanger<>();
+ private static final AtomicBoolean COMPLETE = new AtomicBoolean();
+
+ private static class DelayedCallback extends Callback.Nested
+ {
+ private CompletableFuture _delay = new CompletableFuture<>();
+
+ public DelayedCallback(Callback callback)
+ {
+ super(callback);
+ }
+
+ @Override
+ public void succeeded()
+ {
+ _delay.complete(null);
+ }
+
+ @Override
+ public void failed(Throwable x)
+ {
+ _delay.completeExceptionally(x);
+ }
+
+ public void proceed()
+ {
+ try
+ {
+ _delay.get(10, TimeUnit.SECONDS);
+ getCallback().succeeded();
+ }
+ catch(Throwable th)
+ {
+ th.printStackTrace();
+ getCallback().failed(th);
+ }
+ }
+ }
+
+
+ @BeforeEach
+ public void init() throws Exception
+ {
+ COMPLETE.set(false);
+
+ startServer(new ServerConnector(_server, new HttpConnectionFactory()
+ {
+ @Override
+ public Connection newConnection(Connector connector, EndPoint endPoint)
+ {
+ return configure(new ExtendedHttpConnection(getHttpConfiguration(), connector, endPoint), connector, endPoint);
+ }
+ })
+ {
+ @Override
+ protected ChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
+ {
+ return new ExtendedEndPoint(channel, selectSet, key, getScheduler());
+ }
+ });
+ }
+
+ private static class ExtendedEndPoint extends SocketChannelEndPoint
+ {
+ public ExtendedEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler)
+ {
+ super(channel, selector, key, scheduler);
+ }
+
+ @Override
+ public void write(Callback callback, ByteBuffer... buffers) throws IllegalStateException
+ {
+ DelayedCallback delay = new DelayedCallback(callback);
+ super.write(delay, buffers);
+ try
+ {
+ X.exchange(delay);
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private static class ExtendedHttpConnection extends HttpConnection
+ {
+ public ExtendedHttpConnection(HttpConfiguration config, Connector connector, EndPoint endPoint)
+ {
+ super(config, connector, endPoint, HttpCompliance.RFC7230_LEGACY, false);
+ }
+
+ @Override
+ public void onCompleted()
+ {
+ COMPLETE.compareAndSet(false,true);
+ super.onCompleted();
+ }
+ }
+
+ // Tests from here use these parameters
+ public static Stream tests()
+ {
+ List tests = new ArrayList<>();
+ tests.add(new Object[]{new HelloWorldHandler(), 200, "Hello world"});
+ tests.add(new Object[]{new SendErrorHandler(499,"Test async sendError"), 499, "Test async sendError"});
+ return tests.stream().map(Arguments::of);
+ }
+
+ @ParameterizedTest
+ @MethodSource("tests")
+ public void testAsyncCompletion(Handler handler, int status, String message) throws Exception
+ {
+ configureServer(handler);
+
+ int base = _threadPool.getBusyThreads();
+ try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
+ {
+ OutputStream os = client.getOutputStream();
+
+ // write the request
+ os.write("GET / HTTP/1.0\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1));
+ os.flush();
+
+ // The write should happen but the callback is delayed
+ HttpTester.Response response = HttpTester.parseResponse(client.getInputStream());
+ assertThat(response, Matchers.notNullValue());
+ assertThat(response.getStatus(), is(status));
+ String content = response.getContent();
+ assertThat(content, containsString(message));
+
+ // Check that a thread is held busy in write
+ assertThat(_threadPool.getBusyThreads(), Matchers.greaterThan(base));
+
+ // Getting the Delayed callback will free the thread
+ DelayedCallback delay = X.exchange(null, 10, TimeUnit.SECONDS);
+
+ // wait for threads to return to base level
+ long end = System.nanoTime() + TimeUnit.SECONDS.toNanos(10);
+ while(_threadPool.getBusyThreads() != base)
+ {
+ if (System.nanoTime() > end)
+ throw new TimeoutException();
+ Thread.sleep(10);
+ }
+
+ // We are now asynchronously waiting!
+ assertThat(COMPLETE.get(), is(false));
+
+ // proceed with the completion
+ delay.proceed();
+
+ while(!COMPLETE.get())
+ {
+ if (System.nanoTime() > end)
+ throw new TimeoutException();
+ Thread.sleep(10);
+ }
+ }
+ }
+}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java
index 0f5369036ae..7e396b072b2 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java
@@ -30,7 +30,6 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.server.handler.ErrorHandler;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -53,43 +52,6 @@ public class ErrorHandlerTest
server = new Server();
connector = new LocalConnector(server);
server.addConnector(connector);
- server.addBean(new ErrorHandler()
- {
- @Override
- protected void generateAcceptableResponse(
- Request baseRequest,
- HttpServletRequest request,
- HttpServletResponse response,
- int code,
- String message,
- String mimeType) throws IOException
- {
- switch (mimeType)
- {
- case "text/json":
- case "application/json":
- {
- baseRequest.setHandled(true);
- response.setContentType(mimeType);
- response.getWriter()
- .append("{")
- .append("code: \"").append(Integer.toString(code)).append("\",")
- .append("message: \"").append(message).append('"')
- .append("}");
- break;
- }
- case "text/plain":
- {
- baseRequest.setHandled(true);
- response.setContentType("text/plain");
- response.getOutputStream().print(response.getContentType());
- break;
- }
- default:
- super.generateAcceptableResponse(baseRequest, request, response, code, message, mimeType);
- }
- }
- });
server.setHandler(new AbstractHandler()
{
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java
index 9c667a9b6c8..fcabf1acfe9 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java
@@ -190,6 +190,10 @@ public class HttpInputAsyncStateTest
__history.add("COMPLETE");
break;
+ case READ_REGISTER:
+ _state.getHttpChannel().onAsyncWaitForContent();
+ break;
+
default:
fail("Bad Action: " + action);
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitBadBehaviourTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitBadBehaviourTest.java
deleted file mode 100644
index 336079e4874..00000000000
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitBadBehaviourTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2019 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.server;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.BrokenBarrierException;
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.stream.Stream;
-import javax.servlet.AsyncContext;
-import javax.servlet.DispatcherType;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.HttpTester;
-import org.eclipse.jetty.http.HttpVersion;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-
-//TODO: reset buffer tests
-//TODO: add protocol specific tests for connection: close and/or chunking
-
-public class HttpManyWaysToAsyncCommitBadBehaviourTest extends AbstractHttpTest
-{
- private final String contextAttribute = getClass().getName() + ".asyncContext";
-
- public static Stream httpVersions()
- {
- // boolean dispatch - if true we dispatch, otherwise we complete
- final boolean DISPATCH = true;
- final boolean COMPLETE = false;
-
- List ret = new ArrayList<>();
- ret.add(Arguments.of(HttpVersion.HTTP_1_0, DISPATCH));
- ret.add(Arguments.of(HttpVersion.HTTP_1_0, COMPLETE));
- ret.add(Arguments.of(HttpVersion.HTTP_1_1, DISPATCH));
- ret.add(Arguments.of(HttpVersion.HTTP_1_1, COMPLETE));
- return ret.stream();
- }
-
- @ParameterizedTest
- @MethodSource("httpVersions")
- public void testHandlerSetsHandledAndWritesSomeContent(HttpVersion httpVersion, boolean dispatch) throws Exception
- {
- server.setHandler(new SetHandledWriteSomeDataHandler(false, dispatch));
- server.start();
-
- HttpTester.Response response = executeRequest(httpVersion);
-
- assertThat("response code is 500", response.getStatus(), is(500));
- }
-
- private class SetHandledWriteSomeDataHandler extends ThrowExceptionOnDemandHandler
- {
- private final boolean dispatch;
-
- private SetHandledWriteSomeDataHandler(boolean throwException, boolean dispatch)
- {
- super(throwException);
- this.dispatch = dispatch;
- }
-
- @Override
- public void doNonErrorHandle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
- {
- final CyclicBarrier resumeBarrier = new CyclicBarrier(1);
-
- if (baseRequest.getDispatcherType() == DispatcherType.ERROR)
- {
- response.sendError(500);
- return;
- }
-
- if (request.getAttribute(contextAttribute) == null)
- {
- final AsyncContext asyncContext = baseRequest.startAsync();
- new Thread(new Runnable()
- {
- @Override
- public void run()
- {
- try
- {
- asyncContext.getResponse().getWriter().write("foobar");
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- resumeBarrier.await(5, TimeUnit.SECONDS);
- }
- catch (IOException | TimeoutException | InterruptedException | BrokenBarrierException e)
- {
- e.printStackTrace();
- }
- }
- }).run();
- }
- try
- {
- resumeBarrier.await(5, TimeUnit.SECONDS);
- }
- catch (InterruptedException | BrokenBarrierException | TimeoutException e)
- {
- e.printStackTrace();
- }
- throw new TestCommitException();
- }
- }
-}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitTest.java
index ca5ebddc616..82d9b06bc3c 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitTest.java
@@ -21,6 +21,9 @@ package org.eclipse.jetty.server;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
@@ -31,13 +34,16 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.util.log.StacklessLogging;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.eclipse.jetty.http.HttpFieldsMatchers.containsHeaderValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
//TODO: reset buffer tests
@@ -51,51 +57,72 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
// boolean dispatch - if true we dispatch, otherwise we complete
final boolean DISPATCH = true;
final boolean COMPLETE = false;
+ final boolean IN_WAIT = true;
+ final boolean WHILE_DISPATCHED = false;
List ret = new ArrayList<>();
- ret.add(Arguments.of(HttpVersion.HTTP_1_0, DISPATCH));
- ret.add(Arguments.of(HttpVersion.HTTP_1_1, DISPATCH));
- ret.add(Arguments.of(HttpVersion.HTTP_1_0, COMPLETE));
- ret.add(Arguments.of(HttpVersion.HTTP_1_1, COMPLETE));
+ ret.add(Arguments.of(HttpVersion.HTTP_1_0, DISPATCH, IN_WAIT));
+ ret.add(Arguments.of(HttpVersion.HTTP_1_1, DISPATCH, IN_WAIT));
+ ret.add(Arguments.of(HttpVersion.HTTP_1_0, COMPLETE, IN_WAIT));
+ ret.add(Arguments.of(HttpVersion.HTTP_1_1, COMPLETE, IN_WAIT));
+ ret.add(Arguments.of(HttpVersion.HTTP_1_0, DISPATCH, WHILE_DISPATCHED));
+ ret.add(Arguments.of(HttpVersion.HTTP_1_1, DISPATCH, WHILE_DISPATCHED));
+ ret.add(Arguments.of(HttpVersion.HTTP_1_0, COMPLETE, WHILE_DISPATCHED));
+ ret.add(Arguments.of(HttpVersion.HTTP_1_1, COMPLETE, WHILE_DISPATCHED));
return ret.stream();
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandlerDoesNotSetHandled(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandlerDoesNotSetHandled(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- DoesNotSetHandledHandler handler = new DoesNotSetHandledHandler(false, dispatch);
+ DoesNotSetHandledHandler handler = new DoesNotSetHandledHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(404));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(response.getStatus(), is(404));
+ assertThat(handler.failure(), is(nullValue()));
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandlerDoesNotSetHandledAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandlerDoesNotSetHandledAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- DoesNotSetHandledHandler handler = new DoesNotSetHandledHandler(true, dispatch);
+ DoesNotSetHandledHandler handler = new DoesNotSetHandledHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
- HttpTester.Response response = executeRequest(httpVersion);
+ HttpTester.Response response;
+ if (inWait)
+ {
+ // exception thrown and handled before any async processing
+ response = executeRequest(httpVersion);
+ }
+ else
+ {
+ // exception thrown after async processing, so cannot be handled
+ try (StacklessLogging log = new StacklessLogging(HttpChannelState.class))
+ {
+ response = executeRequest(httpVersion);
+ }
+ }
- assertThat("response code", response.getStatus(), is(500));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(response.getStatus(), is(500));
+ assertThat(handler.failure(), is(nullValue()));
}
private class DoesNotSetHandledHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private DoesNotSetHandledHandler(boolean throwException, boolean dispatch)
+ private DoesNotSetHandledHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -105,17 +132,13 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
- {
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- }).run();
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
+ });
}
super.doNonErrorHandle(target, baseRequest, request, response);
}
@@ -123,42 +146,57 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandlerSetsHandledTrueOnly(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandlerSetsHandledTrueOnly(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- OnlySetHandledHandler handler = new OnlySetHandledHandler(false, dispatch);
+ OnlySetHandledHandler handler = new OnlySetHandledHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
+ assertThat(response.getStatus(), is(200));
if (httpVersion.is("HTTP/1.1"))
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "0"));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(handler.failure(), is(nullValue()));
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandlerSetsHandledTrueOnlyAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandlerSetsHandledTrueOnlyAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- OnlySetHandledHandler handler = new OnlySetHandledHandler(true, dispatch);
+ OnlySetHandledHandler handler = new OnlySetHandledHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
- HttpTester.Response response = executeRequest(httpVersion);
+ HttpTester.Response response;
+ if (inWait)
+ {
+ // exception thrown and handled before any async processing
+ response = executeRequest(httpVersion);
+ }
+ else
+ {
+ // exception thrown after async processing, so cannot be handled
+ try (StacklessLogging log = new StacklessLogging(HttpChannelState.class))
+ {
+ response = executeRequest(httpVersion);
+ }
+ }
- assertThat("response code", response.getStatus(), is(500));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(response.getStatus(), is(500));
+ assertThat(handler.failure(), is(nullValue()));
}
private class OnlySetHandledHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private OnlySetHandledHandler(boolean throwException, boolean dispatch)
+ private OnlySetHandledHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -168,17 +206,13 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
- {
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- }).run();
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
@@ -187,41 +221,55 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandlerSetsHandledAndWritesSomeContent(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandlerSetsHandledAndWritesSomeContent(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- SetHandledWriteSomeDataHandler handler = new SetHandledWriteSomeDataHandler(false, dispatch);
+ SetHandledWriteSomeDataHandler handler = new SetHandledWriteSomeDataHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
+ assertThat(response.getStatus(), is(200));
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "6"));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(handler.failure(), is(nullValue()));
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandlerSetsHandledAndWritesSomeContentAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandlerSetsHandledAndWritesSomeContentAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- SetHandledWriteSomeDataHandler handler = new SetHandledWriteSomeDataHandler(true, dispatch);
+ SetHandledWriteSomeDataHandler handler = new SetHandledWriteSomeDataHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
+ HttpTester.Response response;
+ if (inWait)
+ {
+ // exception thrown and handled before any async processing
+ response = executeRequest(httpVersion);
+ }
+ else
+ {
+ // exception thrown after async processing, so cannot be handled
+ try (StacklessLogging log = new StacklessLogging(HttpChannelState.class))
+ {
+ response = executeRequest(httpVersion);
+ }
+ }
- HttpTester.Response response = executeRequest(httpVersion);
-
- assertThat("response code", response.getStatus(), is(500));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(response.getStatus(), is(500));
+ assertThat(handler.failure(), is(nullValue()));
}
private class SetHandledWriteSomeDataHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private SetHandledWriteSomeDataHandler(boolean throwException, boolean dispatch)
+ private SetHandledWriteSomeDataHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -231,25 +279,21 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
+ try
{
- try
- {
- asyncContext.getResponse().getWriter().write("foobar");
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- catch (IOException e)
- {
- markFailed(e);
- }
+ asyncContext.getResponse().getWriter().write("foobar");
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
}
- }).run();
+ catch (IOException e)
+ {
+ markFailed(e);
+ }
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
@@ -258,44 +302,55 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandlerExplicitFlush(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandlerExplicitFlush(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- ExplicitFlushHandler handler = new ExplicitFlushHandler(false, dispatch);
+ ExplicitFlushHandler handler = new ExplicitFlushHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(response.getStatus(), is(200));
+ assertThat(handler.failure(), is(nullValue()));
if (httpVersion.is("HTTP/1.1"))
assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandlerExplicitFlushAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandlerExplicitFlushAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- ExplicitFlushHandler handler = new ExplicitFlushHandler(true, dispatch);
+ ExplicitFlushHandler handler = new ExplicitFlushHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
- if (httpVersion.is("HTTP/1.1"))
- assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
+ if (inWait)
+ {
+ // throw happens before flush
+ assertThat(response.getStatus(), is(500));
+ }
+ else
+ {
+ // flush happens before throw
+ assertThat(response.getStatus(), is(200));
+ if (httpVersion.is("HTTP/1.1"))
+ assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
+ }
+ assertThat(handler.failure(), is(nullValue()));
}
private class ExplicitFlushHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private ExplicitFlushHandler(boolean throwException, boolean dispatch)
+ private ExplicitFlushHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -305,27 +360,23 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
+ try
{
- try
- {
- ServletResponse asyncContextResponse = asyncContext.getResponse();
- asyncContextResponse.getWriter().write("foobar");
- asyncContextResponse.flushBuffer();
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- catch (IOException e)
- {
- markFailed(e);
- }
+ ServletResponse asyncContextResponse = asyncContext.getResponse();
+ asyncContextResponse.getWriter().write("foobar");
+ asyncContextResponse.flushBuffer();
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
}
- }).run();
+ catch (IOException e)
+ {
+ markFailed(e);
+ }
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
@@ -334,44 +385,55 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandledAndFlushWithoutContent(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandledAndFlushWithoutContent(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- SetHandledAndFlushWithoutContentHandler handler = new SetHandledAndFlushWithoutContentHandler(false, dispatch);
+ SetHandledAndFlushWithoutContentHandler handler = new SetHandledAndFlushWithoutContentHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(response.getStatus(), is(200));
+ assertThat(handler.failure(), is(nullValue()));
if (httpVersion.is("HTTP/1.1"))
assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testHandledAndFlushWithoutContentAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testHandledAndFlushWithoutContentAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- SetHandledAndFlushWithoutContentHandler handler = new SetHandledAndFlushWithoutContentHandler(true, dispatch);
+ SetHandledAndFlushWithoutContentHandler handler = new SetHandledAndFlushWithoutContentHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
- if (httpVersion.is("HTTP/1.1"))
- assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
+ if (inWait)
+ {
+ // throw happens before async behaviour, so is handled
+ assertThat(response.getStatus(), is(500));
+ }
+ else
+ {
+ assertThat(response.getStatus(), is(200));
+ if (httpVersion.is("HTTP/1.1"))
+ assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
+ }
+
+ assertThat(handler.failure(), is(nullValue()));
}
private class SetHandledAndFlushWithoutContentHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private SetHandledAndFlushWithoutContentHandler(boolean throwException, boolean dispatch)
+ private SetHandledAndFlushWithoutContentHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -381,25 +443,21 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
+ try
{
- try
- {
- asyncContext.getResponse().flushBuffer();
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- catch (IOException e)
- {
- markFailed(e);
- }
+ asyncContext.getResponse().flushBuffer();
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
}
- }).run();
+ catch (IOException e)
+ {
+ markFailed(e);
+ }
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
@@ -408,16 +466,16 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testWriteFlushWriteMore(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testWriteFlushWriteMore(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- WriteFlushWriteMoreHandler handler = new WriteFlushWriteMoreHandler(false, dispatch);
+ WriteFlushWriteMoreHandler handler = new WriteFlushWriteMoreHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(response.getStatus(), is(200));
+ assertThat(handler.failure(), is(nullValue()));
// HTTP/1.0 does not do chunked. it will just send content and close
if (httpVersion.is("HTTP/1.1"))
@@ -426,28 +484,39 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testWriteFlushWriteMoreAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testWriteFlushWriteMoreAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- WriteFlushWriteMoreHandler handler = new WriteFlushWriteMoreHandler(true, dispatch);
+ WriteFlushWriteMoreHandler handler = new WriteFlushWriteMoreHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
- if (httpVersion.is("HTTP/1.1"))
- assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
+ if (inWait)
+ {
+ // The exception is thrown before we do any writing or async operations, so it delivered as onError and then
+ // dispatched.
+ assertThat(response.getStatus(), is(500));
+ }
+ else
+ {
+ assertThat(response.getStatus(), is(200));
+ if (httpVersion.is("HTTP/1.1"))
+ assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
+ }
+ assertThat(handler.failure(), is(nullValue()));
}
private class WriteFlushWriteMoreHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private WriteFlushWriteMoreHandler(boolean throwException, boolean dispatch)
+ private WriteFlushWriteMoreHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -457,28 +526,24 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
+ try
{
- try
- {
- ServletResponse asyncContextResponse = asyncContext.getResponse();
- asyncContextResponse.getWriter().write("foo");
- asyncContextResponse.flushBuffer();
- asyncContextResponse.getWriter().write("bar");
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- catch (IOException e)
- {
- markFailed(e);
- }
+ ServletResponse asyncContextResponse = asyncContext.getResponse();
+ asyncContextResponse.getWriter().write("foo");
+ asyncContextResponse.flushBuffer();
+ asyncContextResponse.getWriter().write("bar");
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
}
- }).run();
+ catch (IOException e)
+ {
+ markFailed(e);
+ }
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
@@ -487,47 +552,58 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testBufferOverflow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testBufferOverflow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- OverflowHandler handler = new OverflowHandler(false, dispatch);
+ OverflowHandler handler = new OverflowHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
+ assertThat(response.getStatus(), is(200));
assertThat(response.getContent(), is("foobar"));
if (httpVersion.is("HTTP/1.1"))
assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(handler.failure(), is(nullValue()));
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testBufferOverflowAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testBufferOverflowAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- OverflowHandler handler = new OverflowHandler(true, dispatch);
+ OverflowHandler handler = new OverflowHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- // Buffer size is too small, so the content is written directly producing a 200 response
- assertThat("response code", response.getStatus(), is(200));
- assertThat(response.getContent(), is("foobar"));
- if (httpVersion.is("HTTP/1.1"))
- assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ // Buffer size smaller than content, so writing will commit response.
+ // If this happens before the exception is thrown we get a 200, else a 500 is produced
+ if (inWait)
+ {
+ assertThat(response.getStatus(), is(500));
+ assertThat(response.getContent(), containsString("TestCommitException: Thrown by test"));
+ }
+ else
+ {
+ assertThat(response.getStatus(), is(200));
+ assertThat(response.getContent(), is("foobar"));
+ if (httpVersion.is("HTTP/1.1"))
+ assertThat(response, containsHeaderValue(HttpHeader.TRANSFER_ENCODING, "chunked"));
+ assertThat(handler.failure(), is(nullValue()));
+ }
}
private class OverflowHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private OverflowHandler(boolean throwException, boolean dispatch)
+ private OverflowHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -537,27 +613,23 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
+ try
{
- try
- {
- ServletResponse asyncContextResponse = asyncContext.getResponse();
- asyncContextResponse.setBufferSize(3);
- asyncContextResponse.getWriter().write("foobar");
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- catch (IOException e)
- {
- markFailed(e);
- }
+ ServletResponse asyncContextResponse = asyncContext.getResponse();
+ asyncContextResponse.setBufferSize(3);
+ asyncContextResponse.getWriter().write("foobar");
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
}
- }).run();
+ catch (IOException e)
+ {
+ markFailed(e);
+ }
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
@@ -566,45 +638,54 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testSetContentLengthAndWriteExactlyThatAmountOfBytes(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testSetContentLengthAndWriteExactlyThatAmountOfBytes(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- SetContentLengthAndWriteThatAmountOfBytesHandler handler = new SetContentLengthAndWriteThatAmountOfBytesHandler(false, dispatch);
+ SetContentLengthAndWriteThatAmountOfBytesHandler handler = new SetContentLengthAndWriteThatAmountOfBytesHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
- assertThat("response body", response.getContent(), is("foo"));
+ assertThat(response.getStatus(), is(200));
+ assertThat(response.getContent(), is("foo"));
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "3"));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(handler.failure(), is(nullValue()));
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testSetContentLengthAndWriteExactlyThatAmountOfBytesAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testSetContentLengthAndWriteExactlyThatAmountOfBytesAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- SetContentLengthAndWriteThatAmountOfBytesHandler handler = new SetContentLengthAndWriteThatAmountOfBytesHandler(true, dispatch);
+ SetContentLengthAndWriteThatAmountOfBytesHandler handler = new SetContentLengthAndWriteThatAmountOfBytesHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- //TODO: should we expect 500 here?
- assertThat("response code", response.getStatus(), is(200));
- assertThat("response body", response.getContent(), is("foo"));
- assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "3"));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ if (inWait)
+ {
+ // too late!
+ assertThat(response.getStatus(), is(500));
+ }
+ else
+ {
+ assertThat(response.getStatus(), is(200));
+ assertThat(response.getContent(), is("foo"));
+ assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "3"));
+ }
+ assertThat(handler.failure(), is(nullValue()));
}
private class SetContentLengthAndWriteThatAmountOfBytesHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private SetContentLengthAndWriteThatAmountOfBytesHandler(boolean throwException, boolean dispatch)
+ private SetContentLengthAndWriteThatAmountOfBytesHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -614,27 +695,23 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
+ try
{
- try
- {
- ServletResponse asyncContextResponse = asyncContext.getResponse();
- asyncContextResponse.setContentLength(3);
- asyncContextResponse.getWriter().write("foo");
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- catch (IOException e)
- {
- markFailed(e);
- }
+ ServletResponse asyncContextResponse = asyncContext.getResponse();
+ asyncContextResponse.setContentLength(3);
+ asyncContextResponse.getWriter().write("foo");
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
}
- }).run();
+ catch (IOException e)
+ {
+ markFailed(e);
+ }
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
@@ -643,46 +720,55 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testSetContentLengthAndWriteMoreBytes(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testSetContentLengthAndWriteMoreBytes(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- SetContentLengthAndWriteMoreBytesHandler handler = new SetContentLengthAndWriteMoreBytesHandler(false, dispatch);
+ SetContentLengthAndWriteMoreBytesHandler handler = new SetContentLengthAndWriteMoreBytesHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
+ assertThat(response.getStatus(), is(200));
// jetty truncates the body when content-length is reached.! This is correct and desired behaviour?
- assertThat("response body", response.getContent(), is("foo"));
+ assertThat(response.getContent(), is("foo"));
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "3"));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(handler.failure(), is(nullValue()));
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testSetContentLengthAndWriteMoreAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testSetContentLengthAndWriteMoreAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- SetContentLengthAndWriteMoreBytesHandler handler = new SetContentLengthAndWriteMoreBytesHandler(true, dispatch);
+ SetContentLengthAndWriteMoreBytesHandler handler = new SetContentLengthAndWriteMoreBytesHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- // TODO: we throw before response is committed. should we expect 500?
- assertThat("response code", response.getStatus(), is(200));
- assertThat("response body", response.getContent(), is("foo"));
- assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "3"));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ if (inWait)
+ {
+ // too late!
+ assertThat(response.getStatus(), is(500));
+ }
+ else
+ {
+ assertThat(response.getStatus(), is(200));
+ assertThat(response.getContent(), is("foo"));
+ assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "3"));
+ }
+ assertThat(handler.failure(), is(nullValue()));
}
private class SetContentLengthAndWriteMoreBytesHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private SetContentLengthAndWriteMoreBytesHandler(boolean throwException, boolean dispatch)
+ private SetContentLengthAndWriteMoreBytesHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -692,27 +778,23 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
+ try
{
- try
- {
- ServletResponse asyncContextResponse = asyncContext.getResponse();
- asyncContextResponse.setContentLength(3);
- asyncContextResponse.getWriter().write("foobar");
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- catch (IOException e)
- {
- markFailed(e);
- }
+ ServletResponse asyncContextResponse = asyncContext.getResponse();
+ asyncContextResponse.setContentLength(3);
+ asyncContextResponse.getWriter().write("foobar");
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
}
- }).run();
+ catch (IOException e)
+ {
+ markFailed(e);
+ }
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
@@ -721,41 +803,50 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testWriteAndSetContentLength(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testWriteAndSetContentLength(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- WriteAndSetContentLengthHandler handler = new WriteAndSetContentLengthHandler(false, dispatch);
+ WriteAndSetContentLengthHandler handler = new WriteAndSetContentLengthHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- assertThat("response code", response.getStatus(), is(200));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(response.getStatus(), is(200));
+ assertThat(handler.failure(), is(nullValue()));
//TODO: jetty ignores setContentLength and sends transfer-encoding header. Correct?
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testWriteAndSetContentLengthAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testWriteAndSetContentLengthAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- WriteAndSetContentLengthHandler handler = new WriteAndSetContentLengthHandler(true, dispatch);
+ WriteAndSetContentLengthHandler handler = new WriteAndSetContentLengthHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
-
- assertThat("response code", response.getStatus(), is(200));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ if (inWait)
+ {
+ // too late
+ assertThat(response.getStatus(), is(500));
+ }
+ else
+ {
+ assertThat(response.getStatus(), is(200));
+ }
+ assertThat(handler.failure(), is(nullValue()));
}
private class WriteAndSetContentLengthHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private WriteAndSetContentLengthHandler(boolean throwException, boolean dispatch)
+ private WriteAndSetContentLengthHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -765,27 +856,23 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
+ try
{
- try
- {
- ServletResponse asyncContextResponse = asyncContext.getResponse();
- asyncContextResponse.getWriter().write("foo");
- asyncContextResponse.setContentLength(3); // This should commit the response
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- catch (IOException e)
- {
- markFailed(e);
- }
+ ServletResponse asyncContextResponse = asyncContext.getResponse();
+ asyncContextResponse.getWriter().write("foo");
+ asyncContextResponse.setContentLength(3); // This should commit the response
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
}
- }).run();
+ catch (IOException e)
+ {
+ markFailed(e);
+ }
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
@@ -794,42 +881,52 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@ParameterizedTest
@MethodSource("httpVersion")
- public void testWriteAndSetContentLengthTooSmall(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testWriteAndSetContentLengthTooSmall(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- WriteAndSetContentLengthTooSmallHandler handler = new WriteAndSetContentLengthTooSmallHandler(false, dispatch);
+ WriteAndSetContentLengthTooSmallHandler handler = new WriteAndSetContentLengthTooSmallHandler(false, dispatch, inWait);
server.setHandler(handler);
server.start();
HttpTester.Response response = executeRequest(httpVersion);
- // Setting a content-length too small throws an IllegalStateException
- assertThat("response code", response.getStatus(), is(500));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ // Setting a content-length too small throws an IllegalStateException,
+ // but only in the async handler, which completes or dispatches anyway
+ assertThat(response.getStatus(), is(200));
+ assertThat(handler.failure(), not(is(nullValue())));
}
@ParameterizedTest
@MethodSource("httpVersion")
- public void testWriteAndSetContentLengthTooSmallAndThrow(HttpVersion httpVersion, boolean dispatch) throws Exception
+ public void testWriteAndSetContentLengthTooSmallAndThrow(HttpVersion httpVersion, boolean dispatch, boolean inWait) throws Exception
{
- WriteAndSetContentLengthTooSmallHandler handler = new WriteAndSetContentLengthTooSmallHandler(true, dispatch);
+ WriteAndSetContentLengthTooSmallHandler handler = new WriteAndSetContentLengthTooSmallHandler(true, dispatch, inWait);
server.setHandler(handler);
server.start();
- HttpTester.Response response = executeRequest(httpVersion);
+ HttpTester.Response response;
+ try (StacklessLogging stackless = new StacklessLogging(HttpChannelState.class))
+ {
+ response = executeRequest(httpVersion);
+ }
- // Setting a content-length too small throws an IllegalStateException
- assertThat("response code", response.getStatus(), is(500));
- assertThat("no exceptions", handler.failure(), is(nullValue()));
+ assertThat(response.getStatus(), is(500));
+
+ if (!inWait)
+ assertThat(handler.failure(), not(is(nullValue())));
+ else
+ assertThat(handler.failure(), is(nullValue()));
}
private class WriteAndSetContentLengthTooSmallHandler extends ThrowExceptionOnDemandHandler
{
private final boolean dispatch;
+ private final boolean inWait;
- private WriteAndSetContentLengthTooSmallHandler(boolean throwException, boolean dispatch)
+ private WriteAndSetContentLengthTooSmallHandler(boolean throwException, boolean dispatch, boolean inWait)
{
super(throwException);
this.dispatch = dispatch;
+ this.inWait = inWait;
}
@Override
@@ -839,30 +936,93 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
{
final AsyncContext asyncContext = baseRequest.startAsync();
request.setAttribute(contextAttribute, asyncContext);
- new Thread(new Runnable()
+ runAsync(baseRequest, inWait, () ->
{
- @Override
- public void run()
+ try
{
- try
- {
- ServletResponse asyncContextResponse = asyncContext.getResponse();
- asyncContextResponse.getWriter().write("foobar");
- asyncContextResponse.setContentLength(3);
- if (dispatch)
- asyncContext.dispatch();
- else
- asyncContext.complete();
- }
- catch (IOException e)
- {
- markFailed(e);
- }
+ ServletResponse asyncContextResponse = asyncContext.getResponse();
+ asyncContextResponse.getWriter().write("foobar");
+ asyncContextResponse.setContentLength(3);
}
- }).run();
+ catch (Throwable e)
+ {
+ markFailed(e);
+ if (dispatch)
+ asyncContext.dispatch();
+ else
+ asyncContext.complete();
+ }
+ });
}
baseRequest.setHandled(true);
super.doNonErrorHandle(target, baseRequest, request, response);
}
}
+
+ private void runAsyncInAsyncWait(Request request, Runnable task)
+ {
+ server.getThreadPool().execute(() ->
+ {
+ long end = System.nanoTime() + TimeUnit.SECONDS.toNanos(10);
+ try
+ {
+ while (System.nanoTime() < end)
+ {
+ switch (request.getHttpChannelState().getState())
+ {
+ case WAITING:
+ task.run();
+ return;
+
+ case HANDLING:
+ Thread.sleep(100);
+ continue;
+
+ default:
+ request.getHttpChannel().abort(new IllegalStateException());
+ return;
+ }
+ }
+ request.getHttpChannel().abort(new TimeoutException());
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ private void runAsyncWhileDispatched(Runnable task)
+ {
+ CountDownLatch ran = new CountDownLatch(1);
+
+ server.getThreadPool().execute(() ->
+ {
+ try
+ {
+ task.run();
+ }
+ finally
+ {
+ ran.countDown();
+ }
+ });
+
+ try
+ {
+ ran.await(10, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void runAsync(Request request, boolean inWait, Runnable task)
+ {
+ if (inWait)
+ runAsyncInAsyncWait(request, task);
+ else
+ runAsyncWhileDispatched(task);
+ }
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
index 3102db8873d..fd687f3b7a5 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
@@ -65,13 +65,22 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public abstract class HttpServerTestBase extends HttpServerTestFixture
{
- private static final String REQUEST1_HEADER = "POST / HTTP/1.0\n" + "Host: localhost\n" + "Content-Type: text/xml; charset=utf-8\n" + "Connection: close\n" + "Content-Length: ";
+ private static final String REQUEST1_HEADER = "POST / HTTP/1.0\n" +
+ "Host: localhost\n" +
+ "Content-Type: text/xml; charset=utf-8\n" +
+ "Connection: close\n" +
+ "Content-Length: ";
private static final String REQUEST1_CONTENT = "\n" +
- "\n" +
- " ";
+ "\n" +
+ " ";
private static final String REQUEST1 = REQUEST1_HEADER + REQUEST1_CONTENT.getBytes().length + "\n\n" + REQUEST1_CONTENT;
- private static final String RESPONSE1 = "HTTP/1.1 200 OK\n" + "Content-Length: 13\n" + "Server: Jetty(" + Server.getVersion() + ")\n" + "\n" + "Hello world\n";
+ private static final String RESPONSE1 = "HTTP/1.1 200 OK\n" +
+ "Content-Length: 13\n" +
+ "Server: Jetty(" + Server.getVersion() + ")\n" +
+ "\n" +
+ "Hello world\n";
// Break the request up into three pieces, splitting the header.
private static final String FRAGMENT1 = REQUEST1.substring(0, 16);
@@ -104,7 +113,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
" 73 \n" +
" \n" +
" \n" +
- "\n";
+ "\n";
protected static final String RESPONSE2 =
"HTTP/1.1 200 OK\n" +
"Content-Type: text/xml;charset=iso-8859-1\n" +
@@ -143,9 +152,9 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
OutputStream os = client.getOutputStream();
os.write(("OPTIONS * HTTP/1.1\r\n" +
- "Host: " + _serverURI.getHost() + "\r\n" +
- "Connection: close\r\n" +
- "\r\n").getBytes(StandardCharsets.ISO_8859_1));
+ "Host: " + _serverURI.getHost() + "\r\n" +
+ "Connection: close\r\n" +
+ "\r\n").getBytes(StandardCharsets.ISO_8859_1));
os.flush();
// Read the response.
@@ -154,15 +163,20 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
assertThat(response, Matchers.containsString("HTTP/1.1 200 OK"));
assertThat(response, Matchers.containsString("Allow: GET"));
}
+ }
+ @Test
+ public void testGETStar() throws Exception
+ {
+ configureServer(new OptionsHandler());
try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
{
OutputStream os = client.getOutputStream();
os.write(("GET * HTTP/1.1\r\n" +
- "Host: " + _serverURI.getHost() + "\r\n" +
- "Connection: close\r\n" +
- "\r\n").getBytes(StandardCharsets.ISO_8859_1));
+ "Host: " + _serverURI.getHost() + "\r\n" +
+ "Connection: close\r\n" +
+ "\r\n").getBytes(StandardCharsets.ISO_8859_1));
os.flush();
// Read the response.
@@ -434,27 +448,22 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
{
OutputStream os = client.getOutputStream();
- //@checkstyle-disable-check : IllegalTokenText
- os.write(("GET /R2 HTTP/1.1\015\012" +
- "Host: localhost\015\012" +
- "Transfer-Encoding: chunked\015\012" +
- "Content-Type: text/plain\015\012" +
- "Connection: close\015\012" +
- "\015\012").getBytes());
- //@checkstyle-enable-check : IllegalTokenText
+
+ os.write(("GET /R2 HTTP/1.1\r\n" +
+ "Host: localhost\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "Content-Type: text/plain\r\n" +
+ "Connection: close\r\n" +
+ "\r\n").getBytes());
os.flush();
Thread.sleep(1000);
os.write(("5").getBytes());
Thread.sleep(1000);
- //@checkstyle-disable-check : IllegalTokenText
- os.write(("\015\012").getBytes());
- //@checkstyle-enable-check : IllegalTokenText
+ os.write(("\r\n").getBytes());
os.flush();
Thread.sleep(1000);
- //@checkstyle-disable-check : IllegalTokenText
- os.write(("ABCDE\015\012" +
- "0;\015\012\015\012").getBytes());
- //@checkstyle-enable-check : IllegalTokenText
+ os.write(("ABCDE\r\n" +
+ "0;\r\n\r\n").getBytes());
os.flush();
// Read the response.
@@ -472,14 +481,14 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
{
OutputStream os = client.getOutputStream();
//@checkstyle-disable-check : IllegalTokenText
- os.write(("GET /R2 HTTP/1.1\015\012" +
- "Host: localhost\015\012" +
- "Content-Length: 5\015\012" +
- "Content-Type: text/plain\015\012" +
- "Connection: close\015\012" +
- "\015\012" +
- "ABCDE\015\012" +
- "\015\012"
+ os.write(("GET /R2 HTTP/1.1\r\n" +
+ "Host: localhost\r\n" +
+ "Content-Length: 5\r\n" +
+ "Content-Type: text/plain\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "ABCDE\r\n" +
+ "\r\n"
//@checkstyle-enable-check : IllegalTokenText
).getBytes());
os.flush();
@@ -1136,26 +1145,26 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
//@checkstyle-disable-check : IllegalTokenText
os.write((
- "POST /R1 HTTP/1.1\015\012" +
+ "POST /R1 HTTP/1.1\r\n" +
"Host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\r\n" +
"content-type: text/plain; charset=utf-8\r\n" +
"content-length: 10\r\n" +
- "\015\012" +
+ "\r\n" +
"123456789\n" +
- "HEAD /R2 HTTP/1.1\015\012" +
- "Host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\015\012" +
+ "HEAD /R2 HTTP/1.1\r\n" +
+ "Host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\r\n" +
"content-type: text/plain; charset=utf-8\r\n" +
"content-length: 10\r\n" +
- "\015\012" +
+ "\r\n" +
"ABCDEFGHI\n" +
- "POST /R3 HTTP/1.1\015\012" +
- "Host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\015\012" +
+ "POST /R3 HTTP/1.1\r\n" +
+ "Host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\r\n" +
"content-type: text/plain; charset=utf-8\r\n" +
"content-length: 10\r\n" +
- "Connection: close\015\012" +
- "\015\012" +
+ "Connection: close\r\n" +
+ "\r\n" +
"abcdefghi\n"
//@checkstyle-enable-check : IllegalTokenText
).getBytes(StandardCharsets.ISO_8859_1));
@@ -1553,12 +1562,11 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
{
try
{
- byte[] bytes = (
- "GET / HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
- "Content-Length: " + cl + "\r\n" +
- "\r\n" +
- content).getBytes(StandardCharsets.ISO_8859_1);
+ byte[] bytes = ("GET / HTTP/1.1\r\n" +
+ "Host: localhost\r\n" +
+ "Content-Length: " + cl + "\r\n" +
+ "\r\n" +
+ content).getBytes(StandardCharsets.ISO_8859_1);
for (int i = 0; i < REQS; i++)
{
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestFixture.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestFixture.java
index 96a17208dd5..bd009b30d24 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestFixture.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestFixture.java
@@ -40,7 +40,8 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
public class HttpServerTestFixture
-{ // Useful constants
+{
+ // Useful constants
protected static final long PAUSE = 10L;
protected static final int LOOPS = 50;
@@ -186,6 +187,31 @@ public class HttpServerTestFixture
}
}
+
+ protected static class SendErrorHandler extends AbstractHandler
+ {
+ private final int code;
+ private final String message;
+
+ public SendErrorHandler()
+ {
+ this(500, null);
+ }
+
+ public SendErrorHandler(int code, String message)
+ {
+ this.code = code;
+ this.message = message;
+ }
+
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ baseRequest.setHandled(true);
+ response.sendError(code, message);
+ }
+ }
+
protected static class ReadExactHandler extends AbstractHandler.ErrorDispatchHandler
{
private int expected;
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java
index 81c89ae2331..001b7438437 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java
@@ -32,6 +32,8 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -42,6 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
public class LocalAsyncContextTest
{
+ public static final Logger LOG = Log.getLogger(LocalAsyncContextTest.class);
protected Server _server;
protected SuspendHandler _handler;
protected Connector _connector;
@@ -232,6 +235,7 @@ public class LocalAsyncContextTest
private synchronized String process(String content) throws Exception
{
+ LOG.debug("TEST process: {}", content);
reset();
String request = "GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
@@ -305,6 +309,7 @@ public class LocalAsyncContextTest
@Override
public void handle(String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException
{
+ LOG.debug("handle {} {}", baseRequest.getDispatcherType(), baseRequest);
if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType()))
{
if (_read > 0)
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java
index a872ebdc824..4cb4f63a48a 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java
@@ -35,6 +35,8 @@ import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import java.util.stream.Stream;
+import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
@@ -70,6 +72,8 @@ import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -664,65 +668,41 @@ public class ResponseTest
assertEquals("foo/bar; other=pq charset=utf-8 other=xyz;charset=utf-16", response.getContentType());
}
- @Test
- public void testStatusCodes() throws Exception
+ public static Stream sendErrorTestCodes()
{
- Response response = getResponse();
-
- response.sendError(404);
- assertEquals(404, response.getStatus());
- assertEquals("Not Found", response.getReason());
-
- response = getResponse();
-
- response.sendError(500, "Database Error");
- assertEquals(500, response.getStatus());
- assertEquals("Database Error", response.getReason());
- assertEquals("must-revalidate,no-cache,no-store", response.getHeader(HttpHeader.CACHE_CONTROL.asString()));
-
- response = getResponse();
-
- response.setStatus(200);
- assertEquals(200, response.getStatus());
- assertEquals(null, response.getReason());
-
- response = getResponse();
-
- response.sendError(406, "Super Nanny");
- assertEquals(406, response.getStatus());
- assertEquals("Super Nanny", response.getReason());
- assertEquals("must-revalidate,no-cache,no-store", response.getHeader(HttpHeader.CACHE_CONTROL.asString()));
+ List data = new ArrayList<>();
+ data.add(new Object[]{404, null, "Not Found"});
+ data.add(new Object[]{500, "Database Error", "Database Error"});
+ data.add(new Object[]{406, "Super Nanny", "Super Nanny"});
+ return data.stream();
}
- @Test
- public void testStatusCodesNoErrorHandler() throws Exception
+ @ParameterizedTest
+ @MethodSource(value = "sendErrorTestCodes")
+ public void testStatusCodes(int code, String message, String expectedMessage) throws Exception
+ {
+ Response response = getResponse();
+ assertThat(response.getHttpChannel().getState().handling(), is(HttpChannelState.Action.DISPATCH));
+
+ if (message == null)
+ response.sendError(code);
+ else
+ response.sendError(code, message);
+
+ assertTrue(response.getHttpOutput().isClosed());
+ assertEquals(code, response.getStatus());
+ assertEquals(null, response.getReason());
+ assertEquals(expectedMessage, response.getHttpChannel().getRequest().getAttribute(RequestDispatcher.ERROR_MESSAGE));
+ assertThat(response.getHttpChannel().getState().unhandle(), is(HttpChannelState.Action.SEND_ERROR));
+ assertThat(response.getHttpChannel().getState().unhandle(), is(HttpChannelState.Action.COMPLETE));
+ }
+
+ @ParameterizedTest
+ @MethodSource(value = "sendErrorTestCodes")
+ public void testStatusCodesNoErrorHandler(int code, String message, String expectedMessage) throws Exception
{
_server.removeBean(_server.getBean(ErrorHandler.class));
- Response response = getResponse();
-
- response.sendError(404);
- assertEquals(404, response.getStatus());
- assertEquals("Not Found", response.getReason());
-
- response = getResponse();
-
- response.sendError(500, "Database Error");
- assertEquals(500, response.getStatus());
- assertEquals("Database Error", response.getReason());
- assertThat(response.getHeader(HttpHeader.CACHE_CONTROL.asString()), Matchers.nullValue());
-
- response = getResponse();
-
- response.setStatus(200);
- assertEquals(200, response.getStatus());
- assertEquals(null, response.getReason());
-
- response = getResponse();
-
- response.sendError(406, "Super Nanny");
- assertEquals(406, response.getStatus());
- assertEquals("Super Nanny", response.getReason());
- assertThat(response.getHeader(HttpHeader.CACHE_CONTROL.asString()), Matchers.nullValue());
+ testStatusCodes(code, message, expectedMessage);
}
@Test
@@ -898,7 +878,7 @@ public class ResponseTest
assertTrue(!response.isCommitted());
assertTrue(!writer.checkError());
writer.print("");
- assertTrue(!writer.checkError());
+ // assertTrue(!writer.checkError()); // TODO check if this is correct? checkout does an open check and the print above closes
assertTrue(response.isCommitted());
}
@@ -1032,7 +1012,7 @@ public class ResponseTest
}
@Test
- public void testCookiesWithReset() throws Exception
+ public void testResetContent() throws Exception
{
Response response = getResponse();
@@ -1048,9 +1028,27 @@ public class ResponseTest
cookie2.setPath("/path");
response.addCookie(cookie2);
- //keep the cookies
- response.reset(true);
+ response.setContentType("some/type");
+ response.setContentLength(3);
+ response.setHeader(HttpHeader.EXPIRES,"never");
+ response.setHeader("SomeHeader", "SomeValue");
+
+ response.getOutputStream();
+
+ // reset the content
+ response.resetContent();
+
+ // check content is nulled
+ assertThat(response.getContentType(), nullValue());
+ assertThat(response.getContentLength(), is(-1L));
+ assertThat(response.getHeader(HttpHeader.EXPIRES.asString()), nullValue());
+ response.getWriter();
+
+ // check arbitrary header still set
+ assertThat(response.getHeader("SomeHeader"), is("SomeValue"));
+
+ // check cookies are still there
Enumeration set = response.getHttpFields().getValues("Set-Cookie");
assertNotNull(set);
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/NcsaRequestLogTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/NcsaRequestLogTest.java
index 6964b7c9ef9..e854f3f44f1 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/NcsaRequestLogTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/NcsaRequestLogTest.java
@@ -37,6 +37,7 @@ import org.eclipse.jetty.server.AbstractNCSARequestLog;
import org.eclipse.jetty.server.CustomRequestLog;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpChannelState;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.RequestLog;
@@ -44,6 +45,7 @@ import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
@@ -390,7 +392,7 @@ public class NcsaRequestLogTest
data.add(new Object[]{logType, new IOExceptionPartialHandler(), "/ioex", "\"GET /ioex HTTP/1.0\" 200"});
data.add(new Object[]{logType, new RuntimeExceptionHandler(), "/rtex", "\"GET /rtex HTTP/1.0\" 500"});
data.add(new Object[]{logType, new BadMessageHandler(), "/bad", "\"GET /bad HTTP/1.0\" 499"});
- data.add(new Object[]{logType, new AbortHandler(), "/bad", "\"GET /bad HTTP/1.0\" 488"});
+ data.add(new Object[]{logType, new AbortHandler(), "/bad", "\"GET /bad HTTP/1.0\" 500"});
data.add(new Object[]{logType, new AbortPartialHandler(), "/bad", "\"GET /bad HTTP/1.0\" 200"});
}
@@ -517,7 +519,9 @@ public class NcsaRequestLogTest
startServer();
makeRequest(requestPath);
- expectedLogEntry = "\"GET " + requestPath + " HTTP/1.0\" 200";
+ // If we abort, we can't write a 200 error page
+ if (!(testHandler instanceof AbortHandler))
+ expectedLogEntry = expectedLogEntry.replaceFirst(" [1-9][0-9][0-9]", " 200");
assertRequestLog(expectedLogEntry, _log);
}
@@ -577,6 +581,10 @@ public class NcsaRequestLogTest
{
try
{
+ while (baseRequest.getHttpChannel().getState().getState() != HttpChannelState.State.WAITING)
+ {
+ Thread.sleep(10);
+ }
baseRequest.setHandled(false);
testHandler.handle(target, baseRequest, request, response);
if (!baseRequest.isHandled())
@@ -584,18 +592,21 @@ public class NcsaRequestLogTest
}
catch (BadMessageException bad)
{
- response.sendError(bad.getCode());
+ response.sendError(bad.getCode(), bad.getReason());
}
catch (Exception e)
{
- response.sendError(500);
+ response.sendError(500, e.toString());
}
}
- catch (Throwable th)
+ catch (IOException | IllegalStateException th)
{
- throw new RuntimeException(th);
+ Log.getLog().ignore(th);
+ }
+ finally
+ {
+ ac.complete();
}
- ac.complete();
});
}
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SecuredRedirectHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SecuredRedirectHandlerTest.java
index 4dd9dfbfa1a..73d5193f262 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SecuredRedirectHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SecuredRedirectHandlerTest.java
@@ -266,6 +266,7 @@ public class SecuredRedirectHandlerTest
{
if (!"/".equals(target))
{
+ baseRequest.setHandled(true);
response.sendError(404);
return;
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SniSslConnectionFactoryTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SniSslConnectionFactoryTest.java
index 5c68b9ef802..27c5d89251e 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SniSslConnectionFactoryTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SniSslConnectionFactoryTest.java
@@ -20,7 +20,6 @@ package org.eclipse.jetty.server.ssl;
import java.io.File;
import java.io.FileNotFoundException;
-import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
@@ -42,6 +41,7 @@ import javax.net.ssl.SSLSocketFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
@@ -55,8 +55,8 @@ import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SocketCustomizationListener;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.util.IO;
-import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
@@ -65,9 +65,8 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.startsWith;
+import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
public class SniSslConnectionFactoryTest
{
@@ -81,23 +80,23 @@ public class SniSslConnectionFactoryTest
{
_server = new Server();
- HttpConfiguration http_config = new HttpConfiguration();
- http_config.setSecureScheme("https");
- http_config.setSecurePort(8443);
- http_config.setOutputBufferSize(32768);
- _httpsConfiguration = new HttpConfiguration(http_config);
+ HttpConfiguration httpConfig = new HttpConfiguration();
+ httpConfig.setSecureScheme("https");
+ httpConfig.setSecurePort(8443);
+ httpConfig.setOutputBufferSize(32768);
+ _httpsConfiguration = new HttpConfiguration(httpConfig);
SecureRequestCustomizer src = new SecureRequestCustomizer();
src.setSniHostCheck(true);
_httpsConfiguration.addCustomizer(src);
- _httpsConfiguration.addCustomizer((connector, httpConfig, request) ->
+ _httpsConfiguration.addCustomizer((connector, hc, request) ->
{
EndPoint endp = request.getHttpChannel().getEndPoint();
if (endp instanceof SslConnection.DecryptedEndPoint)
{
try
{
- SslConnection.DecryptedEndPoint ssl_endp = (SslConnection.DecryptedEndPoint)endp;
- SslConnection sslConnection = ssl_endp.getSslConnection();
+ SslConnection.DecryptedEndPoint sslEndp = (SslConnection.DecryptedEndPoint)endp;
+ SslConnection sslConnection = sslEndp.getSslConnection();
SSLEngine sslEngine = sslConnection.getSSLEngine();
SSLSession session = sslEngine.getSession();
for (Certificate c : session.getLocalCertificates())
@@ -224,6 +223,7 @@ public class SniSslConnectionFactoryTest
public void testSameConnectionRequestsForManyDomains() throws Exception
{
start("src/test/resources/keystore_sni.p12");
+ _server.setErrorHandler(new ErrorHandler());
SslContextFactory clientContextFactory = new SslContextFactory.Client(true);
clientContextFactory.start();
@@ -246,8 +246,8 @@ public class SniSslConnectionFactoryTest
output.flush();
InputStream input = sslSocket.getInputStream();
- String response = response(input);
- assertTrue(response.startsWith("HTTP/1.1 200 "));
+ HttpTester.Response response = HttpTester.parseResponse(input);
+ assertThat(response.getStatus(), is(200));
// Same socket, send a request for a different domain but same alias.
request =
@@ -256,9 +256,8 @@ public class SniSslConnectionFactoryTest
"\r\n";
output.write(request.getBytes(StandardCharsets.UTF_8));
output.flush();
-
- response = response(input);
- assertTrue(response.startsWith("HTTP/1.1 200 "));
+ response = HttpTester.parseResponse(input);
+ assertThat(response.getStatus(), is(200));
// Same socket, send a request for a different domain but different alias.
request =
@@ -268,9 +267,9 @@ public class SniSslConnectionFactoryTest
output.write(request.getBytes(StandardCharsets.UTF_8));
output.flush();
- response = response(input);
- assertThat(response, startsWith("HTTP/1.1 400 "));
- assertThat(response, containsString("Host does not match SNI"));
+ response = HttpTester.parseResponse(input);
+ assertThat(response.getStatus(), is(400));
+ assertThat(response.getContent(), containsString("Host does not match SNI"));
}
finally
{
@@ -303,8 +302,8 @@ public class SniSslConnectionFactoryTest
output.flush();
InputStream input = sslSocket.getInputStream();
- String response = response(input);
- assertTrue(response.startsWith("HTTP/1.1 200 "));
+ HttpTester.Response response = HttpTester.parseResponse(input);
+ assertThat(response.getStatus(), is(200));
// Now, on the same socket, send a request for a different valid domain.
request =
@@ -314,8 +313,8 @@ public class SniSslConnectionFactoryTest
output.write(request.getBytes(StandardCharsets.UTF_8));
output.flush();
- response = response(input);
- assertTrue(response.startsWith("HTTP/1.1 200 "));
+ response = HttpTester.parseResponse(input);
+ assertThat(response.getStatus(), is(200));
// Now make a request for an invalid domain for this connection.
request =
@@ -325,9 +324,9 @@ public class SniSslConnectionFactoryTest
output.write(request.getBytes(StandardCharsets.UTF_8));
output.flush();
- response = response(input);
- assertTrue(response.startsWith("HTTP/1.1 400 "));
- assertThat(response, Matchers.containsString("Host does not match SNI"));
+ response = HttpTester.parseResponse(input);
+ assertThat(response.getStatus(), is(400));
+ assertThat(response.getContent(), containsString("Host does not match SNI"));
}
finally
{
@@ -335,22 +334,6 @@ public class SniSslConnectionFactoryTest
}
}
- private String response(InputStream input) throws IOException
- {
- Utf8StringBuilder buffer = new Utf8StringBuilder();
- int crlfs = 0;
- while (true)
- {
- int read = input.read();
- assertTrue(read >= 0);
- buffer.append((byte)read);
- crlfs = (read == '\r' || read == '\n') ? crlfs + 1 : 0;
- if (crlfs == 4)
- break;
- }
- return buffer.toString();
- }
-
private String getResponse(String host, String cn) throws Exception
{
String response = getResponse(host, host, cn);
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java
index 1ae360927b5..6cc49bd60da 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java
@@ -50,6 +50,7 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
@@ -478,7 +479,7 @@ public class AsyncContextTest
assertThat("error servlet", responseBody, containsString("ERROR: /error"));
assertThat("error servlet", responseBody, containsString("PathInfo= /500"));
- assertThat("error servlet", responseBody, containsString("EXCEPTION: java.lang.RuntimeException: TEST"));
+ assertThat("error servlet", responseBody, not(containsString("EXCEPTION: ")));
}
private class DispatchingRunnable implements Runnable
@@ -552,7 +553,7 @@ public class AsyncContextTest
@Override
public void onTimeout(AsyncEvent event) throws IOException
{
- throw new RuntimeException("TEST");
+ throw new RuntimeException("BAD EXPIRE");
}
@Override
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java
index 50fc3a3f2b1..6d6bb5824ed 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java
@@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.io.QuietException;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.QuietServletException;
import org.eclipse.jetty.server.Server;
@@ -42,6 +43,7 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class AsyncListenerTest
@@ -140,7 +142,7 @@ public class AsyncListenerTest
test_StartAsync_Throw_OnError(event ->
{
HttpServletResponse response = (HttpServletResponse)event.getAsyncContext().getResponse();
- response.sendError(HttpStatus.BAD_GATEWAY_502);
+ response.sendError(HttpStatus.BAD_GATEWAY_502, "Message!!!");
});
String httpResponse = connector.getResponse(
"GET /ctx/path HTTP/1.1\r\n" +
@@ -148,7 +150,8 @@ public class AsyncListenerTest
"Connection: close\r\n" +
"\r\n");
assertThat(httpResponse, containsString("HTTP/1.1 502 "));
- assertThat(httpResponse, containsString(TestRuntimeException.class.getName()));
+ assertThat(httpResponse, containsString("Message!!!"));
+ assertThat(httpResponse, not(containsString(TestRuntimeException.class.getName())));
}
@Test
@@ -191,7 +194,7 @@ public class AsyncListenerTest
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
AsyncContext asyncContext = request.startAsync();
- asyncContext.setTimeout(0);
+ asyncContext.setTimeout(10000);
asyncContext.addListener(new AsyncListenerAdapter()
{
@Override
@@ -268,7 +271,8 @@ public class AsyncListenerTest
"Connection: close\r\n" +
"\r\n");
assertThat(httpResponse, containsString("HTTP/1.1 500 "));
- assertThat(httpResponse, containsString(TestRuntimeException.class.getName()));
+ assertThat(httpResponse, containsString("AsyncContext timeout"));
+ assertThat(httpResponse, not(containsString(TestRuntimeException.class.getName())));
}
@Test
@@ -292,6 +296,7 @@ public class AsyncListenerTest
{
HttpServletResponse response = (HttpServletResponse)event.getAsyncContext().getResponse();
response.sendError(HttpStatus.BAD_GATEWAY_502);
+ event.getAsyncContext().complete();
});
String httpResponse = connector.getResponse(
"GET / HTTP/1.1\r\n" +
@@ -384,7 +389,7 @@ public class AsyncListenerTest
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
AsyncContext asyncContext = request.startAsync();
- asyncContext.setTimeout(0);
+ asyncContext.setTimeout(10000);
asyncContext.addListener(new AsyncListenerAdapter()
{
@Override
@@ -447,7 +452,7 @@ public class AsyncListenerTest
}
// Unique named RuntimeException to help during debugging / assertions.
- public static class TestRuntimeException extends RuntimeException
+ public static class TestRuntimeException extends RuntimeException implements QuietException
{
}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletIOTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletIOTest.java
index 3ea4c804437..b80394f61f6 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletIOTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletIOTest.java
@@ -52,6 +52,7 @@ import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
@@ -305,6 +306,7 @@ public class AsyncServletIOTest
request.append(s).append("w=").append(w);
s = '&';
}
+ LOG.debug("process {} {}", request.toString(), BufferUtil.toDetailString(BufferUtil.toBuffer(content)));
request.append(" HTTP/1.1\r\n")
.append("Host: localhost\r\n")
@@ -816,13 +818,15 @@ public class AsyncServletIOTest
// wait until server is ready
_servletStolenAsyncRead.ready.await();
final CountDownLatch wait = new CountDownLatch(1);
-
+ final CountDownLatch held = new CountDownLatch(1);
// Stop any dispatches until we want them
+
UnaryOperator old = _wQTP.wrapper.getAndSet(r ->
() ->
{
try
{
+ held.countDown();
wait.await();
r.run();
}
@@ -836,7 +840,9 @@ public class AsyncServletIOTest
// We are an unrelated thread, let's mess with the input stream
ServletInputStream sin = _servletStolenAsyncRead.listener.in;
sin.setReadListener(_servletStolenAsyncRead.listener);
+
// thread should be dispatched to handle, but held by our wQTP wait.
+ assertTrue(held.await(10, TimeUnit.SECONDS));
// Let's steal our read
assertTrue(sin.isReady());
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java
index d197aa3a57b..571d8d76a7a 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java
@@ -265,7 +265,6 @@ public class AsyncServletTest
"start",
"onTimeout",
"error",
- "onError",
"ERROR /ctx/error/custom",
"!initial",
"onComplete"));
@@ -273,44 +272,6 @@ public class AsyncServletTest
assertContains("ERROR DISPATCH", response);
}
- @Test
- public void testStartOnTimeoutErrorComplete() throws Exception
- {
- String response = process("start=200&timeout=error&error=complete", null);
- assertThat(response, startsWith("HTTP/1.1 200 OK"));
- assertThat(__history, contains(
- "REQUEST /ctx/path/info",
- "initial",
- "start",
- "onTimeout",
- "error",
- "onError",
- "complete",
- "onComplete"));
-
- assertContains("COMPLETED", response);
- }
-
- @Test
- public void testStartOnTimeoutErrorDispatch() throws Exception
- {
- String response = process("start=200&timeout=error&error=dispatch", null);
- assertThat(response, startsWith("HTTP/1.1 200 OK"));
- assertThat(__history, contains(
- "REQUEST /ctx/path/info",
- "initial",
- "start",
- "onTimeout",
- "error",
- "onError",
- "dispatch",
- "ASYNC /ctx/path/info",
- "!initial",
- "onComplete"));
-
- assertContains("DISPATCHED", response);
- }
-
@Test
public void testStartOnTimeoutComplete() throws Exception
{
@@ -526,8 +487,10 @@ public class AsyncServletTest
"onStartAsync",
"start",
"onTimeout",
+ "ERROR /ctx/path/error",
+ "!initial",
"onComplete")); // Error Page Loop!
- assertContains("HTTP ERROR 500", response);
+ assertContains("AsyncContext timeout", response);
}
@Test
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/CustomRequestLogTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/CustomRequestLogTest.java
index a422cf0480f..3c7ba9a7a55 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/CustomRequestLogTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/CustomRequestLogTest.java
@@ -85,7 +85,8 @@ public class CustomRequestLogTest
_connector.getResponse("GET /context/servlet/info HTTP/1.0\n\n");
String log = _entries.poll(5, TimeUnit.SECONDS);
- assertThat(log, is("Filename: " + _tmpDir + File.separator + "servlet" + File.separator + "info"));
+ String expected = new File(_tmpDir + File.separator + "servlet" + File.separator + "info").getCanonicalPath();
+ assertThat(log, is("Filename: " + expected));
}
@Test
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ErrorPageTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ErrorPageTest.java
index 899cc3d0169..0d8db7f6e55 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ErrorPageTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ErrorPageTest.java
@@ -20,8 +20,22 @@ package org.eclipse.jetty.servlet;
import java.io.IOException;
import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.EnumSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -29,8 +43,12 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpChannelState;
import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
@@ -40,43 +58,71 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class ErrorPageTest
{
private Server _server;
private LocalConnector _connector;
private StacklessLogging _stackless;
+ private static CountDownLatch __asyncSendErrorCompleted;
+ private ErrorPageErrorHandler _errorPageErrorHandler;
@BeforeEach
public void init() throws Exception
{
_server = new Server();
_connector = new LocalConnector(_server);
+ _server.addConnector(_connector);
+
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS);
- _server.addConnector(_connector);
_server.setHandler(context);
context.setContextPath("/");
+ context.addFilter(SingleDispatchFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
+
context.addServlet(DefaultServlet.class, "/");
context.addServlet(FailServlet.class, "/fail/*");
context.addServlet(FailClosedServlet.class, "/fail-closed/*");
context.addServlet(ErrorServlet.class, "/error/*");
context.addServlet(AppServlet.class, "/app/*");
context.addServlet(LongerAppServlet.class, "/longer.app/*");
+ context.addServlet(SyncSendErrorServlet.class, "/sync/*");
+ context.addServlet(AsyncSendErrorServlet.class, "/async/*");
+ context.addServlet(NotEnoughServlet.class, "/notenough/*");
+ context.addServlet(DeleteServlet.class, "/delete/*");
+ context.addServlet(ErrorAndStatusServlet.class, "/error-and-status/*");
- ErrorPageErrorHandler error = new ErrorPageErrorHandler();
- context.setErrorHandler(error);
- error.addErrorPage(599, "/error/599");
- error.addErrorPage(400, "/error/400");
+ HandlerWrapper noopHandler = new HandlerWrapper()
+ {
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ if (target.startsWith("/noop"))
+ return;
+ else
+ super.handle(target, baseRequest, request, response);
+ }
+ };
+ context.insertHandler(noopHandler);
+
+ _errorPageErrorHandler = new ErrorPageErrorHandler();
+ context.setErrorHandler(_errorPageErrorHandler);
+ _errorPageErrorHandler.addErrorPage(595, "/error/595");
+ _errorPageErrorHandler.addErrorPage(597, "/sync");
+ _errorPageErrorHandler.addErrorPage(599, "/error/599");
+ _errorPageErrorHandler.addErrorPage(400, "/error/400");
// error.addErrorPage(500,"/error/500");
- error.addErrorPage(IllegalStateException.class.getCanonicalName(), "/error/TestException");
- error.addErrorPage(BadMessageException.class, "/error/BadMessageException");
- error.addErrorPage(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE, "/error/GlobalErrorPage");
+ _errorPageErrorHandler.addErrorPage(IllegalStateException.class.getCanonicalName(), "/error/TestException");
+ _errorPageErrorHandler.addErrorPage(BadMessageException.class, "/error/BadMessageException");
+ _errorPageErrorHandler.addErrorPage(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE, "/error/GlobalErrorPage");
_server.start();
_stackless = new StacklessLogging(ServletHandler.class);
+
+ __asyncSendErrorCompleted = new CountDownLatch(1);
}
@AfterEach
@@ -87,6 +133,101 @@ public class ErrorPageTest
_server.join();
}
+ @Test
+ void testErrorOverridesStatus() throws Exception
+ {
+ String response = _connector.getResponse("GET /error-and-status/anything HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 594 594"));
+ assertThat(response, Matchers.containsString("ERROR_PAGE: /GlobalErrorPage"));
+ assertThat(response, Matchers.containsString("ERROR_MESSAGE: custom get error"));
+ assertThat(response, Matchers.containsString("ERROR_CODE: 594"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION: null"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION_TYPE: null"));
+ assertThat(response, Matchers.containsString("ERROR_SERVLET: org.eclipse.jetty.servlet.ErrorPageTest$ErrorAndStatusServlet-"));
+ assertThat(response, Matchers.containsString("ERROR_REQUEST_URI: /error-and-status/anything"));
+ }
+
+ @Test
+ void testHttp204CannotHaveBody() throws Exception
+ {
+ String response = _connector.getResponse("GET /fail/code?code=204 HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 204 No Content"));
+ assertThat(response, not(Matchers.containsString("DISPATCH: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_PAGE: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_CODE: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_EXCEPTION: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_EXCEPTION_TYPE: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_SERVLET: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_REQUEST_URI: ")));
+ }
+
+ @Test
+ void testDeleteCannotHaveBody() throws Exception
+ {
+ String response = _connector.getResponse("DELETE /delete/anything HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 595 595"));
+ assertThat(response, not(Matchers.containsString("DISPATCH: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_PAGE: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_MESSAGE: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_CODE: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_EXCEPTION: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_EXCEPTION_TYPE: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_SERVLET: ")));
+ assertThat(response, not(Matchers.containsString("ERROR_REQUEST_URI: ")));
+
+ assertThat(response, not(containsString("This shouldn't be seen")));
+ }
+
+ @Test
+ void testGenerateAcceptableResponse_noAcceptHeader() throws Exception
+ {
+ // no global error page here
+ _errorPageErrorHandler.getErrorPages().remove(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE);
+
+ String response = _connector.getResponse("GET /fail/code?code=598 HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 598 598"));
+ assertThat(response, Matchers.containsString("Error 598"));
+ assertThat(response, Matchers.containsString("HTTP ERROR 598"));
+ assertThat(response, Matchers.containsString("/fail/code"));
+ }
+
+ @Test
+ void testGenerateAcceptableResponse_htmlAcceptHeader() throws Exception
+ {
+ // no global error page here
+ _errorPageErrorHandler.getErrorPages().remove(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE);
+
+ // even when text/html is not the 1st content type, a html error page should still be generated
+ String response = _connector.getResponse("GET /fail/code?code=598 HTTP/1.0\r\n" +
+ "Accept: application/bytes,text/html\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 598 598"));
+ assertThat(response, Matchers.containsString("Error 598"));
+ assertThat(response, Matchers.containsString("HTTP ERROR 598"));
+ assertThat(response, Matchers.containsString("/fail/code"));
+ }
+
+ @Test
+ void testGenerateAcceptableResponse_noHtmlAcceptHeader() throws Exception
+ {
+ // no global error page here
+ _errorPageErrorHandler.getErrorPages().remove(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE);
+
+ String response = _connector.getResponse("GET /fail/code?code=598 HTTP/1.0\r\n" +
+ "Accept: application/bytes\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 598 598"));
+ assertThat(response, not(Matchers.containsString("Error 598")));
+ assertThat(response, not(Matchers.containsString("HTTP ERROR 598")));
+ assertThat(response, not(Matchers.containsString("/fail/code")));
+ }
+
+ @Test
+ void testNestedSendErrorDoesNotLoop() throws Exception
+ {
+ String response = _connector.getResponse("GET /fail/code?code=597 HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 597 597"));
+ assertThat(response, not(Matchers.containsString("time this error page is being accessed")));
+ }
+
@Test
public void testSendErrorClosedResponse() throws Exception
{
@@ -167,7 +308,7 @@ public class ErrorPageTest
try (StacklessLogging ignore = new StacklessLogging(Dispatcher.class))
{
String response = _connector.getResponse("GET /app?baa=%88%A4 HTTP/1.0\r\n\r\n");
- assertThat(response, Matchers.containsString("HTTP/1.1 400 Bad query encoding"));
+ assertThat(response, Matchers.containsString("HTTP/1.1 400 Bad Request"));
assertThat(response, Matchers.containsString("ERROR_PAGE: /BadMessageException"));
assertThat(response, Matchers.containsString("ERROR_MESSAGE: Bad query encoding"));
assertThat(response, Matchers.containsString("ERROR_CODE: 400"));
@@ -179,6 +320,94 @@ public class ErrorPageTest
}
}
+ @Test
+ public void testAsyncErrorPageDSC() throws Exception
+ {
+ try (StacklessLogging ignore = new StacklessLogging(Dispatcher.class))
+ {
+ String response = _connector.getResponse("GET /async/info?mode=DSC HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 599 599"));
+ assertThat(response, Matchers.containsString("ERROR_PAGE: /599"));
+ assertThat(response, Matchers.containsString("ERROR_CODE: 599"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION: null"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION_TYPE: null"));
+ assertThat(response, Matchers.containsString("ERROR_SERVLET: org.eclipse.jetty.servlet.ErrorPageTest$AsyncSendErrorServlet-"));
+ assertThat(response, Matchers.containsString("ERROR_REQUEST_URI: /async/info"));
+ assertTrue(__asyncSendErrorCompleted.await(10, TimeUnit.SECONDS));
+ }
+ }
+
+ @Test
+ public void testAsyncErrorPageSDC() throws Exception
+ {
+ try (StacklessLogging ignore = new StacklessLogging(Dispatcher.class))
+ {
+ String response = _connector.getResponse("GET /async/info?mode=SDC HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 599 599"));
+ assertThat(response, Matchers.containsString("ERROR_PAGE: /599"));
+ assertThat(response, Matchers.containsString("ERROR_CODE: 599"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION: null"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION_TYPE: null"));
+ assertThat(response, Matchers.containsString("ERROR_SERVLET: org.eclipse.jetty.servlet.ErrorPageTest$AsyncSendErrorServlet-"));
+ assertThat(response, Matchers.containsString("ERROR_REQUEST_URI: /async/info"));
+ assertTrue(__asyncSendErrorCompleted.await(10, TimeUnit.SECONDS));
+ }
+ }
+
+ @Test
+ public void testAsyncErrorPageSCD() throws Exception
+ {
+ try (StacklessLogging ignore = new StacklessLogging(Dispatcher.class))
+ {
+ String response = _connector.getResponse("GET /async/info?mode=SCD HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 599 599"));
+ assertThat(response, Matchers.containsString("ERROR_PAGE: /599"));
+ assertThat(response, Matchers.containsString("ERROR_CODE: 599"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION: null"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION_TYPE: null"));
+ assertThat(response, Matchers.containsString("ERROR_SERVLET: org.eclipse.jetty.servlet.ErrorPageTest$AsyncSendErrorServlet-"));
+ assertThat(response, Matchers.containsString("ERROR_REQUEST_URI: /async/info"));
+ assertTrue(__asyncSendErrorCompleted.await(10, TimeUnit.SECONDS));
+ }
+ }
+
+ @Test
+ public void testNoop() throws Exception
+ {
+ String response = _connector.getResponse("GET /noop/info HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 404 Not Found"));
+ assertThat(response, Matchers.containsString("DISPATCH: ERROR"));
+ assertThat(response, Matchers.containsString("ERROR_PAGE: /GlobalErrorPage"));
+ assertThat(response, Matchers.containsString("ERROR_CODE: 404"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION: null"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION_TYPE: null"));
+ assertThat(response, Matchers.containsString("ERROR_SERVLET: org.eclipse.jetty.servlet.DefaultServlet-"));
+ assertThat(response, Matchers.containsString("ERROR_REQUEST_URI: /noop/info"));
+ }
+
+ @Test
+ public void testNotEnough() throws Exception
+ {
+ String response = _connector.getResponse("GET /notenough/info HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 500 Server Error"));
+ assertThat(response, Matchers.containsString("DISPATCH: ERROR"));
+ assertThat(response, Matchers.containsString("ERROR_PAGE: /GlobalErrorPage"));
+ assertThat(response, Matchers.containsString("ERROR_CODE: 500"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION: null"));
+ assertThat(response, Matchers.containsString("ERROR_EXCEPTION_TYPE: null"));
+ assertThat(response, Matchers.containsString("ERROR_SERVLET: org.eclipse.jetty.servlet.ErrorPageTest$NotEnoughServlet-"));
+ assertThat(response, Matchers.containsString("ERROR_REQUEST_URI: /notenough/info"));
+ }
+
+ @Test
+ public void testNotEnoughCommitted() throws Exception
+ {
+ String response = _connector.getResponse("GET /notenough/info?commit=true HTTP/1.0\r\n\r\n");
+ assertThat(response, Matchers.containsString("HTTP/1.1 200 OK"));
+ assertThat(response, Matchers.containsString("Content-Length: 1000"));
+ assertThat(response, Matchers.endsWith("SomeBytes"));
+ }
+
public static class AppServlet extends HttpServlet implements Servlet
{
@Override
@@ -198,6 +427,112 @@ public class ErrorPageTest
}
}
+ public static class SyncSendErrorServlet extends HttpServlet implements Servlet
+ {
+ public static final AtomicInteger COUNTER = new AtomicInteger();
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ int count = COUNTER.incrementAndGet();
+
+ PrintWriter writer = response.getWriter();
+ writer.println("this is the " + count + " time this error page is being accessed");
+ response.sendError(597, "loop #" + count);
+ }
+ }
+
+ public static class AsyncSendErrorServlet extends HttpServlet implements Servlet
+ {
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ try
+ {
+ final CountDownLatch hold = new CountDownLatch(1);
+ final String mode = request.getParameter("mode");
+ switch(mode)
+ {
+ case "DSC":
+ case "SDC":
+ case "SCD":
+ break;
+ default:
+ throw new IllegalStateException(mode);
+ }
+
+ final boolean lateComplete = "true".equals(request.getParameter("latecomplete"));
+ AsyncContext async = request.startAsync();
+ async.start(() ->
+ {
+ try
+ {
+ switch(mode)
+ {
+ case "SDC":
+ response.sendError(599);
+ break;
+ case "SCD":
+ response.sendError(599);
+ async.complete();
+ break;
+ default:
+ break;
+ }
+
+ // Complete after original servlet
+ hold.countDown();
+
+ // Wait until request async waiting
+ while (Request.getBaseRequest(request).getHttpChannelState().getState() == HttpChannelState.State.HANDLING)
+ {
+ try
+ {
+ Thread.sleep(10);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ try
+ {
+ switch (mode)
+ {
+ case "DSC":
+ response.sendError(599);
+ async.complete();
+ break;
+ case "SDC":
+ async.complete();
+ break;
+ default:
+ break;
+ }
+ }
+ catch(IllegalStateException e)
+ {
+ Log.getLog().ignore(e);
+ }
+ finally
+ {
+ __asyncSendErrorCompleted.countDown();
+ }
+ }
+ catch (IOException e)
+ {
+ Log.getLog().warn(e);
+ }
+ });
+ hold.await();
+ }
+ catch (InterruptedException e)
+ {
+ throw new ServletException(e);
+ }
+ }
+ }
+
public static class FailServlet extends HttpServlet implements Servlet
{
@Override
@@ -225,16 +560,51 @@ public class ErrorPageTest
}
catch (Throwable ignore)
{
- // no opEchoSocket
+ Log.getLog().ignore(ignore);
}
}
}
+ public static class ErrorAndStatusServlet extends HttpServlet implements Servlet
+ {
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ response.sendError(594, "custom get error");
+ response.setStatus(200);
+ }
+ }
+
+ public static class DeleteServlet extends HttpServlet implements Servlet
+ {
+ @Override
+ protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ response.getWriter().append("This shouldn't be seen");
+ response.sendError(595, "custom delete");
+ }
+ }
+
+ public static class NotEnoughServlet extends HttpServlet implements Servlet
+ {
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ response.setContentLength(1000);
+ response.getOutputStream().write("SomeBytes".getBytes(StandardCharsets.UTF_8));
+ if (Boolean.parseBoolean(request.getParameter("commit")))
+ response.flushBuffer();
+ }
+ }
+
public static class ErrorServlet extends HttpServlet implements Servlet
{
@Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
+ if (request.getDispatcherType() != DispatcherType.ERROR && request.getDispatcherType() != DispatcherType.ASYNC)
+ throw new IllegalStateException("Bad Dispatcher Type " + request.getDispatcherType());
+
PrintWriter writer = response.getWriter();
writer.println("DISPATCH: " + request.getDispatcherType().name());
writer.println("ERROR_PAGE: " + request.getPathInfo());
@@ -247,4 +617,55 @@ public class ErrorPageTest
writer.println("getParameterMap()= " + request.getParameterMap());
}
}
+
+ public static class SingleDispatchFilter implements Filter
+ {
+ ConcurrentMap dispatches = new ConcurrentHashMap<>();
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException
+ {
+
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
+ {
+ final Integer key = request.hashCode();
+ Thread current = Thread.currentThread();
+ final Thread existing = dispatches.putIfAbsent(key, current);
+ if (existing != null && existing != current)
+ {
+ System.err.println("DOUBLE DISPATCH OF REQUEST!!!!!!!!!!!!!!!!!!");
+ System.err.println("Thread " + existing + " :");
+ for (StackTraceElement element : existing.getStackTrace())
+ {
+ System.err.println("\tat " + element);
+ }
+ IllegalStateException ex = new IllegalStateException();
+ ex.printStackTrace();
+ response.flushBuffer();
+ throw ex;
+ }
+
+ try
+ {
+ chain.doFilter(request, response);
+ }
+ finally
+ {
+ if (existing == null)
+ {
+ if (!dispatches.remove(key, current))
+ throw new IllegalStateException();
+ }
+ }
+ }
+
+ @Override
+ public void destroy()
+ {
+
+ }
+ }
}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java
index cf8e7d59261..1362ac6f4d4 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java
@@ -153,7 +153,10 @@ public class GzipHandlerTest
response.setHeader("ETag", __contentETag);
String ifnm = req.getHeader("If-None-Match");
if (ifnm != null && ifnm.equals(__contentETag))
- response.sendError(304);
+ {
+ response.setStatus(304);
+ response.flushBuffer();
+ }
else
{
PrintWriter writer = response.getWriter();
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java
index fcdff1bdec8..d15f57dc3cc 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java
@@ -501,7 +501,16 @@ public class DoSFilter implements Filter
{
if (LOG.isDebugEnabled())
LOG.debug("Timing out {}", request);
- response.sendError(HttpStatus.SERVICE_UNAVAILABLE_503);
+ try
+ {
+ response.sendError(HttpStatus.SERVICE_UNAVAILABLE_503);
+ }
+ catch (IllegalStateException ise)
+ {
+ LOG.ignore(ise);
+ // abort instead
+ response.sendError(-1);
+ }
}
catch (Throwable x)
{
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java
index a0eceef6307..452c1be848c 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java
@@ -440,6 +440,7 @@ public class BufferUtil
*
* @param to Buffer is flush mode
* @param b byte to append
+ * @throws BufferOverflowException if unable to append buffer due to space limits
*/
public static void append(ByteBuffer to, byte b)
{
@@ -1103,20 +1104,20 @@ public class BufferUtil
for (int i = 0; i < buffer.position(); i++)
{
appendContentChar(buf, buffer.get(i));
- if (i == 16 && buffer.position() > 32)
+ if (i == 8 && buffer.position() > 16)
{
buf.append("...");
- i = buffer.position() - 16;
+ i = buffer.position() - 8;
}
}
buf.append("<<<");
for (int i = buffer.position(); i < buffer.limit(); i++)
{
appendContentChar(buf, buffer.get(i));
- if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
+ if (i == buffer.position() + 24 && buffer.limit() > buffer.position() + 48)
{
buf.append("...");
- i = buffer.limit() - 16;
+ i = buffer.limit() - 24;
}
}
buf.append(">>>");
@@ -1125,10 +1126,10 @@ public class BufferUtil
for (int i = limit; i < buffer.capacity(); i++)
{
appendContentChar(buf, buffer.get(i));
- if (i == limit + 16 && buffer.capacity() > limit + 32)
+ if (i == limit + 8 && buffer.capacity() > limit + 16)
{
buf.append("...");
- i = buffer.capacity() - 16;
+ i = buffer.capacity() - 8;
}
}
buffer.limit(limit);
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
index c2d77760c08..41f02b80e8b 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
@@ -171,10 +171,11 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
if (LOG.isDebugEnabled())
LOG.debug("Stopping {}", this);
+ super.doStop();
+
removeBean(_tryExecutor);
_tryExecutor = TryExecutor.NO_TRY;
- super.doStop();
// Signal the Runner threads that we are stopping
int threads = _counts.getAndSetHi(Integer.MIN_VALUE);
diff --git a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketConnectionStatsTest.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketConnectionStatsTest.java
index 41e79c01b86..148720950c4 100644
--- a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketConnectionStatsTest.java
+++ b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketConnectionStatsTest.java
@@ -176,4 +176,4 @@ public class WebSocketConnectionStatsTest
assertThat("stats.sendBytes", statistics.getSentBytes(), is(expectedSent));
assertThat("stats.receivedBytes", statistics.getReceivedBytes(), is(expectedReceived));
}
-}
\ No newline at end of file
+}
diff --git a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketNegotiationTest.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketNegotiationTest.java
index 9c23e097ccb..27ec3c2c45a 100644
--- a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketNegotiationTest.java
+++ b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketNegotiationTest.java
@@ -115,7 +115,7 @@ public class WebSocketNegotiationTest
client.getOutputStream().write(upgradeRequest.getBytes(ISO_8859_1));
String response = getUpgradeResponse(client.getInputStream());
- assertThat(response, containsString("400 Missing request header 'Sec-WebSocket-Key'"));
+ assertThat(response, containsString("400 "));
}
protected static HttpFields newUpgradeRequest(String extensions)
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketInvalidVersionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketInvalidVersionTest.java
index 105de580dc2..36989de4607 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketInvalidVersionTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketInvalidVersionTest.java
@@ -89,6 +89,6 @@ public class WebSocketInvalidVersionTest
connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
});
assertThat(x.getCause(), instanceOf(UpgradeException.class));
- assertThat(x.getMessage(), containsString("400 Unsupported websocket version specification"));
+ assertThat(x.getMessage(), containsString("400 "));
}
}
diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/BadAppTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/BadAppTests.java
index 190bc381743..9248a2dc5e4 100644
--- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/BadAppTests.java
+++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/BadAppTests.java
@@ -108,8 +108,8 @@ public class BadAppTests extends AbstractDistributionTest
startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/badapp/");
assertEquals(HttpStatus.SERVICE_UNAVAILABLE_503, response.getStatus());
- assertThat(response.getContentAsString(), containsString("Unavailable"));
- assertThat(response.getContentAsString(), containsString("Problem accessing /badapp/"));
+ assertThat(response.getContentAsString(), containsString("HTTP ERROR 503 Service Unavailable "));
+ assertThat(response.getContentAsString(), containsString("URI: /badapp/ "));
}
}
}
@@ -148,8 +148,8 @@ public class BadAppTests extends AbstractDistributionTest
startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port + "/badapp/");
assertEquals(HttpStatus.SERVICE_UNAVAILABLE_503, response.getStatus());
- assertThat(response.getContentAsString(), containsString("Unavailable"));
- assertThat(response.getContentAsString(), containsString("Problem accessing /badapp/"));
+ assertThat(response.getContentAsString(), containsString("HTTP ERROR 503 Service Unavailable "));
+ assertThat(response.getContentAsString(), containsString("URI: /badapp/ "));
}
}
}
From 149d9d486227a9f18cba19e8d307ff0e5197ed9c Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Mon, 26 Aug 2019 13:40:32 -0500
Subject: [PATCH 25/55] Fixes #4020 - Revert ExtensionFactory change to
interface.
+ The change in commit 30dc103a129d08304e1f1a99a84c045049de305d
was done to allow the InflaterPool and DeflaterPool
to be managed by the Jetty lifecycle.
+ This restore the original abstract class ExtensionFactory.
+ Had to break the traditional LifeCycle usage for a more
non-traditional one in order to both, not break this existing
API, and not introduce jetty-util to the webapp classloader.
+ This will restore API / binary compatibility for other
projects, like spring-boot.
Signed-off-by: Joakim Erdfelt
---
.../api/extensions/ExtensionFactory.java | 58 ++++++++++++---
.../extensions/WebSocketExtensionFactory.java | 71 ++++++++++++++++++-
2 files changed, 118 insertions(+), 11 deletions(-)
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java
index eae3dd3fbe6..8d46d60a5eb 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java
@@ -18,22 +18,64 @@
package org.eclipse.jetty.websocket.api.extensions;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
+import java.util.ServiceLoader;
import java.util.Set;
-public interface ExtensionFactory extends Iterable>
+public abstract class ExtensionFactory implements Iterable>
{
- Map> getAvailableExtensions();
+ private ServiceLoader extensionLoader = ServiceLoader.load(Extension.class);
+ private Map> availableExtensions;
- Class extends Extension> getExtension(String name);
+ public ExtensionFactory()
+ {
+ availableExtensions = new HashMap<>();
+ for (Extension ext : extensionLoader)
+ {
+ if (ext != null)
+ {
+ availableExtensions.put(ext.getName(), ext.getClass());
+ }
+ }
+ }
- Set getExtensionNames();
+ public Map> getAvailableExtensions()
+ {
+ return availableExtensions;
+ }
- boolean isAvailable(String name);
+ public Class extends Extension> getExtension(String name)
+ {
+ return availableExtensions.get(name);
+ }
- Extension newInstance(ExtensionConfig config);
+ public Set getExtensionNames()
+ {
+ return availableExtensions.keySet();
+ }
- void register(String name, Class extends Extension> extension);
+ public boolean isAvailable(String name)
+ {
+ return availableExtensions.containsKey(name);
+ }
- void unregister(String name);
+ @Override
+ public Iterator> iterator()
+ {
+ return availableExtensions.values().iterator();
+ }
+
+ public abstract Extension newInstance(ExtensionConfig config);
+
+ public void register(String name, Class extends Extension> extension)
+ {
+ availableExtensions.put(name, extension);
+ }
+
+ public void unregister(String name)
+ {
+ availableExtensions.remove(name);
+ }
}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
index f382d687afa..706429567b8 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
@@ -27,6 +27,7 @@ import java.util.zip.Deflater;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.compression.CompressionPool;
import org.eclipse.jetty.util.compression.DeflaterPool;
import org.eclipse.jetty.util.compression.InflaterPool;
@@ -37,8 +38,9 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
import org.eclipse.jetty.websocket.common.extensions.compress.CompressExtension;
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
-public class WebSocketExtensionFactory extends ContainerLifeCycle implements ExtensionFactory
+public class WebSocketExtensionFactory extends ExtensionFactory implements LifeCycle
{
+ private ContainerLifeCycle lifecycle;
private WebSocketContainerScope container;
private ServiceLoader extensionLoader = ServiceLoader.load(Extension.class);
private Map> availableExtensions;
@@ -47,6 +49,7 @@ public class WebSocketExtensionFactory extends ContainerLifeCycle implements Ext
public WebSocketExtensionFactory(WebSocketContainerScope container)
{
+ lifecycle = new ContainerLifeCycle();
availableExtensions = new HashMap<>();
for (Extension ext : extensionLoader)
{
@@ -55,8 +58,8 @@ public class WebSocketExtensionFactory extends ContainerLifeCycle implements Ext
}
this.container = container;
- addBean(inflaterPool);
- addBean(deflaterPool);
+ lifecycle.addBean(inflaterPool);
+ lifecycle.addBean(deflaterPool);
}
@Override
@@ -144,4 +147,66 @@ public class WebSocketExtensionFactory extends ContainerLifeCycle implements Ext
{
return availableExtensions.values().iterator();
}
+
+ /* --- All of the below ugliness due to not being able to break API compatibility with ExtensionFactory --- */
+
+ @Override
+ public void start() throws Exception
+ {
+ lifecycle.start();
+ }
+
+ @Override
+ public void stop() throws Exception
+ {
+ lifecycle.stop();
+ }
+
+ @Override
+ public boolean isRunning()
+ {
+ return lifecycle.isRunning();
+ }
+
+ @Override
+ public boolean isStarted()
+ {
+ return lifecycle.isStarted();
+ }
+
+ @Override
+ public boolean isStarting()
+ {
+ return lifecycle.isStarting();
+ }
+
+ @Override
+ public boolean isStopping()
+ {
+ return lifecycle.isStopping();
+ }
+
+ @Override
+ public boolean isStopped()
+ {
+ return lifecycle.isStopped();
+ }
+
+ @Override
+ public boolean isFailed()
+ {
+ return lifecycle.isFailed();
+ }
+
+ @Override
+ public void addLifeCycleListener(Listener listener)
+ {
+ lifecycle.addLifeCycleListener(listener);
+ }
+
+ @Override
+ public void removeLifeCycleListener(Listener listener)
+ {
+ lifecycle.removeLifeCycleListener(listener);
+ }
}
From 8f6e028f052a10d78d282dbafbfa4abab5325291 Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Tue, 27 Aug 2019 08:41:00 +1000
Subject: [PATCH 26/55] remove duplicate ignores
Signed-off-by: Greg Wilkins
---
jetty-maven-plugin/.gitignore | 5 -----
jetty-unixsocket/.gitignore | 1 -
jetty-util/.gitignore | 7 -------
tests/test-webapps/.gitignore | 1 -
4 files changed, 14 deletions(-)
delete mode 100644 jetty-maven-plugin/.gitignore
delete mode 100644 jetty-unixsocket/.gitignore
delete mode 100644 jetty-util/.gitignore
delete mode 100644 tests/test-webapps/.gitignore
diff --git a/jetty-maven-plugin/.gitignore b/jetty-maven-plugin/.gitignore
deleted file mode 100644
index 929d903c7d3..00000000000
--- a/jetty-maven-plugin/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.classpath
-.project
-.settings
-target
-*.swp
diff --git a/jetty-unixsocket/.gitignore b/jetty-unixsocket/.gitignore
deleted file mode 100644
index b83d22266ac..00000000000
--- a/jetty-unixsocket/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target/
diff --git a/jetty-util/.gitignore b/jetty-util/.gitignore
deleted file mode 100644
index 89c493b64bf..00000000000
--- a/jetty-util/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-.project
-.classpath
-.settings/
-.pmd
-target/
-*.swp
-*.log
diff --git a/tests/test-webapps/.gitignore b/tests/test-webapps/.gitignore
deleted file mode 100644
index e73b9a8a351..00000000000
--- a/tests/test-webapps/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*/src/main/webapp/META-INF
From 5164f7bb4175faa872ab91129dd27e043a532c2c Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Tue, 27 Aug 2019 10:52:27 +1000
Subject: [PATCH 27/55] fixed merge
Signed-off-by: Greg Wilkins
---
.../org/eclipse/jetty/server/HttpChannel.java | 59 ++++++++++---------
1 file changed, 31 insertions(+), 28 deletions(-)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
index 11b0e8b3c37..21b27f69047 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
@@ -487,14 +487,14 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
// RFC 7230, section 3.3.
if (!_request.isHead() && !_response.isContentComplete(_response.getHttpOutput().getWritten()))
- sendErrorOrAbort("Insufficient content written");
-
-
+ {
+ if (sendErrorOrAbort("Insufficient content written"))
+ break;
+ }
// TODO Currently a blocking/aborting consumeAll is done in the handling of the TERMINATED
// TODO Action triggered by the completed callback below. It would be possible to modify the
// TODO callback to do a non-blocking consumeAll at this point and only call completed when
// TODO that is done.
-
checkAndPrepareUpgrade();
// Set a close callback on the HttpOutput to make it an async callback
@@ -525,20 +525,25 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
return !suspended;
}
- public void sendErrorOrAbort(String message)
+ public boolean sendErrorOrAbort(String message)
{
try
{
if (isCommitted())
+ {
abort(new IOException(message));
- else
- _response.sendError(HttpStatus.INTERNAL_SERVER_ERROR_500, message);
+ return false;
+ }
+
+ _response.sendError(HttpStatus.INTERNAL_SERVER_ERROR_500, message);
+ return true;
}
catch (Throwable x)
{
LOG.ignore(x);
abort(x);
}
+ return false;
}
private void dispatch(DispatcherType type, Dispatchable dispatchable) throws IOException, ServletException
@@ -628,8 +633,6 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
_request.setHandled(true);
_state.completing();
sendResponse(null, _response.getHttpOutput().getBuffer(), true, Callback.from(_state::completed));
- {
- }
}
catch (Throwable x)
{
@@ -758,9 +761,9 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
public void onBadMessage(BadMessageException failure)
{
int status = failure.getCode();
- String message = failure.getReason();
+ String reason = failure.getReason();
if (status < HttpStatus.BAD_REQUEST_400 || status > 599)
- failure = new BadMessageException(HttpStatus.BAD_REQUEST_400, message, failure);
+ failure = new BadMessageException(HttpStatus.BAD_REQUEST_400, reason, failure);
notifyRequestFailure(_request, failure);
@@ -786,9 +789,9 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
ErrorHandler handler = getServer().getBean(ErrorHandler.class);
if (handler != null)
- content = handler.badMessageError(status, message, fields);
+ content = handler.badMessageError(status, reason, fields);
- sendResponse(new MetaData.Response(HttpVersion.HTTP_1_1, status, null, fields, BufferUtil.length(content)), content, true);
+ sendResponse(new MetaData.Response(HttpVersion.HTTP_1_1, status, reason, fields, BufferUtil.length(content)), content, true);
}
}
catch (IOException e)
@@ -1127,7 +1130,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onRequestBegin(Request request)
+ default void onRequestBegin(Request request)
{
}
@@ -1136,7 +1139,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onBeforeDispatch(Request request)
+ default void onBeforeDispatch(Request request)
{
}
@@ -1146,7 +1149,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
* @param request the request object
* @param failure the exception thrown by the application
*/
- public default void onDispatchFailure(Request request, Throwable failure)
+ default void onDispatchFailure(Request request, Throwable failure)
{
}
@@ -1155,7 +1158,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onAfterDispatch(Request request)
+ default void onAfterDispatch(Request request)
{
}
@@ -1166,7 +1169,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
* @param request the request object
* @param content a {@link ByteBuffer#slice() slice} of the request content chunk
*/
- public default void onRequestContent(Request request, ByteBuffer content)
+ default void onRequestContent(Request request, ByteBuffer content)
{
}
@@ -1175,7 +1178,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onRequestContentEnd(Request request)
+ default void onRequestContentEnd(Request request)
{
}
@@ -1184,7 +1187,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onRequestTrailers(Request request)
+ default void onRequestTrailers(Request request)
{
}
@@ -1193,7 +1196,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onRequestEnd(Request request)
+ default void onRequestEnd(Request request)
{
}
@@ -1203,7 +1206,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
* @param request the request object
* @param failure the request failure
*/
- public default void onRequestFailure(Request request, Throwable failure)
+ default void onRequestFailure(Request request, Throwable failure)
{
}
@@ -1212,7 +1215,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onResponseBegin(Request request)
+ default void onResponseBegin(Request request)
{
}
@@ -1223,7 +1226,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onResponseCommit(Request request)
+ default void onResponseCommit(Request request)
{
}
@@ -1233,7 +1236,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
* @param request the request object
* @param content a {@link ByteBuffer#slice() slice} of the response content chunk
*/
- public default void onResponseContent(Request request, ByteBuffer content)
+ default void onResponseContent(Request request, ByteBuffer content)
{
}
@@ -1242,7 +1245,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onResponseEnd(Request request)
+ default void onResponseEnd(Request request)
{
}
@@ -1252,7 +1255,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
* @param request the request object
* @param failure the response failure
*/
- public default void onResponseFailure(Request request, Throwable failure)
+ default void onResponseFailure(Request request, Throwable failure)
{
}
@@ -1261,7 +1264,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*
* @param request the request object
*/
- public default void onComplete(Request request)
+ default void onComplete(Request request)
{
}
}
From 387e33acaf0dec60bb9c311ac83f7ac02f6243e4 Mon Sep 17 00:00:00 2001
From: Jan Bartel
Date: Tue, 27 Aug 2019 10:53:54 +1000
Subject: [PATCH 28/55] Issue #4006 Fix ClusteredSessionMigrationTest (#4010)
Signed-off-by: Jan Bartel
---
.../ClusteredSessionMigrationTest.java | 27 ++++++++++++-------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java
index c8a5937f597..31627854634 100644
--- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java
@@ -81,8 +81,14 @@ public class ClusteredSessionMigrationTest extends AbstractTestBase
server1.start();
int port1 = server1.getPort();
- TestServer server2 = new TestServer(0, TestServer.DEFAULT_MAX_INACTIVE, TestServer.DEFAULT_SCAVENGE_SEC,
- cacheFactory, storeFactory);
+ //Configure a cache and store same way for server2
+ DefaultSessionCacheFactory cacheFactory2 = new DefaultSessionCacheFactory();
+ cacheFactory2.setEvictionPolicy(SessionCache.NEVER_EVICT);
+ cacheFactory2.setSaveOnCreate(true);
+ SessionDataStoreFactory storeFactory2 = createSessionDataStoreFactory();
+
+ TestServer server2 = new TestServer(0,TestServer.DEFAULT_MAX_INACTIVE, TestServer.DEFAULT_SCAVENGE_SEC,
+ cacheFactory2, storeFactory2);
server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
try
@@ -110,8 +116,6 @@ public class ClusteredSessionMigrationTest extends AbstractTestBase
request2.header("Cookie", sessionCookie);
ContentResponse response2 = request2.send();
assertEquals(HttpServletResponse.SC_OK, response2.getStatus());
- String response = response2.getContentAsString();
- assertEquals(response.trim(), String.valueOf(value));
}
finally
{
@@ -132,6 +136,8 @@ public class ClusteredSessionMigrationTest extends AbstractTestBase
public static class TestServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
+
+ private static long createTime = 0;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
@@ -149,6 +155,7 @@ public class ClusteredSessionMigrationTest extends AbstractTestBase
{
if (session == null)
session = request.getSession(true);
+ createTime = session.getCreationTime();
int value = Integer.parseInt(request.getParameter("value"));
session.setAttribute("value", value);
PrintWriter writer = response.getWriter();
@@ -157,12 +164,12 @@ public class ClusteredSessionMigrationTest extends AbstractTestBase
}
else if ("get".equals(action))
{
- int value = (Integer)session.getAttribute("value");
- int x = session.getMaxInactiveInterval();
- assertTrue(x > 0);
- PrintWriter writer = response.getWriter();
- writer.println(value);
- writer.flush();
+ //We cannot test if the session contains the attribute node1
+ //set, because it may not have finished writing the attribute
+ //by the time its response returned to the client and the request
+ //was sent to node2. Just test the create time, which should be
+ //saved.
+ assertEquals(createTime, session.getCreationTime());
}
}
}
From 19980ceeb5eb6f18eb88c17b3f6e61565a4d9bae Mon Sep 17 00:00:00 2001
From: Jan Bartel
Date: Tue, 27 Aug 2019 11:00:09 +1000
Subject: [PATCH 29/55] Issue #4009 ServletContextHandler setSecurityHandler
broke handler chain (#4012)
* Issue #4009 ServletContextHandler setSecurityHandler broke handler chain
Signed-off-by: Jan Bartel
---
.../jetty/servlet/ServletContextHandler.java | 2 +-
.../servlet/ServletContextHandlerTest.java | 70 +++++++++++++++++++
2 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
index 365f6fc70f4..ba98aee7515 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
@@ -609,7 +609,7 @@ public class ServletContextHandler extends ContextHandler
*/
public void setSecurityHandler(SecurityHandler securityHandler)
{
- replaceHandler(_sessionHandler, securityHandler);
+ replaceHandler(_securityHandler, securityHandler);
_securityHandler = securityHandler;
relinkHandlers();
}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java
index beb3c2dcdf0..c870a679b94 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java
@@ -52,10 +52,13 @@ import javax.servlet.http.HttpSessionIdListener;
import javax.servlet.http.HttpSessionListener;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.security.RoleInfo;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.AbstractHandlerContainer;
import org.eclipse.jetty.server.handler.ContextHandler;
@@ -81,6 +84,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@@ -703,6 +707,72 @@ public class ServletContextHandlerTest
assertThat("Response", response, containsString("Hello World"));
}
+ @Test
+ public void testSetSecurityHandler() throws Exception
+ {
+ ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS|ServletContextHandler.SECURITY|ServletContextHandler.GZIP);
+ assertNotNull(context.getSessionHandler());
+ SessionHandler sessionHandler = context.getSessionHandler();
+ assertNotNull(context.getSecurityHandler());
+ SecurityHandler securityHandler = context.getSecurityHandler();
+ assertNotNull(context.getGzipHandler());
+ GzipHandler gzipHandler = context.getGzipHandler();
+
+ //check the handler linking order
+ HandlerWrapper h = (HandlerWrapper)context.getHandler();
+ assertSame(h, sessionHandler);
+
+ h = (HandlerWrapper)h.getHandler();
+ assertSame(h, securityHandler);
+
+ h = (HandlerWrapper)h.getHandler();
+ assertSame(h, gzipHandler);
+
+ //replace the security handler
+ SecurityHandler myHandler = new SecurityHandler()
+ {
+ @Override
+ protected RoleInfo prepareConstraintInfo(String pathInContext, Request request)
+ {
+ return null;
+ }
+
+ @Override
+ protected boolean checkUserDataPermissions(String pathInContext, Request request, Response response,
+ RoleInfo constraintInfo) throws IOException
+ {
+ return false;
+ }
+
+ @Override
+ protected boolean isAuthMandatory(Request baseRequest, Response baseResponse, Object constraintInfo)
+ {
+ return false;
+ }
+
+ @Override
+ protected boolean checkWebResourcePermissions(String pathInContext, Request request, Response response,
+ Object constraintInfo, UserIdentity userIdentity)
+ throws IOException
+ {
+ return false;
+ }
+ };
+
+ //check the linking order
+ context.setSecurityHandler(myHandler);
+ assertSame(myHandler, context.getSecurityHandler());
+
+ h = (HandlerWrapper)context.getHandler();
+ assertSame(h, sessionHandler);
+
+ h = (HandlerWrapper)h.getHandler();
+ assertSame(h, myHandler);
+
+ h = (HandlerWrapper)h.getHandler();
+ assertSame(h, gzipHandler);
+ }
+
@Test
public void testReplaceServletHandlerWithoutServlet() throws Exception
{
From 15e2f7226446f1a9f4ba4a6fb4bbd94f8be303e2 Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Tue, 27 Aug 2019 11:33:06 +1000
Subject: [PATCH 30/55] updated after merge to fix tests
Signed-off-by: Greg Wilkins
---
.../jetty/http2/server/HTTP2ServerConnection.java | 5 ++---
.../jetty/http2/server/HttpTransportOverHTTP2.java | 5 +++--
.../java/org/eclipse/jetty/server/HttpChannel.java | 13 ++++++++++---
3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
index 2dd10e670e6..4173eb5f1d0 100644
--- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
@@ -376,10 +376,9 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
}
@Override
- protected void checkAndPrepareUpgrade()
+ protected boolean checkAndPrepareUpgrade()
{
- if (isTunnel())
- getHttpTransport().prepareUpgrade();
+ return isTunnel() && getHttpTransport().prepareUpgrade();
}
@Override
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java
index 1f53feba058..2664adceb7a 100644
--- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java
@@ -322,7 +322,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport
return transportCallback.onIdleTimeout(failure);
}
- void prepareUpgrade()
+ boolean prepareUpgrade()
{
HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttachment();
Request request = channel.getRequest();
@@ -331,7 +331,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport
endPoint.upgrade(connection);
stream.setAttachment(endPoint);
if (request.getHttpInput().hasContent())
- channel.sendErrorOrAbort("Unexpected content in CONNECT request");
+ return channel.sendErrorOrAbort("Unexpected content in CONNECT request");
+ return true;
}
@Override
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
index 21b27f69047..0df6668f113 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
@@ -491,11 +491,15 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
if (sendErrorOrAbort("Insufficient content written"))
break;
}
+
+ // Check if an update is done (if so, do not close)
+ if (checkAndPrepareUpgrade())
+ break;
+
// TODO Currently a blocking/aborting consumeAll is done in the handling of the TERMINATED
// TODO Action triggered by the completed callback below. It would be possible to modify the
// TODO callback to do a non-blocking consumeAll at this point and only call completed when
// TODO that is done.
- checkAndPrepareUpgrade();
// Set a close callback on the HttpOutput to make it an async callback
_response.closeOutput(Callback.from(_state::completed));
@@ -731,9 +735,12 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
* response is sent back to the client.
* This avoids a race where the server is unprepared if the client sends
* data immediately after having received the upgrade response.
+ * @return true if the channel is not complete and more processing is required,
+ * either because the upgrade has succeeded or sendError has been called.
*/
- protected void checkAndPrepareUpgrade()
+ protected boolean checkAndPrepareUpgrade()
{
+ return false;
}
public void onCompleted()
@@ -791,7 +798,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
if (handler != null)
content = handler.badMessageError(status, reason, fields);
- sendResponse(new MetaData.Response(HttpVersion.HTTP_1_1, status, reason, fields, BufferUtil.length(content)), content, true);
+ sendResponse(new MetaData.Response(HttpVersion.HTTP_1_1, status, null, fields, BufferUtil.length(content)), content, true);
}
}
catch (IOException e)
From d216792d2304065856a21fc2d744afcc91ee719b Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Tue, 27 Aug 2019 13:01:34 +1000
Subject: [PATCH 31/55] Made test not fail in symlinked directory
Signed-off-by: Greg Wilkins
---
.../test/java/org/eclipse/jetty/util/TypeUtilTest.java | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java
index b723d195385..e296152ef6d 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java
@@ -21,6 +21,8 @@ package org.eclipse.jetty.util;
import java.nio.file.Path;
import java.nio.file.Paths;
+import org.eclipse.jetty.util.resource.Resource;
+import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnJre;
import org.junit.jupiter.api.condition.EnabledOnJre;
@@ -160,16 +162,15 @@ public class TypeUtilTest
}
@Test
- public void testGetLocationOfClass_FromMavenRepo()
+ public void testGetLocationOfClass_FromMavenRepo() throws Exception
{
String mavenRepoPathProperty = System.getProperty("mavenRepoPath");
assumeTrue(mavenRepoPathProperty != null);
Path mavenRepoPath = Paths.get(mavenRepoPathProperty);
- String mavenRepo = mavenRepoPath.toFile().getPath().replaceAll("\\\\", "/");
-
// Classes from maven dependencies
- assertThat(TypeUtil.getLocationOfClass(org.junit.jupiter.api.Assertions.class).toASCIIString(), containsString(mavenRepo));
+ Resource resource = Resource.newResource(TypeUtil.getLocationOfClass(org.junit.jupiter.api.Assertions.class).toASCIIString());
+ assertThat(resource.getFile().getCanonicalPath(), Matchers.startsWith(mavenRepoPath.toFile().getCanonicalPath()));
}
@Test
From b51d770807e89e1a35c7ce92280e5d18218efcbe Mon Sep 17 00:00:00 2001
From: Olivier Lamy
Date: Tue, 27 Aug 2019 13:03:28 +1000
Subject: [PATCH 32/55] session#getLastAccessedTime should throw
IllegalStateException if session has been invalidated (#4023)
* per servlet api javadoc getLastAccessedTime should throw IllegalStateException if session has been invalidated
Signed-off-by: olivier lamy
* isInvalid test should be done within lock
Signed-off-by: olivier lamy
---
.../eclipse/jetty/server/session/Session.java | 4 ++++
.../jetty/server/session/SessionHandlerTest.java | 16 ++++++++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
index 440883d23db..867afb9bad8 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
@@ -483,6 +483,10 @@ public class Session implements SessionHandler.SessionIf
{
try (Lock lock = _lock.lock())
{
+ if (isInvalid())
+ {
+ throw new IllegalStateException("Session not valid");
+ }
return _sessionData.getLastAccessed();
}
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
index 351ede0d227..e119dad6f33 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
@@ -23,9 +23,10 @@ import java.util.Collections;
import java.util.HashSet;
import javax.servlet.SessionTrackingMode;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
public class SessionHandlerTest
{
@Test
@@ -34,7 +35,18 @@ public class SessionHandlerTest
SessionHandler sessionHandler = new SessionHandler();
sessionHandler.setSessionTrackingModes(new HashSet<>(Arrays.asList(SessionTrackingMode.COOKIE, SessionTrackingMode.URL)));
sessionHandler.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.SSL));
- Assertions.assertThrows(IllegalArgumentException.class,() ->
+ assertThrows(IllegalArgumentException.class,() ->
sessionHandler.setSessionTrackingModes(new HashSet<>(Arrays.asList(SessionTrackingMode.SSL, SessionTrackingMode.URL))));
}
+
+ @Test
+ public void testInvalidSessiongetLastAccessedTime()
+ {
+ Session session = new Session(new SessionHandler(),
+ new SessionData("sd" ,"", "", 0, 0, 0, 0));
+ session.getLastAccessedTime();
+ session.invalidate();
+ assertThrows(IllegalStateException.class, () -> session.getLastAccessedTime());
+ }
+
}
From 5403a30b329bf923ee2e928ce5742340630fe9a1 Mon Sep 17 00:00:00 2001
From: Olivier Lamy
Date: Tue, 27 Aug 2019 13:03:28 +1000
Subject: [PATCH 33/55] session#getLastAccessedTime should throw
IllegalStateException if session has been invalidated (#4023)
* per servlet api javadoc getLastAccessedTime should throw IllegalStateException if session has been invalidated
Signed-off-by: olivier lamy
* isInvalid test should be done within lock
Signed-off-by: olivier lamy
---
.../eclipse/jetty/server/session/Session.java | 4 ++++
.../jetty/server/session/SessionHandlerTest.java | 16 ++++++++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
index 06a85108e39..1052f3b2364 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
@@ -476,6 +476,10 @@ public class Session implements SessionHandler.SessionIf
{
try (Lock lock = _lock.lock())
{
+ if (isInvalid())
+ {
+ throw new IllegalStateException("Session not valid");
+ }
return _sessionData.getLastAccessed();
}
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
index 351ede0d227..e119dad6f33 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
@@ -23,9 +23,10 @@ import java.util.Collections;
import java.util.HashSet;
import javax.servlet.SessionTrackingMode;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
public class SessionHandlerTest
{
@Test
@@ -34,7 +35,18 @@ public class SessionHandlerTest
SessionHandler sessionHandler = new SessionHandler();
sessionHandler.setSessionTrackingModes(new HashSet<>(Arrays.asList(SessionTrackingMode.COOKIE, SessionTrackingMode.URL)));
sessionHandler.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.SSL));
- Assertions.assertThrows(IllegalArgumentException.class,() ->
+ assertThrows(IllegalArgumentException.class,() ->
sessionHandler.setSessionTrackingModes(new HashSet<>(Arrays.asList(SessionTrackingMode.SSL, SessionTrackingMode.URL))));
}
+
+ @Test
+ public void testInvalidSessiongetLastAccessedTime()
+ {
+ Session session = new Session(new SessionHandler(),
+ new SessionData("sd" ,"", "", 0, 0, 0, 0));
+ session.getLastAccessedTime();
+ session.invalidate();
+ assertThrows(IllegalStateException.class, () -> session.getLastAccessedTime());
+ }
+
}
From 1f189d4618877983f528ac7beee80fcbf9dc8b50 Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Tue, 27 Aug 2019 14:27:46 +1000
Subject: [PATCH 34/55] fixed test visibility for JPMS
Signed-off-by: Greg Wilkins
---
.../org/eclipse/jetty/servlet/ErrorPageTest.java | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ErrorPageTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ErrorPageTest.java
index 0d8db7f6e55..a82e7a63452 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ErrorPageTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ErrorPageTest.java
@@ -134,7 +134,7 @@ public class ErrorPageTest
}
@Test
- void testErrorOverridesStatus() throws Exception
+ public void testErrorOverridesStatus() throws Exception
{
String response = _connector.getResponse("GET /error-and-status/anything HTTP/1.0\r\n\r\n");
assertThat(response, Matchers.containsString("HTTP/1.1 594 594"));
@@ -148,7 +148,7 @@ public class ErrorPageTest
}
@Test
- void testHttp204CannotHaveBody() throws Exception
+ public void testHttp204CannotHaveBody() throws Exception
{
String response = _connector.getResponse("GET /fail/code?code=204 HTTP/1.0\r\n\r\n");
assertThat(response, Matchers.containsString("HTTP/1.1 204 No Content"));
@@ -162,7 +162,7 @@ public class ErrorPageTest
}
@Test
- void testDeleteCannotHaveBody() throws Exception
+ public void testDeleteCannotHaveBody() throws Exception
{
String response = _connector.getResponse("DELETE /delete/anything HTTP/1.0\r\n\r\n");
assertThat(response, Matchers.containsString("HTTP/1.1 595 595"));
@@ -179,7 +179,7 @@ public class ErrorPageTest
}
@Test
- void testGenerateAcceptableResponse_noAcceptHeader() throws Exception
+ public void testGenerateAcceptableResponse_noAcceptHeader() throws Exception
{
// no global error page here
_errorPageErrorHandler.getErrorPages().remove(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE);
@@ -192,7 +192,7 @@ public class ErrorPageTest
}
@Test
- void testGenerateAcceptableResponse_htmlAcceptHeader() throws Exception
+ public void testGenerateAcceptableResponse_htmlAcceptHeader() throws Exception
{
// no global error page here
_errorPageErrorHandler.getErrorPages().remove(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE);
@@ -207,7 +207,7 @@ public class ErrorPageTest
}
@Test
- void testGenerateAcceptableResponse_noHtmlAcceptHeader() throws Exception
+ public void testGenerateAcceptableResponse_noHtmlAcceptHeader() throws Exception
{
// no global error page here
_errorPageErrorHandler.getErrorPages().remove(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE);
@@ -221,7 +221,7 @@ public class ErrorPageTest
}
@Test
- void testNestedSendErrorDoesNotLoop() throws Exception
+ public void testNestedSendErrorDoesNotLoop() throws Exception
{
String response = _connector.getResponse("GET /fail/code?code=597 HTTP/1.0\r\n\r\n");
assertThat(response, Matchers.containsString("HTTP/1.1 597 597"));
From d890748f3afa76d03e4c5b41e750b3f732394e7a Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Tue, 27 Aug 2019 16:19:07 +1000
Subject: [PATCH 35/55] More merge fixes
Signed-off-by: Greg Wilkins
---
.../org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java | 2 +-
.../src/main/java/org/eclipse/jetty/server/HttpChannel.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java
index 2664adceb7a..0dac59d2f06 100644
--- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java
@@ -332,7 +332,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport
stream.setAttachment(endPoint);
if (request.getHttpInput().hasContent())
return channel.sendErrorOrAbort("Unexpected content in CONNECT request");
- return true;
+ return false;
}
@Override
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
index 0df6668f113..c036d746728 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
@@ -736,7 +736,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
* This avoids a race where the server is unprepared if the client sends
* data immediately after having received the upgrade response.
* @return true if the channel is not complete and more processing is required,
- * either because the upgrade has succeeded or sendError has been called.
+ * typically because sendError has been called.
*/
protected boolean checkAndPrepareUpgrade()
{
From 83463c2a23563ec4ef2e95d52c0337dc2e3f0124 Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Tue, 27 Aug 2019 17:38:20 +1000
Subject: [PATCH 36/55] Issue #3964 - Listener behavior cleanup (Jetty 9.4.x)
(#3965)
Issue #3964
* Avoid creating listener list for rarely used requestAttributeListener
* AbstractConnector keeps a specific list of HttpChannel.Listeners
to avoid Connection.Listeners and MBean listeners being added to
the HttpChannel listener list.
* Simplified listener handling by avoiding null connector, previously
only needed for testing.
* Fixed test that assumed HttpChannel listeners were not cleared by a recycle
* Separated out durable vs cyclic HttpChannel.Listeners, so as to
simplify handling.
* Deprecated cyclic HttpChannel.Listeners, as I'm not sure the channel is
the right place for them.
* Added improved method to combine multiple HttpChannel Listeners
into a single Listener.
* Fixed MockConnector
* Added benchmark
* Improved benchmark
* Updates from review
* Removed benchmark and alternate implementations.
* Updated javadoc
* Updates from review
Signed-off-by: Greg Wilkins
---
.../SpnegoAuthenticatorTest.java | 30 +-
.../jetty/server/AbstractConnector.java | 37 +++
.../org/eclipse/jetty/server/HttpChannel.java | 257 +++++++++-------
.../jetty/server/HttpChannelListeners.java | 286 ++++++++++++++++++
.../org/eclipse/jetty/server/Request.java | 1 +
.../jetty/server/HttpChannelEventTest.java | 31 ++
.../jetty/server/HttpInputAsyncStateTest.java | 2 +-
.../eclipse/jetty/server/HttpInputTest.java | 2 +-
.../eclipse/jetty/server/HttpWriterTest.java | 2 +-
.../eclipse/jetty/server/MockConnector.java | 46 +++
.../jetty/util/component/Container.java | 2 +-
...tractClusteredInvalidationSessionTest.java | 4 +-
...bstractClusteredSessionScavengingTest.java | 8 +-
.../AbstractWebAppObjectInSessionTest.java | 5 +-
.../session/TestContextScopeListener.java | 76 -----
.../TestHttpChannelCompleteListener.java | 45 +++
.../jetty/server/session/TestServer.java | 6 +
.../jetty/server/session/AsyncTest.java | 21 +-
.../jetty/server/session/CreationTest.java | 24 +-
.../session/DefaultSessionCacheTest.java | 5 +-
.../session/DeleteUnloadableSessionTest.java | 4 +-
.../server/session/DirtyAttributeTest.java | 8 +-
.../jetty/server/session/IdleSessionTest.java | 8 +-
.../NonClusteredSessionScavengingTest.java | 12 +-
.../session/ReentrantRequestSessionTest.java | 4 +-
.../SameContextForwardedSessionTest.java | 4 +-
.../server/session/SaveOptimizeTest.java | 20 +-
.../server/session/SessionRenewTest.java | 10 +-
28 files changed, 702 insertions(+), 258 deletions(-)
create mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelListeners.java
create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/MockConnector.java
delete mode 100644 tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestContextScopeListener.java
create mode 100644 tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpChannelCompleteListener.java
diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java
index 00af87e7ecc..76a6bfa1c14 100644
--- a/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java
+++ b/jetty-security/src/test/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticatorTest.java
@@ -25,6 +25,7 @@ import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpChannelState;
@@ -58,7 +59,7 @@ public class SpnegoAuthenticatorTest
@Test
public void testChallengeSentWithNoAuthorization() throws Exception
{
- HttpChannel channel = new HttpChannel(null, new HttpConfiguration(), null, null)
+ HttpChannel channel = new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null)
{
@Override
public Server getServer()
@@ -94,7 +95,7 @@ public class SpnegoAuthenticatorTest
@Test
public void testChallengeSentWithUnhandledAuthorization() throws Exception
{
- HttpChannel channel = new HttpChannel(null, new HttpConfiguration(), null, null)
+ HttpChannel channel = new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null)
{
@Override
public Server getServer()
@@ -162,4 +163,29 @@ public class SpnegoAuthenticatorTest
assertEquals("negotiate", _authenticator.getAuthSchemeFromHeader(" negotiate asdfasdf"));
assertEquals("negotiated", _authenticator.getAuthSchemeFromHeader(" negotiated asdfasdf"));
}
+
+ class MockConnector extends AbstractConnector
+ {
+ public MockConnector()
+ {
+ super(new Server() , null, null, null, 0);
+ }
+
+ @Override
+ protected void accept(int acceptorID) throws IOException, InterruptedException
+ {
+ }
+
+ @Override
+ public Object getTransport()
+ {
+ return null;
+ }
+
+ @Override
+ public String dumpSelf()
+ {
+ return null;
+ }
+ }
}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
index 46c18701b7e..f1425dde301 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
@@ -45,6 +45,7 @@ import org.eclipse.jetty.util.ProcessorUtils;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.Container;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.component.Graceful;
@@ -154,6 +155,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
private final Set _endpoints = Collections.newSetFromMap(new ConcurrentHashMap<>());
private final Set _immutableEndPoints = Collections.unmodifiableSet(_endpoints);
private final Graceful.Shutdown _shutdown = new Graceful.Shutdown();
+ private HttpChannel.Listener _httpChannelListeners = HttpChannel.NOOP_LISTENER;
private CountDownLatch _stopping;
private long _idleTimeout = 30000;
private String _defaultProtocol;
@@ -188,6 +190,23 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
pool = _server.getBean(ByteBufferPool.class);
_byteBufferPool = pool != null ? pool : new ArrayByteBufferPool();
+ addEventListener(new Container.Listener()
+ {
+ @Override
+ public void beanAdded(Container parent, Object bean)
+ {
+ if (bean instanceof HttpChannel.Listener)
+ _httpChannelListeners = new HttpChannelListeners(getBeans(HttpChannel.Listener.class));
+ }
+
+ @Override
+ public void beanRemoved(Container parent, Object bean)
+ {
+ if (bean instanceof HttpChannel.Listener)
+ _httpChannelListeners = new HttpChannelListeners(getBeans(HttpChannel.Listener.class));
+ }
+ });
+
addBean(_server, false);
addBean(_executor);
if (executor == null)
@@ -208,6 +227,24 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
_acceptors = new Thread[acceptors];
}
+ /**
+ * Get the {@link HttpChannel.Listener}s added to the connector
+ * as a single combined Listener.
+ * This is equivalent to a listener that iterates over the individual
+ * listeners returned from getBeans(HttpChannel.Listener.class);
,
+ * except that:
+ * The result is precomputed, so it is more efficient
+ * The result is ordered by the order added.
+ * The result is immutable.
+ *
+ * @see #getBeans(Class)
+ * @return An unmodifiable list of EventListener beans
+ */
+ public HttpChannel.Listener getHttpChannelListeners()
+ {
+ return _httpChannelListeners;
+ }
+
@Override
public Server getServer()
{
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
index 31714973255..38760aadac4 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.EventListener;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
@@ -69,6 +70,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
*/
public class HttpChannel implements Runnable, HttpOutput.Interceptor
{
+ public static Listener NOOP_LISTENER = new Listener(){};
private static final Logger LOG = Log.getLogger(HttpChannel.class);
private final AtomicLong _requests = new AtomicLong();
@@ -80,9 +82,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
private final HttpChannelState _state;
private final Request _request;
private final Response _response;
+ private final HttpChannel.Listener _combinedListener;
+ @Deprecated
+ private final List _transientListeners = new ArrayList<>();
private HttpFields _trailers;
private final Supplier _trailerSupplier = () -> _trailers;
- private final List _listeners;
private MetaData.Response _committedMetaData;
private RequestLog _requestLog;
private long _oldIdleTimeout;
@@ -103,13 +107,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
_request = new Request(this, newHttpInput(_state));
_response = new Response(this, newHttpOutput());
- _executor = connector == null ? null : connector.getServer().getThreadPool();
- _requestLog = connector == null ? null : connector.getServer().getRequestLog();
-
- List listeners = new ArrayList<>();
- if (connector != null)
- listeners.addAll(connector.getBeans(Listener.class));
- _listeners = listeners;
+ _executor = connector.getServer().getThreadPool();
+ _requestLog = connector.getServer().getRequestLog();
+ _combinedListener = (connector instanceof AbstractConnector)
+ ? ((AbstractConnector)connector).getHttpChannelListeners()
+ : NOOP_LISTENER;
if (LOG.isDebugEnabled())
LOG.debug("new {} -> {},{},{}",
@@ -139,14 +141,32 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
return _state;
}
+ /**
+ * Add a transient Listener to the HttpChannel.
+ * Listeners added by this method will only be notified
+ * if the HttpChannel has been constructed with an instance of
+ * {@link TransientListeners} as an {@link AbstractConnector}
+ * provided listener
+ * Transient listeners are removed after every request cycle
+ * @param listener
+ * @return true if the listener was added.
+ */
+ @Deprecated
public boolean addListener(Listener listener)
{
- return _listeners.add(listener);
+ return _transientListeners.add(listener);
}
+ @Deprecated
public boolean removeListener(Listener listener)
{
- return _listeners.remove(listener);
+ return _transientListeners.remove(listener);
+ }
+
+ @Deprecated
+ public List getTransientListeners()
+ {
+ return _transientListeners;
}
public long getBytesWritten()
@@ -294,6 +314,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
_written = 0;
_trailers = null;
_oldIdleTimeout = 0;
+ _transientListeners.clear();
}
public void onAsyncWaitForContent()
@@ -535,17 +556,17 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
try
{
_request.setDispatcherType(type);
- notifyBeforeDispatch(_request);
+ _combinedListener.onBeforeDispatch(_request);
dispatchable.dispatch();
}
catch (Throwable x)
{
- notifyDispatchFailure(_request, x);
+ _combinedListener.onDispatchFailure(_request, x);
throw x;
}
finally
{
- notifyAfterDispatch(_request);
+ _combinedListener.onAfterDispatch(_request);
_request.setDispatcherType(null);
}
}
@@ -668,7 +689,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
_request.setSecure(HttpScheme.HTTPS.is(request.getURI().getScheme()));
- notifyRequestBegin(_request);
+ _combinedListener.onRequestBegin(_request);
if (LOG.isDebugEnabled())
LOG.debug("REQUEST for {} on {}{}{} {} {}{}{}", request.getURIString(), this, System.lineSeparator(),
@@ -680,7 +701,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
{
if (LOG.isDebugEnabled())
LOG.debug("onContent {} {}", this, content);
- notifyRequestContent(_request, content.getByteBuffer());
+ _combinedListener.onRequestContent(_request, content.getByteBuffer());
return _request.getHttpInput().addContent(content);
}
@@ -688,7 +709,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
{
if (LOG.isDebugEnabled())
LOG.debug("onContentComplete {}", this);
- notifyRequestContentEnd(_request);
+ _combinedListener.onRequestContentEnd(_request);
return false;
}
@@ -697,7 +718,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
if (LOG.isDebugEnabled())
LOG.debug("onTrailers {} {}", this, trailers);
_trailers = trailers;
- notifyRequestTrailers(_request);
+ _combinedListener.onRequestTrailers(_request);
}
public boolean onRequestComplete()
@@ -705,7 +726,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
if (LOG.isDebugEnabled())
LOG.debug("onRequestComplete {}", this);
boolean result = _request.getHttpInput().eof();
- notifyRequestEnd(_request);
+ _combinedListener.onRequestEnd(_request);
return result;
}
@@ -722,7 +743,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
setIdleTimeout(_oldIdleTimeout);
_request.onCompleted();
- notifyComplete(_request);
+ _combinedListener.onComplete(_request);
_transport.onCompleted();
}
@@ -738,7 +759,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
if (status < HttpStatus.BAD_REQUEST_400 || status > 599)
failure = new BadMessageException(HttpStatus.BAD_REQUEST_400, reason, failure);
- notifyRequestFailure(_request, failure);
+ _combinedListener.onRequestFailure(_request, failure);
Action action;
try
@@ -810,7 +831,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
? new Send100Callback(callback)
: new SendCallback(callback, content, true, complete);
- notifyResponseBegin(_request);
+ _combinedListener.onResponseBegin(_request);
// committing write
_transport.send(info, _request.isHead(), content, complete, committed);
@@ -936,89 +957,14 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
{
if (_state.abortResponse())
{
- notifyResponseFailure(_request, failure);
+ _combinedListener.onResponseFailure(_request, failure);
_transport.abort(failure);
}
}
- private void notifyRequestBegin(Request request)
- {
- notifyEvent1(listener -> listener::onRequestBegin, request);
- }
-
- private void notifyBeforeDispatch(Request request)
- {
- notifyEvent1(listener -> listener::onBeforeDispatch, request);
- }
-
- private void notifyDispatchFailure(Request request, Throwable failure)
- {
- notifyEvent2(listener -> listener::onDispatchFailure, request, failure);
- }
-
- private void notifyAfterDispatch(Request request)
- {
- notifyEvent1(listener -> listener::onAfterDispatch, request);
- }
-
- private void notifyRequestContent(Request request, ByteBuffer content)
- {
- notifyEvent2(listener -> listener::onRequestContent, request, content);
- }
-
- private void notifyRequestContentEnd(Request request)
- {
- notifyEvent1(listener -> listener::onRequestContentEnd, request);
- }
-
- private void notifyRequestTrailers(Request request)
- {
- notifyEvent1(listener -> listener::onRequestTrailers, request);
- }
-
- private void notifyRequestEnd(Request request)
- {
- notifyEvent1(listener -> listener::onRequestEnd, request);
- }
-
- private void notifyRequestFailure(Request request, Throwable failure)
- {
- notifyEvent2(listener -> listener::onRequestFailure, request, failure);
- }
-
- private void notifyResponseBegin(Request request)
- {
- notifyEvent1(listener -> listener::onResponseBegin, request);
- }
-
- private void notifyResponseCommit(Request request)
- {
- notifyEvent1(listener -> listener::onResponseCommit, request);
- }
-
- private void notifyResponseContent(Request request, ByteBuffer content)
- {
- notifyEvent2(listener -> listener::onResponseContent, request, content);
- }
-
- private void notifyResponseEnd(Request request)
- {
- notifyEvent1(listener -> listener::onResponseEnd, request);
- }
-
- private void notifyResponseFailure(Request request, Throwable failure)
- {
- notifyEvent2(listener -> listener::onResponseFailure, request, failure);
- }
-
- private void notifyComplete(Request request)
- {
- notifyEvent1(listener -> listener::onComplete, request);
- }
-
private void notifyEvent1(Function> function, Request request)
{
- for (Listener listener : _listeners)
+ for (Listener listener : _transientListeners)
{
try
{
@@ -1033,7 +979,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
private void notifyEvent2(Function> function, Request request, ByteBuffer content)
{
- for (Listener listener : _listeners)
+ for (Listener listener : _transientListeners)
{
ByteBuffer view = content.slice();
try
@@ -1049,7 +995,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
private void notifyEvent2(Function> function, Request request, Throwable failure)
{
- for (Listener listener : _listeners)
+ for (Listener listener : _transientListeners)
{
try
{
@@ -1085,8 +1031,13 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
* Listener methods are invoked synchronously from the thread that is
* performing the request processing, and they should not call blocking code
* (otherwise the request processing will be blocked as well).
+ * Listener instances that are set as a bean on the {@link Connector} are
+ * efficiently added to {@link HttpChannel}. If additional listeners are added
+ * using the deprecated {@link HttpChannel#addListener(Listener)}
method,
+ * then an instance of {@link TransientListeners} must be added to the connector
+ * in order for them to be invoked.
*/
- public interface Listener
+ public interface Listener extends EventListener
{
/**
* Invoked just after the HTTP request line and headers have been parsed.
@@ -1256,11 +1207,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
_response.getHttpOutput().closed();
super.succeeded();
if (_commit)
- notifyResponseCommit(_request);
+ _combinedListener.onResponseCommit(_request);
if (_length > 0)
- notifyResponseContent(_request, _content);
+ _combinedListener.onResponseContent(_request, _content);
if (_complete && _state.completeResponse())
- notifyResponseEnd(_request);
+ _combinedListener.onResponseEnd(_request);
}
@Override
@@ -1313,4 +1264,102 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
super.failed(new IllegalStateException());
}
}
+
+ /**
+ * A Listener instance that can be added as a bean to {@link AbstractConnector} so that
+ * the listeners obtained from HttpChannel{@link #getTransientListeners()}
+ */
+ @Deprecated
+ public static class TransientListeners implements Listener
+ {
+ @Override
+ public void onRequestBegin(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onRequestBegin, request);
+ }
+
+ @Override
+ public void onBeforeDispatch(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onBeforeDispatch, request);
+ }
+
+ @Override
+ public void onDispatchFailure(Request request, Throwable failure)
+ {
+ request.getHttpChannel().notifyEvent2(listener -> listener::onDispatchFailure, request, failure);
+ }
+
+ @Override
+ public void onAfterDispatch(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onAfterDispatch, request);
+ }
+
+ @Override
+ public void onRequestContent(Request request, ByteBuffer content)
+ {
+ request.getHttpChannel().notifyEvent2(listener -> listener::onRequestContent, request, content);
+ }
+
+ @Override
+ public void onRequestContentEnd(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onRequestContentEnd, request);
+ }
+
+ @Override
+ public void onRequestTrailers(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onRequestTrailers, request);
+ }
+
+ @Override
+ public void onRequestEnd(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onRequestEnd, request);
+ }
+
+ @Override
+ public void onRequestFailure(Request request, Throwable failure)
+ {
+ request.getHttpChannel().notifyEvent2(listener -> listener::onRequestFailure, request, failure);
+ }
+
+ @Override
+ public void onResponseBegin(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onResponseBegin, request);
+ }
+
+ @Override
+ public void onResponseCommit(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onResponseCommit, request);
+ }
+
+ @Override
+ public void onResponseContent(Request request, ByteBuffer content)
+ {
+ request.getHttpChannel().notifyEvent2(listener -> listener::onResponseContent, request, content);
+ }
+
+ @Override
+ public void onResponseEnd(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onResponseEnd, request);
+ }
+
+ @Override
+ public void onResponseFailure(Request request, Throwable failure)
+ {
+ request.getHttpChannel().notifyEvent2(listener -> listener::onResponseFailure, request, failure);
+ }
+
+ @Override
+ public void onComplete(Request request)
+ {
+ request.getHttpChannel().notifyEvent1(listener -> listener::onComplete, request);
+ }
+ }
}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelListeners.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelListeners.java
new file mode 100644
index 00000000000..281c7f5eb04
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelListeners.java
@@ -0,0 +1,286 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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.server;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * A {@link HttpChannel.Listener} that holds a collection of
+ * other {@link HttpChannel.Listener} instances that are efficiently
+ * invoked without iteration.
+ * @see AbstractConnector
+ */
+public class HttpChannelListeners implements HttpChannel.Listener
+{
+ static final Logger LOG = Log.getLogger(HttpChannel.class);
+ public static HttpChannel.Listener NOOP = new HttpChannel.Listener() {};
+
+ private final NotifyRequest onRequestBegin;
+ private final NotifyRequest onBeforeDispatch;
+ private final NotifyFailure onDispatchFailure;
+ private final NotifyRequest onAfterDispatch;
+ private final NotifyContent onRequestContent;
+ private final NotifyRequest onRequestContentEnd;
+ private final NotifyRequest onRequestTrailers;
+ private final NotifyRequest onRequestEnd;
+ private final NotifyFailure onRequestFailure;
+ private final NotifyRequest onResponseBegin;
+ private final NotifyRequest onResponseCommit;
+ private final NotifyContent onResponseContent;
+ private final NotifyRequest onResponseEnd;
+ private final NotifyFailure onResponseFailure;
+ private final NotifyRequest onComplete;
+
+ public HttpChannelListeners(Collection listeners)
+ {
+ try
+ {
+ NotifyRequest onRequestBegin = NotifyRequest.NOOP;
+ NotifyRequest onBeforeDispatch = NotifyRequest.NOOP;
+ NotifyFailure onDispatchFailure = NotifyFailure.NOOP;
+ NotifyRequest onAfterDispatch = NotifyRequest.NOOP;
+ NotifyContent onRequestContent = NotifyContent.NOOP;
+ NotifyRequest onRequestContentEnd = NotifyRequest.NOOP;
+ NotifyRequest onRequestTrailers = NotifyRequest.NOOP;
+ NotifyRequest onRequestEnd = NotifyRequest.NOOP;
+ NotifyFailure onRequestFailure = NotifyFailure.NOOP;
+ NotifyRequest onResponseBegin = NotifyRequest.NOOP;
+ NotifyRequest onResponseCommit = NotifyRequest.NOOP;
+ NotifyContent onResponseContent = NotifyContent.NOOP;
+ NotifyRequest onResponseEnd = NotifyRequest.NOOP;
+ NotifyFailure onResponseFailure = NotifyFailure.NOOP;
+ NotifyRequest onComplete = NotifyRequest.NOOP;
+
+ for (HttpChannel.Listener listener : listeners)
+ {
+ if (!listener.getClass().getMethod("onRequestBegin", Request.class).isDefault())
+ onRequestBegin = combine(onRequestBegin, listener::onRequestBegin);
+ if (!listener.getClass().getMethod("onBeforeDispatch", Request.class).isDefault())
+ onBeforeDispatch = combine(onBeforeDispatch, listener::onBeforeDispatch);
+ if (!listener.getClass().getMethod("onDispatchFailure", Request.class, Throwable.class).isDefault())
+ onDispatchFailure = combine(onDispatchFailure, listener::onDispatchFailure);
+ if (!listener.getClass().getMethod("onAfterDispatch", Request.class).isDefault())
+ onAfterDispatch = combine(onAfterDispatch, listener::onAfterDispatch);
+ if (!listener.getClass().getMethod("onRequestContent", Request.class, ByteBuffer.class).isDefault())
+ onRequestContent = combine(onRequestContent, listener::onRequestContent);
+ if (!listener.getClass().getMethod("onRequestContentEnd", Request.class).isDefault())
+ onRequestContentEnd = combine(onRequestContentEnd, listener::onRequestContentEnd);
+ if (!listener.getClass().getMethod("onRequestTrailers", Request.class).isDefault())
+ onRequestTrailers = combine(onRequestTrailers, listener::onRequestTrailers);
+ if (!listener.getClass().getMethod("onRequestEnd", Request.class).isDefault())
+ onRequestEnd = combine(onRequestEnd, listener::onRequestEnd);
+ if (!listener.getClass().getMethod("onRequestFailure", Request.class, Throwable.class).isDefault())
+ onRequestFailure = combine(onRequestFailure, listener::onRequestFailure);
+ if (!listener.getClass().getMethod("onResponseBegin", Request.class).isDefault())
+ onResponseBegin = combine(onResponseBegin, listener::onResponseBegin);
+ if (!listener.getClass().getMethod("onResponseCommit", Request.class).isDefault())
+ onResponseCommit = combine(onResponseCommit, listener::onResponseCommit);
+ if (!listener.getClass().getMethod("onResponseContent", Request.class, ByteBuffer.class).isDefault())
+ onResponseContent = combine(onResponseContent, listener::onResponseContent);
+ if (!listener.getClass().getMethod("onResponseEnd", Request.class).isDefault())
+ onResponseEnd = combine(onResponseEnd, listener::onResponseEnd);
+ if (!listener.getClass().getMethod("onResponseFailure", Request.class, Throwable.class).isDefault())
+ onResponseFailure = combine(onResponseFailure, listener::onResponseFailure);
+ if (!listener.getClass().getMethod("onComplete", Request.class).isDefault())
+ onComplete = combine(onComplete, listener::onComplete);
+ }
+
+ this.onRequestBegin = onRequestBegin;
+ this.onBeforeDispatch = onBeforeDispatch;
+ this.onDispatchFailure = onDispatchFailure;
+ this.onAfterDispatch = onAfterDispatch;
+ this.onRequestContent = onRequestContent;
+ this.onRequestContentEnd = onRequestContentEnd;
+ this.onRequestTrailers = onRequestTrailers;
+ this.onRequestEnd = onRequestEnd;
+ this.onRequestFailure = onRequestFailure;
+ this.onResponseBegin = onResponseBegin;
+ this.onResponseCommit = onResponseCommit;
+ this.onResponseContent = onResponseContent;
+ this.onResponseEnd = onResponseEnd;
+ this.onResponseFailure = onResponseFailure;
+ this.onComplete = onComplete;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void onRequestBegin(Request request)
+ {
+ onRequestBegin.onRequest(request);
+ }
+
+ @Override
+ public void onBeforeDispatch(Request request)
+ {
+ onBeforeDispatch.onRequest(request);
+ }
+
+ @Override
+ public void onDispatchFailure(Request request, Throwable failure)
+ {
+ onDispatchFailure.onFailure(request, failure);
+ }
+
+ @Override
+ public void onAfterDispatch(Request request)
+ {
+ onAfterDispatch.onRequest(request);
+ }
+
+ @Override
+ public void onRequestContent(Request request, ByteBuffer content)
+ {
+ onRequestContent.onContent(request, content);
+ }
+
+ @Override
+ public void onRequestContentEnd(Request request)
+ {
+ onRequestContentEnd.onRequest(request);
+ }
+
+ @Override
+ public void onRequestTrailers(Request request)
+ {
+ onRequestTrailers.onRequest(request);
+ }
+
+ @Override
+ public void onRequestEnd(Request request)
+ {
+ onRequestEnd.onRequest(request);
+ }
+
+ @Override
+ public void onRequestFailure(Request request, Throwable failure)
+ {
+ onRequestFailure.onFailure(request, failure);
+ }
+
+ @Override
+ public void onResponseBegin(Request request)
+ {
+ onResponseBegin.onRequest(request);
+ }
+
+ @Override
+ public void onResponseCommit(Request request)
+ {
+ onResponseCommit.onRequest(request);
+ }
+
+ @Override
+ public void onResponseContent(Request request, ByteBuffer content)
+ {
+ onResponseContent.onContent(request, content);
+ }
+
+ @Override
+ public void onResponseEnd(Request request)
+ {
+ onResponseEnd.onRequest(request);
+ }
+
+ @Override
+ public void onResponseFailure(Request request, Throwable failure)
+ {
+ onResponseFailure.onFailure(request, failure);
+ }
+
+ @Override
+ public void onComplete(Request request)
+ {
+ onComplete.onRequest(request);
+ }
+
+ private interface NotifyRequest
+ {
+ void onRequest(Request request);
+
+ NotifyRequest NOOP = request ->
+ {
+ };
+ }
+
+ private interface NotifyFailure
+ {
+ void onFailure(Request request, Throwable failure);
+
+ NotifyFailure NOOP = (request, failure) ->
+ {
+ };
+ }
+
+ private interface NotifyContent
+ {
+ void onContent(Request request, ByteBuffer content);
+
+ NotifyContent NOOP = (request, content) ->
+ {
+ };
+ }
+
+ private static NotifyRequest combine(NotifyRequest first, NotifyRequest second)
+ {
+ if (first == NotifyRequest.NOOP)
+ return second;
+ if (second == NotifyRequest.NOOP)
+ return first;
+ return request ->
+ {
+ first.onRequest(request);
+ second.onRequest(request);
+ };
+ }
+
+ private static NotifyFailure combine(NotifyFailure first, NotifyFailure second)
+ {
+ if (first == NotifyFailure.NOOP)
+ return second;
+ if (second == NotifyFailure.NOOP)
+ return first;
+ return (request, throwable) ->
+ {
+ first.onFailure(request, throwable);
+ second.onFailure(request, throwable);
+ };
+ }
+
+ private static NotifyContent combine(NotifyContent first, NotifyContent second)
+ {
+ if (first == NotifyContent.NOOP)
+ return (request, content) -> second.onContent(request, content.slice());
+ if (second == NotifyContent.NOOP)
+ return (request, content) -> first.onContent(request, content.slice());
+ return (request, content) ->
+ {
+ content = content.slice();
+ first.onContent(request, content);
+ second.onContent(request, content);
+ };
+ }
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
index a57a550d80b..ef94f6cbf80 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
@@ -1873,6 +1873,7 @@ public class Request implements HttpServletRequest
_remote = null;
_sessions = null;
_input.recycle();
+ _requestAttributeListeners.clear();
}
/*
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpChannelEventTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpChannelEventTest.java
index 15bbfaf9d36..516a81aeeb2 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpChannelEventTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpChannelEventTest.java
@@ -240,6 +240,37 @@ public class HttpChannelEventTest
assertThat(elapsed.get(), Matchers.greaterThan(0L));
}
+ @Test
+ public void testTransientListener() throws Exception
+ {
+ start(new TestHandler());
+
+ CountDownLatch latch = new CountDownLatch(1);
+ connector.addBean(new HttpChannel.TransientListeners());
+ connector.addBean(new HttpChannel.Listener()
+ {
+ @Override
+ public void onRequestBegin(Request request)
+ {
+ request.getHttpChannel().addListener(new HttpChannel.Listener()
+ {
+ @Override
+ public void onComplete(Request request)
+ {
+ latch.countDown();
+ }
+ });
+ }
+ });
+
+ HttpTester.Request request = HttpTester.newRequest();
+ request.setHeader("Host", "localhost");
+ HttpTester.Response response = HttpTester.parseResponse(connector.getResponse(request.toString(), 5, TimeUnit.SECONDS));
+
+ assertEquals(HttpStatus.OK_200, response.getStatus());
+ assertTrue(latch.await(5, TimeUnit.SECONDS));
+ }
+
private static class TestHandler extends AbstractHandler.ErrorDispatchHandler
{
@Override
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java
index fcabf1acfe9..a537317f7f9 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputAsyncStateTest.java
@@ -95,7 +95,7 @@ public class HttpInputAsyncStateTest
public void before()
{
_noReadInDataAvailable = false;
- _in = new HttpInput(new HttpChannelState(new HttpChannel(null, new HttpConfiguration(), null, null)
+ _in = new HttpInput(new HttpChannelState(new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null)
{
@Override
public void onAsyncWaitForContent()
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 c2b43ed0954..fa9fa1a25df 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
@@ -92,7 +92,7 @@ public class HttpInputTest
@BeforeEach
public void before()
{
- _in = new HttpInput(new HttpChannelState(new HttpChannel(null, new HttpConfiguration(), null, null)
+ _in = new HttpInput(new HttpChannelState(new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null)
{
@Override
public void onAsyncWaitForContent()
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java
index 69a3dd171bb..c2a54f8de30 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java
@@ -45,7 +45,7 @@ public class HttpWriterTest
final ByteBufferPool pool = new ArrayByteBufferPool();
- HttpChannel channel = new HttpChannel(null, new HttpConfiguration(), null, null)
+ HttpChannel channel = new HttpChannel(new MockConnector(), new HttpConfiguration(), null, null)
{
@Override
public ByteBufferPool getByteBufferPool()
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/MockConnector.java b/jetty-server/src/test/java/org/eclipse/jetty/server/MockConnector.java
new file mode 100644
index 00000000000..847bc34b7f9
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/MockConnector.java
@@ -0,0 +1,46 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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.server;
+
+import java.io.IOException;
+
+class MockConnector extends AbstractConnector
+{
+ public MockConnector()
+ {
+ super(new Server() , null, null, null, 0);
+ }
+
+ @Override
+ protected void accept(int acceptorID) throws IOException, InterruptedException
+ {
+ }
+
+ @Override
+ public Object getTransport()
+ {
+ return null;
+ }
+
+ @Override
+ public String dumpSelf()
+ {
+ return null;
+ }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java
index b195e150095..51a75156767 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java
@@ -43,7 +43,7 @@ public interface Container
/**
* @param clazz the class of the beans
* @param the Bean type
- * @return the list of beans of the given class (or subclass)
+ * @return a list of beans of the given class (or subclass)
* @see #getBeans()
* @see #getContainedBeans(Class)
*/
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredInvalidationSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredInvalidationSessionTest.java
index ecce32321af..e0af754ec22 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredInvalidationSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredInvalidationSessionTest.java
@@ -65,8 +65,8 @@ public abstract class AbstractClusteredInvalidationSessionTest extends AbstractT
TestServer server1 = new TestServer(0, maxInactiveInterval, scavengeInterval, cacheFactory1, storeFactory1);
ServletContextHandler context = server1.addContext(contextPath);
context.addServlet(TestServlet.class, servletMapping);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- context.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
try
{
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java
index d812834eb30..06bf2f6edc9 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java
@@ -77,8 +77,8 @@ public abstract class AbstractClusteredSessionScavengingTest extends AbstractTes
TestServlet servlet1 = new TestServlet();
ServletHolder holder1 = new ServletHolder(servlet1);
ServletContextHandler context = server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- context.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
TestSessionListener listener1 = new TestSessionListener();
context.getSessionHandler().addEventListener(listener1);
context.addServlet(holder1, servletMapping);
@@ -96,8 +96,8 @@ public abstract class AbstractClusteredSessionScavengingTest extends AbstractTes
((AbstractSessionDataStoreFactory)storeFactory2).setSavePeriodSec(0); //always save when the session exits
TestServer server2 = new TestServer(0, maxInactivePeriod, scavengePeriod, cacheFactory2, storeFactory2);
ServletContextHandler context2 = server2.addContext(contextPath);
- TestContextScopeListener scopeListener2 = new TestContextScopeListener();
- context2.addEventListener(scopeListener2);
+ TestHttpChannelCompleteListener scopeListener2 = new TestHttpChannelCompleteListener();
+ server2.getServerConnector().addBean(scopeListener2);
context2.addServlet(TestServlet.class, servletMapping);
SessionHandler m2 = context2.getSessionHandler();
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java
index 967085da2f9..8fcc6bfca1e 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java
@@ -23,7 +23,6 @@ import java.io.FileOutputStream;
import java.io.FileWriter;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.HttpClient;
@@ -103,8 +102,8 @@ public abstract class AbstractWebAppObjectInSessionTest extends AbstractTestBase
TestServer server1 = new TestServer(0, TestServer.DEFAULT_MAX_INACTIVE, TestServer.DEFAULT_SCAVENGE_SEC,
cacheFactory, storeFactory);
WebAppContext wac1 = server1.addWebAppContext(warDir.getCanonicalPath(), contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- wac1.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
wac1.addServlet(WebAppObjectInSessionServlet.class.getName(), servletMapping);
try
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestContextScopeListener.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestContextScopeListener.java
deleted file mode 100644
index 99f4d0e13a2..00000000000
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestContextScopeListener.java
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2019 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.server.session;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jetty.server.HttpChannel.Listener;
-import org.eclipse.jetty.server.HttpChannelState;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.ContextHandler.Context;
-import org.eclipse.jetty.server.handler.ContextHandler.ContextScopeListener;
-
-public class TestContextScopeListener implements ContextScopeListener
-{
- AtomicReference _exitSynchronizer = new AtomicReference<>();
- boolean listenerAdded = false;
-
- /**
- * @return the exitSynchronizer
- */
- public CountDownLatch getExitSynchronizer()
- {
- return _exitSynchronizer.get();
- }
-
- /**
- * @param exitSynchronizer the exitSynchronizer to set
- */
- public void setExitSynchronizer(CountDownLatch exitSynchronizer)
- {
- _exitSynchronizer.set(exitSynchronizer);
- }
-
- @Override
- public void enterScope(Context context, org.eclipse.jetty.server.Request request, Object reason)
- {
- //noop
- }
-
- @Override
- public void exitScope(final Context context, final org.eclipse.jetty.server.Request request)
- {
- if (request != null && !listenerAdded)
- {
- listenerAdded = true;
- request.getHttpChannel().addListener(new Listener()
- {
- @Override
- public void onComplete(Request request)
- {
- Listener.super.onComplete(request);
- if (_exitSynchronizer.get() != null)
- _exitSynchronizer.get().countDown();
- }
-
- });
- }
- }
-}
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpChannelCompleteListener.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpChannelCompleteListener.java
new file mode 100644
index 00000000000..7fb22f00007
--- /dev/null
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpChannelCompleteListener.java
@@ -0,0 +1,45 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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.server.session;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.server.HttpChannel.Listener;
+import org.eclipse.jetty.server.Request;
+
+public class TestHttpChannelCompleteListener implements Listener
+{
+ private final AtomicReference _exitSynchronizer = new AtomicReference<>();
+
+ /**
+ * @param exitSynchronizer the exitSynchronizer to set
+ */
+ public void setExitSynchronizer(CountDownLatch exitSynchronizer)
+ {
+ _exitSynchronizer.set(exitSynchronizer);
+ }
+
+ @Override
+ public void onComplete(Request request)
+ {
+ if (_exitSynchronizer.get() != null)
+ _exitSynchronizer.get().countDown();
+ }
+}
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestServer.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestServer.java
index 85f3d5dd341..f66bdfc1c5a 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestServer.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestServer.java
@@ -20,6 +20,7 @@ package org.eclipse.jetty.server.session;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SessionIdManager;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
@@ -93,6 +94,11 @@ public class TestServer
return h;
}
+ public ServerConnector getServerConnector()
+ {
+ return _server.getBean(ServerConnector.class);
+ }
+
public void start() throws Exception
{
// server -> contexts collection -> context handler -> session handler -> servlet handler
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AsyncTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AsyncTest.java
index 4a0f031b2f6..8d2ae14a05b 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AsyncTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AsyncTest.java
@@ -22,7 +22,6 @@ import java.io.IOException;
import java.lang.reflect.Proxy;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
@@ -65,8 +64,8 @@ public class AsyncTest
String mapping = "/server";
ServletContextHandler contextHandler = server.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
contextHandler.addServlet(holder, mapping);
@@ -117,8 +116,8 @@ public class AsyncTest
String mapping = "/server";
ServletContextHandler contextHandler = server.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
contextHandler.addServlet(holder, mapping);
@@ -167,8 +166,8 @@ public class AsyncTest
TestServer server = new TestServer(0, -1, -1, cacheFactory, storeFactory);
ServletContextHandler contextA = server.addContext("/ctxA");
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextA.addEventListener(scopeListener); //just pick one of the contexts to register the listener
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener); //just pick one of the contexts to register the listener
CrossContextServlet ccServlet = new CrossContextServlet();
ServletHolder ccHolder = new ServletHolder(ccServlet);
contextA.addServlet(ccHolder, "/*");
@@ -224,8 +223,8 @@ public class AsyncTest
String mapping = "/server";
ServletContextHandler contextHandler = server.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
@@ -277,8 +276,8 @@ public class AsyncTest
TestServer server = new TestServer(0, -1, -1, cacheFactory, storeFactory);
ServletContextHandler contextA = server.addContext("/ctxA");
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextA.addEventListener(scopeListener); //just pick a context
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
CrossContextServlet ccServlet = new CrossContextServlet();
ServletHolder ccHolder = new ServletHolder(ccServlet);
contextA.addServlet(ccHolder, "/*");
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java
index 7c8e8872d56..d2891111e43 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java
@@ -76,8 +76,8 @@ public class CreationTest
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
ServletContextHandler contextHandler = server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore());
server1.start();
@@ -145,8 +145,8 @@ public class CreationTest
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
ServletContextHandler contextHandler = server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore());
server1.start();
@@ -197,8 +197,8 @@ public class CreationTest
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
ServletContextHandler contextHandler = server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore());
server1.start();
@@ -245,8 +245,8 @@ public class CreationTest
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
ServletContextHandler contextHandler = server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore());
server1.start();
@@ -299,8 +299,8 @@ public class CreationTest
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
ServletContextHandler contextHandler = server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
ServletContextHandler ctxB = server1.addContext(contextB);
ctxB.addServlet(TestServletB.class, servletMapping);
@@ -354,8 +354,8 @@ public class CreationTest
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
ServletContextHandler contextHandler = server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
ServletContextHandler ctxB = server1.addContext(contextB);
ctxB.addServlet(TestServletB.class, servletMapping);
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java
index 87182acca2f..21b9bc44b83 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java
@@ -22,7 +22,6 @@ import java.util.Collections;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
@@ -79,8 +78,8 @@ public class DefaultSessionCacheTest
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
TestServer server = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory);
ServletContextHandler contextHandler = server.addContext("/test");
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
TestHttpSessionListener listener = new TestHttpSessionListener();
contextHandler.getSessionHandler().addEventListener(listener);
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java
index 6913d87acc3..2ede7430b8b 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java
@@ -151,8 +151,8 @@ public class DeleteUnloadableSessionTest
TestServer server = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory);
ServletContextHandler context = server.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- context.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java
index 640c37801bd..92505dcfa75 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java
@@ -94,8 +94,8 @@ public class DirtyAttributeTest
ServletContextHandler ctxA = server.addContext("/mod");
ctxA.addServlet(TestDirtyServlet.class, "/test");
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- ctxA.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
server.start();
int port = server.getPort();
@@ -125,14 +125,12 @@ public class DirtyAttributeTest
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
//ensure request fully finished processing
- latch.await(5, TimeUnit.SECONDS);
+ assertTrue(latch.await(5, TimeUnit.SECONDS));
A_VALUE.assertPassivatesEquals(1);
A_VALUE.assertActivatesEquals(1);
A_VALUE.assertBindsEquals(1);
A_VALUE.assertUnbindsEquals(0);
-
-
//do another request using the cookie to try changing the session attribute to the same value again
latch = new CountDownLatch(1);
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java
index a11efa8436a..113e4a73aa3 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java
@@ -76,8 +76,8 @@ public class IdleSessionTest
_server1 = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory);
ServletHolder holder = new ServletHolder(_servlet);
ServletContextHandler contextHandler = _server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ _server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
_server1.start();
int port1 = _server1.getPort();
@@ -202,8 +202,8 @@ public class IdleSessionTest
_server1 = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory);
ServletHolder holder = new ServletHolder(_servlet);
ServletContextHandler contextHandler = _server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ _server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
_server1.start();
int port1 = _server1.getPort();
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java
index 07c3b8f284c..0c7d6b43dc7 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java
@@ -75,8 +75,8 @@ public class NonClusteredSessionScavengingTest extends AbstractTestBase
context1.addServlet(TestServlet.class, servletMapping);
TestHttpSessionListener listener = new TestHttpSessionListener();
context1.getSessionHandler().addEventListener(listener);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- context1.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server1.getServerConnector().addBean(scopeListener);
try
{
@@ -144,8 +144,8 @@ public class NonClusteredSessionScavengingTest extends AbstractTestBase
TestServer server = new TestServer(0, maxInactivePeriod, scavengePeriod,
cacheFactory, storeFactory);
ServletContextHandler context = server.addContext("/");
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- context.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
_dataStore = context.getSessionHandler().getSessionCache().getSessionDataStore();
context.addServlet(TestServlet.class, servletMapping);
@@ -208,8 +208,8 @@ public class NonClusteredSessionScavengingTest extends AbstractTestBase
TestServer server = new TestServer(0, maxInactivePeriod, scavengePeriod,
cacheFactory, storeFactory);
ServletContextHandler context = server.addContext("/");
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- context.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
_dataStore = context.getSessionHandler().getSessionCache().getSessionDataStore();
context.addServlet(TestServlet.class, servletMapping);
String contextPath = "/";
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java
index 731a7c9ad37..663444b8a82 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java
@@ -59,8 +59,8 @@ public class ReentrantRequestSessionTest
ServletContextHandler context = server.addContext(contextPath);
context.addServlet(TestServlet.class, servletMapping);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- context.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ server.getServerConnector().addBean(scopeListener);
try
{
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java
index 368283c365f..2fe9d7b4469 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java
@@ -58,8 +58,8 @@ public class SameContextForwardedSessionTest
TestServer testServer = new TestServer(0, -1, -1, cacheFactory, storeFactory);
ServletContextHandler testServletContextHandler = testServer.addContext("/context");
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- testServletContextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ testServer.getServerConnector().addBean(scopeListener);
ServletHolder holder = new ServletHolder(new Servlet1());
testServletContextHandler.addServlet(holder, "/one");
testServletContextHandler.addServlet(Servlet2.class, "/two");
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java
index a036bd0bd5c..4acc49516aa 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java
@@ -124,8 +124,8 @@ public class SaveOptimizeTest
_servlet = new TestServlet();
ServletHolder holder = new ServletHolder(_servlet);
ServletContextHandler contextHandler = _server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ _server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
_servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore());
_server1.start();
@@ -207,8 +207,8 @@ public class SaveOptimizeTest
_servlet = new TestServlet();
ServletHolder holder = new ServletHolder(_servlet);
ServletContextHandler contextHandler = _server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ _server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
_servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore());
_server1.start();
@@ -297,8 +297,8 @@ public class SaveOptimizeTest
_servlet = new TestServlet();
ServletHolder holder = new ServletHolder(_servlet);
ServletContextHandler contextHandler = _server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ _server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
_servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore());
_server1.start();
@@ -392,8 +392,8 @@ public class SaveOptimizeTest
_servlet = new TestServlet();
ServletHolder holder = new ServletHolder(_servlet);
ServletContextHandler contextHandler = _server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ _server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
_servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore());
_server1.start();
@@ -471,8 +471,8 @@ public class SaveOptimizeTest
_servlet = new TestServlet();
ServletHolder holder = new ServletHolder(_servlet);
ServletContextHandler contextHandler = _server1.addContext(contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextHandler.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ _server1.getServerConnector().addBean(scopeListener);
contextHandler.addServlet(holder, servletMapping);
_servlet.setStore(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore());
_server1.start();
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java
index 828991aee94..69b8b5ec813 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java
@@ -22,7 +22,6 @@ import java.io.IOException;
import java.net.HttpCookie;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@@ -41,7 +40,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
-import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
@@ -118,8 +116,8 @@ public class SessionRenewTest
String contextPathA = "";
String servletMapping = "/server";
WebAppContext contextA = _server.addWebAppContext(".", contextPathA);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- contextA.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ _server.getServerConnector().addBean(scopeListener);
contextA.setParentLoaderPriority(true);
contextA.addServlet(TestServlet.class, servletMapping);
@@ -185,8 +183,8 @@ public class SessionRenewTest
String contextPath = "";
String servletMapping = "/server";
WebAppContext context = _server.addWebAppContext(".", contextPath);
- TestContextScopeListener scopeListener = new TestContextScopeListener();
- context.addEventListener(scopeListener);
+ TestHttpChannelCompleteListener scopeListener = new TestHttpChannelCompleteListener();
+ _server.getServerConnector().addBean(scopeListener);
context.setParentLoaderPriority(true);
context.addServlet(TestServlet.class, servletMapping);
TestHttpSessionIdListener testListener = new TestHttpSessionIdListener();
From 2564a08150bc36e81c02a20fcadfe4b8f9bcf8b3 Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Tue, 27 Aug 2019 18:43:33 +1000
Subject: [PATCH 37/55] fix checkstyle
Signed-off-by: Greg Wilkins
---
.../jetty/server/session/NullSessionCache.java | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCache.java
index 6e88ab45a7c..e22919eed7b 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCache.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCache.java
@@ -25,7 +25,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
-
/**
* NullSessionCache
*
@@ -75,8 +74,7 @@ public class NullSessionCache extends AbstractSessionCache
if (store == null)
return;
- if (_writeThroughMode == WriteThroughMode.ALWAYS
- || (_writeThroughMode == WriteThroughMode.NEW && session.isNew()))
+ if (_writeThroughMode == WriteThroughMode.ALWAYS || (_writeThroughMode == WriteThroughMode.NEW && session.isNew()))
{
//ensure that a call to willPassivate doesn't result in a passivation
//listener removing an attribute, which would cause this listener to
@@ -128,11 +126,10 @@ public class NullSessionCache extends AbstractSessionCache
* (which is the default behaviour of AbstractSessionCache)
*/
ON_EXIT
- };
+ }
private WriteThroughMode _writeThroughMode = WriteThroughMode.ON_EXIT;
protected WriteThroughAttributeListener _listener = null;
-
/**
* @return the writeThroughMode
@@ -142,14 +139,13 @@ public class NullSessionCache extends AbstractSessionCache
return _writeThroughMode;
}
-
/**
* @param writeThroughMode the writeThroughMode to set
*/
public void setWriteThroughMode(WriteThroughMode writeThroughMode)
{
if (getSessionHandler() == null)
- throw new IllegalStateException ("No SessionHandler");
+ throw new IllegalStateException("No SessionHandler");
//assume setting null is the same as ON_EXIT
if (writeThroughMode == null)
@@ -184,7 +180,6 @@ public class NullSessionCache extends AbstractSessionCache
_writeThroughMode = writeThroughMode;
}
-
/**
* @param handler The SessionHandler related to this SessionCache
*/
@@ -193,7 +188,6 @@ public class NullSessionCache extends AbstractSessionCache
super(handler);
super.setEvictionPolicy(EVICT_ON_SESSION_EXIT);
}
-
/**
* @see org.eclipse.jetty.server.session.SessionCache#shutdown()
From d1c462c966982a50e8647a69e82b526326cfa7ef Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Tue, 27 Aug 2019 19:06:32 +1000
Subject: [PATCH 38/55] fix checkstyle
Signed-off-by: Greg Wilkins
---
.../src/main/java/org/eclipse/jetty/http/CookieCutter.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCutter.java b/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCutter.java
index 2b137337842..d0ca77ba9d4 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCutter.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCutter.java
@@ -192,7 +192,7 @@ public abstract class CookieCutter
// This is a new cookie, so add the completed last cookie if we have one
if (cookieName != null)
{
- if(!reject)
+ if (!reject)
{
addCookie(cookieName, cookieValue, cookieDomain, cookiePath, cookieVersion, cookieComment);
reject = false;
From 4d8e8050bd1940e8e1913ec62f6c959a088ff128 Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Tue, 27 Aug 2019 08:48:02 -0500
Subject: [PATCH 39/55] Fixes #4007 - using `user.home` system property instead
of $HOME
Signed-off-by: Joakim Erdfelt
---
.../src/main/java/org/eclipse/jetty/start/StartArgs.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
index 028f5d7fdd3..09cf73b011d 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
@@ -842,7 +842,7 @@ public class StartArgs
if (Utils.isBlank(localRepo))
{
// Try generic env variable
- Path home = Paths.get(System.getenv("HOME"));
+ Path home = Paths.get(System.getProperty("user.home"));
Path localMavenRepository = home.resolve(".m2/repository");
if (Files.exists(localMavenRepository))
localRepo = localMavenRepository.toString();
From 6bcfa2dc6ef409ce0ef55b81d7765f63e4cd5b86 Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Tue, 27 Aug 2019 13:25:08 -0500
Subject: [PATCH 40/55] Fixes #4020 - Deprecate ExtensionFactory
+ This class is removed in Jetty 10 anyway.
+ If all you want is to access available extension names
then use the Factory.getAvailableExtensionNames() method
(which exists in Jetty 10.0.0 as well)
Signed-off-by: Joakim Erdfelt
---
.../api/extensions/ExtensionFactory.java | 6 ++++++
.../server/WebSocketServerFactory.java | 8 ++++++++
.../servlet/WebSocketServletFactory.java | 17 +++++++++++++++++
3 files changed, 31 insertions(+)
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java
index 8d46d60a5eb..94a27769457 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java
@@ -24,6 +24,12 @@ import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
+/**
+ * The Factory for Extensions.
+ *
+ * @deprecated this class is removed from Jetty 10.0.0+
+ */
+@Deprecated
public abstract class ExtensionFactory implements Iterable>
{
private ServiceLoader extensionLoader = ServiceLoader.load(Extension.class);
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
index 520302d95f5..2b5e116bd08 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
@@ -29,6 +29,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.Executor;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
@@ -450,6 +451,13 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
return eventDriverFactory;
}
+ @Override
+ public Set getAvailableExtensionNames()
+ {
+ return Collections.unmodifiableSet(extensionFactory.getExtensionNames());
+ }
+
+ @Deprecated
@Override
public ExtensionFactory getExtensionFactory()
{
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java
index fec0084cd30..b2d98b18ff6 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java
@@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.servlet;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -66,8 +67,24 @@ public interface WebSocketServletFactory
void stop() throws Exception;
+ /**
+ * Get the set of available Extensions by registered name.
+ *
+ * @return the set of available extensions by registered name.
+ */
+ Set getAvailableExtensionNames();
+
WebSocketCreator getCreator();
+ /**
+ * Get the registered extensions for this WebSocket factory.
+ *
+ * @return the ExtensionFactory
+ * @see #getAvailableExtensionNames()
+ * @deprecated this class is removed from Jetty 10.0.0+. To remove specific extensions
+ * from negotiation use {@link WebSocketCreator} to remove then during handshake.
+ */
+ @Deprecated
ExtensionFactory getExtensionFactory();
/**
From eef2481b59294b5783f3c4a3ea24f3262252c294 Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Tue, 27 Aug 2019 14:09:06 -0500
Subject: [PATCH 41/55] Adding cookie parsing test for excessive semicolon
(reported as CVE in other projects)
---
.../eclipse/jetty/server/CookieCutterTest.java | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/CookieCutterTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/CookieCutterTest.java
index 04019ade121..77a7a74c24c 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/CookieCutterTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/CookieCutterTest.java
@@ -18,6 +18,7 @@
package org.eclipse.jetty.server;
+import java.util.Arrays;
import javax.servlet.http.Cookie;
import org.eclipse.jetty.http.CookieCompliance;
@@ -259,4 +260,18 @@ public class CookieCutterTest
assertCookie("Cookies[0]", cookies[0], "server.id", "abcd", 0, null);
assertCookie("Cookies[1]", cookies[1], "server.detail", "cfg", 0, null);
}
+
+ @Test
+ public void testExcessiveSemicolons()
+ {
+ char[] excessive = new char[65535];
+ Arrays.fill(excessive, ';');
+ String rawCookie = "foo=bar; " + excessive + "; xyz=pdq";
+
+ Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie);
+
+ assertThat("Cookies.length", cookies.length, is(2));
+ assertCookie("Cookies[0]", cookies[0], "foo", "bar", 0, null);
+ assertCookie("Cookies[1]", cookies[1], "xyz", "pdq", 0, null);
+ }
}
From 8f383faf7866a6b417ff3241d69f8100f219b0b8 Mon Sep 17 00:00:00 2001
From: Greg Wilkins
Date: Wed, 28 Aug 2019 10:03:46 +1000
Subject: [PATCH 42/55] Issue #3872 Javax Websocket Packaging (#3873)
* Issue #3872 Javax Websocket Packaging
Moved JaxaxWebSocketConfiguration and SCI to config package.
Limited classpath exposure in JavaxConfiguration (more needed)
Updated tests with work around for those that needs more classes exposed
Signed-off-by: Greg Wilkins
* Issue #3872 Javax Websocket Packaging
Moved all remaining classes from org.eclipse.jetty.websocket.javax.server
to org.eclipse.jetty.websocket.javax.server.internal.
This works when running on the classpath, but the tests fail when running
on the modulepath (eg in commandline mvn run). The issue appears to be
that the tests don't load test classes from WEB-INF/lib or WEB-INF/classes.
Instead the test classes were themselves in org.eclipse.jetty.websocket.javax.server,
which is no longer exported from module-info.java.
The hacked "fix" for this has been to create a org.eclipse.jetty.websocket.javax.server.tests
package which is exported and to move all the tests to that. A better fix is needed.
Signed-off-by: Greg Wilkins
* Issue #3872 Javax Websocket Packaging
improve comments
tighten exposed classes more
Signed-off-by: Greg Wilkins
* Issue #3872 - fixing tests
Signed-off-by: Lachlan Roberts
* Issue #3872 - move ContainerDefaultConfigurator to config package
Signed-off-by: Lachlan Roberts
* Issue #3873 - fix javax websocket test classloader issues
move websocket endpoints for test webapps to com.acme.websocket package
Signed-off-by: Lachlan Roberts
---
.../jetty/embedded/WebSocketJsrServer.java | 2 +-
.../jetty-osgi-boot/jettyhome/etc/jetty.xml | 2 +-
.../config/etc/jetty-with-custom-class.xml | 2 +-
.../src/test/config/etc/jetty.xml | 2 +-
.../src/main/java/module-info.java | 8 +-
.../ContainerDefaultConfigurator.java | 2 +-
.../JavaxWebSocketConfiguration.java | 5 +-
...xWebSocketServletContainerInitializer.java | 3 +-
.../AnnotatedServerEndpointConfig.java | 2 +-
.../JavaxWebSocketServerContainer.java | 6 +-
...vaxWebSocketServerFrameHandlerFactory.java | 4 +-
.../UndefinedServerEndpointConfig.java | 2 +-
.../javax.servlet.ServletContainerInitializer | 2 +-
...t.server.ServerEndpointConfig$Configurator | 2 +-
.../org.eclipse.jetty.webapp.Configuration | 2 +-
.../websocket/javax/server/PathParamTest.java | 61 ----------
.../server/browser/JsrBrowserDebugTool.java | 2 +-
.../WebSocketServerExamplesTest.java | 20 ++--
.../websocket/javax/tests/LocalServer.java | 6 +-
.../jetty/websocket/javax/tests/WSServer.java | 2 +-
.../com/acme/websocket/BasicEchoEndpoint.java | 46 ++++++++
...asicEchoEndpointConfigContextListener.java | 54 +++++++++
.../websocket/IdleTimeoutContextListener.java | 54 +++++++++
.../websocket/IdleTimeoutOnOpenEndpoint.java | 44 ++++++++
.../websocket/IdleTimeoutOnOpenSocket.java | 50 +++++++++
.../websocket/LargeEchoContextListener.java | 39 +++++++
.../websocket/LargeEchoDefaultSocket.java} | 14 ++-
.../websocket/OnOpenIdleTimeoutEndpoint.java | 44 ++++++++
.../acme/websocket/PongContextListener.java | 61 ++++++++++
.../acme/websocket/PongMessageEndpoint.java | 66 +++++++++++
.../java/com/acme/websocket/PongSocket.java | 67 +++++++++++
.../websocket/javax/tests/PathParamTest.java | 104 ++++++++++++++++++
.../javax/tests/RestartContextTest.java | 4 +-
...tJavaxWebSocketServerFrameHandlerTest.java | 4 +-
.../tests/server/DeploymentExceptionTest.java | 2 +-
.../tests/server/EndpointViaConfigTest.java | 61 +---------
.../javax/tests/server/IdleTimeoutTest.java | 6 +-
.../JettyServerEndpointConfiguratorTest.java | 2 +-
.../tests/server/LargeContainerTest.java | 34 +-----
.../javax/tests/server/MemoryUsageTest.java | 2 +-
.../javax/tests/server/PingPongTest.java | 103 +----------------
.../WebSocketServerContainerExecutorTest.java | 6 +-
.../basic-echo-endpoint-config-web.xml | 2 +-
.../resources/idle-timeout-config-web.xml | 2 +-
.../test/resources/large-echo-config-web.xml | 2 +-
.../src/test/resources/pong-config-web.xml | 2 +-
.../src/main/java/module-info.java | 1 +
47 files changed, 698 insertions(+), 315 deletions(-)
rename jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/{ => config}/ContainerDefaultConfigurator.java (98%)
rename jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/{ => config}/JavaxWebSocketConfiguration.java (89%)
rename jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/{ => config}/JavaxWebSocketServletContainerInitializer.java (98%)
rename jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/{ => internal}/JavaxWebSocketServerContainer.java (97%)
rename jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/{ => internal}/JavaxWebSocketServerFrameHandlerFactory.java (92%)
delete mode 100644 jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/PathParamTest.java
rename jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/{ => examples}/WebSocketServerExamplesTest.java (90%)
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/BasicEchoEndpoint.java
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/BasicEchoEndpointConfigContextListener.java
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutContextListener.java
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutOnOpenEndpoint.java
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutOnOpenSocket.java
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/LargeEchoContextListener.java
rename jetty-websocket/{javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/DummyServerContainer.java => javax-websocket-tests/src/test/java/com/acme/websocket/LargeEchoDefaultSocket.java} (70%)
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/OnOpenIdleTimeoutEndpoint.java
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongContextListener.java
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongMessageEndpoint.java
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongSocket.java
create mode 100644 jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/PathParamTest.java
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java
index d3ac32dafbd..473fae972ab 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java
@@ -26,7 +26,7 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
/**
* Example of setting up a javax.websocket server with Jetty embedded
diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml
index 17f38f2776d..70c174072ab 100644
--- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml
+++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml
@@ -96,7 +96,7 @@
- org.eclipse.jetty.webapp.JmxConfiguration
- org.eclipse.jetty.osgi.annotations.AnnotationConfiguration
- org.eclipse.jetty.websocket.server.config.JettyWebSocketConfiguration
- - org.eclipse.jetty.websocket.javax.server.JavaxWebSocketConfiguration
+ - org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketConfiguration
- org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration
- org.eclipse.jetty.osgi.boot.OSGiMetaInfConfiguration
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-with-custom-class.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-with-custom-class.xml
index 9cc5f6f72e7..6c2b9d68082 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-with-custom-class.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-with-custom-class.xml
@@ -82,7 +82,7 @@
- org.eclipse.jetty.plus.webapp.EnvConfiguration
- org.eclipse.jetty.webapp.JmxConfiguration
- org.eclipse.jetty.websocket.server.config.JettyWebSocketConfiguration
- - org.eclipse.jetty.websocket.javax.server.JavaxWebSocketConfiguration
+ - org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketConfiguration
- org.eclipse.jetty.osgi.annotations.AnnotationConfiguration
- org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration
- org.eclipse.jetty.osgi.boot.OSGiMetaInfConfiguration
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml
index 291fccd1873..ad2b008c33a 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml
@@ -85,7 +85,7 @@
- org.eclipse.jetty.webapp.JmxConfiguration
- org.eclipse.jetty.osgi.annotations.AnnotationConfiguration
- org.eclipse.jetty.websocket.server.config.JettyWebSocketConfiguration
- - org.eclipse.jetty.websocket.javax.server.JavaxWebSocketConfiguration
+ - org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketConfiguration
- org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration
- org.eclipse.jetty.osgi.boot.OSGiMetaInfConfiguration
diff --git a/jetty-websocket/javax-websocket-server/src/main/java/module-info.java b/jetty-websocket/javax-websocket-server/src/main/java/module-info.java
index 3c20f2e9d1d..8ef5adc7618 100644
--- a/jetty-websocket/javax-websocket-server/src/main/java/module-info.java
+++ b/jetty-websocket/javax-websocket-server/src/main/java/module-info.java
@@ -20,13 +20,13 @@ import javax.servlet.ServletContainerInitializer;
import javax.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.webapp.Configuration;
-import org.eclipse.jetty.websocket.javax.server.ContainerDefaultConfigurator;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketConfiguration;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.ContainerDefaultConfigurator;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketConfiguration;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
module org.eclipse.jetty.websocket.javax.server
{
- exports org.eclipse.jetty.websocket.javax.server;
+ exports org.eclipse.jetty.websocket.javax.server.config;
requires jetty.servlet.api;
requires jetty.websocket.api;
diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/ContainerDefaultConfigurator.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/config/ContainerDefaultConfigurator.java
similarity index 98%
rename from jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/ContainerDefaultConfigurator.java
rename to jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/config/ContainerDefaultConfigurator.java
index b4acdeb8b01..9906438cc3f 100644
--- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/ContainerDefaultConfigurator.java
+++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/config/ContainerDefaultConfigurator.java
@@ -16,7 +16,7 @@
// ========================================================================
//
-package org.eclipse.jetty.websocket.javax.server;
+package org.eclipse.jetty.websocket.javax.server.config;
import java.util.List;
import java.util.ServiceLoader;
diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketConfiguration.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/config/JavaxWebSocketConfiguration.java
similarity index 89%
rename from jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketConfiguration.java
rename to jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/config/JavaxWebSocketConfiguration.java
index 57255fad3b2..d0baa67fb5b 100644
--- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketConfiguration.java
+++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/config/JavaxWebSocketConfiguration.java
@@ -16,7 +16,7 @@
// ========================================================================
//
-package org.eclipse.jetty.websocket.javax.server;
+package org.eclipse.jetty.websocket.javax.server.config;
import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
@@ -38,6 +38,7 @@ public class JavaxWebSocketConfiguration extends AbstractConfiguration
addDependencies(WebXmlConfiguration.class, MetaInfConfiguration.class, WebInfConfiguration.class, FragmentConfiguration.class);
addDependents("org.eclipse.jetty.annotations.AnnotationConfiguration", WebAppConfiguration.class.getName());
protectAndExpose("org.eclipse.jetty.websocket.servlet."); // For WebSocketUpgradeFilter
- protectAndExpose("org.eclipse.jetty.websocket.javax."); // TODO Do we need all classes?
+ protectAndExpose("org.eclipse.jetty.websocket.javax.server.config.");
+ hide("org.eclipse.jetty.websocket.javax.server.internal");
}
}
diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/config/JavaxWebSocketServletContainerInitializer.java
similarity index 98%
rename from jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java
rename to jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/config/JavaxWebSocketServletContainerInitializer.java
index 9261f8356be..0780290b912 100644
--- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServletContainerInitializer.java
+++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/config/JavaxWebSocketServletContainerInitializer.java
@@ -16,7 +16,7 @@
// ========================================================================
//
-package org.eclipse.jetty.websocket.javax.server;
+package org.eclipse.jetty.websocket.javax.server.config;
import java.util.HashSet;
import java.util.Set;
@@ -39,6 +39,7 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.ThreadClassLoaderScope;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
+import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketServerContainer;
import org.eclipse.jetty.websocket.servlet.WebSocketMapping;
import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter;
diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/AnnotatedServerEndpointConfig.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/AnnotatedServerEndpointConfig.java
index 277fa42daec..f3d03450cec 100644
--- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/AnnotatedServerEndpointConfig.java
+++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/AnnotatedServerEndpointConfig.java
@@ -33,7 +33,7 @@ import javax.websocket.server.ServerEndpoint;
import javax.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketContainer;
-import org.eclipse.jetty.websocket.javax.server.ContainerDefaultConfigurator;
+import org.eclipse.jetty.websocket.javax.server.config.ContainerDefaultConfigurator;
public class AnnotatedServerEndpointConfig implements ServerEndpointConfig
{
diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java
similarity index 97%
rename from jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java
rename to jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java
index ffe0ae7bc6b..276c1015cb7 100644
--- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerContainer.java
+++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java
@@ -16,7 +16,7 @@
// ========================================================================
//
-package org.eclipse.jetty.websocket.javax.server;
+package org.eclipse.jetty.websocket.javax.server.internal;
import java.util.ArrayList;
import java.util.List;
@@ -41,9 +41,7 @@ import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.core.WebSocketException;
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
import org.eclipse.jetty.websocket.javax.client.JavaxWebSocketClientContainer;
-import org.eclipse.jetty.websocket.javax.server.internal.AnnotatedServerEndpointConfig;
-import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketCreator;
-import org.eclipse.jetty.websocket.javax.server.internal.UndefinedServerEndpointConfig;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.servlet.WebSocketMapping;
@ManagedObject("JSR356 Server Container")
diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerFrameHandlerFactory.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerFrameHandlerFactory.java
similarity index 92%
rename from jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerFrameHandlerFactory.java
rename to jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerFrameHandlerFactory.java
index 8a5bdee8907..b16b5b2af02 100644
--- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerFrameHandlerFactory.java
+++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerFrameHandlerFactory.java
@@ -16,7 +16,7 @@
// ========================================================================
//
-package org.eclipse.jetty.websocket.javax.server;
+package org.eclipse.jetty.websocket.javax.server.internal;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
@@ -27,8 +27,6 @@ import org.eclipse.jetty.websocket.core.FrameHandler;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketContainer;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerMetadata;
-import org.eclipse.jetty.websocket.javax.server.internal.DelegatedJavaxServletUpgradeRequest;
-import org.eclipse.jetty.websocket.javax.server.internal.PathParamIdentifier;
import org.eclipse.jetty.websocket.servlet.FrameHandlerFactory;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/UndefinedServerEndpointConfig.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/UndefinedServerEndpointConfig.java
index 8fdaf945db5..a5361a48d6a 100644
--- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/UndefinedServerEndpointConfig.java
+++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/UndefinedServerEndpointConfig.java
@@ -27,7 +27,7 @@ import javax.websocket.Encoder;
import javax.websocket.Extension;
import javax.websocket.server.ServerEndpointConfig;
-import org.eclipse.jetty.websocket.javax.server.ContainerDefaultConfigurator;
+import org.eclipse.jetty.websocket.javax.server.config.ContainerDefaultConfigurator;
public class UndefinedServerEndpointConfig implements ServerEndpointConfig
{
diff --git a/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
index 86c5fef3534..68d8b37077c 100644
--- a/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
+++ b/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
@@ -1 +1 @@
-org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer
\ No newline at end of file
+org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer
\ No newline at end of file
diff --git a/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator b/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator
index b925d25755c..e9f7fc540a4 100644
--- a/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator
+++ b/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator
@@ -1 +1 @@
-org.eclipse.jetty.websocket.javax.server.ContainerDefaultConfigurator
\ No newline at end of file
+org.eclipse.jetty.websocket.javax.server.config.ContainerDefaultConfigurator
\ No newline at end of file
diff --git a/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/org.eclipse.jetty.webapp.Configuration b/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/org.eclipse.jetty.webapp.Configuration
index 280be7ed694..9c5a60b0447 100644
--- a/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/org.eclipse.jetty.webapp.Configuration
+++ b/jetty-websocket/javax-websocket-server/src/main/resources/META-INF/services/org.eclipse.jetty.webapp.Configuration
@@ -1 +1 @@
-org.eclipse.jetty.websocket.javax.server.JavaxWebSocketConfiguration
\ No newline at end of file
+org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketConfiguration
\ No newline at end of file
diff --git a/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/PathParamTest.java b/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/PathParamTest.java
deleted file mode 100644
index 796ee693ca6..00000000000
--- a/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/PathParamTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2019 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.websocket.javax.server;
-
-import javax.websocket.DeploymentException;
-import javax.websocket.OnMessage;
-import javax.websocket.server.PathParam;
-import javax.websocket.server.ServerEndpoint;
-
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-public class PathParamTest
-{
- private JavaxWebSocketServerContainer container;
-
- @BeforeEach
- public void startContainer() throws Exception
- {
- container = new DummyServerContainer();
- container.start();
- }
-
- @AfterEach
- public void stopContainer() throws Exception
- {
- container.stop();
- }
-
- @ServerEndpoint("/pathparam/basic/{name}")
- public static class BasicPathParamSocket
- {
- @OnMessage
- public void onMessage(String message, @PathParam("name") String name)
- {
- }
- }
-
- @Test
- public void testBasicPathParamSocket() throws DeploymentException
- {
- container.addEndpoint(BasicPathParamSocket.class);
- }
-}
diff --git a/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/browser/JsrBrowserDebugTool.java b/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/browser/JsrBrowserDebugTool.java
index ccb71039385..be0468ed9b3 100644
--- a/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/browser/JsrBrowserDebugTool.java
+++ b/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/browser/JsrBrowserDebugTool.java
@@ -33,7 +33,7 @@ import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
/**
* Tool to help debug JSR based websocket circumstances reported around browsers.
diff --git a/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/WebSocketServerExamplesTest.java b/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/examples/WebSocketServerExamplesTest.java
similarity index 90%
rename from jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/WebSocketServerExamplesTest.java
rename to jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/examples/WebSocketServerExamplesTest.java
index 56438ccfb47..dffb3e5179c 100644
--- a/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/WebSocketServerExamplesTest.java
+++ b/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/examples/WebSocketServerExamplesTest.java
@@ -16,7 +16,7 @@
// ========================================================================
//
-package org.eclipse.jetty.websocket.javax.server;
+package org.eclipse.jetty.websocket.javax.server.examples;
import java.net.URI;
import java.util.concurrent.ArrayBlockingQueue;
@@ -45,9 +45,7 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.security.Credential;
-import org.eclipse.jetty.websocket.javax.server.examples.GetHttpSessionSocket;
-import org.eclipse.jetty.websocket.javax.server.examples.MyAuthedSocket;
-import org.eclipse.jetty.websocket.javax.server.examples.StreamingEchoSocket;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -93,15 +91,15 @@ public class WebSocketServerExamplesTest
}
static Server _server;
- static ServerConnector connector;
+ static ServerConnector _connector;
static ServletContextHandler _context;
@BeforeAll
public static void setup() throws Exception
{
_server = new Server();
- connector = new ServerConnector(_server);
- _server.addConnector(connector);
+ _connector = new ServerConnector(_server);
+ _server.addConnector(_connector);
_context = new ServletContextHandler(ServletContextHandler.SESSIONS);
_context.setContextPath("/");
@@ -116,7 +114,7 @@ public class WebSocketServerExamplesTest
});
_server.start();
- System.setProperty("org.eclipse.jetty.websocket.port", Integer.toString(connector.getLocalPort()));
+ System.setProperty("org.eclipse.jetty.websocket.port", Integer.toString(_connector.getLocalPort()));
}
@AfterAll
@@ -155,7 +153,7 @@ public class WebSocketServerExamplesTest
public void testMyAuthedSocket() throws Exception
{
//HttpClient is configured for BasicAuthentication with the XmlHttpClientProvider
- URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/secured/socket");
+ URI uri = URI.create("ws://localhost:" + _connector.getLocalPort() + "/secured/socket");
WebSocketContainer clientContainer = ContainerProvider.getWebSocketContainer();
ClientSocket clientEndpoint = new ClientSocket();
@@ -172,7 +170,7 @@ public class WebSocketServerExamplesTest
@Test
public void testStreamingEchoSocket() throws Exception
{
- URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/echo");
+ URI uri = URI.create("ws://localhost:" + _connector.getLocalPort() + "/echo");
WebSocketContainer clientContainer = ContainerProvider.getWebSocketContainer();
ClientSocket clientEndpoint = new ClientSocket();
@@ -189,7 +187,7 @@ public class WebSocketServerExamplesTest
@Test
public void testGetHttpSessionSocket() throws Exception
{
- URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/example");
+ URI uri = URI.create("ws://localhost:" + _connector.getLocalPort() + "/example");
WebSocketContainer clientContainer = ContainerProvider.getWebSocketContainer();
ClientSocket clientEndpoint = new ClientSocket();
diff --git a/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/LocalServer.java b/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/LocalServer.java
index 5a638ab8cd0..9ed2a87aa3c 100644
--- a/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/LocalServer.java
+++ b/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/LocalServer.java
@@ -50,9 +50,9 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.websocket.core.internal.Parser;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSessionListener;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServerContainer;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServerFrameHandlerFactory;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketServerContainer;
+import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketServerFrameHandlerFactory;
import org.eclipse.jetty.websocket.servlet.FrameHandlerFactory;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
diff --git a/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/WSServer.java b/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/WSServer.java
index 817fcc2a7ed..52beae928fb 100644
--- a/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/WSServer.java
+++ b/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/WSServer.java
@@ -39,7 +39,7 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.webapp.WebAppContext;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketConfiguration;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketConfiguration;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/BasicEchoEndpoint.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/BasicEchoEndpoint.java
new file mode 100644
index 00000000000..81ac929eb70
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/BasicEchoEndpoint.java
@@ -0,0 +1,46 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint("/echo")
+public class BasicEchoEndpoint extends Endpoint implements MessageHandler.Whole
+{
+ private Session session;
+
+ @Override
+ public void onMessage(String msg)
+ {
+ // reply with echo
+ session.getAsyncRemote().sendText(msg);
+ }
+
+ @OnOpen
+ public void onOpen(Session session, EndpointConfig config)
+ {
+ this.session = session;
+ session.addMessageHandler(this);
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/BasicEchoEndpointConfigContextListener.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/BasicEchoEndpointConfigContextListener.java
new file mode 100644
index 00000000000..4b8ddb988a8
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/BasicEchoEndpointConfigContextListener.java
@@ -0,0 +1,54 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerEndpointConfig;
+
+public class BasicEchoEndpointConfigContextListener implements ServletContextListener
+{
+ @Override
+ public void contextDestroyed(ServletContextEvent sce)
+ {
+ /* do nothing */
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce)
+ {
+ javax.websocket.server.ServerContainer container = (javax.websocket.server.ServerContainer)sce.getServletContext()
+ .getAttribute(javax.websocket.server.ServerContainer.class.getName());
+ if (container == null)
+ throw new IllegalStateException("No Websocket ServerContainer in " + sce.getServletContext());
+
+ // Build up a configuration with a specific path
+ String path = "/echo";
+ ServerEndpointConfig.Builder builder = ServerEndpointConfig.Builder.create(BasicEchoEndpoint.class, path);
+ try
+ {
+ container.addEndpoint(builder.build());
+ }
+ catch (DeploymentException e)
+ {
+ throw new RuntimeException("Unable to add endpoint via config file", e);
+ }
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutContextListener.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutContextListener.java
new file mode 100644
index 00000000000..e58ba1b9726
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutContextListener.java
@@ -0,0 +1,54 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+import javax.websocket.server.ServerEndpointConfig;
+
+/**
+ * Example of adding a server WebSocket (extending {@link javax.websocket.Endpoint}) programmatically via config
+ */
+public class IdleTimeoutContextListener implements ServletContextListener
+{
+ @Override
+ public void contextDestroyed(ServletContextEvent sce)
+ {
+ /* do nothing */
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce)
+ {
+ ServerContainer container = (ServerContainer)sce.getServletContext().getAttribute(ServerContainer.class.getName());
+ // Build up a configuration with a specific path
+ String path = "/idle-onopen-endpoint";
+ ServerEndpointConfig.Builder builder = ServerEndpointConfig.Builder.create(OnOpenIdleTimeoutEndpoint.class, path);
+ try
+ {
+ container.addEndpoint(builder.build());
+ }
+ catch (DeploymentException e)
+ {
+ throw new RuntimeException("Unable to add endpoint via config file", e);
+ }
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutOnOpenEndpoint.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutOnOpenEndpoint.java
new file mode 100644
index 00000000000..8ad113ec775
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutOnOpenEndpoint.java
@@ -0,0 +1,44 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
+import javax.websocket.Session;
+
+public class IdleTimeoutOnOpenEndpoint extends Endpoint implements MessageHandler.Whole
+{
+ private Session session;
+
+ @Override
+ public void onOpen(Session session, EndpointConfig config)
+ {
+ this.session = session;
+ session.addMessageHandler(this);
+ session.setMaxIdleTimeout(500);
+ }
+
+ @Override
+ public void onMessage(String message)
+ {
+ // echo message back (this is an indication of timeout failure)
+ session.getAsyncRemote().sendText(message);
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutOnOpenSocket.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutOnOpenSocket.java
new file mode 100644
index 00000000000..3278e6594db
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/IdleTimeoutOnOpenSocket.java
@@ -0,0 +1,50 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+import org.eclipse.jetty.websocket.core.WebSocketTimeoutException;
+
+@ServerEndpoint(value = "/idle-onopen-socket")
+public class IdleTimeoutOnOpenSocket
+{
+ @OnOpen
+ public void onOpen(Session session)
+ {
+ session.setMaxIdleTimeout(500);
+ }
+
+ @OnMessage
+ public String onMessage(String msg)
+ {
+ return msg;
+ }
+
+ @OnError
+ public void onError(Throwable cause)
+ {
+ if (!(cause instanceof WebSocketTimeoutException))
+ throw new RuntimeException(cause);
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/LargeEchoContextListener.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/LargeEchoContextListener.java
new file mode 100644
index 00000000000..813caf986df
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/LargeEchoContextListener.java
@@ -0,0 +1,39 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.websocket.server.ServerContainer;
+
+public class LargeEchoContextListener implements ServletContextListener
+{
+ @Override
+ public void contextDestroyed(ServletContextEvent sce)
+ {
+ /* do nothing */
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce)
+ {
+ ServerContainer container = (ServerContainer)sce.getServletContext().getAttribute(ServerContainer.class.getName());
+ container.setDefaultMaxTextMessageBufferSize(128 * 1024);
+ }
+}
diff --git a/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/DummyServerContainer.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/LargeEchoDefaultSocket.java
similarity index 70%
rename from jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/DummyServerContainer.java
rename to jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/LargeEchoDefaultSocket.java
index c39c5169bea..f5b9ddbfb9b 100644
--- a/jetty-websocket/javax-websocket-server/src/test/java/org/eclipse/jetty/websocket/javax/server/DummyServerContainer.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/LargeEchoDefaultSocket.java
@@ -16,14 +16,18 @@
// ========================================================================
//
-package org.eclipse.jetty.websocket.javax.server;
+package com.acme.websocket;
-import org.eclipse.jetty.websocket.servlet.WebSocketMapping;
+import javax.websocket.OnMessage;
+import javax.websocket.server.ServerEndpoint;
-public class DummyServerContainer extends JavaxWebSocketServerContainer
+@ServerEndpoint(value = "/echo/large")
+public class LargeEchoDefaultSocket
{
- public DummyServerContainer()
+ @OnMessage
+ public void echo(javax.websocket.Session session, String msg)
{
- super(new WebSocketMapping());
+ // reply with echo
+ session.getAsyncRemote().sendText(msg);
}
}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/OnOpenIdleTimeoutEndpoint.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/OnOpenIdleTimeoutEndpoint.java
new file mode 100644
index 00000000000..71c305fa353
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/OnOpenIdleTimeoutEndpoint.java
@@ -0,0 +1,44 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
+import javax.websocket.Session;
+
+public class OnOpenIdleTimeoutEndpoint extends Endpoint implements MessageHandler.Whole
+{
+ private Session session;
+
+ @Override
+ public void onOpen(Session session, EndpointConfig config)
+ {
+ this.session = session;
+ session.addMessageHandler(this);
+ session.setMaxIdleTimeout(500);
+ }
+
+ @Override
+ public void onMessage(String message)
+ {
+ // echo message back (this is an indication of timeout failure)
+ session.getAsyncRemote().sendText(message);
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongContextListener.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongContextListener.java
new file mode 100644
index 00000000000..68e47ecd086
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongContextListener.java
@@ -0,0 +1,61 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.websocket.DeploymentException;
+import javax.websocket.HandshakeResponse;
+import javax.websocket.server.HandshakeRequest;
+import javax.websocket.server.ServerContainer;
+import javax.websocket.server.ServerEndpointConfig;
+
+public class PongContextListener implements ServletContextListener
+{
+ public static class Config extends ServerEndpointConfig.Configurator
+ {
+ @Override
+ public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
+ {
+ sec.getUserProperties().put("path", sec.getPath());
+ super.modifyHandshake(sec, request, response);
+ }
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce)
+ {
+ /* do nothing */
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce)
+ {
+ ServerContainer container = (ServerContainer)sce.getServletContext().getAttribute(ServerContainer.class.getName());
+ try
+ {
+ ServerEndpointConfig.Configurator config = new Config();
+ container.addEndpoint(ServerEndpointConfig.Builder.create(PongMessageEndpoint.class, "/pong").configurator(config).build());
+ }
+ catch (DeploymentException e)
+ {
+ throw new RuntimeException("Unable to add endpoint directly", e);
+ }
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongMessageEndpoint.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongMessageEndpoint.java
new file mode 100644
index 00000000000..b7253c13fdf
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongMessageEndpoint.java
@@ -0,0 +1,66 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
+import javax.websocket.PongMessage;
+import javax.websocket.Session;
+
+public class PongMessageEndpoint extends Endpoint implements MessageHandler.Whole
+{
+ private String path = "?";
+ private Session session;
+
+ @Override
+ public void onOpen(Session session, EndpointConfig config)
+ {
+ this.session = session;
+ this.session.addMessageHandler(this);
+ this.path = (String)config.getUserProperties().get("path");
+ }
+
+ @Override
+ public void onMessage(PongMessage pong)
+ {
+ byte[] buf = toArray(pong.getApplicationData());
+ String message = new String(buf, StandardCharsets.UTF_8);
+ this.session.getAsyncRemote().sendText("PongMessageEndpoint.onMessage(PongMessage):[" + path + "]:" + message);
+ }
+
+ public static byte[] toArray(ByteBuffer buffer)
+ {
+ if (buffer.hasArray())
+ {
+ byte[] array = buffer.array();
+ int from = buffer.arrayOffset() + buffer.position();
+ return Arrays.copyOfRange(array, from, from + buffer.remaining());
+ }
+ else
+ {
+ byte[] to = new byte[buffer.remaining()];
+ buffer.slice().get(to);
+ return to;
+ }
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongSocket.java b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongSocket.java
new file mode 100644
index 00000000000..5a0385d5ddb
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/com/acme/websocket/PongSocket.java
@@ -0,0 +1,67 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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 com.acme.websocket;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import javax.websocket.EndpointConfig;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.PongMessage;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint(value = "/pong-socket", configurator = PongContextListener.Config.class)
+public class PongSocket
+{
+ private String path = "?";
+ private Session session;
+
+ @OnOpen
+ public void onOpen(Session session, EndpointConfig config)
+ {
+ this.session = session;
+ this.path = (String)config.getUserProperties().get("path");
+ }
+
+ @OnMessage
+ public void onPong(PongMessage pong)
+ {
+ byte[] buf = toArray(pong.getApplicationData());
+ String message = new String(buf, StandardCharsets.UTF_8);
+ this.session.getAsyncRemote().sendText("PongSocket.onPong(PongMessage)[" + path + "]:" + message);
+ }
+
+ public static byte[] toArray(ByteBuffer buffer)
+ {
+ if (buffer.hasArray())
+ {
+ byte[] array = buffer.array();
+ int from = buffer.arrayOffset() + buffer.position();
+ return Arrays.copyOfRange(array, from, from + buffer.remaining());
+ }
+ else
+ {
+ byte[] to = new byte[buffer.remaining()];
+ buffer.slice().get(to);
+ return to;
+ }
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/PathParamTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/PathParamTest.java
new file mode 100644
index 00000000000..1796eb4caeb
--- /dev/null
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/PathParamTest.java
@@ -0,0 +1,104 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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.websocket.javax.tests;
+
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+import javax.websocket.ContainerProvider;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+public class PathParamTest
+{
+ private Server _server;
+ private ServerConnector _connector;
+ private ServletContextHandler _context;
+
+ @BeforeEach
+ public void startContainer() throws Exception
+ {
+ _server = new Server();
+ _connector = new ServerConnector(_server);
+ _server.addConnector(_connector);
+
+ _context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ _context.setContextPath("/");
+ _server.setHandler(_context);
+
+ JavaxWebSocketServletContainerInitializer.configure(_context, (context, container) ->
+ container.addEndpoint(EchoParamSocket.class));
+
+ _server.start();
+ }
+
+ @AfterEach
+ public void stopContainer() throws Exception
+ {
+ _server.stop();
+ }
+
+ @ServerEndpoint("/pathparam/echo/{name}")
+ public static class EchoParamSocket
+ {
+ private Session session;
+
+ @OnOpen
+ public void onOpen(Session session)
+ {
+ this.session = session;
+ }
+
+ @OnMessage
+ public void onMessage(String message, @PathParam("name") String name)
+ {
+ session.getAsyncRemote().sendText(message+"-"+name);
+ }
+ }
+
+ @Test
+ public void testBasicPathParamSocket() throws Exception
+ {
+ WebSocketContainer container = ContainerProvider.getWebSocketContainer();
+ EventSocket clientEndpoint = new EventSocket();
+
+ URI serverUri = URI.create("ws://localhost:"+ _connector.getLocalPort()+"/pathparam/echo/myParam");
+ Session session = container.connectToServer(clientEndpoint, serverUri);
+ session.getBasicRemote().sendText("echo");
+
+ String resp = clientEndpoint.messageQueue.poll(1, TimeUnit.SECONDS);
+ assertThat("Response echo", resp, is("echo-myParam"));
+ session.close();
+ clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS);
+ }
+}
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/RestartContextTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/RestartContextTest.java
index 2499f5a5017..80a0265c382 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/RestartContextTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/RestartContextTest.java
@@ -37,8 +37,8 @@ import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServerContainer;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketServerContainer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/AbstractJavaxWebSocketServerFrameHandlerTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/AbstractJavaxWebSocketServerFrameHandlerTest.java
index 548526309ee..ae920dae9ad 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/AbstractJavaxWebSocketServerFrameHandlerTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/AbstractJavaxWebSocketServerFrameHandlerTest.java
@@ -27,8 +27,8 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.javax.client.EmptyClientEndpointConfig;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServerContainer;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketServerContainer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/DeploymentExceptionTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/DeploymentExceptionTest.java
index 052d8f87e3f..b38868cbfc0 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/DeploymentExceptionTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/DeploymentExceptionTest.java
@@ -30,7 +30,7 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.javax.common.util.InvalidSignatureException;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.javax.tests.server.sockets.InvalidCloseIntSocket;
import org.eclipse.jetty.websocket.javax.tests.server.sockets.InvalidErrorErrorSocket;
import org.eclipse.jetty.websocket.javax.tests.server.sockets.InvalidErrorIntSocket;
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/EndpointViaConfigTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/EndpointViaConfigTest.java
index 69f27b6c05d..43f0e5dbe8c 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/EndpointViaConfigTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/EndpointViaConfigTest.java
@@ -21,16 +21,9 @@ package org.eclipse.jetty.websocket.javax.tests.server;
import java.net.URI;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.websocket.DeploymentException;
-import javax.websocket.EndpointConfig;
-import javax.websocket.MessageHandler;
-import javax.websocket.OnOpen;
-import javax.websocket.Session;
-import javax.websocket.server.ServerEndpoint;
-import javax.websocket.server.ServerEndpointConfig;
+import com.acme.websocket.BasicEchoEndpoint;
+import com.acme.websocket.BasicEchoEndpointConfigContextListener;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.eclipse.jetty.util.Callback;
@@ -41,7 +34,6 @@ import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.FrameHandler;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
-import org.eclipse.jetty.websocket.javax.tests.WSEventTracker;
import org.eclipse.jetty.websocket.javax.tests.WSServer;
import org.eclipse.jetty.websocket.javax.tests.framehandlers.FrameHandlerTracker;
import org.junit.jupiter.api.Test;
@@ -59,55 +51,6 @@ public class EndpointViaConfigTest
{
private static final Logger LOG = Log.getLogger(EndpointViaConfigTest.class);
- @ServerEndpoint("/echo")
- public static class BasicEchoEndpoint extends WSEventTracker implements MessageHandler.Whole
- {
- @Override
- public void onMessage(String msg)
- {
- super.onWsText(msg);
- // reply with echo
- session.getAsyncRemote().sendText(msg);
- }
-
- @OnOpen
- public void onOpen(Session session, EndpointConfig config)
- {
- super.onWsOpen(session, config);
- this.session.addMessageHandler(this);
- }
- }
-
- public static class BasicEchoEndpointConfigContextListener implements ServletContextListener
- {
- @Override
- public void contextDestroyed(ServletContextEvent sce)
- {
- /* do nothing */
- }
-
- @Override
- public void contextInitialized(ServletContextEvent sce)
- {
- javax.websocket.server.ServerContainer container = (javax.websocket.server.ServerContainer)sce.getServletContext()
- .getAttribute(javax.websocket.server.ServerContainer.class.getName());
- if (container == null)
- throw new IllegalStateException("No Websocket ServerContainer in " + sce.getServletContext());
-
- // Build up a configuration with a specific path
- String path = "/echo";
- ServerEndpointConfig.Builder builder = ServerEndpointConfig.Builder.create(BasicEchoEndpoint.class, path);
- try
- {
- container.addEndpoint(builder.build());
- }
- catch (DeploymentException e)
- {
- throw new RuntimeException("Unable to add endpoint via config file", e);
- }
- }
- }
-
public WorkDir testdir;
@Test
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/IdleTimeoutTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/IdleTimeoutTest.java
index 261f265c3d0..b3561a78b92 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/IdleTimeoutTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/IdleTimeoutTest.java
@@ -21,6 +21,9 @@ package org.eclipse.jetty.websocket.javax.tests.server;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
+import com.acme.websocket.IdleTimeoutContextListener;
+import com.acme.websocket.IdleTimeoutOnOpenEndpoint;
+import com.acme.websocket.IdleTimeoutOnOpenSocket;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.eclipse.jetty.webapp.WebAppContext;
@@ -29,8 +32,6 @@ import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.tests.Fuzzer;
import org.eclipse.jetty.websocket.javax.tests.WSServer;
-import org.eclipse.jetty.websocket.javax.tests.server.sockets.IdleTimeoutOnOpenEndpoint;
-import org.eclipse.jetty.websocket.javax.tests.server.sockets.IdleTimeoutOnOpenSocket;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -59,7 +60,6 @@ public class IdleTimeoutTest
WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
- // wsb.dump();
}
@AfterAll
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/JettyServerEndpointConfiguratorTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/JettyServerEndpointConfiguratorTest.java
index 0c28d087267..61ab2aca1f2 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/JettyServerEndpointConfiguratorTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/JettyServerEndpointConfiguratorTest.java
@@ -22,7 +22,7 @@ import java.util.Iterator;
import java.util.ServiceLoader;
import javax.websocket.server.ServerEndpointConfig;
-import org.eclipse.jetty.websocket.javax.server.ContainerDefaultConfigurator;
+import org.eclipse.jetty.websocket.javax.server.config.ContainerDefaultConfigurator;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/LargeContainerTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/LargeContainerTest.java
index 21ffd70a40a..fbdf26ce9db 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/LargeContainerTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/LargeContainerTest.java
@@ -23,12 +23,8 @@ import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.websocket.OnMessage;
-import javax.websocket.server.ServerContainer;
-import javax.websocket.server.ServerEndpoint;
+import com.acme.websocket.LargeEchoDefaultSocket;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.eclipse.jetty.util.Callback;
@@ -51,33 +47,6 @@ import static org.hamcrest.Matchers.is;
@ExtendWith(WorkDirExtension.class)
public class LargeContainerTest
{
- @ServerEndpoint(value = "/echo/large")
- public static class LargeEchoDefaultSocket
- {
- @OnMessage
- public void echo(javax.websocket.Session session, String msg)
- {
- // reply with echo
- session.getAsyncRemote().sendText(msg);
- }
- }
-
- public static class LargeEchoContextListener implements ServletContextListener
- {
- @Override
- public void contextDestroyed(ServletContextEvent sce)
- {
- /* do nothing */
- }
-
- @Override
- public void contextInitialized(ServletContextEvent sce)
- {
- ServerContainer container = (ServerContainer)sce.getServletContext().getAttribute(ServerContainer.class.getName());
- container.setDefaultMaxTextMessageBufferSize(128 * 1024);
- }
- }
-
public WorkDir testdir;
@SuppressWarnings("Duplicates")
@@ -95,7 +64,6 @@ public class LargeContainerTest
WebAppContext webapp = wsb.createWebAppContext();
wsb.deployWebapp(webapp);
- // wsb.dump();
WebSocketCoreClient client = new WebSocketCoreClient();
try
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/MemoryUsageTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/MemoryUsageTest.java
index e5e0a6821a6..1cb415d913f 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/MemoryUsageTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/MemoryUsageTest.java
@@ -35,7 +35,7 @@ import javax.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/PingPongTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/PingPongTest.java
index 1b44cdc23f0..e323ff87ea5 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/PingPongTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/PingPongTest.java
@@ -19,33 +19,17 @@
package org.eclipse.jetty.websocket.javax.tests.server;
import java.net.URI;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.time.Duration;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.websocket.DeploymentException;
-import javax.websocket.Endpoint;
-import javax.websocket.EndpointConfig;
-import javax.websocket.HandshakeResponse;
-import javax.websocket.MessageHandler;
-import javax.websocket.OnMessage;
-import javax.websocket.OnOpen;
-import javax.websocket.PongMessage;
-import javax.websocket.Session;
-import javax.websocket.server.HandshakeRequest;
-import javax.websocket.server.ServerContainer;
-import javax.websocket.server.ServerEndpoint;
-import javax.websocket.server.ServerEndpointConfig;
+import com.acme.websocket.PongContextListener;
+import com.acme.websocket.PongMessageEndpoint;
+import com.acme.websocket.PongSocket;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.FrameHandler;
@@ -64,87 +48,6 @@ import static org.junit.jupiter.api.Assertions.assertTimeout;
public class PingPongTest
{
- @ServerEndpoint(value = "/pong-socket", configurator = PongContextListener.Config.class)
- public static class PongSocket
- {
- private static final Logger LOG = Log.getLogger(PongSocket.class);
- private String path = "?";
- private Session session;
-
- @OnOpen
- public void onOpen(Session session, EndpointConfig config)
- {
- this.session = session;
- this.path = (String)config.getUserProperties().get("path");
- }
-
- @OnMessage
- public void onPong(PongMessage pong)
- {
- if (LOG.isDebugEnabled())
- LOG.debug("PongSocket.onPong(): PongMessage.appData={}", BufferUtil.toDetailString(pong.getApplicationData()));
- byte[] buf = BufferUtil.toArray(pong.getApplicationData());
- String message = new String(buf, StandardCharsets.UTF_8);
- this.session.getAsyncRemote().sendText("PongSocket.onPong(PongMessage)[" + path + "]:" + message);
- }
- }
-
- public static class PongMessageEndpoint extends Endpoint implements MessageHandler.Whole
- {
- private String path = "?";
- private Session session;
-
- @Override
- public void onOpen(Session session, EndpointConfig config)
- {
- this.session = session;
- this.session.addMessageHandler(this);
- this.path = (String)config.getUserProperties().get("path");
- }
-
- @Override
- public void onMessage(PongMessage pong)
- {
- byte[] buf = BufferUtil.toArray(pong.getApplicationData());
- String message = new String(buf, StandardCharsets.UTF_8);
- this.session.getAsyncRemote().sendText("PongMessageEndpoint.onMessage(PongMessage):[" + path + "]:" + message);
- }
- }
-
- public static class PongContextListener implements ServletContextListener
- {
- public static class Config extends ServerEndpointConfig.Configurator
- {
- @Override
- public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
- {
- sec.getUserProperties().put("path", sec.getPath());
- super.modifyHandshake(sec, request, response);
- }
- }
-
- @Override
- public void contextDestroyed(ServletContextEvent sce)
- {
- /* do nothing */
- }
-
- @Override
- public void contextInitialized(ServletContextEvent sce)
- {
- ServerContainer container = (ServerContainer)sce.getServletContext().getAttribute(ServerContainer.class.getName());
- try
- {
- ServerEndpointConfig.Configurator config = new Config();
- container.addEndpoint(ServerEndpointConfig.Builder.create(PongMessageEndpoint.class, "/pong").configurator(config).build());
- }
- catch (DeploymentException e)
- {
- throw new RuntimeException("Unable to add endpoint directly", e);
- }
- }
- }
-
private static WSServer server;
private static WebSocketCoreClient client;
diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/WebSocketServerContainerExecutorTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/WebSocketServerContainerExecutorTest.java
index 7db6aa77bbe..e406aed6db6 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/WebSocketServerContainerExecutorTest.java
+++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/WebSocketServerContainerExecutorTest.java
@@ -44,12 +44,12 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServerContainer;
-import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketServerContainer;
import org.eclipse.jetty.websocket.javax.tests.WSURI;
import org.junit.jupiter.api.Test;
-import static org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServletContainerInitializer.HTTPCLIENT_ATTRIBUTE;
+import static org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer.HTTPCLIENT_ATTRIBUTE;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.sameInstance;
diff --git a/jetty-websocket/javax-websocket-tests/src/test/resources/basic-echo-endpoint-config-web.xml b/jetty-websocket/javax-websocket-tests/src/test/resources/basic-echo-endpoint-config-web.xml
index 2daa96edb6c..191ba7fff8b 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/resources/basic-echo-endpoint-config-web.xml
+++ b/jetty-websocket/javax-websocket-tests/src/test/resources/basic-echo-endpoint-config-web.xml
@@ -7,6 +7,6 @@
version="3.0">
- org.eclipse.jetty.websocket.javax.tests.server.EndpointViaConfigTest$BasicEchoEndpointConfigContextListener
+ com.acme.websocket.BasicEchoEndpointConfigContextListener
\ No newline at end of file
diff --git a/jetty-websocket/javax-websocket-tests/src/test/resources/idle-timeout-config-web.xml b/jetty-websocket/javax-websocket-tests/src/test/resources/idle-timeout-config-web.xml
index ecb89d2acd2..a60cea6c700 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/resources/idle-timeout-config-web.xml
+++ b/jetty-websocket/javax-websocket-tests/src/test/resources/idle-timeout-config-web.xml
@@ -7,6 +7,6 @@
version="3.0">
- org.eclipse.jetty.websocket.javax.tests.server.IdleTimeoutContextListener
+ com.acme.websocket.IdleTimeoutContextListener
\ No newline at end of file
diff --git a/jetty-websocket/javax-websocket-tests/src/test/resources/large-echo-config-web.xml b/jetty-websocket/javax-websocket-tests/src/test/resources/large-echo-config-web.xml
index c4dfacddef3..b032926b059 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/resources/large-echo-config-web.xml
+++ b/jetty-websocket/javax-websocket-tests/src/test/resources/large-echo-config-web.xml
@@ -7,6 +7,6 @@
version="3.0">
- org.eclipse.jetty.websocket.javax.tests.server.LargeContainerTest$LargeEchoContextListener
+ com.acme.websocket.LargeEchoContextListener
\ No newline at end of file
diff --git a/jetty-websocket/javax-websocket-tests/src/test/resources/pong-config-web.xml b/jetty-websocket/javax-websocket-tests/src/test/resources/pong-config-web.xml
index aa16c7af156..a3478e35e2a 100644
--- a/jetty-websocket/javax-websocket-tests/src/test/resources/pong-config-web.xml
+++ b/jetty-websocket/javax-websocket-tests/src/test/resources/pong-config-web.xml
@@ -7,6 +7,6 @@
version="3.0">
- org.eclipse.jetty.websocket.javax.tests.server.PingPongTest$PongContextListener
+ com.acme.websocket.PongContextListener
\ No newline at end of file
diff --git a/jetty-websocket/jetty-websocket-server/src/main/java/module-info.java b/jetty-websocket/jetty-websocket-server/src/main/java/module-info.java
index 689f680ecea..005c0f64d7f 100644
--- a/jetty-websocket/jetty-websocket-server/src/main/java/module-info.java
+++ b/jetty-websocket/jetty-websocket-server/src/main/java/module-info.java
@@ -25,6 +25,7 @@ import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerI
module org.eclipse.jetty.websocket.jetty.server
{
exports org.eclipse.jetty.websocket.server;
+ exports org.eclipse.jetty.websocket.server.config;
requires jetty.servlet.api;
requires org.eclipse.jetty.http;
From a2fc9b113b7175d7f09493413e4b86f3e0e946ec Mon Sep 17 00:00:00 2001
From: Jan Bartel
Date: Wed, 28 Aug 2019 11:04:31 +1000
Subject: [PATCH 43/55] Fix and enhance session invalidation tests.
Signed-off-by: Jan Bartel
---
.../eclipse/jetty/server/session/Session.java | 1 +
.../server/session/SessionHandlerTest.java | 11 --
.../session/SessionInvalidationTest.java | 138 ++++++++++++++++++
3 files changed, 139 insertions(+), 11 deletions(-)
create mode 100644 tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionInvalidationTest.java
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
index 867afb9bad8..a14d5f5ab53 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
@@ -707,6 +707,7 @@ public class Session implements SessionHandler.SessionIf
{
try (Lock lock = _lock.lock())
{
+ checkValidForRead();
return _sessionData.getAttribute(name);
}
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
index e119dad6f33..728982e3012 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java
@@ -38,15 +38,4 @@ public class SessionHandlerTest
assertThrows(IllegalArgumentException.class,() ->
sessionHandler.setSessionTrackingModes(new HashSet<>(Arrays.asList(SessionTrackingMode.SSL, SessionTrackingMode.URL))));
}
-
- @Test
- public void testInvalidSessiongetLastAccessedTime()
- {
- Session session = new Session(new SessionHandler(),
- new SessionData("sd" ,"", "", 0, 0, 0, 0));
- session.getLastAccessedTime();
- session.invalidate();
- assertThrows(IllegalStateException.class, () -> session.getLastAccessedTime());
- }
-
}
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionInvalidationTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionInvalidationTest.java
new file mode 100644
index 00000000000..8984f7fe214
--- /dev/null
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionInvalidationTest.java
@@ -0,0 +1,138 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 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.server.session;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * SessionInvalidationTest
+ *
+ * Test that various methods on sessions can't be accessed after invalidation
+ */
+public class SessionInvalidationTest
+{
+ @Test
+ public void testInvalidation() throws Exception
+ {
+ String contextPath = "";
+ String servletMapping = "/server";
+ int scavengePeriod = -1;
+
+ DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
+ cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
+ SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
+ ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod);
+
+ TestServer server = new TestServer(0, 0, scavengePeriod,
+ cacheFactory, storeFactory);
+ ServletContextHandler context = server.addContext(contextPath);
+ TestServlet servlet = new TestServlet();
+ ServletHolder holder = new ServletHolder(servlet);
+ context.addServlet(holder, servletMapping);
+
+ try
+ {
+ server.start();
+ int port1 = server.getPort();
+
+ HttpClient client = new HttpClient();
+ client.start();
+ try
+ {
+ String url = "http://localhost:" + port1 + contextPath + servletMapping;
+ // Create the session
+ ContentResponse response1 = client.GET(url + "?action=init");
+ assertEquals(HttpServletResponse.SC_OK, response1.getStatus());
+ String sessionCookie = response1.getHeaders().get("Set-Cookie");
+ assertTrue(sessionCookie != null);
+
+ // Make a request which will invalidate the existing session
+ Request request2 = client.newRequest(url + "?action=test");
+ ContentResponse response2 = request2.send();
+ assertEquals(HttpServletResponse.SC_OK, response2.getStatus());
+ }
+ finally
+ {
+ client.stop();
+ }
+ }
+ finally
+ {
+ server.stop();
+ }
+ }
+
+ public static class TestServlet extends HttpServlet
+ {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
+ {
+ String action = request.getParameter("action");
+
+ if ("init".equals(action))
+ {
+ HttpSession session = request.getSession(true);
+ assertNotNull(session);
+ }
+ else if ("test".equals(action))
+ {
+ HttpSession session = request.getSession(false);
+ assertNotNull(session);
+
+ //invalidate existing session
+ session.invalidate();
+
+ assertThrows(IllegalStateException.class, () -> session.invalidate());
+ assertThrows(IllegalStateException.class, () -> session.getLastAccessedTime());
+ assertThrows(IllegalStateException.class, () -> session.getCreationTime());
+ assertThrows(IllegalStateException.class, () -> session.getAttribute("foo"));
+ assertThrows(IllegalStateException.class, () -> session.getAttributeNames());
+ assertThrows(IllegalStateException.class, () -> session.getValue("foo"));
+ assertThrows(IllegalStateException.class, () -> session.getValueNames());
+ assertThrows(IllegalStateException.class, () -> session.putValue("a", "b"));
+ assertThrows(IllegalStateException.class, () -> session.removeAttribute("foo"));
+ assertThrows(IllegalStateException.class, () -> session.removeValue("foo"));
+ assertThrows(IllegalStateException.class, () -> session.setAttribute("a", "b"));
+ assertDoesNotThrow(() -> session.getId());
+
+ }
+ }
+ }
+}
From 37712d75a2c7d525ffccc42fb74a9f31398034a6 Mon Sep 17 00:00:00 2001
From: Jan Bartel
Date: Wed, 28 Aug 2019 11:08:42 +1000
Subject: [PATCH 44/55] Issue #4027 Ensure AbstractSessionDataStore started or
throws exception. (#4028)
* Issue #4027 Ensure AbstractSessionDataStore started or throws exception.
Signed-off-by: Jan Bartel
---
.../jetty/server/session/AbstractSessionDataStore.java | 9 +++++++++
.../jetty/server/session/DefaultSessionIdManager.java | 7 ++++---
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java
index 9accdb69b16..b876c2e81ef 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java
@@ -80,6 +80,9 @@ public abstract class AbstractSessionDataStore extends ContainerLifeCycle implem
@Override
public SessionData load(String id) throws Exception
{
+ if (!isStarted())
+ throw new IllegalStateException ("Not started");
+
final AtomicReference reference = new AtomicReference();
final AtomicReference exception = new AtomicReference();
@@ -109,6 +112,9 @@ public abstract class AbstractSessionDataStore extends ContainerLifeCycle implem
@Override
public void store(String id, SessionData data) throws Exception
{
+ if (!isStarted())
+ throw new IllegalStateException("Not started");
+
if (data == null)
return;
@@ -154,6 +160,9 @@ public abstract class AbstractSessionDataStore extends ContainerLifeCycle implem
@Override
public Set getExpired(Set candidates)
{
+ if (!isStarted())
+ throw new IllegalStateException ("Not started");
+
try
{
return doGetExpired(candidates);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java
index 23ab41bd40a..fbe85430246 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java
@@ -471,9 +471,9 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
}
/**
- * Get SessionManager for every context.
+ * Get SessionHandler for every context.
*
- * @return all session managers
+ * @return all SessionHandlers that are running
*/
@Override
public Set getSessionHandlers()
@@ -484,7 +484,8 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
{
for (Handler h : tmp)
{
- handlers.add((SessionHandler)h);
+ if (h.isStarted())
+ handlers.add((SessionHandler)h);
}
}
return handlers;
From f4d95e0f2f451332b3c42a351e7b6aa67bcf1162 Mon Sep 17 00:00:00 2001
From: Jan Bartel
Date: Wed, 28 Aug 2019 11:22:14 +1000
Subject: [PATCH 45/55] Remove blank lines for NullSessionCacheTest
Signed-off-by: Jan Bartel
---
.../jetty/server/session/NullSessionCacheTest.java | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NullSessionCacheTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NullSessionCacheTest.java
index 3ae38cb6d0a..5e63b62101b 100644
--- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NullSessionCacheTest.java
+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NullSessionCacheTest.java
@@ -67,9 +67,7 @@ public class NullSessionCacheTest
se.getSession().setAttribute("pv", new TestObject(count));
}
}
-
-
-
+
public static class TestObject implements HttpSessionActivationListener
{
int i;
@@ -97,8 +95,7 @@ public class NullSessionCacheTest
++activates;
}
}
-
-
+
@Test
public void testWritesWithPassivation() throws Exception
{
@@ -191,8 +188,6 @@ public class NullSessionCacheTest
assertEquals(0, context.getSessionHandler()._sessionAttributeListeners.size());
}
-
-
@Test
public void testWriteThroughAlways() throws Exception
{
@@ -245,7 +240,7 @@ public class NullSessionCacheTest
}
@Test
- public void testWriteThroughNew () throws Exception
+ public void testWriteThroughNew() throws Exception
{
Server server = new Server();
@@ -303,8 +298,7 @@ public class NullSessionCacheTest
assertEquals(4, store._numSaves.get());//release session should write it out
assertFalse(session.isResident());
}
-
-
+
@Test
public void testNotCached() throws Exception
{
From 2979ed5046eaa6705df937c9b80cc5497adfe9c9 Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Tue, 27 Aug 2019 20:25:10 -0500
Subject: [PATCH 46/55] Fixes #4020 - Satisfy Container LifeCycle dumpable
behaviors
Signed-off-by: Joakim Erdfelt
---
.../extensions/WebSocketExtensionFactory.java | 56 ++++++++++++++-----
1 file changed, 41 insertions(+), 15 deletions(-)
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
index 706429567b8..f1ca84d635f 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
@@ -18,6 +18,7 @@
package org.eclipse.jetty.websocket.common.extensions;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -27,6 +28,7 @@ import java.util.zip.Deflater;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.compression.CompressionPool;
import org.eclipse.jetty.util.compression.DeflaterPool;
@@ -38,9 +40,9 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
import org.eclipse.jetty.websocket.common.extensions.compress.CompressExtension;
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
-public class WebSocketExtensionFactory extends ExtensionFactory implements LifeCycle
+public class WebSocketExtensionFactory extends ExtensionFactory implements LifeCycle, Dumpable
{
- private ContainerLifeCycle lifecycle;
+ private ContainerLifeCycle containerLifeCycle;
private WebSocketContainerScope container;
private ServiceLoader extensionLoader = ServiceLoader.load(Extension.class);
private Map> availableExtensions;
@@ -49,7 +51,7 @@ public class WebSocketExtensionFactory extends ExtensionFactory implements LifeC
public WebSocketExtensionFactory(WebSocketContainerScope container)
{
- lifecycle = new ContainerLifeCycle();
+ containerLifeCycle = new ContainerLifeCycle();
availableExtensions = new HashMap<>();
for (Extension ext : extensionLoader)
{
@@ -58,8 +60,8 @@ public class WebSocketExtensionFactory extends ExtensionFactory implements LifeC
}
this.container = container;
- lifecycle.addBean(inflaterPool);
- lifecycle.addBean(deflaterPool);
+ containerLifeCycle.addBean(inflaterPool);
+ containerLifeCycle.addBean(deflaterPool);
}
@Override
@@ -153,60 +155,84 @@ public class WebSocketExtensionFactory extends ExtensionFactory implements LifeC
@Override
public void start() throws Exception
{
- lifecycle.start();
+ containerLifeCycle.start();
}
@Override
public void stop() throws Exception
{
- lifecycle.stop();
+ containerLifeCycle.stop();
}
@Override
public boolean isRunning()
{
- return lifecycle.isRunning();
+ return containerLifeCycle.isRunning();
}
@Override
public boolean isStarted()
{
- return lifecycle.isStarted();
+ return containerLifeCycle.isStarted();
}
@Override
public boolean isStarting()
{
- return lifecycle.isStarting();
+ return containerLifeCycle.isStarting();
}
@Override
public boolean isStopping()
{
- return lifecycle.isStopping();
+ return containerLifeCycle.isStopping();
}
@Override
public boolean isStopped()
{
- return lifecycle.isStopped();
+ return containerLifeCycle.isStopped();
}
@Override
public boolean isFailed()
{
- return lifecycle.isFailed();
+ return containerLifeCycle.isFailed();
}
@Override
public void addLifeCycleListener(Listener listener)
{
- lifecycle.addLifeCycleListener(listener);
+ containerLifeCycle.addLifeCycleListener(listener);
}
@Override
public void removeLifeCycleListener(Listener listener)
{
- lifecycle.removeLifeCycleListener(listener);
+ containerLifeCycle.removeLifeCycleListener(listener);
+ }
+
+ @Override
+ public String dump()
+ {
+ return containerLifeCycle.dump();
+ }
+
+ @Override
+ public String dumpSelf()
+ {
+ return containerLifeCycle.dumpSelf();
+ }
+
+ @Override
+ public void dump(Appendable out, String indent) throws IOException
+ {
+ containerLifeCycle.dump(out, indent);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%s@%x{%s}", WebSocketExtensionFactory.class.getName(), hashCode(), containerLifeCycle.getState());
}
}
From 4251a3e092868259b6439aa286f25b8b3d9f2e75 Mon Sep 17 00:00:00 2001
From: Jan Bartel
Date: Wed, 28 Aug 2019 12:29:14 +1000
Subject: [PATCH 47/55] Issue #4022 Prevent Servlet adding another Servlet
(#4024)
* Issue #4022 Prevent Servlet adding Servlet and added unit tests.
Signed-off-by: Jan Bartel
---
.../jetty/servlet/ServletContextHandler.java | 17 +-
.../eclipse/jetty/servlet/ServletHandler.java | 12 +
.../servlet/ServletContextHandlerTest.java | 378 +++++++++++++++++-
.../jetty/servlet/ServletHolderTest.java | 47 +++
4 files changed, 444 insertions(+), 10 deletions(-)
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
index ba98aee7515..db28cfdbdb7 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
@@ -1067,10 +1067,13 @@ public class ServletContextHandler extends ContextHandler
return new Dispatcher(context, name);
}
- private void checkDynamicName(String name)
+ private void checkDynamic(String name)
{
if (isStarted())
throw new IllegalStateException();
+
+ if (ServletContextHandler.this.getServletHandler().isInitialized())
+ throw new IllegalStateException();
if (StringUtil.isBlank(name))
throw new IllegalStateException("Missing name");
@@ -1085,7 +1088,7 @@ public class ServletContextHandler extends ContextHandler
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Class extends Filter> filterClass)
{
- checkDynamicName(filterName);
+ checkDynamic(filterName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
FilterHolder holder = handler.getFilter(filterName);
@@ -1114,7 +1117,7 @@ public class ServletContextHandler extends ContextHandler
@Override
public FilterRegistration.Dynamic addFilter(String filterName, String className)
{
- checkDynamicName(filterName);
+ checkDynamic(filterName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
FilterHolder holder = handler.getFilter(filterName);
@@ -1143,7 +1146,7 @@ public class ServletContextHandler extends ContextHandler
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter)
{
- checkDynamicName(filterName);
+ checkDynamic(filterName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
FilterHolder holder = handler.getFilter(filterName);
@@ -1173,7 +1176,7 @@ public class ServletContextHandler extends ContextHandler
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Class extends Servlet> servletClass)
{
- checkDynamicName(servletName);
+ checkDynamic(servletName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder holder = handler.getServlet(servletName);
@@ -1203,7 +1206,7 @@ public class ServletContextHandler extends ContextHandler
@Override
public ServletRegistration.Dynamic addServlet(String servletName, String className)
{
- checkDynamicName(servletName);
+ checkDynamic(servletName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder holder = handler.getServlet(servletName);
@@ -1233,7 +1236,7 @@ public class ServletContextHandler extends ContextHandler
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
{
- checkDynamicName(servletName);
+ checkDynamic(servletName);
final ServletHandler handler = ServletContextHandler.this.getServletHandler();
ServletHolder holder = handler.getServlet(servletName);
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
index b730ed82b52..897a9ccba98 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
@@ -116,6 +116,7 @@ public class ServletHandler extends ScopedHandler
private PathMappings _servletPathMap;
private ListenerHolder[] _listeners = new ListenerHolder[0];
+ private boolean _initialized = false;
@SuppressWarnings("unchecked")
protected final ConcurrentMap[] _chainCache = new ConcurrentMap[FilterMapping.ALL];
@@ -331,6 +332,7 @@ public class ServletHandler extends ScopedHandler
_filterPathMappings = null;
_filterNameMappings = null;
_servletPathMap = null;
+ _initialized = false;
}
protected IdentityService getIdentityService()
@@ -730,6 +732,8 @@ public class ServletHandler extends ScopedHandler
public void initialize()
throws Exception
{
+ _initialized = true;
+
MultiException mx = new MultiException();
Stream.concat(Stream.concat(
@@ -755,6 +759,14 @@ public class ServletHandler extends ScopedHandler
mx.ifExceptionThrow();
}
+
+ /**
+ * @return true if initialized has been called, false otherwise
+ */
+ public boolean isInitialized()
+ {
+ return _initialized;
+ }
/**
* @return whether the filter chains are cached.
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java
index c870a679b94..14d7ccfa616 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.EventListener;
import java.util.List;
import java.util.Objects;
@@ -29,6 +30,11 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.FilterRegistration;
import javax.servlet.Servlet;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
@@ -37,10 +43,13 @@ import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
+import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -71,6 +80,9 @@ import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.Decorator;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.log.StacklessLogging;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -110,12 +122,13 @@ public class ServletContextHandlerTest
public static class MySCIStarter extends AbstractLifeCycle implements ServletContextHandler.ServletContainerInitializerCaller
{
- MySCI _sci = new MySCI();
+ ServletContainerInitializer _sci = null;
ContextHandler.Context _ctx;
- MySCIStarter(ContextHandler.Context ctx)
+ MySCIStarter(ContextHandler.Context ctx, ServletContainerInitializer sci)
{
_ctx = ctx;
+ _sci = sci;
}
@Override
@@ -417,7 +430,7 @@ public class ServletContextHandlerTest
_server.setHandler(contexts);
ServletContextHandler root = new ServletContextHandler(contexts, "/");
- root.addBean(new MySCIStarter(root.getServletContext()), true);
+ root.addBean(new MySCIStarter(root.getServletContext(), new MySCI()), true);
_server.start();
assertTrue((Boolean)root.getServletContext().getAttribute("MySCI.startup"));
assertTrue((Boolean)root.getServletContext().getAttribute("MyContextListener.contextInitialized"));
@@ -595,6 +608,180 @@ public class ServletContextHandlerTest
assertEquals(0, __testServlets.get());
}
+ @Test
+ public void testAddServletFromServlet() throws Exception
+ {
+ //A servlet cannot be added by another servlet
+ Logger logger = Log.getLogger(ContextHandler.class.getName() + "ROOT");
+
+ try (StacklessLogging stackless = new StacklessLogging(logger))
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ context.setLogger(logger);
+ ServletHolder holder = context.addServlet(ServletAddingServlet.class, "/start");
+ context.getServletHandler().setStartWithUnavailable(false);
+ holder.setInitOrder(0);
+ context.setContextPath("/");
+ _server.setHandler(context);
+ _server.start();
+ fail("Servlet can only be added from SCI or SCL");
+ }
+ catch (Exception e)
+ {
+ if (e instanceof ServletException)
+ {
+ assertTrue(e.getCause() instanceof IllegalStateException);
+ }
+ else
+ fail(e);
+ }
+ }
+
+ @Test
+ public void testAddFilterFromServlet() throws Exception
+ {
+ //A filter cannot be added from a servlet
+ Logger logger = Log.getLogger(ContextHandler.class.getName() + "ROOT");
+
+ try (StacklessLogging stackless = new StacklessLogging(logger))
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ context.setLogger(logger);
+ ServletHolder holder = context.addServlet(FilterAddingServlet.class, "/filter");
+ context.getServletHandler().setStartWithUnavailable(false);
+ holder.setInitOrder(0);
+ context.setContextPath("/");
+ _server.setHandler(context);
+ _server.start();
+ fail("Filter can only be added from SCI or SCL");
+ }
+ catch (Exception e)
+ {
+ if (e instanceof ServletException)
+ {
+ assertTrue(e.getCause() instanceof IllegalStateException);
+ }
+ else
+ fail(e);
+ }
+ }
+
+ @Test
+ public void testAddServletFromFilter() throws Exception
+ {
+ //A servlet cannot be added from a Filter
+ Logger logger = Log.getLogger(ContextHandler.class.getName() + "ROOT");
+
+ try (StacklessLogging stackless = new StacklessLogging(logger))
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ context.setLogger(logger);
+ FilterHolder holder = new FilterHolder(new Filter()
+ {
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException
+ {
+ ServletRegistration rego = filterConfig.getServletContext().addServlet("hello", HelloServlet.class);
+ rego.addMapping("/hello/*");
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException
+ {
+ }
+
+ @Override
+ public void destroy()
+ {
+ }
+
+ });
+ context.addFilter(holder, "/*", EnumSet.of(DispatcherType.REQUEST));
+ context.getServletHandler().setStartWithUnavailable(false);
+ context.setContextPath("/");
+ _server.setHandler(context);
+ _server.start();
+ fail("Servlet can only be added from SCI or SCL");
+ }
+ catch (Exception e)
+ {
+ if (!(e instanceof IllegalStateException))
+ {
+ if (e instanceof ServletException)
+ {
+ assertTrue(e.getCause() instanceof IllegalStateException);
+ }
+ else
+ fail(e);
+ }
+ }
+ }
+
+ @Test
+ public void testAddServletFromSCL() throws Exception
+ {
+ //A servlet can be added from a ServletContextListener
+ ServletContextHandler context = new ServletContextHandler();
+ context.getServletHandler().setStartWithUnavailable(false);
+ context.setContextPath("/");
+ context.addEventListener(new ServletContextListener()
+ {
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce)
+ {
+ ServletRegistration rego = sce.getServletContext().addServlet("hello", HelloServlet.class);
+ rego.addMapping("/hello/*");
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce)
+ {
+ }
+
+ });
+ _server.setHandler(context);
+ _server.start();
+
+ StringBuffer request = new StringBuffer();
+ request.append("GET /hello HTTP/1.0\n");
+ request.append("Host: localhost\n");
+ request.append("\n");
+
+ String response = _connector.getResponse(request.toString());
+ assertThat("Response", response, containsString("Hello World"));
+ }
+
+ @Test
+ public void testAddServletFromSCI() throws Exception
+ {
+ //A servlet can be added from a ServletContainerInitializer
+ ContextHandlerCollection contexts = new ContextHandlerCollection();
+ _server.setHandler(contexts);
+
+ ServletContextHandler root = new ServletContextHandler(contexts, "/");
+ class ServletAddingSCI implements ServletContainerInitializer
+ {
+ @Override
+ public void onStartup(Set> c, ServletContext ctx) throws ServletException
+ {
+ ServletRegistration rego = ctx.addServlet("hello", HelloServlet.class);
+ rego.addMapping("/hello/*");
+ }
+ }
+ root.addBean(new MySCIStarter(root.getServletContext(), new ServletAddingSCI()), true);
+ _server.start();
+
+ StringBuffer request = new StringBuffer();
+ request.append("GET /hello HTTP/1.0\n");
+ request.append("Host: localhost\n");
+ request.append("\n");
+
+ String response = _connector.getResponse(request.toString());
+ assertThat("Response", response, containsString("Hello World"));
+ }
+
@Test
public void testAddServletAfterStart() throws Exception
{
@@ -623,7 +810,126 @@ public class ServletContextHandlerTest
response = _connector.getResponse(request.toString());
assertThat("Response", response, containsString("Hello World"));
}
+
+ @Test
+ public void testServletRegistrationByClass() throws Exception
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ context.setContextPath("/");
+ ServletRegistration reg = context.getServletContext().addServlet("test", TestServlet.class);
+ reg.addMapping("/test");
+ _server.setHandler(context);
+ _server.start();
+
+ StringBuffer request = new StringBuffer();
+ request.append("GET /test HTTP/1.0\n");
+ request.append("Host: localhost\n");
+ request.append("\n");
+
+ String response = _connector.getResponse(request.toString());
+ assertThat("Response", response, containsString("Test"));
+ }
+
+ @Test
+ public void testServletRegistrationByClassName() throws Exception
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ context.setContextPath("/");
+ ServletRegistration reg = context.getServletContext().addServlet("test", TestServlet.class.getName());
+ reg.addMapping("/test");
+
+ _server.setHandler(context);
+ _server.start();
+
+ StringBuffer request = new StringBuffer();
+ request.append("GET /test HTTP/1.0\n");
+ request.append("Host: localhost\n");
+ request.append("\n");
+
+ String response = _connector.getResponse(request.toString());
+ assertThat("Response", response, containsString("Test"));
+ }
+
+ @Test
+ public void testPartialServletRegistrationByName() throws Exception
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ context.setContextPath("/");
+ ServletHolder partial = new ServletHolder();
+ partial.setName("test");
+ context.addServlet(partial, "/test");
+
+ //complete partial servlet registration by providing name of the servlet class
+ ServletRegistration reg = context.getServletContext().addServlet("test", TestServlet.class.getName());
+ assertNotNull(reg);
+ assertEquals(TestServlet.class.getName(), partial.getClassName());
+
+ _server.setHandler(context);
+ _server.start();
+
+ StringBuffer request = new StringBuffer();
+ request.append("GET /test HTTP/1.0\n");
+ request.append("Host: localhost\n");
+ request.append("\n");
+
+ String response = _connector.getResponse(request.toString());
+ assertThat("Response", response, containsString("Test"));
+ }
+
+ @Test
+ public void testPartialServletRegistrationByClass() throws Exception
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ context.setContextPath("/");
+ ServletHolder partial = new ServletHolder();
+ partial.setName("test");
+ context.addServlet(partial, "/test");
+
+ //complete partial servlet registration by providing the servlet class
+ ServletRegistration reg = context.getServletContext().addServlet("test", TestServlet.class);
+ assertNotNull(reg);
+ assertEquals(TestServlet.class.getName(), partial.getClassName());
+ assertSame(TestServlet.class, partial.getHeldClass());
+
+ _server.setHandler(context);
+ _server.start();
+
+ StringBuffer request = new StringBuffer();
+ request.append("GET /test HTTP/1.0\n");
+ request.append("Host: localhost\n");
+ request.append("\n");
+
+ String response = _connector.getResponse(request.toString());
+ assertThat("Response", response, containsString("Test"));
+ }
+
+ @Test
+ public void testNullServletRegistration() throws Exception
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ context.setContextPath("/");
+ ServletHolder full = new ServletHolder();
+ full.setName("test");
+ full.setHeldClass(TestServlet.class);
+ context.addServlet(full, "/test");
+
+ //Must return null if the servlet has been fully defined previously
+ ServletRegistration reg = context.getServletContext().addServlet("test", TestServlet.class);
+ assertNull(reg);
+
+ _server.setHandler(context);
+ _server.start();
+
+ StringBuffer request = new StringBuffer();
+ request.append("GET /test HTTP/1.0\n");
+ request.append("Host: localhost\n");
+ request.append("\n");
+
+ String response = _connector.getResponse(request.toString());
+ assertThat("Response", response, containsString("Test"));
+ }
+
@Test
public void testHandlerBeforeServletHandler() throws Exception
{
@@ -948,6 +1254,28 @@ public class ServletContextHandlerTest
writer.write("Hello World");
}
}
+
+ public static class MyFilter implements Filter
+ {
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException
+ {
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
+ ServletException
+ {
+ request.getServletContext().setAttribute("filter", "filter");
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy()
+ {
+ }
+ }
public static class DummyUtilDecorator implements org.eclipse.jetty.util.Decorator
{
@@ -1009,6 +1337,50 @@ public class ServletContextHandlerTest
}
}
+ public static class ServletAddingServlet extends HttpServlet
+ {
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ resp.getWriter().write("Start");
+ resp.getWriter().close();
+ }
+
+ @Override
+ public void init() throws ServletException
+ {
+ ServletRegistration dynamic = getServletContext().addServlet("added", AddedServlet.class);
+ dynamic.addMapping("/added/*");
+ }
+ }
+
+ public static class FilterAddingServlet extends HttpServlet
+ {
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ resp.getWriter().write("Filter");
+ resp.getWriter().close();
+ }
+
+ @Override
+ public void init() throws ServletException
+ {
+ FilterRegistration dynamic = getServletContext().addFilter("filter", new MyFilter());
+ dynamic.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
+ }
+ }
+
+ public static class AddedServlet extends HttpServlet
+ {
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ resp.getWriter().write("Added");
+ resp.getWriter().close();
+ }
+ }
+
public static class TestServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHolderTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHolderTest.java
index 06a4d4c3933..f9553980962 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHolderTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHolderTest.java
@@ -18,7 +18,11 @@
package org.eclipse.jetty.servlet;
+import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.MultiException;
@@ -31,8 +35,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
+import java.io.IOException;
+
public class ServletHolderTest
{
+
+ public static class FakeServlet extends HttpServlet
+ {
+ }
+
@Test
public void testTransitiveCompareTo() throws Exception
@@ -113,6 +124,42 @@ public class ServletHolderTest
assertThat(e.getCause().getMessage(), containsString("foo"));
}
}
+
+ @Test
+ public void testWithClass() throws Exception
+ {
+ //Test adding servlet by class
+ try (StacklessLogging stackless = new StacklessLogging(BaseHolder.class, ServletHandler.class, ContextHandler.class, ServletContextHandler.class))
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ ServletHandler handler = context.getServletHandler();
+ ServletHolder holder = new ServletHolder();
+ holder.setName("foo");
+ holder.setHeldClass(FakeServlet.class);
+ handler.addServlet(holder);
+ handler.start();
+ assertTrue(holder.isAvailable());
+ assertTrue(holder.isStarted());
+ }
+ }
+
+ @Test
+ public void testWithClassName() throws Exception
+ {
+ //Test adding servlet by classname
+ try (StacklessLogging stackless = new StacklessLogging(BaseHolder.class, ServletHandler.class, ContextHandler.class, ServletContextHandler.class))
+ {
+ ServletContextHandler context = new ServletContextHandler();
+ ServletHandler handler = context.getServletHandler();
+ ServletHolder holder = new ServletHolder();
+ holder.setName("foo");
+ holder.setClassName("org.eclipse.jetty.servlet.ServletHolderTest$FakeServlet");
+ handler.addServlet(holder);
+ handler.start();
+ assertTrue(holder.isAvailable());
+ assertTrue(holder.isStarted());
+ }
+ }
@Test
public void testUnloadableClassName() throws Exception
From b2ea6a0861efee1b337c9beef7d7db3ca0b86f12 Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Wed, 28 Aug 2019 10:43:15 -0500
Subject: [PATCH 48/55] Fixing Test Parameterization
Signed-off-by: Joakim Erdfelt
---
.../org/eclipse/jetty/util/URIUtilTest.java | 682 ++++++++++--------
1 file changed, 392 insertions(+), 290 deletions(-)
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
index c2e7ad56c7d..0ea76fcef5f 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -40,339 +41,442 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
@SuppressWarnings("SpellCheckingInspection")
public class URIUtilTest
{
- @Test // TODO: Parameterize
- public void testEncodePath()
+ public static Stream encodePathSource()
+ {
+ return Stream.of(
+ Arguments.of("/foo%23+;,:=/b a r/?info ", "/foo%2523+%3B,:=/b%20a%20r/%3Finfo%20"),
+ Arguments.of("/context/'list'/\"me\"/;",
+ "/context/%27list%27/%22me%22/%3B%3Cscript%3Ewindow.alert(%27xss%27)%3B%3C/script%3E"),
+ Arguments.of("test\u00f6?\u00f6:\u00df", "test%C3%B6%3F%C3%B6:%C3%9F"),
+ Arguments.of("test?\u00f6?\u00f6:\u00df", "test%3F%C3%B6%3F%C3%B6:%C3%9F")
+ );
+ }
+
+ @ParameterizedTest(name = "[{index}] {0}")
+ @MethodSource("encodePathSource")
+ public void testEncodePath(String rawPath, String expectedEncoded)
{
// test basic encode/decode
StringBuilder buf = new StringBuilder();
-
buf.setLength(0);
- URIUtil.encodePath(buf, "/foo%23+;,:=/b a r/?info ");
- assertEquals("/foo%2523+%3B,:=/b%20a%20r/%3Finfo%20", buf.toString());
-
- assertEquals("/foo%2523+%3B,:=/b%20a%20r/%3Finfo%20", URIUtil.encodePath("/foo%23+;,:=/b a r/?info "));
+ URIUtil.encodePath(buf, rawPath);
+ assertEquals(expectedEncoded, buf.toString());
+ }
+ @Test
+ public void testEncodeString()
+ {
+ StringBuilder buf = new StringBuilder();
buf.setLength(0);
URIUtil.encodeString(buf, "foo%23;,:=b a r", ";,= ");
assertEquals("foo%2523%3b%2c:%3db%20a%20r", buf.toString());
-
- buf.setLength(0);
- URIUtil.encodePath(buf, "/context/'list'/\"me\"/;");
- assertEquals("/context/%27list%27/%22me%22/%3B%3Cscript%3Ewindow.alert(%27xss%27)%3B%3C/script%3E", buf.toString());
-
- buf.setLength(0);
- URIUtil.encodePath(buf, "test\u00f6?\u00f6:\u00df");
- assertEquals("test%C3%B6%3F%C3%B6:%C3%9F", buf.toString());
-
- buf.setLength(0);
- URIUtil.encodePath(buf, "test?\u00f6?\u00f6:\u00df");
- assertEquals("test%3F%C3%B6%3F%C3%B6:%C3%9F", buf.toString());
}
- @Test // TODO: Parameterize
- public void testDecodePath()
+ public static Stream decodePathSource()
{
- assertEquals(URIUtil.decodePath("xx/foo/barxx", 2, 8), "/foo/bar");
- assertEquals("/foo/bar", URIUtil.decodePath("/foo/bar"));
- assertEquals("/f o/b r", URIUtil.decodePath("/f%20o/b%20r"));
- assertEquals("/foo/bar", URIUtil.decodePath("/foo;ignore/bar;ignore"));
- assertEquals("/fää/bar", URIUtil.decodePath("/f\u00e4\u00e4;ignore/bar;ignore"));
- assertEquals("/f\u0629\u0629%23/bar", URIUtil.decodePath("/f%d8%a9%d8%a9%2523;ignore/bar;ignore"));
+ List arguments = new ArrayList<>();
+ arguments.add(Arguments.of("/foo/bar", "/foo/bar"));
- assertEquals("foo%23;,:=b a r", URIUtil.decodePath("foo%2523%3b%2c:%3db%20a%20r;rubbish"));
- assertEquals("/foo/bar%23;,:=b a r=", URIUtil.decodePath("xxx/foo/bar%2523%3b%2c:%3db%20a%20r%3Dxxx;rubbish", 3, 35));
- assertEquals("f\u00e4\u00e4%23;,:=b a r=", URIUtil.decodePath("fää%2523%3b%2c:%3db%20a%20r%3D"));
- assertEquals("f\u0629\u0629%23;,:=b a r", URIUtil.decodePath("f%d8%a9%d8%a9%2523%3b%2c:%3db%20a%20r"));
+ arguments.add(Arguments.of("/f%20o/b%20r", "/f o/b r"));
+ arguments.add(Arguments.of("fää%2523%3b%2c:%3db%20a%20r%3D", "f\u00e4\u00e4%23;,:=b a r="));
+ arguments.add(Arguments.of("f%d8%a9%d8%a9%2523%3b%2c:%3db%20a%20r", "f\u0629\u0629%23;,:=b a r"));
+
+ // path parameters should be ignored
+ arguments.add(Arguments.of("/foo;ignore/bar;ignore", "/foo/bar"));
+ arguments.add(Arguments.of("/f\u00e4\u00e4;ignore/bar;ignore", "/fää/bar"));
+ arguments.add(Arguments.of("/f%d8%a9%d8%a9%2523;ignore/bar;ignore", "/f\u0629\u0629%23/bar"));
+ arguments.add(Arguments.of("foo%2523%3b%2c:%3db%20a%20r;rubbish", "foo%23;,:=b a r"));
// Test for null character (real world ugly test case)
byte[] oddBytes = {'/', 0x00, '/'};
String odd = new String(oddBytes, StandardCharsets.ISO_8859_1);
assertEquals(odd, URIUtil.decodePath("/%00/"));
+ arguments.add(Arguments.of("/%00/", odd));
+
+ return arguments.stream();
}
- @Test // TODO: Parameterize
- public void testAddEncodedPaths()
+ @ParameterizedTest(name = "[{index}] {0}")
+ @MethodSource("decodePathSource")
+ public void testDecodePath(String encodedPath, String expectedPath)
{
- assertEquals(URIUtil.addEncodedPaths(null, null), null, "null+null");
- assertEquals(URIUtil.addEncodedPaths(null, ""), "", "null+");
- assertEquals(URIUtil.addEncodedPaths(null, "bbb"), "bbb", "null+bbb");
- assertEquals(URIUtil.addEncodedPaths(null, "/"), "/", "null+/");
- assertEquals(URIUtil.addEncodedPaths(null, "/bbb"), "/bbb", "null+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("", null), "", "+null");
- assertEquals(URIUtil.addEncodedPaths("", ""), "", "+");
- assertEquals(URIUtil.addEncodedPaths("", "bbb"), "bbb", "+bbb");
- assertEquals(URIUtil.addEncodedPaths("", "/"), "/", "+/");
- assertEquals(URIUtil.addEncodedPaths("", "/bbb"), "/bbb", "+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("aaa", null), "aaa", "aaa+null");
- assertEquals(URIUtil.addEncodedPaths("aaa", ""), "aaa", "aaa+");
- assertEquals(URIUtil.addEncodedPaths("aaa", "bbb"), "aaa/bbb", "aaa+bbb");
- assertEquals(URIUtil.addEncodedPaths("aaa", "/"), "aaa/", "aaa+/");
- assertEquals(URIUtil.addEncodedPaths("aaa", "/bbb"), "aaa/bbb", "aaa+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("/", null), "/", "/+null");
- assertEquals(URIUtil.addEncodedPaths("/", ""), "/", "/+");
- assertEquals(URIUtil.addEncodedPaths("/", "bbb"), "/bbb", "/+bbb");
- assertEquals(URIUtil.addEncodedPaths("/", "/"), "/", "/+/");
- assertEquals(URIUtil.addEncodedPaths("/", "/bbb"), "/bbb", "/+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("aaa/", null), "aaa/", "aaa/+null");
- assertEquals(URIUtil.addEncodedPaths("aaa/", ""), "aaa/", "aaa/+");
- assertEquals(URIUtil.addEncodedPaths("aaa/", "bbb"), "aaa/bbb", "aaa/+bbb");
- assertEquals(URIUtil.addEncodedPaths("aaa/", "/"), "aaa/", "aaa/+/");
- assertEquals(URIUtil.addEncodedPaths("aaa/", "/bbb"), "aaa/bbb", "aaa/+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths(";JS", null), ";JS", ";JS+null");
- assertEquals(URIUtil.addEncodedPaths(";JS", ""), ";JS", ";JS+");
- assertEquals(URIUtil.addEncodedPaths(";JS", "bbb"), "bbb;JS", ";JS+bbb");
- assertEquals(URIUtil.addEncodedPaths(";JS", "/"), "/;JS", ";JS+/");
- assertEquals(URIUtil.addEncodedPaths(";JS", "/bbb"), "/bbb;JS", ";JS+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("aaa;JS", null), "aaa;JS", "aaa;JS+null");
- assertEquals(URIUtil.addEncodedPaths("aaa;JS", ""), "aaa;JS", "aaa;JS+");
- assertEquals(URIUtil.addEncodedPaths("aaa;JS", "bbb"), "aaa/bbb;JS", "aaa;JS+bbb");
- assertEquals(URIUtil.addEncodedPaths("aaa;JS", "/"), "aaa/;JS", "aaa;JS+/");
- assertEquals(URIUtil.addEncodedPaths("aaa;JS", "/bbb"), "aaa/bbb;JS", "aaa;JS+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS", null), "aaa/;JS", "aaa;JS+null");
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS", ""), "aaa/;JS", "aaa;JS+");
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS", "bbb"), "aaa/bbb;JS", "aaa;JS+bbb");
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS", "/"), "aaa/;JS", "aaa;JS+/");
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS", "/bbb"), "aaa/bbb;JS", "aaa;JS+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("?A=1", null), "?A=1", "?A=1+null");
- assertEquals(URIUtil.addEncodedPaths("?A=1", ""), "?A=1", "?A=1+");
- assertEquals(URIUtil.addEncodedPaths("?A=1", "bbb"), "bbb?A=1", "?A=1+bbb");
- assertEquals(URIUtil.addEncodedPaths("?A=1", "/"), "/?A=1", "?A=1+/");
- assertEquals(URIUtil.addEncodedPaths("?A=1", "/bbb"), "/bbb?A=1", "?A=1+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("aaa?A=1", null), "aaa?A=1", "aaa?A=1+null");
- assertEquals(URIUtil.addEncodedPaths("aaa?A=1", ""), "aaa?A=1", "aaa?A=1+");
- assertEquals(URIUtil.addEncodedPaths("aaa?A=1", "bbb"), "aaa/bbb?A=1", "aaa?A=1+bbb");
- assertEquals(URIUtil.addEncodedPaths("aaa?A=1", "/"), "aaa/?A=1", "aaa?A=1+/");
- assertEquals(URIUtil.addEncodedPaths("aaa?A=1", "/bbb"), "aaa/bbb?A=1", "aaa?A=1+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("aaa/?A=1", null), "aaa/?A=1", "aaa?A=1+null");
- assertEquals(URIUtil.addEncodedPaths("aaa/?A=1", ""), "aaa/?A=1", "aaa?A=1+");
- assertEquals(URIUtil.addEncodedPaths("aaa/?A=1", "bbb"), "aaa/bbb?A=1", "aaa?A=1+bbb");
- assertEquals(URIUtil.addEncodedPaths("aaa/?A=1", "/"), "aaa/?A=1", "aaa?A=1+/");
- assertEquals(URIUtil.addEncodedPaths("aaa/?A=1", "/bbb"), "aaa/bbb?A=1", "aaa?A=1+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths(";JS?A=1", null), ";JS?A=1", ";JS?A=1+null");
- assertEquals(URIUtil.addEncodedPaths(";JS?A=1", ""), ";JS?A=1", ";JS?A=1+");
- assertEquals(URIUtil.addEncodedPaths(";JS?A=1", "bbb"), "bbb;JS?A=1", ";JS?A=1+bbb");
- assertEquals(URIUtil.addEncodedPaths(";JS?A=1", "/"), "/;JS?A=1", ";JS?A=1+/");
- assertEquals(URIUtil.addEncodedPaths(";JS?A=1", "/bbb"), "/bbb;JS?A=1", ";JS?A=1+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("aaa;JS?A=1", null), "aaa;JS?A=1", "aaa;JS?A=1+null");
- assertEquals(URIUtil.addEncodedPaths("aaa;JS?A=1", ""), "aaa;JS?A=1", "aaa;JS?A=1+");
- assertEquals(URIUtil.addEncodedPaths("aaa;JS?A=1", "bbb"), "aaa/bbb;JS?A=1", "aaa;JS?A=1+bbb");
- assertEquals(URIUtil.addEncodedPaths("aaa;JS?A=1", "/"), "aaa/;JS?A=1", "aaa;JS?A=1+/");
- assertEquals(URIUtil.addEncodedPaths("aaa;JS?A=1", "/bbb"), "aaa/bbb;JS?A=1", "aaa;JS?A=1+/bbb");
-
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS?A=1", null), "aaa/;JS?A=1", "aaa;JS?A=1+null");
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS?A=1", ""), "aaa/;JS?A=1", "aaa;JS?A=1+");
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS?A=1", "bbb"), "aaa/bbb;JS?A=1", "aaa;JS?A=1+bbb");
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS?A=1", "/"), "aaa/;JS?A=1", "aaa;JS?A=1+/");
- assertEquals(URIUtil.addEncodedPaths("aaa/;JS?A=1", "/bbb"), "aaa/bbb;JS?A=1", "aaa;JS?A=1+/bbb");
+ String path = URIUtil.decodePath(encodedPath);
+ assertEquals(expectedPath, path);
}
- @Test // TODO: Parameterize
- public void testAddDecodedPaths()
+ @Test
+ public void testDecodePathSubstring()
{
- assertEquals(URIUtil.addPaths(null, null), null, "null+null");
- assertEquals(URIUtil.addPaths(null, ""), "", "null+");
- assertEquals(URIUtil.addPaths(null, "bbb"), "bbb", "null+bbb");
- assertEquals(URIUtil.addPaths(null, "/"), "/", "null+/");
- assertEquals(URIUtil.addPaths(null, "/bbb"), "/bbb", "null+/bbb");
+ String path = URIUtil.decodePath("xx/foo/barxx", 2, 8);
+ assertEquals("/foo/bar", path);
- assertEquals(URIUtil.addPaths("", null), "", "+null");
- assertEquals(URIUtil.addPaths("", ""), "", "+");
- assertEquals(URIUtil.addPaths("", "bbb"), "bbb", "+bbb");
- assertEquals(URIUtil.addPaths("", "/"), "/", "+/");
- assertEquals(URIUtil.addPaths("", "/bbb"), "/bbb", "+/bbb");
-
- assertEquals(URIUtil.addPaths("aaa", null), "aaa", "aaa+null");
- assertEquals(URIUtil.addPaths("aaa", ""), "aaa", "aaa+");
- assertEquals(URIUtil.addPaths("aaa", "bbb"), "aaa/bbb", "aaa+bbb");
- assertEquals(URIUtil.addPaths("aaa", "/"), "aaa/", "aaa+/");
- assertEquals(URIUtil.addPaths("aaa", "/bbb"), "aaa/bbb", "aaa+/bbb");
-
- assertEquals(URIUtil.addPaths("/", null), "/", "/+null");
- assertEquals(URIUtil.addPaths("/", ""), "/", "/+");
- assertEquals(URIUtil.addPaths("/", "bbb"), "/bbb", "/+bbb");
- assertEquals(URIUtil.addPaths("/", "/"), "/", "/+/");
- assertEquals(URIUtil.addPaths("/", "/bbb"), "/bbb", "/+/bbb");
-
- assertEquals(URIUtil.addPaths("aaa/", null), "aaa/", "aaa/+null");
- assertEquals(URIUtil.addPaths("aaa/", ""), "aaa/", "aaa/+");
- assertEquals(URIUtil.addPaths("aaa/", "bbb"), "aaa/bbb", "aaa/+bbb");
- assertEquals(URIUtil.addPaths("aaa/", "/"), "aaa/", "aaa/+/");
- assertEquals(URIUtil.addPaths("aaa/", "/bbb"), "aaa/bbb", "aaa/+/bbb");
-
- assertEquals(URIUtil.addPaths(";JS", null), ";JS", ";JS+null");
- assertEquals(URIUtil.addPaths(";JS", ""), ";JS", ";JS+");
- assertEquals(URIUtil.addPaths(";JS", "bbb"), ";JS/bbb", ";JS+bbb");
- assertEquals(URIUtil.addPaths(";JS", "/"), ";JS/", ";JS+/");
- assertEquals(URIUtil.addPaths(";JS", "/bbb"), ";JS/bbb", ";JS+/bbb");
-
- assertEquals(URIUtil.addPaths("aaa;JS", null), "aaa;JS", "aaa;JS+null");
- assertEquals(URIUtil.addPaths("aaa;JS", ""), "aaa;JS", "aaa;JS+");
- assertEquals(URIUtil.addPaths("aaa;JS", "bbb"), "aaa;JS/bbb", "aaa;JS+bbb");
- assertEquals(URIUtil.addPaths("aaa;JS", "/"), "aaa;JS/", "aaa;JS+/");
- assertEquals(URIUtil.addPaths("aaa;JS", "/bbb"), "aaa;JS/bbb", "aaa;JS+/bbb");
-
- assertEquals(URIUtil.addPaths("aaa/;JS", null), "aaa/;JS", "aaa;JS+null");
- assertEquals(URIUtil.addPaths("aaa/;JS", ""), "aaa/;JS", "aaa;JS+");
- assertEquals(URIUtil.addPaths("aaa/;JS", "bbb"), "aaa/;JS/bbb", "aaa;JS+bbb");
- assertEquals(URIUtil.addPaths("aaa/;JS", "/"), "aaa/;JS/", "aaa;JS+/");
- assertEquals(URIUtil.addPaths("aaa/;JS", "/bbb"), "aaa/;JS/bbb", "aaa;JS+/bbb");
-
- assertEquals(URIUtil.addPaths("?A=1", null), "?A=1", "?A=1+null");
- assertEquals(URIUtil.addPaths("?A=1", ""), "?A=1", "?A=1+");
- assertEquals(URIUtil.addPaths("?A=1", "bbb"), "?A=1/bbb", "?A=1+bbb");
- assertEquals(URIUtil.addPaths("?A=1", "/"), "?A=1/", "?A=1+/");
- assertEquals(URIUtil.addPaths("?A=1", "/bbb"), "?A=1/bbb", "?A=1+/bbb");
-
- assertEquals(URIUtil.addPaths("aaa?A=1", null), "aaa?A=1", "aaa?A=1+null");
- assertEquals(URIUtil.addPaths("aaa?A=1", ""), "aaa?A=1", "aaa?A=1+");
- assertEquals(URIUtil.addPaths("aaa?A=1", "bbb"), "aaa?A=1/bbb", "aaa?A=1+bbb");
- assertEquals(URIUtil.addPaths("aaa?A=1", "/"), "aaa?A=1/", "aaa?A=1+/");
- assertEquals(URIUtil.addPaths("aaa?A=1", "/bbb"), "aaa?A=1/bbb", "aaa?A=1+/bbb");
-
- assertEquals(URIUtil.addPaths("aaa/?A=1", null), "aaa/?A=1", "aaa?A=1+null");
- assertEquals(URIUtil.addPaths("aaa/?A=1", ""), "aaa/?A=1", "aaa?A=1+");
- assertEquals(URIUtil.addPaths("aaa/?A=1", "bbb"), "aaa/?A=1/bbb", "aaa?A=1+bbb");
- assertEquals(URIUtil.addPaths("aaa/?A=1", "/"), "aaa/?A=1/", "aaa?A=1+/");
- assertEquals(URIUtil.addPaths("aaa/?A=1", "/bbb"), "aaa/?A=1/bbb", "aaa?A=1+/bbb");
+ path = URIUtil.decodePath("xxx/foo/bar%2523%3b%2c:%3db%20a%20r%3Dxxx;rubbish", 3, 35);
+ assertEquals("/foo/bar%23;,:=b a r=", path);
}
- @Test // TODO: Parameterize
- public void testCompactPath()
+ public static Stream addEncodedPathsSource()
{
- assertEquals("/foo/bar", URIUtil.compactPath("/foo/bar"));
- assertEquals("/foo/bar?a=b//c", URIUtil.compactPath("/foo/bar?a=b//c"));
+ return Stream.of(
+ Arguments.of(null, null, null),
+ Arguments.of(null, "", ""),
+ Arguments.of(null, "bbb", "bbb"),
+ Arguments.of(null, "/", "/"),
+ Arguments.of(null, "/bbb", "/bbb"),
- assertEquals("/foo/bar", URIUtil.compactPath("//foo//bar"));
- assertEquals("/foo/bar?a=b//c", URIUtil.compactPath("//foo//bar?a=b//c"));
+ Arguments.of("", null, ""),
+ Arguments.of("", "", ""),
+ Arguments.of("", "bbb", "bbb"),
+ Arguments.of("", "/", "/"),
+ Arguments.of("", "/bbb", "/bbb"),
- assertEquals("/foo/bar", URIUtil.compactPath("/foo///bar"));
- assertEquals("/foo/bar?a=b//c", URIUtil.compactPath("/foo///bar?a=b//c"));
+ Arguments.of("aaa", null, "aaa"),
+ Arguments.of("aaa", "", "aaa"),
+ Arguments.of("aaa", "bbb", "aaa/bbb"),
+ Arguments.of("aaa", "/", "aaa/"),
+ Arguments.of("aaa", "/bbb", "aaa/bbb"),
+
+ Arguments.of("/", null, "/"),
+ Arguments.of("/", "", "/"),
+ Arguments.of("/", "bbb", "/bbb"),
+ Arguments.of("/", "/", "/"),
+ Arguments.of("/", "/bbb", "/bbb"),
+
+ Arguments.of("aaa/", null, "aaa/"),
+ Arguments.of("aaa/", "", "aaa/"),
+ Arguments.of("aaa/", "bbb", "aaa/bbb"),
+ Arguments.of("aaa/", "/", "aaa/"),
+ Arguments.of("aaa/", "/bbb", "aaa/bbb"),
+
+ Arguments.of(";JS", null, ";JS"),
+ Arguments.of(";JS", "", ";JS"),
+ Arguments.of(";JS", "bbb", "bbb;JS"),
+ Arguments.of(";JS", "/", "/;JS"),
+ Arguments.of(";JS", "/bbb", "/bbb;JS"),
+
+ Arguments.of("aaa;JS", null, "aaa;JS"),
+ Arguments.of("aaa;JS", "", "aaa;JS"),
+ Arguments.of("aaa;JS", "bbb", "aaa/bbb;JS"),
+ Arguments.of("aaa;JS", "/", "aaa/;JS"),
+ Arguments.of("aaa;JS", "/bbb", "aaa/bbb;JS"),
+
+ Arguments.of("aaa/;JS", null, "aaa/;JS"),
+ Arguments.of("aaa/;JS", "", "aaa/;JS"),
+ Arguments.of("aaa/;JS", "bbb", "aaa/bbb;JS"),
+ Arguments.of("aaa/;JS", "/", "aaa/;JS"),
+ Arguments.of("aaa/;JS", "/bbb", "aaa/bbb;JS"),
+
+ Arguments.of("?A=1", null, "?A=1"),
+ Arguments.of("?A=1", "", "?A=1"),
+ Arguments.of("?A=1", "bbb", "bbb?A=1"),
+ Arguments.of("?A=1", "/", "/?A=1"),
+ Arguments.of("?A=1", "/bbb", "/bbb?A=1"),
+
+ Arguments.of("aaa?A=1", null, "aaa?A=1"),
+ Arguments.of("aaa?A=1", "", "aaa?A=1"),
+ Arguments.of("aaa?A=1", "bbb", "aaa/bbb?A=1"),
+ Arguments.of("aaa?A=1", "/", "aaa/?A=1"),
+ Arguments.of("aaa?A=1", "/bbb", "aaa/bbb?A=1"),
+
+ Arguments.of("aaa/?A=1", null, "aaa/?A=1"),
+ Arguments.of("aaa/?A=1", "", "aaa/?A=1"),
+ Arguments.of("aaa/?A=1", "bbb", "aaa/bbb?A=1"),
+ Arguments.of("aaa/?A=1", "/", "aaa/?A=1"),
+ Arguments.of("aaa/?A=1", "/bbb", "aaa/bbb?A=1"),
+
+ Arguments.of(";JS?A=1", null, ";JS?A=1"),
+ Arguments.of(";JS?A=1", "", ";JS?A=1"),
+ Arguments.of(";JS?A=1", "bbb", "bbb;JS?A=1"),
+ Arguments.of(";JS?A=1", "/", "/;JS?A=1"),
+ Arguments.of(";JS?A=1", "/bbb", "/bbb;JS?A=1"),
+
+ Arguments.of("aaa;JS?A=1", null, "aaa;JS?A=1"),
+ Arguments.of("aaa;JS?A=1", "", "aaa;JS?A=1"),
+ Arguments.of("aaa;JS?A=1", "bbb", "aaa/bbb;JS?A=1"),
+ Arguments.of("aaa;JS?A=1", "/", "aaa/;JS?A=1"),
+ Arguments.of("aaa;JS?A=1", "/bbb", "aaa/bbb;JS?A=1"),
+
+ Arguments.of("aaa/;JS?A=1", null, "aaa/;JS?A=1"),
+ Arguments.of("aaa/;JS?A=1", "", "aaa/;JS?A=1"),
+ Arguments.of("aaa/;JS?A=1", "bbb", "aaa/bbb;JS?A=1"),
+ Arguments.of("aaa/;JS?A=1", "/", "aaa/;JS?A=1"),
+ Arguments.of("aaa/;JS?A=1", "/bbb", "aaa/bbb;JS?A=1")
+ );
}
- @Test // TODO: Parameterize
- public void testParentPath()
+ @ParameterizedTest(name = "[{index}] {0}+{1}")
+ @MethodSource("addEncodedPathsSource")
+ public void testAddEncodedPaths(String path1, String path2, String expected)
{
- assertEquals("/aaa/", URIUtil.parentPath("/aaa/bbb/"), "parent /aaa/bbb/");
- assertEquals("/aaa/", URIUtil.parentPath("/aaa/bbb"), "parent /aaa/bbb");
- assertEquals("/", URIUtil.parentPath("/aaa/"), "parent /aaa/");
- assertEquals("/", URIUtil.parentPath("/aaa"), "parent /aaa");
- assertEquals(null, URIUtil.parentPath("/"), "parent /");
- assertEquals(null, URIUtil.parentPath(null), "parent null");
+ String actual = URIUtil.addEncodedPaths(path1, path2);
+ assertEquals(expected, actual, String.format("%s+%s", path1, path2));
}
- @Test // TODO: Parameterize
- public void testEqualsIgnoreEncoding()
+ public static Stream addDecodedPathsSource()
{
- assertTrue(URIUtil.equalsIgnoreEncodings("http://example.com/foo/bar", "http://example.com/foo/bar"));
- assertTrue(URIUtil.equalsIgnoreEncodings("/barry's", "/barry%27s"));
- assertTrue(URIUtil.equalsIgnoreEncodings("/barry%27s", "/barry's"));
- assertTrue(URIUtil.equalsIgnoreEncodings("/barry%27s", "/barry%27s"));
- assertTrue(URIUtil.equalsIgnoreEncodings("/b rry's", "/b%20rry%27s"));
- assertTrue(URIUtil.equalsIgnoreEncodings("/b rry%27s", "/b%20rry's"));
- assertTrue(URIUtil.equalsIgnoreEncodings("/b rry%27s", "/b%20rry%27s"));
+ return Stream.of(
+ Arguments.of(null, null, null),
+ Arguments.of(null, "", ""),
+ Arguments.of(null, "bbb", "bbb"),
+ Arguments.of(null, "/", "/"),
+ Arguments.of(null, "/bbb", "/bbb"),
- assertTrue(URIUtil.equalsIgnoreEncodings("/foo%2fbar", "/foo%2fbar"));
- assertTrue(URIUtil.equalsIgnoreEncodings("/foo%2fbar", "/foo%2Fbar"));
+ Arguments.of("", null, ""),
+ Arguments.of("", "", ""),
+ Arguments.of("", "bbb", "bbb"),
+ Arguments.of("", "/", "/"),
+ Arguments.of("", "/bbb", "/bbb"),
- assertFalse(URIUtil.equalsIgnoreEncodings("ABC", "abc"));
- assertFalse(URIUtil.equalsIgnoreEncodings("/barry's", "/barry%26s"));
+ Arguments.of("aaa", null, "aaa"),
+ Arguments.of("aaa", "", "aaa"),
+ Arguments.of("aaa", "bbb", "aaa/bbb"),
+ Arguments.of("aaa", "/", "aaa/"),
+ Arguments.of("aaa", "/bbb", "aaa/bbb"),
- assertFalse(URIUtil.equalsIgnoreEncodings("/foo/bar", "/foo%2fbar"));
- assertFalse(URIUtil.equalsIgnoreEncodings("/foo2fbar", "/foo/bar"));
+ Arguments.of("/", null, "/"),
+ Arguments.of("/", "", "/"),
+ Arguments.of("/", "bbb", "/bbb"),
+ Arguments.of("/", "/", "/"),
+ Arguments.of("/", "/bbb", "/bbb"),
+
+ Arguments.of("aaa/", null, "aaa/"),
+ Arguments.of("aaa/", "", "aaa/"),
+ Arguments.of("aaa/", "bbb", "aaa/bbb"),
+ Arguments.of("aaa/", "/", "aaa/"),
+ Arguments.of("aaa/", "/bbb", "aaa/bbb"),
+
+ Arguments.of(";JS", null, ";JS"),
+ Arguments.of(";JS", "", ";JS"),
+ Arguments.of(";JS", "bbb", ";JS/bbb"),
+ Arguments.of(";JS", "/", ";JS/"),
+ Arguments.of(";JS", "/bbb", ";JS/bbb"),
+
+ Arguments.of("aaa;JS", null, "aaa;JS"),
+ Arguments.of("aaa;JS", "", "aaa;JS"),
+ Arguments.of("aaa;JS", "bbb", "aaa;JS/bbb"),
+ Arguments.of("aaa;JS", "/", "aaa;JS/"),
+ Arguments.of("aaa;JS", "/bbb", "aaa;JS/bbb"),
+
+ Arguments.of("aaa/;JS", null, "aaa/;JS"),
+ Arguments.of("aaa/;JS", "", "aaa/;JS"),
+ Arguments.of("aaa/;JS", "bbb", "aaa/;JS/bbb"),
+ Arguments.of("aaa/;JS", "/", "aaa/;JS/"),
+ Arguments.of("aaa/;JS", "/bbb", "aaa/;JS/bbb"),
+
+ Arguments.of("?A=1", null, "?A=1"),
+ Arguments.of("?A=1", "", "?A=1"),
+ Arguments.of("?A=1", "bbb", "?A=1/bbb"),
+ Arguments.of("?A=1", "/", "?A=1/"),
+ Arguments.of("?A=1", "/bbb", "?A=1/bbb"),
+
+ Arguments.of("aaa?A=1", null, "aaa?A=1"),
+ Arguments.of("aaa?A=1", "", "aaa?A=1"),
+ Arguments.of("aaa?A=1", "bbb", "aaa?A=1/bbb"),
+ Arguments.of("aaa?A=1", "/", "aaa?A=1/"),
+ Arguments.of("aaa?A=1", "/bbb", "aaa?A=1/bbb"),
+
+ Arguments.of("aaa/?A=1", null, "aaa/?A=1"),
+ Arguments.of("aaa/?A=1", "", "aaa/?A=1"),
+ Arguments.of("aaa/?A=1", "bbb", "aaa/?A=1/bbb"),
+ Arguments.of("aaa/?A=1", "/", "aaa/?A=1/"),
+ Arguments.of("aaa/?A=1", "/bbb", "aaa/?A=1/bbb")
+ );
}
- @Test // TODO: Parameterize
- public void testEqualsIgnoreEncoding_JarFile()
+ @ParameterizedTest(name = "[{index}] {0}+{1}")
+ @MethodSource("addDecodedPathsSource")
+ public void testAddDecodedPaths(String path1, String path2, String expected)
{
- URI uriA = URI.create("jar:file:/path/to/main.jar!/META-INF/versions/");
- URI uriB = URI.create("jar:file:/path/to/main.jar!/META-INF/%76ersions/");
- assertTrue(URIUtil.equalsIgnoreEncodings(uriA, uriB));
-
- uriA = URI.create("JAR:FILE:/path/to/main.jar!/META-INF/versions/");
- uriB = URI.create("jar:file:/path/to/main.jar!/META-INF/versions/");
- assertTrue(URIUtil.equalsIgnoreEncodings(uriA, uriB));
+ String actual = URIUtil.addPaths(path1, path2);
+ assertEquals(expected, actual, String.format("%s+%s", path1, path2));
}
- @Test // TODO: Parameterize
- public void testJarSource() throws Exception
+ public static Stream compactPathSource()
{
- assertThat(URIUtil.getJarSource("file:///tmp/"), is("file:///tmp/"));
- assertThat(URIUtil.getJarSource("jar:file:///tmp/foo.jar"), is("file:///tmp/foo.jar"));
- assertThat(URIUtil.getJarSource("jar:file:///tmp/foo.jar!/some/path"), is("file:///tmp/foo.jar"));
- assertThat(URIUtil.getJarSource(new URI("file:///tmp/")), is(new URI("file:///tmp/")));
- assertThat(URIUtil.getJarSource(new URI("jar:file:///tmp/foo.jar")), is(new URI("file:///tmp/foo.jar")));
- assertThat(URIUtil.getJarSource(new URI("jar:file:///tmp/foo.jar!/some/path")), is(new URI("file:///tmp/foo.jar")));
+ return Stream.of(
+ Arguments.of("/foo/bar", "/foo/bar"),
+ Arguments.of("/foo/bar?a=b//c", "/foo/bar?a=b//c"),
+
+ Arguments.of("//foo//bar", "/foo/bar"),
+ Arguments.of("//foo//bar?a=b//c", "/foo/bar?a=b//c"),
+
+ Arguments.of("/foo///bar", "/foo/bar"),
+ Arguments.of("/foo///bar?a=b//c", "/foo/bar?a=b//c")
+ );
}
- public static Stream encodeSpaces()
+ @ParameterizedTest(name = "[{index}] {0}")
+ @MethodSource("compactPathSource")
+ public void testCompactPath(String path, String expected)
{
- List data = new ArrayList<>();
+ String actual = URIUtil.compactPath(path);
+ assertEquals(expected, actual);
+ }
- // [raw, expected]
+ public static Stream parentPathSource()
+ {
+ return Stream.of(
+ Arguments.of("/aaa/bbb/", "/aaa/"),
+ Arguments.of("/aaa/bbb", "/aaa/"),
+ Arguments.of("/aaa/", "/"),
+ Arguments.of("/aaa", "/"),
+ Arguments.of("/", null),
+ Arguments.of(null, null)
+ );
+ }
- // null
- data.add(new String[]{null, null});
+ @ParameterizedTest(name = "[{index}] {0}")
+ @MethodSource("parentPathSource")
+ public void testParentPath(String path, String expectedPath)
+ {
+ String actual = URIUtil.parentPath(path);
+ assertEquals(expectedPath, actual, String.format("parent %s", path));
+ }
- // no spaces
- data.add(new String[]{"abc", "abc"});
+ public static Stream equalsIgnoreEncodingStringTrueSource()
+ {
+ return Stream.of(
+ Arguments.of("http://example.com/foo/bar", "http://example.com/foo/bar"),
+ Arguments.of("/barry's", "/barry%27s"),
+ Arguments.of("/barry%27s", "/barry's"),
+ Arguments.of("/barry%27s", "/barry%27s"),
+ Arguments.of("/b rry's", "/b%20rry%27s"),
+ Arguments.of("/b rry%27s", "/b%20rry's"),
+ Arguments.of("/b rry%27s", "/b%20rry%27s"),
- // match
- data.add(new String[]{"a c", "a%20c"});
- data.add(new String[]{" ", "%20%20%20"});
- data.add(new String[]{"a%20space", "a%20space"});
-
- return data.stream();
+ Arguments.of("/foo%2fbar", "/foo%2fbar"),
+ Arguments.of("/foo%2fbar", "/foo%2Fbar")
+ );
}
@ParameterizedTest
- @MethodSource(value = "encodeSpaces")
+ @MethodSource("equalsIgnoreEncodingStringTrueSource")
+ public void testEqualsIgnoreEncodingStringTrue(String uriA, String uriB)
+ {
+ assertTrue(URIUtil.equalsIgnoreEncodings(uriA, uriB));
+ }
+
+ public static Stream equalsIgnoreEncodingStringFalseSource()
+ {
+ return Stream.of(
+ Arguments.of("ABC", "abc"),
+ Arguments.of("/barry's", "/barry%26s"),
+
+ Arguments.of("/foo/bar", "/foo%2fbar"),
+ Arguments.of("/foo2fbar", "/foo/bar")
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("equalsIgnoreEncodingStringFalseSource")
+ public void testEqualsIgnoreEncodingStringFalse(String uriA, String uriB)
+ {
+ assertFalse(URIUtil.equalsIgnoreEncodings(uriA, uriB));
+ }
+
+ public static Stream equalsIgnoreEncodingURITrueSource()
+ {
+ return Stream.of(
+ Arguments.of(
+ URI.create("jar:file:/path/to/main.jar!/META-INF/versions/"),
+ URI.create("jar:file:/path/to/main.jar!/META-INF/%76ersions/")
+ ),
+ Arguments.of(
+ URI.create("JAR:FILE:/path/to/main.jar!/META-INF/versions/"),
+ URI.create("jar:file:/path/to/main.jar!/META-INF/versions/")
+ )
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("equalsIgnoreEncodingURITrueSource")
+ public void testEqualsIgnoreEncodingURITrue(URI uriA, URI uriB)
+ {
+ assertTrue(URIUtil.equalsIgnoreEncodings(uriA, uriB));
+ }
+
+ public static Stream getJarSourceStringSource()
+ {
+ return Stream.of(
+ Arguments.of("file:///tmp/", "file:///tmp/"),
+ Arguments.of("jar:file:///tmp/foo.jar", "file:///tmp/foo.jar"),
+ Arguments.of("jar:file:///tmp/foo.jar!/some/path", "file:///tmp/foo.jar")
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("getJarSourceStringSource")
+ public void testJarSourceString(String uri, String expectedJarUri) throws Exception
+ {
+ assertThat(URIUtil.getJarSource(uri), is(expectedJarUri));
+ }
+
+ public static Stream getJarSourceURISource()
+ {
+ return Stream.of(
+ Arguments.of(URI.create("file:///tmp/"), URI.create("file:///tmp/")),
+ Arguments.of(URI.create("jar:file:///tmp/foo.jar"), URI.create("file:///tmp/foo.jar")),
+ Arguments.of(URI.create("jar:file:///tmp/foo.jar!/some/path"), URI.create("file:///tmp/foo.jar"))
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("getJarSourceURISource")
+ public void testJarSourceURI(URI uri, URI expectedJarUri) throws Exception
+ {
+ assertThat(URIUtil.getJarSource(uri), is(expectedJarUri));
+ }
+
+ public static Stream encodeSpacesSource()
+ {
+ return Stream.of(
+ // null
+ Arguments.of(null, null),
+
+ // no spaces
+ Arguments.of("abc", "abc"),
+
+ // match
+ Arguments.of("a c", "a%20c"),
+ Arguments.of(" ", "%20%20%20"),
+ Arguments.of("a%20space", "a%20space")
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("encodeSpacesSource")
public void testEncodeSpaces(String raw, String expected)
{
assertThat(URIUtil.encodeSpaces(raw), is(expected));
}
- public static Stream encodeSpecific()
+ public static Stream encodeSpecific()
{
- List data = new ArrayList<>();
+ return Stream.of(
+ // [raw, chars, expected]
- // [raw, chars, expected]
+ // null input
+ Arguments.of(null, null, null),
- // null input
- data.add(new String[]{null, null, null});
+ // null chars
+ Arguments.of("abc", null, "abc"),
- // null chars
- data.add(new String[]{"abc", null, "abc"});
+ // empty chars
+ Arguments.of("abc", "", "abc"),
- // empty chars
- data.add(new String[]{"abc", "", "abc"});
+ // no matches
+ Arguments.of("abc", ".;", "abc"),
+ Arguments.of("xyz", ".;", "xyz"),
+ Arguments.of(":::", ".;", ":::"),
- // no matches
- data.add(new String[]{"abc", ".;", "abc"});
- data.add(new String[]{"xyz", ".;", "xyz"});
- data.add(new String[]{":::", ".;", ":::"});
+ // matches
+ Arguments.of("a c", " ", "a%20c"),
+ Arguments.of("name=value", "=", "name%3Dvalue"),
+ Arguments.of("This has fewer then 10% hits.", ".%", "This has fewer then 10%25 hits%2E"),
- // matches
- data.add(new String[]{"a c", " ", "a%20c"});
- data.add(new String[]{"name=value", "=", "name%3Dvalue"});
- data.add(new String[]{"This has fewer then 10% hits.", ".%", "This has fewer then 10%25 hits%2E"});
-
- // partially encoded already
- data.add(new String[]{"a%20name=value%20pair", "=", "a%20name%3Dvalue%20pair"});
- data.add(new String[]{"a%20name=value%20pair", "=%", "a%2520name%3Dvalue%2520pair"});
-
- return data.stream();
+ // partially encoded already
+ Arguments.of("a%20name=value%20pair", "=", "a%20name%3Dvalue%20pair"),
+ Arguments.of("a%20name=value%20pair", "=%", "a%2520name%3Dvalue%2520pair")
+ );
}
@ParameterizedTest
@@ -382,36 +486,34 @@ public class URIUtilTest
assertThat(URIUtil.encodeSpecific(raw, chars), is(expected));
}
- public static Stream decodeSpecific()
+ public static Stream decodeSpecific()
{
- List data = new ArrayList<>();
+ return Stream.of(
+ // [raw, chars, expected]
- // [raw, chars, expected]
+ // null input
+ Arguments.of(null, null, null),
- // null input
- data.add(new String[]{null, null, null});
+ // null chars
+ Arguments.of("abc", null, "abc"),
- // null chars
- data.add(new String[]{"abc", null, "abc"});
+ // empty chars
+ Arguments.of("abc", "", "abc"),
- // empty chars
- data.add(new String[]{"abc", "", "abc"});
+ // no matches
+ Arguments.of("abc", ".;", "abc"),
+ Arguments.of("xyz", ".;", "xyz"),
+ Arguments.of(":::", ".;", ":::"),
- // no matches
- data.add(new String[]{"abc", ".;", "abc"});
- data.add(new String[]{"xyz", ".;", "xyz"});
- data.add(new String[]{":::", ".;", ":::"});
+ // matches
+ Arguments.of("a%20c", " ", "a c"),
+ Arguments.of("name%3Dvalue", "=", "name=value"),
+ Arguments.of("This has fewer then 10%25 hits%2E", ".%", "This has fewer then 10% hits."),
- // matches
- data.add(new String[]{"a%20c", " ", "a c"});
- data.add(new String[]{"name%3Dvalue", "=", "name=value"});
- data.add(new String[]{"This has fewer then 10%25 hits%2E", ".%", "This has fewer then 10% hits."});
-
- // partially decode
- data.add(new String[]{"a%20name%3Dvalue%20pair", "=", "a%20name=value%20pair"});
- data.add(new String[]{"a%2520name%3Dvalue%2520pair", "=%", "a%20name=value%20pair"});
-
- return data.stream();
+ // partially decode
+ Arguments.of("a%20name%3Dvalue%20pair", "=", "a%20name=value%20pair"),
+ Arguments.of("a%2520name%3Dvalue%2520pair", "=%", "a%20name=value%20pair")
+ );
}
@ParameterizedTest
From 7da57151ed31bab515a312e81249743a69ada90c Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Wed, 28 Aug 2019 12:08:18 -0500
Subject: [PATCH 49/55] Issue #4033 - lenient percent decode in URIUtil
+ Allows for preserving decoded Strings like "X%YZ"
Signed-off-by: Joakim Erdfelt
---
.../org/eclipse/jetty/util/StringUtil.java | 15 +++
.../java/org/eclipse/jetty/util/URIUtil.java | 107 ++++++++++++++++--
.../org/eclipse/jetty/util/URIUtilTest.java | 31 ++++-
3 files changed, 138 insertions(+), 15 deletions(-)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
index 2c466a34b55..fbc96e38c1d 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
@@ -644,6 +644,21 @@ public class StringUtil
return __UTF8.equalsIgnoreCase(charset) || __UTF8.equalsIgnoreCase(normalizeCharset(charset));
}
+ public static boolean isHex(String str, int offset, int length)
+ {
+ for (int i = offset; i < (offset + length); i++)
+ {
+ char c = str.charAt(i);
+ if (!(((c >= 'a') && (c <= 'f')) ||
+ ((c >= 'A') && (c <= 'F')) ||
+ ((c >= '0') && (c <= '9'))))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static String printable(String name)
{
if (name == null)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
index b86a1b7958a..9e9b2c536dd 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
@@ -470,24 +470,72 @@ public class URIUtil
builder = new Utf8StringBuilder(path.length());
builder.append(path, offset, i - offset);
}
- if ((i + 2) < end)
+
+ // lenient percent decoding
+ if (i >= end)
{
- char u = path.charAt(i + 1);
- if (u == 'u')
+ // [LENIENT] a percent sign at end of string.
+ builder.append('%');
+ i = end;
+ }
+ else if (end > (i + 1))
+ {
+ char type = path.charAt(i + 1);
+ if (type == 'u')
{
- // TODO this is wrong. This is a codepoint not a char
- builder.append((char)(0xffff & TypeUtil.parseInt(path, i + 2, 4, 16)));
- i += 5;
+ // We have a possible (deprecated) microsoft unicode code point "%u####"
+ // - not recommended to use as it's limited to 2 bytes.
+ if ((i + 5) >= end)
+ {
+ // [LENIENT] we have a partial "%u####" at the end of a string.
+ builder.append(path, i, (end - i));
+ i = end;
+ }
+ else
+ {
+ // this seems wrong, as we are casting to a char, but that's the known
+ // limitation of this deprecated encoding (only 2 bytes allowed)
+ if (StringUtil.isHex(path, i + 2, 4))
+ {
+ builder.append((char)(0xffff & TypeUtil.parseInt(path, i + 2, 4, 16)));
+ i += 5;
+ }
+ else
+ {
+ // [LENIENT] copy the "%u" as-is.
+ builder.append(path, i, 2);
+ i += 1;
+ }
+ }
+ }
+ else if (end > (i + 2))
+ {
+ // we have a possible "%##" encoding
+ if (StringUtil.isHex(path, i + 1, 2))
+ {
+ char c1 = path.charAt(i + 1);
+ char c2 = path.charAt(i + 2);
+ builder.append((byte)(0xff & (TypeUtil.convertHexDigit(c1) * 16 + TypeUtil.convertHexDigit(c2))));
+ i += 2;
+ }
+ else
+ {
+ builder.append(path, i, 3);
+ i += 2;
+ }
}
else
{
- builder.append((byte)(0xff & (TypeUtil.convertHexDigit(u) * 16 + TypeUtil.convertHexDigit(path.charAt(i + 2)))));
- i += 2;
+ // [LENIENT] incomplete "%##" sequence at end of string
+ builder.append(path, i, (end - i));
+ i = end;
}
}
else
{
- throw new IllegalArgumentException("Bad URI % encoding");
+ // [LENIENT] the "%" at the end of the string
+ builder.append(path, i, (end - i));
+ i = end;
}
break;
@@ -1156,12 +1204,32 @@ public class URIUtil
int oa = uriA.charAt(a++);
int ca = oa;
if (ca == '%')
- ca = TypeUtil.convertHexDigit(uriA.charAt(a++)) * 16 + TypeUtil.convertHexDigit(uriA.charAt(a++));
+ {
+ ca = lenientPercentDecode(uriA, a);
+ if (ca == (-1))
+ {
+ ca = '%';
+ }
+ else
+ {
+ a += 2;
+ }
+ }
int ob = uriB.charAt(b++);
int cb = ob;
if (cb == '%')
- cb = TypeUtil.convertHexDigit(uriB.charAt(b++)) * 16 + TypeUtil.convertHexDigit(uriB.charAt(b++));
+ {
+ cb = lenientPercentDecode(uriB, b);
+ if (cb == (-1))
+ {
+ cb = '%';
+ }
+ else
+ {
+ b += 2;
+ }
+ }
if (ca == '/' && oa != ob)
return false;
@@ -1172,6 +1240,23 @@ public class URIUtil
return a == lenA && b == lenB;
}
+ private static int lenientPercentDecode(String str, int offset)
+ {
+ if (offset >= str.length())
+ return -1;
+
+ char a1 = str.charAt(offset);
+ char a2 = str.charAt(offset + 1);
+ try
+ {
+ return TypeUtil.convertHexDigit(a1) * 16 + TypeUtil.convertHexDigit(a2);
+ }
+ catch (NumberFormatException e)
+ {
+ return -1;
+ }
+ }
+
public static boolean equalsIgnoreEncodings(URI uriA, URI uriB)
{
if (uriA.equals(uriB))
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
index 0ea76fcef5f..7e7a1aa628a 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
@@ -90,9 +90,22 @@ public class URIUtilTest
// Test for null character (real world ugly test case)
byte[] oddBytes = {'/', 0x00, '/'};
String odd = new String(oddBytes, StandardCharsets.ISO_8859_1);
- assertEquals(odd, URIUtil.decodePath("/%00/"));
arguments.add(Arguments.of("/%00/", odd));
+ // Deprecated Microsoft Percent-U encoding
+ arguments.add(Arguments.of("abc%u3040", "abc\u3040"));
+
+ // Lenient decode
+ arguments.add(Arguments.of("abc%xyz", "abc%xyz")); // not a "%##"
+ arguments.add(Arguments.of("abc%", "abc%")); // percent at end of string
+ arguments.add(Arguments.of("abc%A", "abc%A")); // incomplete "%##" at end of string
+ arguments.add(Arguments.of("abc%uvwxyz", "abc%uvwxyz")); // not a valid "%u####"
+ arguments.add(Arguments.of("abc%uEFGHIJ", "abc%uEFGHIJ")); // not a valid "%u####"
+ arguments.add(Arguments.of("abc%uABC", "abc%uABC")); // incomplete "%u####"
+ arguments.add(Arguments.of("abc%uAB", "abc%uAB")); // incomplete "%u####"
+ arguments.add(Arguments.of("abc%uA", "abc%uA")); // incomplete "%u####"
+ arguments.add(Arguments.of("abc%u", "abc%u")); // incomplete "%u####"
+
return arguments.stream();
}
@@ -344,7 +357,11 @@ public class URIUtilTest
Arguments.of("/b rry%27s", "/b%20rry%27s"),
Arguments.of("/foo%2fbar", "/foo%2fbar"),
- Arguments.of("/foo%2fbar", "/foo%2Fbar")
+ Arguments.of("/foo%2fbar", "/foo%2Fbar"),
+
+ // encoded vs not-encode ("%" symbol is encoded as "%25")
+ Arguments.of("/abc%25xyz", "/abc%xyz"),
+ Arguments.of("/zzz%25", "/zzz%")
);
}
@@ -358,11 +375,17 @@ public class URIUtilTest
public static Stream equalsIgnoreEncodingStringFalseSource()
{
return Stream.of(
+ // case difference
Arguments.of("ABC", "abc"),
+ // Encoding difference ("'" is "%27")
Arguments.of("/barry's", "/barry%26s"),
-
+ // Never match on "%2f" differences
Arguments.of("/foo/bar", "/foo%2fbar"),
- Arguments.of("/foo2fbar", "/foo/bar")
+ // not actually encoded
+ Arguments.of("/foo2fbar", "/foo/bar"),
+ // encoded vs not-encode ("%" symbol is encoded as "%25")
+ Arguments.of("/yyy%25zzz", "/aaa%xxx"),
+ Arguments.of("/zzz%25", "/aaa%")
);
}
From f47115c5856921728954cf5c24de106753ee0a0c Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Wed, 28 Aug 2019 12:20:52 -0500
Subject: [PATCH 50/55] Issue #4033 - More tests for Lenient URIUtil behavior
Signed-off-by: Joakim Erdfelt
---
.../main/java/org/eclipse/jetty/util/StringUtil.java | 5 +++++
.../main/java/org/eclipse/jetty/util/URIUtil.java | 12 ++++--------
.../java/org/eclipse/jetty/util/URIUtilTest.java | 2 ++
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
index fbc96e38c1d..2b01724eb82 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
@@ -646,6 +646,11 @@ public class StringUtil
public static boolean isHex(String str, int offset, int length)
{
+ if (offset + length > str.length())
+ {
+ return false;
+ }
+
for (int i = offset; i < (offset + length); i++)
{
char c = str.charAt(i);
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
index 9e9b2c536dd..63c4b081162 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
@@ -513,9 +513,7 @@ public class URIUtil
// we have a possible "%##" encoding
if (StringUtil.isHex(path, i + 1, 2))
{
- char c1 = path.charAt(i + 1);
- char c2 = path.charAt(i + 2);
- builder.append((byte)(0xff & (TypeUtil.convertHexDigit(c1) * 16 + TypeUtil.convertHexDigit(c2))));
+ builder.append((byte)TypeUtil.parseInt(path, i + 1, 2, 16));
i += 2;
}
else
@@ -1245,13 +1243,11 @@ public class URIUtil
if (offset >= str.length())
return -1;
- char a1 = str.charAt(offset);
- char a2 = str.charAt(offset + 1);
- try
+ if (StringUtil.isHex(str, offset, 2))
{
- return TypeUtil.convertHexDigit(a1) * 16 + TypeUtil.convertHexDigit(a2);
+ return TypeUtil.parseInt(str, offset, 2, 16);
}
- catch (NumberFormatException e)
+ else
{
return -1;
}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
index 7e7a1aa628a..ce02b8019bb 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
@@ -361,6 +361,8 @@ public class URIUtilTest
// encoded vs not-encode ("%" symbol is encoded as "%25")
Arguments.of("/abc%25xyz", "/abc%xyz"),
+ Arguments.of("/abc%25xy", "/abc%xy"),
+ Arguments.of("/abc%25x", "/abc%x"),
Arguments.of("/zzz%25", "/zzz%")
);
}
From e56d91196d6a669b04dc499cfc56329cbccd6297 Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Wed, 28 Aug 2019 12:31:33 -0500
Subject: [PATCH 51/55] Issue #4020 - Adding JMX to BrowserDebugTool to test
dump
Signed-off-by: Joakim Erdfelt
---
jetty-websocket/websocket-server/pom.xml | 6 ++++++
.../jetty/websocket/server/browser/BrowserDebugTool.java | 9 +++++++++
2 files changed, 15 insertions(+)
diff --git a/jetty-websocket/websocket-server/pom.xml b/jetty-websocket/websocket-server/pom.xml
index e406f52595c..c3e50f78364 100644
--- a/jetty-websocket/websocket-server/pom.xml
+++ b/jetty-websocket/websocket-server/pom.xml
@@ -107,6 +107,12 @@
tests
test
+
+ org.eclipse.jetty
+ jetty-jmx
+ ${project.version}
+ test
+
org.eclipse.jetty.toolchain
jetty-test-helper
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java
index 751e5b5479e..2cd9a7fb9f6 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java
@@ -20,12 +20,14 @@ package org.eclipse.jetty.websocket.server.browser;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
+import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ResourceHandler;
@@ -131,10 +133,17 @@ public class BrowserDebugTool implements WebSocketCreator
public void prepare(int port) throws IOException, URISyntaxException
{
server = new Server();
+
+ // Setup JMX
+ MBeanContainer mbContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
+ server.addBean(mbContainer, true);
+
+ // Setup Connector
connector = new ServerConnector(server);
connector.setPort(port);
server.addConnector(connector);
+ // Setup WebSocket
WebSocketHandler wsHandler = new WebSocketHandler()
{
@Override
From 37e7884382dadf9feb7092ed928e2134b5aa3df2 Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Wed, 28 Aug 2019 12:36:07 -0500
Subject: [PATCH 52/55] Issue #4020 - Applying change requested from PR review
Signed-off-by: Joakim Erdfelt
---
.../extensions/WebSocketExtensionFactory.java | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
index f1ca84d635f..118f7a8a4cd 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
@@ -51,12 +51,19 @@ public class WebSocketExtensionFactory extends ExtensionFactory implements LifeC
public WebSocketExtensionFactory(WebSocketContainerScope container)
{
- containerLifeCycle = new ContainerLifeCycle();
+ containerLifeCycle = new ContainerLifeCycle()
+ {
+ @Override
+ public String toString()
+ {
+ return String.format("%s@%x{%s}", WebSocketExtensionFactory.class.getSimpleName(), hashCode(), containerLifeCycle.getState());
+ }
+ };
availableExtensions = new HashMap<>();
for (Extension ext : extensionLoader)
{
if (ext != null)
- availableExtensions.put(ext.getName(),ext.getClass());
+ availableExtensions.put(ext.getName(), ext.getClass());
}
this.container = container;
@@ -135,7 +142,7 @@ public class WebSocketExtensionFactory extends ExtensionFactory implements LifeC
@Override
public void register(String name, Class extends Extension> extension)
{
- availableExtensions.put(name,extension);
+ availableExtensions.put(name, extension);
}
@Override
@@ -233,6 +240,6 @@ public class WebSocketExtensionFactory extends ExtensionFactory implements LifeC
@Override
public String toString()
{
- return String.format("%s@%x{%s}", WebSocketExtensionFactory.class.getName(), hashCode(), containerLifeCycle.getState());
+ return containerLifeCycle.toString();
}
}
From 2fcb311c568e4f288d2cfdbd191027e7e37b98b2 Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Wed, 28 Aug 2019 16:32:19 -0500
Subject: [PATCH 53/55] Issue #4033 - Addressing Lenient URIUtil decode
behavior change in test
Signed-off-by: Joakim Erdfelt
---
.../jetty/server/HttpConnectionTest.java | 17 ++++++-----------
.../java/org/eclipse/jetty/util/URIUtil.java | 3 ++-
2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
index f2be892780c..408ebb1535a 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
@@ -690,17 +690,12 @@ public class HttpConnectionTest
@Test
public void testBadURIencoding() throws Exception
{
- Log.getLogger(HttpParser.class).info("badMessage: bad encoding expected ...");
- String response;
-
- try (StacklessLogging stackless = new StacklessLogging(HttpParser.class))
- {
- response = connector.getResponse("GET /bad/encoding%1 HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
- "Connection: close\r\n" +
- "\r\n");
- checkContains(response, 0, "HTTP/1.1 400");
- }
+ // The URI is being leniently decoded, leaving the "%x" alone
+ String response = connector.getResponse("GET /bad/encoding%x HTTP/1.1\r\n" +
+ "Host: localhost\r\n" +
+ "Connection: close\r\n" +
+ "\r\n");
+ checkContains(response, 0, "HTTP/1.1 200");
}
@Test
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
index 63c4b081162..73a3e77e705 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
@@ -1229,11 +1229,12 @@ public class URIUtil
}
}
+ // Don't match on encoded slash
if (ca == '/' && oa != ob)
return false;
if (ca != cb)
- return URIUtil.decodePath(uriA).equals(URIUtil.decodePath(uriB));
+ return false;
}
return a == lenA && b == lenB;
}
From bb7eb4bc86d6e7e3df0ad77bd7efa1861a1866aa Mon Sep 17 00:00:00 2001
From: Joakim Erdfelt
Date: Fri, 30 Aug 2019 09:23:34 -0500
Subject: [PATCH 54/55] Adding some comments to URIUtilTest
Signed-off-by: Joakim Erdfelt
---
.../src/test/java/org/eclipse/jetty/util/URIUtilTest.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
index ce02b8019bb..1354b2e3398 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
@@ -381,7 +381,8 @@ public class URIUtilTest
Arguments.of("ABC", "abc"),
// Encoding difference ("'" is "%27")
Arguments.of("/barry's", "/barry%26s"),
- // Never match on "%2f" differences
+ // Never match on "%2f" differences - only intested in filename / directory name differences
+ // This could be a directory called "foo" with a file called "bar" on the left, and just a file "foo%2fbar" on the right
Arguments.of("/foo/bar", "/foo%2fbar"),
// not actually encoded
Arguments.of("/foo2fbar", "/foo/bar"),
From 49ba6d1acb230ecc5d2cdca1517d3e97dff4bfbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BA=B7=E6=99=BA=E5=86=AC?=
Date: Tue, 3 Sep 2019 02:29:50 +0800
Subject: [PATCH 55/55] fix typo and grammar (#4045)
Signed-off-by: KangZhiDong
---
.../TestSecurityAnnotationConversions.java | 2 +-
.../eclipse/jetty/client/HttpClientTransport.java | 2 +-
.../java/org/eclipse/jetty/client/HttpContent.java | 2 +-
.../org/eclipse/jetty/client/HttpReceiver.java | 2 +-
.../org/eclipse/jetty/client/HttpRedirector.java | 2 +-
.../java/org/eclipse/jetty/client/HttpRequest.java | 2 +-
.../java/org/eclipse/jetty/client/api/Request.java | 2 +-
.../org/eclipse/jetty/client/api/Response.java | 2 +-
.../jetty/client/http/HttpReceiverOverHTTP.java | 2 +-
.../jetty/client/HttpConnectionLifecycleTest.java | 2 +-
.../eclipse/jetty/continuation/Continuation.java | 2 +-
jetty-deploy/src/test/resources/jetty-http.xml | 4 ++--
.../fcgi/server/proxy/FastCGIProxyServlet.java | 2 +-
.../org/eclipse/jetty/http/HostPortHttpField.java | 2 +-
.../java/org/eclipse/jetty/http/HttpField.java | 2 +-
.../java/org/eclipse/jetty/http/HttpMethod.java | 4 ++--
.../java/org/eclipse/jetty/http/HttpParser.java | 8 ++++----
.../main/java/org/eclipse/jetty/http/HttpURI.java | 2 +-
.../java/org/eclipse/jetty/http/HttpVersion.java | 8 ++++----
.../eclipse/jetty/http/PreEncodedHttpField.java | 2 +-
.../java/org/eclipse/jetty/http/HttpTester.java | 2 +-
.../jetty/http2/BufferingFlowControlStrategy.java | 2 +-
.../java/org/eclipse/jetty/http2/ErrorCode.java | 4 ++--
.../java/org/eclipse/jetty/http2/ISession.java | 2 +-
.../main/java/org/eclipse/jetty/http2/IStream.java | 2 +-
.../java/org/eclipse/jetty/http2/api/Session.java | 8 ++++----
.../java/org/eclipse/jetty/http2/api/Stream.java | 8 ++++----
.../eclipse/jetty/http2/parser/PrefaceParser.java | 2 +-
.../http/HttpClientTransportOverHTTP2Test.java | 2 +-
.../src/main/config/etc/jetty-http2.xml | 2 +-
.../src/main/config/etc/jetty-http2c.xml | 2 +-
.../server/HTTP2CServerConnectionFactory.java | 4 ++--
.../jetty/http2/server/HTTP2ServerConnection.java | 2 +-
.../jetty/http2/server/HTTP2CServerTest.java | 6 +++---
.../jetty-osgi-boot/jettyhome/etc/jetty-http.xml | 4 ++--
.../etc/jetty-http-boot-context-as-service.xml | 4 ++--
.../etc/jetty-http-boot-webapp-as-service.xml | 4 ++--
.../etc/jetty-http-boot-with-annotations.xml | 4 ++--
.../etc/jetty-http-boot-with-javax-websocket.xml | 4 ++--
.../test/config/etc/jetty-http-boot-with-jsp.xml | 4 ++--
.../config/etc/jetty-http-boot-with-websocket.xml | 4 ++--
.../src/test/config/etc/jetty-http.xml | 4 ++--
.../src/test/config/etc/jetty-http2-jdk9.xml | 2 +-
.../src/test/config/etc/jetty-http2.xml | 2 +-
.../src/test/config/etc/jetty-https.xml | 2 +-
.../jetty-rewrite.xml | 2 +-
.../security/ConfigurableSpnegoLoginService.java | 2 +-
.../jetty/security/ConstraintSecurityHandler.java | 2 +-
.../authentication/SessionAuthentication.java | 2 +-
.../org/eclipse/jetty/security/ConstraintTest.java | 4 ++--
jetty-server/src/main/config/etc/jetty-http.xml | 4 ++--
jetty-server/src/main/config/etc/jetty-https.xml | 2 +-
jetty-server/src/main/config/modules/http.mod | 2 +-
.../eclipse/jetty/server/AbstractConnector.java | 2 +-
.../eclipse/jetty/server/ConnectionFactory.java | 6 +++---
.../java/org/eclipse/jetty/server/HttpChannel.java | 4 ++--
.../eclipse/jetty/server/HttpChannelOverHttp.java | 4 ++--
.../eclipse/jetty/server/HttpConfiguration.java | 14 +++++++-------
.../jetty/server/OptionalSslConnectionFactory.java | 2 +-
.../jetty/server/ResourceContentFactory.java | 2 +-
.../java/org/eclipse/jetty/server/Response.java | 2 +-
.../jetty/server/ServletRequestHttpWrapper.java | 2 +-
.../jetty/server/ServletResponseHttpWrapper.java | 2 +-
.../eclipse/jetty/server/handler/ErrorHandler.java | 4 ++--
.../jetty/server/handler/ShutdownHandler.java | 4 ++--
.../handler/gzip/GzipHttpInputInterceptor.java | 2 +-
.../org/eclipse/jetty/server/session/Session.java | 2 +-
.../jetty/server/session/SessionHandler.java | 2 +-
.../eclipse/jetty/server/ThreadStarvationTest.java | 2 +-
.../org/eclipse/jetty/servlet/RequestURITest.java | 2 +-
.../java/org/eclipse/jetty/servlets/DoSFilter.java | 2 +-
.../src/main/config/modules/unixsocket-http.mod | 2 +-
.../src/main/config/modules/unixsocket-http2c.mod | 2 +-
.../org/eclipse/jetty/util/resource/Resource.java | 2 +-
.../eclipse/jetty/util/resource/URLResource.java | 2 +-
.../eclipse/jetty/websocket/api/util/WSURI.java | 2 +-
.../websocket/server/WebSocketUpgradeFilter.java | 2 +-
.../jetty/websocket/server/TooFastClientTest.java | 2 +-
.../tests/distribution/DistributionTester.java | 2 +-
79 files changed, 119 insertions(+), 119 deletions(-)
diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java
index b3975b1c4cb..3ff372e22ee 100644
--- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java
+++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java
@@ -173,7 +173,7 @@ public class TestSecurityAnnotationConversions
public void testMethodAnnotation() throws Exception
{
//ServletSecurity annotation with HttpConstraint of TransportGuarantee.CONFIDENTIAL, and a list of rolesAllowed, and
- //a HttpMethodConstraint for GET method that permits all and has TransportGuarantee.NONE (ie is default)
+ //an HttpMethodConstraint for GET method that permits all and has TransportGuarantee.NONE (ie is default)
WebAppContext wac = makeWebAppContext(Method1Servlet.class.getCanonicalName(), "method1Servlet", new String[]{
"/foo/*", "*.foo"
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java
index b75469f86cf..35b12c0c3f1 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java
@@ -28,7 +28,7 @@ import org.eclipse.jetty.io.ClientConnectionFactory;
* in order to plug-in a different transport for {@link HttpClient}.
*
* While the {@link HttpClient} APIs define the HTTP semantic (request, response, headers, etc.)
- * how a HTTP exchange is carried over the network depends on implementations of this class.
+ * how an HTTP exchange is carried over the network depends on implementations of this class.
*
* The default implementation uses the HTTP protocol to carry over the network the HTTP exchange,
* but the HTTP exchange may also be carried using the FCGI protocol, the HTTP/2 protocol or,
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java
index 4487033e5f6..17c8d3ab1bd 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java
@@ -32,7 +32,7 @@ import org.eclipse.jetty.util.log.Logger;
/**
* {@link HttpContent} is a stateful, linear representation of the request content provided
* by a {@link ContentProvider} that can be traversed one-way to obtain content buffers to
- * send to a HTTP server.
+ * send to an HTTP server.
*
* {@link HttpContent} offers the notion of a one-way cursor to traverse the content.
* The cursor starts in a virtual "before" position and can be advanced using {@link #advance()}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
index 1fba1fdf247..991768f1121 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
@@ -51,7 +51,7 @@ import org.eclipse.jetty.util.log.Logger;
*
* {@link #responseBegin(HttpExchange)}, when the HTTP response data containing the HTTP status code
* is available
- * {@link #responseHeader(HttpExchange, HttpField)}, when a HTTP field is available
+ * {@link #responseHeader(HttpExchange, HttpField)}, when an HTTP field is available
* {@link #responseHeaders(HttpExchange)}, when all HTTP headers are available
* {@link #responseContent(HttpExchange, ByteBuffer, Callback)}, when HTTP content is available
* {@link #responseSuccess(HttpExchange)}, when the response is successful
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java
index 4e6a6a0799c..565a092f64d 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java
@@ -82,7 +82,7 @@ public class HttpRedirector
/**
* @param response the response to check for redirects
- * @return whether the response code is a HTTP redirect code
+ * @return whether the response code is an HTTP redirect code
*/
public boolean isRedirect(Response response)
{
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
index dd26cbe8335..0ede8794655 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
@@ -869,7 +869,7 @@ public class HttpRequest implements Request
}
catch (URISyntaxException x)
{
- // The "path" of a HTTP request may not be a URI,
+ // The "path" of an HTTP request may not be a URI,
// for example for CONNECT 127.0.0.1:8080.
return null;
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
index a13c056595f..0442940df5e 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
@@ -40,7 +40,7 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.util.Fields;
/**
- * {@link Request} represents a HTTP request, and offers a fluent interface to customize
+ *
{@link Request} represents an HTTP request, and offers a fluent interface to customize
* various attributes such as the path, the headers, the content, etc.
* You can create {@link Request} objects via {@link HttpClient#newRequest(String)} and
* you can send them using either {@link #send()} for a blocking semantic, or
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
index a5874fbcad1..99d37164ddf 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
@@ -29,7 +29,7 @@ import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.util.Callback;
/**
- *
{@link Response} represents a HTTP response and offers methods to retrieve status code, HTTP version
+ *
{@link Response} represents an HTTP response and offers methods to retrieve status code, HTTP version
* and headers.
* {@link Response} objects are passed as parameters to {@link Response.Listener} callbacks, or as
* future result of {@link Request#send()}.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
index 1666a60278e..15e239eee06 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
@@ -161,7 +161,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
}
/**
- * Parses a HTTP response in the receivers buffer.
+ * Parses an HTTP response in the receivers buffer.
*
* @return true to indicate that parsing should be interrupted (and will be resumed by another thread).
*/
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java
index 9d22bd0ee9e..3c4b362a324 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java
@@ -494,7 +494,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest
.scheme(scenario.getScheme())
.onResponseBegin(response1 ->
{
- // Simulate a HTTP 1.0 response has been received.
+ // Simulate an HTTP 1.0 response has been received.
((HttpResponse)response1).version(HttpVersion.HTTP_1_0);
})
.send();
diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java
index c0104dbeecb..c5edaf09993 100644
--- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java
+++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java
@@ -26,7 +26,7 @@ import javax.servlet.ServletResponseWrapper;
/**
* Continuation.
*
- * A continuation is a mechanism by which a HTTP Request can be suspended and
+ * A continuation is a mechanism by which an HTTP Request can be suspended and
* restarted after a timeout or an asynchronous event has occurred.
*
* The continuation mechanism is a portable mechanism that will work
diff --git a/jetty-deploy/src/test/resources/jetty-http.xml b/jetty-deploy/src/test/resources/jetty-http.xml
index 57a4fb5567b..43ed57d5425 100644
--- a/jetty-deploy/src/test/resources/jetty-http.xml
+++ b/jetty-deploy/src/test/resources/jetty-http.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java
index 6b847cac9aa..42f82635caf 100644
--- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java
+++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java
@@ -44,7 +44,7 @@ import org.eclipse.jetty.util.ProcessorUtils;
/**
* Specific implementation of {@link org.eclipse.jetty.proxy.AsyncProxyServlet.Transparent} for FastCGI.
*
- * This servlet accepts a HTTP request and transforms it into a FastCGI request
+ * This servlet accepts an HTTP request and transforms it into a FastCGI request
* that is sent to the FastCGI server specified in the {@code proxyTo}
* init-param.
*
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
index 2379bcef99e..4b6128182fc 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
@@ -21,7 +21,7 @@ package org.eclipse.jetty.http;
import org.eclipse.jetty.util.HostPort;
/**
- * A HttpField holding a preparsed Host and port number
+ * An HttpField holding a preparsed Host and port number
*
* @see HostPort
*/
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
index 5f12147772f..db7bce9072b 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
@@ -23,7 +23,7 @@ import java.util.Objects;
import org.eclipse.jetty.util.StringUtil;
/**
- * A HTTP Field
+ * An HTTP Field
*/
public class HttpField
{
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
index 741be954df5..016f3dcbbee 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
@@ -48,7 +48,7 @@ public enum HttpMethod
* @param bytes Array containing ISO-8859-1 characters
* @param position The first valid index
* @param limit The first non valid index
- * @return A HttpMethod if a match or null if no easy match.
+ * @return An HttpMethod if a match or null if no easy match.
*/
public static HttpMethod lookAheadGet(byte[] bytes, final int position, int limit)
{
@@ -110,7 +110,7 @@ public enum HttpMethod
* Optimized lookup to find a method name and trailing space in a byte array.
*
* @param buffer buffer containing ISO-8859-1 characters, it is not modified.
- * @return A HttpMethod if a match or null if no easy match.
+ * @return An HttpMethod if a match or null if no easy match.
*/
public static HttpMethod lookAheadGet(ByteBuffer buffer)
{
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
index 7ebd682f667..435579c9df0 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
@@ -477,7 +477,7 @@ public class HttpParser
return t;
}
- /* Quick lookahead for the start state looking for a request method or a HTTP version,
+ /* Quick lookahead for the start state looking for a request method or an HTTP version,
* otherwise skip white space until something else to parse.
*/
private boolean quickStart(ByteBuffer buffer)
@@ -1873,14 +1873,14 @@ public class HttpParser
boolean messageComplete();
/**
- * This is the method called by parser when a HTTP Header name and value is found
+ * This is the method called by parser when an HTTP Header name and value is found
*
* @param field The field parsed
*/
void parsedHeader(HttpField field);
/**
- * This is the method called by parser when a HTTP Trailer name and value is found
+ * This is the method called by parser when an HTTP Trailer name and value is found
*
* @param field The field parsed
*/
@@ -1890,7 +1890,7 @@ public class HttpParser
/**
* Called to signal that an EOF was received unexpectedly
- * during the parsing of a HTTP message
+ * during the parsing of an HTTP message
*/
void earlyEOF();
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
index 5f5fec2636a..4fb2a36989e 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
@@ -31,7 +31,7 @@ import org.eclipse.jetty.util.UrlEncoded;
/**
* Http URI.
- * Parse a HTTP URI from a string or byte array. Given a URI
+ * Parse an HTTP URI from a string or byte array. Given a URI
* http://user@host:port/path/info;param?query#fragment
* this class will split it into the following undecoded optional elements:
* {@link #getScheme()} - http:
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java
index 762372ef5cc..12991ad105f 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java
@@ -42,12 +42,12 @@ public enum HttpVersion
}
/**
- * Optimised lookup to find a Http Version and whitespace in a byte array.
+ * Optimised lookup to find an Http Version and whitespace in a byte array.
*
* @param bytes Array containing ISO-8859-1 characters
* @param position The first valid index
* @param limit The first non valid index
- * @return A HttpMethod if a match or null if no easy match.
+ * @return An HttpMethod if a match or null if no easy match.
*/
public static HttpVersion lookAheadGet(byte[] bytes, int position, int limit)
{
@@ -84,10 +84,10 @@ public enum HttpVersion
}
/**
- * Optimised lookup to find a HTTP Version and trailing white space in a byte array.
+ * Optimised lookup to find an HTTP Version and trailing white space in a byte array.
*
* @param buffer buffer containing ISO-8859-1 characters
- * @return A HttpVersion if a match or null if no easy match.
+ * @return An HttpVersion if a match or null if no easy match.
*/
public static HttpVersion lookAheadGet(ByteBuffer buffer)
{
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java
index 35ec9a7cd40..cf9cf1c0752 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java
@@ -29,7 +29,7 @@ import org.eclipse.jetty.util.log.Logger;
/**
* Pre encoded HttpField.
- * A HttpField that will be cached and used many times can be created as
+ *
An HttpField that will be cached and used many times can be created as
* a {@link PreEncodedHttpField}, which will use the {@link HttpFieldPreEncoder}
* instances discovered by the {@link ServiceLoader} to pre-encode the header
* for each version of HTTP in use. This will save garbage
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java
index 27d494e3649..eee24e824be 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java
@@ -32,7 +32,7 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
- * A HTTP Testing helper class.
+ * An HTTP Testing helper class.
*
* Example usage:
*
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java
index a5a57fa2666..7eff31981e2 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java
@@ -170,7 +170,7 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
// and here we keep track of its max value.
// Updating the max session recv window is done here
- // so that if a peer decides to send an unilateral
+ // so that if a peer decides to send a unilateral
// window update to enlarge the session window,
// without the corresponding data consumption, here
// we can track it.
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 ac36211f847..4269bc67d1f 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
@@ -40,7 +40,7 @@ public enum ErrorCode
*/
INTERNAL_ERROR(2),
/**
- * Indicates a HTTP/2 flow control violation.
+ * Indicates an HTTP/2 flow control violation.
*/
FLOW_CONTROL_ERROR(3),
/**
@@ -68,7 +68,7 @@ public enum ErrorCode
*/
COMPRESSION_ERROR(9),
/**
- * Indicates that the connection established by a HTTP CONNECT was abnormally closed.
+ * Indicates that the connection established by an HTTP CONNECT was abnormally closed.
*/
HTTP_CONNECT_ERROR(10),
/**
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java
index 2e198fa5931..3df57d39b29 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java
@@ -30,7 +30,7 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
/**
- * The SPI interface for implementing a HTTP/2 session.
+ * The SPI interface for implementing an HTTP/2 session.
* This class extends {@link Session} by adding the methods required to
* implement the HTTP/2 session functionalities.
*/
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java
index c85e25b287f..144ed9190c6 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java
@@ -25,7 +25,7 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.util.Callback;
/**
- * The SPI interface for implementing a HTTP/2 stream.
+ * The SPI interface for implementing an HTTP/2 stream.
* This class extends {@link Stream} by adding the methods required to
* implement the HTTP/2 stream functionalities.
*/
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java
index 7c5472bd135..2ba0b3d78ed 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java
@@ -32,7 +32,7 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
/**
- * A {@link Session} represents the client-side endpoint of a HTTP/2 connection to a single origin server.
+ * A {@link Session} represents the client-side endpoint of an HTTP/2 connection to a single origin server.
* Once a {@link Session} has been obtained, it can be used to open HTTP/2 streams:
*
* Session session = ...;
@@ -127,7 +127,7 @@ public interface Session
/**
* A {@link Listener} is the passive counterpart of a {@link Session} and
- * receives events happening on a HTTP/2 connection.
+ * receives events happening on an HTTP/2 connection.
*
* @see Session
*/
@@ -151,9 +151,9 @@ public interface Session
/**
* Callback method invoked when a new stream is being created upon
- * receiving a HEADERS frame representing a HTTP request.
+ * receiving a HEADERS frame representing an HTTP request.
* Applications should implement this method to process HTTP requests,
- * typically providing a HTTP response via
+ * typically providing an HTTP response via
* {@link Stream#headers(HeadersFrame, Callback)}.
* Applications can detect whether request DATA frames will be arriving
* by testing {@link HeadersFrame#isEndStream()}. If the application is
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java
index 681c0870ff1..bb413d8d953 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java
@@ -29,8 +29,8 @@ import org.eclipse.jetty.util.Promise;
*
A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.
* Differently from socket streams, where the input and output streams are permanently associated
* with the socket (and hence with the connection that the socket represents), there can be multiple
- * HTTP/2 streams present concurrent for a HTTP/2 session.
- * A {@link Stream} maps to a HTTP request/response cycle, and after the request/response cycle is
+ * HTTP/2 streams present concurrent for an HTTP/2 session.
+ * A {@link Stream} maps to an HTTP request/response cycle, and after the request/response cycle is
* completed, the stream is closed and removed from the session.
* Like {@link Session}, {@link Stream} is the active part and by calling its API applications
* can generate events on the stream; conversely, {@link Stream.Listener} is the passive part, and
@@ -51,7 +51,7 @@ public interface Stream
Session getSession();
/**
- *
Sends the given HEADERS {@code frame} representing a HTTP response.
+ * Sends the given HEADERS {@code frame} representing an HTTP response.
*
* @param frame the HEADERS frame to send
* @param callback the callback that gets notified when the frame has been sent
@@ -131,7 +131,7 @@ public interface Stream
/**
* A {@link Stream.Listener} is the passive counterpart of a {@link Stream} and receives
- * events happening on a HTTP/2 stream.
+ * events happening on an HTTP/2 stream.
*
* @see Stream
*/
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java
index 3a6058878a4..741bba433a7 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java
@@ -42,7 +42,7 @@ public class PrefaceParser
* Advances this parser after the {@link PrefaceFrame#PREFACE_PREAMBLE_BYTES}.
* This allows the HTTP/1.1 parser to parse the preamble of the preface,
* which is a legal HTTP/1.1 request, and this parser will parse the remaining
- * bytes, that are not parseable by a HTTP/1.1 parser.
+ * bytes, that are not parseable by an HTTP/1.1 parser.
*/
protected void directUpgrade()
{
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 2e9e2cf725a..6e782a738b0 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
@@ -199,7 +199,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
.onRequestBegin(request ->
{
if (request.getVersion() != HttpVersion.HTTP_2)
- request.abort(new Exception("Not a HTTP/2 request"));
+ request.abort(new Exception("Not an HTTP/2 request"));
})
.send();
diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml
index 6ced1d68a20..56777719fdf 100644
--- a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml
+++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml
index b4cae9a549c..37cb745fe0e 100644
--- a/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml
+++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java
index cc0b9925311..4ed23cf2fea 100644
--- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java
@@ -39,8 +39,8 @@ import org.eclipse.jetty.util.log.Logger;
*
* If used in combination with a {@link HttpConnectionFactory} as the
* default protocol, this factory can support the non-standard direct
- * update mechanism, where a HTTP1 request of the form "PRI * HTTP/2.0"
- * is used to trigger a switch to a HTTP2 connection. This approach
+ * update mechanism, where an HTTP1 request of the form "PRI * HTTP/2.0"
+ * is used to trigger a switch to an HTTP2 connection. This approach
* allows a single port to accept either HTTP/1 or HTTP/2 direct
* connections.
*/
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
index 331696417d2..f8dfdbf7d36 100644
--- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
@@ -64,7 +64,7 @@ import org.eclipse.jetty.util.TypeUtil;
public class HTTP2ServerConnection extends HTTP2Connection implements Connection.UpgradeTo
{
/**
- * @param protocol A HTTP2 protocol variant
+ * @param protocol An HTTP2 protocol variant
* @return True if the protocol version is supported
*/
public static boolean isSupportedProtocol(String protocol)
diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java
index ed1fd6e948a..48552abebac 100644
--- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java
+++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java
@@ -188,7 +188,7 @@ public class HTTP2CServerTest extends AbstractServerTest
assertThat(content, containsString("Hello from Jetty using HTTP/1.1"));
assertThat(content, containsString("uri=/one"));
- // Send a HTTP/2 request.
+ // Send an HTTP/2 request.
headersRef.set(null);
dataRef.set(null);
latchRef.set(new CountDownLatch(2));
@@ -319,7 +319,7 @@ public class HTTP2CServerTest extends AbstractServerTest
connector.setDefaultProtocol(connectionFactory.getProtocol());
connector.start();
- // Now send a HTTP/2 direct request, which
+ // Now send an HTTP/2 direct request, which
// will have the PRI * HTTP/2.0 preface.
byteBufferPool = new MappedByteBufferPool();
@@ -336,7 +336,7 @@ public class HTTP2CServerTest extends AbstractServerTest
output.write(BufferUtil.toArray(buffer));
}
- // We sent a HTTP/2 preface, but the server has no "h2c" connection
+ // We sent an HTTP/2 preface, but the server has no "h2c" connection
// factory so it does not know how to handle this request.
InputStream input = client.getInputStream();
diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml
index 4e571ac750a..412e644a2e2 100644
--- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml
+++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml
index 1c820d39bbd..8e2360b85ca 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml
index b56a9762469..bccf90e1204 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml
index 2e79a92cc29..eab6f8936c8 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml
index 3f8f402579e..dca7d650b74 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml
index 00f8d58fd50..38b5a790496 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml
index f313e299e39..e6857ba7b89 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml
index d16c478cf2b..11c1650548d 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2-jdk9.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2-jdk9.xml
index 6ced1d68a20..56777719fdf 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2-jdk9.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2-jdk9.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml
index fbe3b2b4af0..5e85f018046 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml
index 8c6536074a1..30199cb8677 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/jetty-rewrite/src/test/resources/org.mortbay.jetty.rewrite.handler/jetty-rewrite.xml b/jetty-rewrite/src/test/resources/org.mortbay.jetty.rewrite.handler/jetty-rewrite.xml
index cf4c4e65bcd..fa6bc790c4f 100644
--- a/jetty-rewrite/src/test/resources/org.mortbay.jetty.rewrite.handler/jetty-rewrite.xml
+++ b/jetty-rewrite/src/test/resources/org.mortbay.jetty.rewrite.handler/jetty-rewrite.xml
@@ -40,7 +40,7 @@
-
+
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConfigurableSpnegoLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConfigurableSpnegoLoginService.java
index 8b8724d642c..4b93b7e7ca6 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConfigurableSpnegoLoginService.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConfigurableSpnegoLoginService.java
@@ -51,7 +51,7 @@ import org.ietf.jgss.Oid;
* of the {@link #getServiceName() service name} and the {@link #getHostName() host name},
* for example {@code HTTP/wonder.com}, using a {@code keyTab} file as the service principal
* credentials.
- * Upon receiving a HTTP request, the server tries to authenticate the client
+ *
Upon receiving an HTTP request, the server tries to authenticate the client
* calling {@link #login(String, Object, ServletRequest)} where the GSS APIs are used to
* verify client tokens and (perhaps after a few round-trips) a {@code GSSContext} is
* established.
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
index 6a50ecd8c29..e6224c102cb 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
@@ -806,7 +806,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
{
//an exact method name
if (!hasOmissions)
- //a http-method does not have http-method-omission to cover the other method names
+ //an http-method does not have http-method-omission to cover the other method names
uncoveredPaths.add(path);
}
}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java
index 1a672615e96..1a6de7a1874 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java
@@ -39,7 +39,7 @@ import org.eclipse.jetty.util.log.Logger;
*
* When a user has been successfully authenticated with some types
* of Authenticator, the Authenticator stashes a SessionAuthentication
- * into a HttpSession to remember that the user is authenticated.
+ * into an HttpSession to remember that the user is authenticated.
*/
public class SessionAuthentication extends AbstractUserAuthentication
implements Serializable, HttpSessionActivationListener, HttpSessionBindingListener
diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java
index 67140ff6d70..ffefdea617e 100644
--- a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java
+++ b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java
@@ -423,7 +423,7 @@ public class ConstraintTest
assertEquals(1, uncoveredPaths.size());
assertThat("/user/*", is(in(uncoveredPaths)));
- //Test an explicitly named method with a http-method-omission to cover all other methods
+ //Test an explicitly named method with an http-method-omission to cover all other methods
Constraint constraint2a = new Constraint();
constraint2a.setAuthenticate(true);
constraint2a.setName("forbid constraint");
@@ -437,7 +437,7 @@ public class ConstraintTest
assertNotNull(uncoveredPaths);
assertEquals(0, uncoveredPaths.size());
- //Test a http-method-omission only
+ //Test an http-method-omission only
Constraint constraint3 = new Constraint();
constraint3.setAuthenticate(true);
constraint3.setName("omit constraint");
diff --git a/jetty-server/src/main/config/etc/jetty-http.xml b/jetty-server/src/main/config/etc/jetty-http.xml
index 13b74d5be96..e93bb68dfc1 100644
--- a/jetty-server/src/main/config/etc/jetty-http.xml
+++ b/jetty-server/src/main/config/etc/jetty-http.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/jetty-server/src/main/config/etc/jetty-https.xml b/jetty-server/src/main/config/etc/jetty-https.xml
index 35bb3a6baaf..99abd18df59 100644
--- a/jetty-server/src/main/config/etc/jetty-https.xml
+++ b/jetty-server/src/main/config/etc/jetty-https.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/jetty-server/src/main/config/modules/http.mod b/jetty-server/src/main/config/modules/http.mod
index 430d8519e2e..7c20880043f 100644
--- a/jetty-server/src/main/config/modules/http.mod
+++ b/jetty-server/src/main/config/modules/http.mod
@@ -1,7 +1,7 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
-Enables a HTTP connector on the server.
+Enables an HTTP connector on the server.
By default HTTP/1 is support, but HTTP2C can
be added to the connector with the http2c module.
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
index f1425dde301..1723bcc73df 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
@@ -116,7 +116,7 @@ import org.eclipse.jetty.util.thread.ThreadPoolBudget;
* {@link ConnectionFactory}s may also create temporary {@link org.eclipse.jetty.io.Connection} instances that will exchange bytes
* over the connection to determine what is the next protocol to use. For example the ALPN protocol is an extension
* of SSL to allow a protocol to be specified during the SSL handshake. ALPN is used by the HTTP/2 protocol to
- * negotiate the protocol that the client and server will speak. Thus to accept a HTTP/2 connection, the
+ * negotiate the protocol that the client and server will speak. Thus to accept an HTTP/2 connection, the
* connector will be configured with {@link ConnectionFactory}s for "SSL-ALPN", "h2", "http/1.1"
* with the default protocol being "SSL-ALPN". Thus a newly accepted connection uses "SSL-ALPN", which specifies a
* SSLConnectionFactory with "ALPN" as the next protocol. Thus an SSL connection instance is created chained to an ALPN
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectionFactory.java
index 9a24133b1a5..377947ca7fd 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectionFactory.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectionFactory.java
@@ -35,11 +35,11 @@ import org.eclipse.jetty.io.EndPoint;
* A ConnectionFactory has a protocol name that represents the protocol of the Connections
* created. Example of protocol names include:
*
- * http Creates a HTTP connection that can handle multiple versions of HTTP from 0.9 to 1.1
- * h2 Creates a HTTP/2 connection that handles the HTTP/2 protocol
+ * http Creates an HTTP connection that can handle multiple versions of HTTP from 0.9 to 1.1
+ * h2 Creates an HTTP/2 connection that handles the HTTP/2 protocol
* SSL-XYZ Create an SSL connection chained to a connection obtained from a connection factory
* with a protocol "XYZ".
- * SSL-http Create an SSL connection chained to a HTTP connection (aka https)
+ * SSL-http Create an SSL connection chained to an HTTP connection (aka https)
* SSL-ALPN Create an SSL connection chained to a ALPN connection, that uses a negotiation with
* the client to determine the next protocol.
*
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
index 38760aadac4..e48d6f22156 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
@@ -61,7 +61,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
/**
* HttpChannel represents a single endpoint for HTTP semantic processing.
- * The HttpChannel is both a HttpParser.RequestHandler, where it passively receives events from
+ * The HttpChannel is both an HttpParser.RequestHandler, where it passively receives events from
* an incoming HTTP request, and a Runnable, where it actively takes control of the request/response
* life cycle and calls the application (perhaps suspending and resuming with multiple calls to run).
* The HttpChannel signals the switch from passive mode to active mode by returning true to one of the
@@ -1016,7 +1016,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
/**
* Listener for {@link HttpChannel} events.
* HttpChannel will emit events for the various phases it goes through while
- * processing a HTTP request and response.
+ * processing an HTTP request and response.
* Implementations of this interface may listen to those events to track
* timing and/or other values such as request URI, etc.
* The events parameters, especially the {@link Request} object, may be
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java
index b4e88f029ee..3d12c04f1eb 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java
@@ -44,7 +44,7 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
- * A HttpChannel customized to be transported over the HTTP/1 protocol
+ * An HttpChannel customized to be transported over the HTTP/1 protocol
*/
public class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandler, HttpParser.ComplianceHandler
{
@@ -411,7 +411,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque
}
/**
- *
Attempts to perform a HTTP/1.1 upgrade.
+ * Attempts to perform an HTTP/1.1 upgrade.
* The upgrade looks up a {@link ConnectionFactory.Upgrading} from the connector
* matching the protocol specified in the {@code Upgrade} header.
* The upgrade may succeed, be ignored (which can allow a later handler to implement)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
index 9aa9b62fcc8..e5bd93fde16 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
@@ -39,7 +39,7 @@ import org.eclipse.jetty.util.log.Logger;
/**
* HTTP Configuration.
*
This class is a holder of HTTP configuration for use by the
- * {@link HttpChannel} class. Typically a HTTPConfiguration instance
+ * {@link HttpChannel} class. Typically an HTTPConfiguration instance
* is instantiated and passed to a {@link ConnectionFactory} that can
* create HTTP channels (e.g. HTTP, AJP or FCGI).
* The configuration held by this class is not for the wire protocol,
@@ -184,19 +184,19 @@ public class HttpConfiguration implements Dumpable
return _outputAggregationSize;
}
- @ManagedAttribute("The maximum allowed size in bytes for a HTTP request header")
+ @ManagedAttribute("The maximum allowed size in bytes for an HTTP request header")
public int getRequestHeaderSize()
{
return _requestHeaderSize;
}
- @ManagedAttribute("The maximum allowed size in bytes for a HTTP response header")
+ @ManagedAttribute("The maximum allowed size in bytes for an HTTP response header")
public int getResponseHeaderSize()
{
return _responseHeaderSize;
}
- @ManagedAttribute("The maximum allowed size in bytes for a HTTP header field cache")
+ @ManagedAttribute("The maximum allowed size in bytes for an HTTP header field cache")
public int getHeaderCacheSize()
{
return _headerCacheSize;
@@ -221,20 +221,20 @@ public class HttpConfiguration implements Dumpable
}
/**
- *
The max idle time is applied to a HTTP request for IO operations and
+ *
The max idle time is applied to an HTTP request for IO operations and
* delayed dispatch.
*
* @return the max idle time in ms or if == 0 implies an infinite timeout, <0
* implies no HTTP channel timeout and the connection timeout is used instead.
*/
- @ManagedAttribute("The idle timeout in ms for I/O operations during the handling of a HTTP request")
+ @ManagedAttribute("The idle timeout in ms for I/O operations during the handling of an HTTP request")
public long getIdleTimeout()
{
return _idleTimeout;
}
/**
- * The max idle time is applied to a HTTP request for IO operations and
+ *
The max idle time is applied to an HTTP request for IO operations and
* delayed dispatch.
*
* @param timeoutMs the max idle time in ms or if == 0 implies an infinite timeout, <0
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java
index 71b40c0fa82..41118eb081d 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java
@@ -95,7 +95,7 @@ public class OptionalSslConnectionFactory extends AbstractConnectionFactory
int byte2 = buffer.get(1) & 0xFF;
if (byte1 == 'G' && byte2 == 'E')
{
- // Plain text HTTP to a HTTPS port,
+ // Plain text HTTP to an HTTPS port,
// write a minimal response.
String body =
"\r\n" +
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java
index 95a9d83e533..b6d58845de1 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java
@@ -32,7 +32,7 @@ import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
/**
- * A HttpContent.Factory for transient content (not cached). The HttpContent's created by
+ * An HttpContent.Factory for transient content (not cached). The HttpContent's created by
* this factory are not intended to be cached, so memory limits for individual
* HttpOutput streams are enforced.
*/
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
index 04870c50949..1ef97d7286e 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
@@ -410,7 +410,7 @@ public class Response implements HttpServletResponse
/**
* Sends a 102-Processing response.
- * If the connection is a HTTP connection, the version is 1.1 and the
+ * If the connection is an HTTP connection, the version is 1.1 and the
* request has a Expect header starting with 102, then a 102 response is
* sent. This indicates that the request still be processed and real response
* can still be sent. This method is called by sendError if it is passed 102.
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java
index c754a656694..87c6b753317 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java
@@ -35,7 +35,7 @@ import javax.servlet.http.Part;
/**
* ServletRequestHttpWrapper
*
- * Class to tunnel a ServletRequest via a HttpServletRequest
+ * Class to tunnel a ServletRequest via an HttpServletRequest
*/
public class ServletRequestHttpWrapper extends ServletRequestWrapper implements HttpServletRequest
{
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java
index e3499962918..ff01136cc9c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java
@@ -28,7 +28,7 @@ import javax.servlet.http.HttpServletResponse;
/**
* ServletResponseHttpWrapper
*
- * Wrapper to tunnel a ServletResponse via a HttpServletResponse
+ * Wrapper to tunnel a ServletResponse via an HttpServletResponse
*/
public class ServletResponseHttpWrapper extends ServletResponseWrapper implements HttpServletResponse
{
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
index 14700779b34..c46b31e342c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
@@ -50,7 +50,7 @@ import org.eclipse.jetty.util.log.Logger;
* Handler for Error pages
* An ErrorHandler is registered with {@link ContextHandler#setErrorHandler(ErrorHandler)} or
* {@link Server#setErrorHandler(ErrorHandler)}.
- * It is called by the HttpResponse.sendError method to write a error page via {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)}
+ * It is called by the HttpResponse.sendError method to write an error page via {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)}
* or via {@link #badMessageError(int, String, HttpFields)} for bad requests for which a dispatch cannot be done.
*/
public class ErrorHandler extends AbstractHandler
@@ -467,7 +467,7 @@ public class ErrorHandler extends AbstractHandler
/**
* Bad Message Error body
- * Generate a error response body to be sent for a bad message.
+ *
Generate an error response body to be sent for a bad message.
* In this case there is something wrong with the request, so either
* a request cannot be built, or it is not safe to build a request.
* This method allows for a simple error page body to be returned
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java
index ed5affa51c9..4665db27c89 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java
@@ -38,7 +38,7 @@ import org.eclipse.jetty.util.log.Logger;
* A handler that shuts the server down on a valid request. Used to do "soft" restarts from Java.
* If _exitJvm is set to true a hard System.exit() call is being made.
* If _sendShutdownAtStart is set to true, starting the server will try to shut down an existing server at the same port.
- * If _sendShutdownAtStart is set to true, make a http call to
+ * If _sendShutdownAtStart is set to true, make an http call to
* "http://localhost:" + port + "/shutdown?token=" + shutdownCookie
* in order to shut down the server.
*
@@ -100,7 +100,7 @@ public class ShutdownHandler extends HandlerWrapper
/**
* @param shutdownToken a secret password to avoid unauthorized shutdown attempts
* @param exitJVM If true, when the shutdown is executed, the handler class System.exit()
- * @param sendShutdownAtStart If true, a shutdown is sent as a HTTP post
+ * @param sendShutdownAtStart If true, a shutdown is sent as an HTTP post
* during startup, which will shutdown any previously running instances of
* this server with an identically configured ShutdownHandler
*/
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java
index 9fedb2b3938..c099e09abfd 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java
@@ -27,7 +27,7 @@ import org.eclipse.jetty.server.HttpInput.Content;
import org.eclipse.jetty.util.component.Destroyable;
/**
- * A HttpInput Interceptor that inflates GZIP encoded request content.
+ * An HttpInput Interceptor that inflates GZIP encoded request content.
*/
public class GzipHttpInputInterceptor implements HttpInput.Interceptor, Destroyable
{
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
index a14d5f5ab53..76d146b2ea3 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
@@ -42,7 +42,7 @@ import org.eclipse.jetty.util.thread.Locker.Lock;
/**
* Session
*
- * A heavy-weight Session object representing a HttpSession. Session objects
+ * A heavy-weight Session object representing an HttpSession. Session objects
* relating to a context are kept in a {@link SessionCache}. The purpose of the
* SessionCache is to keep the working set of Session objects in memory so that
* they may be accessed quickly, and facilitate the sharing of a Session object
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java
index 89857621904..7c958c465eb 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java
@@ -555,7 +555,7 @@ public class SessionHandler extends ScopedHandler
/**
* @return same as SessionCookieConfig.getSecure(). If true, session
* cookies are ALWAYS marked as secure. If false, a session cookie is
- * ONLY marked as secure if _secureRequestOnly == true and it is a HTTPS request.
+ * ONLY marked as secure if _secureRequestOnly == true and it is an HTTPS request.
*/
@ManagedAttribute("if true, secure cookie flag is set on session cookies")
public boolean getSecureCookies()
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java
index a145c2c2782..15b31826bf5 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java
@@ -362,7 +362,7 @@ public class ThreadStarvationTest
byte[] content = new byte[BUFFER_SIZE];
{
- // Using a character that will not show up in a HTTP response header
+ // Using a character that will not show up in an HTTP response header
Arrays.fill(content, (byte)'!');
}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestURITest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestURITest.java
index adbb8abd27f..2f0195fa494 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestURITest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestURITest.java
@@ -196,7 +196,7 @@ public class RequestURITest
// Read the response.
String response = readResponse(client);
- // TODO: is HTTP/1.1 response appropriate for a HTTP/1.0 request?
+ // TODO: is HTTP/1.1 response appropriate for an HTTP/1.0 request?
assertThat(response, Matchers.containsString("HTTP/1.1 200 OK"));
assertThat(response, Matchers.containsString("RequestURI: " + expectedReqUri));
assertThat(response, Matchers.containsString("QueryString: " + expectedQuery));
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java
index d15f57dc3cc..45aa1b99637 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java
@@ -489,7 +489,7 @@ public class DoSFilter implements Filter
/**
* Invoked when the request handling exceeds {@link #getMaxRequestMs()}.
*
- * By default, a HTTP 503 response is returned and the handling thread is interrupted.
+ * By default, an HTTP 503 response is returned and the handling thread is interrupted.
*
* @param request the current request
* @param response the current response
diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod
index e8f17427237..8d33f657fef 100644
--- a/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod
+++ b/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod
@@ -1,7 +1,7 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
-Adds a HTTP protocol support to the Unix Domain Socket connector.
+Adds an HTTP protocol support to the Unix Domain Socket connector.
It should be used when a proxy is forwarding either HTTP or decrypted
HTTPS traffic to the connector and may be used with the
unix-socket-http2c modules to upgrade to HTTP/2.
diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod
index 7de5cb019fb..f351a7a8849 100644
--- a/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod
+++ b/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod
@@ -1,7 +1,7 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
-Adds a HTTP2C connetion factory to the Unix Domain Socket Connector
+Adds an HTTP2C connetion factory to the Unix Domain Socket Connector
It can be used when either the proxy forwards direct
HTTP/2C (unecrypted) or decrypted HTTP/2 traffic.
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
index b59b015fdfc..5cebbb37bf5 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
@@ -367,7 +367,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/**
* URL representing the resource.
*
- * @return an URL representing the given resource
+ * @return a URL representing the given resource
* @deprecated use {{@link #getURI()}.toURL() instead.
*/
@Deprecated
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java
index cc4916cac76..66c6734df8b 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java
@@ -151,7 +151,7 @@ public class URLResource extends Resource
}
/**
- * Returns an URL representing the given resource
+ * Returns a URL representing the given resource
*/
@Override
public URL getURL()
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java
index e48a2de056b..f8840f032da 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java
@@ -25,7 +25,7 @@ import java.util.Objects;
// @checkstyle-disable-check : AbbreviationAsWordInNameCheck
/**
- * Utility methods for converting a {@link URI} between a HTTP(S) and WS(S) URI.
+ * Utility methods for converting a {@link URI} between an HTTP(S) and WS(S) URI.
*/
public final class WSURI
{
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java
index de55c297274..20a16f4f9ba 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java
@@ -275,7 +275,7 @@ public class WebSocketUpgradeFilter implements Filter, MappedWebSocketCreator, D
// We are in some kind of funky non-http environment.
if (LOG.isDebugEnabled())
{
- LOG.debug("Not a HttpServletRequest, skipping WebSocketUpgradeFilter");
+ LOG.debug("Not an HttpServletRequest, skipping WebSocketUpgradeFilter");
}
}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/TooFastClientTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/TooFastClientTest.java
index 4077e0f27c8..167e30445fa 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/TooFastClientTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/TooFastClientTest.java
@@ -127,7 +127,7 @@ public class TooFastClientTest
}
/**
- * Test where were a client sends a HTTP Upgrade to websocket AND enough websocket frame(s)
+ * Test where were a client sends an HTTP Upgrade to websocket AND enough websocket frame(s)
* to completely overfill the {@link org.eclipse.jetty.io.AbstractConnection#getInputBufferSize()}
* to test a situation where the WebSocket connection opens with prefill that exceeds
* the normal input buffer sizes.
diff --git a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java
index 2b9178e20b1..13960cfa783 100644
--- a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java
+++ b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java
@@ -97,7 +97,7 @@ import org.eclipse.jetty.util.log.Logger;
* // Wait for Jetty to be fully started.
* assertTrue(run1.awaitConsoleLogsFor("Started @", 20, TimeUnit.SECONDS));
*
- * // Make a HTTP request to the web application.
+ * // Make an HTTP request to the web application.
* HttpClient client = new HttpClient();
* client.start();
* ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp");