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:
commit
29aa1541b6
|
@ -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()]
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue