Tomcat源码6

这一小节需要掌握两个函数。
1,首先先来看看parseConnection()方法:解析连接。下面来看看Tomcat的源码实现:
org.apache.catalina.connector.http.HttpProcessor

 /**
     * Parse and record the connection parameters related to this request.
     *
     * @param socket The socket on which we are connected
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a parsing error occurs
     */
    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);
 }
 上面很清楚,做了三件事,首先是从套接字中获取Internet地址,将其赋值给HttpRequestImpl对象,此外,它还要检查是否使用了代理,最后将Socket对象赋值给request对象。
 但是我对于上面的代码有一个小疑问,就是 ((HttpRequestImpl) request).setInet(socket.getInetAddress())这一句,request实例它就是HttpRequestImpl类型的了,为什么还要做一次转型呢???????????
 2,再来看看parseRequest()函数,解析请求。
  /**
     * Parse the incoming HTTP request and set the corresponding HTTP request
     * properties.
     *
     * @param input The input stream attached to our socket
     * @param output The output stream of the socket
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a parsing error occurs
     */
    private void parseRequest(SocketInputStream input, OutputStream output)
        throws IOException, ServletException {

        // Parse the incoming request line
        input.readRequestLine(requestLine);//读取一行请求,这个方法在后面会详细讨论它
        
        // When the previous method returns, we're actually processing a
        // request
        status = Constants.PROCESSOR_ACTIVE;
        
        String method =
            new String(requestLine.method, 0, requestLine.methodEnd);//获得提交的方法
        String uri = null;//uri
        String protocol = new String(requestLine.protocol, 0,
                                     requestLine.protocolEnd);//获得提交的协议版本信息

        //System.out.println(" Method:" + method + "_ Uri:" + uri
        //                   + "_ Protocol:" + protocol);

        if (protocol.length() == 0)//如果协议版本长度为0,那么protocol设置为0.9
            protocol = "HTTP/0.9";

        // Now check if the connection should be kept alive after parsing the
        // request.
        if ( protocol.equals("HTTP/1.1") ) {//如果protocol为HTTP/1.1,那么将http11标志设置为true
            http11 = true;
            sendAck = false;
        } else {
            http11 = false;
            sendAck = false;
            // For HTTP/1.0, connection are not persistent by default,
            // unless specified with a Connection: Keep-Alive header.
            keepAlive = false;//非HTTP/1.1不支持持久性连接
        }

        // Validate the incoming request line
        if (method.length() < 1) {
            throw new ServletException
                (sm.getString("httpProcessor.parseRequest.method"));
        } else if (requestLine.uriEnd < 1) {
            throw new ServletException
                (sm.getString("httpProcessor.parseRequest.uri"));
        }

        // Parse any query parameters out of the request URI
        //HttpProcess类的process()方法会调用私有方法parseRequest()方法来解析请求行,即HTTP请求的第1行内容。例如一个HTTP请求行的实例:
        //GET /myApp/Modernservlet?userName=tarzan&password=pwd HTTP/1.1
        //请求行的第2部分是URL加上一个可选的查询字符串。在这个例子是,URL是:
        //   /myApp/Modernservlet
        //问号后面的部分就是查询字符串,如下所示: userName=tarzan&password=pwd ----------这些都是从表单提交过来的
        int question = requestLine.indexOf("?");//定位到?的位置
        if (question >= 0) {
            request.setQueryString
                (new String(requestLine.uri, question + 1,
                            requestLine.uriEnd - question - 1));//获取查询字符串
            if (debug >= 1)
                log(" Query string is " +
                    ((HttpServletRequest) request.getRequest())
                    .getQueryString());
            uri = new String(requestLine.uri, 0, question);//设置uri
        } else {
            request.setQueryString(null);//没有查询字符串则置空
            uri = new String(requestLine.uri, 0, requestLine.uriEnd);//设置uri
        }

        // Checking for an absolute URI (with the HTTP protocol)
        //还有一种以   http://www.brainysoftware.com/index.html?name=Tarzan的这种请求方式
        if (!uri.startsWith("/")) {
            int pos = uri.indexOf("://");//获得://中":"的位置
            // Parsing out protocol and host name
            if (pos != -1) {
                pos = uri.indexOf('/', pos + 3);//执行完这一步获得符号"/"的位置
                if (pos == -1) {//如果pos==-1
                    uri = "";//uri设置为空
                } else {
                    uri = uri.substring(pos);//否则uri此时变为http://www.brainsoftware.com/
                }
            }
        }

        // Parse any requested session ID out of the request URI
        //然后,查询字符串可能也会报行一个会话标识符,参数名为jessionid。因此,parseRequest()方法还要检查是否包含会话标识符,若在查询字符串中包含jessionid,
        //则parseRequest()方法要获取jsessionid的值,并调用HttpRequest类的setRequestedSessionId()方法来填充HttpRequest实例
        //match = ";jsessionid="
        int semicolon = uri.indexOf(match);//匹配该字符串
        if (semicolon >= 0) {//如果匹配成功
            String rest = uri.substring(semicolon + match.length());//将提取出字符串中包含jsessionid的那一段字符串
            int semicolon2 = rest.indexOf(';');
            if (semicolon2 >= 0) {
                request.setRequestedSessionId(rest.substring(0, semicolon2));//设置session的ID
                rest = rest.substring(semicolon2);//提取sessionId后面的字符串
            } else {
                request.setRequestedSessionId(rest);//sessionId后面没有带其他字符串那么直接将rest赋值给seesionId
                rest = "";
            }
            request.setRequestedSessionURL(true);
            uri = uri.substring(0, semicolon) + rest;//设置uri
            if (debug >= 1)
                log(" Requested URL session id is " +
                    ((HttpServletRequest) request.getRequest())
                    .getRequestedSessionId());
        } else {
            request.setRequestedSessionId(null);//如果没有session,则ID设置为空
            request.setRequestedSessionURL(false);//表示木有session
        }

        // Normalize URI (using String operations at the moment)
        将字符串进行拨乱反正。例如,出现"\"的地方会被替换为"/"。若URI本身是正常的,或不正常的地方可以修正,则normalize()方法
        //会返回相同的URI或修正过的URI。若URI无法修正,则会认为它是无效的。normalize()方法返回null。在这种情况下(normalize()方法返回null),parseRequest()
        //方法会在方法的末尾抛出异常
        String normalizedUri = normalize(uri);
        if (debug >= 1)
            log("Normalized: '" + uri + "' to '" + normalizedUri + "'");

        // Set the corresponding request properties
        ((HttpRequest) request).setMethod(method);//填充获取到的方法
        request.setProtocol(protocol);//填充获取的到的协议版本
        if (normalizedUri != null) {
            ((HttpRequest) request).setRequestURI(normalizedUri);//填充URI
        } else {
            ((HttpRequest) request).setRequestURI(uri);
        }
        request.setSecure(connector.getSecure());//填充连接器的安全信息
        request.setScheme(connector.getScheme());//填充连接器的版本

        if (normalizedUri == null) {
            log(" Invalid request URI: '" + uri + "'");
            throw new ServletException("Invalid URI: " + uri + "'");
        }

        if (debug >= 1)
            log(" Request is '" + method + "' for '" + uri +
                "' with protocol '" + protocol + "'");

    }
接下来就是苦力活的readRequestLine()还有normalize()方法,请看下一节的分析.........
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值