TrafficServer 是Apache基金會的 HTTP/HTTP2 代理伺服器。
TrafficServer 的 HTTP2 部分主要的代碼在 :
- trafficserver/proxy/http2/HTTP2.h, HTTP2.cc
- trafficserver/proxy/http2/Http2Stream.h, Http2Stream.cc
- trafficserver/proxy/http2/Http2ClientSession.h, Http2ClientSession.cc
- trafficserver/proxy/http2/Http2ConnectionState.h, Http2ConnectionState.cc
- trafficserver/proxy/http2/ Http2DependencyTree.h, Http2DependencyTree.cc
- trafficserver/proxy/http2/HPACK.h, HPACK.cc
- trafficserver/proxy/http2/HuffmanCodec.h, HuffmanCodec.cc
1. trafficserver/proxy/http2/HTTP2.h, HTTP2.cc
10種Frame 的struct定義,解析/序列化函數,HeaderList轉換函數,一些常量定義
2. trafficserver/proxy/http2/Http2ClientSession.h, Http2ClientSession.cc
Http2ClientSession 處理 io event 事件,解析 FrameHeader,
調用順序:
1 2 3 4 5 6 7 8 9 10 11 12 | Http2ClientSession::main_event_handler() --> state_read_connection_preface() --> state_start_frame_read() --> state_process_frame_read() 解析出一個完整的Frame --> do_complete_frame_read() --> Http2ConnectionState::main_event_handler(HTTP2_SESSION_EVENT_RECV ) |
---|
3. trafficserver/proxy/http2/Http2ConnectionState.h, Http2ConnectionState.cc
Http2ConnectionState,對應一個 HTTP2 連接配接,代碼基本等價于 proxygen 的 HTTPSession,主要的成員變量:
1 2 3 4 5 6 7 8 9 10 11 | { 雙連結清單<Http2Stream> //略挫,有個find_stream 用的周遊,改map好點。 Http2ClientSession, HpackHandle 2個, DependencyTree, Http2ConnectionSettingsclient_settings server_settings,連接配接的幾個 Settings 配置項,一個int數組 } |
---|
主要的方法:各個 rcv_xxx_frame() 和 send_xxx_frame(0 Http2ConnectionState::main_event_handler(HTTP2_SESSION_EVENT_RECV )裡面,解析輸入的各種 Frame
- rcv_data_frame, // HTTP2_FRAME_TYPE_DATA
- rcv_headers_frame, // HTTP2_FRAME_TYPE_HEADERS
- rcv_priority_frame, // HTTP2_FRAME_TYPE_PRIORITY
- rcv_rst_stream_frame, // HTTP2_FRAME_TYPE_RST_STREAM
- rcv_settings_frame, // HTTP2_FRAME_TYPE_SETTINGS
- rcv_push_promise_frame, // HTTP2_FRAME_TYPE_PUSH_PROMISE
- rcv_ping_frame, // HTTP2_FRAME_TYPE_PING
- rcv_goaway_frame, // HTTP2_FRAME_TYPE_GOAWAY
- rcv_window_update_frame, // HTTP2_FRAME_TYPE_WINDOW_UPDATE
- rcv_continuation_frame, // HTTP2_FRAME_TYPE_CONTINUATION
還有發送各類 frame 的接口,send_data_frames()/send_headers_frame() / send_push_promise_frame() / send_rst_stream_frame() 等。
具體地:
rcv_data_frame :
find_stream,然後檢查stream的state是不是OPEN/HALF_CLOSE_LOCAL,去除 padding,處理END_STREAM flag,檢查本端流量控制 window_size ,儲存buffer,更新本地的window,發回 Connection 和 Stream Level 的WindowUpdate Frame。
rcv_headers_frame:
find_stream/create_stream,處理padding,處理PRIORITY flag添加到 PriorityTree 裡面,如果 Header Block 結束了(即有END_HEADERS FLAG),那就http2_decode_header_blocks() 做HPACK 解壓縮,調用 Http2Stream 處了解析出的HeaderList
rcv_priority_frame:
find_stream,reprioritize,重新調整樹。
rcv_rst_stream_frame
rcv_settings_frame:
parse檢查收到的各個配置項,更新到client_settings中,并發送SETTINGS_ACK
rcv_push_promise_frame 等
包括 rcv_ping_frame
rcv_goaway_frame:
rcv_window_update_frame
比較簡單,略。
rcv_continuation_frame
類似 rcv_headers_frame
send_data_frames_depends_on_priority
取了 DependencyTree的top(),
send_data_frames 等
send_a_data_frame
send_headers_frame
send_push_promise_frame
send_rst_stream_frame
send_settings_frame
send_ping_frame
send_goaway_frame
send_window_update_frame
比較簡單,就是檢查字段合法性,序列化,然後發送。
4. trafficserver/proxy/http2/Http2Stream.h, Http2Stream.cc
對應實作HTTP2 的Stream,重要的成員變量有:
Http2StreamState _state;//實作IDLE,OPEN,RESERVED,HALF_CLOSE等的切換。
DependencyTree::Node *priority_node;// Priority Tree中的節點指針。
5. trafficserver/proxy/http2/Http2DependencyTree.h, Http2DependencyTree.cc
Http2DependencyTree::Node 表示一個Stream,成員變量有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { bool actived; //是否有輸出資料 bool queued; //是否在 actived 隊列中 uint32_t id; uint32_t weight; uint32_t point; //queue中的節點按照這個 point 做優先級排序 Node *parent; //父節點 DLL<Node> children; //子節點的雙清單 PriorityQueueEntry<Node *> *entry; // PriorityQueue<Node *> *queue; //有輸出資料的所有子節點的隊列,按point 優先級降序排列 Http2Stream *t; } |
---|
Http2DependencyTree 中有個 Node * root 指向 樹的根節點。
Http2DependencyTree的主要方法有:
-
Node *find(uint32_t id);
DFS 遞歸周遊樹,查找一個Stream。
- Node *add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T t); 就是插入 parent 的 children 連結清單中,兼做 exclusive 處理。
- void remove(Node *node); 從parent 的 queue 中移除自己,把自己的 queue 全轉給 parent,把自己的 children 全轉給 parent
- void reprioritize(uint32_t new_parent_id, uint32_t id, bool exclusive); 重排優先級,就是移動節點
- Node *top(); 傳回整個樹中,point 最高的葉子節點。遞歸實作。
- void activate(Node *node); 往上周遊,如果目前節點沒有 在 parent 的 queue中,加入
- void deactivate(Node *node, uint32_t sent); 從parent 的queue中去除自己。
- void update(Node *node, uint32_t sent);
這裡使用 Weighted Fair Queue (WFQ) Scheduling 來排程 Stream 之間的優先級。
Http2ConnectionState::send_data_frames_depends_on_priority() 中,是直接取了 樹的 top() 節點,
6. trafficserver/proxy/http2/HPACK.h, HPACK.cc
實作 HPACK 壓縮/解壓縮
7. trafficserver/proxy/http2/HuffmanCodec.h, HuffmanCodec.cc
實作靜态的 Huffman 表,接口簡單,隻有4個函數,,
是實作成 二叉樹,相比proxygen估計效率會低一些。