Tomcat: has been normalized to [null] which is not valid

surroundings

  1. tomcat 8.5

the reason

When using a relative path to load the configuration file, if a relative path beyond the root directory of tomcat container, the tomcat will be prompted xxx has been normalized to [null] which is not valid.

analysis

Let's analyze the tomcat source.

validate

In StandardRoot, there is a validate method, this method is annotated as follows:

/**
    * Ensures that this object is in a valid state to serve resources, checks
    * that the path is a String that starts with '/' and checks that the path
    * can be normalized without stepping outside of the root.
    *
    * @param path
    * @return  the normalized path
    */

Finally, a method is described cause of the error, it is possible without departing from the root of the container.

normalize

The method may parse the path parameters, beyond which check logic root here. When resolving parent directory, if found to be outside the root directory, simply return null.

while (true) {
    int index = normalized.indexOf("/../");
    if (index < 0) {
        break;
    }
    if (index == 0) {
        return null;  // Trying to go outside our context
    }
    int index2 = normalized.lastIndexOf('/', index - 1);
    normalized = normalized.substring(0, index2) + normalized.substring(index + 3);
}

External placement

Before external configuration, since the relative path, and beyond the root of the container, if the error occurs, need to be modified, can use the URL to achieve.

URL url = Thread.currentThread().getContextClassLoader().getResource("");

try {

    Resource resource = new UrlResource(url).createRelative(EXTERNAL_CONFIG_FILE);

    if (!resource.exists()) {

        logger.info("外部配置不存在。");
        return;
    }

    logger.info("外部配置存在。");
    ResourcePropertySource source = new ResourcePropertySource(new EncodedResource(resource, "UTF-8"));
    // 外部配置的优先级最高
    beanFactory.getBean(StandardEnvironment.class).getPropertySources().addFirst(source);

} catch (IOException e) {

    logger.error("加载外部配置出错。", e);
}

appendix

validate methods

/**
 * Ensures that this object is in a valid state to serve resources, checks
 * that the path is a String that starts with '/' and checks that the path
 * can be normalized without stepping outside of the root.
 *
 * @param path
 * @return  the normalized path
 */
private String validate(String path) {
    if (!getState().isAvailable()) {
        throw new IllegalStateException(
                sm.getString("standardRoot.checkStateNotStarted"));
    }

    if (path == null || path.length() == 0 || !path.startsWith("/")) {
        throw new IllegalArgumentException(
                sm.getString("standardRoot.invalidPath", path));
    }

    String result;
    if (File.separatorChar == '\\') {
        // On Windows '\\' is a separator so in case a Windows style
        // separator has managed to make it into the path, replace it.
        result = RequestUtil.normalize(path, true);
    } else {
        // On UNIX and similar systems, '\\' is a valid file name so do not
        // convert it to '/'
        result = RequestUtil.normalize(path, false);
    }

    // 检查到超出根目录,在这里抛出了异常。
    if (result == null || result.length() == 0 || !result.startsWith("/")) {
        throw new IllegalArgumentException(
                sm.getString("standardRoot.invalidPathNormal", path, result));
    }

    return result;
}

normalize method

/**
 * Normalize a relative URI path that may have relative values ("/./",
 * "/../", and so on ) it it.  <strong>WARNING</strong> - This method is
 * useful only for normalizing application-generated paths.  It does not
 * try to perform security checks for malicious input.
 *
 * @param path Relative path to be normalized
 * @param replaceBackSlash Should '\\' be replaced with '/'
 *
 * @return The normalized path or <code>null</code> if the path cannot be
 *         normalized
 */
public static String normalize(String path, boolean replaceBackSlash) {

    if (path == null) {
        return null;
    }

    // Create a place for the normalized path
    String normalized = path;

    if (replaceBackSlash && normalized.indexOf('\\') >= 0)
        normalized = normalized.replace('\\', '/');

    // Add a leading "/" if necessary
    if (!normalized.startsWith("/"))
        normalized = "/" + normalized;

    boolean addedTrailingSlash = false;
    if (normalized.endsWith("/.") || normalized.endsWith("/..")) {
        normalized = normalized + "/";
        addedTrailingSlash = true;
    }

    // Resolve occurrences of "//" in the normalized path
    while (true) {
        int index = normalized.indexOf("//");
        if (index < 0) {
            break;
        }
        normalized = normalized.substring(0, index) + normalized.substring(index + 1);
    }

    // Resolve occurrences of "/./" in the normalized path
    while (true) {
        int index = normalized.indexOf("/./");
        if (index < 0) {
            break;
        }
        normalized = normalized.substring(0, index) + normalized.substring(index + 2);
    }

    // 在这里检查,超出根目录返回null。
    // Resolve occurrences of "/../" in the normalized path
    while (true) {
        int index = normalized.indexOf("/../");
        if (index < 0) {
            break;
        }
        if (index == 0) {
            return null;  // Trying to go outside our context
        }
        int index2 = normalized.lastIndexOf('/', index - 1);
        normalized = normalized.substring(0, index2) + normalized.substring(index + 3);
    }

    if (normalized.length() > 1 && addedTrailingSlash) {
        // Remove the trailing '/' we added to that input and output are
        // consistent w.r.t. to the presence of the trailing '/'.
        normalized = normalized.substring(0, normalized.length() - 1);
    }

    // Return the normalized path that we have completed
    return normalized;
}

Guess you like

Origin www.cnblogs.com/jiangbo44/p/11948981.html
Recommended