http報文結構
start-line: 起始行,描述請求或響應的基本信息
*( header-field CRLF ): 頭
CRLF
[message-body]: 消息body,實際傳輸的數據
狀態機
jetty通過狀態機解析這些字符串。具體看org.eclipse.jetty.http.HttpParse類
public enum State
{
START,
METHOD,
SPACE1,
STATUS,
URI,
SPACE2,
REQUEST_VERSION,
REASON,
PROXY,
HEADER,
CONTENT,
EOF_CONTENT,
CHUNKED_CONTENT,
CHUNK_SIZE,
CHUNK_PARAMS,
CHUNK,
TRAILER,
END,
CLOSE,
CLOSED
}
總共分成了21種狀態,然后進行狀態間的流轉。在parseNext方法中分別對起始行 -> header -> body content分別解析
public boolean parseNext(ByteBuffer buffer)
{
……
// Start a request/response
if (_state==State.START)
{
// 快速判斷
if (quickStart(buffer))
return true;
}
// Request/response line 轉換
if (_state.ordinal()>= State.START.ordinal() && _state.ordinal()<State.HEADER.ordinal())
{
if (parseLine(buffer))
return true;
}
// headers轉換
if (_state== State.HEADER)
{
if (parseFields(buffer))
return true;
}
// content轉換
if (_state.ordinal()>= State.CONTENT.ordinal() && _state.ordinal()<State.TRAILER.ordinal())
{
// Handle HEAD response
if (_responseStatus>0 && _headResponse)
{
setState(State.END);
return handleContentMessage();
}
else
{
if (parseContent(buffer))
return true;
}
}
return false;
}
整體流程
有三條路徑
1、開始 -> start-line -> header -> 結束
2、開始 -> start-line -> header -> content -> 結束
3、開始 -> start-line -> header -> chunk-content -> 結束
起始行
start-line = request-line(請求起始行)/(響應起始行)status-line
1、請求報文解析狀態遷移 請求行:START -> METHOD -> SPACE1 -> URI -> SPACE2 -> REQUEST_VERSION
2、響應報文解析狀態遷移 響應行:START -> RESPONSE_VERSION -> SPACE1 -> STATUS -> SPACE2 -> REASON
header 頭
HEADER 的狀態只有一種了,在jetty的老版本中還區分了HEADER_IN_NAM, HEADER_VALUE, HEADER_IN_VALUE等,新版本中去除了。為了提高匹配效率,jetty使用了Trie樹快速匹配header頭。
static
{
CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE));
CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE));
// 以下省略了很多了通用header頭
content
請求體:
1、CONTENT -> END,這種是普通的帶Content-Length頭的報文,HttpParser一直運行CONTENT狀態,直到最后ContentLength達到了指定的數量,則進入END狀態
2、chunked分塊傳輸的數據 CHUNKED_CONTENT -> CHUNK_SIZE -> CHUNK -> CHUNK_END -> END