这一节说说tomcat如何解析请求的头部的。这一节要介绍的东西比较多,先给出tomcat解析头部的大概思路,然后再从各个细节进行突破。
解析头部的大概思路还是比较清晰的,首先头部的信息是以键值对来进行存储的,那么只要把键和值给分离开来就OK了,然后根据具体的key,来对value进行设置。
设置到HttpRequestImpl中的信息有:authorization,accept-language,cookie,content-length,content-type,host,connection,close,expect,100-continue,transfer-encoding,具体看下面代码的注释!
/**
* Parse the incoming HTTP request headers, and set the appropriate
* request headers.
*
* @param input The input stream connected to our socket
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a parsing error occurs
*/
private void parseHeaders(SocketInputStream input)
throws IOException, ServletException {
while (true) {
HttpHeader header = request.allocateHeader();//创建一个内容为空的HttpHeader实例
// Read the next header
//将该HttpHeader实例传入SocketInputStream实例中的readHeader()方法中,若所有的请求都已经读取过了,
//则readHeader()方法不会再给HttpHeader实例位置name属性了。这时就可以退出parseHeader()方法了。
input.readHeader(header);
//如果header.nameEnd的长度与header.valueEnd为0,则返回,因为没有头部信息读取
if (header.nameEnd == 0) {
if (header.valueEnd == 0) {
return;
} else {
throw new ServletException
(sm.getString("httpProcessor.parseHeaders.colon"));
}
}
String value = new String(header.value, 0, header.valueEnd);//否则将头部信息转化为字符串
if (debug >= 1)
log(" Header " + new String(header.name, 0, header.nameEnd)
+ " = " + value);
// Set the corresponding request headers
//设置Authorization
if (header.equals(DefaultHeaders.AUTHORIZATION_NAME)) {
request.setAuthorization(value);
} else if (header.equals(DefaultHeaders.ACCEPT_LANGUAGE_NAME)) {//设置ACCEPT_LANGUAGE_NAME
parseAcceptLanguage(value);
} else if (header.equals(DefaultHeaders.COOKIE_NAME)) {//设置COOKIE_NAME
Cookie cookies[] = RequestUtil.parseCookieHeader(value);//解析Cookie
for (int i = 0; i < cookies.length; i++) {
if (cookies[i].getName().equals
(Globals.SESSION_COOKIE_NAME)) {
// Override anything requested in the URL
if (!request.isRequestedSessionIdFromCookie()) {
// Accept only the first session id cookie
request.setRequestedSessionId
(cookies[i].getValue());//设置SessionID
request.setRequestedSessionCookie(true);//如果SessionID是通过cookies传送过来的,那么这个标志设置为true
request.setRequestedSessionURL(false);//如果SessionID不是通过URI传送过来的,那么这个标志设置为false
if (debug >= 1)
log(" Requested cookie session id is " +
((HttpServletRequest) request.getRequest())
.getRequestedSessionId());
}
}
if (debug >= 1)
log(" Adding cookie " + cookies[i].getName() + "=" +
cookies[i].getValue());
request.addCookie(cookies[i]);//将cookies加入到数组容器中
}
} else if (header.equals(DefaultHeaders.CONTENT_LENGTH_NAME)) {//如果在http请求头中发现"content-length"
int n = -1;
try {
n = Integer.parseInt(value);
} catch (Exception e) {
throw new ServletException
(sm.getString
("httpProcessor.parseHeaders.contentLength"));
}
request.setContentLength(n);//设置文本长度
} else if (header.equals(DefaultHeaders.CONTENT_TYPE_NAME)) {//如果在http请求头中发现"content-type"
request.setContentType(value);//设置请求文本类型
} else if (header.equals(DefaultHeaders.HOST_NAME)) {//如果在http请求头中发现"host"
int n = value.indexOf(':');//获取协议方式
if (n < 0) {
if (connector.getScheme().equals("http")) {
request.setServerPort(80);//如果是http那么监听80端口
} else if (connector.getScheme().equals("https")) {
request.setServerPort(443);//如果是https那么监听443端口
}
if (proxyName != null)
request.setServerName(proxyName);//设置代理服务器名字
else
request.setServerName(value);//设置服务器名字
} else {
if (proxyName != null)
request.setServerName(proxyName);
else
request.setServerName(value.substring(0, n).trim());
if (proxyPort != 0)
request.setServerPort(proxyPort);//设置代理端口号
else {
int port = 80;
try {
port =
Integer.parseInt(value.substring(n+1).trim());
} catch (Exception e) {
throw new ServletException
(sm.getString
("httpProcessor.parseHeaders.portNumber"));
}
request.setServerPort(port);//设置端口号
}
}
} else if (header.equals(DefaultHeaders.CONNECTION_NAME)) {//如果在http请求头中发现"connection"
if (header.valueEquals
(DefaultHeaders.CONNECTION_CLOSE_VALUE)) {//如果在http请求头中发现"close"
keepAlive = false;//说明不持久连接
response.setHeader("Connection", "close");
}
//request.setConnection(header);
/*
if ("keep-alive".equalsIgnoreCase(value)) {
keepAlive = true;
}
*/
} else if (header.equals(DefaultHeaders.EXPECT_NAME)) {//如果在http请求头中发现"expect"
if (header.valueEquals(DefaultHeaders.EXPECT_100_VALUE))//并且在http请求头中发现"100-continue"
sendAck = true;//允许分块发送
else
throw new ServletException
(sm.getString
("httpProcessor.parseHeaders.unknownExpectation"));
} else if (header.equals(DefaultHeaders.TRANSFER_ENCODING_NAME)) {
//request.setTransferEncoding(header);
}
request.nextHeader();//读取下一个请求头
}
}
接下来会继续分析这串代码中的细节部分!
解析头部的大概思路还是比较清晰的,首先头部的信息是以键值对来进行存储的,那么只要把键和值给分离开来就OK了,然后根据具体的key,来对value进行设置。
设置到HttpRequestImpl中的信息有:authorization,accept-language,cookie,content-length,content-type,host,connection,close,expect,100-continue,transfer-encoding,具体看下面代码的注释!
/**
* Parse the incoming HTTP request headers, and set the appropriate
* request headers.
*
* @param input The input stream connected to our socket
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a parsing error occurs
*/
private void parseHeaders(SocketInputStream input)
throws IOException, ServletException {
while (true) {
HttpHeader header = request.allocateHeader();//创建一个内容为空的HttpHeader实例
// Read the next header
//将该HttpHeader实例传入SocketInputStream实例中的readHeader()方法中,若所有的请求都已经读取过了,
//则readHeader()方法不会再给HttpHeader实例位置name属性了。这时就可以退出parseHeader()方法了。
input.readHeader(header);
//如果header.nameEnd的长度与header.valueEnd为0,则返回,因为没有头部信息读取
if (header.nameEnd == 0) {
if (header.valueEnd == 0) {
return;
} else {
throw new ServletException
(sm.getString("httpProcessor.parseHeaders.colon"));
}
}
String value = new String(header.value, 0, header.valueEnd);//否则将头部信息转化为字符串
if (debug >= 1)
log(" Header " + new String(header.name, 0, header.nameEnd)
+ " = " + value);
// Set the corresponding request headers
//设置Authorization
if (header.equals(DefaultHeaders.AUTHORIZATION_NAME)) {
request.setAuthorization(value);
} else if (header.equals(DefaultHeaders.ACCEPT_LANGUAGE_NAME)) {//设置ACCEPT_LANGUAGE_NAME
parseAcceptLanguage(value);
} else if (header.equals(DefaultHeaders.COOKIE_NAME)) {//设置COOKIE_NAME
Cookie cookies[] = RequestUtil.parseCookieHeader(value);//解析Cookie
for (int i = 0; i < cookies.length; i++) {
if (cookies[i].getName().equals
(Globals.SESSION_COOKIE_NAME)) {
// Override anything requested in the URL
if (!request.isRequestedSessionIdFromCookie()) {
// Accept only the first session id cookie
request.setRequestedSessionId
(cookies[i].getValue());//设置SessionID
request.setRequestedSessionCookie(true);//如果SessionID是通过cookies传送过来的,那么这个标志设置为true
request.setRequestedSessionURL(false);//如果SessionID不是通过URI传送过来的,那么这个标志设置为false
if (debug >= 1)
log(" Requested cookie session id is " +
((HttpServletRequest) request.getRequest())
.getRequestedSessionId());
}
}
if (debug >= 1)
log(" Adding cookie " + cookies[i].getName() + "=" +
cookies[i].getValue());
request.addCookie(cookies[i]);//将cookies加入到数组容器中
}
} else if (header.equals(DefaultHeaders.CONTENT_LENGTH_NAME)) {//如果在http请求头中发现"content-length"
int n = -1;
try {
n = Integer.parseInt(value);
} catch (Exception e) {
throw new ServletException
(sm.getString
("httpProcessor.parseHeaders.contentLength"));
}
request.setContentLength(n);//设置文本长度
} else if (header.equals(DefaultHeaders.CONTENT_TYPE_NAME)) {//如果在http请求头中发现"content-type"
request.setContentType(value);//设置请求文本类型
} else if (header.equals(DefaultHeaders.HOST_NAME)) {//如果在http请求头中发现"host"
int n = value.indexOf(':');//获取协议方式
if (n < 0) {
if (connector.getScheme().equals("http")) {
request.setServerPort(80);//如果是http那么监听80端口
} else if (connector.getScheme().equals("https")) {
request.setServerPort(443);//如果是https那么监听443端口
}
if (proxyName != null)
request.setServerName(proxyName);//设置代理服务器名字
else
request.setServerName(value);//设置服务器名字
} else {
if (proxyName != null)
request.setServerName(proxyName);
else
request.setServerName(value.substring(0, n).trim());
if (proxyPort != 0)
request.setServerPort(proxyPort);//设置代理端口号
else {
int port = 80;
try {
port =
Integer.parseInt(value.substring(n+1).trim());
} catch (Exception e) {
throw new ServletException
(sm.getString
("httpProcessor.parseHeaders.portNumber"));
}
request.setServerPort(port);//设置端口号
}
}
} else if (header.equals(DefaultHeaders.CONNECTION_NAME)) {//如果在http请求头中发现"connection"
if (header.valueEquals
(DefaultHeaders.CONNECTION_CLOSE_VALUE)) {//如果在http请求头中发现"close"
keepAlive = false;//说明不持久连接
response.setHeader("Connection", "close");
}
//request.setConnection(header);
/*
if ("keep-alive".equalsIgnoreCase(value)) {
keepAlive = true;
}
*/
} else if (header.equals(DefaultHeaders.EXPECT_NAME)) {//如果在http请求头中发现"expect"
if (header.valueEquals(DefaultHeaders.EXPECT_100_VALUE))//并且在http请求头中发现"100-continue"
sendAck = true;//允许分块发送
else
throw new ServletException
(sm.getString
("httpProcessor.parseHeaders.unknownExpectation"));
} else if (header.equals(DefaultHeaders.TRANSFER_ENCODING_NAME)) {
//request.setTransferEncoding(header);
}
request.nextHeader();//读取下一个请求头
}
}
接下来会继续分析这串代码中的细节部分!