Skip to content

Commit

Permalink
Jetty 12 - Resource resolve() and newResource() return null on re…
Browse files Browse the repository at this point in the history
…sources 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
  • Loading branch information
joakime authored Oct 19, 2022
1 parent ed3d4a4 commit 259deea
Show file tree
Hide file tree
Showing 56 changed files with 615 additions and 380 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
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;

Expand Down Expand Up @@ -226,10 +227,26 @@ protected void doStart() throws Exception
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
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
Expand Down Expand Up @@ -54,6 +55,8 @@ public HttpContent getContent(String pathInContext) throws IOException
{
// 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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;

Expand All @@ -56,7 +57,9 @@ public static String getAsXHTML(Resource resource, String base, boolean parent,
{
// 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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
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;
Expand Down Expand Up @@ -715,7 +716,18 @@ public void setBaseResource(Resource resourceBase)
{
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)
Expand All @@ -728,11 +740,10 @@ public void setBaseResource(Path path)
}

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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
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.
Expand Down Expand Up @@ -93,7 +94,7 @@ private void setupContentFactory()
{
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -76,22 +90,13 @@ public URI getURI()
@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
Expand All @@ -106,6 +111,12 @@ public long length()
return _bytes.length;
}

@Override
public Resource resolve(String subUriPath)
{
return null;
}

@Override
public InputStream newInputStream() throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
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;

Expand All @@ -26,6 +28,14 @@
*/
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
Expand All @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
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;
Expand All @@ -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
Expand Down Expand Up @@ -262,6 +273,95 @@ public URI getURI()
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)
{
Expand Down
Loading

0 comments on commit 259deea

Please sign in to comment.