Jetty 12 - Resource `resolve()` and `newResource()` return null on resources that do not exist (#8702)

* Resource `resolve()` and `newResource()` return null on resources that do not exist
* Introduce `Resources` utility methods and use them
* Updating javadoc
This commit is contained in:
Joakim Erdfelt 2022-10-19 15:50:37 -05:00 committed by GitHub
parent ed3d4a46c7
commit 259deea2f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 616 additions and 381 deletions

View File

@ -40,6 +40,7 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Environment;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -226,10 +227,26 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
List<Path> files = new ArrayList<>();
for (Resource resource : _monitored)
{
if (resource.exists() && Files.isReadable(resource.getPath()))
files.add(resource.getPath());
else
if (Resources.missing(resource))
{
LOG.warn("Does not exist: {}", resource);
continue; // skip
}
// handle resource smartly
for (Resource r: resource)
{
Path path = r.getPath();
if (path == null)
{
LOG.warn("Not based on FileSystem Path: {}", r);
continue; // skip
}
if (Files.isDirectory(path) || Files.isReadable(path))
files.add(resource.getPath());
else
LOG.warn("Unsupported Path (not a directory and/or not readable): {}", r);
}
}
_scanner = new Scanner(null, _useRealPaths);

View File

@ -27,6 +27,7 @@ import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.ResourceHttpContent;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
/**
* An HttpContent.Factory for transient content (not cached). The HttpContent's created by
@ -54,6 +55,8 @@ public class ResourceContentFactory implements ContentFactory
{
// try loading the content from our factory.
Resource resource = this._factory.newResource(pathInContext);
if (Resources.missing(resource))
return null;
return load(pathInContext, resource);
}
catch (Throwable t)

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.UrlEncoded;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollators;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -56,7 +57,9 @@ public class ResourceListing
{
// This method doesn't check aliases, so it is OK to canonicalize here.
base = URIUtil.normalizePath(base);
if (base == null || !resource.isDirectory())
if (base == null)
return null;
if (!Resources.isReadableDirectory(resource))
return null;
List<Resource> listing = resource.list().stream()

View File

@ -55,6 +55,7 @@ import org.eclipse.jetty.util.component.Graceful;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.util.thread.Invocable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -715,7 +716,18 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
{
if (isStarted())
throw new IllegalStateException(getState());
_baseResource = resourceBase;
// Allow resource base to be unset
if (resourceBase == null)
{
_baseResource = null;
return;
}
if (Resources.isReadable(resourceBase))
_baseResource = resourceBase;
else
throw new IllegalArgumentException("Base Resource is not valid: " + resourceBase);
}
public void setBaseResource(Path path)
@ -728,11 +740,10 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
}
Resource resource = ResourceFactory.of(this).newResource(path);
if (resource != null && resource.exists())
setBaseResource(resource);
else
if (!Resources.isReadable(resource))
throw new IllegalArgumentException("Base Resource is not valid: " + path);
setBaseResource(resource);
}
/**

View File

@ -28,6 +28,7 @@ import org.eclipse.jetty.server.ResourceService;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
/**
* Resource Handler.
@ -93,7 +94,7 @@ public class ResourceHandler extends Handler.Wrapper
{
String welcomeInContext = URIUtil.addPaths(request.getPathInContext(), welcome);
Resource welcomePath = _resourceBase.resolve(request.getPathInContext()).resolve(welcome);
if (welcomePath != null && welcomePath.exists())
if (Resources.isReadableFile(welcomePath))
return welcomeInContext;
}
// not found

View File

@ -58,13 +58,27 @@ public class MemoryResource extends Resource
@Override
public Path getPath()
{
return Path.of(_uri);
// memory resource has no path (it would be problematic for mounting reasons as well)
return null;
}
@Override
public boolean isDirectory()
{
return false;
}
@Override
public boolean isReadable()
{
return true;
}
@Override
public boolean isContainedIn(Resource r)
{
return getPath().startsWith(r.getPath());
// memory resource can never be contained in another memory resource
return false;
}
@Override
@ -76,22 +90,13 @@ public class MemoryResource extends Resource
@Override
public String getName()
{
Path p = getPath();
if (p == null)
return _uri.toASCIIString();
return p.toAbsolutePath().toString();
return _uri.toASCIIString();
}
@Override
public String getFileName()
{
Path p = getPath();
if (p == null)
return FileID.getFileName(_uri);
Path fn = p.getFileName();
if (fn == null)
return ""; // no segments, so no filename
return fn.toString();
return FileID.getFileName(_uri);
}
@Override
@ -106,6 +111,12 @@ public class MemoryResource extends Resource
return _bytes.length;
}
@Override
public Resource resolve(String subUriPath)
{
return null;
}
@Override
public InputStream newInputStream() throws IOException
{

View File

@ -16,7 +16,9 @@ package org.eclipse.jetty.util.resource;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.eclipse.jetty.util.URIUtil;
@ -26,6 +28,14 @@ import org.eclipse.jetty.util.URIUtil;
*/
public class MountedPathResource extends PathResource
{
public static MountedPathResource of(URI uri) throws IOException
{
Path path = Paths.get(uri.normalize());
if (!Files.exists(path))
return null;
return new MountedPathResource(path, uri);
}
private final URI containerUri;
MountedPathResource(URI uri) throws IOException
@ -34,6 +44,18 @@ public class MountedPathResource extends PathResource
containerUri = URIUtil.unwrapContainer(getURI());
}
MountedPathResource(Path path, URI uri)
{
super(path, uri, true);
containerUri = URIUtil.unwrapContainer(getURI());
}
@Override
protected Resource newResource(Path path, URI uri)
{
return new MountedPathResource(path, uri);
}
@Override
public boolean isContainedIn(Resource r)
{

View File

@ -18,11 +18,14 @@ import java.net.URI;
import java.nio.file.DirectoryIteratorException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -47,6 +50,14 @@ public class PathResource extends Resource
.with("jrt")
.build();
public static PathResource of(URI uri) throws IOException
{
Path path = Paths.get(uri.normalize());
if (!Files.exists(path))
return null;
return new PathResource(path, uri, false);
}
// The path object represented by this instance
private final Path path;
// The as-requested URI for this path object
@ -262,6 +273,95 @@ public class PathResource extends Resource
return this.uri;
}
@Override
public Resource resolve(String subUriPath)
{
// Check that the path is within the root,
// but use the original path to create the
// resource, to preserve aliasing.
if (URIUtil.isNotNormalWithinSelf(subUriPath))
throw new IllegalArgumentException(subUriPath);
if (URIUtil.SLASH.equals(subUriPath))
return this;
// Sub-paths are always resolved under the given URI,
// we compensate for input sub-paths like "/subdir"
// where default resolve behavior would be to treat
// that like an absolute path.
while (subUriPath.startsWith(URIUtil.SLASH))
{
// TODO XXX this appears entirely unnecessary and inefficient. We already have utilities
// to handle appending path strings with/without slashes.
subUriPath = subUriPath.substring(1);
}
URI uri = getURI();
URI resolvedUri = URIUtil.addPath(uri, subUriPath);
Path path = Paths.get(resolvedUri);
if (Files.exists(path))
return newResource(path, resolvedUri);
return null;
}
/**
* Internal override for creating a new PathResource.
* Used by MountedPathResource (eg)
*/
protected Resource newResource(Path path, URI uri)
{
return new PathResource(path, uri, true);
}
@Override
public boolean isDirectory()
{
return Files.isDirectory(getPath(), LinkOption.NOFOLLOW_LINKS);
}
@Override
public boolean isReadable()
{
return Files.isReadable(getPath());
}
@Override
public Instant lastModified()
{
Path path = getPath();
if (path == null)
return Instant.EPOCH;
if (!Files.exists(path))
return Instant.EPOCH;
try
{
FileTime ft = Files.getLastModifiedTime(path, LinkOption.NOFOLLOW_LINKS);
return ft.toInstant();
}
catch (IOException e)
{
LOG.trace("IGNORED", e);
return Instant.EPOCH;
}
}
@Override
public long length()
{
try
{
return Files.size(getPath());
}
catch (IOException e)
{
// in case of error, use Files.size() logic of 0L
return 0L;
}
}
@Override
public boolean isContainedIn(Resource r)
{

View File

@ -26,7 +26,6 @@ import java.nio.file.Paths;
import java.nio.file.ProviderNotFoundException;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
@ -87,9 +86,9 @@ public abstract class Resource implements Iterable<Resource>
// If the scheme is allowed by PathResource, we can build a non-mounted PathResource.
if (PathResource.ALLOWED_SCHEMES.contains(uri.getScheme()))
return new PathResource(uri);
return PathResource.of(uri);
return new MountedPathResource(uri);
return MountedPathResource.of(uri);
}
catch (URISyntaxException | ProviderNotFoundException | IOException ex)
{
@ -140,69 +139,43 @@ public abstract class Resource implements Iterable<Resource>
}
/**
* Equivalent to {@link Files#isDirectory(Path, LinkOption...)} with the following parameter:
* {@link #getPath()}.
* Return true if resource represents a directory of potential resources.
*
* @return true if the represented resource is a container/directory.
*/
public boolean isDirectory()
{
return Files.isDirectory(getPath(), FOLLOW_LINKS);
}
public abstract boolean isDirectory();
/**
* True if the resource is readable.
*
* @return true if the represented resource exists, and can read from.
*/
public abstract boolean isReadable();
/**
* The time the resource was last modified.
*
* Equivalent to {@link Files#getLastModifiedTime(Path, LinkOption...)} with the following parameter:
* {@link #getPath()} then returning {@link FileTime#toInstant()}.
*
* @return the last modified time instant, or {@link Instant#EPOCH} if unable to obtain last modified.
*/
public Instant lastModified()
{
Path path = getPath();
if (path == null)
return Instant.EPOCH;
if (!Files.exists(path))
return Instant.EPOCH;
try
{
FileTime ft = Files.getLastModifiedTime(path, FOLLOW_LINKS);
return ft.toInstant();
}
catch (IOException e)
{
LOG.trace("IGNORED", e);
return Instant.EPOCH;
}
return Instant.EPOCH;
}
/**
* Length of the resource.
* Equivalent to {@link Files#size(Path)} with the following parameter:
* {@link #getPath()}.
*
* @return the length of the resource or 0 if {@link Files#size(Path)} throws {@link IOException}.
* @return the length of the resource in bytes, or -1L if unable to provide a size (such as a directory resource).
*/
public long length()
{
try
{
return Files.size(getPath());
}
catch (IOException e)
{
// in case of error, use File.length logic of 0L
return 0L;
}
return -1L;
}
/**
* URI representing the resource.
*
* @return an URI representing the given resource
* @return a URI representing the given resource
*/
public abstract URI getURI();
@ -258,39 +231,13 @@ public abstract class Resource implements Iterable<Resource>
}
/**
* Resolve a new Resource from an encoded subUriPath.
* Resolve an existing Resource.
*
* @param subUriPath the encoded subUriPath
* @return a Resource representing the subUriPath
* @return an existing Resource representing the requested subUriPath, or null if resource does not exist.
* @throws IllegalArgumentException if subUriPath is invalid
*/
public Resource resolve(String subUriPath)
{
// Check that the path is within the root,
// but use the original path to create the
// resource, to preserve aliasing.
// TODO do a URI safe encoding?
if (URIUtil.isNotNormalWithinSelf(subUriPath))
throw new IllegalArgumentException(subUriPath);
if (URIUtil.SLASH.equals(subUriPath))
return this;
// Sub-paths are always resolved under the given URI,
// we compensate for input sub-paths like "/subdir"
// where default resolve behavior would be to treat
// that like an absolute path.
while (subUriPath.startsWith(URIUtil.SLASH))
{
// TODO XXX this appears entirely unnecessary and inefficient. We already have utilities
// to handle appending path strings with/without slashes.
subUriPath = subUriPath.substring(1);
}
URI uri = getURI();
URI resolvedUri = URIUtil.addPath(uri, subUriPath);
return create(resolvedUri);
}
public abstract Resource resolve(String subUriPath);
/**
* @return true if this Resource is an alias to another real Resource

View File

@ -104,13 +104,13 @@ public class ResourceCollection extends Resource
/**
* Resolves a path against the resource collection.
*
* @param subUriPath The path segment to add
* @return The resulting resource(s) :
* @param subUriPath The path segment to resolve
* @return The resulting resource :
* <ul>
* <li>is a file that exists in at least one of the collection, then the first one found is returned</li>
* <li>is a directory that exists in at exactly one of the collection, then that directory resource is returned </li>
* <li>is a directory that exists in at exactly one of the collection, then that simple directory resource is returned</li>
* <li>is a directory that exists in several of the collection, then a ResourceCollection of those directories is returned</li>
* <li>do not exist in any of the collection, then a new non existent resource relative to the first in the collection is returned.</li>
* <li>is null if not found in any entry in this collection</li>
* </ul>
*/
@Override
@ -131,8 +131,8 @@ public class ResourceCollection extends Resource
for (Resource res : _resources)
{
addedResource = res.resolve(subUriPath);
if (!addedResource.exists())
continue;
if (Resources.missing(addedResource))
continue; // skip, doesn't exist
if (!addedResource.isDirectory())
return addedResource; // Return simple (non-directory) Resource
if (resources == null)
@ -257,6 +257,17 @@ public class ResourceCollection extends Resource
return true;
}
@Override
public boolean isReadable()
{
for (Resource r : _resources)
{
if (r.isReadable())
return true;
}
return false;
}
@Override
public Instant lastModified()
{

View File

@ -0,0 +1,94 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.util.resource;
/**
* Collection of helpful static methods for working with {@link Resource} objects.
*/
public final class Resources
{
/**
* True if the resource exists.
*
* @param resource the resource to test
* @return true if resource is non-null and exists
* @see Resource#exists()
*/
public static boolean exists(Resource resource)
{
return resource != null && resource.exists();
}
/**
* True if the resource is missing.
*
* @param resource the resource to test
* @return true if resource is null or doesn't exist
* @see Resource#exists()
*/
public static boolean missing(Resource resource)
{
return resource == null || !resource.exists();
}
/**
* True if resource is a valid directory.
*
* @param resource the resource to test
* @return true if resource is non-null, exists, and is a directory
* @see Resource#exists()
* @see Resource#isDirectory()
*/
public static boolean isDirectory(Resource resource)
{
return resource != null && resource.isDirectory();
}
/**
* True if resource is readable.
*
* @param resource the resource to test
* @return true if resource is non-null, exists, and is readable
* @see Resource#exists()
* @see Resource#isReadable()
*/
public static boolean isReadable(Resource resource)
{
return resource != null && resource.isReadable();
}
/**
* True if resource is a valid directory that can be read from.
*
* @param resource the resource to test
* @return true if resource is non-null, exists, and is a directory
* @see Resource#exists()
* @see Resource#isDirectory()
*/
public static boolean isReadableDirectory(Resource resource)
{
return resource != null && resource.isDirectory() && resource.isReadable();
}
/**
* True if resource exists, is not a directory, is readable.
*
* @param resource the resource to test
* @return true if resource exists, is not a directory, is
*/
public static boolean isReadableFile(Resource resource)
{
return resource != null && !resource.isDirectory() && resource.isReadable();
}
}

View File

@ -82,6 +82,7 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.util.security.CertificateUtils;
import org.eclipse.jetty.util.security.CertificateValidator;
import org.eclipse.jetty.util.security.Password;
@ -640,10 +641,10 @@ public abstract class SslContextFactory extends ContainerLifeCycle implements Du
}
Resource res = ResourceFactory.of(this).newResource(keyStorePath);
if (!res.exists())
if (!Resources.isReadableFile(res))
{
_keyStoreResource = null;
throw new IllegalArgumentException("KeyStore Path does not exist: " + keyStorePath);
throw new IllegalArgumentException("KeyStore Path not accessible: " + keyStorePath);
}
_keyStoreResource = res;
}
@ -724,10 +725,10 @@ public abstract class SslContextFactory extends ContainerLifeCycle implements Du
}
Resource res = ResourceFactory.of(this).newResource(trustStorePath);
if (!res.exists())
if (!Resources.isReadableFile(res))
{
_trustStoreResource = null;
throw new IllegalArgumentException("TrustStore Path does not exist: " + trustStorePath);
throw new IllegalArgumentException("TrustStore Path not accessible: " + trustStorePath);
}
_trustStoreResource = res;
}

