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

[WIP] initial implementation of webresource based on path API #630

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 38 additions & 24 deletions java/org/apache/catalina/webresources/AbstractFileResourceSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package org.apache.catalina.webresources;

import java.io.File;
import java.io.IOException;
import java.io.IOError;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;

import org.apache.catalina.LifecycleException;
import org.apache.juli.logging.Log;
Expand All @@ -33,16 +35,20 @@ public abstract class AbstractFileResourceSet extends AbstractResourceSet {

protected static final String[] EMPTY_STRING_ARRAY = new String[0];

private File fileBase;
private Path fileBase;
private String absoluteBase;
private String canonicalBase;
private boolean readOnly = false;

protected AbstractFileResourceSet(String internalPath) {
setInternalPath(internalPath);
}

@Deprecated
protected final File getFileBase() {
return fileBase.toFile();
}

protected final Path getPathBase() {
return fileBase;
}

Expand All @@ -56,23 +62,32 @@ public boolean isReadOnly() {
return readOnly;
}

/**
* @deprecated use {@link #path(String, boolean)} instead.
*/
@Deprecated
protected final File file(String name, boolean mustExist) {
final var path = path(name, mustExist);
return path == null ? null : path.toFile();
}

protected final Path path(String name, boolean mustExist) {

if (name.equals("/")) {
name = "";
}
File file = new File(fileBase, name);
Path file = fileBase.resolve(name);

// If the requested names ends in '/', the Java File API will return a
// matching file if one exists. This isn't what we want as it is not
// consistent with the Servlet spec rules for request mapping.
if (name.endsWith("/") && file.isFile()) {
if (name.endsWith("/") && Files.isRegularFile(file)) {
return null;
}

// If the file/dir must exist but the identified file/dir can't be read
// then signal that the resource was not found
if (mustExist && !file.canRead()) {
if (mustExist && !Files.isReadable(file)) {
return null;
}

Expand All @@ -91,11 +106,11 @@ protected final File file(String name, boolean mustExist) {
// Check that this file is located under the WebResourceSet's base
String canPath = null;
try {
canPath = file.getCanonicalPath();
} catch (IOException e) {
canPath = file.toAbsolutePath().toString();
} catch (IOError e) {
// Ignore
}
if (canPath == null || !canPath.startsWith(canonicalBase)) {
if (canPath == null || !canPath.startsWith(absoluteBase)) {
return null;
}

Expand All @@ -106,7 +121,7 @@ protected final File file(String name, boolean mustExist) {
// checks are retained as an additional safety measure
// absoluteBase has been normalized so absPath needs to be normalized as
// well.
String absPath = normalize(file.getAbsolutePath());
String absPath = normalize(canPath);
if (absoluteBase.length() > absPath.length()) {
return null;
}
Expand All @@ -115,10 +130,9 @@ protected final File file(String name, boolean mustExist) {
// was not part of the requested path and the remaining check only
// applies to the request path
absPath = absPath.substring(absoluteBase.length());
canPath = canPath.substring(canonicalBase.length());

// The remaining request path must start with '/' if it has non-zero length
if (canPath.length() > 0 && canPath.charAt(0) != File.separatorChar) {
if (absPath.length() > 0 && absPath.charAt(0) != File.separatorChar) {
return null;
}

Expand Down Expand Up @@ -225,26 +239,26 @@ public void gc() {

@Override
protected void initInternal() throws LifecycleException {
fileBase = new File(getBase(), getInternalPath());
fileBase = getInternalBase().resolve(getInternalPath());
checkType(fileBase);

this.absoluteBase = normalize(fileBase.getAbsolutePath());

try {
this.canonicalBase = fileBase.getCanonicalPath();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
this.absoluteBase = normalize(fileBase.toAbsolutePath().toString());

// Need to handle mapping of the file system root as a special case
if ("/".equals(this.absoluteBase)) {
this.absoluteBase = "";
}
if ("/".equals(this.canonicalBase)) {
this.canonicalBase = "";
}
}


protected abstract void checkType(File file);
@Deprecated
protected void checkType(File file) {
checkType(file.toPath());
}

protected abstract void checkType(Path file);

protected Path getInternalBase() { // absolute Path.of() can fail on windows depending the path in some version
return new File(getBase()).toPath();
}
}
Loading
Loading