Merged branch 'jetty-12.0.x' into 'jetty-12.1.x'.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2024-09-27 17:55:34 +02:00
commit 29aa1541b6
No known key found for this signature in database
GPG Key ID: 1677D141BCF3584D
18 changed files with 480 additions and 40 deletions

13
Jenkinsfile vendored
View File

@ -28,21 +28,10 @@ pipeline {
}
}
stage("Build / Test - JDK22") {
agent { node { label 'linux' } }
steps {
timeout( time: 210, unit: 'MINUTES' ) {
checkout scm
mavenBuild( "jdk22", "clean install -Dspotbugs.skip=true -Djacoco.skip=true", "maven3")
recordIssues id: "jdk22", name: "Static Analysis jdk22", aggregatingResults: true, enabledForFailure: true, tools: [mavenConsole(), java(), checkStyle(), javaDoc()]
}
}
}
stage("Build / Test - JDK23") {
agent { node { label 'linux' } }
steps {
timeout( time: 180, unit: 'MINUTES' ) {
timeout( time: 210, unit: 'MINUTES' ) {
checkout scm
mavenBuild( "jdk23", "clean install -Dspotbugs.skip=true -Djacoco.skip=true", "maven3")
recordIssues id: "jdk23", name: "Static Analysis jdk23", aggregatingResults: true, enabledForFailure: true, tools: [mavenConsole(), java(), checkStyle(), javaDoc()]

View File

@ -47,6 +47,7 @@ import org.eclipse.jetty.client.InputStreamRequestContent;
import org.eclipse.jetty.client.InputStreamResponseListener;
import org.eclipse.jetty.client.OutputStreamRequestContent;
import org.eclipse.jetty.client.PathRequestContent;
import org.eclipse.jetty.client.PathResponseListener;
import org.eclipse.jetty.client.ProxyConfiguration;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.Response;
@ -494,6 +495,30 @@ public class HTTPClientDocs
// end::inputStreamResponseListener[]
}
public void pathResponseListener() throws Exception
{
HttpClient httpClient = new HttpClient();
httpClient.start();
// tag::pathResponseListener[]
Path savePath = Path.of("/path/to/save/file.bin");
// Typical usage as a response listener.
PathResponseListener listener = new PathResponseListener(savePath, true);
httpClient.newRequest("http://domain.com/path")
.send(listener);
// Wait for the response content to be saved.
var result = listener.get(5, TimeUnit.SECONDS);
// Alternative usage with CompletableFuture.
var completable = PathResponseListener.write(httpClient.newRequest("http://domain.com/path"), savePath, true);
completable.whenComplete((pathResponse, failure) ->
{
// Your logic here.
});
// end::pathResponseListener[]
}
public void forwardContent() throws Exception
{
HttpClient httpClient = new HttpClient();

View File

@ -468,6 +468,13 @@ If you want to avoid buffering, you can wait for the response and then stream th
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=inputStreamResponseListener]
----
If you want to save the response content to a file, you can use the `PathResponseListener` utility class:
[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=pathResponseListener]
----
Finally, let's look at the advanced usage of the response content handling.
The response content is provided by the `HttpClient` implementation to application listeners following the read/demand model of `org.eclipse.jetty.io.Content.Source`.

View File

@ -0,0 +1,140 @@
//
// ========================================================================
// 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.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import org.eclipse.jetty.client.Response.Listener;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.IO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>Implementation of {@link Response.ContentListener} that
* saves the response content to a file {@link Path}, like
* {@code curl <url> -o file.bin} does.</p>
* <p>Typical usage is:</p>
* <pre>{@code
* // Typical usage.
* httpClient.newRequest(host, port)
* .send(new PathResponseListener(Path.of("/tmp/file.bin")), overwriteExistingFile);
*
* // Alternative usage.
* var request = httpClient.newRequest(host, port);
* CompletableFuture<PathResponse> completable = PathResponseListener.write(request, Path.of("/tmp/file.bin"), overwriteExistingFile);
* }</pre>
*/
public class PathResponseListener extends CompletableFuture<PathResponseListener.PathResponse> implements Listener
{
private static final Logger LOG = LoggerFactory.getLogger(InputStreamResponseListener.class);
private final Path path;
private final FileChannel fileChannel;
public PathResponseListener(Path path, boolean overwrite) throws IOException
{
this.path = path;
if (Files.exists(path) && !overwrite)
throw new FileAlreadyExistsException(path.toString(), null, "File cannot be overwritten");
fileChannel = FileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
}
@Override
public void onHeaders(Response response)
{
if (response.getStatus() != HttpStatus.OK_200)
response.abort(new HttpResponseException(String.format("Cannot save response content for HTTP status code %d", response.getStatus()), response));
else if (LOG.isDebugEnabled())
LOG.debug("saving response content to {}", path);
}
@Override
public void onContent(Response response, ByteBuffer content)
{
try
{
var bytesWritten = fileChannel.write(content);
if (LOG.isDebugEnabled())
LOG.debug("{} bytes written to {}", bytesWritten, path);
}
catch (Throwable x)
{
response.abort(x);
}
}
@Override
public void onSuccess(Response response)
{
if (LOG.isDebugEnabled())
LOG.debug("saved response content to {}", path);
}
@Override
public void onFailure(Response response, Throwable failure)
{
if (LOG.isDebugEnabled())
LOG.debug("failed to save response content to {}", path);
}
@Override
public void onComplete(Result result)
{
IO.close(fileChannel);
if (result.isSucceeded())
complete(new PathResponse(result.getResponse(), path));
else
completeExceptionally(result.getFailure());
}
/**
* <p>Writes the response content to the given file {@link Path}.</p>
*
* @param request the HTTP request
* @param path the path to write the response content to
* @param overwrite whether to overwrite an existing file
* @return a {@link CompletableFuture} that is completed when the exchange completes
*/
public static CompletableFuture<PathResponse> write(Request request, Path path, boolean overwrite)
{
PathResponseListener listener = null;
try
{
listener = new PathResponseListener(path, overwrite);
request.send(listener);
return listener;
}
catch (Throwable x)
{
CompletableFuture<PathResponse> completable = Objects.requireNonNullElse(listener, new CompletableFuture<>());
completable.completeExceptionally(x);
return completable;
}
}
public record PathResponse(Response response, Path path)
{
}
}

View File

@ -0,0 +1,133 @@
//
// ========================================================================
// 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.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class PathResponseListenerTest
{
private Server server;
private ServerConnector connector;
private Path resourceDir;
@BeforeEach
public void startServer() throws Exception
{
QueuedThreadPool serverThreads = new QueuedThreadPool();
serverThreads.setName("server");
server = new Server(serverThreads);
ResourceHandler resourceHandler = new ResourceHandler();
resourceDir = MavenTestingUtils.getTargetTestingPath(PathResponseListenerTest.class.getSimpleName());
FS.ensureEmpty(resourceDir);
resourceHandler.setBaseResource(ResourceFactory.of(server).newResource(resourceDir));
resourceHandler.setDirAllowed(false);
connector = new ServerConnector(server);
server.addConnector(connector);
server.setHandler(resourceHandler);
server.start();
}
@AfterEach
public void stopServer() throws Exception
{
FS.ensureEmpty(resourceDir);
LifeCycle.stop(server);
}
private Path createServerFile(int length) throws IOException
{
Path path = Files.createTempFile(resourceDir, "file-", ".bin");
try (SeekableByteChannel channel = Files.newByteChannel(path, StandardOpenOption.WRITE))
{
ByteBuffer buffer = ByteBuffer.allocate(length);
ThreadLocalRandom.current().nextBytes(buffer.array());
channel.write(buffer);
}
return path;
}
@ParameterizedTest
@ValueSource(ints = {0, 1024, 1048576})
public void testFileDownload(int length) throws Exception
{
try (HttpClient client = new HttpClient())
{
client.start();
Path serverPath = createServerFile(length);
URI uri = URI.create("http://localhost:" + connector.getLocalPort() + "/" + serverPath.getFileName());
Path clientPath = Files.createTempFile(resourceDir, "saved-", ".bin");
PathResponseListener listener = new PathResponseListener(clientPath, true);
client.newRequest(uri).send(listener);
var pathResponse = listener.get(5, TimeUnit.SECONDS);
assertTrue(Files.exists(pathResponse.path()));
assertArrayEquals(Files.readAllBytes(serverPath), Files.readAllBytes(clientPath));
// Do it again with overwrite=false.
Files.delete(clientPath);
listener = new PathResponseListener(clientPath, false);
client.newRequest(uri).send(listener);
pathResponse = listener.get(5, TimeUnit.SECONDS);
assertTrue(Files.exists(pathResponse.path()));
assertArrayEquals(Files.readAllBytes(serverPath), Files.readAllBytes(clientPath));
}
}
@ParameterizedTest
@ValueSource(ints = {0, 1024, 1048576})
public void testFileDownloadWithCompletable(int length) throws Exception
{
try (HttpClient client = new HttpClient())
{
client.start();
Path serverPath = createServerFile(length);
URI uri = URI.create("http://localhost:" + connector.getLocalPort() + "/" + serverPath.getFileName());
Path clientPath = Files.createTempFile(resourceDir, "saved-", ".bin");
var pathResponse = PathResponseListener.write(client.newRequest(uri), clientPath, true)
.get(5, TimeUnit.SECONDS);
assertTrue(Files.exists(pathResponse.path()));
assertArrayEquals(Files.readAllBytes(serverPath), Files.readAllBytes(clientPath));
}
}
}

View File

@ -66,7 +66,7 @@ public class SessionHandler extends AbstractSessionManager implements Handler.Si
return false;
SessionRequest sessionRequest = new SessionRequest(request);
addSessionStreamWrapper(request);
addSessionStreamWrapper(sessionRequest);
return sessionRequest.process(next, response, callback);
}

View File

@ -13,6 +13,7 @@
package org.eclipse.jetty.session;
import java.io.File;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@ -26,7 +27,9 @@ import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.Session;
import org.eclipse.jetty.session.AbstractSessionManager.RequestedSession;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -739,4 +742,70 @@ public class SessionHandlerTest
}
}
@Test
public void testFlushOnResponseCommit() throws Exception
{
// Setup temporary datastore with write-through null cache
File datastoreDir = MavenTestingUtils.getTargetTestingDir("datastore");
IO.delete(datastoreDir);
FileSessionDataStore datastore = new FileSessionDataStore();
datastore.setStoreDir(datastoreDir);
NullSessionCache cache = new NullSessionCache(_sessionHandler);
cache.setSessionDataStore(datastore);
cache.setFlushOnResponseCommit(true);
_sessionHandler.setSessionCache(cache);
_server.start();
LocalConnector.LocalEndPoint endPoint = _connector.connect();
endPoint.addInput("""
GET /create HTTP/1.1
Host: localhost
""");
HttpTester.Response response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
String setCookie = response.get(HttpHeader.SET_COOKIE);
String id = setCookie.substring(setCookie.indexOf("SESSION_ID=") + 11, setCookie.indexOf("; Path=/"));
String content = response.getContent();
assertThat(content, startsWith("Session="));
endPoint.addInput("""
GET /set/attribute/value HTTP/1.1
Host: localhost
Cookie: SESSION_ID=%s
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("attribute = value"));
// Session should persist through restart
_server.stop();
_server.start();
endPoint.addInput("""
GET /set/attribute/value HTTP/1.1
Host: localhost
Cookie: SESSION_ID=%s
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
assertThat(response.get(HttpHeader.SET_COOKIE), nullValue());
content = response.getContent();
assertThat(content, containsString("Session=" + id.substring(0, id.indexOf(".node0"))));
assertThat(content, containsString("attribute = value"));
}
}