View File

@ -166,7 +166,7 @@ public class FileSystemResourceTest
{
// Doesn't exist.
Resource resource = ResourceFactory.root().newResource(new URI("path/to/resource"));
assertFalse(resource.exists());
assertTrue(Resources.missing(resource));
// Create a directory
Path testdir = workDir.getEmptyPathDir().resolve("path/to/resource");
@ -229,7 +229,7 @@ public class FileSystemResourceTest
assertThat("sub/.isDirectory", sub.isDirectory(), is(true));
Resource tmp = sub.resolve("/tmp");
assertThat("No root", tmp.exists(), is(false));
assertTrue(Resources.missing(tmp), "Reference to root not allowed");
}
@Test
@ -245,7 +245,7 @@ public class FileSystemResourceTest
assertThat("sub.isDirectory", sub.isDirectory(), is(true));
Resource tmp = sub.resolve("/tmp");
assertThat("No root", tmp.exists(), is(false));
assertTrue(Resources.missing(tmp), "Reference to root not allowed");
}
@Test
@ -266,7 +266,7 @@ public class FileSystemResourceTest
{
Resource rrd = sub.resolve(readableRootDir);
// we are executing on unix and OSX
assertThat("Readable Root Dir", rrd.exists(), is(false));
assertTrue(Resources.missing(rrd), "Readable Root Dir");
}
catch (InvalidPathException e)
{
@ -398,16 +398,6 @@ public class FileSystemResourceTest
assertThat("foo.lastModified", res.lastModified(), is(expected));
}
@Test
public void testLastModifiedNotExists()
{
Path dir = workDir.getEmptyPathDir();
Resource base = ResourceFactory.root().newResource(dir);
Resource res = base.resolve("foo");
assertThat("foo.lastModified", res.lastModified(), is(Instant.EPOCH));
}
@Test
public void testLength() throws Exception
{
@ -424,17 +414,6 @@ public class FileSystemResourceTest
assertThat("foo.length", res.length(), is(expected));
}
@Test
public void testLengthNotExists() throws Exception
{
Path dir = workDir.getEmptyPathDir();
Files.createDirectories(dir);
Resource base = ResourceFactory.root().newResource(dir);
Resource res = base.resolve("foo");
assertThat("foo.length", res.length(), is(0L));
}
@Test
public void testDelete() throws Exception
{
@ -453,22 +432,6 @@ public class FileSystemResourceTest
assertThat("foo.exists", res.exists(), is(false));
}
@Test
public void testDeleteNotExists() throws Exception
{
Path dir = workDir.getEmptyPathDir();
Files.createDirectories(dir);
Resource base = ResourceFactory.root().newResource(dir);
// Is it there?
Resource res = base.resolve("foo");
assertThat("foo.exists", res.exists(), is(false));
// delete it
Files.deleteIfExists(res.getPath());
// is it there?
assertThat("foo.exists", res.exists(), is(false));
}
@Test
public void testName() throws Exception
{
@ -623,13 +586,13 @@ public class FileSystemResourceTest
}
@Test
public void testNonExistantSymlink() throws Exception
public void testNonExistentSymlink() throws Exception
{
Path dir = workDir.getEmptyPathDir();
Files.createDirectories(dir);
Path foo = dir.resolve("foo");
Path bar = dir.resolve("bar");
Path foo = dir.resolve("foo"); // does not exist
Path bar = dir.resolve("bar"); // to become a link to "foo"
boolean symlinkSupported;
try
@ -649,25 +612,8 @@ public class FileSystemResourceTest
Resource resFoo = base.resolve("foo");
Resource resBar = base.resolve("bar");
assertThat("resFoo.uri", resFoo.getURI(), is(foo.toUri()));
// Access to the same resource, but via a symlink means that they are not equivalent
assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false));
// This is not an alias because the file does not exist.
assertFalse(resFoo.exists());
assertFalse(Files.exists(resFoo.getPath()));
assertFalse(resFoo.isAlias());
assertNotNull(resFoo.getURI());
assertNull(resFoo.getRealURI());
// This is alias because the target file does not exist even though the symlink file does exist.
// This resource cannot be served, so it should not exist, nor have an alias
assertFalse(resBar.exists());
assertFalse(Files.exists(resBar.getPath()));
assertFalse(resBar.isAlias());
assertNotNull(resBar.getURI());
assertNull(resBar.getRealURI());
assertTrue(Resources.missing(resFoo), "resFoo");
assertTrue(Resources.missing(resBar), "resBar");
}
@Test
@ -689,7 +635,7 @@ public class FileSystemResourceTest
// On some case-insensitive file systems, lets see if an alternate
// case for the filename results in an alias reference
Resource alias = base.resolve("FILE");
if (alias.exists())
if (Resources.exists(alias))
{
// If it exists, it must be an alias
assertThat("targetURI", alias, isRealResourceFor(resource));
@ -1188,11 +1134,11 @@ public class FileSystemResourceTest
assertThat("Target URI: " + basePath, base, isNotAlias());
Resource r = base.resolve("aa%5C/foo.txt");
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa%5C/foo.txt"));
if (WINDOWS.isCurrentOs())
{
assertThat("getPath().toString()", r.getPath().toString(), containsString("aa\\foo.txt"));
assertThat("getURI()", r.getPath().toString(), containsString("aa\\/foo.txt"));
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa%5C/foo.txt"));
assertThat("isAlias()", r.isAlias(), is(true));
assertThat("getRealURI()", r.getRealURI(), notNullValue());
assertThat("getRealURI()", r.getRealURI().toASCIIString(), containsString("aa/foo.txt"));
@ -1200,9 +1146,7 @@ public class FileSystemResourceTest
}
else
{
assertThat("getPath().toString()", r.getPath().toString(), containsString("aa\\/foo.txt"));
assertThat("isAlias()", r.isAlias(), is(false));
assertThat("Exists: " + r, r.exists(), is(false));
assertTrue(Resources.missing(r), "Backslash resource");
}
}
catch (IllegalArgumentException e)
@ -1232,10 +1176,10 @@ public class FileSystemResourceTest
assertThat("Is Not Alias: " + basePath, base, isNotAlias());
Resource r = base.resolve("aa./foo.txt");
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa./foo.txt"));
if (WINDOWS.isCurrentOs())
{
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa./foo.txt"));
assertThat("isAlias()", r.isAlias(), is(true));
assertThat("getRealURI()", r.getRealURI(), notNullValue());
assertThat("getRealURI()", r.getRealURI().toASCIIString(), containsString("aa/foo.txt"));
@ -1243,8 +1187,7 @@ public class FileSystemResourceTest
}
else
{
assertThat("isAlias()", r.isAlias(), is(false));
assertThat("Exists: " + r, r.exists(), is(false));
assertTrue(Resources.missing(r), "extension-less directory reference");
}
}
catch (IllegalArgumentException e)

