Tomcat源码5

来源:互联网 发布:剑灵高冷凌女数据 编辑:程序博客网 时间:2024/05/06 14:30
接着我们就来看看HttpProcessor的process()方法了,这个方法是处理请求的重头级函数!
首先要处理请求,要么首先要有获取资源的来源,那么在HttpProcessor类中需要HttpRequestImpl和HttpResponseImpl对象,因为这两个类是获取信息的来源!
那么首先看看HttpProcessor初始化HttpRequestImpl和HttpResponseImpl对象的?
在HttpConnector类中初始化HttpProcessor实例时,就会调用HttpProcessor的构造方法,看看其构造方法做了什么事?

org.apache.catalina.connector.http.HttpProcessor
        /**
     * The HTTP request object we will pass to our associated container.
     */
    private HttpRequestImpl request = null;


    /**
     * The HTTP response object we will pass to our associated container.
     */
    private HttpResponseImpl response = null;
    
     // ----------------------------------------------------------- Constructors


    /**
     * Construct a new HttpProcessor associated with the specified connector.
     *
     * @param connector HttpConnector that owns this processor
     * @param id Identifier of this HttpProcessor (unique per connector)
     */
    public HttpProcessor(HttpConnector connector, int id) {

        super();
        this.connector = connector;
        this.debug = connector.getDebug();
        this.id = id;
        this.proxyName = connector.getProxyName();
        this.proxyPort = connector.getProxyPort();
        this.request = (HttpRequestImpl) connector.createRequest();
        this.response = (HttpResponseImpl) connector.createResponse();
        this.serverPort = connector.getPort();
        this.threadName =
          "HttpProcessor[" + connector.getPort() + "][" + id + "]";

    }
    
    这个构造函数就创建了HttpRequestImpl和HttpResponseImpl实例!那么接着就看处理处理这个实例!
    
先分析一下调用过程,当Socket对象被赋值给HttpProcessor类后,HttpProcessor类的run()方法会调用process()方法,process()方法会执行以下3个操作:解析连接,解析请求,解析请求头。先给出tomcat4.0给出的整体的实现,然后再分小段来看!
org.apache.catalina.connector.http.HttpProcessor

  /**
     * The HTTP request object we will pass to our associated container.
     */
    private HttpRequestImpl request = null;


    /**
     * The HTTP response object we will pass to our associated container.
     */
    private HttpResponseImpl response = null;
    
    
