1. org.apache.coyote.http11.Http11Processor.process
处理请求的数据
2. org.apache.coyote.http11.InternalInputBuffer.parseRequestLine()
// 例如:127.0.0.1:8080/test.jsp?a=%E4%B8%AD%E5%9B%BD
request.unparsedURI().setBytes(buf, start, end - start);
if (questionPos >= 0) {
// queryString: a=%E4%B8%AD%E5%9B%BD
request.queryString().setBytes(buf, questionPos + 1,
end - questionPos - 1);
// requestURI: 127.0.0.1:8080/test.jsp
request.requestURI().setBytes(buf, start, questionPos - start);
} else {
request.requestURI().setBytes(buf, start, end - start);
}
3. org.apache.catalina.connector.CoyoteAdapter
public void service(org.apache.coyote.Request req,
org.apache.coyote.Response res)
/**
* Service method.
*/
public void service(org.apache.coyote.Request req,
org.apache.coyote.Response res)
throws Exception {
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
if (request == null) {
// Create objects
request = (Request) connector.createRequest();
request.setCoyoteRequest(req);
response = (Response) connector.createResponse();
response.setCoyoteResponse(res);
// Link objects
request.setResponse(response);
response.setRequest(request);
// Set as notes
req.setNote(ADAPTER_NOTES, request);
res.setNote(ADAPTER_NOTES, response);
// Set query string encoding // 设置了queryString的编码
req.getParameters().setQueryStringEncoding
(connector.getURIEncoding());
}
if (connector.getXpoweredBy()) {
response.addHeader("X-Powered-By", POWERED_BY);
}
/**
* Parse additional request parameters.
*/
protected boolean postParseRequest(org.apache.coyote.Request req,
Request request,
org.apache.coyote.Response res,
Response response)
3. 解析参数
org.apache.catalina.connector.Request.parseParameters
/**
* Parse request parameters.
*/
protected void parseParameters() {
parametersParsed = true;
Parameters parameters = coyoteRequest.getParameters();
// 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) { // 如果此选项设置了的话, 设置queryStr的编码
parameters.setQueryStringEncoding(enc);
}
} else {
parameters.setEncoding
(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
if (useBodyEncodingForURI) {
parameters.setQueryStringEncoding
(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
}
}
// 解析query str
parameters.handleQueryParameters();
if (usingInputStream || usingReader)
return;
// 不是post, 直接返回
if (!getMethod().equalsIgnoreCase("POST"))
return;
String contentType = getContentType();
if (contentType == null)
contentType = "";
int semicolon = contentType.indexOf(';');
if (semicolon >= 0) {
contentType = contentType.substring(0, semicolon).trim();
} else {
contentType = contentType.trim();
}
// 当不是表单数据时, 返回
if (!("application/x-www-form-urlencoded".equals(contentType)))
return;
// 是表单数据, 读取解析
int len = getContentLength();
if (len > 0) {
int maxPostSize = connector.getMaxPostSize();
if ((maxPostSize > 0) && (len > maxPostSize)) {
if (context.getLogger().isDebugEnabled()) {
context.getLogger().debug(
sm.getString("coyoteRequest.postTooLarge"));
}
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, 0, len);
} else if ("chunked".equalsIgnoreCase(
coyoteRequest.getHeader("transfer-encoding"))) {
byte[] formData = null;
try {
formData = readChunkedPostBody();
} catch (IOException e) {
// Client disconnect
if (context.getLogger().isDebugEnabled()) {
context.getLogger().debug(
sm.getString("coyoteRequest.parseParameters"), e);
}
return;
}
if (formData != null) {
parameters.processParameters(formData, 0, formData.length);
}
}
}
// 使用querystr的encoding
public void processParameters( MessageBytes data, String encoding ) {
if( data==null || data.isNull() || data.getLength() <= 0 ) return;
if( data.getType() == MessageBytes.T_BYTES ) {
ByteChunk bc=data.getByteChunk();
processParameters( bc.getBytes(), bc.getOffset(),
bc.getLength(), encoding);
} else {
if (data.getType()!= MessageBytes.T_CHARS )
data.toChars();
CharChunk cc=data.getCharChunk();
processParameters( cc.getChars(), cc.getOffset(),
cc.getLength());
}
}
小结:
1. 所有参数tomcat都会先做url decode(这很正常, 标准情况下, 都要做url编码, 可同时保证特殊字符的正确传送, 不管get传参还是post传参)
字符 特殊字符的含义 URL编码
# 用来标志特定的文档位置 %23
% 对特殊字符进行编码 %25
& 分隔不同的变量值对 %26
+ 在变量值中表示空格 %2B
\ 表示目录路径 %2F
= 用来连接键和值 %3D
? 表示查询字符串的开始 %3F
% 对特殊字符进行编码 %25
& 分隔不同的变量值对 %26
+ 在变量值中表示空格 %2B
\ 表示目录路径 %2F
= 用来连接键和值 %3D
? 表示查询字符串的开始 %3F
2. 做url编码时, 肯定有指定的字符集(这里假定为utf-8), 如果后端的处理字符集与此字符集不同, 一般来说, 就有乱码
针对get方式的参数, 有两种方式, 可以正确处理
(1) tomcat的服务器配置URIEncoding="UTF-8"
(2) tomcat的服务器配置useBodyEncodingForURI="true", 读取参数之前, 设置
request.setCharacterEncoding("utf-8");
针对post方式的参数, 只要设置如下即可:
request.setCharacterEncoding("utf-8");
相关推荐
shiro版本时,其参数remeberMe存在硬编码,它对于cookie的处理流程是,首先获取rememberMe的cookie值,然后进行Base64解码,再进行AES解密,最后反序列化。但在这个过程中,其AES的Key硬编码,导致反序列化漏洞的...
具体进行的处理为全程采用UTF-8编码. 1,mysql创建时,字符集必须选择UTF-8 2,在mysql jdbc连接的url中,必须指定采用utf-8 encoding。 jdbc:mysql://localhost/forum?useUnicode=true&characterEncoding=utf-8&...
Chain 提供实现组织复杂的处理流程的“责任链模式”. CLI CLI 提供针对命令行参数,选项,选项组,强制选项等的简单API. Codec Codec 包含一些通用的编码解码算法。包括一些语音编码器, Hex, Base64, 以及URL ...
5.3.6 掌握Servelet处理流程 5.3.7 Eclipse快速创建Servlet 5.4 一夫当关——配置并应用Servlet过滤器 5.4.1 过滤器的基本原理 5.4.2 过滤器的核心API 5.4.3 过滤器的创建与配置 5.4.4 JavaWeb中字符乱码分析 5.4.5 ...
从高层架构至底层细节的编码思路和方法,从底层数据库到实体类、逻辑类再到控制层最后到表层页面的设计编码顺序。 边开发边测试的开发过程实践。 整合多个Servlet调用,使用传入操作参数operate实现区别调用业务逻辑...
具体进行的处理为全程采用UTF-8编码. 1,mysql创建时,字符集必须选择UTF-8 2,在mysql jdbc连接的url中,必须指定采用utf-8 encoding。 jdbc:mysql://localhost/forum?useUnicode=true&characterEncoding...
84.2. 我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 106 84.3. 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。以下程序使用...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...
Tomcat Native 这个项目可以让 Tomcat 使用 Apache 的 apr 包来处理包括文件和网络IO操作,以提升性能。 预输入搜索 Cleo Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司...