Tomcat: has been normalized to [null] which is not valid
环境
- 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的更多相关文章
- 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 ...
- 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 ...
- Spring 加载项目外部配置文件
背景 在项目的部署过程中,一般是打成 war 或者 jar 包,这样一般存在两种问题: 即使是配置文件修改,也还需要整个项目重新打包和部署. 整个项目只有一套环境,不能切换. 针对上面的问题,可以使用 ...
- 烂泥:学习tomcat之通过shell批量管理多个tomcat
本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 公司的业务是使用tomcat做web容器,为了更有效的利用服务器的性能,我们一般部署多个 ...
- Tomcat的SessionID引起的Session Fixation和Session Hijacking问题
上一篇说到<Spring MVC防御CSRF.XSS和SQL注入攻击>,今天说说SessionID带来的漏洞攻击问题.首先,什么是Session Fixation攻击和Session Hi ...
- 基于内嵌Tomcat的应用开发
为什么使用内嵌Tomcat开发? 开发人员无需搭建Tomcat的环境就可以使用内嵌式Tomcat进行开发,减少搭建J2EE容器环境的时间和开发时容器频繁启动所花时间,提高开发的效率. 怎么搭建内嵌To ...
- Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动
之前在Spring Boot启动过程(二)提到过createEmbeddedServletContainer创建了内嵌的Servlet容器,我用的是默认的Tomcat. private void cr ...
- Spring Boot启动过程(六):内嵌Tomcat中StandardHost与StandardContext的启动
看代码有助于线上出现预料之外的事的时候,不至于心慌... StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程 ...
- Tomcat 部署安装及JVM调优~
Tomcat 部署Tomcat环境 环境准备 linux: CentOS 7.3 tomcat: 9.0.0.M21 jdk: 1.8.0_131 ip: 192.168.1.5 tomcat官方下载 ...
随机推荐
- NOIP模拟9
#rank3,开心 话说这次考试时,心态并不是很好,考试前一天看了DeepinC大佬的博客,上次他rank15就 感觉炸成那样,那我上次rank30算什么?反正内心虚得一比;昨天晚上做梦梦到自己模拟赛 ...
- mac使用brew安装的PHP替换自带的PHP
在.zshrc文件后面加上 export PATH="$(brew --prefix homebrew/php/php56)/bin:$PATH"
- vue-element-admin平时使用归纳
message提示的使用 import { Message } from 'element-ui'; Message({ message: res.data.message || 'Error', t ...
- 利用pyltp进行实体识别
一.实体识别作为信息抽取中基础的也是重要的一步,其技术可以分为三类,分别是其于规则的方法.其于统计模型的方法以及基于深度学习的方法. 基于规则的方法,主要依靠构建大量的实体抽取规则,一般由具有一定领域 ...
- java什么时候进行垃圾回收,垃圾回收的执行流程
java的垃圾回收分为 三个区域新生代 老年代 永久代 一个对象实例化时 先去看伊甸园有没有足够的空间如果有 不进行垃圾回收 ,对象直接在伊甸园存储.如果伊甸园内存已满,会进行一次minor gc然后 ...
- Python 文件writelines() 方法和处理双层列表
概述 writelines() 方法用于向文件中写入一序列的字符串. 这一序列字符串可以是由迭代对象产生的,如一个字符串列表. 换行需要制定换行符 \n. 语法 writelines() 方法语法如下 ...
- zabbix自定义监控,自定义图表。
zabbix server:hostname=Zabbix server ip:192.168.100.7 zabbix agent: hostname=host3 ip:192.168.100.3 ...
- leetcode-hard-array-149. Max Points on a Line -NO
mycode 不会.... 参考 因为每次遍历一个点,也就是i的时候,都是新建的一个lines,所以也就是考虑了k相同b不同的情况 最后gcd函数就求最大公约数,来解决斜率精度的问题 class S ...
- 前端知识点回顾——Javascript篇(二)
JavaScript的解析顺序 第一阶段:编译期 寻找关键字声明的变量.函数声明的变量,同时会对变量进行作用域的绑定 var声明的变量,在编译期会赋一个默认值undefined,变量提升的特性. ES ...
- Activity的生命周期是谁调用的?
我们知道Activity的生命周期包括onCreate.onStart.onResume.onRestart.onStop.onDestory.onSaveInstanceState.onRestor ...