Merge remote-tracking branch 'origin/jetty-12.0.x' into merge/jetty-12.1.x/update-from-12_0

This commit is contained in:
Ludovic Orban 2024-07-19 11:02:16 +02:00
commit 7b3e953e56
No known key found for this signature in database
GPG Key ID: 3D146A4A1C58367E
32 changed files with 585 additions and 109 deletions

View File

@ -212,6 +212,7 @@ updates:
versions: [ ">=12" ]
- dependency-name: "com.hazelcast:*"
- dependency-name: "org.apache.directory*"
- dependency-name: "org.apache.maven.plugin-tools:*"
- dependency-name: "org.apache.felix:*"
versions: [ ">=4" ]
- dependency-name: "org.jboss.weld.servlet:*"

2
.gitignore vendored
View File

@ -52,3 +52,5 @@ bin/
# reports
reports/
.launchable

38
Jenkinsfile vendored
View File

@ -9,6 +9,9 @@ pipeline {
buildDiscarder logRotator( numToKeepStr: '60' )
disableRestartFromStage()
}
environment {
LAUNCHABLE_TOKEN = credentials('launchable-token')
}
stages {
stage("Parallel Stage") {
parallel {
@ -62,6 +65,10 @@ pipeline {
}
fixed {
slackNotif()
websiteBuild()
}
success {
websiteBuild()
}
}
}
@ -118,6 +125,8 @@ def mavenBuild(jdk, cmdline, mvnName) {
extraArgs = " -Dmaven.test.failure.ignore=true "
}
}
runLaunchable ("verify")
runLaunchable ("record build --name jetty-12.0.x")
sh "mvn $extraArgs -DsettingsPath=$GLOBAL_MVN_SETTINGS -Dmaven.repo.uri=http://nexus-service.nexus.svc.cluster.local:8081/repository/maven-public/ -ntp -s $GLOBAL_MVN_SETTINGS -Dmaven.repo.local=.repository -Pci -V -B -e -U $cmdline"
if(saveHome()) {
archiveArtifacts artifacts: ".repository/org/eclipse/jetty/jetty-home/**/jetty-home-*", allowEmptyArchive: true, onlyIfSuccessful: false
@ -127,7 +136,9 @@ def mavenBuild(jdk, cmdline, mvnName) {
}
finally
{
junit testResults: '**/target/surefire-reports/**/*.xml,**/target/invoker-reports/TEST*.xml', allowEmptyResults: true
junit testDataPublishers: [[$class: 'JUnitFlakyTestDataPublisher']], testResults: '**/target/surefire-reports/**/*.xml,**/target/invoker-reports/TEST*.xml', allowEmptyResults: true
echo "Launchable record tests"
runLaunchable ("record tests --build jetty-12.0.x maven '**/target/surefire-reports/**/*.xml' '**/target/invoker-reports/TEST*.xml'")
}
}
}
@ -153,4 +164,29 @@ def saveHome() {
return false;
}
def websiteBuild() {
script {
try {
if (env.BRANCH_NAME == 'jetty-10.0.x' || env.BRANCH_NAME == 'jetty-11.0.x' || env.BRANCH_NAME == 'jetty-12.0.x') {
build(job: 'website/jetty.website/main', propagate: false, wait: false)
}
} catch (Exception e) {
e.printStackTrace()
echo "skip website build triggering: " + e.getMessage()
}
}
}
/**
* run launchable with args and ignore any errors
* @param args
*/
def runLaunchable(args) {
try {
sh "launchable $args"
} catch (Exception e) {
e.printStackTrace()
echo "skip failure running Launchable: " + e.getMessage()
}
}
// vim: et:ts=2:sw=2:ft=groovy

View File

@ -20,9 +20,9 @@ The following checklist is used to handle security issues:
- [ ] If the vulnerability cannot be confirmed then close the security advisory, else continue.
- [ ] Generate a CVE score and add it to the advisory description.
- [ ] Identify a CWE Definition and add it to the advisory description.
- [ ] Identify vulnerable version(s), including current and past versions that are affected (e.g. 9.4.0 through 9.4.35, and 10.0.0.alpha1 through 10.0.0.beta3…​etc.)
- [ ] Identify vulnerable version(s), including current and past versions that are affected (e.g. 9.4.0 through 9.4.35, and 10.0.0.alpha1 through 10.0.0.beta3 etc.)
- [ ] Identify and document workaround(s), if applicable, in the comments of the security advisory.
- [ ] Open an [Gitlab@Eclipse EMO CVE issue](https://gitlab.eclipse.org/eclipsefdn/emo-team/emo/-/issues/new?issuable_template=cve) to have a CVE allocated.
- [ ] Open an [Gitlab@Eclipse CVE Assignment](https://gitlab.eclipse.org/security/cve-assignement/-/issues/new) to have a CVE allocated.
The issue should be opened under the "Eclipse Foundation" > "EMO Team" > "EMO" section as a "cve" description, with the "This issue is confidential" checkbox checked.
Follow the template for what details are necessary to file for a CVE.
- [ ] Once the CVE is allocated update the Security Advisory with the number

View File

@ -18,7 +18,7 @@
<maven.javadoc.plugin.version>3.4.0</maven.javadoc.plugin.version>
<maven.javadoc.skip>true</maven.javadoc.skip>
<maven.remote-resources.plugin.version>3.2.0</maven.remote-resources.plugin.version>
<maven.surefire.plugin.version>3.2.5</maven.surefire.plugin.version>
<maven.surefire.plugin.version>3.3.1</maven.surefire.plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<skipTests>true</skipTests>
</properties>
@ -41,7 +41,7 @@
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.41.1</version>
<version>2.43.0</version>
<configuration>
<pom>
<includes>

View File

@ -75,7 +75,7 @@
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>h2spec-maven-plugin</artifactId>
<version>1.0.10</version>
<version>1.0.12</version>
<configuration>
<mainClass>org.eclipse.jetty.http2.tests.H2SpecServer</mainClass>
<skip>${h2spec.skip}</skip>

View File

@ -66,4 +66,25 @@
</dependency>
</dependencies>
<profiles>
<profile>
<id>enable-foreign</id>
<activation>
<jdk>[22,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine}
${jetty.surefire.argLine}
--enable-native-access=ALL-UNNAMED</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -38,6 +38,7 @@ import org.eclipse.jetty.http3.frames.SettingsFrame;
import org.eclipse.jetty.http3.server.AbstractHTTP3ServerConnectionFactory;
import org.eclipse.jetty.http3.server.internal.HTTP3SessionServer;
import org.eclipse.jetty.quic.client.ClientQuicSession;
import org.eclipse.jetty.quic.common.QuicErrorCode;
import org.eclipse.jetty.quic.common.QuicSession;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@ -640,4 +641,24 @@ public class ClientServerTest extends AbstractClientServerTest
assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
}
@Test
public void testMissingNeededClientCertificateDeniesConnection() throws Exception
{
start(new Session.Server.Listener() {});
connector.getQuicConfiguration().getSslContextFactory().setNeedClientAuth(true);
CountDownLatch latch = new CountDownLatch(1);
newSession(new Session.Client.Listener()
{
@Override
public void onDisconnect(Session session, long error, String reason)
{
assertEquals(QuicErrorCode.CONNECTION_REFUSED.code(), error);
assertEquals("missing_client_certificate_chain", reason);
latch.countDown();
}
});
assertTrue(latch.await(5, TimeUnit.SECONDS));
}
}

