17void wr32(uint8_t *p, uint32_t v)
19 p[0] = (uint8_t)(v >> 24);
20 p[1] = (uint8_t)(v >> 16);
21 p[2] = (uint8_t)(v >> 8);
24uint32_t rd32(
const uint8_t *p)
26 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
30bool h2_parse_header(
const uint8_t *buf,
size_t len, H2FrameHeader *out)
32 if (len < H2_FRAME_HEADER_LEN)
34 out->length = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | buf[2];
37 out->stream_id = ((uint32_t)(buf[5] & 0x7f) << 24) | ((uint32_t)buf[6] << 16) | ((uint32_t)buf[7] << 8) |
42size_t h2_write_header(uint8_t *out,
size_t cap, uint32_t length, uint8_t type, uint8_t flags, uint32_t stream_id)
44 if (cap < H2_FRAME_HEADER_LEN || length > 0xFFFFFF)
46 out[0] = (uint8_t)(length >> 16);
47 out[1] = (uint8_t)(length >> 8);
48 out[2] = (uint8_t)length;
51 out[5] = (uint8_t)((stream_id >> 24) & 0x7f);
52 out[6] = (uint8_t)(stream_id >> 16);
53 out[7] = (uint8_t)(stream_id >> 8);
54 out[8] = (uint8_t)stream_id;
55 return H2_FRAME_HEADER_LEN;
58void h2_settings_defaults(H2Settings *s)
60 s->header_table_size = 4096;
62 s->max_concurrent_streams = 0xFFFFFFFFu;
63 s->initial_window_size = 65535;
64 s->max_frame_size = 16384;
65 s->max_header_list_size = 0xFFFFFFFFu;
68bool h2_parse_settings(
const uint8_t *payload,
size_t len, H2Settings *s)
72 for (
size_t i = 0; i < len; i += 6)
74 uint16_t
id = (uint16_t)(((uint16_t)payload[i] << 8) | payload[i + 1]);
75 uint32_t val = rd32(payload + i + 2);
78 case H2Setting::H2_SETTINGS_HEADER_TABLE_SIZE:
79 s->header_table_size = val;
81 case H2Setting::H2_SETTINGS_ENABLE_PUSH:
86 case H2Setting::H2_SETTINGS_MAX_CONCURRENT_STREAMS:
87 s->max_concurrent_streams = val;
89 case H2Setting::H2_SETTINGS_INITIAL_WINDOW_SIZE:
92 s->initial_window_size = val;
94 case H2Setting::H2_SETTINGS_MAX_FRAME_SIZE:
95 if (val < 16384 || val > 16777215)
97 s->max_frame_size = val;
99 case H2Setting::H2_SETTINGS_MAX_HEADER_LIST_SIZE:
100 s->max_header_list_size = val;
109size_t h2_build_settings(uint8_t *out,
size_t cap,
const uint16_t *ids,
const uint32_t *vals,
size_t n)
111 size_t payload = n * 6;
112 if (cap < H2_FRAME_HEADER_LEN + payload)
114 h2_write_header(out, cap, (uint32_t)payload, H2FrameType::H2_SETTINGS, 0, 0);
115 uint8_t *p = out + H2_FRAME_HEADER_LEN;
116 for (
size_t i = 0; i < n; i++)
118 p[0] = (uint8_t)(ids[i] >> 8);
119 p[1] = (uint8_t)ids[i];
120 wr32(p + 2, vals[i]);
123 return H2_FRAME_HEADER_LEN + payload;
126size_t h2_build_settings_ack(uint8_t *out,
size_t cap)
128 return h2_write_header(out, cap, 0, H2FrameType::H2_SETTINGS, H2_FLAG_ACK, 0);
131size_t h2_build_window_update(uint8_t *out,
size_t cap, uint32_t stream_id, uint32_t increment)
133 if (cap < H2_FRAME_HEADER_LEN + 4)
135 h2_write_header(out, cap, 4, H2FrameType::H2_WINDOW_UPDATE, 0, stream_id);
136 wr32(out + H2_FRAME_HEADER_LEN, increment & 0x7FFFFFFF);
137 return H2_FRAME_HEADER_LEN + 4;
140size_t h2_build_rst_stream(uint8_t *out,
size_t cap, uint32_t stream_id, uint32_t error)
142 if (cap < H2_FRAME_HEADER_LEN + 4)
144 h2_write_header(out, cap, 4, H2FrameType::H2_RST_STREAM, 0, stream_id);
145 wr32(out + H2_FRAME_HEADER_LEN, error);
146 return H2_FRAME_HEADER_LEN + 4;
149size_t h2_build_goaway(uint8_t *out,
size_t cap, uint32_t last_stream_id, uint32_t error)
151 if (cap < H2_FRAME_HEADER_LEN + 8)
153 h2_write_header(out, cap, 8, H2FrameType::H2_GOAWAY, 0, 0);
154 wr32(out + H2_FRAME_HEADER_LEN, last_stream_id & 0x7FFFFFFF);
155 wr32(out + H2_FRAME_HEADER_LEN + 4, error);
156 return H2_FRAME_HEADER_LEN + 8;
159size_t h2_build_ping_ack(uint8_t *out,
size_t cap,
const uint8_t opaque[8])
161 if (cap < H2_FRAME_HEADER_LEN + 8)
163 h2_write_header(out, cap, 8, H2FrameType::H2_PING, H2_FLAG_ACK, 0);
164 memcpy(out + H2_FRAME_HEADER_LEN, opaque, 8);
165 return H2_FRAME_HEADER_LEN + 8;
168size_t h2_build_headers(uint8_t *out,
size_t cap, uint32_t stream_id,
const uint8_t *block,
size_t block_len,
171 if (cap < H2_FRAME_HEADER_LEN + block_len)
173 uint8_t flags = H2_FLAG_END_HEADERS | (end_stream ? H2_FLAG_END_STREAM : 0);
174 h2_write_header(out, cap, (uint32_t)block_len, H2FrameType::H2_HEADERS, flags, stream_id);
175 memcpy(out + H2_FRAME_HEADER_LEN, block, block_len);
176 return H2_FRAME_HEADER_LEN + block_len;
179size_t h2_build_data(uint8_t *out,
size_t cap, uint32_t stream_id,
const uint8_t *data,
size_t data_len,
182 if (cap < H2_FRAME_HEADER_LEN + data_len)
184 h2_write_header(out, cap, (uint32_t)data_len, H2FrameType::H2_DATA, end_stream ? H2_FLAG_END_STREAM : 0, stream_id);
186 memcpy(out + H2_FRAME_HEADER_LEN, data, data_len);
187 return H2_FRAME_HEADER_LEN + data_len;
HTTP/2 binary framing (RFC 9113 sec 4 + sec 6).