View File

@ -165,9 +165,7 @@ public class PathResourceTest
// Resolve to name, but different case
testText = archiveResource.resolve("/TEST.TXT");
assertFalse(testText.exists());
assertThat("Resource.getName", testText.getName(), is("/TEST.TXT"));
assertThat("Resource.getFileName", testText.getFileName(), is("TEST.TXT"));
assertNull(testText);
// Resolve using path navigation
testText = archiveResource.resolve("/foo/../test.txt");
@ -224,9 +222,9 @@ public class PathResourceTest
// Resolve file to name, but different case
testText = archiveResource.resolve("/dir/TEST.TXT");
assertFalse(testText.exists());
assertNull(testText);
testText = archiveResource.resolve("/DIR/test.txt");
assertFalse(testText.exists());
assertNull(testText);
// Resolve file using path navigation
testText = archiveResource.resolve("/foo/../dir/test.txt");
@ -240,8 +238,7 @@ public class PathResourceTest
// Resolve file using extension-less directory
testText = archiveResource.resolve("/dir./test.txt");
assertFalse(testText.exists());
assertFalse(testText.isAlias());
assertNull(testText);
// Resolve directory to name, no slash
Resource dirResource = archiveResource.resolve("/dir");
@ -471,7 +468,7 @@ public class PathResourceTest
Resource rootRes = resourceFactory.newResource(docroot);
// Test navigation through a directory that doesn't exist
Resource fileResViaBar = rootRes.resolve("bar/../dir/test.txt");
assertFalse(fileResViaBar.exists());
assertTrue(Resources.missing(fileResViaBar));
// Test navigation through a directory that does exist
Resource fileResViaFoo = rootRes.resolve("foo/../dir/test.txt");

View File

@ -76,12 +76,7 @@ public class ResourceAliasTest
Resource rootRes = resourceFactory.newResource(docroot);
// Test navigation through a directory that doesn't exist
Resource fileResViaBar = rootRes.resolve("bar/../dir/test.txt");
assertFalse(fileResViaBar.exists(), "Should not exist");
assertFalse(fileResViaBar.isAlias(), "Should not be an alias");
Files.createDirectory(docroot.resolve("bar"));
assertTrue(fileResViaBar.exists(), "Should exist");
assertTrue(fileResViaBar.isAlias(), "Should be an alias");
assertTrue(Resources.missing(fileResViaBar), "File doesn't exist");
// Test navigation through a directory that does exist
Resource fileResViaFoo = rootRes.resolve("foo/../dir/test.txt");

View File

@ -48,6 +48,7 @@ import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(WorkDirExtension.class)
@ -111,7 +112,8 @@ public class ResourceCollectionTest
assertThat(listingFilenames, containsInAnyOrder(expected));
assertThat(rc.resolve("unknown").list(), is(empty()));
Resource unk = rc.resolve("unknown");
assertNull(unk);
assertEquals(getContent(rc, "1.txt"), "1 - one");
assertEquals(getContent(rc, "2.txt"), "2 - two");