View File

@ -447,21 +447,40 @@ public interface ResourceFactory
}
/**
* Split a string of references, that may be split with '{@code ,}', or '{@code ;}', or '{@code |}' into URIs.
* Split a string of references, that may be split with '{@code ,}', or '{@code ;}', or '{@code |}' into a List of {@link Resource}.
* <p>
* Each part of the input string could be path references (unix or windows style), or string URI references.
* Each part of the input string could be path references (unix or windows style), string URI references, or even glob references (eg: {@code /path/to/libs/*}).
* </p>
* <p>
* If the result of processing the input segment is a java archive, then its resulting URI will be a mountable URI as {@code jar:file:...!/}
* </p>
*
* @param str the input string of references
* @return list of resources
*/
default List<Resource> split(String str)
{
return split(str, ",;|");
}
/**
* Split a string of references by provided delims into a List of {@link Resource}.
* <p>
* Each part of the input string could be path references (unix or windows style), string URI references, or even glob references (eg: {@code /path/to/libs/*}).
* Note: that if you use the {@code :} character in your delims, then URI references will be impossible.
* </p>
* <p>
* If the result of processing the input segment is a java archive, then its resulting URI will be a mountable URI as {@code jar:file:...!/}
* </p>
*
* @param str the input string of references
* @return list of resources
*/
default List<Resource> split(String str, String delims)
{
List<Resource> list = new ArrayList<>();
StringTokenizer tokenizer = new StringTokenizer(str, ",;|");
StringTokenizer tokenizer = new StringTokenizer(str, delims);
while (tokenizer.hasMoreTokens())
{
String reference = tokenizer.nextToken();
@ -475,7 +494,6 @@ public interface ResourceFactory
{
List<Resource> expanded = dir.list();
expanded.sort(ResourceCollators.byName(true));
// TODO it is unclear why non archive files are not expanded into the list
expanded.stream().filter(r -> FileID.isLibArchive(r.getName())).forEach(list::add);
}
}
@ -487,11 +505,12 @@ public interface ResourceFactory
}
catch (Exception e)
{
LOG.warn("Invalid Resource Reference: " + reference);
LOG.warn("Invalid Resource Reference: {}", reference);
throw e;
}
}
// Perform Archive file mounting (if needed)
for (ListIterator<Resource> i = list.listIterator(); i.hasNext(); )
{
Resource resource = i.next();

View File

@ -405,7 +405,7 @@ public class ResourceFactoryTest
}
@Test
public void testSplitOnPipeWithGlob() throws IOException
public void testSplitOnPathSeparatorWithGlob() throws IOException
{
try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable())
{
@ -418,9 +418,54 @@ public class ResourceFactoryTest
FS.ensureDirExists(bar);
Files.copy(MavenPaths.findTestResourceFile("jar-file-resource.jar"), bar.resolve("lib-foo.jar"));
Files.copy(MavenPaths.findTestResourceFile("jar-file-resource.jar"), bar.resolve("lib-zed.zip"));
Path exampleJar = base.resolve("example.jar");
Files.copy(MavenPaths.findTestResourceFile("example.jar"), exampleJar);
// This represents a classpath with a glob
String config = String.join(File.pathSeparator, List.of(
dir.toString(), foo.toString(), bar + File.separator + "*", exampleJar.toString()
));
// Split using commas
List<URI> uris = resourceFactory.split(config, File.pathSeparator).stream().map(Resource::getURI).toList();
URI[] expected = new URI[]{
dir.toUri(),
foo.toUri(),
// Should see the two archives as `jar:file:` URI entries
URIUtil.toJarFileUri(bar.resolve("lib-foo.jar").toUri()),
URIUtil.toJarFileUri(bar.resolve("lib-zed.zip").toUri()),
URIUtil.toJarFileUri(exampleJar.toUri())
};
assertThat(uris, contains(expected));
}
}
@ParameterizedTest
@ValueSource(strings = {";", "|", ","})
public void testSplitOnDelimWithGlob(String delimChar) throws IOException
{
try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable())
{
// TIP: don't allow raw delim to show up in base dir, otherwise the string split later will be wrong.
Path base = MavenPaths.targetTestDir("testSplitOnPipeWithGlob_%02x".formatted((byte)delimChar.charAt(0)));
FS.ensureEmpty(base);
Path dir = base.resolve("dir");
FS.ensureDirExists(dir);
Path foo = dir.resolve("foo");
FS.ensureDirExists(foo);
Path bar = dir.resolve("bar");
FS.ensureDirExists(bar);
Files.copy(MavenPaths.findTestResourceFile("jar-file-resource.jar"), bar.resolve("lib-foo.jar"));
Files.copy(MavenPaths.findTestResourceFile("jar-file-resource.jar"), bar.resolve("lib-zed.zip"));
Path exampleJar = base.resolve("example.jar");
Files.copy(MavenPaths.findTestResourceFile("example.jar"), exampleJar);
// This represents the user-space raw configuration with a glob
String config = String.format("%s;%s;%s%s*", dir, foo, bar, File.separator);
String config = String.join(delimChar, List.of(
dir.toString(), foo.toString(), bar + File.separator + "*", exampleJar.toString()
));
// Split using commas
List<URI> uris = resourceFactory.split(config).stream().map(Resource::getURI).toList();
@ -430,7 +475,8 @@ public class ResourceFactoryTest
foo.toUri(),
// Should see the two archives as `jar:file:` URI entries
URIUtil.toJarFileUri(bar.resolve("lib-foo.jar").toUri()),
URIUtil.toJarFileUri(bar.resolve("lib-zed.zip").toUri())
URIUtil.toJarFileUri(bar.resolve("lib-zed.zip").toUri()),
URIUtil.toJarFileUri(exampleJar.toUri())
};
assertThat(uris, contains(expected));

View File

@ -60,6 +60,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -106,6 +107,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -156,6 +158,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -202,9 +205,9 @@ public class AsyncTest
@Test
public void testSessionCreatedBeforeDispatch() throws Exception
{
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -257,6 +260,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);

View File

@ -166,10 +166,10 @@ public class MetaInfConfiguration extends AbstractConfiguration
String classPath = System.getProperty("java.class.path");
if (classPath != null)
{
Stream.of(classPath.split(File.pathSeparator))
.map(resourceFactory::newResource)
resourceFactory.split(classPath, File.pathSeparator)
.stream()
.filter(Objects::nonNull)
.filter(r -> uriPatternPredicate.test(r.getURI()))
.filter(r -> uriPatternPredicate.test(URIUtil.unwrapContainer(r.getURI())))
.forEach(addContainerResource);
}

View File

@ -557,6 +557,7 @@ public class MetaInfConfigurationTest
.stream()
.sorted(ResourceCollators.byName(true))
.map(Resource::getURI)
.map(URIUtil::unwrapContainer)
.map(URI::toASCIIString)
.toList();
// we "correct" the bad file URLs that come from the ClassLoader

View File

@ -60,6 +60,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -106,6 +107,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -156,6 +158,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -202,9 +205,9 @@ public class AsyncTest
@Test
public void testSessionCreatedBeforeDispatch() throws Exception
{
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -257,6 +260,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);