/**
     * Process an incoming HTTP request on the Socket that has been assigned
     * to this Processor.  Any exceptions that occur during processing must be
     * swallowed and dealt with.
     *
     * @param socket The socket on which we are connected to the client
     */
    private void process(Socket socket) {

        boolean ok = true;//表示在处理过程中是否有错误发生
        boolean finishResponse = true;//表示是否应该调用Response接口的finishResponse()方法
        SocketInputStream input = null;
        OutputStream output = null;
    
    //socketInputStream实例用于包装套借字的输入流
        // Construct and initialize the objects we will need
        try {
            input = new SocketInputStream(socket.getInputStream(),
                                          connector.getBufferSize());
        } catch (Exception e) {
            log("process.create", e);
            ok = false;
        }

        keepAlive = true;//表示该链接是否是持久连接,//stopped表明HttpProcessor实例是否被连接器终止,如果stopped为真,那么process()也应该被终止

    //stopped表示HttpProcessor实例是否被连接器终止,keepAlive表明该连接是否持久连接
        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);
                ok = false;
            }

            // Parse the incoming request
            try {
                if (ok) {
                    parseConnection(socket);//获取请求所使用的协议,若是Http1.0,则将keepAlive设置为false,因为Http1.0不支持持久连接
                    parseRequest(input, output);//解析请求
                    if (!request.getRequest().getProtocol()
                        .startsWith("HTTP/0"))
                        parseHeaders(input);//若是在http请求头中找到"Expect:100-continue",则parseHeaders()方法将设置sendACK为true
                    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);
                    }
                }
            } catch (EOFException e) {//如果已经读到了数据末尾,但是连接断开了,如果再继续读取数据则会抛出此异常
                // It's very likely to be a socket disconnect on either the
                // client or the server
                ok = false;
                finishResponse = false;
            } catch (ServletException e) {
                ok = false;
                try {
                    ((HttpServletResponse) response.getResponse())
                        .sendError(HttpServletResponse.SC_BAD_REQUEST);
                } catch (Exception f) {
                    ;
                }
            } catch (InterruptedIOException e) {
                if (debug > 1) {
                    try {
                        log("process.parse", e);
                        ((HttpServletResponse) response.getResponse())
                            .sendError(HttpServletResponse.SC_BAD_REQUEST);
                    } catch (Exception f) {
                        ;
                    }
                }
                ok = false;
            } catch (Exception e) {
                try {
                    log("process.parse", e);
                    ((HttpServletResponse) response.getResponse()).sendError
                        (HttpServletResponse.SC_BAD_REQUEST);
                } catch (Exception f) {
                    ;
                }
                ok = false;
            }

            // Ask our Container to process this request
            try {
                ((HttpServletResponse) response).setHeader
                    ("Date", FastHttpDateFormat.getCurrentDate());
                if (ok) {
                    connector.getContainer().invoke(request, response);//解析完成,process()方法将request和response对象作为参数传入servlet容器的invoke方法,这个暂时不是这里的重点
                }
            } catch (ServletException e) {
                log("process.invoke", e);
                try {
                    ((HttpServletResponse) response.getResponse()).sendError
                        (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                } catch (Exception f) {
                    ;
                }
                ok = false;
            } catch (InterruptedIOException e) {
                ok = false;
            } catch (Throwable e) {
                log("process.invoke", e);
                try {
                    ((HttpServletResponse) response.getResponse()).sendError
                        (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                } catch (Exception f) {
                    ;
                }
                ok = false;
            }

            // Finish up the handling of the request
            if (finishResponse) {
                try {
                    response.finishResponse();
                } catch (IOException e) {
                    ok = false;
                } catch (Throwable e) {
                    log("process.invoke", e);
                    ok = false;
                }
                try {
                    request.finishRequest();
                } catch (IOException e) {
                    ok = false;
                } catch (Throwable e) {
                    log("process.invoke", e);
                    ok = false;
                }
                try {
                    if (output != null)
                        output.flush();
                } catch (IOException e) {
                    ok = false;
                }
            }

            // We have to check if the connection closure has been requested
            // by the application or the response stream (in case of HTTP/1.0
            // and keep-alive).
            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();
        } catch (IOException e) {
            ;
        } catch (Throwable e) {
            log("process.invoke", e);
        }
        socket = null;

    }
    
1,先分析这个方法中一些变量的含义:
process()方法使用一个布尔变量ok来处理过程中是否有错误发生,以及一个布尔变量finishResponse来表示是否应该调用Response接口的finishResponse()方法:
boolean ok = true;
boolean finishResponse = true;
此外,process()方法还是用了其他一些布尔类型的成员变量,如keepAlive,stopped和http11。keepAlive表示该连接是否是持久连接,stopped表示HttpProcessor实例是否被连接器终止,这样的话process()方法也应该被终止。http11表明HTTP请求是否是从支持HTTP1.1客户端发送来的。
2,看看这个input = new SocketInputStream(socket.getInputStream(),
                                        connector.getBufferSize());
SocketInputStream实例用于包装套接字的输入流。要注意的是,SocketInputStream类的构造函数也接受以缓冲区的大小为参数,该参数来自连接器,而不是HttpProcessor类中的一个局部变量。这是因为,对默认连接器的用户来说,HttpProcessor是不可见的。通过在Connector借口中设置缓冲区大小,任何人都可以使用连接器来设置缓冲区的大小;
org.apache.catalina.connector.http.HttpProcessor
 SocketInputStream input = null;
        OutputStream output = null;
    
    //socketInputStream实例用于包装套借字的输入流
        // Construct and initialize the objects we will need
        try {
            input = new SocketInputStream(socket.getInputStream(),
                                          connector.getBufferSize());
        } catch (Exception e) {
            log("process.create", e);
            ok = false;
        }
-----------------------------------------------------------------------------------------------------------------        
    
org.apache.catalina.connector.http.HttpConnector

 /**
     * The input buffer size we should create on input streams.
     */
    private int bufferSize = 2048;
    
    
    /**
     * Return the input buffer size for this Connector.
     */
    public int getBufferSize() {

        return (this.bufferSize);

    }


    /**
     * Set the input buffer size for this Connector.
     *
     * @param bufferSize The new input buffer size.
     */
    public void setBufferSize(int bufferSize) {

        this.bufferSize = bufferSize;

    }