View File

@ -33,6 +33,7 @@ import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.eclipse.jetty.util.IO;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
@ -49,6 +50,7 @@ import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
@ -257,12 +259,16 @@ public class ResourceTest
public WorkDir workDir;
@Disabled
@ParameterizedTest
@MethodSource("scenarios")
public void testResourceExists(Scenario data)
{
Resource res = data.getResource();
assertThat("Exists: " + res.getName(), res.exists(), equalTo(data.exists));
if (data.exists)
assertThat("Exists: " + res.getName(), res.exists(), equalTo(data.exists));
else
assertNull(res);
}
@ParameterizedTest
@ -362,14 +368,37 @@ public class ResourceTest
}
@Test
public void testClimbAboveBase()
public void testClimbAboveBase(WorkDir workDir)
{
Resource resource = resourceFactory.newResource("/foo/bar");
Path testdir = workDir.getEmptyPathDir().resolve("foo/bar");
FS.ensureDirExists(testdir);
Resource resource = resourceFactory.newResource(testdir);
assertThrows(IllegalArgumentException.class, () -> resource.resolve(".."));
assertThrows(IllegalArgumentException.class, () -> resource.resolve("./.."));
assertThrows(IllegalArgumentException.class, () -> resource.resolve("./../bar"));
}
@Test
public void testNewResourcePathDoesNotExist(WorkDir workDir)
{
Path dir = workDir.getEmptyPathDir().resolve("foo/bar");
// at this point we have a directory reference that does not exist
Resource resource = resourceFactory.newResource(dir);
assertNull(resource);
}
@Test
public void testNewResourceFileDoesNotExists(WorkDir workDir) throws IOException
{
Path dir = workDir.getEmptyPathDir().resolve("foo");
FS.ensureDirExists(dir);
Path file = dir.resolve("bar.txt");
// at this point we have a file reference that does not exist
assertFalse(Files.exists(file));
Resource resource = resourceFactory.newResource(file);
assertNull(resource);
}
@Test
public void testDotAliasDirExists(WorkDir workDir) throws IOException
{
@ -383,18 +412,6 @@ public class ResourceTest
assertTrue(Files.isSameFile(dot.getPath(), Paths.get(dot.getRealURI())));
}
@Test
public void testDotAliasDirDoesNotExist(WorkDir workDir)
{
Path dir = workDir.getEmptyPathDir().resolve("foo/bar");
// at this point we have a directory reference that does not exist
Resource resource = resourceFactory.newResource(dir);
Resource dot = resource.resolve(".");
assertNotNull(dot);
assertFalse(dot.exists());
assertFalse(dot.isAlias(), "Reference to '.' is not an alias as directory doesn't exist");
}
@Test
public void testDotAliasFileExists(WorkDir workDir) throws IOException
{
@ -404,27 +421,9 @@ public class ResourceTest
FS.touch(file);
assertTrue(Files.exists(file));
Resource resource = resourceFactory.newResource(file);
// Requesting a resource that would point to a location called ".../testDotAliasFileExists/foo/bar.txt/."
Resource dot = resource.resolve(".");
// We are now pointing to a resource at ".../testDotAliasFileExists/foo/bar.txt/."
assertNotNull(dot);
assertFalse(dot.exists());
assertFalse(dot.isAlias(), "Reference to '.' against a file is not an alias");
}
@Test
public void testDotAliasFileDoesNotExists(WorkDir workDir) throws IOException
{
Path dir = workDir.getEmptyPathDir().resolve("foo");
FS.ensureDirExists(dir);
Path file = dir.resolve("bar.txt");
// at this point we have a file reference that does not exist
assertFalse(Files.exists(file));
Resource resource = resourceFactory.newResource(file);
Resource dot = resource.resolve(".");
// We are now pointing to a resource at ".../testDotAliasFileDoesNotExists/foo/bar.txt/."
assertNotNull(dot);
assertFalse(dot.exists());
assertFalse(dot.isAlias(), "Reference to '.' against a file is not an alias (the file also does not exist)");
assertTrue(Resources.missing(dot), "Cannot reference file as a directory");
}
@Test

View File

@ -258,7 +258,7 @@ public class SslContextFactoryTest
cf.setTrustStorePath("/foo");
cf.start();
});
assertThat(x.getMessage(), containsString("TrustStore Path does not exist: /foo"));
assertThat(x.getMessage(), containsString("TrustStore Path not accessible: /foo"));
}
}

View File

