SocketInputStream.java:
下面来看看上一节留下来的两个函数,先看第一个:
org.apache.catalina.connector.http.SocketInputStream// ----------------------------------------------------------- Constructors
/**
* Construct a servlet input stream associated with the specified socket
* input.
*
* @param is socket input stream
* @param bufferSize size of the internal buffer
*/
public SocketInputStream(InputStream is, int bufferSize) {
this.is = is;
buf = new byte[bufferSize];
}
// -------------------------------------------------------------- Variables
/**
* The string manager for this package.
*/
protected static StringManager sm =
StringManager.getManager(Constants.Package);
// ----------------------------------------------------- Instance Variables
// --------------------------------------------------------- Public Methods
/**
* Read the request line, and copies it to the given buffer. This
* function is meant to be used during the HTTP request header parsing.
* Do NOT attempt to read the request body using it.
*
* @param requestLine Request line object
* @throws IOException If an exception occurs during the underlying socket
* read operations, or if the given buffer is not big enough to accomodate
* the whole line.
*/
public void readRequestLine(HttpRequestLine requestLine)
throws IOException {
// Recycling check
if (requestLine.methodEnd != 0)
requestLine.recycle();
// Checking for a blank line
//检查是否有空行
//过滤掉换行符,'\r\n'(windows换行符),'\n'(UNIX换行符)
//下面这段来说就是获取提交的方法
int chr = 0;
do { // Skipping CR or LF
try {
chr = read();//
} catch (IOException e) {
chr = -1;
}
} while ((chr == CR) || (chr == LF));
if (chr == -1)
throw new EOFException
(sm.getString("requestStream.readline.error"));
pos--;
//解析请求的方法
// Reading the method name
int maxRead = requestLine.method.length;
int readCount = 0;
boolean space = false;//标记是否读到空格
//一旦遇到空格就终止循环
while (!space) {
//如果缓冲区满了,扩大缓冲区
// if the buffer is full, extend it
if (readCount >= maxRead) {//如果存放方法的字节数组的长度大于给定的长度时
if ((2 * maxRead) <= HttpRequestLine.MAX_METHOD_SIZE) {//该原数组扩大两倍
char[] newBuffer = new char[2 * maxRead];
System.arraycopy(requestLine.method, 0, newBuffer, 0,
maxRead);//将requestLine.method数组拷贝到newBuffer数组中
requestLine.method = newBuffer;//将newBuffer的引用传给method
maxRead = requestLine.method.length;//更新一下长度
} else {
throw new IOException
(sm.getString("requestStream.readline.toolong"));
}
}
// We're at the end of the internal buffer
//再读取一下数据。
//读到了内部buffer结束的位置,因为在上面已经成功读取一行数据了,接下来就是要逐个读取每个字节
//一旦pos大于count,将pos置0
if (pos >= count) {
int val = read();
if (val == -1) {
throw new IOException
(sm.getString("requestStream.readline.error"));
}
pos = 0;
}
if (buf[pos] == SP) {//判断当前读到的字节是否' '
space = true;//设置space,方便上面跳出while循环
}
requestLine.method[readCount] = (char) buf[pos];//将请求的方法填充到requestLine.method字节数组中
readCount++;//当前字节数加1
pos++;//当前位置加1
}
requestLine.methodEnd = readCount - 1;
//解析URI
// Reading URI
maxRead = requestLine.uri.length;
readCount = 0;
space = false;
boolean eol = false;
while (!space) {
//更上面的差不多
// if the buffer is full, extend it
if (readCount >= maxRead) {
if ((2 * maxRead) <= HttpRequestLine.MAX_URI_SIZE) {
char[] newBuffer = new char[2 * maxRead];
System.arraycopy(requestLine.uri, 0, newBuffer, 0,
maxRead);
requestLine.uri = newBuffer;
maxRead = requestLine.uri.length;
} else {
throw new IOException
(sm.getString("requestStream.readline.toolong"));
}
}
// We're at the end of the internal buffer
//读到了内部buffer结束的位置,因为在上面已经成功读取一行数据了,接下来就是要逐个读取每个字节
//一旦pos大于count,将pos置0
if (pos >= count) {
int val = read();//逐个读取buffer中的字节
if (val == -1)
throw new IOException
(sm.getString("requestStream.readline.error"));
pos = 0;
}
if (buf[pos] == SP) {//判断当前读到的字节是否' '
space = true;//设置space,方便上面跳出while循环
} else if ((buf[pos] == CR) || (buf[pos] == LF)) {
// HTTP/0.9 style request
//HTTP/0.9的风格
eol = true;
space = true;
}
requestLine.uri[readCount] = (char) buf[pos];
readCount++;
pos++;
}
requestLine.uriEnd = readCount - 1;//设置uri的末尾结束位置
//解析协议
// Reading protocol
maxRead = requestLine.protocol.length;
readCount = 0;
//如果是HTTP/0.9不用解析协议。HTTP的请求格式类似:GET www.cnblogs.com
while (!eol) {
// if the buffer is full, extend it
if (readCount >= maxRead) {
if ((2 * maxRead) <= HttpRequestLine.MAX_PROTOCOL_SIZE) {
char[] newBuffer = new char[2 * maxRead];
System.arraycopy(requestLine.protocol, 0, newBuffer, 0,
maxRead);
requestLine.protocol = newBuffer;
maxRead = requestLine.protocol.length;
} else {
throw new IOException
(sm.getString("requestStream.readline.toolong"));
}
}
// We're at the end of the internal buffer
//一旦pos大于count,将pos置0
// Copying part (or all) of the internal buffer to the line
// buffer
int val = read();
if (val == -1)
throw new IOException
(sm.getString("requestStream.readline.error"));
pos = 0;
}
//过滤换行符
if (buf[pos] == CR) {
// Skip CR.
} else if (buf[pos] == LF) {
eol = true;
} else {
requestLine.protocol[readCount] = (char) buf[pos];
readCount++;
}
pos++;
}
requestLine.protocolEnd = readCount;//设置协议的末尾结束位置
}
/**
* Read byte.
*/
public int read()
throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return buf[pos++] & 0xff;//进行高24位清0,返回当前字节
}
// ------------------------------------------------------ Protected Methods
/**
* Fill the internal buffer using data from the undelying input stream.
*/
protected void fill()
throws IOException {
pos = 0;
count = 0;
int nRead = is.read(buf, 0, buf.length);//读取buf.length长度的字节存放到buf字节数组中
if (nRead > 0) {
count = nRead;//将读到的字节数目赋值给count
}
}
这是就获得的请求的版本,方法,URI等信息了。
//纠正函数,就是把错误的URI进行纠正
//各种纠正方式,这里就不说了,自己慢慢看!
org.apache.catalina.connector.http.HttpProcessor
/**
* Return a context-relative path, beginning with a "/", that represents
* the canonical version of the specified path after ".." and "." elements
* are resolved out. If the specified path attempts to go outside the
* boundaries of the current context (i.e. too many ".." path elements
* are present), return <code>null</code> instead.
*
* @param path Path to be normalized
*/
protected String normalize(String path) {
if (path == null)
return null;
// Create a place for the normalized path
String normalized = path;
// Normalize "/%7E" and "/%7e" at the beginning to "/~"
if (normalized.startsWith("/%7E") ||
normalized.startsWith("/%7e"))
normalized = "/~" + normalized.substring(4);
// Prevent encoding '%', '/', '.' and '\', which are special reserved
// characters
if ((normalized.indexOf("%25") >= 0)
|| (normalized.indexOf("%2F") >= 0)
|| (normalized.indexOf("%2E") >= 0)
|| (normalized.indexOf("%5C") >= 0)
|| (normalized.indexOf("%2f") >= 0)
|| (normalized.indexOf("%2e") >= 0)
|| (normalized.indexOf("%5c") >= 0)) {
return null;
}
if (normalized.equals("/."))
return "/";
// Normalize the slashes and add leading slash if necessary
if (normalized.indexOf('\\') >= 0)
normalized = normalized.replace('\\', '/');
if (!normalized.startsWith("/"))
normalized = "/" + normalized;
// Resolve occurrences of "//" in the normalized path
while (true) {
int index = normalized.indexOf("//");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 1);
}
// Resolve occurrences of "/./" in the normalized path
while (true) {
int index = normalized.indexOf("/./");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 2);
}
// Resolve occurrences of "/../" in the normalized path
while (true) {
int index = normalized.indexOf("/../");
if (index < 0)
break;
if (index == 0)
return (null); // Trying to go outside our context
int index2 = normalized.lastIndexOf('/', index - 1);
normalized = normalized.substring(0, index2) +
normalized.substring(index + 3);
}
// Declare occurrences of "/..." (three or more dots) to be invalid
// (on some Windows platforms this walks the directory tree!!!)
if (normalized.indexOf("/...") >= 0)
return (null);
// Return the normalized path that we have completed
return (normalized);
}
下面就来看看如何解析头部了。。。。。。。。。。。。。。。