來源于公眾號(hào)方丈的寺院 ,
作者cnstonefang
摘要
作為服務(wù)端,web容器是如何解析http報(bào)文的呢?本文以jetty和undertow容器為例,來解析web容器是如何處理http報(bào)文的。
http報(bào)文其實(shí)就是一定規(guī)則的字符串,那么解析它們,就是解析字符串,看看是否滿足http協(xié)議約定的規(guī)則。
start-line: 起始行,描述請(qǐng)求或響應(yīng)的基本信息 *( header-field CRLF ): 頭 CRLF [message-body]: 消息body,實(shí)際傳輸?shù)臄?shù)據(jù)
jetty
以下代碼都是jetty9.4.12版本
如何解析這么長的字符串呢,jetty是通過狀態(tài)機(jī)來實(shí)現(xiàn)的。具體可以看下 org.eclipse.jetty.http.HttpParse類
總共分成了21種狀態(tài),然后進(jìn)行狀態(tài)間的流轉(zhuǎn)。在 parseNext方法中分別對(duì)起始行 -> header -> body content分別解析
整體流程
整體有三條路徑
- 開始 -> start-line -> header -> 結(jié)束
- 開始 -> start-line -> header -> content -> 結(jié)束
- 開始 -> start-line -> header -> chunk-content -> 結(jié)束
起始行
start-line = request-line(請(qǐng)求起始行)/(響應(yīng)起始行)status-line
請(qǐng)求報(bào)文解析狀態(tài)遷移 請(qǐng)求行:START -> METHOD -> SPACE1 -> URI -> SPACE2 -> REQUEST_VERSION
響應(yīng)報(bào)文解析狀態(tài)遷移 響應(yīng)行:START -> RESPONSE_VERSION -> SPACE1 -> STATUS -> SPACE2 -> REASON
header 頭
HEADER 的狀態(tài)只有一種了,在jetty的老版本中還區(qū)分了 HEADER_IN_NAM, HEADER_VALUE, HEADER_IN_VALUE等,9.4中都去除了。為了提高匹配效率,jetty使用了Trie樹快速匹配header頭。
content
請(qǐng)求體:
- CONTENT -> END,這種是普通的帶Content-Length頭的報(bào)文,HttpParser一直運(yùn)行CONTENT狀態(tài),直到最后ContentLength達(dá)到了指定的數(shù)量,則進(jìn)入END狀態(tài)
- chunked分塊傳輸?shù)臄?shù)據(jù) CHUNKEDCONTENT -> CHUNKSIZE -> CHUNK -> CHUNK_END -> END
undertow
undertow是另一種web容器,它的處理方式與jetty有什么不同呢 狀態(tài)機(jī)種類不一樣了, io.undertow.util.HttpString.ParseState
具體處理流程在 HttpRequestParser抽象類中
與jetty不同的是對(duì)content的處理,在header處理完以后,將數(shù)據(jù)放到 io.undertow.server.HttpServerExchange,然后根據(jù)類型,有不同的content讀取方式,比如處理固定長度的, FixedLengthStreamSourceConduit。