@ -26,6 +26,7 @@ import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.Resources;
/**
* Base class for all goals that operate on unassembled webapps.
@ -176,7 +177,7 @@ public abstract class AbstractUnassembledWebAppMojo extends AbstractWebAppMojo
if (webXml != null)
{
Resource r = webApp.getResourceFactory().newResource(webXml.toPath());
if (r.exists() && !r.isDirectory())
if (Resources.isReadableFile(r))
{
webApp.setDescriptor(r.getURI().toASCIIString());
}
@ -188,7 +189,7 @@ public abstract class AbstractUnassembledWebAppMojo extends AbstractWebAppMojo
// TODO: should never return from WEB-INF/lib/foo.jar!/WEB-INF/web.xml
// TODO: should also never return from a META-INF/versions/#/WEB-INF/web.xml location
Resource r = webApp.getBaseResource().resolve("WEB-INF/web.xml");
if (r.exists() && !r.isDirectory())
if (Resources.isReadableFile(r))
{
webApp.setDescriptor(r.getURI().toASCIIString());
}

View File

@ -41,6 +41,7 @@ import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -391,11 +392,11 @@ public class MavenWebAppContext extends WebAppContext
// try matching
Resource res = null;
int i = 0;
while (res == null && (i < _webInfClasses.size()))
while (Resources.missing(res) && (i < _webInfClasses.size()))
{
String newPath = StringUtil.replace(uri, WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
res = this.getResourceFactory().newResource(newPath);
if (!res.exists())
if (Resources.missing(res))
{
res = null;
i++;

View File

@ -21,6 +21,7 @@ import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -112,6 +113,24 @@ public class SelectiveJarResource extends Resource
return _delegate.getPath();
}
@Override
public boolean isDirectory()
{
return _delegate.isDirectory();
}
@Override
public Instant lastModified()
{
return _delegate.lastModified();
}
@Override
public boolean isReadable()
{
return _delegate.isReadable();
}
@Override
public boolean isContainedIn(Resource r)
{
@ -136,6 +155,12 @@ public class SelectiveJarResource extends Resource
return _delegate.getFileName();
}
@Override
public Resource resolve(String subUriPath)
{
return _delegate.resolve(subUriPath);
}
@Override
public void copyTo(Path directory) throws IOException
{

View File

@ -42,6 +42,7 @@ import org.eclipse.jetty.jndi.local.localContextRoot;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -101,7 +102,7 @@ public class EnvConfiguration extends AbstractConfiguration
// TODO: should never return from WEB-INF/lib/foo.jar!/WEB-INF/jetty-env.xml
// TODO: should also never return from a META-INF/versions/#/WEB-INF/jetty-env.xml location
org.eclipse.jetty.util.resource.Resource jettyEnv = webInf.resolve("jetty-env.xml");
if (jettyEnv.exists())
if (Resources.exists(jettyEnv))
{
jettyEnvXmlResource = jettyEnv;
}

View File

@ -35,6 +35,7 @@ import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.xml.XmlParser;
/**
@ -203,10 +204,9 @@ public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
for (URI uri : uris)
{
Resource r = _resourceFactory.newResource(uri);
if (r.exists())
visitMetaInfResource(context, r);
else
if (Resources.missing(r))
throw new IllegalArgumentException("Resource not found: " + r);
visitMetaInfResource(context, r);
}
}
default ->

View File

@ -56,6 +56,7 @@ import org.eclipse.jetty.util.RolloverFileOutputStream;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.slf4j.Logger;
@ -109,8 +110,8 @@ public class Runner
public void addJars(Resource lib)
{
if (lib == null || !lib.exists() || lib.isDirectory())
throw new IllegalStateException("lib is invalid: " + lib);
if (!Resources.isReadableFile(lib) || !FileID.isJavaArchive(lib.getURI()))
throw new IllegalStateException("Invalid lib: " + lib);
for (Resource item: lib.list())
{
@ -195,23 +196,27 @@ public class Runner
if ("--lib".equals(args[i]))
{
Resource lib = resourceFactory.newResource(args[++i]);
if (!lib.exists() || !lib.isDirectory())
usage("No such lib directory " + lib);
_classpath.addJars(lib);
if (Resources.isReadableDirectory(lib))
_classpath.addJars(lib);
else
usage("Invalid directory: " + lib);
}
else if ("--jar".equals(args[i]))
{
Resource jar = resourceFactory.newResource(args[++i]);
if (!jar.exists() || jar.isDirectory())
usage("No such jar " + jar);
_classpath.addPath(jar);
if (Resources.isReadableFile(jar) && FileID.isJavaArchive(jar.getURI()))
_classpath.addPath(jar);
else
usage("Invalid JAR: " + jar);
}
else if ("--classes".equals(args[i]))
{
Resource classes = resourceFactory.newResource(args[++i]);
if (!classes.exists() || !classes.isDirectory())
usage("No such classes directory " + classes);
_classpath.addPath(classes);
if (Resources.isReadableDirectory(classes))
_classpath.addPath(classes);
else
usage("Invalid classes directory: " + classes);
}
else if (args[i].startsWith("--"))
i++;

View File

@ -74,6 +74,7 @@ import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -182,7 +183,7 @@ public class DefaultServlet extends HttpServlet
try
{
Resource stylesheet = _resourceFactory.newResource(stylesheetParam);
if (stylesheet.exists())
if (Resources.isReadableFile(stylesheet))
{
_resourceService.setStylesheet(stylesheet);
}
@ -347,7 +348,7 @@ public class DefaultServlet extends HttpServlet
try
{
HttpContent content = _resourceService.getContent(pathInContext, ServletContextRequest.getServletContextRequest(req));
if (content == null || !content.getResource().exists())
if (content == null || Resources.missing(content.getResource()))
{
if (included)
{
@ -965,14 +966,14 @@ public class DefaultServlet extends HttpServlet
String welcomeServlet = null;
Resource base = _baseResource.resolve(requestTarget);
if (base != null && base.exists())
if (Resources.isReadableDirectory(base))
{
for (String welcome : welcomes)
{
Resource welcomePath = base.resolve(welcome);
String welcomeInContext = URIUtil.addPaths(coreRequest.getPathInContext(), welcome);
if (welcomePath != null && welcomePath.exists())
if (Resources.isReadableFile(welcomePath))
return welcomeInContext;
if ((_welcomeServlets || _welcomeExactServlets) && welcomeServlet == null)

View File

@ -97,6 +97,7 @@ import org.eclipse.jetty.util.component.Graceful;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -2927,7 +2928,8 @@ public class ServletContextHandler extends ContextHandler implements Graceful
for (Resource r: resource)
{
if (r.exists())
// return first
if (Resources.exists(r))
return r.getURI().toURL();
}

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.util.PathWatcher;
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.util.security.Credential;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -159,7 +160,7 @@ public class PropertyUserStore extends UserStore implements PathWatcher.Listener
if (LOG.isDebugEnabled())
LOG.debug("Loading {} from {}", this, config);
if (!config.exists())
if (Resources.missing(config))
throw new IllegalStateException("Config does not exist: " + config);
Properties properties = new Properties();

View File

@ -17,6 +17,7 @@ import java.io.IOException;
import java.util.Map;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -56,14 +57,14 @@ public class JettyWebXmlConfiguration extends AbstractConfiguration
// handle any WEB-INF descriptors
if (webInf != null && webInf.isDirectory())
{
// do jetty.xml file
// Attempt to load ancient jetty8-web.xml file
Resource jetty = webInf.resolve("jetty8-web.xml");
if (!jetty.exists())
if (Resources.missing(jetty))
jetty = webInf.resolve(JETTY_WEB_XML);
if (!jetty.exists())
if (Resources.missing(jetty))
jetty = webInf.resolve("web-jetty.xml");
if (jetty.exists())
if (Resources.isReadableFile(jetty))
{
if (LOG.isDebugEnabled())
LOG.debug("Configure: {}", jetty);

View File

@ -45,6 +45,7 @@ import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollators;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.ResourceUriPatternPredicate;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -148,7 +149,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
Consumer<URI> addContainerResource = (uri) ->
{
Resource resource = _resourceFactory.newResource(uri);
if (resource == null || !resource.exists())
if (Resources.missing(resource))
{
if (LOG.isDebugEnabled())
LOG.debug("Classpath URI doesn't exist: " + uri);
@ -386,7 +387,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
public void scanForResources(WebAppContext context, Resource target, ConcurrentHashMap<Resource, Resource> cache)
{
// Resource target does not exist
if (target == null || !target.exists())
if (Resources.missing(target))
return;
Resource resourcesDir = null;
@ -419,7 +420,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
resourcesDir = _resourceFactory.newResource(URIUtil.uriJarPrefix(uri, "!/META-INF/resources"));
}
if (cache != null)
if (Resources.isReadableDirectory(resourcesDir) && (cache != null))
{
Resource old = cache.putIfAbsent(target, resourcesDir);
if (old != null)
@ -449,7 +450,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
private static boolean isEmptyResource(Resource resourcesDir)
{
return !resourcesDir.exists() || !resourcesDir.isDirectory();
return !Resources.isReadableFile(resourcesDir);
}
/**
@ -489,7 +490,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
webFrag = _resourceFactory.newResource(URIUtil.uriJarPrefix(uri, "!/META-INF/web-fragment.xml"));
}
if (cache != null)
if (Resources.isReadable(webFrag) && (cache != null))
{
//web-fragment.xml doesn't exist: put token in cache to signal we've seen the jar
Resource old = cache.putIfAbsent(jar, webFrag);
@ -516,7 +517,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
private static boolean isEmptyFragment(Resource webFrag)
{
return !webFrag.exists() || webFrag.isDirectory();
return !Resources.isReadableFile(webFrag);
}
/**
@ -704,7 +705,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
Resource webInfLib = webInf.resolve("lib");
if (webInfLib != null && webInfLib.exists() && webInfLib.isDirectory())
if (Resources.isReadableDirectory(webInfLib))
{
return webInfLib.list().stream()
.filter((lib) -> FileID.isLibArchive(lib.getFileName()))
@ -752,11 +753,11 @@ public class MetaInfConfiguration extends AbstractConfiguration
Resource webInf = context.getWebInf();
// Find WEB-INF/classes
if (webInf != null && webInf.isDirectory())
if (Resources.isReadableDirectory(webInf))
{
// Look for classes directory
Resource webInfClassesDir = webInf.resolve("classes/");
if (webInfClassesDir != null && webInfClassesDir.exists() && webInfClassesDir.isDirectory())
if (Resources.isReadableDirectory(webInfClassesDir))
return webInfClassesDir;
}
return null;

View File

@ -45,6 +45,7 @@ import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -231,7 +232,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
{
for (Resource resource: resources)
{
if (resource != null && resource.exists())
if (Resources.exists(resource))
addURL(resource.getURI().toURL());
else
{
@ -280,7 +281,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
*/
public void addJars(Resource libs)
{
if (libs == null || !libs.exists() || !libs.isDirectory())
if (!Resources.isReadableDirectory(libs))
return;
for (Resource libDir: libs)

View File

@ -61,6 +61,7 @@ import org.eclipse.jetty.util.component.DumpableCollection;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -388,7 +389,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
try
{
resource = super.getResource(pathInContext);
if (resource != null && resource.exists())
if (Resources.exists(resource))
return resource;
pathInContext = getResourceAlias(pathInContext);
@ -815,10 +816,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
// Can return from WEB-INF/lib/foo.jar!/WEB-INF
// Can also never return from a META-INF/versions/#/WEB-INF location
Resource webInf = getBaseResource().resolve("WEB-INF/");
if (!webInf.exists() || !webInf.isDirectory())
return null;
if (Resources.isReadableDirectory(webInf))
return webInf;
return webInf;
return null;
}
/**
@ -1454,8 +1455,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
for (Resource r: resource)
{
if (r.exists())
return r.getURI().toURL();
// return first entry
return r.getURI().toURL();
}
// A Resource was returned, but did not exist

View File

@ -30,6 +30,7 @@ import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.MountedPathResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -66,12 +67,12 @@ public class WebInfConfiguration extends AbstractConfiguration
{
// Look for classes directory
Resource classes = webInf.resolve("classes/");
if (classes.exists())
if (Resources.isReadableDirectory(classes))
((WebAppClassLoader)context.getClassLoader()).addClassPath(classes);
// Look for jars
Resource lib = webInf.resolve("lib/");
if (lib.exists() || lib.isDirectory())
if (Resources.isReadableDirectory(lib))
((WebAppClassLoader)context.getClassLoader()).addJars(lib);
}
}
@ -298,7 +299,7 @@ public class WebInfConfiguration extends AbstractConfiguration
if (LOG.isDebugEnabled())
LOG.debug("{} anti-aliased to {}", webApp, realURI);
Resource realWebApp = context.newResource(realURI);
if (realWebApp != null && realWebApp.exists())
if (Resources.exists(realWebApp))
webApp = realWebApp;
}
@ -312,20 +313,19 @@ public class WebInfConfiguration extends AbstractConfiguration
Resource originalWarResource = webApp;
// Is the WAR usable directly?
if (webApp != null && webApp.exists() && !webApp.isDirectory() && FileID.isJavaArchive(webApp.getURI()) && !webApp.getURI().getScheme().equalsIgnoreCase("jar"))
if (Resources.isReadableFile(webApp) && FileID.isJavaArchive(webApp.getURI()) && !webApp.getURI().getScheme().equalsIgnoreCase("jar"))
{
// Turned this into a jar URL.
Resource jarWebApp = context.getResourceFactory().newJarFileResource(webApp.getURI());
if (jarWebApp != null && jarWebApp.exists() && !jarWebApp.isDirectory())
if (Resources.isReadableFile(jarWebApp)) // but only if it is readable
webApp = jarWebApp;
}
// If we should extract or the URL is still not usable
if (webApp.exists() && (
(context.isCopyWebDir() && webApp.getPath() != null && originalWarResource.isDirectory()) ||
if ((context.isCopyWebDir() && webApp.getPath() != null && originalWarResource.isDirectory()) ||
(context.isExtractWAR() && webApp.getPath() != null && !originalWarResource.isDirectory()) ||
(context.isExtractWAR() && webApp.getPath() == null) ||
!originalWarResource.isDirectory())
!originalWarResource.isDirectory()
)
{
// Look for sibling directory.
@ -350,7 +350,7 @@ public class WebInfConfiguration extends AbstractConfiguration
context.setAttribute(TEMPORARY_RESOURCE_BASE, extractedWebAppDir);
}
if (webApp.getPath() != null && webApp.isDirectory())
if (Resources.isReadableDirectory(webApp))
{
// Copy directory
if (LOG.isDebugEnabled())
@ -397,11 +397,15 @@ public class WebInfConfiguration extends AbstractConfiguration
}
}
}
webApp = context.getResourceFactory().newResource(extractedWebAppDir.normalize());
Resource extractedWebApp = context.getResourceFactory().newResource(extractedWebAppDir.normalize());
if (extractedWebApp == null)
LOG.warn("Unable to use non-existent extracted war location: " + extractedWebApp);
else
webApp = extractedWebApp;
}
// Now do we have something usable?
if (!webApp.exists() || !webApp.isDirectory())
if (Resources.missing(webApp))
{
LOG.warn("Web application not found {}", war);
throw new java.io.FileNotFoundException(war);
@ -418,7 +422,7 @@ public class WebInfConfiguration extends AbstractConfiguration
{
Resource webInf = webApp.resolve("WEB-INF/");
if (webInf != null && webInf.exists() && webInf.isDirectory())
if (Resources.isReadableDirectory(webInf))
{
File extractedWebInfDir = new File(context.getTempDirectory(), "webinf");
if (extractedWebInfDir.exists())
@ -428,7 +432,7 @@ public class WebInfConfiguration extends AbstractConfiguration
File webInfDir = new File(extractedWebInfDir, "WEB-INF");
webInfDir.mkdir();
if (webInfLib != null && webInfLib.exists() && webInfLib.isDirectory())
if (Resources.isReadableDirectory(webInfLib))
{
File webInfLibDir = new File(webInfDir, "lib");
if (webInfLibDir.exists())
@ -441,7 +445,7 @@ public class WebInfConfiguration extends AbstractConfiguration
}
Resource webInfClasses = webInf.resolve("classes/");
if (webInfClasses != null && webInfClasses.exists() && !webInfClasses.isDirectory())
if (Resources.isReadableDirectory(webInfClasses))
{
File webInfClassesDir = new File(webInfDir, "classes");
if (webInfClassesDir.exists())

View File

@ -22,6 +22,7 @@ import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -50,7 +51,7 @@ public class WebXmlConfiguration extends AbstractConfiguration
if (defaultsDescriptor != null && defaultsDescriptor.length() > 0)
{
Resource dftResource = context.getResourceFactory().newSystemResource(defaultsDescriptor);
if (dftResource == null)
if (Resources.missing(dftResource))
{
String pkg = WebXmlConfiguration.class.getPackageName().replace(".", "/") + "/";
if (defaultsDescriptor.startsWith(pkg))
@ -62,10 +63,10 @@ public class WebXmlConfiguration extends AbstractConfiguration
dftResource = context.getResourceFactory().newResource(uri);
}
}
if (dftResource == null)
if (Resources.missing(dftResource))
dftResource = context.newResource(defaultsDescriptor);
}
if (dftResource != null && dftResource.exists() && !dftResource.isDirectory())
if (Resources.isReadableFile(dftResource))
context.getMetaData().setDefaultsDescriptor(new DefaultsDescriptor(dftResource));
}
@ -84,9 +85,9 @@ public class WebXmlConfiguration extends AbstractConfiguration
if (overrideDescriptor != null && overrideDescriptor.length() > 0)
{
Resource orideResource = context.getResourceFactory().newSystemResource(overrideDescriptor);
if (orideResource == null)
if (Resources.missing(orideResource))
orideResource = context.newResource(overrideDescriptor);
if (orideResource != null && orideResource.exists() && !orideResource.isDirectory())
if (Resources.isReadableFile(orideResource))
context.getMetaData().addOverrideDescriptor(new OverrideDescriptor(orideResource));
}
}
@ -107,7 +108,7 @@ public class WebXmlConfiguration extends AbstractConfiguration
if (descriptor != null)
{
Resource web = context.newResource(descriptor);
if (web.exists() && !web.isDirectory())
if (web != null && !web.isDirectory())
return web;
}
@ -116,7 +117,7 @@ public class WebXmlConfiguration extends AbstractConfiguration
{
// do web.xml file
Resource web = webInf.resolve("web.xml");
if (web.exists())
if (Resources.isReadableFile(web))
return web;
if (LOG.isDebugEnabled())
LOG.debug("No WEB-INF/web.xml in {}. Serving files and default/dynamic servlets only", context.getWar());

View File

@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ClassMatcherTest
@ -211,15 +212,15 @@ public class ClassMatcherTest
{
// jar from JVM classloader
URI modString = TypeUtil.getLocationOfClass(String.class);
// System.err.println(modString);
assertNotNull(modString);
// a jar from maven repo jar
URI locJunit = TypeUtil.getLocationOfClass(Test.class);
// System.err.println(locJunit);
assertNotNull(locJunit);
// class file
URI locTest = TypeUtil.getLocationOfClass(ClassMatcherTest.class);
// System.err.println(locTest);
assertNotNull(locTest);
ClassMatcher pattern = new ClassMatcher();
@ -234,7 +235,7 @@ public class ClassMatcherTest
pattern.exclude("jrt:/java.base/");
// Add jar for individual class and classes directory
pattern.exclude(locJunit.toString(), locTest.toString());
pattern.exclude(locJunit.toASCIIString(), locTest.toASCIIString());
assertThat(pattern.match(String.class), is(false));
assertThat(pattern.match(Test.class), is(false));

View File

@ -27,6 +27,7 @@ import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.FileSystemPool;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

View File

@ -234,8 +234,8 @@ public class WebAppContextTest
server.start();
ServletContext ctx = context.getServletContext();
assertNotNull(ctx.getRealPath("/doesnotexist"));
assertNotNull(ctx.getRealPath("/doesnotexist/"));
assertNull(ctx.getRealPath("/doesnotexist"));
assertNull(ctx.getRealPath("/doesnotexist/"));
}
/**

View File

@ -38,25 +38,6 @@ public class WebInfConfigurationTest
{
public WorkDir workDir;
public static Stream<Arguments> rawResourceNames()
{
return Stream.of(
Arguments.of("/", ""),
Arguments.of("/a", "a")
);
}
@ParameterizedTest
@MethodSource("rawResourceNames")
public void testTinyGetResourceBaseName(String rawPath, String expectedName) throws IOException
{
try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable())
{
Resource resource = resourceFactory.newResource(rawPath);
assertThat(WebInfConfiguration.getResourceBaseName(resource), is(expectedName));
}
}
public static Stream<Arguments> fileBaseResourceNames()
{
return Stream.of(

View File

@ -547,9 +547,6 @@ public class AnnotationParser
if (r == null)
return;
if (!r.exists())
return;
if (FileID.isJavaArchive(r.getPath()))
{
parseJar(handlers, r);

View File

@ -25,6 +25,7 @@ import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Parameter;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
/**
* Base class for all goals that operate on unassembled webapps.
@ -167,7 +168,7 @@ public abstract class AbstractUnassembledWebAppMojo extends AbstractWebAppMojo
if (webXml != null)
{
Resource r = webApp.getResourceFactory().newResource(webXml.toPath());
if (r.exists() && !r.isDirectory())
if (Resources.isReadableFile(r))
{
webApp.setDescriptor(r.getURI().toASCIIString());
}
@ -177,7 +178,7 @@ public abstract class AbstractUnassembledWebAppMojo extends AbstractWebAppMojo
if (webApp.getDescriptor() == null && webApp.getBaseResource() != null)
{
Resource r = webApp.getBaseResource().resolve("WEB-INF/web.xml");
if (r.exists() && !r.isDirectory())
if (Resources.isReadableFile(r))
{
webApp.setDescriptor(r.toString());
}

View File

@ -43,6 +43,7 @@ import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -369,7 +370,7 @@ public class MavenWebAppContext extends WebAppContext
// If no regular resource exists check for access to /WEB-INF/lib or
// /WEB-INF/classes
if ((resource == null || !resource.exists()) && pathInContext != null && _classes != null)
if (resource == null && pathInContext != null && _classes != null)
{
// Normalize again to look for the resource inside /WEB-INF subdirectories.
String uri = URIUtil.normalizePath(pathInContext);
@ -394,11 +395,11 @@ public class MavenWebAppContext extends WebAppContext
// try matching
Resource res = null;
int i = 0;
while (res == null && (i < _webInfClasses.size()))
while (Resources.missing(res) && (i < _webInfClasses.size()))
{
String newPath = StringUtil.replace(uri, WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath());
res = ResourceFactory.of(this).newResource(newPath);
if (!res.exists())
if (Resources.missing(res))
{
res = null;
i++;

View File

@ -21,6 +21,7 @@ import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -112,6 +113,24 @@ public class SelectiveJarResource extends Resource
return _delegate.getPath();
}
@Override
public boolean isDirectory()
{
return _delegate.isDirectory();
}
@Override
public Instant lastModified()
{
return _delegate.lastModified();
}
@Override
public boolean isReadable()
{
return _delegate.isReadable();
}
@Override
public boolean isContainedIn(Resource r)
{
@ -136,6 +155,12 @@ public class SelectiveJarResource extends Resource
return _delegate.getFileName();
}
@Override
public Resource resolve(String subUriPath)
{
return _delegate.resolve(subUriPath);
}
@Override
public void copyTo(Path directory) throws IOException
{

View File

@ -43,6 +43,7 @@ import org.eclipse.jetty.http.ResourceHttpContent;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -231,7 +232,8 @@ public class CachedContentFactory implements HttpContent.ContentFactory
{
compressedContent = null;
Resource compressedResource = _factory.newResource(compressedPathInContext);
if (compressedResource != null && compressedResource.exists() && ResourceContentFactory.newerThanOrEqual(compressedResource, resource) &&
if (Resources.isReadable(compressedResource) &&
ResourceContentFactory.newerThanOrEqual(compressedResource, resource) &&
compressedResource.length() < resource.length())
{
compressedContent = new CachedHttpContent(compressedPathInContext, compressedResource, null);

View File

@ -89,6 +89,7 @@ import org.eclipse.jetty.util.component.Environment;
import org.eclipse.jetty.util.component.Graceful;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -1401,7 +1402,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
public boolean checkAlias(String path, Resource resource)
{
// Is the resource aliased?
if (resource.isAlias())
if (Resources.isReadable(resource) && resource.isAlias())
{
if (LOG.isDebugEnabled())
LOG.debug("Alias resource {} for {}", resource, resource.getRealURI());

View File

@ -33,6 +33,7 @@ import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -152,7 +153,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,
r = contextBase.resolve(path);
}
if ((r == null || !r.exists()) && path.endsWith("/jetty-dir.css"))
if (Resources.missing(r) && path.endsWith("/jetty-dir.css"))
r = getStylesheet();
if (r == null)

View File

@ -55,6 +55,7 @@ import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.MultiPartOutputStream;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -245,7 +246,7 @@ public class ResourceService
LOG.debug("content={}", content);
// Not found?
if (content == null || !content.getResource().exists())
if (content == null || Resources.missing(content.getResource()))
{
if (included)
throw new FileNotFoundException("!" + pathInContext);

View File

@ -42,6 +42,7 @@ import org.eclipse.jetty.jndi.local.localContextRoot;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -101,7 +102,7 @@ public class EnvConfiguration extends AbstractConfiguration
// TODO: should never return from WEB-INF/lib/foo.jar!/WEB-INF/jetty-env.xml
// TODO: should also never return from a META-INF/versions/#/WEB-INF/jetty-env.xml location
org.eclipse.jetty.util.resource.Resource jettyEnv = webInf.resolve("jetty-env.xml");
if (jettyEnv.exists())
if (Resources.isReadableFile(jettyEnv))
{
jettyEnvXmlResource = jettyEnv;
}

View File

@ -35,6 +35,7 @@ import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.xml.XmlParser;
/**
@ -203,10 +204,9 @@ public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
for (URI uri : uris)
{
Resource r = _resourceFactory.newResource(uri);
if (r.exists())
visitMetaInfResource(context, r);
else
if (Resources.missing(r))
throw new IllegalArgumentException("Resource not found: " + r);
visitMetaInfResource(context, r);
}
}
default ->

View File

@ -40,6 +40,7 @@ import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -212,7 +213,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
if (stylesheet != null)
{
_stylesheet = _resourceFactory.newResource(stylesheet);
if (!_stylesheet.exists())
if (Resources.missing(_stylesheet))
{
LOG.warn("Stylesheet {} does not exist", stylesheet);
_stylesheet = null;
@ -475,7 +476,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
LOG.trace("IGNORED", e);
}
if ((r == null || !r.exists()) && subUriPath.endsWith("/jetty-dir.css"))
if (Resources.missing(r) && subUriPath.endsWith("/jetty-dir.css"))
r = _stylesheet;
return r;

View File

@ -17,6 +17,7 @@ import java.io.IOException;
import java.util.Map;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -58,12 +59,12 @@ public class JettyWebXmlConfiguration extends AbstractConfiguration
{
// do jetty.xml file
Resource jetty = webInf.resolve("jetty8-web.xml");
if (!jetty.exists())
if (Resources.missing(jetty))
jetty = webInf.resolve(JETTY_WEB_XML);
if (!jetty.exists())
if (Resources.missing(jetty))
jetty = webInf.resolve("web-jetty.xml");
if (jetty.exists())
if (Resources.isReadableFile(jetty))
{
if (LOG.isDebugEnabled())
LOG.debug("Configure: {}", jetty);

View File

@ -45,6 +45,7 @@ import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollators;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.ResourceUriPatternPredicate;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -148,7 +149,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
Consumer<URI> addContainerResource = (uri) ->
{
Resource resource = _resourceFactory.newResource(uri);
if (resource == null || !resource.exists())
if (Resources.missing(resource))
{
if (LOG.isDebugEnabled())
LOG.debug("Classpath URI doesn't exist: " + uri);
@ -385,6 +386,10 @@ public class MetaInfConfiguration extends AbstractConfiguration
*/
public void scanForResources(WebAppContext context, Resource target, ConcurrentHashMap<Resource, Resource> cache)
{
// Resource target does not exist
if (target == null)
return;
Resource resourcesDir = null;
if (cache != null && cache.containsKey(target))
{
@ -415,7 +420,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
resourcesDir = _resourceFactory.newResource(URIUtil.uriJarPrefix(uri, "!/META-INF/resources"));
}
if (cache != null)
if (Resources.isReadableDirectory(resourcesDir) && (cache != null))
{
Resource old = cache.putIfAbsent(target, resourcesDir);
if (old != null)
@ -445,7 +450,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
private static boolean isEmptyResource(Resource resourcesDir)
{
return !resourcesDir.exists() || !resourcesDir.isDirectory();
return resourcesDir == null || !resourcesDir.isDirectory();
}
/**
@ -485,7 +490,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
webFrag = _resourceFactory.newResource(URIUtil.uriJarPrefix(uri, "!/META-INF/web-fragment.xml"));
}
if (cache != null)
if ((webFrag != null) && (cache != null))
{
//web-fragment.xml doesn't exist: put token in cache to signal we've seen the jar
Resource old = cache.putIfAbsent(jar, webFrag);
@ -512,7 +517,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
private static boolean isEmptyFragment(Resource webFrag)
{
return !webFrag.exists() || webFrag.isDirectory();
return !Resources.isReadableFile(webFrag);
}
/**
@ -694,15 +699,20 @@ public class MetaInfConfiguration extends AbstractConfiguration
return List.of();
Resource webInf = context.getWebInf();
if (webInf == null || !webInf.exists() || !webInf.isDirectory())
return List.of();
if (Resources.isReadableDirectory(webInf))
{
Resource webInfLib = webInf.resolve("lib");
Resource webInfLib = webInf.resolve("/lib");
if (Resources.isReadableDirectory(webInfLib))
{
return webInfLib.list().stream()
.filter((lib) -> FileID.isLibArchive(lib.getFileName()))
.sorted(ResourceCollators.byName(true))
.collect(Collectors.toList());
}
}
return webInfLib.list().stream()
.filter((lib) -> FileID.isLibArchive(lib.getFileName()))
.sorted(ResourceCollators.byName(true))
.collect(Collectors.toList());
return List.of();
}
/**
@ -741,12 +751,12 @@ public class MetaInfConfiguration extends AbstractConfiguration
Resource webInf = context.getWebInf();
// Find WEB-INF/classes
if (webInf != null && webInf.isDirectory())
if (Resources.isReadableDirectory(webInf))
{
// Look for classes directory
Resource classes = webInf.resolve("classes/");
if (classes.exists())
return classes;
Resource classesDir = webInf.resolve("classes/");
if (Resources.isReadableDirectory(classesDir))
return classesDir;
}
return null;
}

View File

@ -45,6 +45,7 @@ import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -231,7 +232,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
{
for (Resource resource: resources)
{
if (resource.exists())
if (Resources.exists(resource))
addURL(resource.getURI().toURL());
else
{
@ -280,7 +281,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
*/
public void addJars(Resource libs)
{
if (libs == null || !libs.exists() || !libs.isDirectory())
if (!Resources.isReadableDirectory(libs))
return;
for (Resource libDir: libs)

View File

@ -65,6 +65,7 @@ import org.eclipse.jetty.util.component.DumpableCollection;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -397,7 +398,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
try
{
resource = super.getResource(pathInContext);
if (resource != null && resource.exists())
if (Resources.exists(resource))
return resource;
pathInContext = getResourceAlias(pathInContext);
@ -817,10 +818,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
// Can return from WEB-INF/lib/foo.jar!/WEB-INF
// Can also never return from a META-INF/versions/#/WEB-INF location
Resource webInf = super.getBaseResource().resolve("WEB-INF/");
if (!webInf.exists() || !webInf.isDirectory())
return null;
if (Resources.isReadableDirectory(webInf))
return webInf;
return webInf;
return null;
}
/**
@ -1443,7 +1444,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
for (Resource r: resource)
{
if (r.exists())
// return first entry
if (Resources.exists(r))
return r.getURI().toURL();
}

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.MountedPathResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -65,12 +66,12 @@ public class WebInfConfiguration extends AbstractConfiguration
{
// Look for classes directory
Resource classes = webInf.resolve("classes/");
if (classes.exists())
if (Resources.isReadableDirectory(classes))
((WebAppClassLoader)context.getClassLoader()).addClassPath(classes);
// Look for jars
Resource lib = webInf.resolve("lib/");
if (lib.exists() || lib.isDirectory())
if (Resources.isReadableDirectory(lib))
((WebAppClassLoader)context.getClassLoader()).addJars(lib);
}
}
@ -310,12 +311,12 @@ public class WebInfConfiguration extends AbstractConfiguration
Resource originalWarResource = webApp;
// Is the WAR usable directly?
if (webApp.exists() && !webApp.isDirectory() && FileID.isJavaArchive(webApp.getURI()) && !webApp.getURI().getScheme().equalsIgnoreCase("jar"))
if (Resources.isReadableFile(webApp) && FileID.isJavaArchive(webApp.getURI()) && !webApp.getURI().getScheme().equalsIgnoreCase("jar"))
{
// No - then lets see if it can be turned into a jar URL.
// Turned this into a jar URL.
Resource jarWebApp = context.getResourceFactory().newJarFileResource(webApp.getURI());
if (jarWebApp != null && jarWebApp.exists())
if (Resources.isReadableFile(jarWebApp)) // but only if it is readable
webApp = jarWebApp;
}
@ -400,7 +401,7 @@ public class WebInfConfiguration extends AbstractConfiguration
}
// Now do we have something usable?
if (!webApp.exists() || !webApp.isDirectory())
if (Resources.missing(webApp))
{
LOG.warn("Web application not found {}", war);
throw new java.io.FileNotFoundException(war);
@ -417,7 +418,7 @@ public class WebInfConfiguration extends AbstractConfiguration
{
Resource webInf = webApp.resolve("WEB-INF/");
if (webInf != null && webInf.isDirectory())
if (Resources.isReadableDirectory(webInf))
{
File extractedWebInfDir = new File(context.getTempDirectory(), "webinf");
if (extractedWebInfDir.exists())
@ -428,7 +429,7 @@ public class WebInfConfiguration extends AbstractConfiguration
webInfDir.mkdir();
Resource webInfLib = webInf.resolve("lib/");
if (webInfLib != null && webInfLib.isDirectory())
if (Resources.isReadableDirectory(webInfLib))
{
File webInfLibDir = new File(webInfDir, "lib");
if (webInfLibDir.exists())
@ -441,7 +442,7 @@ public class WebInfConfiguration extends AbstractConfiguration
}
Resource webInfClasses = webInf.resolve("classes/");
if (webInfClasses != null && webInfClasses.isDirectory())
if (Resources.isReadableDirectory(webInfClasses))
{
File webInfClassesDir = new File(webInfDir, "classes");
if (webInfClassesDir.exists())

View File

@ -22,6 +22,7 @@ import org.eclipse.jetty.ee9.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -50,7 +51,7 @@ public class WebXmlConfiguration extends AbstractConfiguration
if (defaultsDescriptor != null && defaultsDescriptor.length() > 0)
{
Resource dftResource = context.getResourceFactory().newSystemResource(defaultsDescriptor);
if (dftResource == null)
if (Resources.missing(dftResource))
{
String pkg = WebXmlConfiguration.class.getPackageName().replace(".", "/") + "/";
if (defaultsDescriptor.startsWith(pkg))
@ -62,10 +63,10 @@ public class WebXmlConfiguration extends AbstractConfiguration
dftResource = context.getResourceFactory().newResource(uri);
}
}
if (dftResource == null)
if (Resources.missing(dftResource))
dftResource = context.newResource(defaultsDescriptor);
}
if (dftResource != null && dftResource.exists() && !dftResource.isDirectory())
if (Resources.isReadableFile(dftResource))
context.getMetaData().setDefaultsDescriptor(new DefaultsDescriptor(dftResource));
}
@ -106,7 +107,7 @@ public class WebXmlConfiguration extends AbstractConfiguration
if (descriptor != null)
{
Resource web = context.newResource(descriptor);
if (web.exists() && !web.isDirectory())
if (web != null && !web.isDirectory())
return web;
}
@ -115,7 +116,7 @@ public class WebXmlConfiguration extends AbstractConfiguration
{
// do web.xml file
Resource web = webInf.resolve("web.xml");
if (web.exists())
if (Resources.isReadableFile(web))
return web;
if (LOG.isDebugEnabled())
LOG.debug("No WEB-INF/web.xml in {}. Serving files and default/dynamic servlets only", context.getWar());

View File

@ -27,6 +27,7 @@ import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.FileSystemPool;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -86,7 +87,7 @@ public class TestMetaData
Resource fragMount = resourceFactory.newJarFileResource(fragFile.toUri());
assertNotNull(fragMount);
webfragxml = fragMount.resolve("/META-INF/web-fragment.xml");
assertNotNull(webfragxml);
assertTrue(Resources.isReadableFile(webfragxml));
Path testContainerDir = testDir.resolve("container");
FS.ensureDirExists(testContainerDir);
@ -94,9 +95,9 @@ public class TestMetaData
FS.ensureDirExists(testWebInfClassesDir);
containerDir = resourceFactory.newResource(testContainerDir);
assertNotNull(containerDir);
assertTrue(Resources.isReadableDirectory(containerDir));
webInfClassesDir = resourceFactory.newResource(testWebInfClassesDir);
assertNotNull(webInfClassesDir);
assertTrue(Resources.isReadableDirectory(webInfClassesDir));
wac = new WebAppContext();
applications = new ArrayList<>();

View File

@ -52,6 +52,7 @@ import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.FileSystemPool;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@ -235,8 +236,8 @@ public class WebAppContextTest
server.start();
ServletContext ctx = context.getServletContext();
assertNotNull(ctx.getRealPath("/doesnotexist"));
assertNotNull(ctx.getRealPath("/doesnotexist/"));
assertNull(ctx.getRealPath("/doesnotexist"));
assertNull(ctx.getRealPath("/doesnotexist/"));
}
/**
@ -410,7 +411,7 @@ public class WebAppContextTest
WebAppContext context = new WebAppContext();
Path testWebapp = MavenPaths.findTestResourceDir("webapp");
Resource testWebappResource = context.getResourceFactory().newResource(testWebapp);
assertTrue(testWebappResource.isDirectory());
assertTrue(Resources.isReadableDirectory(testWebappResource));
context.setBaseResource(testWebappResource);
context.setContextPath("/");