Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12.1.x

This commit is contained in:
Jan Bartel 2024-05-28 10:23:00 +10:00
commit 810eccaeea
85 changed files with 781 additions and 635 deletions

View File

@ -12,8 +12,8 @@
<name>Documentation :: Content Root</name>
<properties>
<!-- build cache must be skipped for antora goal to work and for run.jetty.classpath value to be computed properly -->
<maven.build.cache.skipCache>true</maven.build.cache.skipCache>
<!-- build cache must be disabled for antora goal to work and for run.jetty.classpath value to be computed properly -->
<maven.build.cache.enabled>false</maven.build.cache.enabled>
</properties>
<build>

View File

@ -147,24 +147,19 @@ public interface Response
* Callback method invoked when the response content has been received, parsed and there is demand.
* This method may be invoked multiple times, and the {@code content} buffer
* must be consumed (or copied) before returning from this method.
* This method is also always invoked when content arrives as demand is automatically registered on return.
*
* @param response the response containing the response line data and the headers
* @param content the content bytes received
* @throws Exception an uncaught exception will abort the response and eventually reclaim the ByteBuffer, if applicable
*/
void onContent(Response response, ByteBuffer content);
void onContent(Response response, ByteBuffer content) throws Exception;
@Override
default void onContent(Response response, Content.Chunk chunk, Runnable demander)
default void onContent(Response response, Content.Chunk chunk, Runnable demander) throws Exception
{
try
{
onContent(response, chunk.getByteBuffer());
demander.run();
}
catch (Throwable x)
{
response.abort(x);
}
onContent(response, chunk.getByteBuffer());
demander.run();
}
}
@ -175,7 +170,19 @@ public interface Response
*/
interface AsyncContentListener extends ContentSourceListener
{
void onContent(Response response, Content.Chunk chunk, Runnable demander);
/**
* Callback method invoked when the response content has been received, parsed and there is demand.
* The {@code chunk} must be consumed, copied, or retained before returning from this method as
* it is then automatically released.
* The {@code demander} must be run before this method may be invoked again.
*
* @param response the response containing the response line data and the headers
* @param chunk the chunk received
* @param demander the runnable to be run to demand the next chunk
* @throws Exception an uncaught exception will abort the response, release the chunk and fail the content source
* from which the chunk was read from
*/
void onContent(Response response, Content.Chunk chunk, Runnable demander) throws Exception;
@Override
default void onContentSource(Response response, Content.Source contentSource)

View File

@ -33,6 +33,31 @@ import static org.hamcrest.Matchers.is;
public class AsyncContentListenerTest
{
@Test
public void testOnContentThrowingException()
{
TestSource originalSource = new TestSource(
Content.Chunk.from(ByteBuffer.wrap(new byte[] {1}), false),
Content.Chunk.from(ByteBuffer.wrap(new byte[] {2}), false),
Content.Chunk.from(ByteBuffer.wrap(new byte[] {3}), true)
);
Response.AsyncContentListener asyncContentListener = (response, chunk, demander) ->
{
throw new NumberFormatException();
};
HttpResponse response = new HttpResponse(new HttpRequest(new HttpClient(), new HttpConversation(), URI.create("http://localhost")));
asyncContentListener.onContentSource(response, originalSource);
// Assert that the source was failed.
Content.Chunk lastChunk = originalSource.read();
assertThat(Content.Chunk.isFailure(lastChunk, true), is(true));
assertThat(lastChunk.getFailure(), instanceOf(NumberFormatException.class));
// Assert that the response was aborted.
assertThat(response.getRequest().getAbortCause(), instanceOf(NumberFormatException.class));
}
@Test
public void testTransientFailureBecomesTerminal()
{
@ -70,7 +95,7 @@ public class AsyncContentListenerTest
originalSource.close();
}
private static class TestSource extends ChunksContentSource implements Closeable
static class TestSource extends ChunksContentSource implements Closeable
{
private Content.Chunk[] chunks;

View File

@ -0,0 +1,56 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.client;
import java.net.URI;
import java.nio.ByteBuffer;
import org.eclipse.jetty.client.AsyncContentListenerTest.TestSource;
import org.eclipse.jetty.client.transport.HttpConversation;
import org.eclipse.jetty.client.transport.HttpRequest;
import org.eclipse.jetty.client.transport.HttpResponse;
import org.eclipse.jetty.io.Content;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
public class ContentListenerTest
{
@Test
public void testOnContentThrowingException()
{
TestSource originalSource = new TestSource(
Content.Chunk.from(ByteBuffer.wrap(new byte[] {1}), false),
Content.Chunk.from(ByteBuffer.wrap(new byte[] {2}), false),
Content.Chunk.from(ByteBuffer.wrap(new byte[] {3}), true)
);
Response.ContentListener contentListener = (response, content) ->
{
throw new NumberFormatException();
};
HttpResponse response = new HttpResponse(new HttpRequest(new HttpClient(), new HttpConversation(), URI.create("http://localhost")));
contentListener.onContentSource(response, originalSource);
// Assert that the source was failed.
Content.Chunk lastChunk = originalSource.read();
assertThat(Content.Chunk.isFailure(lastChunk, true), is(true));
assertThat(lastChunk.getFailure(), instanceOf(NumberFormatException.class));
// Assert that the response was aborted.
assertThat(response.getRequest().getAbortCause(), instanceOf(NumberFormatException.class));
}
}

View File

@ -15,7 +15,7 @@ module org.eclipse.jetty.deploy
{
requires java.xml;
requires org.eclipse.jetty.xml;
requires org.eclipse.jetty.server;
requires transitive org.eclipse.jetty.server;
requires org.slf4j;
// Only required if using JMX.

View File

@ -11,6 +11,9 @@
// ========================================================================
//
import com.sun.net.httpserver.spi.HttpServerProvider;
import org.eclipse.jetty.http.spi.JettyHttpServerProvider;
module org.eclipse.jetty.http.spi
{
requires transitive jdk.httpserver;
@ -19,4 +22,6 @@ module org.eclipse.jetty.http.spi
requires transitive org.eclipse.jetty.util;
exports org.eclipse.jetty.http.spi;
}
provides HttpServerProvider with JettyHttpServerProvider;
}

View File

@ -21,8 +21,6 @@ import java.util.ListIterator;
import java.util.Map;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Cookie parser
@ -31,9 +29,8 @@ import org.slf4j.LoggerFactory;
@Deprecated (forRemoval = true)
public class CookieCache implements CookieParser.Handler, ComplianceViolation.Listener
{
protected static final Logger LOG = LoggerFactory.getLogger(CookieCache.class);
protected final List<String> _rawFields = new ArrayList<>();
protected List<HttpCookie> _cookieList;
private final List<String> _rawFields = new ArrayList<>();
private List<HttpCookie> _cookieList;
private final CookieParser _parser;
private List<ComplianceViolation.Event> _violations;

View File

@ -33,7 +33,7 @@ import static org.eclipse.jetty.http.CookieCompliance.Violation.SPECIAL_CHARS_IN
@Deprecated
public class CookieCutter implements CookieParser
{
protected static final Logger LOG = LoggerFactory.getLogger(CookieCutter.class);
private static final Logger LOG = LoggerFactory.getLogger(CookieCutter.class);
private final CookieParser.Handler _handler;
private final CookieCompliance _complianceMode;

View File

@ -13,6 +13,7 @@
package org.eclipse.jetty.http;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
@ -24,6 +25,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
@ -596,7 +598,41 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
*/
default Set<String> getFieldNamesCollection()
{
return stream().map(HttpField::getName).collect(Collectors.toSet());
Set<HttpHeader> seenByHeader = EnumSet.noneOf(HttpHeader.class);
Set<String> seenByName = null;
List<String> list = new ArrayList<>(size());
for (HttpField f : this)
{
HttpHeader header = f.getHeader();
if (header == null)
{
if (seenByName == null)
seenByName = new TreeSet<>(String::compareToIgnoreCase);
if (seenByName.add(f.getName()))
list.add(f.getName());
}
else if (seenByHeader.add(header))
{
list.add(f.getName());
}
}
// use the list to retain a rough ordering
return new AbstractSet<>()
{
@Override
public Iterator<String> iterator()
{
return list.iterator();
}
@Override
public int size()
{
return list.size();
}
};
}
/**

View File

@ -92,7 +92,7 @@ import static org.eclipse.jetty.http.HttpTokens.LINE_FEED;
*/
public class HttpParser
{
public static final Logger LOG = LoggerFactory.getLogger(HttpParser.class);
private static final Logger LOG = LoggerFactory.getLogger(HttpParser.class);
public static final int INITIAL_URI_LENGTH = 256;
private static final int MAX_CHUNK_LENGTH = Integer.MAX_VALUE / 16 - 16;
private static final String UNMATCHED_VALUE = "\u0000";

View File

@ -16,8 +16,6 @@ package org.eclipse.jetty.http;
import java.util.Locale;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.eclipse.jetty.http.CookieCompliance.Violation.ATTRIBUTES;
import static org.eclipse.jetty.http.CookieCompliance.Violation.ATTRIBUTE_VALUES;
@ -34,8 +32,6 @@ import static org.eclipse.jetty.http.CookieCompliance.Violation.SPECIAL_CHARS_IN
*/
public class RFC6265CookieParser implements CookieParser
{
protected static final Logger LOG = LoggerFactory.getLogger(RFC6265CookieParser.class);
private final CookieParser.Handler _handler;
private final CookieCompliance _complianceMode;
private final ComplianceViolation.Listener _complianceListener;

View File

@ -335,6 +335,47 @@ public class HttpFieldsTest
assertThrows(NoSuchElementException.class, () -> header.getField(2));
}
@Test
public void testCaseInsensitive()
{
HttpFields header = HttpFields.build()
.add("expect", "100")
.add("RaNdOm", "value")
.add("Accept-Charset", "UTF-8")
.add("accept-charset", "UTF-16")
.add("foo-bar", "one")
.add("Foo-Bar", "two")
.asImmutable();
assertThat(header.get("expect"), is("100"));
assertThat(header.get("Expect"), is("100"));
assertThat(header.get("EXPECT"), is("100"));
assertThat(header.get("eXpEcT"), is("100"));
assertThat(header.get(HttpHeader.EXPECT), is("100"));
assertThat(header.get("random"), is("value"));
assertThat(header.get("Random"), is("value"));
assertThat(header.get("RANDOM"), is("value"));
assertThat(header.get("rAnDoM"), is("value"));
assertThat(header.get("RaNdOm"), is("value"));
assertThat(header.get("Accept-Charset"), is("UTF-8"));
assertThat(header.get("accept-charset"), is("UTF-8"));
assertThat(header.get(HttpHeader.ACCEPT_CHARSET), is("UTF-8"));
assertThat(header.getValuesList("Accept-Charset"), contains("UTF-8", "UTF-16"));
assertThat(header.getValuesList("accept-charset"), contains("UTF-8", "UTF-16"));
assertThat(header.getValuesList(HttpHeader.ACCEPT_CHARSET), contains("UTF-8", "UTF-16"));
assertThat(header.get("foo-bar"), is("one"));
assertThat(header.get("Foo-Bar"), is("one"));
assertThat(header.getValuesList("foo-bar"), contains("one", "two"));
assertThat(header.getValuesList("Foo-Bar"), contains("one", "two"));
// We know the order of the set is deterministic
assertThat(header.getFieldNamesCollection(), contains("expect", "RaNdOm", "Accept-Charset", "foo-bar"));
}
@ParameterizedTest
@MethodSource("mutables")
public void testGetKnown(HttpFields.Mutable header)

View File

@ -72,7 +72,7 @@ public class ChunkAccumulator
public byte[] take()
{
if (_length == 0)
return BufferUtil.EMPTY_BUFFER.array();
return BufferUtil.EMPTY_BYTES;
byte[] bytes = new byte[_length];
int offset = 0;
for (Chunk chunk : _chunks)

View File

@ -53,7 +53,7 @@ import org.slf4j.LoggerFactory;
public abstract class SelectorManager extends ContainerLifeCycle implements Dumpable
{
public static final int DEFAULT_CONNECT_TIMEOUT = 15000;
protected static final Logger LOG = LoggerFactory.getLogger(SelectorManager.class);
private static final Logger LOG = LoggerFactory.getLogger(SelectorManager.class);
private final Executor executor;
private final Scheduler scheduler;

View File

@ -13,13 +13,13 @@
module org.eclipse.jetty.plus
{
requires org.eclipse.jetty.security;
requires transitive org.eclipse.jetty.security;
requires org.eclipse.jetty.util;
requires org.slf4j;
requires transitive java.naming;
// Only required if using DataSourceLoginService.
requires static java.sql;
requires static transitive java.sql;
exports org.eclipse.jetty.plus.annotation;
exports org.eclipse.jetty.plus.jndi;

View File

@ -17,7 +17,7 @@ module org.eclipse.jetty.security
requires transitive org.eclipse.jetty.util;
requires transitive org.slf4j;
requires static java.security.jgss;
requires static java.sql;
requires static transitive java.sql;
exports org.eclipse.jetty.security;
exports org.eclipse.jetty.security.authentication;

View File

@ -251,7 +251,7 @@ public class HttpConnectionTest
@MethodSource("contentLengths")
public void testHttp11MultipleContentLength(int[] clen) throws Exception
{
HttpParser.LOG.info("badMessage: 400 Bad messages EXPECTED...");
LOG.info("badMessage: 400 Bad messages EXPECTED...");
StringBuilder request = new StringBuilder();
request.append("POST / HTTP/1.1\r\n");
request.append("Host: local\r\n");
@ -298,7 +298,7 @@ public class HttpConnectionTest
@MethodSource("http11ContentLengthAndChunkedData")
public void testHttp11ContentLengthAndChunk(int[] contentLengths) throws Exception
{
HttpParser.LOG.info("badMessage: 400 Bad messages EXPECTED...");
LOG.info("badMessage: 400 Bad messages EXPECTED...");
StringBuilder request = new StringBuilder();
request.append("POST / HTTP/1.1\r\n");
@ -405,7 +405,7 @@ public class HttpConnectionTest
@MethodSource("http11TransferEncodingInvalidChunked")
public void testHttp11TransferEncodingInvalidChunked(List<String> tokens) throws Exception
{
HttpParser.LOG.info("badMessage: 400 Bad messages EXPECTED...");
LOG.info("badMessage: 400 Bad messages EXPECTED...");
StringBuilder request = new StringBuilder();
request.append("POST / HTTP/1.1\r\n");
request.append("Host: local\r\n");

View File

@ -18,7 +18,7 @@ module org.eclipse.jetty.session
requires transitive org.slf4j;
// Only required if using DatabaseAdaptor/JDBCSessionDataStore.
requires static java.sql;
requires static transitive java.sql;
requires static java.naming;
exports org.eclipse.jetty.session;

View File

@ -14,7 +14,7 @@
module org.eclipse.jetty.util
{
// Standard Jetty Logging now.
requires org.slf4j;
requires transitive org.slf4j;
// Required by SSL code (for X509).
requires transitive java.naming;

View File

@ -38,7 +38,7 @@ public interface Attributes
/**
* Remove an attribute
* @param name the attribute to remove
* @return the value of the attribute if removed, else null
* @return the value of the attribute if removed, else {@code null}
*/
Object removeAttribute(String name);
@ -46,20 +46,20 @@ public interface Attributes
* Set an attribute
* @param name the attribute to set
* @param attribute the value to set. A null value is equivalent to removing the attribute.
* @return the previous value of the attribute if set, else null
* @return the previous value of the attribute if set, else {@code null}
*/
Object setAttribute(String name, Object attribute);
/**
* Get an attribute
* @param name the attribute to get
* @return the value of the attribute
* @return the value of the attribute, or {@code null} if no such attribute exists
*/
Object getAttribute(String name);
/**
* Get the immutable set of attribute names.
* @return Set of attribute names
* @return Set of attribute names, or an empty set if there are no attributes.
*/
Set<String> getAttributeNameSet();

View File

@ -106,7 +106,8 @@ public class BufferUtil
(byte)'E', (byte)'F'
};
public static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(new byte[0]).asReadOnlyBuffer();
public static final byte[] EMPTY_BYTES = new byte[0];
public static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(EMPTY_BYTES).asReadOnlyBuffer();
/**
* Allocate ByteBuffer in flush mode.

View File

@ -41,7 +41,7 @@ import org.slf4j.LoggerFactory;
*/
public class Utf8StringBuilder implements CharsetStringBuilder
{
protected static final Logger LOG = LoggerFactory.getLogger(Utf8StringBuilder.class);
private static final Logger LOG = LoggerFactory.getLogger(Utf8StringBuilder.class);
public static final char REPLACEMENT = '<27>';
private static final int UTF8_ACCEPT = 0;
private static final int UTF8_REJECT = 12;

View File

@ -26,7 +26,6 @@ import java.awt.Toolkit;
*/
public class AWTLeakPreventer extends AbstractLeakPreventer
{
@Override
public void prevent(ClassLoader loader)
{

View File

@ -30,7 +30,7 @@ import org.slf4j.LoggerFactory;
*/
public abstract class AbstractLeakPreventer extends AbstractLifeCycle
{
protected static final Logger LOG = LoggerFactory.getLogger(AbstractLeakPreventer.class);
static final Logger LOG = LoggerFactory.getLogger(AbstractLeakPreventer.class);
public abstract void prevent(ClassLoader loader);

View File

@ -25,7 +25,6 @@ import javax.imageio.ImageIO;
*/
public class AppContextLeakPreventer extends AbstractLeakPreventer
{
@Override
public void prevent(ClassLoader loader)
{

View File

@ -24,7 +24,6 @@ import java.sql.DriverManager;
*/
public class DriverManagerLeakPreventer extends AbstractLeakPreventer
{
@Override
public void prevent(ClassLoader loader)
{

View File

@ -23,8 +23,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A scheduler based on the the JVM Timer class
* A scheduler based on the JVM {@link Timer} class.
*
* @deprecated use {@link ScheduledExecutorScheduler} instead.
*/
@Deprecated(since = "12.0.9", forRemoval = true)
public class TimerScheduler extends AbstractLifeCycle implements Scheduler, Runnable
{
private static final Logger LOG = LoggerFactory.getLogger(TimerScheduler.class);

View File

@ -27,9 +27,10 @@ module org.eclipse.jetty.websocket.core.common
org.eclipse.jetty.util; // Export to DecoratedObjectFactory.
uses org.eclipse.jetty.websocket.core.Extension;
provides org.eclipse.jetty.websocket.core.Extension with
org.eclipse.jetty.websocket.core.internal.FragmentExtension,
org.eclipse.jetty.websocket.core.internal.FrameCaptureExtension,
org.eclipse.jetty.websocket.core.internal.IdentityExtension,
org.eclipse.jetty.websocket.core.internal.PerMessageDeflateExtension,
org.eclipse.jetty.websocket.core.internal.ValidationExtension;

View File

@ -1,5 +1,5 @@
org.eclipse.jetty.websocket.core.internal.IdentityExtension
org.eclipse.jetty.websocket.core.internal.FragmentExtension
org.eclipse.jetty.websocket.core.internal.FrameCaptureExtension
org.eclipse.jetty.websocket.core.internal.IdentityExtension
org.eclipse.jetty.websocket.core.internal.PerMessageDeflateExtension
org.eclipse.jetty.websocket.core.internal.ValidationExtension
org.eclipse.jetty.websocket.core.internal.FrameCaptureExtension

View File

@ -322,7 +322,7 @@ public class ServerWebSocketContainer extends ContainerLifeCycle implements WebS
* @see #upgrade(WebSocketCreator, Request, Response, Callback)
*/
@Override
public boolean handle(Request request, Response response, Callback callback) throws WebSocketException
public boolean handle(Request request, Response response, Callback callback)
{
return mappings.upgrade(request, response, callback, configuration);
}
@ -346,7 +346,7 @@ public class ServerWebSocketContainer extends ContainerLifeCycle implements WebS
* @throws WebSocketException there is an error during the upgrade
* @see #handle(Request, Response, Callback)
*/
public boolean upgrade(WebSocketCreator creator, Request request, Response response, Callback callback) throws WebSocketException
public boolean upgrade(WebSocketCreator creator, Request request, Response response, Callback callback)
{
var coreCreator = newWebSocketCreator(creator);
WebSocketNegotiator negotiator = WebSocketNegotiator.from(coreCreator, factory);

View File

@ -44,21 +44,6 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.interceptor</groupId>
<artifactId>jakarta.interceptor-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>

View File

@ -14,9 +14,9 @@
module org.eclipse.jetty.ee10.apache.jsp
{
requires java.xml;
requires jakarta.servlet;
requires transitive jakarta.servlet;
requires org.eclipse.jetty.util;
requires org.mortbay.apache.jasper;
requires transitive org.mortbay.apache.jasper;
requires org.slf4j;
exports org.eclipse.jetty.ee10.apache.jsp;

View File

@ -11,6 +11,11 @@
// ========================================================================
//
import jakarta.servlet.ServletContainerInitializer;
import org.eclipse.jetty.ee10.cdi.CdiConfiguration;
import org.eclipse.jetty.ee10.cdi.CdiServletContainerInitializer;
import org.eclipse.jetty.ee10.webapp.Configuration;
module org.eclipse.jetty.ee10.cdi
{
requires org.eclipse.jetty.ee10.annotations;
@ -20,4 +25,7 @@ module org.eclipse.jetty.ee10.cdi
requires static jakarta.cdi;
exports org.eclipse.jetty.ee10.cdi;
}
provides ServletContainerInitializer with CdiServletContainerInitializer;
provides Configuration with CdiConfiguration;
}

View File

@ -29,8 +29,9 @@ import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import jakarta.servlet.AsyncContext;
import jakarta.servlet.AsyncEvent;
@ -55,15 +56,15 @@ import jakarta.servlet.http.Part;
/**
* Dump Servlet Request.
*/
@SuppressWarnings("serial")
public class Dump extends HttpServlet
{
/**
* Zero Width Space, to allow text to be wrapped at designated spots
*/
private static final String ZWSP = "&#8203;";
boolean fixed;
Timer _timer;
private final ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor();
private boolean fixed;
@Override
public void init(ServletConfig config) throws ServletException
@ -72,12 +73,9 @@ public class Dump extends HttpServlet
if (config.getInitParameter("unavailable") != null && !fixed)
{
fixed = true;
throw new UnavailableException("Unavailable test", Integer.parseInt(config.getInitParameter("unavailable")));
}
_timer = new Timer(true);
}
@Override
@ -124,9 +122,9 @@ public class Dump extends HttpServlet
final String chars = request.getParameter("chars");
final String block = request.getParameter("block");
final String dribble = request.getParameter("dribble");
final boolean flush = request.getParameter("flush") != null ? Boolean.parseBoolean(request.getParameter("flush")) : false;
final boolean flush = request.getParameter("flush") != null && Boolean.parseBoolean(request.getParameter("flush"));
if (request.getPathInfo() != null && request.getPathInfo().toLowerCase(Locale.ENGLISH).indexOf("script") != -1)
if (request.getPathInfo() != null && request.getPathInfo().toLowerCase(Locale.ENGLISH).contains("script"))
{
response.sendRedirect(response.encodeRedirectURL(getServletContext().getContextPath() + "/dump/info"));
return;
@ -139,6 +137,7 @@ public class Dump extends HttpServlet
long end = System.currentTimeMillis() + Long.parseLong(request.getParameter("busy"));
while (System.currentTimeMillis() < end)
{
Thread.onSpinWait();
}
}
@ -154,7 +153,7 @@ public class Dump extends HttpServlet
try
{
long s = Long.parseLong(request.getParameter("sleep"));
if (request.getHeader("Expect") != null && request.getHeader("Expect").indexOf("102") >= 0)
if (request.getHeader("Expect") != null && request.getHeader("Expect").contains("102"))
{
Thread.sleep(s / 2);
response.sendError(102);
@ -184,7 +183,7 @@ public class Dump extends HttpServlet
{
@Override
public void onTimeout(AsyncEvent event) throws IOException
public void onTimeout(AsyncEvent event)
{
response.addHeader("Dump", "onTimeout");
try
@ -203,19 +202,19 @@ public class Dump extends HttpServlet
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException
public void onStartAsync(AsyncEvent event)
{
response.addHeader("Dump", "onStartAsync");
}
@Override
public void onError(AsyncEvent event) throws IOException
public void onError(AsyncEvent event)
{
response.addHeader("Dump", "onError");
}
@Override
public void onComplete(AsyncEvent event) throws IOException
public void onComplete(AsyncEvent event)
{
response.addHeader("Dump", "onComplete");
}
@ -226,36 +225,25 @@ public class Dump extends HttpServlet
request.setAttribute("RESUME", Boolean.TRUE);
final long resume = Long.parseLong(request.getParameter("dispatch"));
_timer.schedule(new TimerTask()
{
@Override
public void run()
{
async.dispatch();
}
}, resume);
_scheduler.schedule(() -> async.dispatch(), resume, TimeUnit.MILLISECONDS);
}
if (request.getParameter("complete") != null)
{
final long complete = Long.parseLong(request.getParameter("complete"));
_timer.schedule(new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
try
{
try
{
response.setContentType("text/html");
response.getOutputStream().println("<h1>COMPLETED</h1>");
async.complete();
}
catch (Exception e)
{
e.printStackTrace();
}
response.setContentType("text/html");
response.getOutputStream().println("<h1>COMPLETED</h1>");
async.complete();
}
}, complete);
catch (Exception e)
{
e.printStackTrace();
}
}, complete, TimeUnit.MILLISECONDS);
}
return;
@ -272,7 +260,7 @@ public class Dump extends HttpServlet
// Force a content length response
String length = request.getParameter("length");
if (length != null && length.length() > 0)
if (length != null && !length.isEmpty())
{
response.setContentLength(Integer.parseInt(length));
}
@ -298,7 +286,7 @@ public class Dump extends HttpServlet
// test a reset
String reset = request.getParameter("reset");
if (reset != null && reset.length() > 0)
if (reset != null && !reset.isEmpty())
{
response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
response.setHeader("SHOULD_NOT", "BE SEEN");
@ -307,7 +295,7 @@ public class Dump extends HttpServlet
// handle an redirect
String redirect = request.getParameter("redirect");
if (redirect != null && redirect.length() > 0)
if (redirect != null && !redirect.isEmpty())
{
response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
response.sendRedirect(response.encodeRedirectURL(redirect));
@ -324,7 +312,7 @@ public class Dump extends HttpServlet
// handle an error
String error = request.getParameter("error");
if (error != null && error.length() > 0 && request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) == null)
if (error != null && !error.isEmpty() && request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) == null)
{
response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
response.sendError(Integer.parseInt(error));
@ -352,7 +340,7 @@ public class Dump extends HttpServlet
// Handle a extra headers
String headers = request.getParameter("headers");
if (headers != null && headers.length() > 0)
if (headers != null && !headers.isEmpty())
{
long h = Long.parseLong(headers);
for (int i = 0; i < h; i++)
@ -362,7 +350,7 @@ public class Dump extends HttpServlet
}
String buffer = request.getParameter("buffer");
if (buffer != null && buffer.length() > 0)
if (buffer != null && !buffer.isEmpty())
response.setBufferSize(Integer.parseInt(buffer));
String charset = request.getParameter("charset");
@ -371,7 +359,7 @@ public class Dump extends HttpServlet
response.setCharacterEncoding(charset);
response.setContentType("text/html");
if (info != null && info.indexOf("Locale/") >= 0)
if (info != null && info.contains("Locale/"))
{
try
{
@ -418,8 +406,7 @@ public class Dump extends HttpServlet
String buffered = request.getParameter("buffered");
PrintWriter pout = null;
PrintWriter pout;
try
{
pout = response.getWriter();
@ -438,7 +425,7 @@ public class Dump extends HttpServlet
pout.write("<table width=\"95%\">");
pout.write("<tr>\n");
pout.write("<th align=\"right\">getContentLength:&nbsp;</th>");
pout.write("<td>" + Integer.toString(request.getContentLength()) + "</td>");
pout.write("<td>" + request.getContentLength() + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getContentType:&nbsp;</th>");
pout.write("<td>" + notag(request.getContentType()) + "</td>");
@ -459,7 +446,7 @@ public class Dump extends HttpServlet
pout.write("<td>" + request.getLocalAddr() + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getLocalPort:&nbsp;</th>");
pout.write("<td>" + Integer.toString(request.getLocalPort()) + "</td>");
pout.write("<td>" + request.getLocalPort() + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getMethod:&nbsp;</th>");
pout.write("<td>" + notag(request.getMethod()) + "</td>");
@ -507,7 +494,7 @@ public class Dump extends HttpServlet
pout.write("<td>" + notag(request.getServletPath()) + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getServerPort:&nbsp;</th>");
pout.write("<td>" + Integer.toString(request.getServerPort()) + "</td>");
pout.write("<td>" + request.getServerPort() + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getUserPrincipal:&nbsp;</th>");
pout.write("<td>" + request.getUserPrincipal() + "</td>");
@ -541,12 +528,12 @@ public class Dump extends HttpServlet
String name;
while (h.hasMoreElements())
{
name = (String)h.nextElement();
name = h.nextElement();
Enumeration<String> h2 = request.getHeaders(name);
while (h2.hasMoreElements())
{
String hv = (String)h2.nextElement();
String hv = h2.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">" + notag(name) + ":&nbsp;</th>");
pout.write("<td>" + notag(hv) + "</td>");
@ -558,7 +545,7 @@ public class Dump extends HttpServlet
h = request.getParameterNames();
while (h.hasMoreElements())
{
name = (String)h.nextElement();
name = h.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">" + notag(name) + ":&nbsp;</th>");
pout.write("<td>" + notag(request.getParameter(name)) + "</td>");
@ -646,13 +633,12 @@ public class Dump extends HttpServlet
Enumeration<String> a = request.getAttributeNames();
while (a.hasMoreElements())
{
name = (String)a.nextElement();
name = a.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ":&nbsp;</th>");
Object value = request.getAttribute(name);
if (value instanceof File)
if (value instanceof File file)
{
File file = (File)value;
pout.write("<td>" + "<pre>" + file.getName() + " (" + file.length() + " " + new Date(file.lastModified()) + ")</pre>" + "</td>");
}
else
@ -665,7 +651,7 @@ public class Dump extends HttpServlet
a = getInitParameterNames();
while (a.hasMoreElements())
{
name = (String)a.nextElement();
name = a.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">" + name + ":&nbsp;</th>");
pout.write("<td>" + toString(getInitParameter(name)) + "</td>");
@ -676,7 +662,7 @@ public class Dump extends HttpServlet
a = getServletContext().getInitParameterNames();
while (a.hasMoreElements())
{
name = (String)a.nextElement();
name = a.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ":&nbsp;</th>");
pout.write("<td>" + toString(getServletContext().getInitParameter(name)) + "</td>");
@ -687,14 +673,14 @@ public class Dump extends HttpServlet
a = getServletContext().getAttributeNames();
while (a.hasMoreElements())
{
name = (String)a.nextElement();
name = a.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ":&nbsp;</th>");
pout.write("<td>" + "<pre>" + toString(getServletContext().getAttribute(name)) + "</pre>" + "</td>");
}
String res = request.getParameter("resource");
if (res != null && res.length() > 0)
if (res != null && !res.isEmpty())
{
pout.write("</tr><tr>\n");
pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Get Resource: \"" + res + "\"</big></th>");
@ -707,7 +693,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
pout.write("</tr><tr>\n");
@ -718,7 +704,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
pout.write("</tr><tr>\n");
@ -729,7 +715,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
pout.write("</tr><tr>\n");
@ -748,7 +734,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
pout.write("</tr><tr>\n");
@ -759,7 +745,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
String cp = context.getContextPath();
@ -897,12 +883,12 @@ public class Dump extends HttpServlet
if (pi != null)
{
if ("/ex4".equals(pi))
throw new ServletException("test ex4", new Throwable());
if ("/ex5".equals(pi))
throw new IOException("test ex5");
if ("/ex6".equals(pi))
throw new UnavailableException("test ex6");
switch (pi)
{
case "/ex4" -> throw new ServletException("test ex4", new Throwable());
case "/ex5" -> throw new IOException("test ex5");
case "/ex6" -> throw new UnavailableException("test ex6");
}
}
}
@ -915,7 +901,7 @@ public class Dump extends HttpServlet
@Override
public void destroy()
{
_timer.cancel();
_scheduler.shutdownNow();
}
private String getURI(HttpServletRequest request)
@ -935,7 +921,7 @@ public class Dump extends HttpServlet
{
if (o.getClass().isArray())
{
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
if (!o.getClass().getComponentType().isPrimitive())
{
Object[] array = (Object[])o;
@ -978,11 +964,11 @@ public class Dump extends HttpServlet
private boolean dump(HttpServletResponse response, String data, String chars, String block, String dribble, boolean flush) throws IOException
{
if (data != null && data.length() > 0)
int len = (block != null && !block.isEmpty()) ? Integer.parseInt(block) : 50;
if (data != null && !data.isEmpty())
{
int b = (block != null && block.length() > 0) ? Integer.parseInt(block) : 50;
byte[] buf = new byte[b];
for (int i = 0; i < b; i++)
byte[] buf = new byte[len];
for (int i = 0; i < len; i++)
{
buf[i] = (byte)('0' + (i % 10));
@ -995,15 +981,15 @@ public class Dump extends HttpServlet
long d = Long.parseLong(data);
while (d > 0)
{
if (b == 1)
if (len == 1)
{
out.write(d % 80 == 0 ? '\n' : '.');
d--;
}
else if (d >= b)
else if (d >= len)
{
out.write(buf);
d = d - b;
d = d - len;
}
else
{
@ -1033,11 +1019,10 @@ public class Dump extends HttpServlet
}
// Handle a dump of data
if (chars != null && chars.length() > 0)
if (chars != null && !chars.isEmpty())
{
int b = (block != null && block.length() > 0) ? Integer.parseInt(block) : 50;
char[] buf = new char[b];
for (int i = 0; i < b; i++)
char[] buf = new char[len];
for (int i = 0; i < len; i++)
{
buf[i] = (char)('0' + (i % 10));
if (i % 10 == 9)
@ -1049,15 +1034,15 @@ public class Dump extends HttpServlet
long d = Long.parseLong(chars);
while (d > 0 && !out.checkError())
{
if (b == 1)
if (len == 1)
{
out.write(d % 80 == 0 ? '\n' : '.');
d--;
}
else if (d >= b)
else if (d >= len)
{
out.write(buf);
d = d - b;
d = d - len;
}
else
{

View File

@ -19,7 +19,7 @@ module org.eclipse.jetty.ee10.jndi
requires transitive java.naming;
// Only required if using MailSessionReference.
requires static jakarta.mail;
requires static transitive jakarta.mail;
exports org.eclipse.jetty.ee10.jndi.factories;
}

View File

@ -16,13 +16,13 @@ import org.eclipse.jetty.ee10.plus.webapp.PlusConfiguration;
module org.eclipse.jetty.ee10.plus
{
requires org.eclipse.jetty.plus;
requires transitive org.eclipse.jetty.plus;
requires org.slf4j;
requires transitive org.eclipse.jetty.ee10.webapp;
// Only required if using Transaction.
requires static jakarta.transaction;
requires static transitive jakarta.transaction;
exports org.eclipse.jetty.ee10.plus.jndi;
exports org.eclipse.jetty.ee10.plus.webapp;

View File

@ -16,8 +16,6 @@ package org.eclipse.jetty.ee10.plus.jndi;
import javax.naming.NamingException;
import jakarta.transaction.UserTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Transaction
@ -26,8 +24,6 @@ import org.slf4j.LoggerFactory;
*/
public class Transaction extends org.eclipse.jetty.plus.jndi.Transaction
{
private static final Logger LOG = LoggerFactory.getLogger(Transaction.class);
/**
* @param scope the scope, usually an environment like ee9, ee10
* @param userTransaction the UserTransaction

View File

@ -1,2 +1,2 @@
org.eclipse.jetty.ee10.plus.webapp.PlusConfiguration
org.eclipse.jetty.ee10.plus.webapp.EnvConfiguration
org.eclipse.jetty.ee10.plus.webapp.PlusConfiguration

View File

@ -13,7 +13,7 @@
module org.eclipse.jetty.ee10.proxy
{
requires jakarta.servlet;
requires transitive jakarta.servlet;
requires transitive org.eclipse.jetty.client;
requires transitive org.eclipse.jetty.server;
requires transitive org.slf4j;

View File

@ -11,6 +11,10 @@
// ========================================================================
//
import org.eclipse.jetty.ee10.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.ee10.quickstart.QuickStartGeneratorConfiguration;
import org.eclipse.jetty.ee10.webapp.Configuration;
module org.eclipse.jetty.ee10.quickstart
{
requires jakarta.servlet;
@ -19,4 +23,6 @@ module org.eclipse.jetty.ee10.quickstart
requires transitive org.eclipse.jetty.ee10.annotations;
exports org.eclipse.jetty.ee10.quickstart;
provides Configuration with QuickStartConfiguration, QuickStartGeneratorConfiguration;
}

View File

@ -56,6 +56,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.Blocker;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.ExceptionUtil;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.Resources;
@ -555,7 +556,16 @@ public class DefaultServlet extends HttpServlet
if (includedServletPath != null)
return encodePath(getIncludedPathInContext(req, includedServletPath, !isDefaultMapping(req)));
else if (!isDefaultMapping(req))
return encodePath(req.getPathInfo());
{
//a match via an extension mapping will more than likely
//have no path info
String path = req.getPathInfo();
if (StringUtil.isEmpty(path) &&
MappingMatch.EXTENSION.equals(req.getHttpServletMapping().getMappingMatch()))
path = req.getServletPath();
return encodePath(path);
}
else if (req instanceof ServletApiRequest apiRequest)
return Context.getPathInContext(req.getContextPath(), apiRequest.getRequest().getHttpURI().getCanonicalPath());
else

View File

@ -20,10 +20,10 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
@ -42,7 +42,6 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Response;
@ -69,17 +68,16 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class AsyncServletTest
{
protected AsyncServlet _servlet = new AsyncServlet();
protected int _port;
protected Server _server = new Server();
protected ServletHandler _servletHandler;
protected ErrorPageErrorHandler _errorHandler;
protected ServerConnector _connector;
protected List<String> _log;
protected int _expectedLogs;
protected String _expectedCode;
protected List<String> _history = new CopyOnWriteArrayList<>();
protected CountDownLatch _latch;
private final AsyncServlet _servlet = new AsyncServlet();
private int _port;
private final Server _server = new Server();
private ServletHandler _servletHandler;
private ErrorPageErrorHandler _errorHandler;
private List<String> _log;
private int _expectedLogs;
private String _expectedCode;
private final List<String> _history = new CopyOnWriteArrayList<>();
private CountDownLatch _latch;
private void historyAdd(String item)
{
@ -90,8 +88,8 @@ public class AsyncServletTest
@BeforeEach
public void setUp() throws Exception
{
_connector = new ServerConnector(_server);
_server.setConnectors(new Connector[]{_connector});
ServerConnector connector = new ServerConnector(_server);
_server.addConnector(connector);
_log = new ArrayList<>();
RequestLog log = new Log();
@ -128,7 +126,7 @@ public class AsyncServletTest
holder2.setAsyncSupported(false);
_servletHandler.addServletWithMapping(holder2, "/noasync/*");
_server.start();
_port = _connector.getLocalPort();
_port = connector.getLocalPort();
_history.clear();
_latch = new CountDownLatch(1);
}
@ -787,7 +785,7 @@ public class AsyncServletTest
private class AsyncServlet extends HttpServlet
{
private final Timer _timer = new Timer();
private final ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor();
@Override
public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
@ -889,28 +887,20 @@ public class AsyncServletTest
if (completeAfter > 0)
{
TimerTask complete = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
try
{
try
{
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
catch (Exception e)
{
e.printStackTrace();
}
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
};
synchronized (_timer)
{
_timer.schedule(complete, completeAfter);
}
catch (Exception e)
{
e.printStackTrace();
}
}, completeAfter, TimeUnit.MILLISECONDS);
}
else if (completeAfter == 0)
{
@ -921,28 +911,20 @@ public class AsyncServletTest
}
else if (dispatchAfter > 0)
{
TimerTask dispatch = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
historyAdd("dispatch");
if (path != null)
{
historyAdd("dispatch");
if (path != null)
{
int q = path.indexOf('?');
String uriInContext = (q >= 0)
? URIUtil.encodePath(path.substring(0, q)) + path.substring(q)
: URIUtil.encodePath(path);
async.dispatch(uriInContext);
}
else
async.dispatch();
int q = path.indexOf('?');
String uriInContext = (q >= 0)
? URIUtil.encodePath(path.substring(0, q)) + path.substring(q)
: URIUtil.encodePath(path);
async.dispatch(uriInContext);
}
};
synchronized (_timer)
{
_timer.schedule(dispatch, dispatchAfter);
}
else
async.dispatch();
}, dispatchAfter, TimeUnit.MILLISECONDS);
}
else if (dispatchAfter == 0)
{
@ -993,28 +975,20 @@ public class AsyncServletTest
if (complete2After > 0)
{
TimerTask complete = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
try
{
try
{
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
catch (Exception e)
{
e.printStackTrace();
}
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
};
synchronized (_timer)
{
_timer.schedule(complete, complete2After);
}
catch (Exception e)
{
e.printStackTrace();
}
}, complete2After, TimeUnit.MILLISECONDS);
}
else if (complete2After == 0)
{
@ -1025,19 +999,11 @@ public class AsyncServletTest
}
else if (dispatch2After > 0)
{
TimerTask dispatch = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
{
historyAdd("dispatch");
async.dispatch();
}
};
synchronized (_timer)
{
_timer.schedule(dispatch, dispatch2After);
}
historyAdd("dispatch");
async.dispatch();
}, dispatch2After, TimeUnit.MILLISECONDS);
}
else if (dispatch2After == 0)
{

View File

@ -3487,6 +3487,26 @@ public class DefaultServletTest
assertThat(response.getContent(), containsString("testPathInfoOnly-OK"));
}
@Test
public void testSuffixMappings() throws Exception
{
server.stop();
Path suffixroot = MavenTestingUtils.getTestResourcePath("suffixroot");
ResourceFactory resourceFactory = ResourceFactory.of(context);
context.setBaseResource(resourceFactory.newResource(suffixroot.toUri()));
ServletHolder holderAlt = new ServletHolder("static-js", DefaultServlet.class);
context.addServlet(holderAlt, "*.js");
ServletHolder holderDef = new ServletHolder("default", DefaultServlet.class);
holderDef.setInitParameter("dirAllowed", "true");
context.addServlet(holderDef, "/");
server.start();
String rawResponse = connector.getResponse("GET /context/test.js HTTP/1.0\r\n\r\n");
assertThat(rawResponse, containsString("Hello"));
}
@Test
public void testMemoryResourceRange() throws Exception
{

View File

@ -118,6 +118,60 @@ public class RequestTest
LifeCycle.stop(_server);
}
@Test
public void testCaseInsensitiveHeaders() throws Exception
{
final AtomicReference<Boolean> resultIsSecure = new AtomicReference<>();
startServer(new HttpServlet()
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp)
{
assertThat(request.getHeader("accept"), is("*/*"));
assertThat(request.getHeader("Accept"), is("*/*"));
assertThat(request.getHeader("ACCEPT"), is("*/*"));
assertThat(request.getHeader("AcCePt"), is("*/*"));
assertThat(request.getHeader("random"), is("value"));
assertThat(request.getHeader("Random"), is("value"));
assertThat(request.getHeader("RANDOM"), is("value"));
assertThat(request.getHeader("rAnDoM"), is("value"));
assertThat(request.getHeader("RaNdOm"), is("value"));
assertThat(request.getHeader("Accept-Charset"), is("UTF-8"));
assertThat(request.getHeader("accept-charset"), is("UTF-8"));
assertThat(Collections.list(request.getHeaders("Accept-Charset")), contains("UTF-8", "UTF-16"));
assertThat(Collections.list(request.getHeaders("accept-charset")), contains("UTF-8", "UTF-16"));
assertThat(request.getHeader("foo-bar"), is("one"));
assertThat(request.getHeader("Foo-Bar"), is("one"));
assertThat(Collections.list(request.getHeaders("foo-bar")), contains("one", "two"));
assertThat(Collections.list(request.getHeaders("Foo-Bar")), contains("one", "two"));
assertThat(Collections.list(request.getHeaderNames()),
contains("Host", "Connection", "Accept", "RaNdOm", "Accept-Charset", "Foo-Bar"));
}
});
String rawResponse = _connector.getResponse(
"""
GET / HTTP/1.1
Host: local
Connection: close
Accept: */*
RaNdOm: value
Accept-Charset: UTF-8
accept-charset: UTF-16
Foo-Bar: one
foo-bar: two
""");
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
assertThat(response.getStatus(), is(HttpStatus.OK_200));
}
@Test
public void testIsSecure() throws Exception
{

View File

@ -0,0 +1 @@
document.write("Hello");

View File

@ -26,7 +26,7 @@ module org.eclipse.jetty.ee10.servlets
requires static org.eclipse.jetty.http;
requires static org.eclipse.jetty.server;
// Only required if using CrossOriginFilter, DoSFilter, etc.
requires static org.eclipse.jetty.util;
requires static transitive org.eclipse.jetty.util;
exports org.eclipse.jetty.ee10.servlets;
}

View File

@ -1 +1 @@
org.eclipse.jetty.test.jmx.MyContainerInitializer
org.eclipse.jetty.ee10.test.jmx.MyContainerInitializer

View File

@ -1,7 +1,7 @@
org.eclipse.jetty.ee10.webapp.FragmentConfiguration
org.eclipse.jetty.ee10.webapp.JettyWebXmlConfiguration
org.eclipse.jetty.ee10.webapp.JaasConfiguration
org.eclipse.jetty.ee10.webapp.JaspiConfiguration
org.eclipse.jetty.ee10.webapp.JettyWebXmlConfiguration
org.eclipse.jetty.ee10.webapp.JmxConfiguration
org.eclipse.jetty.ee10.webapp.JndiConfiguration
org.eclipse.jetty.ee10.webapp.JspConfiguration

View File

@ -264,8 +264,11 @@ public class WebSocketOverHTTP2Test
startServer();
startClient(clientConnector -> new ClientConnectionFactoryOverHTTP2.HTTP2(new HTTP2Client(clientConnector)));
// Port 293 is not assigned by IANA, so
// it should be impossible to connect.
int nonExistingPort = 293;
EventSocket wsEndPoint = new EventSocket();
URI uri = URI.create("ws://localhost:" + (connector.getLocalPort() + 1) + "/ws/echo");
URI uri = URI.create("ws://localhost:" + nonExistingPort + "/ws/echo");
ExecutionException failure = Assertions.assertThrows(ExecutionException.class, () ->
wsClient.connect(wsEndPoint, uri).get(5, TimeUnit.SECONDS));

View File

@ -44,21 +44,6 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.interceptor</groupId>
<artifactId>jakarta.interceptor-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>

View File

@ -14,9 +14,9 @@
module org.eclipse.jetty.ee11.apache.jsp
{
requires java.xml;
requires jakarta.servlet;
requires transitive jakarta.servlet;
requires org.eclipse.jetty.util;
requires org.mortbay.apache.jasper;
requires transitive org.mortbay.apache.jasper;
requires org.slf4j;
exports org.eclipse.jetty.ee11.apache.jsp;

View File

@ -11,6 +11,11 @@
// ========================================================================
//
import jakarta.servlet.ServletContainerInitializer;
import org.eclipse.jetty.ee11.cdi.CdiConfiguration;
import org.eclipse.jetty.ee11.cdi.CdiServletContainerInitializer;
import org.eclipse.jetty.ee11.webapp.Configuration;
module org.eclipse.jetty.ee11.cdi
{
requires org.eclipse.jetty.ee11.annotations;
@ -20,4 +25,7 @@ module org.eclipse.jetty.ee11.cdi
requires static jakarta.cdi;
exports org.eclipse.jetty.ee11.cdi;
}
provides ServletContainerInitializer with CdiServletContainerInitializer;
provides Configuration with CdiConfiguration;
}

View File

@ -29,8 +29,9 @@ import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import jakarta.servlet.AsyncContext;
import jakarta.servlet.AsyncEvent;
@ -55,15 +56,15 @@ import jakarta.servlet.http.Part;
/**
* Dump Servlet Request.
*/
@SuppressWarnings("serial")
public class Dump extends HttpServlet
{
/**
* Zero Width Space, to allow text to be wrapped at designated spots
*/
private static final String ZWSP = "&#8203;";
boolean fixed;
Timer _timer;
private final ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor();
private boolean fixed;
@Override
public void init(ServletConfig config) throws ServletException
@ -72,12 +73,9 @@ public class Dump extends HttpServlet
if (config.getInitParameter("unavailable") != null && !fixed)
{
fixed = true;
throw new UnavailableException("Unavailable test", Integer.parseInt(config.getInitParameter("unavailable")));
}
_timer = new Timer(true);
}
@Override
@ -124,9 +122,9 @@ public class Dump extends HttpServlet
final String chars = request.getParameter("chars");
final String block = request.getParameter("block");
final String dribble = request.getParameter("dribble");
final boolean flush = request.getParameter("flush") != null ? Boolean.parseBoolean(request.getParameter("flush")) : false;
final boolean flush = request.getParameter("flush") != null && Boolean.parseBoolean(request.getParameter("flush"));
if (request.getPathInfo() != null && request.getPathInfo().toLowerCase(Locale.ENGLISH).indexOf("script") != -1)
if (request.getPathInfo() != null && request.getPathInfo().toLowerCase(Locale.ENGLISH).contains("script"))
{
response.sendRedirect(response.encodeRedirectURL(getServletContext().getContextPath() + "/dump/info"));
return;
@ -139,6 +137,7 @@ public class Dump extends HttpServlet
long end = System.currentTimeMillis() + Long.parseLong(request.getParameter("busy"));
while (System.currentTimeMillis() < end)
{
Thread.onSpinWait();
}
}
@ -154,7 +153,7 @@ public class Dump extends HttpServlet
try
{
long s = Long.parseLong(request.getParameter("sleep"));
if (request.getHeader("Expect") != null && request.getHeader("Expect").indexOf("102") >= 0)
if (request.getHeader("Expect") != null && request.getHeader("Expect").contains("102"))
{
Thread.sleep(s / 2);
response.sendError(102);
@ -184,7 +183,7 @@ public class Dump extends HttpServlet
{
@Override
public void onTimeout(AsyncEvent event) throws IOException
public void onTimeout(AsyncEvent event)
{
response.addHeader("Dump", "onTimeout");
try
@ -203,19 +202,19 @@ public class Dump extends HttpServlet
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException
public void onStartAsync(AsyncEvent event)
{
response.addHeader("Dump", "onStartAsync");
}
@Override
public void onError(AsyncEvent event) throws IOException
public void onError(AsyncEvent event)
{
response.addHeader("Dump", "onError");
}
@Override
public void onComplete(AsyncEvent event) throws IOException
public void onComplete(AsyncEvent event)
{
response.addHeader("Dump", "onComplete");
}
@ -226,36 +225,25 @@ public class Dump extends HttpServlet
request.setAttribute("RESUME", Boolean.TRUE);
final long resume = Long.parseLong(request.getParameter("dispatch"));
_timer.schedule(new TimerTask()
{
@Override
public void run()
{
async.dispatch();
}
}, resume);
_scheduler.schedule(() -> async.dispatch(), resume, TimeUnit.MILLISECONDS);
}
if (request.getParameter("complete") != null)
{
final long complete = Long.parseLong(request.getParameter("complete"));
_timer.schedule(new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
try
{
try
{
response.setContentType("text/html");
response.getOutputStream().println("<h1>COMPLETED</h1>");
async.complete();
}
catch (Exception e)
{
e.printStackTrace();
}
response.setContentType("text/html");
response.getOutputStream().println("<h1>COMPLETED</h1>");
async.complete();
}
}, complete);
catch (Exception e)
{
e.printStackTrace();
}
}, complete, TimeUnit.MILLISECONDS);
}
return;
@ -272,7 +260,7 @@ public class Dump extends HttpServlet
// Force a content length response
String length = request.getParameter("length");
if (length != null && length.length() > 0)
if (length != null && !length.isEmpty())
{
response.setContentLength(Integer.parseInt(length));
}
@ -298,7 +286,7 @@ public class Dump extends HttpServlet
// test a reset
String reset = request.getParameter("reset");
if (reset != null && reset.length() > 0)
if (reset != null && !reset.isEmpty())
{
response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
response.setHeader("SHOULD_NOT", "BE SEEN");
@ -307,7 +295,7 @@ public class Dump extends HttpServlet
// handle an redirect
String redirect = request.getParameter("redirect");
if (redirect != null && redirect.length() > 0)
if (redirect != null && !redirect.isEmpty())
{
response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
response.sendRedirect(response.encodeRedirectURL(redirect));
@ -324,7 +312,7 @@ public class Dump extends HttpServlet
// handle an error
String error = request.getParameter("error");
if (error != null && error.length() > 0 && request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) == null)
if (error != null && !error.isEmpty() && request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) == null)
{
response.getOutputStream().println("THIS SHOULD NOT BE SEEN!");
response.sendError(Integer.parseInt(error));
@ -352,7 +340,7 @@ public class Dump extends HttpServlet
// Handle a extra headers
String headers = request.getParameter("headers");
if (headers != null && headers.length() > 0)
if (headers != null && !headers.isEmpty())
{
long h = Long.parseLong(headers);
for (int i = 0; i < h; i++)
@ -362,7 +350,7 @@ public class Dump extends HttpServlet
}
String buffer = request.getParameter("buffer");
if (buffer != null && buffer.length() > 0)
if (buffer != null && !buffer.isEmpty())
response.setBufferSize(Integer.parseInt(buffer));
String charset = request.getParameter("charset");
@ -371,7 +359,7 @@ public class Dump extends HttpServlet
response.setCharacterEncoding(charset);
response.setContentType("text/html");
if (info != null && info.indexOf("Locale/") >= 0)
if (info != null && info.contains("Locale/"))
{
try
{
@ -418,8 +406,7 @@ public class Dump extends HttpServlet
String buffered = request.getParameter("buffered");
PrintWriter pout = null;
PrintWriter pout;
try
{
pout = response.getWriter();
@ -438,7 +425,7 @@ public class Dump extends HttpServlet
pout.write("<table width=\"95%\">");
pout.write("<tr>\n");
pout.write("<th align=\"right\">getContentLength:&nbsp;</th>");
pout.write("<td>" + Integer.toString(request.getContentLength()) + "</td>");
pout.write("<td>" + request.getContentLength() + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getContentType:&nbsp;</th>");
pout.write("<td>" + notag(request.getContentType()) + "</td>");
@ -459,7 +446,7 @@ public class Dump extends HttpServlet
pout.write("<td>" + request.getLocalAddr() + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getLocalPort:&nbsp;</th>");
pout.write("<td>" + Integer.toString(request.getLocalPort()) + "</td>");
pout.write("<td>" + request.getLocalPort() + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getMethod:&nbsp;</th>");
pout.write("<td>" + notag(request.getMethod()) + "</td>");
@ -507,7 +494,7 @@ public class Dump extends HttpServlet
pout.write("<td>" + notag(request.getServletPath()) + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getServerPort:&nbsp;</th>");
pout.write("<td>" + Integer.toString(request.getServerPort()) + "</td>");
pout.write("<td>" + request.getServerPort() + "</td>");
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">getUserPrincipal:&nbsp;</th>");
pout.write("<td>" + request.getUserPrincipal() + "</td>");
@ -541,12 +528,12 @@ public class Dump extends HttpServlet
String name;
while (h.hasMoreElements())
{
name = (String)h.nextElement();
name = h.nextElement();
Enumeration<String> h2 = request.getHeaders(name);
while (h2.hasMoreElements())
{
String hv = (String)h2.nextElement();
String hv = h2.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">" + notag(name) + ":&nbsp;</th>");
pout.write("<td>" + notag(hv) + "</td>");
@ -558,7 +545,7 @@ public class Dump extends HttpServlet
h = request.getParameterNames();
while (h.hasMoreElements())
{
name = (String)h.nextElement();
name = h.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">" + notag(name) + ":&nbsp;</th>");
pout.write("<td>" + notag(request.getParameter(name)) + "</td>");
@ -646,13 +633,12 @@ public class Dump extends HttpServlet
Enumeration<String> a = request.getAttributeNames();
while (a.hasMoreElements())
{
name = (String)a.nextElement();
name = a.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ":&nbsp;</th>");
Object value = request.getAttribute(name);
if (value instanceof File)
if (value instanceof File file)
{
File file = (File)value;
pout.write("<td>" + "<pre>" + file.getName() + " (" + file.length() + " " + new Date(file.lastModified()) + ")</pre>" + "</td>");
}
else
@ -665,7 +651,7 @@ public class Dump extends HttpServlet
a = getInitParameterNames();
while (a.hasMoreElements())
{
name = (String)a.nextElement();
name = a.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\">" + name + ":&nbsp;</th>");
pout.write("<td>" + toString(getInitParameter(name)) + "</td>");
@ -676,7 +662,7 @@ public class Dump extends HttpServlet
a = getServletContext().getInitParameterNames();
while (a.hasMoreElements())
{
name = (String)a.nextElement();
name = a.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ":&nbsp;</th>");
pout.write("<td>" + toString(getServletContext().getInitParameter(name)) + "</td>");
@ -687,14 +673,14 @@ public class Dump extends HttpServlet
a = getServletContext().getAttributeNames();
while (a.hasMoreElements())
{
name = (String)a.nextElement();
name = a.nextElement();
pout.write("</tr><tr>\n");
pout.write("<th align=\"right\" valign=\"top\">" + name.replace(".", ZWSP + ".") + ":&nbsp;</th>");
pout.write("<td>" + "<pre>" + toString(getServletContext().getAttribute(name)) + "</pre>" + "</td>");
}
String res = request.getParameter("resource");
if (res != null && res.length() > 0)
if (res != null && !res.isEmpty())
{
pout.write("</tr><tr>\n");
pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Get Resource: \"" + res + "\"</big></th>");
@ -707,7 +693,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
pout.write("</tr><tr>\n");
@ -718,7 +704,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
pout.write("</tr><tr>\n");
@ -729,7 +715,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
pout.write("</tr><tr>\n");
@ -748,7 +734,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
pout.write("</tr><tr>\n");
@ -759,7 +745,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
pout.write("<td>" + "" + e + "</td>");
pout.write("<td>" + e + "</td>");
}
String cp = context.getContextPath();
@ -897,12 +883,12 @@ public class Dump extends HttpServlet
if (pi != null)
{
if ("/ex4".equals(pi))
throw new ServletException("test ex4", new Throwable());
if ("/ex5".equals(pi))
throw new IOException("test ex5");
if ("/ex6".equals(pi))
throw new UnavailableException("test ex6");
switch (pi)
{
case "/ex4" -> throw new ServletException("test ex4", new Throwable());
case "/ex5" -> throw new IOException("test ex5");
case "/ex6" -> throw new UnavailableException("test ex6");
}
}
}
@ -915,7 +901,7 @@ public class Dump extends HttpServlet
@Override
public void destroy()
{
_timer.cancel();
_scheduler.shutdownNow();
}
private String getURI(HttpServletRequest request)
@ -935,7 +921,7 @@ public class Dump extends HttpServlet
{
if (o.getClass().isArray())
{
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
if (!o.getClass().getComponentType().isPrimitive())
{
Object[] array = (Object[])o;
@ -978,11 +964,11 @@ public class Dump extends HttpServlet
private boolean dump(HttpServletResponse response, String data, String chars, String block, String dribble, boolean flush) throws IOException
{
if (data != null && data.length() > 0)
int len = (block != null && !block.isEmpty()) ? Integer.parseInt(block) : 50;
if (data != null && !data.isEmpty())
{
int b = (block != null && block.length() > 0) ? Integer.parseInt(block) : 50;
byte[] buf = new byte[b];
for (int i = 0; i < b; i++)
byte[] buf = new byte[len];
for (int i = 0; i < len; i++)
{
buf[i] = (byte)('0' + (i % 10));
@ -995,15 +981,15 @@ public class Dump extends HttpServlet
long d = Long.parseLong(data);
while (d > 0)
{
if (b == 1)
if (len == 1)
{
out.write(d % 80 == 0 ? '\n' : '.');
d--;
}
else if (d >= b)
else if (d >= len)
{
out.write(buf);
d = d - b;
d = d - len;
}
else
{
@ -1033,11 +1019,10 @@ public class Dump extends HttpServlet
}
// Handle a dump of data
if (chars != null && chars.length() > 0)
if (chars != null && !chars.isEmpty())
{
int b = (block != null && block.length() > 0) ? Integer.parseInt(block) : 50;
char[] buf = new char[b];
for (int i = 0; i < b; i++)
char[] buf = new char[len];
for (int i = 0; i < len; i++)
{
buf[i] = (char)('0' + (i % 10));
if (i % 10 == 9)
@ -1049,15 +1034,15 @@ public class Dump extends HttpServlet
long d = Long.parseLong(chars);
while (d > 0 && !out.checkError())
{
if (b == 1)
if (len == 1)
{
out.write(d % 80 == 0 ? '\n' : '.');
d--;
}
else if (d >= b)
else if (d >= len)
{
out.write(buf);
d = d - b;
d = d - len;
}
else
{

View File

@ -19,7 +19,7 @@ module org.eclipse.jetty.ee11.jndi
requires transitive java.naming;
// Only required if using MailSessionReference.
requires static jakarta.mail;
requires static transitive jakarta.mail;
exports org.eclipse.jetty.ee11.jndi.factories;
}

View File

@ -16,13 +16,13 @@ import org.eclipse.jetty.ee11.plus.webapp.PlusConfiguration;
module org.eclipse.jetty.ee11.plus
{
requires org.eclipse.jetty.plus;
requires transitive org.eclipse.jetty.plus;
requires org.slf4j;
requires transitive org.eclipse.jetty.ee11.webapp;
// Only required if using Transaction.
requires static jakarta.transaction;
requires static transitive jakarta.transaction;
exports org.eclipse.jetty.ee11.plus.jndi;
exports org.eclipse.jetty.ee11.plus.webapp;

View File

@ -16,8 +16,6 @@ package org.eclipse.jetty.ee11.plus.jndi;
import javax.naming.NamingException;
import jakarta.transaction.UserTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Transaction
@ -26,8 +24,6 @@ import org.slf4j.LoggerFactory;
*/
public class Transaction extends org.eclipse.jetty.plus.jndi.Transaction
{
private static final Logger LOG = LoggerFactory.getLogger(Transaction.class);
/**
* @param scope the scope, usually an environment like ee9, ee10, ee11
* @param userTransaction the UserTransaction

View File

@ -1,2 +1,2 @@
org.eclipse.jetty.ee11.plus.webapp.PlusConfiguration
org.eclipse.jetty.ee11.plus.webapp.EnvConfiguration
org.eclipse.jetty.ee11.plus.webapp.PlusConfiguration

View File

@ -13,7 +13,7 @@
module org.eclipse.jetty.ee11.proxy
{
requires jakarta.servlet;
requires transitive jakarta.servlet;
requires transitive org.eclipse.jetty.client;
requires transitive org.eclipse.jetty.server;
requires transitive org.slf4j;

View File

@ -11,6 +11,10 @@
// ========================================================================
//
import org.eclipse.jetty.ee11.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.ee11.quickstart.QuickStartGeneratorConfiguration;
import org.eclipse.jetty.ee11.webapp.Configuration;
module org.eclipse.jetty.ee11.quickstart
{
requires jakarta.servlet;
@ -19,4 +23,6 @@ module org.eclipse.jetty.ee11.quickstart
requires transitive org.eclipse.jetty.ee11.annotations;
exports org.eclipse.jetty.ee11.quickstart;
provides Configuration with QuickStartConfiguration, QuickStartGeneratorConfiguration;
}

View File

@ -56,6 +56,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.Blocker;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.ExceptionUtil;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.Resources;
@ -555,7 +556,16 @@ public class DefaultServlet extends HttpServlet
if (includedServletPath != null)
return encodePath(getIncludedPathInContext(req, includedServletPath, !isDefaultMapping(req)));
else if (!isDefaultMapping(req))
return encodePath(req.getPathInfo());
{
//a match via an extension mapping will more than likely
//have no path info
String path = req.getPathInfo();
if (StringUtil.isEmpty(path) &&
MappingMatch.EXTENSION.equals(req.getHttpServletMapping().getMappingMatch()))
path = req.getServletPath();
return encodePath(path);
}
else if (req instanceof ServletApiRequest apiRequest)
return Context.getPathInContext(req.getContextPath(), apiRequest.getRequest().getHttpURI().getCanonicalPath());
else

View File

@ -20,10 +20,10 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
@ -42,7 +42,6 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Response;
@ -69,17 +68,16 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class AsyncServletTest
{
protected AsyncServlet _servlet = new AsyncServlet();
protected int _port;
protected Server _server = new Server();
protected ServletHandler _servletHandler;
protected ErrorPageErrorHandler _errorHandler;
protected ServerConnector _connector;
protected List<String> _log;
protected int _expectedLogs;
protected String _expectedCode;
protected List<String> _history = new CopyOnWriteArrayList<>();
protected CountDownLatch _latch;
private final AsyncServlet _servlet = new AsyncServlet();
private int _port;
private final Server _server = new Server();
private ServletHandler _servletHandler;
private ErrorPageErrorHandler _errorHandler;
private List<String> _log;
private int _expectedLogs;
private String _expectedCode;
private final List<String> _history = new CopyOnWriteArrayList<>();
private CountDownLatch _latch;
private void historyAdd(String item)
{
@ -90,8 +88,8 @@ public class AsyncServletTest
@BeforeEach
public void setUp() throws Exception
{
_connector = new ServerConnector(_server);
_server.setConnectors(new Connector[]{_connector});
ServerConnector connector = new ServerConnector(_server);
_server.addConnector(connector);
_log = new ArrayList<>();
RequestLog log = new Log();
@ -128,7 +126,7 @@ public class AsyncServletTest
holder2.setAsyncSupported(false);
_servletHandler.addServletWithMapping(holder2, "/noasync/*");
_server.start();
_port = _connector.getLocalPort();
_port = connector.getLocalPort();
_history.clear();
_latch = new CountDownLatch(1);
}
@ -787,7 +785,7 @@ public class AsyncServletTest
private class AsyncServlet extends HttpServlet
{
private final Timer _timer = new Timer();
private final ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor();
@Override
public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
@ -889,28 +887,20 @@ public class AsyncServletTest
if (completeAfter > 0)
{
TimerTask complete = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
try
{
try
{
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
catch (Exception e)
{
e.printStackTrace();
}
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
};
synchronized (_timer)
{
_timer.schedule(complete, completeAfter);
}
catch (Exception e)
{
e.printStackTrace();
}
}, completeAfter, TimeUnit.MILLISECONDS);
}
else if (completeAfter == 0)
{
@ -921,28 +911,20 @@ public class AsyncServletTest
}
else if (dispatchAfter > 0)
{
TimerTask dispatch = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
historyAdd("dispatch");
if (path != null)
{
historyAdd("dispatch");
if (path != null)
{
int q = path.indexOf('?');
String uriInContext = (q >= 0)
? URIUtil.encodePath(path.substring(0, q)) + path.substring(q)
: URIUtil.encodePath(path);
async.dispatch(uriInContext);
}
else
async.dispatch();
int q = path.indexOf('?');
String uriInContext = (q >= 0)
? URIUtil.encodePath(path.substring(0, q)) + path.substring(q)
: URIUtil.encodePath(path);
async.dispatch(uriInContext);
}
};
synchronized (_timer)
{
_timer.schedule(dispatch, dispatchAfter);
}
else
async.dispatch();
}, dispatchAfter, TimeUnit.MILLISECONDS);
}
else if (dispatchAfter == 0)
{
@ -993,28 +975,20 @@ public class AsyncServletTest
if (complete2After > 0)
{
TimerTask complete = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
try
{
try
{
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
catch (Exception e)
{
e.printStackTrace();
}
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
};
synchronized (_timer)
{
_timer.schedule(complete, complete2After);
}
catch (Exception e)
{
e.printStackTrace();
}
}, complete2After, TimeUnit.MILLISECONDS);
}
else if (complete2After == 0)
{
@ -1025,19 +999,11 @@ public class AsyncServletTest
}
else if (dispatch2After > 0)
{
TimerTask dispatch = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
{
historyAdd("dispatch");
async.dispatch();
}
};
synchronized (_timer)
{
_timer.schedule(dispatch, dispatch2After);
}
historyAdd("dispatch");
async.dispatch();
}, dispatch2After, TimeUnit.MILLISECONDS);
}
else if (dispatch2After == 0)
{

View File

@ -3487,6 +3487,26 @@ public class DefaultServletTest
assertThat(response.getContent(), containsString("testPathInfoOnly-OK"));
}
@Test
public void testSuffixMappings() throws Exception
{
server.stop();
Path suffixroot = MavenTestingUtils.getTestResourcePath("suffixroot");
ResourceFactory resourceFactory = ResourceFactory.of(context);
context.setBaseResource(resourceFactory.newResource(suffixroot.toUri()));
ServletHolder holderAlt = new ServletHolder("static-js", DefaultServlet.class);
context.addServlet(holderAlt, "*.js");
ServletHolder holderDef = new ServletHolder("default", DefaultServlet.class);
holderDef.setInitParameter("dirAllowed", "true");
context.addServlet(holderDef, "/");
server.start();
String rawResponse = connector.getResponse("GET /context/test.js HTTP/1.0\r\n\r\n");
assertThat(rawResponse, containsString("Hello"));
}
@Test
public void testMemoryResourceRange() throws Exception
{

View File

@ -118,6 +118,60 @@ public class RequestTest
LifeCycle.stop(_server);
}
@Test
public void testCaseInsensitiveHeaders() throws Exception
{
final AtomicReference<Boolean> resultIsSecure = new AtomicReference<>();
startServer(new HttpServlet()
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp)
{
assertThat(request.getHeader("accept"), is("*/*"));
assertThat(request.getHeader("Accept"), is("*/*"));
assertThat(request.getHeader("ACCEPT"), is("*/*"));
assertThat(request.getHeader("AcCePt"), is("*/*"));
assertThat(request.getHeader("random"), is("value"));
assertThat(request.getHeader("Random"), is("value"));
assertThat(request.getHeader("RANDOM"), is("value"));
assertThat(request.getHeader("rAnDoM"), is("value"));
assertThat(request.getHeader("RaNdOm"), is("value"));
assertThat(request.getHeader("Accept-Charset"), is("UTF-8"));
assertThat(request.getHeader("accept-charset"), is("UTF-8"));
assertThat(Collections.list(request.getHeaders("Accept-Charset")), contains("UTF-8", "UTF-16"));
assertThat(Collections.list(request.getHeaders("accept-charset")), contains("UTF-8", "UTF-16"));
assertThat(request.getHeader("foo-bar"), is("one"));
assertThat(request.getHeader("Foo-Bar"), is("one"));
assertThat(Collections.list(request.getHeaders("foo-bar")), contains("one", "two"));
assertThat(Collections.list(request.getHeaders("Foo-Bar")), contains("one", "two"));
assertThat(Collections.list(request.getHeaderNames()),
contains("Host", "Connection", "Accept", "RaNdOm", "Accept-Charset", "Foo-Bar"));
}
});
String rawResponse = _connector.getResponse(
"""
GET / HTTP/1.1
Host: local
Connection: close
Accept: */*
RaNdOm: value
Accept-Charset: UTF-8
accept-charset: UTF-16
Foo-Bar: one
foo-bar: two
""");
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
assertThat(response.getStatus(), is(HttpStatus.OK_200));
}
@Test
public void testIsSecure() throws Exception
{

View File

@ -0,0 +1 @@
document.write("Hello");

View File

@ -26,7 +26,7 @@ module org.eclipse.jetty.ee11.servlets
requires static org.eclipse.jetty.http;
requires static org.eclipse.jetty.server;
// Only required if using CrossOriginFilter, DoSFilter, etc.
requires static org.eclipse.jetty.util;
requires static transitive org.eclipse.jetty.util;
exports org.eclipse.jetty.ee11.servlets;
}

View File

@ -1 +1 @@
org.eclipse.jetty.test.jmx.MyContainerInitializer
org.eclipse.jetty.ee11.test.jmx.MyContainerInitializer

View File

@ -1,7 +1,7 @@
org.eclipse.jetty.ee11.webapp.FragmentConfiguration
org.eclipse.jetty.ee11.webapp.JettyWebXmlConfiguration
org.eclipse.jetty.ee11.webapp.JaasConfiguration
org.eclipse.jetty.ee11.webapp.JaspiConfiguration
org.eclipse.jetty.ee11.webapp.JettyWebXmlConfiguration
org.eclipse.jetty.ee11.webapp.JmxConfiguration
org.eclipse.jetty.ee11.webapp.JndiConfiguration
org.eclipse.jetty.ee11.webapp.JspConfiguration

View File

@ -264,8 +264,11 @@ public class WebSocketOverHTTP2Test
startServer();
startClient(clientConnector -> new ClientConnectionFactoryOverHTTP2.HTTP2(new HTTP2Client(clientConnector)));
// Port 293 is not assigned by IANA, so
// it should be impossible to connect.
int nonExistingPort = 293;
EventSocket wsEndPoint = new EventSocket();
URI uri = URI.create("ws://localhost:" + (connector.getLocalPort() + 1) + "/ws/echo");
URI uri = URI.create("ws://localhost:" + nonExistingPort + "/ws/echo");
ExecutionException failure = Assertions.assertThrows(ExecutionException.class, () ->
wsClient.connect(wsEndPoint, uri).get(5, TimeUnit.SECONDS));

View File

@ -49,11 +49,6 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>

View File

@ -48,11 +48,6 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>

View File

@ -14,9 +14,9 @@
module org.eclipse.jetty.ee9.apache.jsp
{
requires java.xml;
requires jetty.servlet.api;
requires transitive jetty.servlet.api;
requires org.eclipse.jetty.util;
requires org.mortbay.apache.jasper;
requires transitive org.mortbay.apache.jasper;
requires org.slf4j;
exports org.eclipse.jetty.ee9.apache.jsp;

View File

@ -11,6 +11,11 @@
// ========================================================================
//
import jakarta.servlet.ServletContainerInitializer;
import org.eclipse.jetty.ee9.cdi.CdiConfiguration;
import org.eclipse.jetty.ee9.cdi.CdiServletContainerInitializer;
import org.eclipse.jetty.ee9.webapp.Configuration;
module org.eclipse.jetty.ee9.cdi
{
requires org.eclipse.jetty.ee9.annotations;
@ -18,4 +23,7 @@ module org.eclipse.jetty.ee9.cdi
requires transitive org.eclipse.jetty.ee9.webapp;
exports org.eclipse.jetty.ee9.cdi;
}
provides ServletContainerInitializer with CdiServletContainerInitializer;
provides Configuration with CdiConfiguration;
}

View File

@ -29,8 +29,9 @@ import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import jakarta.servlet.AsyncContext;
import jakarta.servlet.AsyncEvent;
@ -63,7 +64,7 @@ public class Dump extends HttpServlet
*/
private static final String ZWSP = "&#8203;";
boolean fixed;
Timer _timer;
ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor();
@Override
public void init(ServletConfig config) throws ServletException
@ -76,8 +77,6 @@ public class Dump extends HttpServlet
fixed = true;
throw new UnavailableException("Unavailable test", Integer.parseInt(config.getInitParameter("unavailable")));
}
_timer = new Timer(true);
}
@Override
@ -226,36 +225,25 @@ public class Dump extends HttpServlet
request.setAttribute("RESUME", Boolean.TRUE);
final long resume = Long.parseLong(request.getParameter("dispatch"));
_timer.schedule(new TimerTask()
{
@Override
public void run()
{
async.dispatch();
}
}, resume);
_scheduler.schedule(() -> async.dispatch(), resume, TimeUnit.MILLISECONDS);
}
if (request.getParameter("complete") != null)
{
final long complete = Long.parseLong(request.getParameter("complete"));
_timer.schedule(new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
try
{
try
{
response.setContentType("text/html");
response.getOutputStream().println("<h1>COMPLETED</h1>");
async.complete();
}
catch (Exception e)
{
e.printStackTrace();
}
response.setContentType("text/html");
response.getOutputStream().println("<h1>COMPLETED</h1>");
async.complete();
}
}, complete);
catch (Exception e)
{
e.printStackTrace();
}
}, complete, TimeUnit.MILLISECONDS);
}
return;
@ -915,7 +903,7 @@ public class Dump extends HttpServlet
@Override
public void destroy()
{
_timer.cancel();
_scheduler.shutdownNow();
}
private String getURI(HttpServletRequest request)

View File

@ -19,7 +19,7 @@ module org.eclipse.jetty.ee9.jndi
requires transitive java.naming;
// Only required if using MailSessionReference.
requires static jakarta.mail;
requires static transitive jakarta.mail;
exports org.eclipse.jetty.ee9.jndi.factories;
}

View File

@ -1,49 +0,0 @@
body {
background-color: #FFFFFF;
margin: 10px;
padding: 5px;
font-family: sans-serif;
}
h1.title {
text-shadow: #000000 -1px -1px 1px;
color: #FC390E;
font-weight: bold;
}
table.listing {
border: 0px;
}
thead a {
color: blue;
}
thead th {
border-bottom: black 1px solid;
}
.name, .lastmodified {
text-align: left;
padding-right: 15px;
}
.size {
text-align: right;
}
a {
color: #7036be;
font-weight: bold;
font-style: normal;
text-decoration: none;
font-size:inherit;
}
td {
font-style: italic;
padding: 2px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -23,7 +23,7 @@ module org.eclipse.jetty.ee9.plus
requires transitive org.eclipse.jetty.plus;
// Only required if using Transaction.
requires static jakarta.transaction;
requires static transitive jakarta.transaction;
exports org.eclipse.jetty.ee9.plus.jndi;
exports org.eclipse.jetty.ee9.plus.webapp;

View File

@ -1,2 +1,2 @@
org.eclipse.jetty.ee9.plus.webapp.PlusConfiguration
org.eclipse.jetty.ee9.plus.webapp.EnvConfiguration
org.eclipse.jetty.ee9.plus.webapp.PlusConfiguration

View File

@ -11,6 +11,10 @@
// ========================================================================
//
import org.eclipse.jetty.ee9.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.ee9.quickstart.QuickStartGeneratorConfiguration;
import org.eclipse.jetty.ee9.webapp.Configuration;
module org.eclipse.jetty.ee9.quickstart
{
requires jetty.servlet.api;
@ -19,4 +23,6 @@ module org.eclipse.jetty.ee9.quickstart
requires transitive org.eclipse.jetty.ee9.annotations;
exports org.eclipse.jetty.ee9.quickstart;
provides Configuration with QuickStartConfiguration, QuickStartGeneratorConfiguration;
}

View File

@ -19,10 +19,10 @@ import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import jakarta.servlet.AsyncContext;
@ -691,7 +691,7 @@ public class AsyncServletTest
private static class AsyncServlet extends HttpServlet
{
private static final long serialVersionUID = -8161977157098646562L;
private final Timer _timer = new Timer();
private final ScheduledExecutorService _scheduler = Executors.newSingleThreadScheduledExecutor();
@Override
public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
@ -797,28 +797,20 @@ public class AsyncServletTest
if (completeAfter > 0)
{
TimerTask complete = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
try
{
try
{
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
catch (Exception e)
{
e.printStackTrace();
}
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
};
synchronized (_timer)
{
_timer.schedule(complete, completeAfter);
}
catch (Exception e)
{
e.printStackTrace();
}
}, completeAfter, TimeUnit.MILLISECONDS);
}
else if (completeAfter == 0)
{
@ -829,28 +821,20 @@ public class AsyncServletTest
}
else if (dispatchAfter > 0)
{
TimerTask dispatch = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
historyAdd("dispatch");
if (path != null)
{
historyAdd("dispatch");
if (path != null)
{
int q = path.indexOf('?');
String uriInContext = (q >= 0)
? URIUtil.encodePath(path.substring(0, q)) + path.substring(q)
: URIUtil.encodePath(path);
async.dispatch(uriInContext);
}
else
async.dispatch();
int q = path.indexOf('?');
String uriInContext = (q >= 0)
? URIUtil.encodePath(path.substring(0, q)) + path.substring(q)
: URIUtil.encodePath(path);
async.dispatch(uriInContext);
}
};
synchronized (_timer)
{
_timer.schedule(dispatch, dispatchAfter);
}
else
async.dispatch();
}, dispatchAfter, TimeUnit.MILLISECONDS);
}
else if (dispatchAfter == 0)
{
@ -901,28 +885,20 @@ public class AsyncServletTest
if (complete2After > 0)
{
TimerTask complete = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
try
{
try
{
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
catch (Exception e)
{
e.printStackTrace();
}
response.setStatus(200);
response.getOutputStream().println("COMPLETED\n");
historyAdd("complete");
async.complete();
}
};
synchronized (_timer)
{
_timer.schedule(complete, complete2After);
}
catch (Exception e)
{
e.printStackTrace();
}
}, complete2After, TimeUnit.MILLISECONDS);
}
else if (complete2After == 0)
{
@ -933,19 +909,11 @@ public class AsyncServletTest
}
else if (dispatch2After > 0)
{
TimerTask dispatch = new TimerTask()
_scheduler.schedule(() ->
{
@Override
public void run()
{
historyAdd("dispatch");
async.dispatch();
}
};
synchronized (_timer)
{
_timer.schedule(dispatch, dispatch2After);
}
historyAdd("dispatch");
async.dispatch();
}, dispatch2After, TimeUnit.MILLISECONDS);
}
else if (dispatch2After == 0)
{

View File

@ -26,7 +26,7 @@ module org.eclipse.jetty.ee9.servlets
requires static org.eclipse.jetty.http;
requires static org.eclipse.jetty.server;
// Only required if using CrossOriginFilter, DoSFilter, etc.
requires static org.eclipse.jetty.util;
requires static transitive org.eclipse.jetty.util;
// Only required if using DataRateLimitedServlet
requires static org.eclipse.jetty.ee9.nested;

View File

@ -1 +1 @@
org.eclipse.jetty.test.jmx.MyContainerInitializer
org.eclipse.jetty.ee9.test.jmx.MyContainerInitializer

View File

@ -1,7 +1,7 @@
org.eclipse.jetty.ee9.webapp.FragmentConfiguration
org.eclipse.jetty.ee9.webapp.JettyWebXmlConfiguration
org.eclipse.jetty.ee9.webapp.JaasConfiguration
org.eclipse.jetty.ee9.webapp.JaspiConfiguration
org.eclipse.jetty.ee9.webapp.JettyWebXmlConfiguration
org.eclipse.jetty.ee9.webapp.JmxConfiguration
org.eclipse.jetty.ee9.webapp.JndiConfiguration
org.eclipse.jetty.ee9.webapp.JspConfiguration

View File

@ -248,8 +248,11 @@ public class WebSocketOverHTTP2Test
startServer();
startClient(clientConnector -> new ClientConnectionFactoryOverHTTP2.HTTP2(new HTTP2Client(clientConnector)));
// Port 293 is not assigned by IANA, so
// it should be impossible to connect.
int nonExistingPort = 293;
EventSocket wsEndPoint = new EventSocket();
URI uri = URI.create("ws://localhost:" + (connector.getLocalPort() + 1) + "/ws/echo");
URI uri = URI.create("ws://localhost:" + nonExistingPort + "/ws/echo");
ExecutionException failure = Assertions.assertThrows(ExecutionException.class, () ->
wsClient.connect(wsEndPoint, uri).get(5, TimeUnit.SECONDS));