View File

@ -1150,7 +1150,7 @@ public class Content
@Deprecated(forRemoval = true, since = "12.1.0")
default Chunk asReadOnly()
{
if (getByteBuffer().isReadOnly())
if (!getByteBuffer().hasRemaining() || getByteBuffer().isReadOnly())
return this;
if (canRetain())
return asChunk(getByteBuffer().asReadOnlyBuffer(), isLast(), this);

View File

@ -73,7 +73,7 @@
<configuration>
<argLine>@{argLine}
${jetty.surefire.argLine}
--enable-native-access org.eclipse.jetty.quic.quiche.foreign</argLine>
--enable-native-access=ALL-UNNAMED</argLine>
</configuration>
</plugin>
</plugins>

View File

@ -74,6 +74,12 @@ public class ClientQuicSession extends QuicSession
return new ClientProtocolSession(this);
}
@Override
protected boolean validateNewlyEstablishedConnection()
{
return true;
}
@Override
public Connection newConnection(QuicStreamEndPoint endPoint)
{

View File

@ -319,6 +319,9 @@ public abstract class QuicSession extends ContainerLifeCycle
ProtocolSession protocol = protocolSession;
if (protocol == null)
{
if (!validateNewlyEstablishedConnection())
return null;
protocolSession = protocol = createProtocolSession();
addManaged(protocol);
}
@ -343,6 +346,11 @@ public abstract class QuicSession extends ContainerLifeCycle
protected abstract ProtocolSession createProtocolSession();
/**
* @return true if the connection is valid, false otherwise.
*/
protected abstract boolean validateNewlyEstablishedConnection();
List<Long> getWritableStreamIds()
{
return quicheConnection.writableStreamIds();

View File

@ -42,7 +42,6 @@ public class QuicStreamEndPoint extends AbstractEndPoint
{
private static final Logger LOG = LoggerFactory.getLogger(QuicStreamEndPoint.class);
private static final ByteBuffer LAST_FLAG = ByteBuffer.allocate(0);
private static final ByteBuffer EMPTY_WRITABLE_BUFFER = ByteBuffer.allocate(0);
private final QuicSession session;
private final long streamId;
@ -272,7 +271,7 @@ public class QuicStreamEndPoint extends AbstractEndPoint
// Check if the stream was finished normally.
try
{
fill(EMPTY_WRITABLE_BUFFER);
fill(BufferUtil.EMPTY_BUFFER);
}
catch (EOFException x)
{

View File

@ -80,6 +80,9 @@ public class PemExporter
try (OutputStream os = Files.newOutputStream(paths[1]))
{
Certificate[] certChain = keyStore.getCertificateChain(alias);
if (certChain == null)
throw new IllegalArgumentException("Alias does not exist in key store: " + alias);
for (Certificate cert : certChain)
writeAsPEM(os, cert);
Files.setPosixFilePermissions(paths[1], Set.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE));

View File

@ -71,6 +71,11 @@ public class ServerQuicConnection extends QuicConnection
return connector;
}
ServerQuicConfiguration getQuicConfiguration()
{
return quicConfiguration;
}
@Override
public void onOpen()
{

View File

@ -25,7 +25,7 @@ import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.CyclicTimeouts;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.quic.common.ProtocolSession;
import org.eclipse.jetty.quic.common.QuicConnection;
import org.eclipse.jetty.quic.common.QuicErrorCode;
import org.eclipse.jetty.quic.common.QuicSession;
import org.eclipse.jetty.quic.common.QuicStreamEndPoint;
import org.eclipse.jetty.quic.quiche.QuicheConnection;
@ -46,7 +46,7 @@ public class ServerQuicSession extends QuicSession implements CyclicTimeouts.Exp
private final Connector connector;
private long expireNanoTime = Long.MAX_VALUE;
public ServerQuicSession(Executor executor, Scheduler scheduler, ByteBufferPool bufferPool, QuicheConnection quicheConnection, QuicConnection connection, SocketAddress remoteAddress, Connector connector)
public ServerQuicSession(Executor executor, Scheduler scheduler, ByteBufferPool bufferPool, QuicheConnection quicheConnection, ServerQuicConnection connection, SocketAddress remoteAddress, Connector connector)
{
super(executor, scheduler, bufferPool, quicheConnection, connection, remoteAddress);
this.connector = connector;
@ -67,6 +67,18 @@ public class ServerQuicSession extends QuicSession implements CyclicTimeouts.Exp
return new ServerProtocolSession(this);
}
@Override
protected boolean validateNewlyEstablishedConnection()
{
if (getQuicConnection().getQuicConfiguration().getSslContextFactory().getNeedClientAuth() && getPeerCertificates() == null)
{
outwardClose(QuicErrorCode.CONNECTION_REFUSED.code(), "missing_client_certificate_chain");
flush();
return false;
}
return true;
}
@Override
public Connection newConnection(QuicStreamEndPoint endPoint)
{

View File

@ -14,7 +14,6 @@
package org.eclipse.jetty.server;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
@ -22,13 +21,13 @@ import javax.net.ssl.SSLEngineResult;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.BufferUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class NegotiatingServerConnection extends AbstractConnection
{
private static final Logger LOG = LoggerFactory.getLogger(NegotiatingServerConnection.class);
private static final ByteBuffer EMPTY_WRITABLE_BUFFER = ByteBuffer.allocate(0);
public interface CipherDiscriminator
{
@ -145,7 +144,7 @@ public abstract class NegotiatingServerConnection extends AbstractConnection
{
try
{
return getEndPoint().fill(EMPTY_WRITABLE_BUFFER);
return getEndPoint().fill(BufferUtil.EMPTY_BUFFER);
}
catch (IOException x)
{

View File

@ -324,11 +324,7 @@ public class GzipResponseAndCallback extends Response.Wrapper implements Callbac
@Override
protected void onCompleteFailure(Throwable x)
{
if (_deflaterEntry != null)
{
_deflaterEntry.release();
_deflaterEntry = null;
}
cleanup();
super.onCompleteFailure(x);
}
@ -381,6 +377,7 @@ public class GzipResponseAndCallback extends Response.Wrapper implements Callbac
{
if (_deflaterEntry != null)
{
_state.set(GZState.FINISHED);
_deflaterEntry.release();
_deflaterEntry = null;
}

View File

@ -49,6 +49,7 @@ import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.Context;
import org.eclipse.jetty.server.FormFields;
import org.eclipse.jetty.server.Handler;
@ -59,6 +60,7 @@ import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenPaths;
@ -194,6 +196,64 @@ public class GzipHandlerTest
_gzipHandler.setHandler(_contextHandler);
}
@Test
public void testFailureDuringGzipWrite() throws Exception
{
Handler leafHandler = new Handler.Abstract()
{
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{
try (var out = Content.Sink.asOutputStream(response))
{
out.write("Hello, Jetty".getBytes(StandardCharsets.UTF_8));
}
return true;
}
};
Handler rootHandler = new Handler.Wrapper(new GzipHandler(leafHandler))
{
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{
return super.handle(request, new Response.Wrapper(request, response)
{
@Override
public void write(boolean last, ByteBuffer byteBuffer, Callback callback)
{
throw new ArithmeticException("expected");
}
}, callback);
}
};
_server.setHandler(rootHandler);
ErrorHandler errorHandler = new ErrorHandler();
errorHandler.setShowStacks(true);
errorHandler.setShowCauses(true);
_server.setErrorHandler(errorHandler);
_server.start();
// generated and parsed test
HttpTester.Request request = HttpTester.newRequest();
HttpTester.Response response;
request.setMethod("GET");
request.setURI("/");
request.setVersion("HTTP/1.0");
request.setHeader("Host", "tester");
request.setHeader("accept-encoding", "gzip");
try (StacklessLogging ignore = new StacklessLogging(Response.class))
{
response = HttpTester.parseResponse(_connector.getResponse(request.generate()));
}
assertThat(response.getStatus(), is(500));
String content = response.getContent();
assertThat(content, containsString("ArithmeticException: expected"));
assertThat(content, not(containsString("Suppressed: ")));
}
@Test
public void testAddIncludePaths()
{

View File

@ -656,15 +656,15 @@ public class StartArgs
cmd.addArg(propPath.toAbsolutePath().toString());
}
for (Path xml : jettyEnvironment.getXmlFiles())
{
cmd.addArg(xml.toAbsolutePath().toString());
}
for (Path propertyFile : jettyEnvironment.getPropertyFiles())
{
cmd.addArg(propertyFile.toAbsolutePath().toString());
}
for (Path xml : jettyEnvironment.getXmlFiles())
{
cmd.addArg(xml.toAbsolutePath().toString());
}
}
if (parts.contains("envs"))

View File

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

View File

@ -191,7 +191,7 @@ public class Fields implements Iterable<Fields.Field>
public void put(String name, String value)
{
// Preserve the case for the field name
Field field = new Field(name, value);
Field field = new Field(name, StringUtil.nonNull(value));
fields.put(name, field);
}
@ -222,9 +222,9 @@ public class Fields implements Iterable<Fields.Field>
{
if (f == null)
// Preserve the case for the field name
return new Field(name, value);
return new Field(name, StringUtil.nonNull(value));
else
return new Field(f.getName(), f.getValues(), value);
return new Field(f.getName(), f.getValues(), StringUtil.nonNull(value));
});
}
@ -246,9 +246,9 @@ public class Fields implements Iterable<Fields.Field>
fields.compute(name, (k, f) ->
{
if (f == null)
return new Field(name, List.of(values));
return new Field(name, StringUtil.toListNonNull(values));
else
return new Field(f.getName(), f.getValues(), List.of(values));
return new Field(f.getName(), f.getValues(), StringUtil.toListNonNull(values));
});
}
}

View File

@ -540,6 +540,23 @@ public class StringUtil
return s;
}
/**
* Convert an array of strings to a list of non-null strings.
*
* @param strings the array
* @return The list of non-null strings.
* @see #nonNull(String)
*/
public static List<String> toListNonNull(String... strings)
{
List<String> result = new ArrayList<>(strings.length);
for (String s : strings)
{
result.add(nonNull(s));
}
return result;
}
public static boolean equals(String s, char[] buf, int offset, int length)
{
if (s.length() != length)

View File

@ -82,4 +82,18 @@ public class FieldsTest
assertThat(set, containsInAnyOrder("x", "y", "z"));
}
@Test
public void testNullValues()
{
Fields fields = new Fields();
fields.add("x", (String)null);
fields.add("y", "1", null, "2");
fields.put("z", null);
assertThat(fields.getSize(), equalTo(3));
assertThat(fields.getValues("x"), contains(""));
assertThat(fields.getValues("y"), contains("1", "", "2"));
assertThat(fields.getValues("z"), contains(""));
}
}

View File

@ -19,7 +19,7 @@
<dependency>
<groupId>org.hibernate.search</groupId>
<artifactId>hibernate-search-mapper-pojo-base</artifactId>
<version>7.1.0.Final</version>
<version>7.1.1.Final</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>

View File

@ -632,7 +632,7 @@ public class MultiPartFormInputStream implements MultiPart.Parser
if (parser.getState() != MultiPartParser.State.END)
{
if (parser.getState() == MultiPartParser.State.PREAMBLE)
_err = new IOException("Missing initial multi part boundary");
_err = new IOException("Missing content for multipart request");
else
_err = new IOException("Incomplete Multipart");
}

View File

@ -65,10 +65,11 @@ import org.slf4j.LoggerFactory;
*
* @deprecated Replaced by {@link MultiPartFormInputStream}.
* This code is slower and subject to more bugs than its replacement {@link MultiPartFormInputStream}. However,
* this class accepts formats non-compliant the RFC that the new {@link MultiPartFormInputStream} does not accept.
* this class accepts non-compliant RFC formats that the new {@link MultiPartFormInputStream} does not accept.
* This class is unavailable on <em>ee10</em> and newer environments.
*/
@Deprecated
class MultiPartInputStreamLegacyParser implements MultiPart.Parser
@Deprecated (forRemoval = true, since = "10.0.10")
public class MultiPartInputStreamLegacyParser implements MultiPart.Parser
{
private static final Logger LOG = LoggerFactory.getLogger(MultiPartInputStreamLegacyParser.class);
public static final MultipartConfigElement __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir"));
@ -598,7 +599,7 @@ class MultiPartInputStreamLegacyParser implements MultiPart.Parser
}
if (line == null || line.length() == 0)
throw new IOException("Missing initial multi part boundary");
throw new IOException("Missing content for multipart request");
// Empty multipart.
if (line.equals(lastBoundary))
@ -699,7 +700,7 @@ class MultiPartInputStreamLegacyParser implements MultiPart.Parser
// Check if we can create a new part.
_numParts++;
if (_maxParts >= 0 && _numParts > _maxParts)
throw new IllegalStateException(String.format("Form with too many parts [%d > %d]", _numParts, _maxParts));
throw new IllegalStateException(String.format("Form with too many keys [%d > %d]", _numParts, _maxParts));
//Have a new Part
MultiPart part = new MultiPart(name, filename);
@ -863,7 +864,7 @@ class MultiPartInputStreamLegacyParser implements MultiPart.Parser
MultiPartCompliance.Violation.LF_LINE_TERMINATION, "0x10"));
}
else
throw new IOException("Incomplete parts");
throw new IOException("Incomplete Multipart");
}
catch (Exception e)
{

View File

@ -515,7 +515,7 @@ public class Request implements HttpServletRequest
String msg = "Unable to extract content parameters";
if (LOG.isDebugEnabled())
LOG.debug(msg, e);
throw new RuntimeIOException(msg, e);
throw new BadMessageException(msg, e);
}
}
}
@ -2044,7 +2044,16 @@ public class Request implements HttpServletRequest
MultiPartCompliance multiPartCompliance = getHttpChannel().getHttpConfiguration().getMultiPartCompliance();
_multiParts = newMultiParts(multiPartCompliance, config, maxFormKeys);
Collection<Part> parts = _multiParts.getParts();
Collection<Part> parts;
try
{
parts = _multiParts.getParts();
}
catch (IOException e)
{
throw new BadMessageException("Unable to parse form content", e);
}
reportComplianceViolations();
String formCharset = null;

