Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jetty 12 - Delay Resource Alias calculation until it's requested/needed #8573

Merged
merged 9 commits into from
Sep 27, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,7 @@ public boolean checkAlias(String pathInContext, Resource resource)
if (resource.isAlias())
{
if (LOG.isDebugEnabled())
LOG.debug("Aliased resource: {}~={}", resource, resource.getAlias());
LOG.debug("Aliased resource: {} -> {}", resource, resource.getTargetURI());

// alias checks
for (AliasCheck check : _aliasChecks)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ public void testAliasedFileAllowed() throws Exception

Resource resource = context.getResource(path);
assertNotNull(resource);
assertEquals(context.getResource("/subdir/TextFile.Long.txt").getURI(), resource.getAlias());
assertEquals(context.getResource("/subdir/TextFile.Long.txt").getURI(), resource.getTargetURI());

URL url = context.getServletContext().getResource(path);
assertNotNull(url);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,79 +48,9 @@ public class PathResource extends Resource
.build();

private final Path path;
private final Path alias;
private final URI uri;

private Path checkAliasPath()
{
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
{
// Use normalized path to get past navigational references like "/bar/../foo/test.txt"
Path ref = Paths.get(uri.normalize());
return ref.toRealPath();
}
catch (IOException ioe)
{
// If the toRealPath() call fails, then let
// the alias checking routines continue on
// to other techniques.
LOG.trace("IGNORED", ioe);
}
}

if (!abs.isAbsolute())
abs = path.toAbsolutePath();

// Any normalization difference means it's an alias,
// and we don't want to bother further to follow
// symlinks as it's an alias anyway.
Path normal = path.normalize();
if (!isSameName(abs, normal))
return normal;

try
{
if (Files.isSymbolicLink(path))
return path.getParent().resolve(Files.readSymbolicLink(path));
if (Files.exists(path))
{
Path real = abs.toRealPath();
if (!isSameName(abs, real))
return real;
}
}
catch (IOException e)
{
LOG.trace("IGNORED", e);
}
catch (Exception e)
{
LOG.warn("bad alias ({} {}) for {}", e.getClass().getName(), e.getMessage(), path);
}
return null;
}
private boolean targetResolved = false;
private Path alias;
joakime marked this conversation as resolved.
Show resolved Hide resolved

/**
* Test if the paths are the same name.
Expand Down Expand Up @@ -235,7 +165,6 @@ public static boolean isSameName(Path pathA, Path pathB)

this.path = path;
this.uri = uri;
this.alias = checkAliasPath();
}

@Override
Expand Down Expand Up @@ -325,9 +254,87 @@ public boolean isContainedIn(Resource r)
}

@Override
public URI getAlias()
public URI getTargetURI()
{
return this.alias == null ? null : this.alias.toUri();
if (!targetResolved)
{
alias = resolveTargetPath();
targetResolved = true;
}
if (alias == null)
return null;
return alias.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
{
// Use normalized path to get past navigational references like "/bar/../foo/test.txt"
Path ref = Paths.get(uri.normalize());
return ref.toRealPath();
}
catch (IOException ioe)
{
// If the toRealPath() call fails, then let
// the alias checking routines continue on
// to other techniques.
LOG.trace("IGNORED", ioe);
}
}

if (!abs.isAbsolute())
abs = path.toAbsolutePath();

// Any normalization difference means it's an alias,
// and we don't want to bother further to follow
// symlinks as it's an alias anyway.
Path normal = path.normalize();
if (!isSameName(abs, normal))
return normal;

try
{
if (Files.isSymbolicLink(path))
return path.getParent().resolve(Files.readSymbolicLink(path));
if (Files.exists(path))
{
Path real = abs.toRealPath();
if (!isSameName(abs, real))
return real;
}
}
catch (IOException e)
{
LOG.trace("IGNORED", e);
}
catch (Exception e)
{
LOG.warn("bad alias ({} {}) for {}", e.getClass().getName(), e.getMessage(), path);
}
return null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,15 +325,17 @@ public Resource resolve(String subUriPath)
*/
public boolean isAlias()
{
return getAlias() != null;
return getTargetURI() != null;
}

/**
* The canonical Alias for the Resource as a URI.
* If this Resource is an alias pointing to a different location,
* return the target location as URI.
*
* @return The canonical Alias of this resource or null if none.
* @return The target URI location of this resource,
* or null if there is no target URI location (eg: not an alias, or a symlink)
*/
public URI getAlias()
public URI getTargetURI()
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

package org.eclipse.jetty.util.ssl;

import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -53,11 +54,10 @@ public KeyStoreScanner(SslContextFactory sslContextFactory)
if (Files.isDirectory(monitoredFile))
throw new IllegalArgumentException("expected keystore file not directory");

if (keystoreResource.getAlias() != null)
{
// this resource has an alias, use the alias, as that's what's returned in the Scanner
monitoredFile = Paths.get(keystoreResource.getAlias());
}
// Use real location of keystore (if different), so that change monitoring can work properly
URI realUri = keystoreResource.getTargetURI();
joakime marked this conversation as resolved.
Show resolved Hide resolved
if (realUri != null)
monitoredFile = Paths.get(realUri);

keystoreFile = monitoredFile;
if (LOG.isDebugEnabled())
Expand Down
Loading