1. 看下面源码,找到%号,每次加2,然后将16进制转换为int,也就是%号后两位加2得到16进制,转换为int

                   while ( ((i+) < numChars) && (c=='%')) {
int v = Integer.parseInt(s.substring(i+,i+),);
if (v < )
throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value");
bytes[pos++] = (byte) v;
i+= ;
if (i < numChars)
c = s.charAt(i);
}

这就是为什么url中不能有%号的原因,

2. 下面错就有可能url中有特殊字符,比如 %

Note that the name and value quoted here may be corrupted due to the failed decoding. Use debug level logging to see the original, non-corrupted values.
Note: further occurrences of Parameter errors will be logged at DEBUG level.

3. request.getParameter("Json");这个获得的是 null,urldecode之后的,因为urldecode出错了,所以会是null

4. request.getQueryString();这个得到的是,没有urldecode的,也就是原始的

二、 关于看tomcat源码的一些知识点,这是一个链接到达tomcat之后,要执行的过程,为什么要总结呢,request.getParameter("Json");中,如果Json中有特殊符号,如%,服务器会的到null,就是因为urldecode导致,看了源码什么都懂了

String an = request.getQueryString();   //获取没有被urldecode的参数值

String an = request.getParameter("Json"); //获取被urldecode解码后的参数值

1.  org.apache.catalina.connector.Connector  ,其中还有很多关于配置的在这个类中,自己看

 public Connector(String protocol) {
setProtocol(protocol);
// Instantiate protocol handler
try {
Class<?> clazz = Class.forName(protocolHandlerClassName);
this.protocolHandler = (ProtocolHandler) clazz.newInstance();
} catch (Exception e) {
log.error(sm.getString(
"coyoteConnector.protocolHandlerInstantiationFailed"), e);
}
}
构造函数中  protocol  对应  server.xml  protocol="HTTP/1.1"   所以构造函数中的 protocol 值为 HTTP/1.1

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxHttpHeaderSize="1048576"/>

2. org.apache.catalina.connector.RequestFacade implements HttpServletRequest

 public String getParameter(String name) { //不是这个方法,下面那个方法

        if (request == null) {
throw new IllegalStateException(
sm.getString("requestFacade.nullRequest"));
} if (Globals.IS_SECURITY_ENABLED){
return AccessController.doPrivileged(
new GetParameterPrivilegedAction(name));
} else {
return request.getParameter(name);
}
}
 @Override
public Map<String,String[]> getParameterMap() {//这个方法 if (request == null) {
throw new IllegalStateException(
sm.getString("requestFacade.nullRequest"));
} if (Globals.IS_SECURITY_ENABLED){
return AccessController.doPrivileged(
new GetParameterMapPrivilegedAction());
} else {
return request.getParameterMap();
}
}
 public Map<String, String[]> getParameterMap() {

        if (parameterMap.isLocked()) {
return parameterMap;
} Enumeration<String> enumeration = getParameterNames();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
String[] values = getParameterValues(name);
parameterMap.put(name, values);
} parameterMap.setLocked(true); return parameterMap; }
 public Enumeration<String> getParameterNames() {

        if (!parametersParsed) {
parseParameters();
} return coyoteRequest.getParameters().getParameterNames(); }

3. org.apache.catalina.connector.Request implements HttpServletRequest

 public String getParameter(String name) {

        if (!parametersParsed) {
parseParameters();
} return coyoteRequest.getParameters().getParameter(name); }

4. org.apache.catalina.connector.Request implements HttpServletRequest

