Tomcat源码7

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

            if (pos >= count) {
                // 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);

    }
下面就来看看如何解析头部了。。。。。。。。。。。。。。。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值