Catalina中有两个重要的模块:连接器和容器。
利用Bootstrap类来启动应用程序:
public final class Bootstrap {
public static void main(String[] args) {
HttpConnector connector = new HttpConnector();
connector.start();
}
}
Bootstrap类的main方法中,实例化HttpConnector并调用了它的start方法。
HttpConnector类指代指代一个连接器,职责是创建一个服务器套接字来等待Http请求。
public class HttpConnector implements Runnable {
boolean stopped;
private String scheme = "http";
public String getScheme() {
return scheme;
}
public void run() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket = new ServerSocket(port, 1,
InetAddress.getByName("127.0.0.1"));
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
while (!stopped) {
// Accept the next incoming connection from the server socket
Socket socket = null;
try {
socket = serverSocket.accept();
} catch (Exception e) {
continue;
}
// Hand this socket off to an HttpProcessor
HttpProcessor processor = new HttpProcessor(this);
processor.process(socket);
}
}
public void start() {
Thread thread = new Thread(this);
thread.start();
}
}
HttpConnector类实现了Runnable接口,所以它将是一个独立运行的线程,它能被它自己的线程专用,实例被创建时,它的run方法将会被调用。
这个线程主要用来作下面的事情:
- 等HTTP请求
- 为每个请求创建HttpProcessor实例
- 调用HttpProcessor的process方法
HttpProcessor类的process方法接受来自HTTP请求的套接字后,将会完成下面的工作:
- 创建一个HttpRequest对象
- 创建一个HttpResponse对象
- 解析HTTP请求的第一行和头部,并放到HttpRequest对象。
- 解析HttpRequest和HttpResponse对象到一个ServletProcessor或者StaticResourceProcessor。
public void process(Socket socket) {
SocketInputStream input = null;
OutputStream output = null;
try {
input = new SocketInputStream(socket.getInputStream(), 2048);
output = socket.getOutputStream();
// create HttpRequest object and parse
request = new HttpRequest(input);
// create HttpResponse object
response = new HttpResponse(output);
response.setRequest(request);
response.setHeader("Server", "Pyrmont Servlet Container");
parseRequest(input, output);
parseHeaders(input);
// check if this is a request for a servlet or a static resource
// a request for a servlet begins with "/servlet/"
if (request.getRequestURI().startsWith("/servlet/")) {
ServletProcessor processor = new ServletProcessor();
processor.process(request, response);
} else {
StaticResourceProcessor processor = new StaticResourceProcessor();
processor.process(request, response);
}
// Close the socket
socket.close();
// no shutdown for this application
} catch (Exception e) {
e.printStackTrace();
}
}
在process方法中首先获取服务器套接字的输入输出流,需要注意的是这里使用SocketInputStream类对服务器套接字的输入流进行的封装。
input = new SocketInputStream(socket.getInputStream(), 2048);
SocketInputStream继承自InputStream类,也就是服务器套接字输入流的实际类型。SocketInputStream可以在处理HTTP头信息时提高读取效率。
parseRequest(input, output);
解析HTTP请求:
private void parseRequest(SocketInputStream input, OutputStream output)
throws IOException, ServletException {
// Parse the incoming request line
input.readRequestLine(requestLine);
String method = new String(requestLine.method, 0,
requestLine.methodEnd);
String uri = null;
String protocol = new String(requestLine.protocol, 0,
requestLine.protocolEnd);
// Validate the incoming request line
if (method.length() < 1) {
throw new ServletException("Missing HTTP request method");
} else if (requestLine.uriEnd < 1) {
throw new ServletException("Missing HTTP request URI");
}
// Parse any query parameters out of the request URI
int question = requestLine.indexOf("?");
if (question >= 0) {
request.setQueryString(new String(requestLine.uri, question + 1,
requestLine.uriEnd - question - 1));
uri = new String(requestLine.uri, 0, question);
} else {
request.setQueryString(null);
uri = new String(requestLine.uri, 0, requestLine.uriEnd);
}
// Checking for an absolute URI (with the HTTP protocol)
if (!uri.startsWith("/")) {
int pos = uri.indexOf("://");
// Parsing out protocol and host name
if (pos != -1) {
pos = uri.indexOf('/', pos + 3);
if (pos == -1) {
uri = "";
} else {
uri = uri.substring(pos);
}
}
}
// Parse any requested session ID out of the request URI
String match = ";jsessionid=";
int semicolon = uri.indexOf(match);
if (semicolon >= 0) {
String rest = uri.substring(semicolon + match.length());
int semicolon2 = rest.indexOf(';');
if (semicolon2 >= 0) {
request.setRequestedSessionId(rest.substring(0, semicolon2));
rest = rest.substring(semicolon2);
} else {
request.setRequestedSessionId(rest);
rest = "";
}
request.setRequestedSessionURL(true);
uri = uri.substring(0, semicolon) + rest;
} else {
request.setRequestedSessionId(null);
request.setRequestedSessionURL(false);
}
// Normalize URI (using String operations at the moment)
String normalizedUri = normalize(uri);
// Set the corresponding request properties
((HttpRequest) request).setMethod(method);
request.setProtocol(protocol);
if (normalizedUri != null) {
((HttpRequest) request).setRequestURI(normalizedUri);
} else {
((HttpRequest) request).setRequestURI(uri);
}
if (normalizedUri == null) {
throw new ServletException("Invalid URI: " + uri + "'");
}
}
parseRequest方法读取请求行,用于解析HTTP请求行信息
input.readRequestLine(requestLine)
HttpRequestLine类是一个HTTP请求行的枚举类,以静态变量的形式提供了HTTP请求的method,protocol,uri,并提供方法检测uri中是否包含指定字符,如”?”等。readRequestLine方法读取服务器套接字的输入流(即,HTTP请求)并解析,将值赋给HttpRequestLine类method,protocol,uri等变量,方便parseRequest方法构建Request对象。
process方法中;
parseHeaders(input);
与parseRequest类似,用于解析HTTP请求的头信息,每一次的解析结果都赋给HttpHeader类,这是一个HTTP header的枚举类。读取HttpHeader类中的信息将之赋值给Request对象。