protected void parseParameters() {

        parametersParsed = true;

        Parameters parameters = coyoteRequest.getParameters();
boolean success = false;
try {
// Set this every time in case limit has been changed via JMX
parameters.setLimit(getConnector().getMaxParameterCount()); //参数的数量最多为10000 // getCharacterEncoding() may have been overridden to search for
// hidden form field containing request encoding
String enc = getCharacterEncoding(); boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
if (enc != null) {
parameters.setEncoding(enc);
if (useBodyEncodingForURI) {
parameters.setQueryStringEncoding(enc);
}
} else {
parameters.setEncoding
(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
if (useBodyEncodingForURI) {
parameters.setQueryStringEncoding
(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
}
} parameters.handleQueryParameters(); if (usingInputStream || usingReader) {
success = true;
return;
} if( !getConnector().isParseBodyMethod(getMethod()) ) {
success = true;
return;
} String contentType = getContentType();
if (contentType == null) {
contentType = "";
}
int semicolon = contentType.indexOf(';');
if (semicolon >= ) {
contentType = contentType.substring(, semicolon).trim();
} else {
contentType = contentType.trim();
} if ("multipart/form-data".equals(contentType)) {
parseParts();
success = true;
return;
} if (!("application/x-www-form-urlencoded".equals(contentType))) {
success = true;
return;
} int len = getContentLength(); if (len > ) {
int maxPostSize = connector.getMaxPostSize();
if ((maxPostSize > ) && (len > maxPostSize)) {
if (context.getLogger().isDebugEnabled()) {
context.getLogger().debug(
sm.getString("coyoteRequest.postTooLarge"));
}
checkSwallowInput();
return;
}
byte[] formData = null;
if (len < CACHED_POST_LEN) {
if (postData == null) {
postData = new byte[CACHED_POST_LEN];
}
formData = postData;
} else {
formData = new byte[len];
}
try {
if (readPostBody(formData, len) != len) {
return;
}
} catch (IOException e) {
// Client disconnect
if (context.getLogger().isDebugEnabled()) {
context.getLogger().debug(
sm.getString("coyoteRequest.parseParameters"), e);
}
return;
}
parameters.processParameters(formData, , len);
} else if ("chunked".equalsIgnoreCase(
coyoteRequest.getHeader("transfer-encoding"))) {
byte[] formData = null;
try {
formData = readChunkedPostBody();
} catch (IOException e) {
// Client disconnect or chunkedPostTooLarge error
if (context.getLogger().isDebugEnabled()) {
context.getLogger().debug(
sm.getString("coyoteRequest.parseParameters"), e);
}
return;
}
if (formData != null) {
parameters.processParameters(formData, , formData.length);
}
}
success = true;
} finally {
if (!success) {
parameters.setParseFailed(true);
}
} }

5. org.apache.tomcat.util.http.Parameters  中  processParameters

  private void processParameters(byte bytes[], int start, int len,
Charset charset) { if(log.isDebugEnabled()) {
log.debug(sm.getString("parameters.bytes",
new String(bytes, start, len, DEFAULT_CHARSET)));
} int decodeFailCount = ; int pos = start;
int end = start + len; while(pos < end) {
int nameStart = pos;
int nameEnd = -;
int valueStart = -;
int valueEnd = -; boolean parsingName = true;
boolean decodeName = false;
boolean decodeValue = false;
boolean parameterComplete = false; do {
switch(bytes[pos]) {
case '=':
if (parsingName) {
// Name finished. Value starts from next character
nameEnd = pos;
parsingName = false;
valueStart = ++pos;
} else {
// Equals character in value
pos++;
}
break;
case '&':
if (parsingName) {
// Name finished. No value.
nameEnd = pos;
} else {
// Value finished
valueEnd = pos;
}
parameterComplete = true;
pos++;
break;
case '%':
case '+':
// Decoding required
if (parsingName) {
decodeName = true;
} else {
decodeValue = true;
}
pos ++;
break;
default:
pos ++;
break;
}
} while (!parameterComplete && pos < end); if (pos == end) {
if (nameEnd == -) {
nameEnd = pos;
} else if (valueStart > - && valueEnd == -){
valueEnd = pos;
}
} if (log.isDebugEnabled() && valueStart == -) {
log.debug(sm.getString("parameters.noequal",
Integer.valueOf(nameStart), Integer.valueOf(nameEnd),
new String(bytes, nameStart, nameEnd-nameStart,
DEFAULT_CHARSET)));
} if (nameEnd <= nameStart ) {
if (valueStart == -) {
// &&
if (log.isDebugEnabled()) {
log.debug(sm.getString("parameters.emptyChunk"));
}
// Do not flag as error
continue;
}
// &=foo&
UserDataHelper.Mode logMode = userDataLog.getNextMode();
if (logMode != null) {
String extract;
if (valueEnd > nameStart) {
extract = new String(bytes, nameStart, valueEnd
- nameStart, DEFAULT_CHARSET);
} else {
extract = "";
}
String message = sm.getString("parameters.invalidChunk",
Integer.valueOf(nameStart),
Integer.valueOf(valueEnd), extract);
switch (logMode) {
case INFO_THEN_DEBUG:
message += sm.getString("parameters.fallToDebug");
//$FALL-THROUGH$
case INFO:
log.info(message);
break;
case DEBUG:
log.debug(message);
}
}
parseFailed = true;
continue;
// invalid chunk - it's better to ignore
} tmpName.setBytes(bytes, nameStart, nameEnd - nameStart);
if (valueStart >= ) {
tmpValue.setBytes(bytes, valueStart, valueEnd - valueStart);
} else {
tmpValue.setBytes(bytes, , );
} // Take copies as if anything goes wrong originals will be
// corrupted. This means original values can be logged.
// For performance - only done for debug
if (log.isDebugEnabled()) {
try {
origName.append(bytes, nameStart, nameEnd - nameStart);
if (valueStart >= ) {
origValue.append(bytes, valueStart, valueEnd - valueStart);
} else {
origValue.append(bytes, , );
}
} catch (IOException ioe) {
// Should never happen...
log.error(sm.getString("parameters.copyFail"), ioe);
}
} try {
String name;
String value; if (decodeName) {
urlDecode(tmpName);
}
tmpName.setCharset(charset);
name = tmpName.toString(); if (valueStart >= ) {
if (decodeValue) {
urlDecode(tmpValue);
}
tmpValue.setCharset(charset); //ISO-8859-1
value = tmpValue.toString();
} else {
value = "";
} try {
addParameter(name, value); // 添加到参数集合中
} catch (IllegalStateException ise) {
// Hitting limit stops processing further params but does
// not cause request to fail.
parseFailed = true;
UserDataHelper.Mode logMode = maxParamCountLog.getNextMode();
if (logMode != null) {
String message = ise.getMessage();
switch (logMode) {
case INFO_THEN_DEBUG:
message += sm.getString(
"parameters.maxCountFail.fallToDebug");
//$FALL-THROUGH$
case INFO:
log.info(message);
break;
case DEBUG:
log.debug(message);
}
}
break;
}
} catch (IOException e) {
parseFailed = true;
decodeFailCount++;
if (decodeFailCount == || log.isDebugEnabled()) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("parameters.decodeFail.debug",
origName.toString(), origValue.toString()), e);
} else if (log.isInfoEnabled()) {
UserDataHelper.Mode logMode = userDataLog.getNextMode();
if (logMode != null) {
String message = sm.getString(
"parameters.decodeFail.info",
tmpName.toString(), tmpValue.toString());
switch (logMode) {
case INFO_THEN_DEBUG:
message += sm.getString("parameters.fallToDebug");
//$FALL-THROUGH$
case INFO:
log.info(message);
break;
case DEBUG:
log.debug(message);
}
}
}
}
} tmpName.recycle();
tmpValue.recycle();
// Only recycle copies if we used them
if (log.isDebugEnabled()) {
origName.recycle();
origValue.recycle();
}
} if (decodeFailCount > && !log.isDebugEnabled()) {
UserDataHelper.Mode logMode = userDataLog.getNextMode();
if (logMode != null) {
String message = sm.getString(
"parameters.multipleDecodingFail",
Integer.valueOf(decodeFailCount));
switch (logMode) {
case INFO_THEN_DEBUG:
message += sm.getString("parameters.fallToDebug");
//$FALL-THROUGH$
case INFO:
log.info(message);
break;
case DEBUG:
log.debug(message);
}
}
}
}