View File

@ -166,10 +166,10 @@ public class MetaInfConfiguration extends AbstractConfiguration
String classPath = System.getProperty("java.class.path");
if (classPath != null)
{
Stream.of(classPath.split(File.pathSeparator))
.map(resourceFactory::newResource)
resourceFactory.split(classPath, File.pathSeparator)
.stream()
.filter(Objects::nonNull)
.filter(r -> uriPatternPredicate.test(r.getURI()))
.filter(r -> uriPatternPredicate.test(URIUtil.unwrapContainer(r.getURI())))
.forEach(addContainerResource);
}

View File

@ -557,6 +557,7 @@ public class MetaInfConfigurationTest
.stream()
.sorted(ResourceCollators.byName(true))
.map(Resource::getURI)
.map(URIUtil::unwrapContainer)
.map(URI::toASCIIString)
.toList();
// we "correct" the bad file URLs that come from the ClassLoader

View File

@ -60,6 +60,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -102,9 +103,9 @@ public class AsyncTest
public void testSessionWithAsyncComplete() throws Exception
{
// Test async write, which creates a session and completes outside of a dispatch
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -153,6 +154,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -198,9 +200,9 @@ public class AsyncTest
@Test
public void testSessionCreatedBeforeDispatch() throws Exception
{
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);
@ -252,6 +254,7 @@ public class AsyncTest
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT);
cacheFactory.setFlushOnResponseCommit(true);
SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
SessionTestSupport server = new SessionTestSupport(0, -1, -1, cacheFactory, storeFactory);

View File

@ -169,9 +169,10 @@ public class MetaInfConfiguration extends AbstractConfiguration
String classPath = System.getProperty("java.class.path");
if (classPath != null)
{
Stream.of(classPath.split(File.pathSeparator))
.map(resourceFactory::newResource)
.filter(r -> uriPatternPredicate.test(r.getURI()))
resourceFactory.split(classPath, File.pathSeparator)
.stream()
.filter(Objects::nonNull)
.filter(r -> uriPatternPredicate.test(URIUtil.unwrapContainer(r.getURI())))
.forEach(addContainerResource);
}

View File

@ -20,14 +20,11 @@ import java.util.List;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.resource.FileSystemPool;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -153,13 +150,14 @@ public class MetaInfConfigurationTest
assertEquals(2, containerResources.size());
for (Resource r : containerResources)
{
String s = r.toString();
String s = URIUtil.unwrapContainer(r.getURI()).toASCIIString();
assertTrue(s.endsWith("foo-bar-janb.jar") || s.contains("servlet-api"));
}
}
finally
{
config.postConfigure(context);
LifeCycle.stop(context.getResourceFactory());
}
}
}