3,然后是一个while循环,在循环体内,不断地读取输入流,直到HttpProcessor实例终止,抛出一个异常,或连接断开。
keepAlive = true;
while(!stopped && ok && keepAlive){
....
}
4,在while循环内,process()方法会先将变量finishResponse的值设置为true,然后获取输出流对象,执行request和reponse对象的一些初始化操作:
org.apache.catalina.connector.http.HttpProcessor
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);
                ok = false;
            }
5,接着process()方法会调用parseConnection(),parseRequest()和parseHeaders()方法开始解析引入的HTTP请求。这三个方法的具体实现会在后面来分析,现在来分析这三个方法做了一些什么事情。
org.apache.catalina.connector.http.HttpProcessor,
try {
                if (ok) {
                    parseConnection(socket);//获取请求所使用的协议,若是Http1.0,则将keepAlive设置为false,因为Http1.0不支持持久连接
                    parseRequest(input, output);//解析请求.............................
                    if (!request.getRequest().getProtocol()
                        .startsWith("HTTP/0"))
                        parseHeaders(input);//若是在http请求头中找到"Expect:100-continue",则parseHeaders()方法将设置sendACK为true
parseConnection()方法获取请求所使用的协议,其值可以是HTTP0.9,HTTP1.0或HTTP1.1。若值为HTTP1.0,则将keepAlive设置为false,因为HTTP1.0不支持持久连接。若是在http请求中找到发现"Expect: 100-continue",则parseHeaders()方法将设置sendAck为sendAck为true
若请求协议为HTTP1.1,而且客户端也发出了"Expect: 100-continue"请求头,会对调用ackRequest()方法该请求头进行响应,此外,还会检查是否允许分块:
 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);
                    }
ackRequest()方法检查sendAck的值,若其值为true,则发送下面格式的字符串:HTTP/1.1 100 Continue\r\n\r\n
6,在解析HTTP请求过程中,有可能会抛出很多种异常,发生任何一个异常都会将变量ok或finishResponse设置为false。完成解析后,process()方法将request和reprose对象作为参数传入servlet容器的invoke()方法。
 try {
                ((HttpServletResponse) response).setHeader
                    ("Date", FastHttpDateFormat.getCurrentDate());
                if (ok) {
                    connector.getContainer().invoke(request, response);//解析完成,process()方法将request和response对象作为参数传入servlet容器的invoke方法,这个暂时不是这里的重点
                }
7,然后,若变量finishResponse()的值为true,则调用response对象的finishResponse()方法和request对象的finishRequest()方法,再将结果发送至多个客户端:
  // Finish up the handling of the request
            if (finishResponse) {
                try {
                    response.finishResponse();
                } catch (IOException e) {
                    ok = false;
                } catch (Throwable e) {
                    log("process.invoke", e);
                    ok = false;
                }
                try {
                    request.finishRequest();
                } catch (IOException e) {
                    ok = false;
                } catch (Throwable e) {
                    log("process.invoke", e);
                    ok = false;
                }
                try {
                    if (output != null)
                        output.flush();
                } catch (IOException e) {
                    ok = false;
                }
            }
8,while()循环的最后一部分检查response的头信息"Connection"是否在servlet中被设置为"close",或者协议是否是HTTP1.0(不支持持久连接)。若这两种情况中任意一种为真,则将keepAlive设置为false,最后将request对象和response对象回收:
           // We have to check if the connection closure has been requested
            // by the application or the response stream (in case of HTTP/1.0
            // and keep-alive).
            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();
9,在这种情况下,若keepAlive为true,或者前面的解析工作中没有错误,或HttpProcessor实例没有被终止,则while循环则继续运行。否则调用shutdownInput()方法,并关闭套接字:
 try {
            shutdownInput(input);//会检查是否有未读完的字节,若有,则它跳过这些字节
            socket.close();
        } catch (IOException e) {
            ;
        } catch (Throwable e) {
            log("process.invoke", e);
        }
        socket = null;
      }
好了Process方法的大概就讲到了这里,后面对Process()方法里面的细节再进一步详细的介绍。