View File

@ -24,6 +24,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.zip.GZIPInputStream;
import jakarta.servlet.MultipartConfigElement;
@ -49,15 +50,20 @@ import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.MultiPart;
import org.eclipse.jetty.http.MultiPartCompliance;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.logging.StacklessLogging;
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.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.util.IO;
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.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
@ -130,14 +136,15 @@ public class MultiPartServletTest
}
}
@BeforeEach
public void start() throws Exception
private void startServer(MultiPartCompliance multiPartCompliance) throws Exception
{
tmpDir = Files.createTempDirectory(MultiPartServletTest.class.getSimpleName());
assertNotNull(tmpDir);
server = new Server();
connector = new ServerConnector(server);
HttpConfiguration httpConfiguration = new HttpConfiguration();
httpConfiguration.setMultiPartCompliance(multiPartCompliance);
connector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
server.addConnector(connector);
MultipartConfigElement config = new MultipartConfigElement(tmpDir.toAbsolutePath().toString(),
@ -180,9 +187,50 @@ public class MultiPartServletTest
IO.delete(tmpDir.toFile());
}
@Test
public void testLargePart() throws Exception
public static Stream<Arguments> multipartModes()
{
return Stream.of(
Arguments.of(MultiPartCompliance.RFC7578),
Arguments.of(MultiPartCompliance.LEGACY)
);
}
/**
* The request indicates that it is a multipart/form-data, but no body is sent.
*/
@ParameterizedTest
@MethodSource("multipartModes")
public void testEmptyBodyMultipartForm(MultiPartCompliance multiPartCompliance) throws Exception
{
startServer(multiPartCompliance);
String contentType = "multipart/form-data; boundary=---------------boundaryXYZ123";
StringRequestContent emptyContent = new StringRequestContent(contentType, "");
InputStreamResponseListener listener = new InputStreamResponseListener();
client.newRequest("localhost", connector.getLocalPort())
.path("/defaultConfig")
.scheme(HttpScheme.HTTP.asString())
.method(HttpMethod.POST)
.body(emptyContent)
.send(listener);
Response response = listener.get(60, TimeUnit.SECONDS);
assertThat(response.getStatus(), equalTo(HttpStatus.BAD_REQUEST_400));
assert400orEof(listener, responseContent ->
{
assertThat(responseContent, containsString("Unable to parse form content"));
assertThat(responseContent, containsString("Missing content for multipart request"));
});
}
@ParameterizedTest
@MethodSource("multipartModes")
public void testLargePart(MultiPartCompliance multiPartCompliance) throws Exception
{
startServer(multiPartCompliance);
OutputStreamRequestContent content = new OutputStreamRequestContent();
MultiPartRequestContent multiPart = new MultiPartRequestContent();
multiPart.addPart(new MultiPart.ContentSourcePart("param", null, null, content));
@ -212,9 +260,122 @@ public class MultiPartServletTest
});
}
@Test
public void testManyParts() throws Exception
@ParameterizedTest
@MethodSource("multipartModes")
public void testIncompleteMultipart(MultiPartCompliance multiPartCompliance) throws Exception
{
startServer(multiPartCompliance);
String contentType = "multipart/form-data; boundary=-------------------------7e21c038151054";
String incompleteForm = """
---------------------------7e21c038151054
Content-Disposition: form-data; name="description"
Some data, but incomplete
---------------------------7e21c038151054
Content-Disposition: form-d"""; // intentionally incomplete
StringRequestContent incomplete = new StringRequestContent(
contentType,
incompleteForm
);
InputStreamResponseListener listener = new InputStreamResponseListener();
client.newRequest("localhost", connector.getLocalPort())
.path("/defaultConfig")
.scheme(HttpScheme.HTTP.asString())
.method(HttpMethod.POST)
.body(incomplete)
.send(listener);
assert400orEof(listener, responseContent ->
{
assertThat(responseContent, containsString("Unable to parse form content"));
assertThat(responseContent, containsString("Incomplete Multipart"));
});
}
@ParameterizedTest
@MethodSource("multipartModes")
public void testLineFeedCarriageReturnEOL(MultiPartCompliance multiPartCompliance) throws Exception
{
startServer(multiPartCompliance);
String contentType = "multipart/form-data; boundary=---------------------------7e25e1e151054";
String rawForm = """
-----------------------------7e25e1e151054\r
Content-Disposition: form-data; name="user"\r
\r
anotheruser\r
-----------------------------7e25e1e151054\r
Content-Disposition: form-data; name="comment"\r
\r
with something to say\r
-----------------------------7e25e1e151054--\r
""";
StringRequestContent form = new StringRequestContent(
contentType,
rawForm
);
InputStreamResponseListener listener = new InputStreamResponseListener();
client.newRequest("localhost", connector.getLocalPort())
.path("/defaultConfig")
.scheme(HttpScheme.HTTP.asString())
.method(HttpMethod.POST)
.body(form)
.send(listener);
assert400orEof(listener, responseContent ->
{
assertThat(responseContent, containsString("Unable to parse form content"));
if (multiPartCompliance == MultiPartCompliance.RFC7578)
{
assertThat(responseContent, containsString("Illegal character ALPHA=&apos;s&apos"));
}
else if (multiPartCompliance == MultiPartCompliance.LEGACY)
{
assertThat(responseContent, containsString("Incomplete Multipart"));
}
});
}
@ParameterizedTest
@MethodSource("multipartModes")
public void testAllWhitespaceForm(MultiPartCompliance multiPartCompliance) throws Exception
{
startServer(multiPartCompliance);
String contentType = "multipart/form-data; boundary=----WebKitFormBoundaryjwqONTsAFgubfMZc";
String rawForm = " \n \n \n \n \n \n \n \n \n ";
StringRequestContent form = new StringRequestContent(
contentType,
rawForm
);
InputStreamResponseListener listener = new InputStreamResponseListener();
client.newRequest("localhost", connector.getLocalPort())
.path("/defaultConfig")
.scheme(HttpScheme.HTTP.asString())
.method(HttpMethod.POST)
.body(form)
.send(listener);
assert400orEof(listener, responseContent ->
{
assertThat(responseContent, containsString("Unable to parse form content"));
assertThat(responseContent, containsString("Missing content for multipart request"));
});
}
@ParameterizedTest
@MethodSource("multipartModes")
public void testManyParts(MultiPartCompliance multiPartCompliance) throws Exception
{
startServer(multiPartCompliance);
byte[] byteArray = new byte[1024];
Arrays.fill(byteArray, (byte)1);
@ -241,9 +402,12 @@ public class MultiPartServletTest
});
}
@Test
public void testMaxRequestSize() throws Exception
@ParameterizedTest
@MethodSource("multipartModes")
public void testMaxRequestSize(MultiPartCompliance multiPartCompliance) throws Exception
{
startServer(multiPartCompliance);
OutputStreamRequestContent content = new OutputStreamRequestContent();
MultiPartRequestContent multiPart = new MultiPartRequestContent();
multiPart.addPart(new MultiPart.ContentSourcePart("param", null, null, content));
@ -301,9 +465,12 @@ public class MultiPartServletTest
checkbody.accept(responseContent);
}
@Test
public void testTempFilesDeletedOnError() throws Exception
@ParameterizedTest
@MethodSource("multipartModes")
public void testTempFilesDeletedOnError(MultiPartCompliance multiPartCompliance) throws Exception
{
startServer(multiPartCompliance);
byte[] byteArray = new byte[LARGE_MESSAGE_SIZE];
Arrays.fill(byteArray, (byte)1);
BytesRequestContent content = new BytesRequestContent(byteArray);
@ -333,6 +500,8 @@ public class MultiPartServletTest
@Test
public void testMultiPartGzip() throws Exception
{
startServer(MultiPartCompliance.RFC7578);
String contentString = "the quick brown fox jumps over the lazy dog, " +
"the quick brown fox jumps over the lazy dog";
StringRequestContent content = new StringRequestContent(contentString);
@ -357,12 +526,14 @@ public class MultiPartServletTest
assertThat(headers.get(HttpHeader.CONTENT_TYPE), startsWith("multipart/form-data"));
assertThat(headers.get(HttpHeader.CONTENT_ENCODING), is("gzip"));
InputStream inputStream = new GZIPInputStream(responseStream.getInputStream());
String contentType = headers.get(HttpHeader.CONTENT_TYPE);
MultiPartFormInputStream mpis = new MultiPartFormInputStream(inputStream, contentType, null, null);
List<Part> parts = new ArrayList<>(mpis.getParts());
assertThat(parts.size(), is(1));
assertThat(IO.toString(parts.get(0).getInputStream()), is(contentString));
try (InputStream inputStream = new GZIPInputStream(responseStream.getInputStream()))
{
String contentType = headers.get(HttpHeader.CONTENT_TYPE);
MultiPartFormInputStream mpis = new MultiPartFormInputStream(inputStream, contentType, null, null);
List<Part> parts = new ArrayList<>(mpis.getParts());
assertThat(parts.size(), is(1));
assertThat(IO.toString(parts.get(0).getInputStream()), is(contentString));
}
}
}
}

