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. poj2349 Arctic Network - 最小生成树

    2017-08-04 16:19:13 writer:pprp 题意如下: Description The Department of National Defence (DND) wishes to ...

  2. C语言查找算法之顺序查找、二分查找(折半查找)

    C语言查找算法之顺序查找.二分查找(折半查找),最近考试要用到,网上也有很多例子,我觉得还是自己写的看得懂一些. 顺序查找 /*顺序查找 顺序查找是在一个已知无(或有序)序队列中找出与给定关键字相同的 ...

  3. angular-ui-bootstrap各版本下载地址

    http://www.bootcdn.cn/angular-ui-bootstrap/

  4. LeetCode第[17]题(Java):Letter Combinations of a Phone Number

    题目:最长公共前缀 难度:EASY 题目内容: Given a string containing digits from 2-9 inclusive, return all possible let ...

  5. 利用JS获取地址栏的中文参数

    地址栏中为:localhost:22865/ZYHSYY.aspx?BQH=305&DoctorName=张三&DoctorId=100我想利用JS获取到“张三”,请问该如何写js?目 ...

  6. charles抓包工具的使用:概述

    一. 什么是包 用户和后台客户端之间的请求数据,都是以包的形式来传递的,具体要深究,可以去看看这方面的网络知识 二. 为何要抓包 1) 可以用来分析网络流量 2) 可以用来破译抓来的数据,比如密码之类 ...

  7. Easyui 行编辑

    之前没用过,突然用了的时候手忙脚乱的感觉  找了官方文档也好 百度了一大堆东西   表示个人脑袋跟不上思路 直接铺上简化的  以后自己 找起来也方便  以下代码已经执行 应该不会再错了 <tab ...

  8. Java基础摘要(一)

    三大特性 封装 所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏.封装是面向对象的特征之一,是对象和类概念的主要特性.简单的说,一 ...

  9. ElasticSearch6.0 Java API 使用 排序,分组 ,创建索引,添加索引数据,打分等(一)

    ElasticSearch6.0  Java API  使用     排序,分组 ,创建索引,添加索引数据,打分等 如果此文章对你有帮助,请关注一下哦 1.1 搭建maven 工程  创建web工程 ...

  10. springmvc用来绑定参数的注解(转)

    引言: 原文链接:http://blog.csdn.net/kobejayandy/article/details/12690161 接上一篇文章,对@RequestMapping进行地址映射讲解之后 ...