TrafficServer 是Apache基金会的 HTTP/HTTP2 代理服务器。
TrafficServer 的 HTTP2 部分主要的代码在 :
10种Frame 的struct定义,解析/序列化函数,HeaderList转换函数,一些常量定义
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 ) |
---|
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
还有发送各类 frame 的接口,send_data_frames()/send_headers_frame() / send_push_promise_frame() / send_rst_stream_frame() 等。
具体地:
find_stream,然后检查stream的state是不是OPEN/HALF_CLOSE_LOCAL,去除 padding,处理END_STREAM flag,检查本端流量控制 window_size ,保存buffer,更新本地的window,发回 Connection 和 Stream Level 的WindowUpdate Frame。
find_stream/create_stream,处理padding,处理PRIORITY flag添加到 PriorityTree 里面,如果 Header Block 结束了(即有END_HEADERS FLAG),那就http2_decode_header_blocks() 做HPACK 解压缩,调用 Http2Stream 处理解析出的HeaderList
find_stream,reprioritize,重新调整树。
parse检查收到的各个配置项,更新到client_settings中,并发送SETTINGS_ACK
包括 rcv_ping_frame
rcv_goaway_frame:
rcv_window_update_frame
比较简单,略。
类似 rcv_headers_frame
取了 DependencyTree的top(),
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
比较简单,就是检查字段合法性,序列化,然后发送。
对应实现HTTP2 的Stream,重要的成员变量有:
Http2StreamState _state;//实现IDLE,OPEN,RESERVED,HALF_CLOSE等的切换。
DependencyTree::Node *priority_node;// Priority Tree中的节点指针。
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的主要方法有:
这里使用 Weighted Fair Queue (WFQ) Scheduling 来调度 Stream 之间的优先级。
Http2ConnectionState::send_data_frames_depends_on_priority() 中,是直接取了 树的 top() 节点,
实现 HPACK 压缩/解压缩
实现静态的 Huffman 表,接口简单,只有4个函数,,
是实现成 二叉树,相比proxygen估计效率会低一些。