Jetty 12 - Simplification of aliases in `PathResource` (Take 2) (#8734)
* simplify the PathResource.resolveTargetPath code * changes to how PathResource handles aliases * fix usages of Resource.getTargetUri() * fixes for FileSystemResourceTest * update javadoc for Resource.getTargetURI() * rename getTargetURI to getCanonicalURI * let resolveCanonicalPath return null if resource does not exist * add test in PathResourceTest for broken symlinks * some changes from review + optimization for exists() * restore name to getTargetUri in Resource * fix some tests related to PathResource changes * revert changes to PathResource equals and hashcode * also compare URI in PathResource * checkAlias to resolveAlias * PathResource cleanup + Adding comments about class fields. + Removing normalization from input/output/comparison flows. + Collapsing `resolveTargetPath` into `resolveAlias` to react accordingly to the exceptions that can flow out of Path.toRealPath(). + Failure on Path.toRealPath() is never an alias, as the resource cannot ever be served anyway. + More comments in `resolveAlias()` + Failed / Bad / Nonexistent / Inaccessible resources are not aliases to anything. * Renames of targetPath/targetUri `targetPath` to `realPath` `targetURI` to `realURI` * Cleanup alias/aliasResolved booleans * More testcase cleanup around not-exist * Don't resolve alias on Error during toRealPath * Add test to check how Alias check behaves if non-existent resource exists later Signed-off-by: Lachlan Roberts <lachlan@webtide.com> Co-authored-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
6ba81ce10d
commit
9061348ec4
|
@ -867,7 +867,7 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
|
||||||
if (resource.isAlias())
|
if (resource.isAlias())
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Aliased resource: {} -> {}", resource, resource.getTargetURI());
|
LOG.debug("Aliased resource: {} -> {}", resource, resource.getRealURI());
|
||||||
|
|
||||||
// alias checks
|
// alias checks
|
||||||
for (AliasCheck check : _aliasChecks)
|
for (AliasCheck check : _aliasChecks)
|
||||||
|
|
|
@ -344,7 +344,7 @@ public class ContextHandlerGetResourceTest
|
||||||
|
|
||||||
Resource resource = context.getResource(path);
|
Resource resource = context.getResource(path);
|
||||||
assertNotNull(resource);
|
assertNotNull(resource);
|
||||||
assertEquals(context.getResource("/subdir/TextFile.Long.txt").getURI(), resource.getTargetURI());
|
assertEquals(context.getResource("/subdir/TextFile.Long.txt").getURI(), resource.getRealURI());
|
||||||
|
|
||||||
URL url = context.getServletContext().getResource(path);
|
URL url = context.getServletContext().getResource(path);
|
||||||
assertNotNull(url);
|
assertNotNull(url);
|
||||||
|
|
|
@ -47,10 +47,14 @@ public class PathResource extends Resource
|
||||||
.with("jrt")
|
.with("jrt")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// The path object represented by this instance
|
||||||
private final Path path;
|
private final Path path;
|
||||||
|
// The as-requested URI for this path object
|
||||||
private final URI uri;
|
private final URI uri;
|
||||||
private boolean targetResolved = false;
|
// True / False to indicate if this is an alias of something else, or null if the alias hasn't been resolved
|
||||||
private Path targetPath;
|
private Boolean alias;
|
||||||
|
// The Path representing the real-path of this PathResource instance. (populated during alias checking)
|
||||||
|
private Path realPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if the paths are the same name.
|
* Test if the paths are the same name.
|
||||||
|
@ -142,9 +146,7 @@ public class PathResource extends Resource
|
||||||
|
|
||||||
PathResource(URI uri, boolean bypassAllowedSchemeCheck)
|
PathResource(URI uri, boolean bypassAllowedSchemeCheck)
|
||||||
{
|
{
|
||||||
// normalize to referenced location, Paths.get() doesn't like "/bar/../foo/text.txt" style references
|
this(Paths.get(uri), uri, bypassAllowedSchemeCheck);
|
||||||
// and will return a Path that will not be found with `Files.exists()` or `Files.isDirectory()`
|
|
||||||
this(Paths.get(uri.normalize()), uri, bypassAllowedSchemeCheck);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PathResource(Path path)
|
PathResource(Path path)
|
||||||
|
@ -152,6 +154,13 @@ public class PathResource extends Resource
|
||||||
this(path, path.toUri(), true);
|
this(path, path.toUri(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a PathResource.
|
||||||
|
*
|
||||||
|
* @param path the Path object
|
||||||
|
* @param uri the as-requested URI for the resource
|
||||||
|
* @param bypassAllowedSchemeCheck true to bypass the allowed schemes check
|
||||||
|
*/
|
||||||
PathResource(Path path, URI uri, boolean bypassAllowedSchemeCheck)
|
PathResource(Path path, URI uri, boolean bypassAllowedSchemeCheck)
|
||||||
{
|
{
|
||||||
if (!uri.isAbsolute())
|
if (!uri.isAbsolute())
|
||||||
|
@ -159,9 +168,12 @@ public class PathResource extends Resource
|
||||||
if (!bypassAllowedSchemeCheck && !ALLOWED_SCHEMES.contains(uri.getScheme()))
|
if (!bypassAllowedSchemeCheck && !ALLOWED_SCHEMES.contains(uri.getScheme()))
|
||||||
throw new IllegalArgumentException("not an allowed scheme: " + uri);
|
throw new IllegalArgumentException("not an allowed scheme: " + uri);
|
||||||
|
|
||||||
String uriString = uri.toASCIIString();
|
if (Files.isDirectory(path))
|
||||||
if (Files.isDirectory(path) && !uriString.endsWith(URIUtil.SLASH))
|
{
|
||||||
uri = URIUtil.correctFileURI(URI.create(uriString + URIUtil.SLASH));
|
String uriString = uri.toASCIIString();
|
||||||
|
if (!uriString.endsWith(URIUtil.SLASH))
|
||||||
|
uri = URIUtil.correctFileURI(URI.create(uriString + URIUtil.SLASH));
|
||||||
|
}
|
||||||
|
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
|
@ -170,36 +182,38 @@ public class PathResource extends Resource
|
||||||
@Override
|
@Override
|
||||||
public boolean exists()
|
public boolean exists()
|
||||||
{
|
{
|
||||||
return Files.exists(targetPath != null ? targetPath : path);
|
if (alias == null)
|
||||||
|
{
|
||||||
|
// no alias check performed
|
||||||
|
return Files.exists(path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (realPath == null)
|
||||||
|
return false;
|
||||||
|
return Files.exists(realPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj)
|
|
||||||
{
|
|
||||||
if (this == obj)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PathResource other = (PathResource)obj;
|
|
||||||
return Objects.equals(path, other.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the {@link Path} of the resource
|
|
||||||
*/
|
|
||||||
public Path getPath()
|
public Path getPath()
|
||||||
{
|
{
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Path getRealPath()
|
||||||
|
{
|
||||||
|
resolveAlias();
|
||||||
|
return realPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URI getRealURI()
|
||||||
|
{
|
||||||
|
Path realPath = getRealPath();
|
||||||
|
return (realPath == null) ? null : realPath.toUri();
|
||||||
|
}
|
||||||
|
|
||||||
public List<Resource> list()
|
public List<Resource> list()
|
||||||
{
|
{
|
||||||
if (!isDirectory())
|
if (!isDirectory())
|
||||||
|
@ -220,6 +234,13 @@ public class PathResource extends Resource
|
||||||
return List.of(); // empty
|
return List.of(); // empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlias()
|
||||||
|
{
|
||||||
|
resolveAlias();
|
||||||
|
return alias != null && alias;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
|
@ -241,12 +262,6 @@ public class PathResource extends Resource
|
||||||
return this.uri;
|
return this.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Objects.hashCode(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isContainedIn(Resource r)
|
public boolean isContainedIn(Resource r)
|
||||||
{
|
{
|
||||||
|
@ -255,88 +270,141 @@ public class PathResource extends Resource
|
||||||
return r.getClass() == PathResource.class && path.startsWith(r.getPath());
|
return r.getClass() == PathResource.class && path.startsWith(r.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public URI getTargetURI()
|
* <p>
|
||||||
|
* Perform a check of the original Path and as-requested URI to determine
|
||||||
|
* if this resource is an alias to another name/location.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <table>
|
||||||
|
* <thead>
|
||||||
|
* <tr>
|
||||||
|
* <th>path</th>
|
||||||
|
* <th>realPath</th>
|
||||||
|
* <th>uri-as-requested</th>
|
||||||
|
* <th>uri-from-realPath</th>
|
||||||
|
* <th>alias</th>
|
||||||
|
* </tr>
|
||||||
|
* </thead>
|
||||||
|
* <tbody>
|
||||||
|
* <tr>
|
||||||
|
* <td><code>C:/temp/aa./foo.txt</code></td>
|
||||||
|
* <td><code>C:/temp/aa/foo.txt</code></td>
|
||||||
|
* <td><code>file:///C:/temp/aa./foo.txt</code></td>
|
||||||
|
* <td><code>file:///C:/temp/aa./foo.txt</code></td>
|
||||||
|
* <td>true</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><code>/tmp/foo-symlink</code></td>
|
||||||
|
* <td><code>/tmp/bar.txt</code></td>
|
||||||
|
* <td><code>file:///tmp/foo-symlink</code></td>
|
||||||
|
* <td><code>file:///tmp/bar.txt</code></td>
|
||||||
|
* <td>true</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><code>C:/temp/aa.txt</code></td>
|
||||||
|
* <td><code>C:/temp/AA.txt</code></td>
|
||||||
|
* <td><code>file:///C:/temp/aa.txt</code></td>
|
||||||
|
* <td><code>file:///C:/temp/AA.txt</code></td>
|
||||||
|
* <td>true</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><code>/tmp/bar-exists/../foo.txt</code></td>
|
||||||
|
* <td><code>/tmp/foo.txt</code></td>
|
||||||
|
* <td><code>file:///tmp/bar-exists/../foo.txt</code></td>
|
||||||
|
* <td><code>file:///tmp/foo.txt</code></td>
|
||||||
|
* <td>true</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><code>/tmp/doesnt-exist.txt</code></td>
|
||||||
|
* <td>null (does not exist)</td>
|
||||||
|
* <td><code>file:///tmp/doesnt-exist.txt</code></td>
|
||||||
|
* <td>null (does not exist)</td>
|
||||||
|
* <td>false</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><code>/tmp/doesnt-exist/../foo.txt</code></td>
|
||||||
|
* <td>null (intermediate does not exist)</td>
|
||||||
|
* <td><code>file:///tmp/doesnt-exist/../foo.txt</code></td>
|
||||||
|
* <td>null (intermediate does not exist)</td>
|
||||||
|
* <td>false</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><code>/var/protected/config.xml</code></td>
|
||||||
|
* <td>null (no permissions)</td>
|
||||||
|
* <td><code>file:///var/protected/config.xml</code></td>
|
||||||
|
* <td>null (no permission)</td>
|
||||||
|
* <td>false</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><code>/tmp/foo-symlink</code></td>
|
||||||
|
* <td>null (broken symlink, doesn't point to anything)</td>
|
||||||
|
* <td><code>file:///tmp/foo-symlink</code></td>
|
||||||
|
* <td>null (broken symlink, doesn't point to anything)</td>
|
||||||
|
* <td>false</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><code>C:/temp/cannot:be:referenced</code></td>
|
||||||
|
* <td>null (illegal filename)</td>
|
||||||
|
* <td><code>file:///C:/temp/cannot:be:referenced</code></td>
|
||||||
|
* <td>null (illegal filename)</td>
|
||||||
|
* <td>false</td>
|
||||||
|
* </tr>
|
||||||
|
* </tbody>
|
||||||
|
* </table>
|
||||||
|
*/
|
||||||
|
private void resolveAlias()
|
||||||
{
|
{
|
||||||
if (!targetResolved)
|
if (alias == null)
|
||||||
{
|
|
||||||
targetPath = resolveTargetPath();
|
|
||||||
targetResolved = true;
|
|
||||||
}
|
|
||||||
if (targetPath == null)
|
|
||||||
return null;
|
|
||||||
return targetPath.toUri();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path resolveTargetPath()
|
|
||||||
{
|
|
||||||
Path abs = path;
|
|
||||||
|
|
||||||
// TODO: is this a valid shortcut?
|
|
||||||
// If the path doesn't exist, then there's no alias to reference
|
|
||||||
if (!Files.exists(path))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
/* Catch situation where the Path class has already normalized
|
|
||||||
* the URI eg. input path "aa./foo.txt"
|
|
||||||
* from an #resolve(String) is normalized away during
|
|
||||||
* the creation of a Path object reference.
|
|
||||||
* If the URI is different from the Path.toUri() then
|
|
||||||
* we will just use the original URI to construct the
|
|
||||||
* alias reference Path.
|
|
||||||
*
|
|
||||||
* We use the method `toUri(Path)` here, instead of
|
|
||||||
* Path.toUri() to ensure that the path contains
|
|
||||||
* a trailing slash if it's a directory, (something
|
|
||||||
* not all FileSystems seem to support)
|
|
||||||
*/
|
|
||||||
if (!URIUtil.equalsIgnoreEncodings(uri, toUri(path)))
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Use normalized path to get past navigational references like "/bar/../foo/test.txt"
|
// Default behavior is to follow symlinks.
|
||||||
Path ref = Paths.get(uri.normalize());
|
// We don't want to use the NO_FOLLOW_LINKS parameter as that takes this call from
|
||||||
return ref.toRealPath();
|
// being filesystem aware, and using FileSystem specific techniques to find
|
||||||
|
// the real file, to being done in-API (which doesn't work reliably on
|
||||||
|
// filesystems that have different names for the same file.
|
||||||
|
// eg: case-insensitive file systems, unicode name normalization,
|
||||||
|
// alternate names, etc)
|
||||||
|
// We also don't want to use Path.normalize() here as that eliminates
|
||||||
|
// the knowledge of what directories are being navigated through.
|
||||||
|
realPath = path.toRealPath();
|
||||||
}
|
}
|
||||||
catch (IOException ioe)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
// If the toRealPath() call fails, then let
|
if (e instanceof IOException)
|
||||||
// the alias checking routines continue on
|
LOG.trace("IGNORED", e);
|
||||||
// to other techniques.
|
else
|
||||||
LOG.trace("IGNORED", ioe);
|
LOG.warn("bad alias ({} {}) for {}", e.getClass().getName(), e.getMessage(), path);
|
||||||
|
// Not possible to serve this resource.
|
||||||
|
// - This resource doesn't exist.
|
||||||
|
// - No access rights to this resource.
|
||||||
|
// - Unable to read the file or directory.
|
||||||
|
// - Navigation segments (eg: "foo/../test.txt") would go through something that doesn't exist, or not accessible.
|
||||||
|
// - FileSystem doesn't support toRealPath.
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!abs.isAbsolute())
|
/* If the path and realPath are the same, also check
|
||||||
abs = path.toAbsolutePath();
|
* The as-requested URI as it will represent what was
|
||||||
|
* URI created this PathResource.
|
||||||
// Any normalization difference means it's an alias,
|
* e.g. the input of `resolve("aa./foo.txt")
|
||||||
// and we don't want to bother further to follow
|
* on windows would resolve the path, but the Path.toUri() would
|
||||||
// symlinks as it's an alias anyway.
|
* not always show this extension-less access.
|
||||||
Path normal = path.normalize();
|
* The as-requested URI will retain this extra '.' and be used
|
||||||
if (!isSameName(abs, normal))
|
* to evaluate if the realPath.toUri() is the same as the as-requested URI.
|
||||||
return normal;
|
*
|
||||||
|
* // On Windows
|
||||||
try
|
* PathResource resource = PathResource("C:/temp");
|
||||||
{
|
* PathResource child = resource.resolve("aa./foo.txt");
|
||||||
if (Files.isSymbolicLink(path))
|
* child.exists() == true
|
||||||
return path.getParent().resolve(Files.readSymbolicLink(path));
|
* child.isAlias() == true
|
||||||
if (Files.exists(path))
|
* child.toUri() == "file:///C:/temp/aa./foo.txt"
|
||||||
{
|
* child.getPath().toUri() == "file:///C:/temp/aa/foo.txt"
|
||||||
Path real = abs.toRealPath();
|
* child.getRealURI() == "file:///C:/temp/aa/foo.txt"
|
||||||
if (!isSameName(abs, real))
|
*/
|
||||||
return real;
|
alias = !isSameName(path, realPath) || !Objects.equals(uri, toUri(realPath));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
LOG.trace("IGNORED", e);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
LOG.warn("bad alias ({} {}) for {}", e.getClass().getName(), e.getMessage(), path);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -373,6 +441,25 @@ public class PathResource extends Resource
|
||||||
return pathUri;
|
return pathUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
PathResource other = (PathResource)obj;
|
||||||
|
return Objects.equals(path, other.path) && Objects.equals(uri, other.uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hash(path, uri);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -297,19 +297,20 @@ public abstract class Resource implements Iterable<Resource>
|
||||||
*/
|
*/
|
||||||
public boolean isAlias()
|
public boolean isAlias()
|
||||||
{
|
{
|
||||||
return getTargetURI() != null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this Resource is an alias pointing to a different location,
|
* <p>The real URI of the resource.</p>
|
||||||
* return the target location as URI.
|
* <p>If this Resource is an alias, ({@link #isAlias()}), this
|
||||||
|
* URI will be different from {@link #getURI()}, and will point to the real name/location
|
||||||
|
* of the Resource.</p>
|
||||||
*
|
*
|
||||||
* @return The target URI location of this resource,
|
* @return The real URI location of this resource.
|
||||||
* or null if there is no target URI location (eg: not an alias, or a symlink)
|
|
||||||
*/
|
*/
|
||||||
public URI getTargetURI()
|
public URI getRealURI()
|
||||||
{
|
{
|
||||||
return null;
|
return getURI();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.util.ssl;
|
package org.eclipse.jetty.util.ssl;
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
@ -48,16 +47,15 @@ public class KeyStoreScanner extends ContainerLifeCycle implements Scanner.Discr
|
||||||
{
|
{
|
||||||
this.sslContextFactory = sslContextFactory;
|
this.sslContextFactory = sslContextFactory;
|
||||||
Resource keystoreResource = sslContextFactory.getKeyStoreResource();
|
Resource keystoreResource = sslContextFactory.getKeyStoreResource();
|
||||||
Path monitoredFile = keystoreResource.getPath();
|
if (!keystoreResource.exists())
|
||||||
if (monitoredFile == null || !Files.exists(monitoredFile))
|
|
||||||
throw new IllegalArgumentException("keystore file does not exist");
|
throw new IllegalArgumentException("keystore file does not exist");
|
||||||
if (Files.isDirectory(monitoredFile))
|
if (keystoreResource.isDirectory())
|
||||||
throw new IllegalArgumentException("expected keystore file not directory");
|
throw new IllegalArgumentException("expected keystore file not directory");
|
||||||
|
|
||||||
// Use real location of keystore (if different), so that change monitoring can work properly
|
// Use real location of keystore (if different), so that change monitoring can work properly
|
||||||
URI targetURI = keystoreResource.getTargetURI();
|
Path monitoredFile = keystoreResource.getPath();
|
||||||
if (targetURI != null)
|
if (keystoreResource.isAlias())
|
||||||
monitoredFile = Paths.get(targetURI);
|
monitoredFile = Paths.get(keystoreResource.getRealURI());
|
||||||
|
|
||||||
keystoreFile = monitoredFile;
|
keystoreFile = monitoredFile;
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
|
|
|
@ -55,13 +55,15 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.endsWith;
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
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.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||||
|
@ -86,32 +88,55 @@ public class FileSystemResourceTest
|
||||||
assertThat(FileSystemPool.INSTANCE.mounts(), empty());
|
assertThat(FileSystemPool.INSTANCE.mounts(), empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Matcher<Resource> hasNoTargetURI()
|
private Matcher<Resource> isAlias()
|
||||||
{
|
{
|
||||||
return new BaseMatcher<>()
|
return new BaseMatcher<>()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Object item)
|
public boolean matches(Object item)
|
||||||
{
|
{
|
||||||
final Resource res = (Resource)item;
|
return ((Resource)item).isAlias();
|
||||||
return res.getTargetURI() == null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void describeTo(Description description)
|
public void describeTo(Description description)
|
||||||
{
|
{
|
||||||
description.appendText("getTargetURI should return null");
|
description.appendText("isAlias() should return true");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void describeMismatch(Object item, Description description)
|
public void describeMismatch(Object item, Description description)
|
||||||
{
|
{
|
||||||
description.appendText("was ").appendValue(((Resource)item).getTargetURI());
|
description.appendText("was ").appendValue(((Resource)item).getRealURI());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Matcher<Resource> isTargetFor(final Resource resource)
|
private Matcher<Resource> isNotAlias()
|
||||||
|
{
|
||||||
|
return new BaseMatcher<>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean matches(Object item)
|
||||||
|
{
|
||||||
|
return !((Resource)item).isAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description)
|
||||||
|
{
|
||||||
|
description.appendText("isAlias() should return false");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeMismatch(Object item, Description description)
|
||||||
|
{
|
||||||
|
description.appendText("was ").appendValue(((Resource)item).getRealURI());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Matcher<Resource> isRealResourceFor(final Resource resource)
|
||||||
{
|
{
|
||||||
return new BaseMatcher<>()
|
return new BaseMatcher<>()
|
||||||
{
|
{
|
||||||
|
@ -119,27 +144,19 @@ public class FileSystemResourceTest
|
||||||
public boolean matches(Object item)
|
public boolean matches(Object item)
|
||||||
{
|
{
|
||||||
final Resource ritem = (Resource)item;
|
final Resource ritem = (Resource)item;
|
||||||
final URI alias = ritem.getTargetURI();
|
return ritem.getRealURI().equals(resource.getRealURI());
|
||||||
if (alias == null)
|
|
||||||
{
|
|
||||||
return resource.getTargetURI() == null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return alias.equals(resource.getURI());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void describeTo(Description description)
|
public void describeTo(Description description)
|
||||||
{
|
{
|
||||||
description.appendText("getTargetURI should return ").appendValue(resource.getURI());
|
description.appendText("getRealURI should return ").appendValue(resource.getURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void describeMismatch(Object item, Description description)
|
public void describeMismatch(Object item, Description description)
|
||||||
{
|
{
|
||||||
description.appendText("was ").appendValue(((Resource)item).getTargetURI());
|
description.appendText("was ").appendValue(((Resource)item).getRealURI());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -596,13 +613,13 @@ public class FileSystemResourceTest
|
||||||
// Access to the same resource, but via a symlink means that they are not equivalent
|
// Access to the same resource, but via a symlink means that they are not equivalent
|
||||||
assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false));
|
assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false));
|
||||||
|
|
||||||
assertThat("resource.targetURI", resFoo, hasNoTargetURI());
|
assertThat("resource.targetURI", resFoo, isNotAlias());
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resFoo.getURI()), hasNoTargetURI());
|
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resFoo.getURI()), isNotAlias());
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resFoo.getPath()), hasNoTargetURI());
|
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resFoo.getPath()), isNotAlias());
|
||||||
|
|
||||||
assertThat("targetURI", resBar, isTargetFor(resFoo));
|
assertThat("targetURI", resBar, isRealResourceFor(resFoo));
|
||||||
assertThat("uri.targetURI", ResourceFactory.root().newResource(resBar.getURI()), isTargetFor(resFoo));
|
assertThat("uri.targetURI", ResourceFactory.root().newResource(resBar.getURI()), isRealResourceFor(resFoo));
|
||||||
assertThat("file.targetURI", ResourceFactory.root().newResource(resBar.getPath()), isTargetFor(resFoo));
|
assertThat("file.targetURI", ResourceFactory.root().newResource(resBar.getPath()), isRealResourceFor(resFoo));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -618,6 +635,7 @@ public class FileSystemResourceTest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Files.createSymbolicLink(bar, foo);
|
Files.createSymbolicLink(bar, foo);
|
||||||
|
// Now a "bar" symlink exists, pointing to a "foo" that doesn't exist
|
||||||
symlinkSupported = true;
|
symlinkSupported = true;
|
||||||
}
|
}
|
||||||
catch (UnsupportedOperationException | FileSystemException e)
|
catch (UnsupportedOperationException | FileSystemException e)
|
||||||
|
@ -636,13 +654,20 @@ public class FileSystemResourceTest
|
||||||
// Access to the same resource, but via a symlink means that they are not equivalent
|
// Access to the same resource, but via a symlink means that they are not equivalent
|
||||||
assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false));
|
assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false));
|
||||||
|
|
||||||
assertThat("resource.targetURI", resFoo, hasNoTargetURI());
|
// This is not an alias because the file does not exist.
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resFoo.getURI()), hasNoTargetURI());
|
assertFalse(resFoo.exists());
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resFoo.getPath()), hasNoTargetURI());
|
assertFalse(Files.exists(resFoo.getPath()));
|
||||||
|
assertFalse(resFoo.isAlias());
|
||||||
|
assertNotNull(resFoo.getURI());
|
||||||
|
assertNull(resFoo.getRealURI());
|
||||||
|
|
||||||
assertThat("targetURI", resBar, isTargetFor(resFoo));
|
// This is alias because the target file does not exist even though the symlink file does exist.
|
||||||
assertThat("uri.targetURI", ResourceFactory.root().newResource(resBar.getURI()), isTargetFor(resFoo));
|
// This resource cannot be served, so it should not exist, nor have an alias
|
||||||
assertThat("file.targetURI", ResourceFactory.root().newResource(resBar.getPath()), isTargetFor(resFoo));
|
assertFalse(resBar.exists());
|
||||||
|
assertFalse(Files.exists(resBar.getPath()));
|
||||||
|
assertFalse(resBar.isAlias());
|
||||||
|
assertNotNull(resBar.getURI());
|
||||||
|
assertNull(resBar.getRealURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -657,9 +682,9 @@ public class FileSystemResourceTest
|
||||||
// Reference to actual resource that exists
|
// Reference to actual resource that exists
|
||||||
Resource resource = base.resolve("file");
|
Resource resource = base.resolve("file");
|
||||||
|
|
||||||
assertThat("resource.targetURI", resource, hasNoTargetURI());
|
assertThat("resource.targetURI", resource, isNotAlias());
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), hasNoTargetURI());
|
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), isNotAlias());
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), hasNoTargetURI());
|
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), isNotAlias());
|
||||||
|
|
||||||
// On some case-insensitive file systems, lets see if an alternate
|
// On some case-insensitive file systems, lets see if an alternate
|
||||||
// case for the filename results in an alias reference
|
// case for the filename results in an alias reference
|
||||||
|
@ -667,9 +692,9 @@ public class FileSystemResourceTest
|
||||||
if (alias.exists())
|
if (alias.exists())
|
||||||
{
|
{
|
||||||
// If it exists, it must be an alias
|
// If it exists, it must be an alias
|
||||||
assertThat("targetURI", alias, isTargetFor(resource));
|
assertThat("targetURI", alias, isRealResourceFor(resource));
|
||||||
assertThat("targetURI.uri", ResourceFactory.root().newResource(alias.getURI()), isTargetFor(resource));
|
assertThat("targetURI.uri", ResourceFactory.root().newResource(alias.getURI()), isRealResourceFor(resource));
|
||||||
assertThat("targetURI.file", ResourceFactory.root().newResource(alias.getPath()), isTargetFor(resource));
|
assertThat("targetURI.file", ResourceFactory.root().newResource(alias.getPath()), isRealResourceFor(resource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,9 +720,9 @@ public class FileSystemResourceTest
|
||||||
// Long filename
|
// Long filename
|
||||||
Resource resource = base.resolve("TextFile.Long.txt");
|
Resource resource = base.resolve("TextFile.Long.txt");
|
||||||
|
|
||||||
assertThat("resource.targetURI", resource, hasNoTargetURI());
|
assertThat("resource.targetURI", resource, isNotAlias());
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), hasNoTargetURI());
|
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), isNotAlias());
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), hasNoTargetURI());
|
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), isNotAlias());
|
||||||
|
|
||||||
// On some versions of Windows, the long filename can be referenced
|
// On some versions of Windows, the long filename can be referenced
|
||||||
// via a short 8.3 equivalent filename.
|
// via a short 8.3 equivalent filename.
|
||||||
|
@ -705,9 +730,9 @@ public class FileSystemResourceTest
|
||||||
if (alias.exists())
|
if (alias.exists())
|
||||||
{
|
{
|
||||||
// If it exists, it must be an alias
|
// If it exists, it must be an alias
|
||||||
assertThat("targetURI", alias, isTargetFor(resource));
|
assertThat("targetURI", alias, isRealResourceFor(resource));
|
||||||
assertThat("targetURI.uri", ResourceFactory.root().newResource(alias.getURI()), isTargetFor(resource));
|
assertThat("targetURI.uri", ResourceFactory.root().newResource(alias.getURI()), isRealResourceFor(resource));
|
||||||
assertThat("targetURI.file", ResourceFactory.root().newResource(alias.getPath()), isTargetFor(resource));
|
assertThat("targetURI.file", ResourceFactory.root().newResource(alias.getPath()), isRealResourceFor(resource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -731,9 +756,9 @@ public class FileSystemResourceTest
|
||||||
Resource base = ResourceFactory.root().newResource(dir);
|
Resource base = ResourceFactory.root().newResource(dir);
|
||||||
Resource resource = base.resolve("testfile");
|
Resource resource = base.resolve("testfile");
|
||||||
|
|
||||||
assertThat("resource.targetURI", resource, hasNoTargetURI());
|
assertThat("resource.targetURI", resource, isNotAlias());
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), hasNoTargetURI());
|
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), isNotAlias());
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), hasNoTargetURI());
|
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), isNotAlias());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -742,9 +767,9 @@ public class FileSystemResourceTest
|
||||||
if (alias.exists())
|
if (alias.exists())
|
||||||
{
|
{
|
||||||
// If it exists, it must be an alias
|
// If it exists, it must be an alias
|
||||||
assertThat("resource.targetURI", alias, isTargetFor(resource));
|
assertThat("resource.targetURI", alias, isRealResourceFor(resource));
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(alias.getURI()), isTargetFor(resource));
|
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(alias.getURI()), isRealResourceFor(resource));
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(alias.getPath()), isTargetFor(resource));
|
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(alias.getPath()), isRealResourceFor(resource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (InvalidPathException e)
|
catch (InvalidPathException e)
|
||||||
|
@ -773,9 +798,9 @@ public class FileSystemResourceTest
|
||||||
Resource base = ResourceFactory.root().newResource(dir);
|
Resource base = ResourceFactory.root().newResource(dir);
|
||||||
Resource resource = base.resolve("testfile");
|
Resource resource = base.resolve("testfile");
|
||||||
|
|
||||||
assertThat("resource.targetURI", resource, hasNoTargetURI());
|
assertThat("resource.targetURI", resource, isNotAlias());
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), hasNoTargetURI());
|
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), isNotAlias());
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), hasNoTargetURI());
|
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), isNotAlias());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -786,9 +811,9 @@ public class FileSystemResourceTest
|
||||||
assumeTrue(alias.getURI().getScheme().equals("file"));
|
assumeTrue(alias.getURI().getScheme().equals("file"));
|
||||||
|
|
||||||
// If it exists, it must be an alias
|
// If it exists, it must be an alias
|
||||||
assertThat("resource.targetURI", alias, isTargetFor(resource));
|
assertThat("resource.targetURI", alias, isRealResourceFor(resource));
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(alias.getURI()), isTargetFor(resource));
|
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(alias.getURI()), isRealResourceFor(resource));
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(alias.getPath()), isTargetFor(resource));
|
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(alias.getPath()), isRealResourceFor(resource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (InvalidPathException e)
|
catch (InvalidPathException e)
|
||||||
|
@ -817,9 +842,9 @@ public class FileSystemResourceTest
|
||||||
Resource base = ResourceFactory.root().newResource(dir);
|
Resource base = ResourceFactory.root().newResource(dir);
|
||||||
Resource resource = base.resolve("testfile");
|
Resource resource = base.resolve("testfile");
|
||||||
|
|
||||||
assertThat("resource.targetURI", resource, hasNoTargetURI());
|
assertThat("resource.targetURI", resource, isNotAlias());
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), hasNoTargetURI());
|
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(resource.getURI()), isNotAlias());
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), hasNoTargetURI());
|
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(resource.getPath()), isNotAlias());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -828,9 +853,9 @@ public class FileSystemResourceTest
|
||||||
if (alias.exists())
|
if (alias.exists())
|
||||||
{
|
{
|
||||||
// If it exists, it must be an alias
|
// If it exists, it must be an alias
|
||||||
assertThat("resource.targetURI", alias, isTargetFor(resource));
|
assertThat("resource.targetURI", alias, isRealResourceFor(resource));
|
||||||
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(alias.getURI()), isTargetFor(resource));
|
assertThat("resource.uri.targetURI", ResourceFactory.root().newResource(alias.getURI()), isRealResourceFor(resource));
|
||||||
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(alias.getPath()), isTargetFor(resource));
|
assertThat("resource.file.targetURI", ResourceFactory.root().newResource(alias.getPath()), isRealResourceFor(resource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (InvalidPathException e)
|
catch (InvalidPathException e)
|
||||||
|
@ -857,7 +882,7 @@ public class FileSystemResourceTest
|
||||||
|
|
||||||
Resource base = ResourceFactory.root().newResource(dir);
|
Resource base = ResourceFactory.root().newResource(dir);
|
||||||
Resource res = base.resolve("foo;");
|
Resource res = base.resolve("foo;");
|
||||||
assertThat("Target URI: " + res, res, hasNoTargetURI());
|
assertThat("Target URI: " + res, res, isNotAlias());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1052,25 +1077,25 @@ public class FileSystemResourceTest
|
||||||
|
|
||||||
Resource fileres = ResourceFactory.root().newResource(refQuoted);
|
Resource fileres = ResourceFactory.root().newResource(refQuoted);
|
||||||
assertThat("Exists: " + refQuoted, fileres.exists(), is(true));
|
assertThat("Exists: " + refQuoted, fileres.exists(), is(true));
|
||||||
assertThat("Target URI: " + refQuoted, fileres, hasNoTargetURI());
|
assertThat("Is Not Alias: " + refQuoted, fileres, isNotAlias());
|
||||||
|
|
||||||
URI refEncoded = dir.toUri().resolve("foo%27s.txt");
|
URI refEncoded = dir.toUri().resolve("foo%27s.txt");
|
||||||
|
|
||||||
fileres = ResourceFactory.root().newResource(refEncoded);
|
fileres = ResourceFactory.root().newResource(refEncoded);
|
||||||
assertThat("Exists: " + refEncoded, fileres.exists(), is(true));
|
assertThat("Exists: " + refEncoded, fileres.exists(), is(true));
|
||||||
assertThat("Target URI: " + refEncoded, fileres, hasNoTargetURI());
|
assertThat("Is Alias: " + refEncoded, fileres, isAlias());
|
||||||
|
|
||||||
URI refQuoteSpace = dir.toUri().resolve("f%20o's.txt");
|
URI refQuoteSpace = dir.toUri().resolve("f%20o's.txt");
|
||||||
|
|
||||||
fileres = ResourceFactory.root().newResource(refQuoteSpace);
|
fileres = ResourceFactory.root().newResource(refQuoteSpace);
|
||||||
assertThat("Exists: " + refQuoteSpace, fileres.exists(), is(true));
|
assertThat("Exists: " + refQuoteSpace, fileres.exists(), is(true));
|
||||||
assertThat("Target URI: " + refQuoteSpace, fileres, hasNoTargetURI());
|
assertThat("Is Not Alias: " + refQuoteSpace, fileres, isNotAlias());
|
||||||
|
|
||||||
URI refEncodedSpace = dir.toUri().resolve("f%20o%27s.txt");
|
URI refEncodedSpace = dir.toUri().resolve("f%20o%27s.txt");
|
||||||
|
|
||||||
fileres = ResourceFactory.root().newResource(refEncodedSpace);
|
fileres = ResourceFactory.root().newResource(refEncodedSpace);
|
||||||
assertThat("Exists: " + refEncodedSpace, fileres.exists(), is(true));
|
assertThat("Exists: " + refEncodedSpace, fileres.exists(), is(true));
|
||||||
assertThat("Target URI: " + refEncodedSpace, fileres, hasNoTargetURI());
|
assertThat("Is Alias: " + refEncodedSpace, fileres, isAlias());
|
||||||
|
|
||||||
URI refA = dir.toUri().resolve("foo's.txt");
|
URI refA = dir.toUri().resolve("foo's.txt");
|
||||||
URI refB = dir.toUri().resolve("foo%27s.txt");
|
URI refB = dir.toUri().resolve("foo%27s.txt");
|
||||||
|
@ -1081,10 +1106,14 @@ public class FileSystemResourceTest
|
||||||
"URI[b] = " + refB;
|
"URI[b] = " + refB;
|
||||||
assertThat(msg, refA.equals(refB), is(false));
|
assertThat(msg, refA.equals(refB), is(false));
|
||||||
|
|
||||||
// now show that Resource.equals() does work
|
// These resources are not equal because they have different request URIs.
|
||||||
Resource a = ResourceFactory.root().newResource(refA);
|
Resource a = ResourceFactory.root().newResource(refA);
|
||||||
Resource b = ResourceFactory.root().newResource(refB);
|
Resource b = ResourceFactory.root().newResource(refB);
|
||||||
assertThat("A.equals(B)", a.equals(b), is(true));
|
assertThat("A.equals(B)", a.equals(b), is(false));
|
||||||
|
assertThat(a.getPath(), equalTo(b.getPath()));
|
||||||
|
assertThat(a.getRealURI(), equalTo(b.getRealURI()));
|
||||||
|
assertFalse(a.isAlias());
|
||||||
|
assertTrue(b.isAlias());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1156,7 +1185,7 @@ public class FileSystemResourceTest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
assertThat("Exists: " + basePath, base.exists(), is(true));
|
assertThat("Exists: " + basePath, base.exists(), is(true));
|
||||||
assertThat("Target URI: " + basePath, base, hasNoTargetURI());
|
assertThat("Target URI: " + basePath, base, isNotAlias());
|
||||||
|
|
||||||
Resource r = base.resolve("aa%5C/foo.txt");
|
Resource r = base.resolve("aa%5C/foo.txt");
|
||||||
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa%5C/foo.txt"));
|
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa%5C/foo.txt"));
|
||||||
|
@ -1165,8 +1194,8 @@ public class FileSystemResourceTest
|
||||||
{
|
{
|
||||||
assertThat("getPath().toString()", r.getPath().toString(), containsString("aa\\foo.txt"));
|
assertThat("getPath().toString()", r.getPath().toString(), containsString("aa\\foo.txt"));
|
||||||
assertThat("isAlias()", r.isAlias(), is(true));
|
assertThat("isAlias()", r.isAlias(), is(true));
|
||||||
assertThat("getTargetURI()", r.getTargetURI(), notNullValue());
|
assertThat("getRealURI()", r.getRealURI(), notNullValue());
|
||||||
assertThat("getTargetURI()", r.getTargetURI().toASCIIString(), containsString("aa/foo.txt"));
|
assertThat("getRealURI()", r.getRealURI().toASCIIString(), containsString("aa/foo.txt"));
|
||||||
assertThat("Exists: " + r, r.exists(), is(true));
|
assertThat("Exists: " + r, r.exists(), is(true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1200,7 +1229,7 @@ public class FileSystemResourceTest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
assertThat("Exists: " + basePath, base.exists(), is(true));
|
assertThat("Exists: " + basePath, base.exists(), is(true));
|
||||||
assertThat("Target URI: " + basePath, base, hasNoTargetURI());
|
assertThat("Is Not Alias: " + basePath, base, isNotAlias());
|
||||||
|
|
||||||
Resource r = base.resolve("aa./foo.txt");
|
Resource r = base.resolve("aa./foo.txt");
|
||||||
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa./foo.txt"));
|
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa./foo.txt"));
|
||||||
|
@ -1208,8 +1237,8 @@ public class FileSystemResourceTest
|
||||||
if (WINDOWS.isCurrentOs())
|
if (WINDOWS.isCurrentOs())
|
||||||
{
|
{
|
||||||
assertThat("isAlias()", r.isAlias(), is(true));
|
assertThat("isAlias()", r.isAlias(), is(true));
|
||||||
assertThat("getTargetURI()", r.getTargetURI(), notNullValue());
|
assertThat("getRealURI()", r.getRealURI(), notNullValue());
|
||||||
assertThat("getTargetURI()", r.getTargetURI().toASCIIString(), containsString("aa/foo.txt"));
|
assertThat("getRealURI()", r.getRealURI().toASCIIString(), containsString("aa/foo.txt"));
|
||||||
assertThat("Exists: " + r, r.exists(), is(true));
|
assertThat("Exists: " + r, r.exists(), is(true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1240,7 +1269,7 @@ public class FileSystemResourceTest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
assertThat("Exists: " + basePath, base.exists(), is(true));
|
assertThat("Exists: " + basePath, base.exists(), is(true));
|
||||||
assertThat("Target URI: " + basePath, base, hasNoTargetURI());
|
assertThat("Is Not Alias: " + basePath, base, isNotAlias());
|
||||||
|
|
||||||
Resource r = base.resolve("/foo.txt");
|
Resource r = base.resolve("/foo.txt");
|
||||||
assertThat("getURI()", r.getURI().toASCIIString(), containsString("/foo.txt"));
|
assertThat("getURI()", r.getURI().toASCIIString(), containsString("/foo.txt"));
|
||||||
|
@ -1270,13 +1299,13 @@ public class FileSystemResourceTest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
assertThat("Exists: " + basePath, base.exists(), is(true));
|
assertThat("Exists: " + basePath, base.exists(), is(true));
|
||||||
assertThat("Target URI: " + basePath, base, hasNoTargetURI());
|
assertThat("Is Not Alias: " + basePath, base, isNotAlias());
|
||||||
|
|
||||||
Resource r = base.resolve("//foo.txt");
|
Resource r = base.resolve("//foo.txt");
|
||||||
assertThat("getURI()", r.getURI().toASCIIString(), containsString("/foo.txt"));
|
assertThat("getURI()", r.getURI().toASCIIString(), containsString("/foo.txt"));
|
||||||
|
|
||||||
assertThat("isAlias()", r.isAlias(), is(false));
|
assertThat("isAlias()", r.isAlias(), is(false));
|
||||||
assertThat("getTargetURI()", r.getTargetURI(), nullValue());
|
assertThat("Is Not Alias: " + r.getPath(), r, isNotAlias());
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e)
|
catch (IllegalArgumentException e)
|
||||||
{
|
{
|
||||||
|
@ -1302,13 +1331,13 @@ public class FileSystemResourceTest
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
assertThat("Exists: " + basePath, base.exists(), is(true));
|
assertThat("Exists: " + basePath, base.exists(), is(true));
|
||||||
assertThat("Target URI: " + basePath, base, hasNoTargetURI());
|
assertThat("Is Not Alias: " + basePath, base, isNotAlias());
|
||||||
|
|
||||||
Resource r = base.resolve("aa//foo.txt");
|
Resource r = base.resolve("aa//foo.txt");
|
||||||
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa/foo.txt"));
|
assertThat("getURI()", r.getURI().toASCIIString(), containsString("aa/foo.txt"));
|
||||||
|
|
||||||
assertThat("isAlias()", r.isAlias(), is(false));
|
assertThat("isAlias()", r.isAlias(), is(false));
|
||||||
assertThat("getTargetURI()", r.getTargetURI(), nullValue());
|
assertThat("Is Not Alias: " + r.getPath(), r, isNotAlias());
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e)
|
catch (IllegalArgumentException e)
|
||||||
{
|
{
|
||||||
|
@ -1356,11 +1385,11 @@ public class FileSystemResourceTest
|
||||||
|
|
||||||
Resource base = ResourceFactory.root().newResource(utf8Dir);
|
Resource base = ResourceFactory.root().newResource(utf8Dir);
|
||||||
assertThat("Exists: " + utf8Dir, base.exists(), is(true));
|
assertThat("Exists: " + utf8Dir, base.exists(), is(true));
|
||||||
assertThat("Target URI: " + utf8Dir, base, hasNoTargetURI());
|
assertThat("Is Not Alias: " + utf8Dir, base, isNotAlias());
|
||||||
|
|
||||||
Resource r = base.resolve("file.txt");
|
Resource r = base.resolve("file.txt");
|
||||||
assertThat("Exists: " + r, r.exists(), is(true));
|
assertThat("Exists: " + r, r.exists(), is(true));
|
||||||
assertThat("Target URI: " + r, r, hasNoTargetURI());
|
assertThat("Is Not Alias: " + r, r, isNotAlias());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1371,7 +1400,7 @@ public class FileSystemResourceTest
|
||||||
Resource resource = base.resolve("WEB-INF/");
|
Resource resource = base.resolve("WEB-INF/");
|
||||||
assertThat("getURI()", resource.getURI().toASCIIString(), containsString("path/WEB-INF/"));
|
assertThat("getURI()", resource.getURI().toASCIIString(), containsString("path/WEB-INF/"));
|
||||||
assertThat("isAlias()", resource.isAlias(), is(false));
|
assertThat("isAlias()", resource.isAlias(), is(false));
|
||||||
assertThat("getTargetURI()", resource.getTargetURI(), nullValue());
|
assertThat("Is Not Alias: " + resource.getPath(), resource, isNotAlias());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String toString(Resource resource) throws IOException
|
private String toString(Resource resource) throws IOException
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||||
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.URIUtil;
|
import org.eclipse.jetty.util.URIUtil;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -38,6 +39,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
@ -303,37 +305,37 @@ public class PathResourceTest
|
||||||
// Test not alias paths
|
// Test not alias paths
|
||||||
Resource resource = resourceFactory.newResource(file);
|
Resource resource = resourceFactory.newResource(file);
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file.toAbsolutePath());
|
resource = resourceFactory.newResource(file.toAbsolutePath());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file.toUri());
|
resource = resourceFactory.newResource(file.toUri());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file.toUri().toString());
|
resource = resourceFactory.newResource(file.toUri().toString());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
resource = archiveResource.resolve("test.txt");
|
resource = archiveResource.resolve("test.txt");
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
|
|
||||||
// Test alias paths
|
// Test alias paths
|
||||||
resource = resourceFactory.newResource(file0);
|
resource = resourceFactory.newResource(file0);
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file0.toAbsolutePath());
|
resource = resourceFactory.newResource(file0.toAbsolutePath());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file0.toUri());
|
resource = resourceFactory.newResource(file0.toUri());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file0.toUri().toString());
|
resource = resourceFactory.newResource(file0.toUri().toString());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
|
|
||||||
resource = archiveResource.resolve("test.txt\0");
|
resource = archiveResource.resolve("test.txt\0");
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
}
|
}
|
||||||
catch (InvalidPathException e)
|
catch (InvalidPathException e)
|
||||||
{
|
{
|
||||||
|
@ -402,9 +404,9 @@ public class PathResourceTest
|
||||||
assertThat("resource.uri.alias", resourceFactory.newResource(resFoo.getURI()).isAlias(), is(false));
|
assertThat("resource.uri.alias", resourceFactory.newResource(resFoo.getURI()).isAlias(), is(false));
|
||||||
assertThat("resource.file.alias", resourceFactory.newResource(resFoo.getPath()).isAlias(), is(false));
|
assertThat("resource.file.alias", resourceFactory.newResource(resFoo.getPath()).isAlias(), is(false));
|
||||||
|
|
||||||
assertThat("targetURI", resBar.getTargetURI(), is(resFoo.getURI()));
|
assertThat("targetURI", resBar.getRealURI(), is(resFoo.getURI()));
|
||||||
assertThat("uri.targetURI", resourceFactory.newResource(resBar.getURI()).getTargetURI(), is(resFoo.getURI()));
|
assertThat("uri.targetURI", resourceFactory.newResource(resBar.getURI()).getRealURI(), is(resFoo.getURI()));
|
||||||
assertThat("file.targetURI", resourceFactory.newResource(resBar.getPath()).getTargetURI(), is(resFoo.getURI()));
|
assertThat("file.targetURI", resourceFactory.newResource(resBar.getPath()).getRealURI(), is(resFoo.getURI()));
|
||||||
}
|
}
|
||||||
catch (InvalidPathException e)
|
catch (InvalidPathException e)
|
||||||
{
|
{
|
||||||
|
@ -413,6 +415,43 @@ public class PathResourceTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBrokenSymlink(WorkDir workDir) throws Exception
|
||||||
|
{
|
||||||
|
Path testDir = workDir.getEmptyPathDir();
|
||||||
|
Path resourcePath = testDir.resolve("resource.txt");
|
||||||
|
IO.copy(MavenTestingUtils.getTestResourcePathFile("resource.txt").toFile(), resourcePath.toFile());
|
||||||
|
Path symlinkPath = Files.createSymbolicLink(testDir.resolve("symlink.txt"), resourcePath);
|
||||||
|
|
||||||
|
PathResource fileResource = new PathResource(resourcePath);
|
||||||
|
assertTrue(fileResource.exists());
|
||||||
|
PathResource symlinkResource = new PathResource(symlinkPath);
|
||||||
|
assertTrue(symlinkResource.exists());
|
||||||
|
|
||||||
|
// Their paths are not equal but not their canonical paths are.
|
||||||
|
assertThat(fileResource.getPath(), not(equalTo(symlinkResource.getPath())));
|
||||||
|
assertThat(fileResource.getPath(), equalTo(symlinkResource.getRealPath()));
|
||||||
|
assertFalse(fileResource.isAlias());
|
||||||
|
assertTrue(symlinkResource.isAlias());
|
||||||
|
assertTrue(fileResource.exists());
|
||||||
|
assertTrue(symlinkResource.exists());
|
||||||
|
|
||||||
|
// After deleting file the Resources do not exist even though symlink file exists.
|
||||||
|
assumeTrue(Files.deleteIfExists(resourcePath));
|
||||||
|
assertFalse(fileResource.exists());
|
||||||
|
assertFalse(symlinkResource.exists());
|
||||||
|
|
||||||
|
// Re-create and test the resources now that the file has been deleted.
|
||||||
|
fileResource = new PathResource(resourcePath);
|
||||||
|
assertFalse(fileResource.exists());
|
||||||
|
assertNull(fileResource.getRealPath());
|
||||||
|
assertTrue(symlinkResource.isAlias());
|
||||||
|
symlinkResource = new PathResource(symlinkPath);
|
||||||
|
assertFalse(symlinkResource.exists());
|
||||||
|
assertNull(symlinkResource.getRealPath());
|
||||||
|
assertFalse(symlinkResource.isAlias());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveNavigation(WorkDir workDir) throws Exception
|
public void testResolveNavigation(WorkDir workDir) throws Exception
|
||||||
{
|
{
|
||||||
|
@ -421,15 +460,22 @@ public class PathResourceTest
|
||||||
Path dir = docroot.resolve("dir");
|
Path dir = docroot.resolve("dir");
|
||||||
Files.createDirectory(dir);
|
Files.createDirectory(dir);
|
||||||
|
|
||||||
|
Path foo = docroot.resolve("foo");
|
||||||
|
Files.createDirectory(foo);
|
||||||
|
|
||||||
Path testText = dir.resolve("test.txt");
|
Path testText = dir.resolve("test.txt");
|
||||||
Files.createFile(testText);
|
Files.createFile(testText);
|
||||||
|
|
||||||
try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable())
|
try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable())
|
||||||
{
|
{
|
||||||
Resource rootRes = resourceFactory.newResource(docroot);
|
Resource rootRes = resourceFactory.newResource(docroot);
|
||||||
// This is the heart of the test, we should support this
|
// Test navigation through a directory that doesn't exist
|
||||||
Resource fileRes = rootRes.resolve("bar/../dir/test.txt");
|
Resource fileResViaBar = rootRes.resolve("bar/../dir/test.txt");
|
||||||
assertTrue(fileRes.exists());
|
assertFalse(fileResViaBar.exists());
|
||||||
|
|
||||||
|
// Test navigation through a directory that does exist
|
||||||
|
Resource fileResViaFoo = rootRes.resolve("foo/../dir/test.txt");
|
||||||
|
assertTrue(fileResViaFoo.exists());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,6 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
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.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@ExtendWith(WorkDirExtension.class)
|
@ExtendWith(WorkDirExtension.class)
|
||||||
|
@ -62,16 +60,34 @@ public class ResourceAliasTest
|
||||||
@Test
|
@Test
|
||||||
public void testAliasNavigation() throws IOException
|
public void testAliasNavigation() throws IOException
|
||||||
{
|
{
|
||||||
Path baseDir = workDir.getEmptyPathDir();
|
Path docroot = workDir.getEmptyPathDir();
|
||||||
|
|
||||||
Path foo = baseDir.resolve("foo");
|
Path dir = docroot.resolve("dir");
|
||||||
Files.createDirectories(foo);
|
Files.createDirectory(dir);
|
||||||
Files.writeString(foo.resolve("test.txt"), "Contents of test.txt", StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
Resource resource = ResourceFactory.root().newResource(baseDir);
|
Path foo = docroot.resolve("foo");
|
||||||
Resource test = resource.resolve("/bar/../foo/test.txt");
|
Files.createDirectory(foo);
|
||||||
assertTrue(test.exists(), "Should exist");
|
|
||||||
assertTrue(test.isAlias(), "Should be an alias");
|
Path testText = dir.resolve("test.txt");
|
||||||
|
Files.writeString(testText, "Contents of test.txt", StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable())
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
|
||||||
|
// Test navigation through a directory that does exist
|
||||||
|
Resource fileResViaFoo = rootRes.resolve("foo/../dir/test.txt");
|
||||||
|
assertTrue(fileResViaFoo.exists(), "Should exist");
|
||||||
|
assertTrue(fileResViaFoo.isAlias(), "Should be an alias");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -132,37 +148,37 @@ public class ResourceAliasTest
|
||||||
// Test not alias paths
|
// Test not alias paths
|
||||||
Resource resource = resourceFactory.newResource(file);
|
Resource resource = resourceFactory.newResource(file);
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file.toAbsolutePath());
|
resource = resourceFactory.newResource(file.toAbsolutePath());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file.toUri());
|
resource = resourceFactory.newResource(file.toUri());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file.toUri().toString());
|
resource = resourceFactory.newResource(file.toUri().toString());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
resource = dir.resolve("test.txt");
|
resource = dir.resolve("test.txt");
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNull(resource.getTargetURI());
|
assertFalse(resource.isAlias());
|
||||||
|
|
||||||
// Test alias paths
|
// Test alias paths
|
||||||
resource = resourceFactory.newResource(file0);
|
resource = resourceFactory.newResource(file0);
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file0.toAbsolutePath());
|
resource = resourceFactory.newResource(file0.toAbsolutePath());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file0.toUri());
|
resource = resourceFactory.newResource(file0.toUri());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
resource = resourceFactory.newResource(file0.toUri().toString());
|
resource = resourceFactory.newResource(file0.toUri().toString());
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
|
|
||||||
resource = dir.resolve("test.txt\0");
|
resource = dir.resolve("test.txt\0");
|
||||||
assertTrue(resource.exists());
|
assertTrue(resource.exists());
|
||||||
assertNotNull(resource.getTargetURI());
|
assertTrue(resource.isAlias());
|
||||||
}
|
}
|
||||||
catch (InvalidPathException e)
|
catch (InvalidPathException e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -380,7 +380,7 @@ public class ResourceTest
|
||||||
assertNotNull(dot);
|
assertNotNull(dot);
|
||||||
assertTrue(dot.exists());
|
assertTrue(dot.exists());
|
||||||
assertTrue(dot.isAlias(), "Reference to '.' is an alias to itself");
|
assertTrue(dot.isAlias(), "Reference to '.' is an alias to itself");
|
||||||
assertTrue(Files.isSameFile(dot.getPath(), Paths.get(dot.getTargetURI())));
|
assertTrue(Files.isSameFile(dot.getPath(), Paths.get(dot.getRealURI())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -402,12 +402,13 @@ public class ResourceTest
|
||||||
FS.ensureDirExists(dir);
|
FS.ensureDirExists(dir);
|
||||||
Path file = dir.resolve("bar.txt");
|
Path file = dir.resolve("bar.txt");
|
||||||
FS.touch(file);
|
FS.touch(file);
|
||||||
|
assertTrue(Files.exists(file));
|
||||||
Resource resource = resourceFactory.newResource(file);
|
Resource resource = resourceFactory.newResource(file);
|
||||||
Resource dot = resource.resolve(".");
|
Resource dot = resource.resolve(".");
|
||||||
|
// We are now pointing to a resource at ".../testDotAliasFileExists/foo/bar.txt/."
|
||||||
assertNotNull(dot);
|
assertNotNull(dot);
|
||||||
assertTrue(dot.exists());
|
assertFalse(dot.exists());
|
||||||
assertTrue(dot.isAlias(), "Reference to '.' is an alias to itself");
|
assertFalse(dot.isAlias(), "Reference to '.' against a file is not an alias");
|
||||||
assertTrue(Files.isSameFile(dot.getPath(), Paths.get(dot.getTargetURI())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -420,9 +421,10 @@ public class ResourceTest
|
||||||
assertFalse(Files.exists(file));
|
assertFalse(Files.exists(file));
|
||||||
Resource resource = resourceFactory.newResource(file);
|
Resource resource = resourceFactory.newResource(file);
|
||||||
Resource dot = resource.resolve(".");
|
Resource dot = resource.resolve(".");
|
||||||
|
// We are now pointing to a resource at ".../testDotAliasFileDoesNotExists/foo/bar.txt/."
|
||||||
assertNotNull(dot);
|
assertNotNull(dot);
|
||||||
assertFalse(dot.exists());
|
assertFalse(dot.exists());
|
||||||
assertFalse(dot.isAlias(), "Reference to '.' is not an alias as file doesn't exist");
|
assertFalse(dot.isAlias(), "Reference to '.' against a file is not an alias (the file also does not exist)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -74,7 +74,6 @@ import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||||
import org.eclipse.jetty.ee10.servlet.security.SecurityHandler;
|
import org.eclipse.jetty.ee10.servlet.security.SecurityHandler;
|
||||||
import org.eclipse.jetty.http.HttpURI;
|
import org.eclipse.jetty.http.HttpURI;
|
||||||
import org.eclipse.jetty.http.MimeTypes;
|
import org.eclipse.jetty.http.MimeTypes;
|
||||||
import org.eclipse.jetty.http.pathmap.MappedResource;
|
|
||||||
import org.eclipse.jetty.http.pathmap.MatchedResource;
|
import org.eclipse.jetty.http.pathmap.MatchedResource;
|
||||||
import org.eclipse.jetty.server.Handler;
|
import org.eclipse.jetty.server.Handler;
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
|
@ -1081,7 +1080,7 @@ public class ServletContextHandler extends ContextHandler implements Graceful
|
||||||
Resource baseResource = getBaseResource();
|
Resource baseResource = getBaseResource();
|
||||||
if (baseResource != null && baseResource.isAlias())
|
if (baseResource != null && baseResource.isAlias())
|
||||||
LOG.warn("BaseResource {} is aliased to {} in {}. May not be supported in future releases.",
|
LOG.warn("BaseResource {} is aliased to {} in {}. May not be supported in future releases.",
|
||||||
baseResource, baseResource.getTargetURI(), this);
|
baseResource, baseResource.getRealURI(), this);
|
||||||
|
|
||||||
if (_logger == null)
|
if (_logger == null)
|
||||||
_logger = LoggerFactory.getLogger(ContextHandler.class.getName() + getLogNameSuffix());
|
_logger = LoggerFactory.getLogger(ContextHandler.class.getName() + getLogNameSuffix());
|
||||||
|
|
|
@ -603,6 +603,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
||||||
* @return the list of tlds found
|
* @return the list of tlds found
|
||||||
* @throws IOException if unable to scan the directory
|
* @throws IOException if unable to scan the directory
|
||||||
*/
|
*/
|
||||||
|
// TODO: Needs to use resource.
|
||||||
public Collection<URL> getTlds(Path dir) throws IOException
|
public Collection<URL> getTlds(Path dir) throws IOException
|
||||||
{
|
{
|
||||||
if (dir == null || !Files.isDirectory(dir))
|
if (dir == null || !Files.isDirectory(dir))
|
||||||
|
|
|
@ -292,14 +292,14 @@ public class WebInfConfiguration extends AbstractConfiguration
|
||||||
throw new IllegalStateException("No resourceBase or war set for context");
|
throw new IllegalStateException("No resourceBase or war set for context");
|
||||||
|
|
||||||
// Use real location (if different) for WAR file, so that change/modification monitoring can work.
|
// Use real location (if different) for WAR file, so that change/modification monitoring can work.
|
||||||
URI targetURI = webApp.getTargetURI();
|
if (webApp.isAlias())
|
||||||
if (targetURI != null)
|
|
||||||
{
|
{
|
||||||
|
URI realURI = webApp.getRealURI();
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("{} anti-aliased to {}", webApp, targetURI);
|
LOG.debug("{} anti-aliased to {}", webApp, realURI);
|
||||||
Resource targetWebApp = context.newResource(targetURI);
|
Resource realWebApp = context.newResource(realURI);
|
||||||
if (targetWebApp != null && targetWebApp.exists())
|
if (realWebApp != null && realWebApp.exists())
|
||||||
webApp = targetWebApp;
|
webApp = realWebApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
|
|
|
@ -231,7 +231,7 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
||||||
{
|
{
|
||||||
compressedContent = null;
|
compressedContent = null;
|
||||||
Resource compressedResource = _factory.newResource(compressedPathInContext);
|
Resource compressedResource = _factory.newResource(compressedPathInContext);
|
||||||
if (compressedResource.exists() && ResourceContentFactory.newerThanOrEqual(compressedResource, resource) &&
|
if (compressedResource != null && compressedResource.exists() && ResourceContentFactory.newerThanOrEqual(compressedResource, resource) &&
|
||||||
compressedResource.length() < resource.length())
|
compressedResource.length() < resource.length())
|
||||||
{
|
{
|
||||||
compressedContent = new CachedHttpContent(compressedPathInContext, compressedResource, null);
|
compressedContent = new CachedHttpContent(compressedPathInContext, compressedResource, null);
|
||||||
|
|
|
@ -1383,11 +1383,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
// addPath with accept non-canonical paths that don't go above the root,
|
// addPath with accept non-canonical paths that don't go above the root,
|
||||||
// but will treat them as aliases. So unless allowed by an AliasChecker
|
// but will treat them as aliases. So unless allowed by an AliasChecker
|
||||||
// they will be rejected below.
|
// they will be rejected below.
|
||||||
Resource resource = baseResource.resolve(pathInContext);
|
return baseResource.resolve(pathInContext);
|
||||||
|
|
||||||
if (checkAlias(pathInContext, resource))
|
|
||||||
return resource;
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -1408,7 +1404,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
if (resource.isAlias())
|
if (resource.isAlias())
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Alias resource {} for {}", resource, resource.getTargetURI());
|
LOG.debug("Alias resource {} for {}", resource, resource.getRealURI());
|
||||||
|
|
||||||
// alias checks
|
// alias checks
|
||||||
for (AliasCheck check : getAliasChecks())
|
for (AliasCheck check : getAliasChecks())
|
||||||
|
|
|
@ -253,6 +253,15 @@ public class ResourceService
|
||||||
return response.isCommitted();
|
return response.isCommitted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContextHandler contextHandler = ContextHandler.getContextHandler(request.getServletContext());
|
||||||
|
if (contextHandler != null && !contextHandler.checkAlias(pathInContext, content.getResource()))
|
||||||
|
{
|
||||||
|
if (included)
|
||||||
|
throw new FileNotFoundException("!" + pathInContext);
|
||||||
|
notFound(request, response);
|
||||||
|
return response.isCommitted();
|
||||||
|
}
|
||||||
|
|
||||||
// Directory?
|
// Directory?
|
||||||
if (content.getResource().isDirectory())
|
if (content.getResource().isDirectory())
|
||||||
{
|
{
|
||||||
|
@ -289,6 +298,10 @@ public class ResourceService
|
||||||
HttpContent precompressedContent = precompressedContents.get(precompressedContentEncoding);
|
HttpContent precompressedContent = precompressedContents.get(precompressedContentEncoding);
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("precompressed={}", precompressedContent);
|
LOG.debug("precompressed={}", precompressedContent);
|
||||||
|
|
||||||
|
if (contextHandler != null && !contextHandler.checkAlias(pathInContext, precompressedContent.getResource()))
|
||||||
|
content = null;
|
||||||
|
|
||||||
content = precompressedContent;
|
content = precompressedContent;
|
||||||
response.setHeader(HttpHeader.CONTENT_ENCODING.asString(), precompressedContentEncoding.getEncoding());
|
response.setHeader(HttpHeader.CONTENT_ENCODING.asString(), precompressedContentEncoding.getEncoding());
|
||||||
}
|
}
|
||||||
|
|
|
@ -457,8 +457,6 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
|
||||||
if (_baseResource != null)
|
if (_baseResource != null)
|
||||||
{
|
{
|
||||||
r = _baseResource.resolve(subUriPath);
|
r = _baseResource.resolve(subUriPath);
|
||||||
if (!_contextHandler.checkAlias(subUriPath, r))
|
|
||||||
r = null;
|
|
||||||
}
|
}
|
||||||
else if (_servletContext instanceof ContextHandler.APIContext)
|
else if (_servletContext instanceof ContextHandler.APIContext)
|
||||||
{
|
{
|
||||||
|
|
|
@ -290,12 +290,14 @@ public class WebInfConfiguration extends AbstractConfiguration
|
||||||
throw new IllegalStateException("No resourceBase or war set for context");
|
throw new IllegalStateException("No resourceBase or war set for context");
|
||||||
|
|
||||||
// Use real location (if different) for WAR file, so that change/modification monitoring can work.
|
// Use real location (if different) for WAR file, so that change/modification monitoring can work.
|
||||||
URI targetURI = webApp.getTargetURI();
|
if (webApp.isAlias())
|
||||||
if (targetURI != null)
|
|
||||||
{
|
{
|
||||||
|
URI realURI = webApp.getRealURI();
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("{} anti-aliased to {}", webApp, targetURI);
|
LOG.debug("{} anti-aliased to {}", webApp, realURI);
|
||||||
webApp = context.newResource(targetURI);
|
Resource realWebApp = context.newResource(realURI);
|
||||||
|
if (realWebApp != null && realWebApp.exists())
|
||||||
|
webApp = realWebApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
|
|
Loading…
Reference in New Issue