InternalInputBuffer處理HTTP請求行-Tomcat源碼-我們到底能走多遠系列(11)Tomcat StringManager閱讀學習

來源:互聯網
上載者:User
我們到底能走多遠系列(11)

扯淡:

  最近行情不好嗎?跳槽的比較少嘛,哈哈。有些人一直抗拒跳槽,覺得弊端很多:什麼業務積累,職務,別人覺得你不可靠啊等等。我就想:這一輩子時間有限,何必為了一顆可以乘涼的樹,放棄穿過森林的機會呢?祝在跳槽路上的朋友 順利!(ps:個人喜歡面試 那種刺激感)

  最爽不顧躺著,最美不過夕陽。秋天的夕陽是一年中最華麗的,各位不要錯過哦。

主題:

  在tomcat中,一個http請求,會被送到Http11Processor類,執行這個類的process(Socket theSocket) 處理的傳入的Socket,Socket裡面裝的就是http訊息。

  tomcat是如何調用到Http11Processor的process方法的,可以參照:http://blog.csdn.net/woorh/article/details/8017323

  Http11Processor在org.apache.coyote.http11包下。

  Http11Processor的rocess方法中,用inputBuffer.parseRequestLine();調用瞭解析http訊息的請求行。這裡的inputBuffer是tomcat自訂的InternalInputBuffer。

  需要瞭解的是:

  1,org.apache.coyote.Request 是tomcat內部使用用於存放關於request訊息的資料結構

  2,org.apache.tomcat.util.buf.MessageBytes 用於存放訊息,在org.apache.coyote.Request中大量用於存放解析後的byte字元

  3,org.apache.tomcat.util.buf.ByteChunk 真正用於存放資料的資料結構,存放的是byte[],org.apache.tomcat.util.buf.MessageBytes使用它。

  大流程:

  http訊息通過inputBuffer解析後放到Request中,Request把它放到相應的MessageBytes,最後MessageBytes把它存到ByteChunk裡。

  以上都可以通過方法調用來完成流程。

  主要關注的是解析的原始碼,在查看原始碼前需要瞭解http請求行的結構:可以參照:http://www.cnblogs.com/killbug/archive/2012/10/10/2719142.html

  閱讀前準備

  1,方法中全部的異常時,會調用getString方法,其實就是StringManager的寫日誌方法,這是tomcat中統一的管理日誌的方法。詳細的解釋在前一篇中已經幾時過了:Tomcat StringManager閱讀學習

  2,

逸出字元 意義 ASCII碼值(十進位)
\a 響鈴(BEL) 007
\b 退格(BS) ,將當前位置移到前一列 008
\f 換頁(FF),將當前位置移到下頁開頭 012
\n 換行(LF) ,將當前位置移到下一行開頭 010
\r 斷行符號(CR) ,將當前位置移到本行開頭 013
\t 水平製表(HT) (跳到下一個TAB位置) 009
\v 垂直製表(VT) 011
\\ 代表一個反斜線字元''\' 092

源碼:

  

public void parseRequestLine()        throws IOException {        int start = 0;        //        // Skipping blank lines        // 忽略空行        //        byte chr = 0;        do {            // Read new bytes if needed            if (pos >= lastValid) {                if (!fill())                    throw new EOFException(sm.getString("iib.eof.error"));            }            chr = buf[pos++];        } while ((chr == Constants.CR) || (chr == Constants.LF));        pos--;        // Mark the current buffer position        start = pos;        //        // Reading the method name        // Method name is always US-ASCII        //        // space類似於開關一樣,當為false時,查內容,為true時,去除空行時間        boolean space = false;        while (!space) {            // Read new bytes if needed            if (pos >= lastValid) {                if (!fill())                    throw new EOFException(sm.getString("iib.eof.error"));            }            // Spec says no CR or LF in method name            if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) {                throw new IllegalArgumentException(                        sm.getString("iib.invalidmethod"));            }            // Spec says single SP but it also says be tolerant of HT            // 查出第一個空格,tab居然也是允許的            if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {                space = true;//跳出迴圈                // 把下標記錄下來,這裡的method()得到一個Requast的MessageBytes:methodMB                request.method().setBytes(buf, start, pos - start);            }            pos++;        }                // Spec says single SP but also says be tolerant of multiple and/or HT        // 忽略空格後面的空格或者tab,因為是忽略的內容所以不需要什麼start        while (space) {            // Read new bytes if needed            if (pos >= lastValid) {                if (!fill())                    throw new EOFException(sm.getString("iib.eof.error"));            }            if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {                pos++;// 忽略的方式就是繼續移動下標            } else {                space = false;            }        }        // Mark the current buffer position        start = pos; // 出現start了,後面肯定是需要記錄下標        int end = 0;        int questionPos = -1;        //        // Reading the URI        // 上面是源碼的注釋,URI是什嗎?你懂的        //        boolean eol = false;        while (!space) {            // Read new bytes if needed            if (pos >= lastValid) {                if (!fill())                    throw new EOFException(sm.getString("iib.eof.error"));            }            // Spec says single SP but it also says be tolerant of HT            // 尋找第二個空格,第一個空格和第二個空格之間就是傳說中的URI            if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {                space = true;                end = pos;            } else if ((buf[pos] == Constants.CR)                        || (buf[pos] == Constants.LF)) {                // HTTP/0.9 style request                // 為了相容HTTP/0.9格式                eol = true;                space = true;                end = pos;            } else if ((buf[pos] == Constants.QUESTION) // 遇到‘?’了                       && (questionPos == -1)) {                // 把問號的位置先記錄下來                questionPos = pos;            }            pos++;        }        // 把可能包含問號的URI的起始位和結束位記錄下來        request.unparsedURI().setBytes(buf, start, end - start);        if (questionPos >= 0) {// 有問號的情況            // 問號位置記錄            request.queryString().setBytes(buf, questionPos + 1,                                            end - questionPos - 1);            // 把URI記錄下來            request.requestURI().setBytes(buf, start, questionPos - start);        } else {            request.requestURI().setBytes(buf, start, end - start);        }        // Spec says single SP but also says be tolerant of multiple and/or HT        // 這段算是重複代碼吧,就是忽略空格用和tab用的        while (space) {            // Read new bytes if needed            if (pos >= lastValid) {                if (!fill())                    throw new EOFException(sm.getString("iib.eof.error"));            }            if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {                pos++;            } else {                space = false;            }        }        // Mark the current buffer position        start = pos;        end = 0;        //        // Reading the protocol        // Protocol is always US-ASCII        //        // eol標誌位是為了標記是否是HTTP/0.9 style request 前面代碼已經提到        // 最後一樣:protocol(HTTP/ 1.1或1.0)        while (!eol) {            // Read new bytes if needed            if (pos >= lastValid) {                if (!fill())                    throw new EOFException(sm.getString("iib.eof.error"));            }            // 查出  /r/n(CRLF)            if (buf[pos] == Constants.CR) {                end = pos;            } else if (buf[pos] == Constants.LF) {                if (end == 0)                    end = pos;                eol = true;            }            pos++;        }        // 至此把head分成三部分,放到Request定義好的MessageBytes中去了        if ((end - start) > 0) {            request.protocol().setBytes(buf, start, end - start);        } else {            request.protocol().setString("");        }    }

總結習點:

  1,利用表示位來控制解析式每個while的功能,上面代碼用的是space

  2,不用截斷的方式儲存需要的內容,而是記錄開始和結束的下標。

 

 

讓我們繼續前行

 

----------------------------------------------------------------------

 

努力不一定成功,但不努力肯定不會成功。
共勉

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.