Coyote for Http11: org.apache.coyote.http11
概述
這個包支援http1.1協議,內部分為三類:ARP、NIO、普通http,這裡只對最基本的普通http(使用java的IO流,而非NIO流)作簡單研究
根據上一篇提到的coyote的介面,這個包主要有以下幾個類:
- Http11Protocol,實現了ProtocolHandler介面
- Http11Processor,實現了ActionHook介面
- InternalInputBuffer,實現了InputBuffer介面
- InternalOutputBuffer,實現了OutputBuffer介面
- InputFilter和OutputFilter介面,具體的實現類在 org.apache.coyote.http11.filters 中
下面是這幾個類之間的關係,隨便畫了一幅圖,湊合著看看^_^
大致過程如下:
- JIOEndpoint起到一個連線池的作用,可以啟動多個socket監聽,一旦收到瀏覽器發來的請求後,把對應的socket物件通過process方法,傳遞給Http11ConnectionHandler,再交給Http11Processor
- Http11Processor內部有個InternalInputBuffer(圖上未畫出),InternalInputBuffer是真正對socket中包含的位元組流進行處理的,它將位元組轉換為Request
- Request流經過濾器filters,最後到達實現了Adapter介面的容器,coyote的工作就到此為止,回頭繼續處理下一個socket
下面是幾個主要類的功能介紹
Http11Protocol
http1.1協議的ProtocolHandler實現
主要包含
Http11ConnectionHandler(內部類)
JIoEndpoint
ServerSocketFactory(J2SE)
大致過程如下:
在init方法中,將ServerSocketFactory、Http11ConnectionHandler傳遞給JIoEndpoint進行初始化
然後,在start、pause等方法中,同樣也會呼叫JIoEndpoint的start、pause
JIoEndpoint可以設定最大執行緒數、優先順序、埠等屬性,根據這些屬性,JIoEndpoint生成對應數量的ServerSocketFactory,用於監聽相應的埠,一旦收到http請求,JIoEndpoint則將對應的Socket例項傳遞給Http11ConnectionHandler.process方法進行處理;而Http11ConnectionHandler裡頭會有一個processor例項,這個例項真正處理socket並將其中的資料轉換為Request物件
因此,ProtocolHandler的作用就是把所有這些和連線有關的元件包裝起來,統一設定它們的屬性,並負責控制它們的生命週期
Http11Processor
這個類的作用就是生成Request(當然本質上還是InternalInputBuffer完成的),交給實現了Adapter介面的容器
這個類有adapter、request、response、inputbuffer、outputbuffer等幾個關鍵欄位,其餘就是和http協議有關的欄位了,還有很多方法是關於http協議的,水平有限實在看不懂,估計要先詳細學習一遍http協議才能讀懂,這裡就略過,直接看最關鍵的process(Socket socket) 方法
該方法依次做如下的工作:
- 把socket的inputstream和outputstream分別與inputbuffer和outputbuffer關聯起來
- 通過inputBuffer.parseRequestLine() 和 inputBuffer.parseHeaders() 方法,解析socket位元組流中的頭欄位,寫到request中
- 通過prepareRequest方法組裝filter,用於處理http訊息體
- adapter.service(request, response) 把生成的request和response交給容器處理
- 如果一切順利,開始處理socket中的下一個請求(因為http1.1是支援持續連線的,所以一個socket中可能包含多個請求),迴圈回到第一步
- 如果出錯,則設定response的響應碼,並終止迴圈
prepareRequest方法,用於準備inputbuffer的filter,這裡簡單寫一下。關於filter的機理,請看:
- 根據之前對http頭欄位的解析,分別檢查protocol、method、expect、user-agent和MIMEheaders,此外還檢查URI的格式(是否符合:protocol://host:port/ 的格式)
- 準備載入filter
- 如果有transfer-encoding這個頭欄位(貌似是編碼格式,可以有多個,逗號分割),則分別設定不同編碼的filter
- 校驗content-length頭欄位
InternalInputBuffer
研究這個類可以從Http11Processor的process方法入手
這個類的主要功能是:從socket中獲取位元組流,將位元組讀入一個緩衝區buf,然後從緩衝區逐個解析http請求頭以及內容
主要的欄位:
- request:Request物件,從緩衝區中解析出的資訊會寫入request中
- buf:緩衝區,從socket的inputstream讀取的位元組放入此緩衝區中
- headers : MimeHeaders,儲存以鍵值對出現的報頭,也就是除去請求報文第一行之後的所有頭部
具體的http請求報頭的規範,可以參考W3C,或者
http://www.yuanma.org/data/2008/0827/article_3143.htm
parseRequestLine()
解析請求報頭的第一行,形如:GET http://class/download.microtool.de:80/somedata.exe,包括請求方法(GET or POST)、協議(http)、URI。解析後,放入request中
parseHeader()
解析剛才parseRequestLine()之後的報頭,由於RequestLine之後的報頭都是以“:”分隔的鍵值對,因此每執行一次本方法,則在headers 中加入一個鍵值對,如果格式錯誤則返回false
endRequest()
結束一個request的處理,把多餘的位元組清空
nextRequest()
準備下一個request的處理,這個方法主要用來對所有的標記位和指標進行復位
fill()
從socket的inputstream中讀出一定數量的位元組,填充buf,在很多方法中都有用到。例如解析報頭時,當發現buf已經讀取完了,就呼叫fill重新填充buf,如果inputstream已經讀完了,fill返回false
InternalOutputBuffer的一些疑問
根據inputbuffer的理解,可以大致猜到,這個類是用來從response中讀取資訊,然後寫入socket的outputstream中,返回給客戶端的
類裡面的方法許多也和inputbuffer一樣,但令人納悶的是居然還有nextRequest()、endRequest()方法,而裡面做的事情卻是針對response的(OutputBuffer本來就只有response),看不出任何與request有關的東西。難道是作者拷程式碼過來的時候忘了改方法名稱?
最後,覺得這個類和InternalInputBuffer實在有太多相似之處,為什麼不抽象出一個父類呢?
相關文章
- Http11: org.apache.coyote.http11HTTPApache
- org.apache.coyote.AbstractProtocol.destroy Failed to destroy end point associated with ProtocolHandlApacheProtocolAI
- org.apache.coyote.AbstractProtocol pauseTomcat程式意外退出的問題分析ApacheProtocolTomcat
- Rampant Coyote:闡述智慧財產權對獨立遊戲開發者的價值遊戲開發
- 指令碼啟動tomcat專案當機問題 org.apache.coyote.AbstractProtocol pause指令碼TomcatApacheProtocol