51
jetty-p2/pom.xml Normal file
View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>12.0.12-SNAPSHOT</version>
</parent>
<artifactId>jetty-p2</artifactId>
<packaging>pom</packaging>
<name>Jetty :: P2</name>
<description>Generates a (maven based) P2 Updatesite</description>
<properties>
<enforcer.skip>true</enforcer.skip>
<tycho-version>4.0.8</tycho-version>
</properties>
<dependencies>
<!-- This dependency is to make sure this projects is build after all relevant
artifacts are created -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-home</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-p2-repository-plugin</artifactId>
<version>${tycho-version}</version>
<executions>
<execution>
<id>maven-p2-site</id>
<goals>
<goal>assemble-maven-repository</goal>
</goals>
<phase>prepare-package</phase>
<configuration>
<categoryName>Jetty Bundles</categoryName>
<includeReactor>true</includeReactor>
<includeDependencies>false</includeDependencies>
<includePGPSignature>true</includePGPSignature>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

140
pom.xml
View File

@ -8,7 +8,7 @@
<packaging>pom</packaging>
<name>Jetty :: Project</name>
<description>The Eclipse Jetty Project</description>
<url>https://eclipse.dev/jetty</url>
<url>https://jetty.org</url>
<inceptionYear>1995</inceptionYear>
<organization>
@ -133,6 +133,7 @@
<module>tests</module>
<module>javadoc</module>
<module>documentation</module>
<module>jetty-p2</module>
</modules>
<scm>
@ -167,25 +168,26 @@
<apache.httpcore.version>4.4.16</apache.httpcore.version>
<asciidoctor.maven.plugin.version>3.0.0</asciidoctor.maven.plugin.version>
<asciidoctor.skip>false</asciidoctor.skip>
<asciidoctorj-diagram.version>2.3.0</asciidoctorj-diagram.version>
<asciidoctorj-diagram.version>2.3.1</asciidoctorj-diagram.version>
<asciidoctorj.version>3.0.0-alpha.2</asciidoctorj.version>
<asm.version>9.7</asm.version>
<awaitility.version>4.2.1</awaitility.version>
<bndlib.version>7.0.0</bndlib.version>
<build-helper.maven.plugin.version>3.5.0</build-helper.maven.plugin.version>
<build-helper.maven.plugin.version>3.6.0</build-helper.maven.plugin.version>
<build-support.version>1.5</build-support.version>
<buildnumber.maven.plugin.version>3.2.0</buildnumber.maven.plugin.version>
<checkstyle.version>10.15.0</checkstyle.version>
<commons-codec.version>1.16.1</commons-codec.version>
<checkstyle.version>10.17.0</checkstyle.version>
<commons-codec.version>1.17.0</commons-codec.version>
<commons-lang3.version>3.14.0</commons-lang3.version>
<commons.compress.version>1.26.1</commons.compress.version>
<commons.io.version>2.16.0</commons.io.version>
<commons.compress.version>1.26.2</commons.compress.version>
<commons.io.version>2.16.1</commons.io.version>
<compiler.release>17</compiler.release>
<compiler.source>17</compiler.source>
<compiler.target>17</compiler.target>
<conscrypt.version>2.5.2</conscrypt.version>
<cyclonedx.maven.plugin.version>2.8.0</cyclonedx.maven.plugin.version>
<depends.maven.plugin.version>1.5.0</depends.maven.plugin.version>
<duplicate-finder-maven-plugin.version>2.0.1</duplicate-finder-maven-plugin.version>
<eclipse.jdt.ecj.version>3.38.0</eclipse.jdt.ecj.version>
<ee10.jakarta.activation.api.version>2.1.3</ee10.jakarta.activation.api.version>
@ -282,31 +284,31 @@
<felix.version>7.0.5</felix.version>
<findbugs.jsr305.version>3.0.2</findbugs.jsr305.version>
<flatten.maven.plugin.version>1.6.0</flatten.maven.plugin.version>
<google.errorprone.version>2.26.1</google.errorprone.version>
<google.errorprone.version>2.28.0</google.errorprone.version>
<groovy.version>4.0.6</groovy.version>
<grpc.version>1.63.0</grpc.version>
<gson.version>2.10.1</gson.version>
<guava.version>33.1.0-jre</guava.version>
<grpc.version>1.65.0</grpc.version>
<gson.version>2.11.0</gson.version>
<guava.version>33.2.1-jre</guava.version>
<guice.version>7.0.0</guice.version>
<h2spec.maven.plugin.version>1.0.11</h2spec.maven.plugin.version>
<h2spec.maven.plugin.version>1.0.12</h2spec.maven.plugin.version>
<hamcrest.version>2.2</hamcrest.version>
<hazelcast.version>5.4.0</hazelcast.version>
<hibernate.search.version>7.1.1.Final</hibernate.search.version>
<infinispan.docker.image.name>infinispan/server</infinispan.docker.image.name>
<infinispan.docker.image.version>15.0.5.Final</infinispan.docker.image.version>
<infinispan.protostream.version>5.0.4.Final</infinispan.protostream.version>
<infinispan.protostream.version>5.0.5.Final</infinispan.protostream.version>
<infinispan.version>15.0.5.Final</infinispan.version>
<injection.bundle.version>1.2</injection.bundle.version>
<invoker.mergeUserSettings>false</invoker.mergeUserSettings>
<it.debug>false</it.debug>
<jackson.version>2.17.0</jackson.version>
<jackson.version>2.17.1</jackson.version>
<jacoco.maven.plugin.version>0.8.12</jacoco.maven.plugin.version>
<javadoc.verbose>false</javadoc.verbose>
<jboss-logmanager.version>3.0.5.Final</jboss-logmanager.version>
<jboss-threads.version>3.6.1.Final</jboss-threads.version>
<jboss.logging.annotations.version>2.2.1.Final</jboss.logging.annotations.version>
<jboss.logging.processor.version>2.2.1.Final</jboss.logging.processor.version>
<jboss.logging.version>3.5.3.Final</jboss.logging.version>
<jboss.logging.version>3.6.0.Final</jboss.logging.version>
<jetty-assembly-descriptors.version>1.1</jetty-assembly-descriptors.version>
<jetty-quiche-native.version>0.22.0</jetty-quiche-native.version>
<jetty-test-policy.version>1.2</jetty-test-policy.version>
@ -332,41 +334,41 @@
<junit.jupiter.execution.parallel.mode.classes.default>concurrent</junit.jupiter.execution.parallel.mode.classes.default>
<junit.jupiter.execution.parallel.mode.default>same_thread</junit.jupiter.execution.parallel.mode.default>
<junit.jupiter.extensions.autodetection.enabled>true</junit.jupiter.extensions.autodetection.enabled>
<junit.version>5.10.2</junit.version>
<junit.version>5.10.3</junit.version>
<kerb-simplekdc.version>2.0.3</kerb-simplekdc.version>
<license.maven.plugin.version>4.3</license.maven.plugin.version>
<license.maven.plugin.version>4.5</license.maven.plugin.version>
<localRepoPath>${project.build.directory}/local-repo</localRepoPath>
<log4j2.version>2.23.1</log4j2.version>
<logback.version>1.5.6</logback.version>
<lucene.version>9.9.2</lucene.version>
<mariadb.docker.version>10.3.6</mariadb.docker.version>
<mariadb.version>3.3.3</mariadb.version>
<mariadb.version>3.4.0</mariadb.version>
<maven-artifact-transfer.version>0.13.1</maven-artifact-transfer.version>
<maven-build-cache.version>1.1.0</maven-build-cache.version>
<maven-plugin.plugin.version>3.12.0</maven-plugin.plugin.version>
<maven-build-cache.version>1.2.0</maven-build-cache.version>
<maven-plugin.plugin.version>3.13.1</maven-plugin.plugin.version>
<maven.antrun.plugin.version>3.1.0</maven.antrun.plugin.version>
<maven.assembly.plugin.version>3.7.1</maven.assembly.plugin.version>
<maven.bundle.plugin.version>5.1.9</maven.bundle.plugin.version>
<maven.checkstyle.plugin.version>3.3.1</maven.checkstyle.plugin.version>
<maven.clean.plugin.version>3.3.2</maven.clean.plugin.version>
<maven.checkstyle.plugin.version>3.4.0</maven.checkstyle.plugin.version>
<maven.clean.plugin.version>3.4.0</maven.clean.plugin.version>
<maven.compiler.createMissingPackageInfoClass>false</maven.compiler.createMissingPackageInfoClass>
<maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
<maven.dependency.plugin.version>3.6.1</maven.dependency.plugin.version>
<maven.deploy.plugin.version>3.1.1</maven.deploy.plugin.version>
<maven.deps.version>3.9.6</maven.deps.version>
<maven.enforcer.plugin.version>3.4.1</maven.enforcer.plugin.version>
<maven.exec.plugin.version>3.2.0</maven.exec.plugin.version>
<maven.gpg.plugin.version>3.2.2</maven.gpg.plugin.version>
<maven.install.plugin.version>3.1.1</maven.install.plugin.version>
<maven.invoker.plugin.version>3.6.1</maven.invoker.plugin.version>
<maven.jar.plugin.version>3.4.1</maven.jar.plugin.version>
<maven.javadoc.plugin.version>3.6.3</maven.javadoc.plugin.version>
<maven.plugin-tools.version>3.12.0</maven.plugin-tools.version>
<maven.release.plugin.version>3.0.1</maven.release.plugin.version>
<maven.dependency.plugin.version>3.7.1</maven.dependency.plugin.version>
<maven.deploy.plugin.version>3.1.2</maven.deploy.plugin.version>
<maven.deps.version>3.9.8</maven.deps.version>
<maven.enforcer.plugin.version>3.5.0</maven.enforcer.plugin.version>
<maven.exec.plugin.version>3.3.0</maven.exec.plugin.version>
<maven.gpg.plugin.version>3.2.4</maven.gpg.plugin.version>
<maven.install.plugin.version>3.1.2</maven.install.plugin.version>
<maven.invoker.plugin.version>3.7.0</maven.invoker.plugin.version>
<maven.jar.plugin.version>3.4.2</maven.jar.plugin.version>
<maven.javadoc.plugin.version>3.7.0</maven.javadoc.plugin.version>
<maven.plugin-tools.version>3.13.1</maven.plugin-tools.version>
<maven.release.plugin.version>3.1.0</maven.release.plugin.version>
<maven.remote-resources-plugin.version>3.2.0</maven.remote-resources-plugin.version>
<maven.resolver.version>1.9.18</maven.resolver.version>
<maven.resources.plugin.version>3.3.1</maven.resources.plugin.version>
<maven.shade.plugin.version>3.5.3</maven.shade.plugin.version>
<maven.shade.plugin.version>3.6.0</maven.shade.plugin.version>
<maven.source.plugin.version>3.3.1</maven.source.plugin.version>
<!-- do not upgrade as jpms issue with ee11 annotations -->
<maven.surefire.plugin.version>3.2.5</maven.surefire.plugin.version>
@ -386,31 +388,31 @@
<osgi-service-component-version>1.5.1</osgi-service-component-version>
<osgi-service-event-version>1.4.1</osgi-service-event-version>
<osgi-service-http-whiteboard>1.1.1</osgi-service-http-whiteboard>
<osgi-services-version>3.12.0</osgi-services-version>
<osgi-services-version>3.12.100</osgi-services-version>
<osgi-util-function-version>1.2.0</osgi-util-function-version>
<osgi-util-measurement-version>1.0.2</osgi-util-measurement-version>
<osgi-util-position-version>1.0.1</osgi-util-position-version>
<osgi-util-tracker-version>1.5.4</osgi-util-tracker-version>
<osgi-util-version>3.7.300</osgi-util-version>
<osgi-util-xml-version>1.0.2</osgi-util-xml-version>
<osgi-version>3.19.0</osgi-version>
<osgi-version>3.20.0</osgi-version>
<osgi.slf4j.import.packages>org.slf4j;version="[1.7,3.0)", org.slf4j.event;version="[1.7,3.0)", org.slf4j.helpers;version="[1.7,3.0)", org.slf4j.spi;version="[1.7,3.0)"</osgi.slf4j.import.packages>
<pax.exam.version>4.13.5</pax.exam.version>
<pax.url.version>2.6.14</pax.url.version>
<plexus-component-annotations.version>2.2.0</plexus-component-annotations.version>
<plexus-utils.version>4.0.1</plexus-utils.version>
<plexus-xml.version>4.0.3</plexus-xml.version>
<plexus-xml.version>4.0.4</plexus-xml.version>
<project.build.outputTimestamp>2024-04-26T07:15:13Z</project.build.outputTimestamp>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<reactive-streams.version>1.0.4</reactive-streams.version>
<settingsPath>src/it/settings.xml</settingsPath>
<slf4j.version>2.0.12</slf4j.version>
<slf4j.version>2.0.13</slf4j.version>
<spifly.version>1.3.7</spifly.version>
<spotbugs.maven.plugin.version>4.8.3.1</spotbugs.maven.plugin.version>
<spotbugs.maven.plugin.version>4.8.6.0</spotbugs.maven.plugin.version>
<surefire.failIfNoSpecifiedTests>false</surefire.failIfNoSpecifiedTests>
<surefire.rerunFailingTestsCount>0</surefire.rerunFailingTestsCount>
<swissbox.version>1.8.3</swissbox.version>
<testcontainers.version>1.19.7</testcontainers.version>
<testcontainers.version>1.19.8</testcontainers.version>
<testng.version>7.10.2</testng.version>
<tinybundles.version>3.0.0</tinybundles.version>
<versions.maven.plugin.version>2.16.2</versions.maven.plugin.version>
@ -428,6 +430,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
<version>${netty.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.hibernate.search</groupId>
<artifactId>hibernate-search-bom</artifactId>
@ -528,11 +537,6 @@
<artifactId>grpc-core</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
@ -623,6 +627,11 @@
<artifactId>maven-model</artifactId>
<version>${maven.deps.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model-builder</artifactId>
<version>${maven.deps.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
@ -634,6 +643,17 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-api</artifactId>
<version>${maven.deps.version}</version>
<exclusions>
<exclusion>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-provider</artifactId>
@ -659,6 +679,22 @@
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-tools-api</artifactId>
<version>${maven.plugin-tools.version}</version>
<exclusions>
<exclusion>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-api</artifactId>
<version>${maven.resolver.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-supplier</artifactId>
<version>${maven.resolver.version}</version>
</dependency>
<dependency>
<groupId>org.asciidoctor</groupId>
@ -675,6 +711,11 @@
<artifactId>awaitility</artifactId>
<version>${awaitility.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-classworlds</artifactId>
<version>${plexus-classworlds.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-annotations</artifactId>
@ -1089,6 +1130,11 @@
<artifactId>org.eclipse.osgi.util</artifactId>
<version>${osgi-util-version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.plexus</artifactId>
<version>${sisu.plexus.version}</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
@ -2027,7 +2073,7 @@
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>
<version>2.0.0</version>
<version>${duplicate-finder-maven-plugin.version}</version>
</plugin>
<!-- Build helper maven plugin sets the parsedVersion.osgiVersion property -->
<plugin>

View File

@ -13,19 +13,16 @@
<properties>
<bundle-symbolic-name>${project.groupId}.testers</bundle-symbolic-name>
<maven.model.builder.version>3.9.6</maven.model.builder.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model-builder</artifactId>
<version>${maven.model.builder.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-supplier</artifactId>
<version>${maven.resolver.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>