NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
http2_protocol.hpp
浏览该文件的文档.
1#ifndef NEFORCE_NETWORK_HTTP_HTTP2_PROTOCOL_HPP__
2#define NEFORCE_NETWORK_HTTP_HTTP2_PROTOCOL_HPP__
3
11
15NEFORCE_BEGIN_NAMESPACE__
16NEFORCE_BEGIN_HTTP__
17
22
24NEFORCE_INLINE17 constexpr uint32_t HTTP2_MAX_FRAME_SIZE = 16384;
26NEFORCE_INLINE17 constexpr uint32_t HTTP2_DEFAULT_HEADER_TABLE_SIZE = 4096;
28NEFORCE_INLINE17 constexpr uint32_t HTTP2_DEFAULT_MAX_CONCURRENT_STREAMS = 100;
30NEFORCE_INLINE17 constexpr uint32_t HTTP2_DEFAULT_INITIAL_WINDOW_SIZE = 65535;
32NEFORCE_INLINE17 constexpr uint32_t HTTP2_DEFAULT_MAX_HEADER_LIST_SIZE = 0xFFFFFFFF;
34NEFORCE_INLINE17 constexpr size_t HPACK_STATIC_TABLE_SIZE = 61;
36NEFORCE_INLINE17 constexpr string_view HTTP2_CLIENT_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
37
38class byte_cursor;
39
44 DATA = 0x0,
45 HEADERS = 0x1,
46 PRIORITY = 0x2,
47 RST_STREAM = 0x3,
48 SETTINGS = 0x4,
50 PING = 0x6,
51 GOAWAY = 0x7,
54};
55
56#ifdef NO_ERROR
57# undef NO_ERROR
58#endif
59
79
91
92
102#pragma pack(push, 1)
113
114 NEFORCE_NODISCARD uint32_t get_length() const noexcept {
115 return (static_cast<uint32_t>(length_hi) << 16) | (static_cast<uint32_t>(length_mid) << 8) |
116 static_cast<uint32_t>(length_lo);
117 }
118
119 void set_length(uint32_t len) noexcept {
120 length_hi = static_cast<uint8_t>((len >> 16) & 0xFF);
121 length_mid = static_cast<uint8_t>((len >> 8) & 0xFF);
122 length_lo = static_cast<uint8_t>(len & 0xFF);
123 }
124
125 NEFORCE_NODISCARD uint32_t get_stream_id() const noexcept {
126 return (static_cast<uint32_t>(sid_r & 0x7F) << 24) | (static_cast<uint32_t>(sid_mid) << 16) |
127 (static_cast<uint32_t>(sid_lo1) << 8) | static_cast<uint32_t>(sid_lo0);
128 }
129
130 void set_stream_id(uint32_t id) noexcept {
131 sid_r = static_cast<uint8_t>((id >> 24) & 0x7F);
132 sid_mid = static_cast<uint8_t>((id >> 16) & 0xFF);
133 sid_lo1 = static_cast<uint8_t>((id >> 8) & 0xFF);
134 sid_lo0 = static_cast<uint8_t>(id & 0xFF);
135 }
136};
137#pragma pack(pop)
138
139
140NEFORCE_INLINE17 constexpr uint8_t HTTP2_FLAG_END_STREAM = 0x1;
141NEFORCE_INLINE17 constexpr uint8_t HTTP2_FLAG_END_HEADERS = 0x4;
142NEFORCE_INLINE17 constexpr uint8_t HTTP2_FLAG_PADDED = 0x8;
143NEFORCE_INLINE17 constexpr uint8_t HTTP2_FLAG_PRIORITY = 0x20;
144NEFORCE_INLINE17 constexpr uint8_t HTTP2_FLAG_ACK = 0x1;
145
153
162
172
185
193
201
207 bool ack = false;
208};
209
218
226
237
246
251 string name;
252 string value;
253};
254
255
263class NEFORCE_API hpack_encoder {
264private:
265 struct table_entry {
266 string name;
267 string value;
268 size_t name_len;
269 size_t value_len;
270 };
271
273 uint32_t max_table_size_;
275 uint32_t current_table_size_ = 0;
277 vector<table_entry> dynamic_table_;
278
279 void add_to_dynamic_table(const string& name, const string& value);
280 void evict_for_size(uint32_t needed);
281 NEFORCE_NODISCARD int32_t find_in_tables(const string& name, const string& value) const;
282 NEFORCE_NODISCARD int32_t find_name_in_tables(const string& name) const;
283
284public:
285 explicit hpack_encoder(uint32_t max_table_size = HTTP2_DEFAULT_HEADER_TABLE_SIZE);
286
287 byte_vector encode(const vector<hpack_header_field>& headers);
288
289 void set_max_table_size(uint32_t size);
290 NEFORCE_NODISCARD uint32_t max_table_size() const noexcept { return max_table_size_; }
291 NEFORCE_NODISCARD size_t table_size() const noexcept { return dynamic_table_.size(); }
292};
293
301class NEFORCE_API hpack_decoder {
302public:
304 using header_callback = function<void(const string& name, const string& value)>;
305
306private:
307 struct table_entry {
308 string name;
309 string value;
310 size_t name_len;
311 size_t value_len;
312 };
313
315 uint32_t max_table_size_;
317 uint32_t current_table_size_ = 0;
319 vector<table_entry> dynamic_table_;
320
321 void add_to_dynamic_table(const string& name, const string& value);
322 void evict_for_size(uint32_t needed);
323
324public:
325 explicit hpack_decoder(uint32_t max_table_size = HTTP2_DEFAULT_HEADER_TABLE_SIZE);
326
327 vector<hpack_header_field> decode(const byte_t* data, size_t len);
328 void set_max_table_size(uint32_t size);
329
330 void decode_incremental(byte_cursor& cur, header_callback cb);
331};
332
333
341class NEFORCE_API http2_framer {
342public:
343 using frame_callback =
344 function<void(http2_frame_type type, uint8_t flags, uint32_t stream_id, const byte_t* payload, size_t len)>;
345
346private:
348 byte_vector partial_buffer_;
350 size_t expected_length_ = 0;
352 http2_frame_header current_header_{};
354 bool reading_header_ = true;
355
356public:
357 static byte_vector encode_data_frame(const http2_data_frame& frame);
358 static byte_vector encode_headers_frame(const http2_headers_frame& frame);
359 static byte_vector encode_push_promise_frame(const http2_push_promise_frame& frame);
360 static byte_vector encode_rst_stream_frame(const http2_rst_stream_frame& frame);
361 static byte_vector encode_settings_frame(const http2_settings_frame& frame);
362 static byte_vector encode_ping_frame(const http2_ping_frame& frame);
363 static byte_vector encode_goaway_frame(const http2_goaway_frame& frame);
364 static byte_vector encode_window_update_frame(const http2_window_update_frame& frame);
365 static byte_vector encode_continuation_frame(const http2_continuation_frame& frame);
366
367 void decode_frames(const byte_t* data, size_t len, frame_callback cb);
368};
369
370
375 IDLE,
376 RESERVED_LOCAL,
377 RESERVED_REMOTE,
378 OPEN,
379 HALF_CLOSED_LOCAL,
380 HALF_CLOSED_REMOTE,
381 CLOSED,
382};
383
390class NEFORCE_API http2_stream {
391public:
392 explicit http2_stream(uint32_t stream_id);
393
394 NEFORCE_NODISCARD uint32_t id() const noexcept { return stream_id_; }
395 NEFORCE_NODISCARD http2_stream_state state() const noexcept { return state_; }
396
397 NEFORCE_NODISCARD bool can_send_headers() const;
398 NEFORCE_NODISCARD bool can_send_data() const;
399 NEFORCE_NODISCARD bool can_receive() const;
400 NEFORCE_NODISCARD bool is_closed() const noexcept { return state_ == http2_stream_state::CLOSED; }
401
402 void on_send_headers(bool end_stream);
403 void on_send_data(bool end_stream);
404 void on_receive_headers(bool end_stream);
405 void on_receive_data(bool end_stream);
406 void on_send_rst_stream();
407 void on_receive_rst_stream();
408 void close();
409
410 NEFORCE_NODISCARD uint32_t local_window() const noexcept { return local_window_; }
411 NEFORCE_NODISCARD uint32_t remote_window() const noexcept { return remote_window_; }
412 void consume_local_window(uint32_t amount);
413 void consume_remote_window(uint32_t amount);
414 void add_local_window(uint32_t amount);
415 void add_remote_window(uint32_t amount);
416
417private:
419 uint32_t stream_id_;
421 http2_stream_state state_ = http2_stream_state::IDLE;
426};
427
435class NEFORCE_API http2_flow_control {
436public:
437 explicit http2_flow_control(uint32_t initial_window = HTTP2_DEFAULT_INITIAL_WINDOW_SIZE);
438
439 void set_initial_window(uint32_t size);
440
441 NEFORCE_NODISCARD bool can_send(uint32_t stream_id, uint32_t amount) const;
442 void consume(uint32_t stream_id, uint32_t amount);
443 void add_window(uint32_t stream_id, uint32_t amount);
444 NEFORCE_NODISCARD uint32_t window(uint32_t stream_id) const;
445 NEFORCE_NODISCARD uint32_t connection_window() const noexcept { return connection_window_; }
446
447private:
449 uint32_t initial_window_;
451 uint32_t connection_window_;
453 unordered_map<uint32_t, uint32_t> stream_windows_;
454};
455
456
464class NEFORCE_API http2_settings {
465public:
466 http2_settings();
467
468 void set(http2_settings_id id, uint32_t value);
469 NEFORCE_NODISCARD uint32_t get(http2_settings_id id) const;
470
471 NEFORCE_NODISCARD uint32_t header_table_size() const;
472 NEFORCE_NODISCARD bool enable_push() const;
473 NEFORCE_NODISCARD uint32_t max_concurrent_streams() const;
474 NEFORCE_NODISCARD uint32_t initial_window_size() const;
475 NEFORCE_NODISCARD uint32_t max_frame_size() const;
476 NEFORCE_NODISCARD uint32_t max_header_list_size() const;
477
478 void apply_remote_settings(const http2_settings_frame& frame);
479
480 static http2_settings defaults() { return {}; }
481
482private:
485};
486 // HTTP
488
489NEFORCE_END_HTTP__
490NEFORCE_END_NAMESPACE__
491#endif // NEFORCE_NETWORK_HTTP_HTTP2_PROTOCOL_HPP__
函数包装器主模板声明
带边界检查的字节游标,用于协议解析
HPACK 头部解码器(RFC 7541)
function< void(const string &name, const string &value)> header_callback
解码回调:void(const string& name, const string& value)
动态大小数组容器
通用函数包装器
vector< byte_t > byte_vector
字节向量类型别名
unsigned char byte_t
字节类型,定义为无符号字符
unsigned int uint32_t
32位无符号整数类型
unsigned long uint64_t
64位无符号整数类型
unsigned char uint8_t
8位无符号整数类型
int int32_t
32位有符号整数类型
unsigned short uint16_t
16位无符号整数类型
constexpr uint32_t HTTP2_MAX_FRAME_SIZE
HTTP/2 最大帧负载大小(RFC 7540 §4.1)
constexpr uint32_t HTTP2_DEFAULT_INITIAL_WINDOW_SIZE
默认初始流控窗口
constexpr string_view HTTP2_CLIENT_PREFACE
HTTP/2 客户端连接前言(RFC 7540 §3.5)
http2_settings_id
HTTP/2 SETTINGS 参数标识符(RFC 7540 §6.5.2)
http2_stream_state
HTTP/2 流状态(RFC 7540 §5.1)
constexpr size_t HPACK_STATIC_TABLE_SIZE
HPACK 静态表条目数
http2_frame_type
HTTP/2 帧类型(RFC 7540 §6)
constexpr uint32_t HTTP2_DEFAULT_MAX_CONCURRENT_STREAMS
默认最大并发流数
http2_error
HTTP/2 错误码(RFC 7540 §7)
constexpr uint32_t HTTP2_DEFAULT_MAX_HEADER_LIST_SIZE
默认最大头部列表大小
constexpr uint32_t HTTP2_DEFAULT_HEADER_TABLE_SIZE
HPACK 默认动态表大小
@ ENABLE_PUSH
是否启用服务端推送
@ MAX_HEADER_LIST_SIZE
最大头部列表大小
@ HEADER_TABLE_SIZE
HPACK 动态表最大大小
@ INITIAL_WINDOW_SIZE
流级初始窗口大小
@ SETTINGS_TIMEOUT
SETTINGS 确认超时
basic_string_view< char > string_view
字符字符串视图
constexpr decltype(auto) size(const Container &cont) noexcept(noexcept(cont.size()))
获取容器的大小
constexpr decltype(auto) data(Container &cont) noexcept(noexcept(cont.data()))
获取容器的底层数据指针
字符串类型别名和实用函数
HPACK 头部字段(名值对)
string name
头部名称(小写)
CONTINUATION 帧(RFC 7540 §6.10)
byte_vector header_block
HPACK 编码的续帧头部块
HTTP/2 帧头(RFC 7540 §4.1),9 字节 packed 布局
uint8_t sid_r
R(1) | StreamID[30:24]
GOAWAY 帧(RFC 7540 §6.8)
uint32_t last_stream_id
最后处理的流 ID
HEADERS 帧(RFC 7540 §6.2)
byte_vector header_block
HPACK 编码的头部块
http2_priority priority
优先级信息
uint64_t opaque_data
不透明数据(回显)
流优先级信息(RFC 7540 §5.3)
bool exclusive
是否为独占依赖
uint32_t stream_dependency
依赖的流 ID(0 表示根)
PUSH_PROMISE 帧(RFC 7540 §6.6)
uint32_t promised_stream_id
服务器承诺的新流 ID(必须为偶数)
uint32_t stream_id
关联的流 ID(父流)
RST_STREAM 帧(RFC 7540 §6.4)
SETTINGS 帧中的单个参数条目
uint32_t value
参数值
http2_settings_id id
参数标识符
SETTINGS 帧(RFC 7540 §6.5)
vector< http2_settings_entry > entries
设置参数列表
WINDOW_UPDATE 帧(RFC 7540 §6.9)
uint32_t stream_id
流 ID(0 表示连接级)
无序映射容器