环境

  1. tomcat 8.5

原因

在使用相对路径加载配置文件时,如果相对路径超出了 tomcat 容器的根目录,那么 tomcat 会提示 xxx has been normalized to [null] which is not valid

分析

下面从 tomcat 的源码来进行分析。

validate

在 StandardRoot 中,有一个 validate 方法,该方法的注释如下:

/**
* 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
*/

方法的最后一句说明了出错的原因,不能够超出容器的根目录。

normalize

该方法可以解析路径参数,其中超出根目录的检查逻辑就在这里。在解析父级目录时,如果发现超出了根目录,则直接返回 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);
}

外部配置

在之前的外部配置中,由于使用了相对路径,并且超出了容器的根目录,如果出现这个错误,则需要进行修改,可以使用 URL 的方式来实现。

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

拓展

如果使用该种方法,在 jboss 中出现如下错误:

java.lang.RuntimeException: java.io.IOException: Using reverse path on top path: /xxx

则可以参考这里

附录

validate方法

/**
* 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方法

/**
* 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;
}

Tomcat: has been normalized to [null] which is not valid的更多相关文章

  1. org.apache.tomcat.util.bcel.classfile.ClassFormatException: null is not a Java .class file

    org.apache.tomcat.util.bcel.classfile.ClassFormatException: null is not a Java .class file   在$TOMCA ...

  2. tomcat Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986

      1.情景展示 tomcat 日志时不时会报出如下异常信息,到底是怎么回事? java.lang.IllegalArgumentException: Invalid character found ...

  3. Spring 加载项目外部配置文件

    背景 在项目的部署过程中,一般是打成 war 或者 jar 包,这样一般存在两种问题: 即使是配置文件修改,也还需要整个项目重新打包和部署. 整个项目只有一套环境,不能切换. 针对上面的问题,可以使用 ...

  4. 烂泥:学习tomcat之通过shell批量管理多个tomcat

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 公司的业务是使用tomcat做web容器,为了更有效的利用服务器的性能,我们一般部署多个 ...

  5. Tomcat的SessionID引起的Session Fixation和Session Hijacking问题

    上一篇说到<Spring MVC防御CSRF.XSS和SQL注入攻击>,今天说说SessionID带来的漏洞攻击问题.首先,什么是Session Fixation攻击和Session Hi ...

  6. 基于内嵌Tomcat的应用开发

    为什么使用内嵌Tomcat开发? 开发人员无需搭建Tomcat的环境就可以使用内嵌式Tomcat进行开发,减少搭建J2EE容器环境的时间和开发时容器频繁启动所花时间,提高开发的效率. 怎么搭建内嵌To ...

  7. Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动

    之前在Spring Boot启动过程(二)提到过createEmbeddedServletContainer创建了内嵌的Servlet容器,我用的是默认的Tomcat. private void cr ...

  8. Spring Boot启动过程(六):内嵌Tomcat中StandardHost与StandardContext的启动

    看代码有助于线上出现预料之外的事的时候,不至于心慌... StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程 ...

  9. Tomcat 部署安装及JVM调优~

    Tomcat 部署Tomcat环境 环境准备 linux: CentOS 7.3 tomcat: 9.0.0.M21 jdk: 1.8.0_131 ip: 192.168.1.5 tomcat官方下载 ...

随机推荐

  1. NOIP模拟9

    #rank3,开心 话说这次考试时,心态并不是很好,考试前一天看了DeepinC大佬的博客,上次他rank15就 感觉炸成那样,那我上次rank30算什么?反正内心虚得一比;昨天晚上做梦梦到自己模拟赛 ...

  2. mac使用brew安装的PHP替换自带的PHP

    在.zshrc文件后面加上 export PATH="$(brew --prefix homebrew/php/php56)/bin:$PATH"

  3. vue-element-admin平时使用归纳

    message提示的使用 import { Message } from 'element-ui'; Message({ message: res.data.message || 'Error', t ...

  4. 利用pyltp进行实体识别

    一.实体识别作为信息抽取中基础的也是重要的一步,其技术可以分为三类,分别是其于规则的方法.其于统计模型的方法以及基于深度学习的方法. 基于规则的方法,主要依靠构建大量的实体抽取规则,一般由具有一定领域 ...

  5. java什么时候进行垃圾回收,垃圾回收的执行流程

    java的垃圾回收分为 三个区域新生代 老年代 永久代 一个对象实例化时 先去看伊甸园有没有足够的空间如果有 不进行垃圾回收 ,对象直接在伊甸园存储.如果伊甸园内存已满,会进行一次minor gc然后 ...

  6. Python 文件writelines() 方法和处理双层列表

    概述 writelines() 方法用于向文件中写入一序列的字符串. 这一序列字符串可以是由迭代对象产生的,如一个字符串列表. 换行需要制定换行符 \n. 语法 writelines() 方法语法如下 ...

  7. zabbix自定义监控,自定义图表。

    zabbix server:hostname=Zabbix server ip:192.168.100.7 zabbix agent: hostname=host3 ip:192.168.100.3 ...

  8. leetcode-hard-array-149. Max Points on a Line -NO

    mycode  不会.... 参考 因为每次遍历一个点,也就是i的时候,都是新建的一个lines,所以也就是考虑了k相同b不同的情况 最后gcd函数就求最大公约数,来解决斜率精度的问题 class S ...

  9. 前端知识点回顾——Javascript篇(二)

    JavaScript的解析顺序 第一阶段:编译期 寻找关键字声明的变量.函数声明的变量,同时会对变量进行作用域的绑定 var声明的变量,在编译期会赋一个默认值undefined,变量提升的特性. ES ...

  10. Activity的生命周期是谁调用的?

    我们知道Activity的生命周期包括onCreate.onStart.onResume.onRestart.onStop.onDestory.onSaveInstanceState.onRestor ...