// Tomcat支持 Content-Type multipart/form-data; boundary=---------------------------312511929827998 文件上传
// Tomcat支持 Content-Type application/x-www-form-urlencoded; charset=UTF-8 普通post提交
// Tomcat不支持: Content-Type text/html; charset=utf-8
// 提交类型为"multipart/form-data"的时候,要开启<multipart-config>,否则不能使用,req.getParameter("lname");取不到任何数据
// 当有配置<multipart-config>文件上传功能是,这个字段parts会被填充
// 提交类型是multipart/form-data,并且没配置<multipart-config>,在Servlet中使用了req.getInputStream() 或者 req.getReader()可以取到数据
// 提交类型是multipart/form-data,并且没配置<multipart-config>,在Servlet中使用了req.getParameter("lname")取不到数据
// 提交类型是multipart/form-data,有配置<multipart-config>,在Servlet中使用了req.getParameter("lname")取得到数据,req.getInputStream() 或者 req.getReader()取不到数据
// 提交类型是application/x-www-form-urlencoded,如果在Servlet中使用了req.getInputStream() 或者 req.getReader(),那么req.getParameter("lname")取不到数据
// 提交类型是application/x-www-form-urlencoded,如果在Servlet中使用了req.getParameter("lname"),那么req.getInputStream() 或者 req.getReader()取不到数据
class org.apache.catalina.connector.RequestFacade{
public String getParameter(String name) {
return request.getParameter(name);//!!!
}
}
class org.apache.catalina.connector.Request{
public String getParameter(String name) { // 读取参数
if (!parametersParsed) {
// Tomcat支持 Content-Type multipart/form-data; boundary=---------------------------312511929827998 文件上传
// Tomcat支持 Content-Type application/x-www-form-urlencoded; charset=UTF-8 普通post提交
// Tomcat不支持: Content-Type text/html; charset=utf-8
// 提交类型为"multipart/form-data"的时候,要开启<multipart-config>,否则不能使用,req.getParameter("lname");取不到任何数据
// 当有配置<multipart-config>文件上传功能是,这个字段parts会被填充
// 把值设置进入: coyoteRequest.getParameters().addParameter(name, value);
parseParameters(); // 走这边,解析参数
}
return coyoteRequest.getParameters().getParameter(name);
}
// 解析参数
protected void parseParameters() {
parametersParsed = true;
Parameters parameters = coyoteRequest.getParameters();//!!!!
parameters.setLimit(getConnector().getMaxParameterCount()); // 限制参数最多数量
String enc = getCharacterEncoding(); // 取得编码类型 如: utf-8
parameters.setEncoding("ISO-8859-1");
if (useBodyEncodingForURI) {
parameters.setQueryStringEncoding("ISO-8859-1");
}
parameters.handleQueryParameters(); // 处理URL查询参数,如:a=value1&b=value2
// 如果在Servlet中使用了req.getInputStream() 或者 req.getReader(),就解析不到数据了
if (usingInputStream || usingReader) {
success = true;
return;
}
if( !getConnector().isParseBodyMethod(getMethod()) ) { // 本请求方式,是否需要解析body部分,默认是POST要解析body
success = true;
return;
}
// Content-Type multipart/form-data; boundary=---------------------------312511929827998 文件上传
// Content-Type application/x-www-form-urlencoded; charset=UTF-8 普通post提交
// 不支持: Content-Type text/html; charset=utf-8
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 ("multipart/form-data".equals(contentType)) { // multipart/form-data; charset=utf-8
parseParts(false); // !!! 解析multipart/form-data类型的各个part
success = true;
return;
}
// 不支持: Content-Type text/html; charset=utf-8
if (!("application/x-www-form-urlencoded".equals(contentType))) { // 普通post提交 application/x-www-form-urlencoded; charset=utf-8
success = true;
return;
}
int len = getContentLength(); // 内容的长度
byte[] formData = null;
if (readPostBody(formData, len) != len) { // 读取body的内容,放入formData
parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE);
return;
}
// 解析body的内容 formData === "a=value1&b=value2"
parameters.processParameters(formData, 0, len);
success = true;
}
// 解析multipart/form-data类型的各个part
private void parseParts(boolean explicit) {
// Return immediately if the parts have already been parsed
if (parts != null || partsParseException != null) {
return;
}
// org.apache.catalina.core.StandardContext
Context context = getContext();
// <web-app>
// <servlet>
// <multipart-config>
// <!-- 50MB max -->
// <max-file-size>52428800</max-file-size>
// <max-request-size>52428800</max-request-size>
// <file-size-threshold>0</file-size-threshold>
// </multipart-config>
// </servlet>
// </web-app>
// org.apache.catalina.core.StandardWrapper.getMultipartConfigElement()
MultipartConfigElement mce = getWrapper().getMultipartConfigElement(); //如果有配置<multipart-config>标签,就不为null
if (mce == null) { // 当有配置<multipart-config>标签时,这个条件为false
if(context.getAllowCasualMultipartParsing()) { // false
mce = new MultipartConfigElement(null,
connector.getMaxPostSize(),
connector.getMaxPostSize(),
connector.getMaxPostSize());
} else {
if (explicit) { // false
partsParseException = new IllegalStateException(
sm.getString("coyoteRequest.noMultipartConfig"));
return;
} else { // 默认走这里
parts = Collections.emptyList();
return;
}
}
}
Parameters parameters = coyoteRequest.getParameters();
parameters.setLimit(getConnector().getMaxParameterCount()); // 最大参数数量
boolean success = false;
try {
File location;
String locationStr = mce.getLocation();
location = ((File) context.getServletContext().getAttribute(
ServletContext.TEMPDIR)); // 使用临时目录
// 上传处理器
// Create a new file upload handler
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(location.getCanonicalFile()); // 设置文件存放位置
factory.setSizeThreshold(mce.getFileSizeThreshold()); // 设置请求大小阈值
// 文件上传
ServletFileUpload upload = new ServletFileUpload();
upload.setFileItemFactory(factory);
upload.setFileSizeMax(mce.getMaxFileSize());
upload.setSizeMax(mce.getMaxRequestSize()); // 允许的body大小
parts = new ArrayList<>();
List<FileItem> items =
upload.parseRequest(new ServletRequestContext(this)); // 解析所有表单项
int maxPostSize = getConnector().getMaxPostSize();
int postSize = 0;
String enc = getCharacterEncoding(); // 编码类型
Charset charset = null;
if (enc != null) {
try {
charset = B2CConverter.getCharset(enc);
} catch (UnsupportedEncodingException e) {
// Ignore
}
}
// item === org.apache.tomcat.util.http.fileupload.disk.DiskFileItem
for (FileItem item : items) { // 迭代所有表单项
ApplicationPart part = new ApplicationPart(item, location);
parts.add(part);
if (part.getSubmittedFileName() == null) { // 不是文件上传字段
String name = part.getName(); // 字段名称 如: file1 如:username
String value = null;
String encoding = parameters.getEncoding();
if (encoding == null) {
if (enc == null) {
encoding = Parameters.DEFAULT_ENCODING;
} else {
encoding = enc;
}
}
value = part.getString(encoding);
parameters.addParameter(name, value); // 不是文件上传字段
}
}
success = true;
}
// 读取body的内容,放入body
protected int readPostBody(byte[] body, int len)
throws IOException {
int offset = 0;
do {
// inputStream
int inputLen = getStream().read(body, offset, len - offset);
if (inputLen <= 0) {
return offset;
}
offset += inputLen;
} while ((len - offset) > 0);
return len;
}
}
class org.apache.tomcat.util.http.Parameters{
public void setQuery( MessageBytes queryMB ) {
this.queryMB=queryMB;
}
public void handleQueryParameters() {
if( didQueryParameters ) {
return;
}
didQueryParameters=true;
// queryMB存放的是URL的查询参数,如:a=value1&b=value2
// 设置查询字符串到decodedQuery.byteC、 decodedQuery.charC
// 如:a=value1&b=value2
decodedQuery.duplicate( queryMB ); //
processParameters( decodedQuery, queryStringEncoding ); //解析查询字符串
}
public void processParameters( MessageBytes data, String encoding ) {
// 取得查询字符串 如:a=value1&b=value2
ByteChunk bc=data.getByteChunk();
processParameters( bc.getBytes(), bc.getOffset(),
bc.getLength(), getCharset(encoding));
}
private void processParameters(byte bytes[], int start, int len,
Charset charset) {
// 如:bytes == "a=value1&b=value2"
addParameter(name, value); // 添加参数----------
}
// 添加参数
public void addParameter( String key, String value )
throws IllegalStateException {
// 设置key,value值
ArrayList<String> values = paramHashValues.get(key);
if (values == null) {
values = new ArrayList<>(1);
paramHashValues.put(key, values);
}
values.add(value);
}
public String getParameter(String name ) {
handleQueryParameters();
ArrayList<String> values = paramHashValues.get(name);
if (values != null) {
if(values.size() == 0) {
return "";
}
return values.get(0);
} else {
return null;
}
}
}