Coder 爱翻译 How Tomcat Works 第四章 第二部分
Request Objects
在默认的连接器中org.apache.catalina.Request接口代表了一个HTTP请求对象。HttpRequest的父类—RequestBase类直接实现了这个接口。最终的实现是HttpRequestImpl,它继承HttpRequest。在第三章中,有facade类:RequstFacade和HttpRequestFacade。
Response Objects
Processing Requests
现在,你已经了解了request、response对象和HttpConnector对象怎么创建它们。这部分我们关注HttpProcessor类的process方法,这个方法是HttpProcessor类的被指配了一个socket后的run方法里调用。这个process方法处理一下工作:
?解析连接
?解析请求
?解析头部信息
process方法使用boolean变量ok来表示在处理过程中是否出错和使用boolean变量finishResponse来表示Response接口的finishResponse方法应该被调用。
boolean ok = true; boolean finishResponse = true;
OutputStream output = null; // Construct and initialize the objects we will need try { input = new SocketInputStream(socket.getInputstream(), connector.getBufferSize()); } catch (Exception e) { ok = false;} keepAlive = true; while (!stopped && ok && keepAlive) { ... }finishResponse = true; try { request.setStream(input); request.setResponse(response); output = socket.getOutputStream(); response.setStream(output); response.setRequest(request); ((HttpServletResponse) response.getResponse()).setHeader ("Server", SERVER_INFO); } catch (Exception e) { log("process.create", e); //logging is discussed in Chapter 7 ok = false; } try { if (ok) { parseConnection(socket); parseRequest(input, output); if (!request.getRequest().getProtocol() .startsWith("HTTP/0")) parseHeaders(input);if (http11) { // Sending a request acknowledge back to the client if // requested. ackRequest(output); // If the protocol is HTTP/1.1, chunking is allowed. if (connector.isChunkingAllowed()) response.setAllowChunking(true); } try { ((HttpServletResponse) response).setHeader ("Date", FastHttpDateFormat.getCurrentDate()); if (ok) { connector.getContainer().invoke(request, response); } } if (finishResponse) { ... response.finishResponse(); ... request.finishRequest(); ... output.flush(); if ( "close".equals(response.getHeader("Connection")) ) { keepAlive = false; } // End of request processing status = Constants.PROCESSOR_IDLE; // Recycling the request and the response objects request.recycle(); response.recycle();}try { shutdownInput(input); socket.close(); } ...private void parseConnection(Socket socket) throws IOException, ServletException { if (debug >= 2) log(" parseConnection: address=" + socket.getInetAddress() + ", port=" + connector.getPort()); ((HttpRequestImpl) request).setInet(socket.getInetAddress()); if (proxyPort != 0) request.setServerPort(proxyPort); else request.setServerPort(serverPort); request.setSocket(socket); }static final char[] AUTHORIZATION_NAME = "authorization".toCharArray(); static final char[] ACCEPT_LANGUAGE_NAME = "accept-language".toCharArray(); static final char[] COOKIE_NAME = "cookie".toCharArray(); ...
HttpHeader header = request.allocateHeader(); // Read the next header input.readHeader(header);
if (header.nameEnd == 0) { if (header.valueEnd == 0) { return; } else { throw new ServletException (sm.getString("httpProcessor.parseHeaders.colon")); } } if (header.equals(DefaultHeaders.AUTHORIZATION_NAME)) { request.setAuthorization(value); } else if (header.equals(DefaultHeaders.ACCEPT_LANGUAGE_NAME)) { parseAcceptLanguage(value); } else if (header.equals(DefaultHeaders.COOKIE_NAME)) { // parse cookie } else if (header.equals(DefaultHeaders.CONTENT_LENGTH_NAME)) { // get content length } else if (header.equals(DefaultHeaders.CONTENT_TYPE_NAME)) { request.setContentType(value); } else if (header.equals(DefaultHeaders.HOST_NAME)) { // get host name } else if (header.equals(DefaultHeaders.CONNECTION_NAME)) { if (header.valueEquals(DefaultHeaders.CONNECTION_CLOSE_VALUE)) { keepAlive = false; response.setHeader("Connection", "close"); } } else if (header.equals(DefaultHeaders.EXPECT_NAME)) { if (header.valueEquals(DefaultHeaders.EXPECT_100_VALUE)) sendAck = true; else throw new ServletException(sm.getstring ("httpProcessor.parseHeaders.unknownExpectation")); } else if (header.equals(DefaultHeaders.TRANSFER_ENCODING_NAME)) { //request.setTransferEncoding(header); } request.nextHeader();Listing 4.3: The SimpleContainer class package ex04.pyrmont.core; import java.beans.PropertyChangeListener; import java.net.URL; import java.net.URLClassLoader; import java.net.URLStreamHandler; import java.io.File; import java.io.IOException; import javax.naming.directory.DirContext; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Cluster;import org.apache.catalina.Container; import org.apache.catalina.ContainerListener; import org.apache.catalina.Loader; import org.apache.catalina.Logger; import org.apache.catalina.Manager; import org.apache.catalina.Mapper; import org.apache.catalina.Realm; import org.apache.catalina.Request; import org.apache.catalina.Response; public class SimpleContainer implements Container { public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot"; public SimpleContainer() { } public String getInfo() { return null; } public Loader getLoader() { return null; } public void setLoader(Loader loader) { } public Logger getLogger() { return null; } public void setLogger(Logger logger) { } public Manager getManager() { return null; } public void setCluster(Cluster cluster) { } public String getName() { return null; } public void setName(String name) { } public Container getParent() { return null; } public void setParent(Container container) { } public ClassLoader getParentClassLoader() { return null; } public void setParentClassLoader(ClassLoader parent) { } public Realm getRealm() { return null; } public void setRealm(Realm realm) { } public DirContext getResources() { return null; } public void setResources(DirContext resources) { } public void addChild(Container child) { } public void addContainerListener(ContainerListener listener) { } public void addMapper(Mapper mapper) { } public void addPropertyChangeListener( PropertyChangeListener listener) { } public Container findchild(String name) { return null; } public Container[] findChildren() { return null; } public ContainerListener[] findContainerListeners() { return null; } public Mapper findMapper(String protocol) { return null; } public Mapper[] findMappers() { return null; } public void invoke(Request request, Response response) throws IoException, ServletException { string servletName = ( (Httpservletrequest) request).getRequestURI(); servletName = servletName.substring(servletName.lastIndexof("/") + 1); URLClassLoader loader = null; try { URL[] urls = new URL[1]; URLStreamHandler streamHandler = null; File classpath = new File(WEB_ROOT); string repository = (new URL("file",null, classpath.getCanonicalpath() + File.separator)).toString(); urls[0] = new URL(null, repository, streamHandler); loader = new URLClassLoader(urls); } catch (IOException e) { System.out.println(e.toString() ); } Class myClass = null; try { myClass = loader.loadclass(servletName); } catch (classNotFoundException e) { System.out.println(e.toString()); } servlet servlet = null; try { servlet = (Servlet) myClass.newInstance(); servlet.service((HttpServletRequest) request,(HttpServletResponse) response); } catch (Exception e) { System.out.println(e.toString()); } catch (Throwable e) { System.out.println(e.toString()); } } public Container map(Request request, boolean update) { return null; } public void removeChild(Container child) { } public void removeContainerListener(ContainerListener listener) { } public void removeMapper(Mapper mapper) { } public void removeMapper(Mapper mapper) { } public void removoPropertyChangeListener( PropertyChangeListener listener) { } }Listing 4.4: The ex04.pyrmont.startup.Bootstrap class package ex04.pyrmont.startup; import ex04.pyrmont.core.simplecontainer; import org.apache.catalina.connector.http.HttpConnector; public final class Bootstrap { public static void main(string[] args) { HttpConnector connector = new HttpConnector(); SimpleContainer container = new SimpleContainer(); connector.setContainer(container); try { connector.initialize(); connector.start(); // make the application wait until we press any key. System in.read(); } catch (Exception e) { e.printStackTrace(); } } }