6. org.apache.tomcat.util.buf.UDecoder

public final String convert(String str, boolean query)
{
if (str == null) {
return null;
} if( (!query || str.indexOf( '+' ) < ) && str.indexOf( '%' ) < ) {
return str;
} final boolean noSlash = !(ALLOW_ENCODED_SLASH || query); StringBuilder dec = new StringBuilder(); // decoded string output
int strPos = ;
int strLen = str.length(); dec.ensureCapacity(str.length());
while (strPos < strLen) {
int laPos; // lookahead position // look ahead to next URLencoded metacharacter, if any
for (laPos = strPos; laPos < strLen; laPos++) {
char laChar = str.charAt(laPos);
if ((laChar == '+' && query) || (laChar == '%')) {
break;
}
} // if there were non-metacharacters, copy them all as a block
if (laPos > strPos) {
dec.append(str.substring(strPos,laPos));
strPos = laPos;
} // shortcut out of here if we're at the end of the string
if (strPos >= strLen) {
break;
} // process next metacharacter
char metaChar = str.charAt(strPos);
if (metaChar == '+') {
dec.append(' ');
strPos++;
continue;
} else if (metaChar == '%') {
// We throw the original exception - the super will deal with
// it
// try {
char res = (char) Integer.parseInt( //得到%号后面两个字符,之后以16进制转换成int类型再转换成char类型,之后追加到dec上
str.substring(strPos + 1, strPos + 3), 16);
if (noSlash && (res == '/')) {
throw new IllegalArgumentException("noSlash");
}
dec.append(res);
strPos += 3;
}
} return dec.toString();
}

