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 pc_h2_parse_header(
const uint8_t *buf,
size_t len, H2FrameHeader *out)
32 if (len < H2_FRAME_HEADER_LEN)
36 out->length = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | buf[2];
39 out->stream_id = ((uint32_t)(buf[5] & 0x7f) << 24) | ((uint32_t)buf[6] << 16) | ((uint32_t)buf[7] << 8) |
44size_t pc_h2_write_header(uint8_t *out,
size_t cap, uint32_t length, uint8_t type, uint8_t flags, uint32_t stream_id)
46 if (cap < H2_FRAME_HEADER_LEN || length > 0xFFFFFF)
50 out[0] = (uint8_t)(length >> 16);
51 out[1] = (uint8_t)(length >> 8);
52 out[2] = (uint8_t)length;
55 out[5] = (uint8_t)((stream_id >> 24) & 0x7f);
56 out[6] = (uint8_t)(stream_id >> 16);
57 out[7] = (uint8_t)(stream_id >> 8);
58 out[8] = (uint8_t)stream_id;
59 return H2_FRAME_HEADER_LEN;
62void pc_h2_settings_defaults(H2Settings *s)
64 s->header_table_size = 4096;
66 s->max_concurrent_streams = 0xFFFFFFFFu;
67 s->initial_window_size = 65535;
68 s->max_frame_size = 16384;
69 s->max_header_list_size = 0xFFFFFFFFu;
72bool pc_h2_parse_settings(
const uint8_t *payload,
size_t len, H2Settings *s)
78 for (
size_t i = 0; i < len; i += 6)
80 uint16_t
id = (uint16_t)(((uint16_t)payload[i] << 8) | payload[i + 1]);
81 uint32_t val = rd32(payload + i + 2);
84 case H2Setting::H2_SETTINGS_HEADER_TABLE_SIZE:
85 s->header_table_size = val;
87 case H2Setting::H2_SETTINGS_ENABLE_PUSH:
94 case H2Setting::H2_SETTINGS_MAX_CONCURRENT_STREAMS:
95 s->max_concurrent_streams = val;
97 case H2Setting::H2_SETTINGS_INITIAL_WINDOW_SIZE:
102 s->initial_window_size = val;
104 case H2Setting::H2_SETTINGS_MAX_FRAME_SIZE:
105 if (val < 16384 || val > 16777215)
109 s->max_frame_size = val;
111 case H2Setting::H2_SETTINGS_MAX_HEADER_LIST_SIZE:
112 s->max_header_list_size = val;
121size_t pc_h2_build_settings(uint8_t *out,
size_t cap,
const uint16_t *ids,
const uint32_t *vals,
size_t n)
123 size_t payload = n * 6;
124 if (cap < H2_FRAME_HEADER_LEN + payload)
128 pc_h2_write_header(out, cap, (uint32_t)payload, H2FrameType::H2_SETTINGS, 0, 0);
129 uint8_t *p = out + H2_FRAME_HEADER_LEN;
130 for (
size_t i = 0; i < n; i++)
132 p[0] = (uint8_t)(ids[i] >> 8);
133 p[1] = (uint8_t)ids[i];
134 wr32(p + 2, vals[i]);
137 return H2_FRAME_HEADER_LEN + payload;
140size_t pc_h2_build_settings_ack(uint8_t *out,
size_t cap)
142 return pc_h2_write_header(out, cap, 0, H2FrameType::H2_SETTINGS, H2_FLAG_ACK, 0);
145size_t pc_h2_build_window_update(uint8_t *out,
size_t cap, uint32_t stream_id, uint32_t increment)
147 if (cap < H2_FRAME_HEADER_LEN + 4)
151 pc_h2_write_header(out, cap, 4, H2FrameType::H2_WINDOW_UPDATE, 0, stream_id);
152 wr32(out + H2_FRAME_HEADER_LEN, increment & 0x7FFFFFFF);
153 return H2_FRAME_HEADER_LEN + 4;
156size_t pc_h2_build_rst_stream(uint8_t *out,
size_t cap, uint32_t stream_id, uint32_t error)
158 if (cap < H2_FRAME_HEADER_LEN + 4)
162 pc_h2_write_header(out, cap, 4, H2FrameType::H2_RST_STREAM, 0, stream_id);
163 wr32(out + H2_FRAME_HEADER_LEN, error);
164 return H2_FRAME_HEADER_LEN + 4;
167size_t pc_h2_build_goaway(uint8_t *out,
size_t cap, uint32_t last_stream_id, uint32_t error)
169 if (cap < H2_FRAME_HEADER_LEN + 8)
173 pc_h2_write_header(out, cap, 8, H2FrameType::H2_GOAWAY, 0, 0);
174 wr32(out + H2_FRAME_HEADER_LEN, last_stream_id & 0x7FFFFFFF);
175 wr32(out + H2_FRAME_HEADER_LEN + 4, error);
176 return H2_FRAME_HEADER_LEN + 8;
179size_t pc_h2_build_ping_ack(uint8_t *out,
size_t cap,
const uint8_t opaque[8])
181 if (cap < H2_FRAME_HEADER_LEN + 8)
185 pc_h2_write_header(out, cap, 8, H2FrameType::H2_PING, H2_FLAG_ACK, 0);
186 memcpy(out + H2_FRAME_HEADER_LEN, opaque, 8);
187 return H2_FRAME_HEADER_LEN + 8;
190size_t pc_h2_build_headers(uint8_t *out,
size_t cap, uint32_t stream_id,
const uint8_t *block,
size_t block_len,
193 if (cap < H2_FRAME_HEADER_LEN + block_len)
197 uint8_t flags = H2_FLAG_END_HEADERS | (end_stream ? H2_FLAG_END_STREAM : 0);
198 pc_h2_write_header(out, cap, (uint32_t)block_len, H2FrameType::H2_HEADERS, flags, stream_id);
199 memcpy(out + H2_FRAME_HEADER_LEN, block, block_len);
200 return H2_FRAME_HEADER_LEN + block_len;
203size_t pc_h2_build_data(uint8_t *out,
size_t cap, uint32_t stream_id,
const uint8_t *data,
size_t data_len,
206 if (cap < H2_FRAME_HEADER_LEN + data_len)
210 pc_h2_write_header(out, cap, (uint32_t)data_len, H2FrameType::H2_DATA, end_stream ? H2_FLAG_END_STREAM : 0,
214 memcpy(out + H2_FRAME_HEADER_LEN, data, data_len);
216 return H2_FRAME_HEADER_LEN + data_len;