关于urlDecode和tomcat一些源码的更多相关文章

  1. Servlet和Tomcat底层源码分析

    Servlet 源码分析   Servlet 结构图 Servlet 和 ServletConfig 都是顶层接口,而 GenericServlet 实现了这两个顶层接口,然后HttpServlet ...

  2. tomcat 源码解析

    how_tomcat_works https://www.uzh.ch/cmsssl/dam/jcr:00000000-29c9-42ee-0000-000074fab75a/how_tomcat_w ...

  3. JavaWeb过滤器Filter(附tomcat部分源码分析)

    过滤器Filter 过滤器通常对一些web资源进行拦截,做完一些处理器再交给下一个过滤器处理,直到所有的过滤器处理器,再调用servlet实例的service方法进行处理.过滤器可以对request进 ...

  4. Tomcat修改源码,重新编译

    源码和编译的区别:源码不能直接运行,是人读的,而编译后的程序是计算机可以读的.所以它们是不同的语言.

  5. Tomcat 7源码学习笔记 -9 tomcat重启后session仍然保留

    使用Tomcat 7缺省的配置,tomcat关闭后重新启动,发现原来的session没有被删掉,用原来的request获取session仍然可以取到.但是并没有配置session持久化. 原因如下: ...

  6. 《深入剖析Tomcat》源码

    <深入剖析Tomcat>翻译自<How Tomcat Works> 可以到官网下载:https://brainysoftware.com/download 官网下载比较慢,我就 ...

  7. tomcat源码---->request的请求参数分析

    当contentType为application/json的时候,在servlet中通过request.getParameter得到的数据为空.今天我们就java的请求,分析一下request得到参数 ...

  8. tomcat源码剖析

    最近看Tomcat的源码的节奏还算是挺紧凑的,给人的感觉,tomcat的代码相对以前读的jetty的代码显得更有条理一些...当然这也是有可能是因为自己看的jetty的版本是比较老的,而看的Tomca ...

  9. Eclipse导入Tomcat源码(转)

    想要研究下Tomcat的体系结构或者源码,最好将Tomcat的源码导入到ide中,编写实例进行代码跟踪(debug). 这里参考了网上一些资料,将自己操作过程记个流水账. 准备: 1.Tomcat源码 ...

随机推荐

  1. java.lang.IllegalArgumentException异常处理的一种方法

    我遇到的问题 用spring注解来加载bean,都是一个简单的了,但是还是报了这样一个错java.lang.IllegalArgumentException 网上查了一下,说是jdk版本要1.7的,然 ...

  2. Rancher + K8S RestApi使用

      1前言 1.1使用的软件及版本 软件 版本号 Rancher 1.6stable Kubernetes 1.8.3 Docker 1.12.6 1.2 Rancher与K8S的RESTAPI差异 ...

  3. dll隐式链接延迟加载

    dll隐式链接延迟加载 程序隐式链接dll后,启动程序将自动加载dll,查找路径依次是: 1:当前文件路径: 2:使用SetDLLDirectory设置的路径: 3:系统路径,system32文件夹, ...

  4. Django进阶Model篇004 - ORM常用操作

    一.增加 create和save方法 实例: 1.增加一条作者记录 >>> from hello.models import * >>> Author.object ...

  5. git一个系列教程

    https://git-scm.com/book/zh/v1/%E8%B5%B7%E6%AD%A5-%E5%85%B3%E4%BA%8E%E7%89%88%E6%9C%AC%E6%8E%A7%E5%8 ...

  6. 【spark】RDD创建

    首先我们要建立 sparkconf 配置文件,然后通过配置文件来建立sparkcontext. import org.apache.spark._ object MyRdd { def main(ar ...

  7. UI- 不易记知识点汇总

    1.static: 所有的全局变量都是静态变量,而局部变量只有定义时加上类型修饰符static,才为局部静态变量. 静态变量并不是说其就不能改变值,不能改变值的量叫常量. 其拥有的值是可变的 ,而且它 ...

  8. react use axios拦截器

    import axios from 'axios'; improt Promise from 'es6-promise'; Promise.polyfill(); const axiosService ...

  9. 剑指offer--32.把数组排成最小的数

    用to_string()将整形转化为字符串,对字符串进行比较 --------------------------------------------------------------------- ...

  10. Git的origin和master分析

    首先要明确一点,对git的操作是围绕3个大的步骤来展开的(其实几乎所有的SCM都是这样) 1. 从git取数据(git clone) 2. 改动代码 3. 将改动传回git(git push) 这3个 ...