1 /*
2 * nghttp3
3 *
4 * Copyright (c) 2019 nghttp3 contributors
5 * Copyright (c) 2013 nghttp2 contributors
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26 #include "nghttp3_qpack.h"
27
28 #include <string.h>
29 #include <assert.h>
30 #include <stdio.h>
31
32 #include "nghttp3_str.h"
33 #include "nghttp3_macro.h"
34 #include "nghttp3_debug.h"
35
36 /* NGHTTP3_QPACK_MAX_QPACK_STREAMS is the maximum number of concurrent
37 nghttp3_qpack_stream object to handle a client which never cancel
38 or acknowledge header block. After this limit, encoder stops using
39 dynamic table. */
40 #define NGHTTP3_QPACK_MAX_QPACK_STREAMS 2000
41
42 /* Make scalar initialization form of nghttp3_qpack_static_entry */
43 #define MAKE_STATIC_ENT(I, T, H) \
44 { I, T, H }
45
46 /* Generated by mkstatichdtbl.py */
47 static nghttp3_qpack_static_entry token_stable[] = {
48 MAKE_STATIC_ENT(0, NGHTTP3_QPACK_TOKEN__AUTHORITY, 3153725150u),
49 MAKE_STATIC_ENT(15, NGHTTP3_QPACK_TOKEN__METHOD, 695666056u),
50 MAKE_STATIC_ENT(16, NGHTTP3_QPACK_TOKEN__METHOD, 695666056u),
51 MAKE_STATIC_ENT(17, NGHTTP3_QPACK_TOKEN__METHOD, 695666056u),
52 MAKE_STATIC_ENT(18, NGHTTP3_QPACK_TOKEN__METHOD, 695666056u),
53 MAKE_STATIC_ENT(19, NGHTTP3_QPACK_TOKEN__METHOD, 695666056u),
54 MAKE_STATIC_ENT(20, NGHTTP3_QPACK_TOKEN__METHOD, 695666056u),
55 MAKE_STATIC_ENT(21, NGHTTP3_QPACK_TOKEN__METHOD, 695666056u),
56 MAKE_STATIC_ENT(1, NGHTTP3_QPACK_TOKEN__PATH, 3292848686u),
57 MAKE_STATIC_ENT(22, NGHTTP3_QPACK_TOKEN__SCHEME, 2510477674u),
58 MAKE_STATIC_ENT(23, NGHTTP3_QPACK_TOKEN__SCHEME, 2510477674u),
59 MAKE_STATIC_ENT(24, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
60 MAKE_STATIC_ENT(25, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
61 MAKE_STATIC_ENT(26, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
62 MAKE_STATIC_ENT(27, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
63 MAKE_STATIC_ENT(28, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
64 MAKE_STATIC_ENT(63, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
65 MAKE_STATIC_ENT(64, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
66 MAKE_STATIC_ENT(65, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
67 MAKE_STATIC_ENT(66, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
68 MAKE_STATIC_ENT(67, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
69 MAKE_STATIC_ENT(68, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
70 MAKE_STATIC_ENT(69, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
71 MAKE_STATIC_ENT(70, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
72 MAKE_STATIC_ENT(71, NGHTTP3_QPACK_TOKEN__STATUS, 4000288983u),
73 MAKE_STATIC_ENT(29, NGHTTP3_QPACK_TOKEN_ACCEPT, 136609321u),
74 MAKE_STATIC_ENT(30, NGHTTP3_QPACK_TOKEN_ACCEPT, 136609321u),
75 MAKE_STATIC_ENT(31, NGHTTP3_QPACK_TOKEN_ACCEPT_ENCODING, 3379649177u),
76 MAKE_STATIC_ENT(72, NGHTTP3_QPACK_TOKEN_ACCEPT_LANGUAGE, 1979086614u),
77 MAKE_STATIC_ENT(32, NGHTTP3_QPACK_TOKEN_ACCEPT_RANGES, 1713753958u),
78 MAKE_STATIC_ENT(73, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS,
79 901040780u),
80 MAKE_STATIC_ENT(74, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS,
81 901040780u),
82 MAKE_STATIC_ENT(33, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS,
83 1524311232u),
84 MAKE_STATIC_ENT(34, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS,
85 1524311232u),
86 MAKE_STATIC_ENT(75, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS,
87 1524311232u),
88 MAKE_STATIC_ENT(76, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_METHODS,
89 2175229868u),
90 MAKE_STATIC_ENT(77, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_METHODS,
91 2175229868u),
92 MAKE_STATIC_ENT(78, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_METHODS,
93 2175229868u),
94 MAKE_STATIC_ENT(35, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN,
95 2710797292u),
96 MAKE_STATIC_ENT(79, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_EXPOSE_HEADERS,
97 2449824425u),
98 MAKE_STATIC_ENT(80, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_REQUEST_HEADERS,
99 3599549072u),
100 MAKE_STATIC_ENT(81, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_REQUEST_METHOD,
101 2417078055u),
102 MAKE_STATIC_ENT(82, NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_REQUEST_METHOD,
103 2417078055u),
104 MAKE_STATIC_ENT(2, NGHTTP3_QPACK_TOKEN_AGE, 742476188u),
105 MAKE_STATIC_ENT(83, NGHTTP3_QPACK_TOKEN_ALT_SVC, 2148877059u),
106 MAKE_STATIC_ENT(84, NGHTTP3_QPACK_TOKEN_AUTHORIZATION, 2436257726u),
107 MAKE_STATIC_ENT(36, NGHTTP3_QPACK_TOKEN_CACHE_CONTROL, 1355326669u),
108 MAKE_STATIC_ENT(37, NGHTTP3_QPACK_TOKEN_CACHE_CONTROL, 1355326669u),
109 MAKE_STATIC_ENT(38, NGHTTP3_QPACK_TOKEN_CACHE_CONTROL, 1355326669u),
110 MAKE_STATIC_ENT(39, NGHTTP3_QPACK_TOKEN_CACHE_CONTROL, 1355326669u),
111 MAKE_STATIC_ENT(40, NGHTTP3_QPACK_TOKEN_CACHE_CONTROL, 1355326669u),
112 MAKE_STATIC_ENT(41, NGHTTP3_QPACK_TOKEN_CACHE_CONTROL, 1355326669u),
113 MAKE_STATIC_ENT(3, NGHTTP3_QPACK_TOKEN_CONTENT_DISPOSITION, 3889184348u),
114 MAKE_STATIC_ENT(42, NGHTTP3_QPACK_TOKEN_CONTENT_ENCODING, 65203592u),
115 MAKE_STATIC_ENT(43, NGHTTP3_QPACK_TOKEN_CONTENT_ENCODING, 65203592u),
116 MAKE_STATIC_ENT(4, NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH, 1308181789u),
117 MAKE_STATIC_ENT(85, NGHTTP3_QPACK_TOKEN_CONTENT_SECURITY_POLICY,
118 1569039836u),
119 MAKE_STATIC_ENT(44, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
120 MAKE_STATIC_ENT(45, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
121 MAKE_STATIC_ENT(46, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
122 MAKE_STATIC_ENT(47, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
123 MAKE_STATIC_ENT(48, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
124 MAKE_STATIC_ENT(49, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
125 MAKE_STATIC_ENT(50, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
126 MAKE_STATIC_ENT(51, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
127 MAKE_STATIC_ENT(52, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
128 MAKE_STATIC_ENT(53, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
129 MAKE_STATIC_ENT(54, NGHTTP3_QPACK_TOKEN_CONTENT_TYPE, 4244048277u),
130 MAKE_STATIC_ENT(5, NGHTTP3_QPACK_TOKEN_COOKIE, 2007449791u),
131 MAKE_STATIC_ENT(6, NGHTTP3_QPACK_TOKEN_DATE, 3564297305u),
132 MAKE_STATIC_ENT(86, NGHTTP3_QPACK_TOKEN_EARLY_DATA, 4080895051u),
133 MAKE_STATIC_ENT(7, NGHTTP3_QPACK_TOKEN_ETAG, 113792960u),
134 MAKE_STATIC_ENT(87, NGHTTP3_QPACK_TOKEN_EXPECT_CT, 1183214960u),
135 MAKE_STATIC_ENT(88, NGHTTP3_QPACK_TOKEN_FORWARDED, 1485178027u),
136 MAKE_STATIC_ENT(8, NGHTTP3_QPACK_TOKEN_IF_MODIFIED_SINCE, 2213050793u),
137 MAKE_STATIC_ENT(9, NGHTTP3_QPACK_TOKEN_IF_NONE_MATCH, 2536202615u),
138 MAKE_STATIC_ENT(89, NGHTTP3_QPACK_TOKEN_IF_RANGE, 2340978238u),
139 MAKE_STATIC_ENT(10, NGHTTP3_QPACK_TOKEN_LAST_MODIFIED, 3226950251u),
140 MAKE_STATIC_ENT(11, NGHTTP3_QPACK_TOKEN_LINK, 232457833u),
141 MAKE_STATIC_ENT(12, NGHTTP3_QPACK_TOKEN_LOCATION, 200649126u),
142 MAKE_STATIC_ENT(90, NGHTTP3_QPACK_TOKEN_ORIGIN, 3649018447u),
143 MAKE_STATIC_ENT(91, NGHTTP3_QPACK_TOKEN_PURPOSE, 4212263681u),
144 MAKE_STATIC_ENT(55, NGHTTP3_QPACK_TOKEN_RANGE, 4208725202u),
145 MAKE_STATIC_ENT(13, NGHTTP3_QPACK_TOKEN_REFERER, 3969579366u),
146 MAKE_STATIC_ENT(92, NGHTTP3_QPACK_TOKEN_SERVER, 1085029842u),
147 MAKE_STATIC_ENT(14, NGHTTP3_QPACK_TOKEN_SET_COOKIE, 1848371000u),
148 MAKE_STATIC_ENT(56, NGHTTP3_QPACK_TOKEN_STRICT_TRANSPORT_SECURITY,
149 4138147361u),
150 MAKE_STATIC_ENT(57, NGHTTP3_QPACK_TOKEN_STRICT_TRANSPORT_SECURITY,
151 4138147361u),
152 MAKE_STATIC_ENT(58, NGHTTP3_QPACK_TOKEN_STRICT_TRANSPORT_SECURITY,
153 4138147361u),
154 MAKE_STATIC_ENT(93, NGHTTP3_QPACK_TOKEN_TIMING_ALLOW_ORIGIN, 2432297564u),
155 MAKE_STATIC_ENT(94, NGHTTP3_QPACK_TOKEN_UPGRADE_INSECURE_REQUESTS,
156 2479169413u),
157 MAKE_STATIC_ENT(95, NGHTTP3_QPACK_TOKEN_USER_AGENT, 606444526u),
158 MAKE_STATIC_ENT(59, NGHTTP3_QPACK_TOKEN_VARY, 1085005381u),
159 MAKE_STATIC_ENT(60, NGHTTP3_QPACK_TOKEN_VARY, 1085005381u),
160 MAKE_STATIC_ENT(61, NGHTTP3_QPACK_TOKEN_X_CONTENT_TYPE_OPTIONS,
161 3644557769u),
162 MAKE_STATIC_ENT(96, NGHTTP3_QPACK_TOKEN_X_FORWARDED_FOR, 2914187656u),
163 MAKE_STATIC_ENT(97, NGHTTP3_QPACK_TOKEN_X_FRAME_OPTIONS, 3993834824u),
164 MAKE_STATIC_ENT(98, NGHTTP3_QPACK_TOKEN_X_FRAME_OPTIONS, 3993834824u),
165 MAKE_STATIC_ENT(62, NGHTTP3_QPACK_TOKEN_X_XSS_PROTECTION, 2501058888u),
166 };
167
168 /* Make scalar initialization form of nghttp3_qpack_static_entry */
169 #define MAKE_STATIC_HD(N, V, T) \
170 { \
171 {NULL, NULL, (uint8_t *)(N), sizeof((N)) - 1, -1}, \
172 {NULL, NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, T \
173 }
174
175 static nghttp3_qpack_static_header stable[] = {
176 MAKE_STATIC_HD(":authority", "", NGHTTP3_QPACK_TOKEN__AUTHORITY),
177 MAKE_STATIC_HD(":path", "/", NGHTTP3_QPACK_TOKEN__PATH),
178 MAKE_STATIC_HD("age", "0", NGHTTP3_QPACK_TOKEN_AGE),
179 MAKE_STATIC_HD("content-disposition", "",
180 NGHTTP3_QPACK_TOKEN_CONTENT_DISPOSITION),
181 MAKE_STATIC_HD("content-length", "0", NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH),
182 MAKE_STATIC_HD("cookie", "", NGHTTP3_QPACK_TOKEN_COOKIE),
183 MAKE_STATIC_HD("date", "", NGHTTP3_QPACK_TOKEN_DATE),
184 MAKE_STATIC_HD("etag", "", NGHTTP3_QPACK_TOKEN_ETAG),
185 MAKE_STATIC_HD("if-modified-since", "",
186 NGHTTP3_QPACK_TOKEN_IF_MODIFIED_SINCE),
187 MAKE_STATIC_HD("if-none-match", "", NGHTTP3_QPACK_TOKEN_IF_NONE_MATCH),
188 MAKE_STATIC_HD("last-modified", "", NGHTTP3_QPACK_TOKEN_LAST_MODIFIED),
189 MAKE_STATIC_HD("link", "", NGHTTP3_QPACK_TOKEN_LINK),
190 MAKE_STATIC_HD("location", "", NGHTTP3_QPACK_TOKEN_LOCATION),
191 MAKE_STATIC_HD("referer", "", NGHTTP3_QPACK_TOKEN_REFERER),
192 MAKE_STATIC_HD("set-cookie", "", NGHTTP3_QPACK_TOKEN_SET_COOKIE),
193 MAKE_STATIC_HD(":method", "CONNECT", NGHTTP3_QPACK_TOKEN__METHOD),
194 MAKE_STATIC_HD(":method", "DELETE", NGHTTP3_QPACK_TOKEN__METHOD),
195 MAKE_STATIC_HD(":method", "GET", NGHTTP3_QPACK_TOKEN__METHOD),
196 MAKE_STATIC_HD(":method", "HEAD", NGHTTP3_QPACK_TOKEN__METHOD),
197 MAKE_STATIC_HD(":method", "OPTIONS", NGHTTP3_QPACK_TOKEN__METHOD),
198 MAKE_STATIC_HD(":method", "POST", NGHTTP3_QPACK_TOKEN__METHOD),
199 MAKE_STATIC_HD(":method", "PUT", NGHTTP3_QPACK_TOKEN__METHOD),
200 MAKE_STATIC_HD(":scheme", "http", NGHTTP3_QPACK_TOKEN__SCHEME),
201 MAKE_STATIC_HD(":scheme", "https", NGHTTP3_QPACK_TOKEN__SCHEME),
202 MAKE_STATIC_HD(":status", "103", NGHTTP3_QPACK_TOKEN__STATUS),
203 MAKE_STATIC_HD(":status", "200", NGHTTP3_QPACK_TOKEN__STATUS),
204 MAKE_STATIC_HD(":status", "304", NGHTTP3_QPACK_TOKEN__STATUS),
205 MAKE_STATIC_HD(":status", "404", NGHTTP3_QPACK_TOKEN__STATUS),
206 MAKE_STATIC_HD(":status", "503", NGHTTP3_QPACK_TOKEN__STATUS),
207 MAKE_STATIC_HD("accept", "*/*", NGHTTP3_QPACK_TOKEN_ACCEPT),
208 MAKE_STATIC_HD("accept", "application/dns-message",
209 NGHTTP3_QPACK_TOKEN_ACCEPT),
210 MAKE_STATIC_HD("accept-encoding", "gzip, deflate, br",
211 NGHTTP3_QPACK_TOKEN_ACCEPT_ENCODING),
212 MAKE_STATIC_HD("accept-ranges", "bytes", NGHTTP3_QPACK_TOKEN_ACCEPT_RANGES),
213 MAKE_STATIC_HD("access-control-allow-headers", "cache-control",
214 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS),
215 MAKE_STATIC_HD("access-control-allow-headers", "content-type",
216 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS),
217 MAKE_STATIC_HD("access-control-allow-origin", "*",
218 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN),
219 MAKE_STATIC_HD("cache-control", "max-age=0",
220 NGHTTP3_QPACK_TOKEN_CACHE_CONTROL),
221 MAKE_STATIC_HD("cache-control", "max-age=2592000",
222 NGHTTP3_QPACK_TOKEN_CACHE_CONTROL),
223 MAKE_STATIC_HD("cache-control", "max-age=604800",
224 NGHTTP3_QPACK_TOKEN_CACHE_CONTROL),
225 MAKE_STATIC_HD("cache-control", "no-cache",
226 NGHTTP3_QPACK_TOKEN_CACHE_CONTROL),
227 MAKE_STATIC_HD("cache-control", "no-store",
228 NGHTTP3_QPACK_TOKEN_CACHE_CONTROL),
229 MAKE_STATIC_HD("cache-control", "public, max-age=31536000",
230 NGHTTP3_QPACK_TOKEN_CACHE_CONTROL),
231 MAKE_STATIC_HD("content-encoding", "br",
232 NGHTTP3_QPACK_TOKEN_CONTENT_ENCODING),
233 MAKE_STATIC_HD("content-encoding", "gzip",
234 NGHTTP3_QPACK_TOKEN_CONTENT_ENCODING),
235 MAKE_STATIC_HD("content-type", "application/dns-message",
236 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
237 MAKE_STATIC_HD("content-type", "application/javascript",
238 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
239 MAKE_STATIC_HD("content-type", "application/json",
240 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
241 MAKE_STATIC_HD("content-type", "application/x-www-form-urlencoded",
242 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
243 MAKE_STATIC_HD("content-type", "image/gif",
244 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
245 MAKE_STATIC_HD("content-type", "image/jpeg",
246 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
247 MAKE_STATIC_HD("content-type", "image/png",
248 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
249 MAKE_STATIC_HD("content-type", "text/css",
250 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
251 MAKE_STATIC_HD("content-type", "text/html; charset=utf-8",
252 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
253 MAKE_STATIC_HD("content-type", "text/plain",
254 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
255 MAKE_STATIC_HD("content-type", "text/plain;charset=utf-8",
256 NGHTTP3_QPACK_TOKEN_CONTENT_TYPE),
257 MAKE_STATIC_HD("range", "bytes=0-", NGHTTP3_QPACK_TOKEN_RANGE),
258 MAKE_STATIC_HD("strict-transport-security", "max-age=31536000",
259 NGHTTP3_QPACK_TOKEN_STRICT_TRANSPORT_SECURITY),
260 MAKE_STATIC_HD("strict-transport-security",
261 "max-age=31536000; includesubdomains",
262 NGHTTP3_QPACK_TOKEN_STRICT_TRANSPORT_SECURITY),
263 MAKE_STATIC_HD("strict-transport-security",
264 "max-age=31536000; includesubdomains; preload",
265 NGHTTP3_QPACK_TOKEN_STRICT_TRANSPORT_SECURITY),
266 MAKE_STATIC_HD("vary", "accept-encoding", NGHTTP3_QPACK_TOKEN_VARY),
267 MAKE_STATIC_HD("vary", "origin", NGHTTP3_QPACK_TOKEN_VARY),
268 MAKE_STATIC_HD("x-content-type-options", "nosniff",
269 NGHTTP3_QPACK_TOKEN_X_CONTENT_TYPE_OPTIONS),
270 MAKE_STATIC_HD("x-xss-protection", "1; mode=block",
271 NGHTTP3_QPACK_TOKEN_X_XSS_PROTECTION),
272 MAKE_STATIC_HD(":status", "100", NGHTTP3_QPACK_TOKEN__STATUS),
273 MAKE_STATIC_HD(":status", "204", NGHTTP3_QPACK_TOKEN__STATUS),
274 MAKE_STATIC_HD(":status", "206", NGHTTP3_QPACK_TOKEN__STATUS),
275 MAKE_STATIC_HD(":status", "302", NGHTTP3_QPACK_TOKEN__STATUS),
276 MAKE_STATIC_HD(":status", "400", NGHTTP3_QPACK_TOKEN__STATUS),
277 MAKE_STATIC_HD(":status", "403", NGHTTP3_QPACK_TOKEN__STATUS),
278 MAKE_STATIC_HD(":status", "421", NGHTTP3_QPACK_TOKEN__STATUS),
279 MAKE_STATIC_HD(":status", "425", NGHTTP3_QPACK_TOKEN__STATUS),
280 MAKE_STATIC_HD(":status", "500", NGHTTP3_QPACK_TOKEN__STATUS),
281 MAKE_STATIC_HD("accept-language", "", NGHTTP3_QPACK_TOKEN_ACCEPT_LANGUAGE),
282 MAKE_STATIC_HD("access-control-allow-credentials", "FALSE",
283 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS),
284 MAKE_STATIC_HD("access-control-allow-credentials", "TRUE",
285 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS),
286 MAKE_STATIC_HD("access-control-allow-headers", "*",
287 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS),
288 MAKE_STATIC_HD("access-control-allow-methods", "get",
289 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_METHODS),
290 MAKE_STATIC_HD("access-control-allow-methods", "get, post, options",
291 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_METHODS),
292 MAKE_STATIC_HD("access-control-allow-methods", "options",
293 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_METHODS),
294 MAKE_STATIC_HD("access-control-expose-headers", "content-length",
295 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_EXPOSE_HEADERS),
296 MAKE_STATIC_HD("access-control-request-headers", "content-type",
297 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_REQUEST_HEADERS),
298 MAKE_STATIC_HD("access-control-request-method", "get",
299 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_REQUEST_METHOD),
300 MAKE_STATIC_HD("access-control-request-method", "post",
301 NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_REQUEST_METHOD),
302 MAKE_STATIC_HD("alt-svc", "clear", NGHTTP3_QPACK_TOKEN_ALT_SVC),
303 MAKE_STATIC_HD("authorization", "", NGHTTP3_QPACK_TOKEN_AUTHORIZATION),
304 MAKE_STATIC_HD("content-security-policy",
305 "script-src 'none'; object-src 'none'; base-uri 'none'",
306 NGHTTP3_QPACK_TOKEN_CONTENT_SECURITY_POLICY),
307 MAKE_STATIC_HD("early-data", "1", NGHTTP3_QPACK_TOKEN_EARLY_DATA),
308 MAKE_STATIC_HD("expect-ct", "", NGHTTP3_QPACK_TOKEN_EXPECT_CT),
309 MAKE_STATIC_HD("forwarded", "", NGHTTP3_QPACK_TOKEN_FORWARDED),
310 MAKE_STATIC_HD("if-range", "", NGHTTP3_QPACK_TOKEN_IF_RANGE),
311 MAKE_STATIC_HD("origin", "", NGHTTP3_QPACK_TOKEN_ORIGIN),
312 MAKE_STATIC_HD("purpose", "prefetch", NGHTTP3_QPACK_TOKEN_PURPOSE),
313 MAKE_STATIC_HD("server", "", NGHTTP3_QPACK_TOKEN_SERVER),
314 MAKE_STATIC_HD("timing-allow-origin", "*",
315 NGHTTP3_QPACK_TOKEN_TIMING_ALLOW_ORIGIN),
316 MAKE_STATIC_HD("upgrade-insecure-requests", "1",
317 NGHTTP3_QPACK_TOKEN_UPGRADE_INSECURE_REQUESTS),
318 MAKE_STATIC_HD("user-agent", "", NGHTTP3_QPACK_TOKEN_USER_AGENT),
319 MAKE_STATIC_HD("x-forwarded-for", "", NGHTTP3_QPACK_TOKEN_X_FORWARDED_FOR),
320 MAKE_STATIC_HD("x-frame-options", "deny",
321 NGHTTP3_QPACK_TOKEN_X_FRAME_OPTIONS),
322 MAKE_STATIC_HD("x-frame-options", "sameorigin",
323 NGHTTP3_QPACK_TOKEN_X_FRAME_OPTIONS),
324 };
325
memeq(const void * s1,const void * s2,size_t n)326 static int memeq(const void *s1, const void *s2, size_t n) {
327 return n == 0 || memcmp(s1, s2, n) == 0;
328 }
329
330 /* Generated by genlibtokenlookup.py */
qpack_lookup_token(const uint8_t * name,size_t namelen)331 static int32_t qpack_lookup_token(const uint8_t *name, size_t namelen) {
332 switch (namelen) {
333 case 2:
334 switch (name[1]) {
335 case 'e':
336 if (memeq("t", name, 1)) {
337 return NGHTTP3_QPACK_TOKEN_TE;
338 }
339 break;
340 }
341 break;
342 case 3:
343 switch (name[2]) {
344 case 'e':
345 if (memeq("ag", name, 2)) {
346 return NGHTTP3_QPACK_TOKEN_AGE;
347 }
348 break;
349 }
350 break;
351 case 4:
352 switch (name[3]) {
353 case 'e':
354 if (memeq("dat", name, 3)) {
355 return NGHTTP3_QPACK_TOKEN_DATE;
356 }
357 break;
358 case 'g':
359 if (memeq("eta", name, 3)) {
360 return NGHTTP3_QPACK_TOKEN_ETAG;
361 }
362 break;
363 case 'k':
364 if (memeq("lin", name, 3)) {
365 return NGHTTP3_QPACK_TOKEN_LINK;
366 }
367 break;
368 case 't':
369 if (memeq("hos", name, 3)) {
370 return NGHTTP3_QPACK_TOKEN_HOST;
371 }
372 break;
373 case 'y':
374 if (memeq("var", name, 3)) {
375 return NGHTTP3_QPACK_TOKEN_VARY;
376 }
377 break;
378 }
379 break;
380 case 5:
381 switch (name[4]) {
382 case 'e':
383 if (memeq("rang", name, 4)) {
384 return NGHTTP3_QPACK_TOKEN_RANGE;
385 }
386 break;
387 case 'h':
388 if (memeq(":pat", name, 4)) {
389 return NGHTTP3_QPACK_TOKEN__PATH;
390 }
391 break;
392 }
393 break;
394 case 6:
395 switch (name[5]) {
396 case 'e':
397 if (memeq("cooki", name, 5)) {
398 return NGHTTP3_QPACK_TOKEN_COOKIE;
399 }
400 break;
401 case 'n':
402 if (memeq("origi", name, 5)) {
403 return NGHTTP3_QPACK_TOKEN_ORIGIN;
404 }
405 break;
406 case 'r':
407 if (memeq("serve", name, 5)) {
408 return NGHTTP3_QPACK_TOKEN_SERVER;
409 }
410 break;
411 case 't':
412 if (memeq("accep", name, 5)) {
413 return NGHTTP3_QPACK_TOKEN_ACCEPT;
414 }
415 break;
416 }
417 break;
418 case 7:
419 switch (name[6]) {
420 case 'c':
421 if (memeq("alt-sv", name, 6)) {
422 return NGHTTP3_QPACK_TOKEN_ALT_SVC;
423 }
424 break;
425 case 'd':
426 if (memeq(":metho", name, 6)) {
427 return NGHTTP3_QPACK_TOKEN__METHOD;
428 }
429 break;
430 case 'e':
431 if (memeq(":schem", name, 6)) {
432 return NGHTTP3_QPACK_TOKEN__SCHEME;
433 }
434 if (memeq("purpos", name, 6)) {
435 return NGHTTP3_QPACK_TOKEN_PURPOSE;
436 }
437 if (memeq("upgrad", name, 6)) {
438 return NGHTTP3_QPACK_TOKEN_UPGRADE;
439 }
440 break;
441 case 'r':
442 if (memeq("refere", name, 6)) {
443 return NGHTTP3_QPACK_TOKEN_REFERER;
444 }
445 break;
446 case 's':
447 if (memeq(":statu", name, 6)) {
448 return NGHTTP3_QPACK_TOKEN__STATUS;
449 }
450 break;
451 }
452 break;
453 case 8:
454 switch (name[7]) {
455 case 'e':
456 if (memeq("if-rang", name, 7)) {
457 return NGHTTP3_QPACK_TOKEN_IF_RANGE;
458 }
459 break;
460 case 'n':
461 if (memeq("locatio", name, 7)) {
462 return NGHTTP3_QPACK_TOKEN_LOCATION;
463 }
464 break;
465 case 'y':
466 if (memeq("priorit", name, 7)) {
467 return NGHTTP3_QPACK_TOKEN_PRIORITY;
468 }
469 break;
470 }
471 break;
472 case 9:
473 switch (name[8]) {
474 case 'd':
475 if (memeq("forwarde", name, 8)) {
476 return NGHTTP3_QPACK_TOKEN_FORWARDED;
477 }
478 break;
479 case 'l':
480 if (memeq(":protoco", name, 8)) {
481 return NGHTTP3_QPACK_TOKEN__PROTOCOL;
482 }
483 break;
484 case 't':
485 if (memeq("expect-c", name, 8)) {
486 return NGHTTP3_QPACK_TOKEN_EXPECT_CT;
487 }
488 break;
489 }
490 break;
491 case 10:
492 switch (name[9]) {
493 case 'a':
494 if (memeq("early-dat", name, 9)) {
495 return NGHTTP3_QPACK_TOKEN_EARLY_DATA;
496 }
497 break;
498 case 'e':
499 if (memeq("keep-aliv", name, 9)) {
500 return NGHTTP3_QPACK_TOKEN_KEEP_ALIVE;
501 }
502 if (memeq("set-cooki", name, 9)) {
503 return NGHTTP3_QPACK_TOKEN_SET_COOKIE;
504 }
505 break;
506 case 'n':
507 if (memeq("connectio", name, 9)) {
508 return NGHTTP3_QPACK_TOKEN_CONNECTION;
509 }
510 break;
511 case 't':
512 if (memeq("user-agen", name, 9)) {
513 return NGHTTP3_QPACK_TOKEN_USER_AGENT;
514 }
515 break;
516 case 'y':
517 if (memeq(":authorit", name, 9)) {
518 return NGHTTP3_QPACK_TOKEN__AUTHORITY;
519 }
520 break;
521 }
522 break;
523 case 12:
524 switch (name[11]) {
525 case 'e':
526 if (memeq("content-typ", name, 11)) {
527 return NGHTTP3_QPACK_TOKEN_CONTENT_TYPE;
528 }
529 break;
530 }
531 break;
532 case 13:
533 switch (name[12]) {
534 case 'd':
535 if (memeq("last-modifie", name, 12)) {
536 return NGHTTP3_QPACK_TOKEN_LAST_MODIFIED;
537 }
538 break;
539 case 'h':
540 if (memeq("if-none-matc", name, 12)) {
541 return NGHTTP3_QPACK_TOKEN_IF_NONE_MATCH;
542 }
543 break;
544 case 'l':
545 if (memeq("cache-contro", name, 12)) {
546 return NGHTTP3_QPACK_TOKEN_CACHE_CONTROL;
547 }
548 break;
549 case 'n':
550 if (memeq("authorizatio", name, 12)) {
551 return NGHTTP3_QPACK_TOKEN_AUTHORIZATION;
552 }
553 break;
554 case 's':
555 if (memeq("accept-range", name, 12)) {
556 return NGHTTP3_QPACK_TOKEN_ACCEPT_RANGES;
557 }
558 break;
559 }
560 break;
561 case 14:
562 switch (name[13]) {
563 case 'h':
564 if (memeq("content-lengt", name, 13)) {
565 return NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH;
566 }
567 break;
568 }
569 break;
570 case 15:
571 switch (name[14]) {
572 case 'e':
573 if (memeq("accept-languag", name, 14)) {
574 return NGHTTP3_QPACK_TOKEN_ACCEPT_LANGUAGE;
575 }
576 break;
577 case 'g':
578 if (memeq("accept-encodin", name, 14)) {
579 return NGHTTP3_QPACK_TOKEN_ACCEPT_ENCODING;
580 }
581 break;
582 case 'r':
583 if (memeq("x-forwarded-fo", name, 14)) {
584 return NGHTTP3_QPACK_TOKEN_X_FORWARDED_FOR;
585 }
586 break;
587 case 's':
588 if (memeq("x-frame-option", name, 14)) {
589 return NGHTTP3_QPACK_TOKEN_X_FRAME_OPTIONS;
590 }
591 break;
592 }
593 break;
594 case 16:
595 switch (name[15]) {
596 case 'g':
597 if (memeq("content-encodin", name, 15)) {
598 return NGHTTP3_QPACK_TOKEN_CONTENT_ENCODING;
599 }
600 break;
601 case 'n':
602 if (memeq("proxy-connectio", name, 15)) {
603 return NGHTTP3_QPACK_TOKEN_PROXY_CONNECTION;
604 }
605 if (memeq("x-xss-protectio", name, 15)) {
606 return NGHTTP3_QPACK_TOKEN_X_XSS_PROTECTION;
607 }
608 break;
609 }
610 break;
611 case 17:
612 switch (name[16]) {
613 case 'e':
614 if (memeq("if-modified-sinc", name, 16)) {
615 return NGHTTP3_QPACK_TOKEN_IF_MODIFIED_SINCE;
616 }
617 break;
618 case 'g':
619 if (memeq("transfer-encodin", name, 16)) {
620 return NGHTTP3_QPACK_TOKEN_TRANSFER_ENCODING;
621 }
622 break;
623 }
624 break;
625 case 19:
626 switch (name[18]) {
627 case 'n':
628 if (memeq("content-dispositio", name, 18)) {
629 return NGHTTP3_QPACK_TOKEN_CONTENT_DISPOSITION;
630 }
631 if (memeq("timing-allow-origi", name, 18)) {
632 return NGHTTP3_QPACK_TOKEN_TIMING_ALLOW_ORIGIN;
633 }
634 break;
635 }
636 break;
637 case 22:
638 switch (name[21]) {
639 case 's':
640 if (memeq("x-content-type-option", name, 21)) {
641 return NGHTTP3_QPACK_TOKEN_X_CONTENT_TYPE_OPTIONS;
642 }
643 break;
644 }
645 break;
646 case 23:
647 switch (name[22]) {
648 case 'y':
649 if (memeq("content-security-polic", name, 22)) {
650 return NGHTTP3_QPACK_TOKEN_CONTENT_SECURITY_POLICY;
651 }
652 break;
653 }
654 break;
655 case 25:
656 switch (name[24]) {
657 case 's':
658 if (memeq("upgrade-insecure-request", name, 24)) {
659 return NGHTTP3_QPACK_TOKEN_UPGRADE_INSECURE_REQUESTS;
660 }
661 break;
662 case 'y':
663 if (memeq("strict-transport-securit", name, 24)) {
664 return NGHTTP3_QPACK_TOKEN_STRICT_TRANSPORT_SECURITY;
665 }
666 break;
667 }
668 break;
669 case 27:
670 switch (name[26]) {
671 case 'n':
672 if (memeq("access-control-allow-origi", name, 26)) {
673 return NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN;
674 }
675 break;
676 }
677 break;
678 case 28:
679 switch (name[27]) {
680 case 's':
681 if (memeq("access-control-allow-header", name, 27)) {
682 return NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS;
683 }
684 if (memeq("access-control-allow-method", name, 27)) {
685 return NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_METHODS;
686 }
687 break;
688 }
689 break;
690 case 29:
691 switch (name[28]) {
692 case 'd':
693 if (memeq("access-control-request-metho", name, 28)) {
694 return NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_REQUEST_METHOD;
695 }
696 break;
697 case 's':
698 if (memeq("access-control-expose-header", name, 28)) {
699 return NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_EXPOSE_HEADERS;
700 }
701 break;
702 }
703 break;
704 case 30:
705 switch (name[29]) {
706 case 's':
707 if (memeq("access-control-request-header", name, 29)) {
708 return NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_REQUEST_HEADERS;
709 }
710 break;
711 }
712 break;
713 case 32:
714 switch (name[31]) {
715 case 's':
716 if (memeq("access-control-allow-credential", name, 31)) {
717 return NGHTTP3_QPACK_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS;
718 }
719 break;
720 }
721 break;
722 }
723 return -1;
724 }
725
table_space(size_t namelen,size_t valuelen)726 static size_t table_space(size_t namelen, size_t valuelen) {
727 return NGHTTP3_QPACK_ENTRY_OVERHEAD + namelen + valuelen;
728 }
729
qpack_nv_name_eq(const nghttp3_qpack_nv * a,const nghttp3_nv * b)730 static int qpack_nv_name_eq(const nghttp3_qpack_nv *a, const nghttp3_nv *b) {
731 return a->name->len == b->namelen &&
732 memeq(a->name->base, b->name, b->namelen);
733 }
734
qpack_nv_value_eq(const nghttp3_qpack_nv * a,const nghttp3_nv * b)735 static int qpack_nv_value_eq(const nghttp3_qpack_nv *a, const nghttp3_nv *b) {
736 return a->value->len == b->valuelen &&
737 memeq(a->value->base, b->value, b->valuelen);
738 }
739
qpack_map_init(nghttp3_qpack_map * map)740 static void qpack_map_init(nghttp3_qpack_map *map) {
741 memset(map, 0, sizeof(nghttp3_qpack_map));
742 }
743
qpack_map_insert(nghttp3_qpack_map * map,nghttp3_qpack_entry * ent)744 static void qpack_map_insert(nghttp3_qpack_map *map, nghttp3_qpack_entry *ent) {
745 nghttp3_qpack_entry **bucket;
746
747 bucket = &map->table[ent->hash & (NGHTTP3_QPACK_MAP_SIZE - 1)];
748
749 if (*bucket == NULL) {
750 *bucket = ent;
751 return;
752 }
753
754 /* larger absidx is linked near the root */
755 ent->map_next = *bucket;
756 *bucket = ent;
757 }
758
qpack_map_remove(nghttp3_qpack_map * map,nghttp3_qpack_entry * ent)759 static void qpack_map_remove(nghttp3_qpack_map *map, nghttp3_qpack_entry *ent) {
760 nghttp3_qpack_entry **dst;
761
762 dst = &map->table[ent->hash & (NGHTTP3_QPACK_MAP_SIZE - 1)];
763
764 for (; *dst; dst = &(*dst)->map_next) {
765 if (*dst != ent) {
766 continue;
767 }
768
769 *dst = ent->map_next;
770 ent->map_next = NULL;
771 return;
772 }
773 }
774
775 /*
776 * qpack_context_can_reference returns nonzero if dynamic table entry
777 * at |absidx| can be referenced. In other words, it is within
778 * ctx->max_dtable_capacity.
779 */
qpack_context_can_reference(nghttp3_qpack_context * ctx,uint64_t absidx)780 static int qpack_context_can_reference(nghttp3_qpack_context *ctx,
781 uint64_t absidx) {
782 nghttp3_qpack_entry *ent = nghttp3_qpack_context_dtable_get(ctx, absidx);
783 return ctx->dtable_sum - ent->sum <= ctx->max_dtable_capacity;
784 }
785
786 /* |*ppb_match| (post-base match), if it is not NULL, is always exact
787 match. */
encoder_qpack_map_find(nghttp3_qpack_encoder * encoder,int * exact_match,nghttp3_qpack_entry ** pmatch,nghttp3_qpack_entry ** ppb_match,const nghttp3_nv * nv,int32_t token,uint32_t hash,uint64_t krcnt,int allow_blocking,int name_only)788 static void encoder_qpack_map_find(nghttp3_qpack_encoder *encoder,
789 int *exact_match,
790 nghttp3_qpack_entry **pmatch,
791 nghttp3_qpack_entry **ppb_match,
792 const nghttp3_nv *nv, int32_t token,
793 uint32_t hash, uint64_t krcnt,
794 int allow_blocking, int name_only) {
795 nghttp3_qpack_entry *p;
796
797 *exact_match = 0;
798 *pmatch = NULL;
799 *ppb_match = NULL;
800
801 for (p = encoder->dtable_map.table[hash & (NGHTTP3_QPACK_MAP_SIZE - 1)]; p;
802 p = p->map_next) {
803 if (token != p->nv.token ||
804 (token == -1 && (hash != p->hash || !qpack_nv_name_eq(&p->nv, nv))) ||
805 !qpack_context_can_reference(&encoder->ctx, p->absidx)) {
806 continue;
807 }
808 if (allow_blocking || p->absidx + 1 <= krcnt) {
809 if (!*pmatch) {
810 *pmatch = p;
811 if (name_only) {
812 return;
813 }
814 }
815 if (qpack_nv_value_eq(&p->nv, nv)) {
816 *pmatch = p;
817 *exact_match = 1;
818 return;
819 }
820 } else if (!*ppb_match && qpack_nv_value_eq(&p->nv, nv)) {
821 *ppb_match = p;
822 }
823 }
824 }
825
826 /*
827 * qpack_context_init initializes |ctx|. |max_dtable_capacity| is the
828 * maximum size of dynamic table. |mem| is a memory allocator.
829 *
830 * This function returns 0 if it succeeds, or one of the following
831 * negative error codes:
832 *
833 * NGHTTP3_ERR_NOMEM
834 * Out of memory.
835 */
qpack_context_init(nghttp3_qpack_context * ctx,size_t max_dtable_capacity,size_t max_blocked_streams,const nghttp3_mem * mem)836 static int qpack_context_init(nghttp3_qpack_context *ctx,
837 size_t max_dtable_capacity,
838 size_t max_blocked_streams,
839 const nghttp3_mem *mem) {
840 int rv;
841 size_t len = 4096 / NGHTTP3_QPACK_ENTRY_OVERHEAD;
842 size_t len2;
843
844 for (len2 = 1; len2 < len; len2 <<= 1)
845 ;
846
847 rv = nghttp3_ringbuf_init(&ctx->dtable, len2, sizeof(nghttp3_qpack_entry *),
848 mem);
849 if (rv != 0) {
850 return rv;
851 }
852
853 ctx->mem = mem;
854 ctx->dtable_size = 0;
855 ctx->dtable_sum = 0;
856 ctx->hard_max_dtable_capacity = max_dtable_capacity;
857 ctx->max_dtable_capacity = 0;
858 ctx->max_blocked_streams = max_blocked_streams;
859 ctx->next_absidx = 0;
860 ctx->bad = 0;
861
862 return 0;
863 }
864
qpack_context_free(nghttp3_qpack_context * ctx)865 static void qpack_context_free(nghttp3_qpack_context *ctx) {
866 nghttp3_qpack_entry *ent;
867 size_t i, len = nghttp3_ringbuf_len(&ctx->dtable);
868
869 for (i = 0; i < len; ++i) {
870 ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, i);
871 nghttp3_qpack_entry_free(ent);
872 nghttp3_mem_free(ctx->mem, ent);
873 }
874 nghttp3_ringbuf_free(&ctx->dtable);
875 }
876
ref_min_cnt_less(const nghttp3_pq_entry * lhsx,const nghttp3_pq_entry * rhsx)877 static int ref_min_cnt_less(const nghttp3_pq_entry *lhsx,
878 const nghttp3_pq_entry *rhsx) {
879 nghttp3_qpack_header_block_ref *lhs =
880 nghttp3_struct_of(lhsx, nghttp3_qpack_header_block_ref, min_cnts_pe);
881 nghttp3_qpack_header_block_ref *rhs =
882 nghttp3_struct_of(rhsx, nghttp3_qpack_header_block_ref, min_cnts_pe);
883
884 return lhs->min_cnt < rhs->min_cnt;
885 }
886
887 typedef struct nghttp3_blocked_streams_key {
888 uint64_t max_cnt;
889 uint64_t id;
890 } nghttp3_blocked_streams_key;
891
max_cnt_greater(const nghttp3_ksl_key * lhs,const nghttp3_ksl_key * rhs)892 static int max_cnt_greater(const nghttp3_ksl_key *lhs,
893 const nghttp3_ksl_key *rhs) {
894 const nghttp3_blocked_streams_key *a = lhs;
895 const nghttp3_blocked_streams_key *b = rhs;
896 return a->max_cnt > b->max_cnt || (a->max_cnt == b->max_cnt && a->id < b->id);
897 }
898
nghttp3_qpack_encoder_init(nghttp3_qpack_encoder * encoder,const nghttp3_mem * mem)899 int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder,
900 const nghttp3_mem *mem) {
901 int rv;
902
903 rv = qpack_context_init(&encoder->ctx, 0, 0, mem);
904 if (rv != 0) {
905 return rv;
906 }
907
908 rv = nghttp3_map_init(&encoder->streams, mem);
909 if (rv != 0) {
910 goto streams_init_fail;
911 }
912
913 rv = nghttp3_ksl_init(&encoder->blocked_streams, max_cnt_greater,
914 sizeof(nghttp3_blocked_streams_key), mem);
915 if (rv != 0) {
916 goto blocked_streams_init_fail;
917 }
918
919 qpack_map_init(&encoder->dtable_map);
920 nghttp3_pq_init(&encoder->min_cnts, ref_min_cnt_less, mem);
921
922 encoder->krcnt = 0;
923 encoder->state = NGHTTP3_QPACK_DS_STATE_OPCODE;
924 encoder->opcode = 0;
925 encoder->min_dtable_update = SIZE_MAX;
926 encoder->last_max_dtable_update = 0;
927 encoder->flags = NGHTTP3_QPACK_ENCODER_FLAG_NONE;
928
929 nghttp3_qpack_read_state_reset(&encoder->rstate);
930
931 return 0;
932
933 blocked_streams_init_fail:
934 nghttp3_map_free(&encoder->streams);
935 streams_init_fail:
936 qpack_context_free(&encoder->ctx);
937
938 return rv;
939 }
940
map_stream_free(void * data,void * ptr)941 static int map_stream_free(void *data, void *ptr) {
942 const nghttp3_mem *mem = ptr;
943 nghttp3_qpack_stream *stream = data;
944 nghttp3_qpack_stream_del(stream, mem);
945 return 0;
946 }
947
nghttp3_qpack_encoder_free(nghttp3_qpack_encoder * encoder)948 void nghttp3_qpack_encoder_free(nghttp3_qpack_encoder *encoder) {
949 nghttp3_pq_free(&encoder->min_cnts);
950 nghttp3_ksl_free(&encoder->blocked_streams);
951 nghttp3_map_each_free(&encoder->streams, map_stream_free,
952 (void *)encoder->ctx.mem);
953 nghttp3_map_free(&encoder->streams);
954 qpack_context_free(&encoder->ctx);
955 }
956
nghttp3_qpack_encoder_set_max_dtable_capacity(nghttp3_qpack_encoder * encoder,size_t max_dtable_capacity)957 int nghttp3_qpack_encoder_set_max_dtable_capacity(
958 nghttp3_qpack_encoder *encoder, size_t max_dtable_capacity) {
959 if (encoder->ctx.hard_max_dtable_capacity < max_dtable_capacity) {
960 return NGHTTP3_ERR_INVALID_ARGUMENT;
961 }
962
963 if (encoder->ctx.max_dtable_capacity == max_dtable_capacity) {
964 return 0;
965 }
966
967 encoder->flags |= NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP;
968
969 if (encoder->min_dtable_update > max_dtable_capacity) {
970 encoder->min_dtable_update = max_dtable_capacity;
971 encoder->ctx.max_dtable_capacity = max_dtable_capacity;
972 }
973 encoder->last_max_dtable_update = max_dtable_capacity;
974
975 return 0;
976 }
977
nghttp3_qpack_encoder_set_hard_max_dtable_capacity(nghttp3_qpack_encoder * encoder,size_t hard_max_dtable_capacity)978 void nghttp3_qpack_encoder_set_hard_max_dtable_capacity(
979 nghttp3_qpack_encoder *encoder, size_t hard_max_dtable_capacity) {
980 encoder->ctx.hard_max_dtable_capacity = hard_max_dtable_capacity;
981 }
982
nghttp3_qpack_encoder_set_max_blocked_streams(nghttp3_qpack_encoder * encoder,size_t max_blocked_streams)983 void nghttp3_qpack_encoder_set_max_blocked_streams(
984 nghttp3_qpack_encoder *encoder, size_t max_blocked_streams) {
985 encoder->ctx.max_blocked_streams = max_blocked_streams;
986 }
987
nghttp3_qpack_encoder_get_min_cnt(nghttp3_qpack_encoder * encoder)988 uint64_t nghttp3_qpack_encoder_get_min_cnt(nghttp3_qpack_encoder *encoder) {
989 assert(!nghttp3_pq_empty(&encoder->min_cnts));
990
991 return nghttp3_struct_of(nghttp3_pq_top(&encoder->min_cnts),
992 nghttp3_qpack_header_block_ref, min_cnts_pe)
993 ->min_cnt;
994 }
995
nghttp3_qpack_encoder_shrink_dtable(nghttp3_qpack_encoder * encoder)996 void nghttp3_qpack_encoder_shrink_dtable(nghttp3_qpack_encoder *encoder) {
997 nghttp3_ringbuf *dtable = &encoder->ctx.dtable;
998 const nghttp3_mem *mem = encoder->ctx.mem;
999 uint64_t min_cnt = UINT64_MAX;
1000 size_t len;
1001 nghttp3_qpack_entry *ent;
1002
1003 if (encoder->ctx.dtable_size <= encoder->ctx.max_dtable_capacity) {
1004 return;
1005 }
1006
1007 if (!nghttp3_pq_empty(&encoder->min_cnts)) {
1008 min_cnt = nghttp3_qpack_encoder_get_min_cnt(encoder);
1009 }
1010
1011 for (; encoder->ctx.dtable_size > encoder->ctx.max_dtable_capacity;) {
1012 len = nghttp3_ringbuf_len(dtable);
1013 ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(dtable, len - 1);
1014 if (ent->absidx + 1 == min_cnt) {
1015 return;
1016 }
1017
1018 encoder->ctx.dtable_size -=
1019 table_space(ent->nv.name->len, ent->nv.value->len);
1020
1021 nghttp3_ringbuf_pop_back(dtable);
1022 qpack_map_remove(&encoder->dtable_map, ent);
1023
1024 nghttp3_qpack_entry_free(ent);
1025 nghttp3_mem_free(mem, ent);
1026 }
1027 }
1028
1029 /*
1030 * qpack_encoder_add_stream_ref adds another dynamic table reference
1031 * to a stream denoted by |stream_id|. |stream| must be NULL if no
1032 * stream object is not found for the given stream ID. |max_cnt| and
1033 * |min_cnt| is the maximum and minimum insert count it references
1034 * respectively.
1035 *
1036 * This function returns 0 if it succeeds, or one of the following
1037 * negative error codes:
1038 *
1039 * NGHTTP3_ERR_NOMEM
1040 * Out of memory.
1041 */
qpack_encoder_add_stream_ref(nghttp3_qpack_encoder * encoder,int64_t stream_id,nghttp3_qpack_stream * stream,uint64_t max_cnt,uint64_t min_cnt)1042 static int qpack_encoder_add_stream_ref(nghttp3_qpack_encoder *encoder,
1043 int64_t stream_id,
1044 nghttp3_qpack_stream *stream,
1045 uint64_t max_cnt, uint64_t min_cnt) {
1046 nghttp3_qpack_header_block_ref *ref;
1047 const nghttp3_mem *mem = encoder->ctx.mem;
1048 uint64_t prev_max_cnt = 0;
1049 int rv;
1050
1051 if (stream == NULL) {
1052 rv = nghttp3_qpack_stream_new(&stream, stream_id, mem);
1053 if (rv != 0) {
1054 assert(rv == NGHTTP3_ERR_NOMEM);
1055 return rv;
1056 }
1057 rv = nghttp3_map_insert(&encoder->streams,
1058 (nghttp3_map_key_type)stream->stream_id, stream);
1059 if (rv != 0) {
1060 assert(rv == NGHTTP3_ERR_NOMEM);
1061 nghttp3_qpack_stream_del(stream, mem);
1062 return rv;
1063 }
1064 } else {
1065 prev_max_cnt = nghttp3_qpack_stream_get_max_cnt(stream);
1066 if (nghttp3_qpack_encoder_stream_is_blocked(encoder, stream) &&
1067 max_cnt > prev_max_cnt) {
1068 nghttp3_qpack_encoder_unblock_stream(encoder, stream);
1069 }
1070 }
1071
1072 rv = nghttp3_qpack_header_block_ref_new(&ref, max_cnt, min_cnt, mem);
1073 if (rv != 0) {
1074 return rv;
1075 }
1076
1077 rv = nghttp3_qpack_stream_add_ref(stream, ref);
1078 if (rv != 0) {
1079 nghttp3_qpack_header_block_ref_del(ref, mem);
1080 return rv;
1081 }
1082
1083 if (max_cnt > prev_max_cnt &&
1084 nghttp3_qpack_encoder_stream_is_blocked(encoder, stream)) {
1085 rv = nghttp3_qpack_encoder_block_stream(encoder, stream);
1086 if (rv != 0) {
1087 return rv;
1088 }
1089 }
1090
1091 return nghttp3_pq_push(&encoder->min_cnts, &ref->min_cnts_pe);
1092 }
1093
qpack_encoder_remove_stream(nghttp3_qpack_encoder * encoder,nghttp3_qpack_stream * stream)1094 static void qpack_encoder_remove_stream(nghttp3_qpack_encoder *encoder,
1095 nghttp3_qpack_stream *stream) {
1096 size_t i, len;
1097 nghttp3_qpack_header_block_ref *ref;
1098
1099 nghttp3_map_remove(&encoder->streams,
1100 (nghttp3_map_key_type)stream->stream_id);
1101
1102 len = nghttp3_ringbuf_len(&stream->refs);
1103 for (i = 0; i < len; ++i) {
1104 ref = *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs,
1105 i);
1106
1107 assert(ref->min_cnts_pe.index != NGHTTP3_PQ_BAD_INDEX);
1108
1109 nghttp3_pq_remove(&encoder->min_cnts, &ref->min_cnts_pe);
1110 }
1111 }
1112
1113 /*
1114 * reserve_buf_internal ensures that |buf| contains at least
1115 * |extra_size| of free space. In other words, if this function
1116 * succeeds, nghttp2_buf_left(buf) >= extra_size holds. |min_size| is
1117 * the minimum size of buffer. The allocated buffer has at least
1118 * |min_size| bytes.
1119 *
1120 * This function returns 0 if it succeeds, or one of the following
1121 * negative error codes:
1122 *
1123 * NGHTTP3_ERR_NOMEM
1124 * Out of memory.
1125 */
reserve_buf_internal(nghttp3_buf * buf,size_t extra_size,size_t min_size,const nghttp3_mem * mem)1126 static int reserve_buf_internal(nghttp3_buf *buf, size_t extra_size,
1127 size_t min_size, const nghttp3_mem *mem) {
1128 size_t left = nghttp3_buf_left(buf);
1129 size_t n = min_size, need;
1130
1131 if (left >= extra_size) {
1132 return 0;
1133 }
1134
1135 need = nghttp3_buf_cap(buf) + extra_size - left;
1136
1137 for (; n < need; n *= 2)
1138 ;
1139
1140 return nghttp3_buf_reserve(buf, n, mem);
1141 }
1142
reserve_buf_small(nghttp3_buf * buf,size_t extra_size,const nghttp3_mem * mem)1143 static int reserve_buf_small(nghttp3_buf *buf, size_t extra_size,
1144 const nghttp3_mem *mem) {
1145 return reserve_buf_internal(buf, extra_size, 32, mem);
1146 }
1147
reserve_buf(nghttp3_buf * buf,size_t extra_size,const nghttp3_mem * mem)1148 static int reserve_buf(nghttp3_buf *buf, size_t extra_size,
1149 const nghttp3_mem *mem) {
1150 return reserve_buf_internal(buf, extra_size, 32, mem);
1151 }
1152
nghttp3_qpack_encoder_encode(nghttp3_qpack_encoder * encoder,nghttp3_buf * pbuf,nghttp3_buf * rbuf,nghttp3_buf * ebuf,int64_t stream_id,const nghttp3_nv * nva,size_t nvlen)1153 int nghttp3_qpack_encoder_encode(nghttp3_qpack_encoder *encoder,
1154 nghttp3_buf *pbuf, nghttp3_buf *rbuf,
1155 nghttp3_buf *ebuf, int64_t stream_id,
1156 const nghttp3_nv *nva, size_t nvlen) {
1157 size_t i;
1158 uint64_t max_cnt = 0, min_cnt = UINT64_MAX;
1159 uint64_t base;
1160 int rv = 0;
1161 int allow_blocking;
1162 int blocked_stream;
1163 nghttp3_qpack_stream *stream;
1164
1165 if (encoder->ctx.bad) {
1166 return NGHTTP3_ERR_QPACK_FATAL;
1167 }
1168
1169 rv = nghttp3_qpack_encoder_process_dtable_update(encoder, ebuf);
1170 if (rv != 0) {
1171 goto fail;
1172 }
1173
1174 base = encoder->ctx.next_absidx;
1175
1176 stream = nghttp3_qpack_encoder_find_stream(encoder, stream_id);
1177 blocked_stream =
1178 stream && nghttp3_qpack_encoder_stream_is_blocked(encoder, stream);
1179 allow_blocking =
1180 blocked_stream || encoder->ctx.max_blocked_streams >
1181 nghttp3_ksl_len(&encoder->blocked_streams);
1182
1183 DEBUGF("qpack::encode: stream %ld blocked=%d allow_blocking=%d\n", stream_id,
1184 blocked_stream, allow_blocking);
1185
1186 for (i = 0; i < nvlen; ++i) {
1187 rv = nghttp3_qpack_encoder_encode_nv(encoder, &max_cnt, &min_cnt, rbuf,
1188 ebuf, &nva[i], base, allow_blocking);
1189 if (rv != 0) {
1190 goto fail;
1191 }
1192 }
1193
1194 nghttp3_qpack_encoder_write_field_section_prefix(encoder, pbuf, max_cnt,
1195 base);
1196
1197 /* TODO If max_cnt == 0, no reference is made to dtable. */
1198 if (!max_cnt) {
1199 return 0;
1200 }
1201
1202 rv = qpack_encoder_add_stream_ref(encoder, stream_id, stream, max_cnt,
1203 min_cnt);
1204 if (rv != 0) {
1205 goto fail;
1206 }
1207
1208 return 0;
1209
1210 fail:
1211 encoder->ctx.bad = 1;
1212 return rv;
1213 }
1214
1215 /*
1216 * qpack_write_number writes variable integer to |rbuf|. |num| is an
1217 * integer to write. |prefix| is a prefix of variable integer
1218 * encoding.
1219 *
1220 * This function returns 0 if it succeeds, or one of the following
1221 * negative error codes:
1222 *
1223 * NGHTTP3_ERR_NOMEM
1224 * Out of memory.
1225 */
qpack_write_number(nghttp3_buf * rbuf,uint8_t fb,uint64_t num,size_t prefix,const nghttp3_mem * mem)1226 static int qpack_write_number(nghttp3_buf *rbuf, uint8_t fb, uint64_t num,
1227 size_t prefix, const nghttp3_mem *mem) {
1228 int rv;
1229 size_t len = nghttp3_qpack_put_varint_len(num, prefix);
1230 uint8_t *p;
1231
1232 rv = reserve_buf(rbuf, len, mem);
1233 if (rv != 0) {
1234 return rv;
1235 }
1236
1237 p = rbuf->last;
1238
1239 *p = fb;
1240 p = nghttp3_qpack_put_varint(p, num, prefix);
1241
1242 assert((size_t)(p - rbuf->last) == len);
1243
1244 rbuf->last = p;
1245
1246 return 0;
1247 }
1248
nghttp3_qpack_encoder_process_dtable_update(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf)1249 int nghttp3_qpack_encoder_process_dtable_update(nghttp3_qpack_encoder *encoder,
1250 nghttp3_buf *ebuf) {
1251 int rv;
1252
1253 nghttp3_qpack_encoder_shrink_dtable(encoder);
1254
1255 if (encoder->ctx.max_dtable_capacity < encoder->ctx.dtable_size ||
1256 !(encoder->flags & NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP)) {
1257 return 0;
1258 }
1259
1260 if (encoder->min_dtable_update < encoder->last_max_dtable_update) {
1261 rv = nghttp3_qpack_encoder_write_set_dtable_cap(encoder, ebuf,
1262 encoder->min_dtable_update);
1263 if (rv != 0) {
1264 return rv;
1265 }
1266 }
1267
1268 rv = nghttp3_qpack_encoder_write_set_dtable_cap(
1269 encoder, ebuf, encoder->last_max_dtable_update);
1270 if (rv != 0) {
1271 return rv;
1272 }
1273
1274 encoder->flags &= (uint8_t)~NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP;
1275 encoder->min_dtable_update = SIZE_MAX;
1276 encoder->ctx.max_dtable_capacity = encoder->last_max_dtable_update;
1277
1278 return 0;
1279 }
1280
nghttp3_qpack_encoder_write_set_dtable_cap(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,size_t cap)1281 int nghttp3_qpack_encoder_write_set_dtable_cap(nghttp3_qpack_encoder *encoder,
1282 nghttp3_buf *ebuf, size_t cap) {
1283 DEBUGF("qpack::encode: Set Dynamic Table Capacity capacity=%zu\n", cap);
1284 return qpack_write_number(ebuf, 0x20, cap, 5, encoder->ctx.mem);
1285 }
1286
1287 nghttp3_qpack_stream *
nghttp3_qpack_encoder_find_stream(nghttp3_qpack_encoder * encoder,int64_t stream_id)1288 nghttp3_qpack_encoder_find_stream(nghttp3_qpack_encoder *encoder,
1289 int64_t stream_id) {
1290 return nghttp3_map_find(&encoder->streams, (nghttp3_map_key_type)stream_id);
1291 }
1292
nghttp3_qpack_encoder_stream_is_blocked(nghttp3_qpack_encoder * encoder,nghttp3_qpack_stream * stream)1293 int nghttp3_qpack_encoder_stream_is_blocked(nghttp3_qpack_encoder *encoder,
1294 nghttp3_qpack_stream *stream) {
1295 return stream && encoder->krcnt < nghttp3_qpack_stream_get_max_cnt(stream);
1296 }
1297
1298 /*
1299 * qpack_encoder_decide_indexing_mode determines and returns indexing
1300 * mode for header field |nv|. |token| is a token of header field
1301 * name.
1302 */
1303 static nghttp3_qpack_indexing_mode
qpack_encoder_decide_indexing_mode(nghttp3_qpack_encoder * encoder,const nghttp3_nv * nv,int32_t token)1304 qpack_encoder_decide_indexing_mode(nghttp3_qpack_encoder *encoder,
1305 const nghttp3_nv *nv, int32_t token) {
1306 if (nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) {
1307 return NGHTTP3_QPACK_INDEXING_MODE_NEVER;
1308 }
1309
1310 switch (token) {
1311 case NGHTTP3_QPACK_TOKEN_AUTHORIZATION:
1312 return NGHTTP3_QPACK_INDEXING_MODE_NEVER;
1313 case NGHTTP3_QPACK_TOKEN_COOKIE:
1314 if (nv->valuelen < 20) {
1315 return NGHTTP3_QPACK_INDEXING_MODE_NEVER;
1316 }
1317 break;
1318 case -1:
1319 case NGHTTP3_QPACK_TOKEN__PATH:
1320 case NGHTTP3_QPACK_TOKEN_AGE:
1321 case NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH:
1322 case NGHTTP3_QPACK_TOKEN_ETAG:
1323 case NGHTTP3_QPACK_TOKEN_IF_MODIFIED_SINCE:
1324 case NGHTTP3_QPACK_TOKEN_IF_NONE_MATCH:
1325 case NGHTTP3_QPACK_TOKEN_LOCATION:
1326 case NGHTTP3_QPACK_TOKEN_SET_COOKIE:
1327 return NGHTTP3_QPACK_INDEXING_MODE_LITERAL;
1328 case NGHTTP3_QPACK_TOKEN_HOST:
1329 case NGHTTP3_QPACK_TOKEN_TE:
1330 case NGHTTP3_QPACK_TOKEN__PROTOCOL:
1331 case NGHTTP3_QPACK_TOKEN_PRIORITY:
1332 break;
1333 default:
1334 if (token >= 1000) {
1335 return NGHTTP3_QPACK_INDEXING_MODE_LITERAL;
1336 }
1337 }
1338
1339 if (table_space(nv->namelen, nv->valuelen) >
1340 encoder->ctx.max_dtable_capacity * 3 / 4) {
1341 return NGHTTP3_QPACK_INDEXING_MODE_LITERAL;
1342 }
1343
1344 return NGHTTP3_QPACK_INDEXING_MODE_STORE;
1345 }
1346
1347 /*
1348 * qpack_encoder_can_index returns nonzero if an entry which occupies
1349 * |need| bytes can be inserted into dynamic table. |min_cnt| is the
1350 * minimum insert count which blocked stream requires.
1351 */
qpack_encoder_can_index(nghttp3_qpack_encoder * encoder,size_t need,uint64_t min_cnt)1352 static int qpack_encoder_can_index(nghttp3_qpack_encoder *encoder, size_t need,
1353 uint64_t min_cnt) {
1354 size_t avail = 0;
1355 size_t len;
1356 uint64_t gmin_cnt;
1357 nghttp3_qpack_entry *min_ent, *last_ent;
1358 nghttp3_ringbuf *dtable = &encoder->ctx.dtable;
1359
1360 if (encoder->ctx.max_dtable_capacity > encoder->ctx.dtable_size) {
1361 avail = encoder->ctx.max_dtable_capacity - encoder->ctx.dtable_size;
1362 if (need <= avail) {
1363 return 1;
1364 }
1365 }
1366
1367 if (!nghttp3_pq_empty(&encoder->min_cnts)) {
1368 gmin_cnt = nghttp3_qpack_encoder_get_min_cnt(encoder);
1369 min_cnt = nghttp3_min(min_cnt, gmin_cnt);
1370 }
1371
1372 if (min_cnt == UINT64_MAX) {
1373 return encoder->ctx.max_dtable_capacity >= need;
1374 }
1375
1376 min_ent = nghttp3_qpack_context_dtable_get(&encoder->ctx, min_cnt - 1);
1377
1378 len = nghttp3_ringbuf_len(&encoder->ctx.dtable);
1379 assert(len);
1380 last_ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(dtable, len - 1);
1381
1382 if (min_ent == last_ent) {
1383 return 0;
1384 }
1385
1386 return avail + min_ent->sum - last_ent->sum >= need;
1387 }
1388
1389 /*
1390 * qpack_encoder_can_index_nv returns nonzero if header field |nv| can
1391 * be inserted into dynamic table. |min_cnt| is the minimum insert
1392 * count which blocked stream requires.
1393 */
qpack_encoder_can_index_nv(nghttp3_qpack_encoder * encoder,const nghttp3_nv * nv,uint64_t min_cnt)1394 static int qpack_encoder_can_index_nv(nghttp3_qpack_encoder *encoder,
1395 const nghttp3_nv *nv, uint64_t min_cnt) {
1396 return qpack_encoder_can_index(
1397 encoder, table_space(nv->namelen, nv->valuelen), min_cnt);
1398 }
1399
1400 /*
1401 * qpack_encoder_can_index_duplicate returns nonzero if an entry at
1402 * |absidx| in dynamic table can be inserted to dynamic table as
1403 * duplicate. |min_cnt| is the minimum insert count which blocked
1404 * stream requires.
1405 */
qpack_encoder_can_index_duplicate(nghttp3_qpack_encoder * encoder,uint64_t absidx,uint64_t min_cnt)1406 static int qpack_encoder_can_index_duplicate(nghttp3_qpack_encoder *encoder,
1407 uint64_t absidx,
1408 uint64_t min_cnt) {
1409 nghttp3_qpack_entry *ent =
1410 nghttp3_qpack_context_dtable_get(&encoder->ctx, absidx);
1411
1412 return qpack_encoder_can_index(
1413 encoder, table_space(ent->nv.name->len, ent->nv.value->len), min_cnt);
1414 }
1415
1416 /*
1417 * qpack_context_check_draining returns nonzero if an entry at
1418 * |absidx| in dynamic table is one of draining entries.
1419 */
qpack_context_check_draining(nghttp3_qpack_context * ctx,uint64_t absidx)1420 static int qpack_context_check_draining(nghttp3_qpack_context *ctx,
1421 uint64_t absidx) {
1422 const size_t safe = ctx->max_dtable_capacity -
1423 nghttp3_min(512, ctx->max_dtable_capacity * 1 / 8);
1424 nghttp3_qpack_entry *ent = nghttp3_qpack_context_dtable_get(ctx, absidx);
1425
1426 return ctx->dtable_sum - ent->sum > safe;
1427 }
1428
nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder * encoder,uint64_t * pmax_cnt,uint64_t * pmin_cnt,nghttp3_buf * rbuf,nghttp3_buf * ebuf,const nghttp3_nv * nv,uint64_t base,int allow_blocking)1429 int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder,
1430 uint64_t *pmax_cnt, uint64_t *pmin_cnt,
1431 nghttp3_buf *rbuf, nghttp3_buf *ebuf,
1432 const nghttp3_nv *nv, uint64_t base,
1433 int allow_blocking) {
1434 uint32_t hash = 0;
1435 int32_t token;
1436 nghttp3_qpack_indexing_mode indexing_mode;
1437 nghttp3_qpack_lookup_result sres = {-1, 0, -1}, dres = {-1, 0, -1};
1438 nghttp3_qpack_entry *new_ent = NULL;
1439 int static_entry;
1440 int just_index = 0;
1441 int rv;
1442
1443 token = qpack_lookup_token(nv->name, nv->namelen);
1444 static_entry = token != -1 && (size_t)token < nghttp3_arraylen(token_stable);
1445 if (static_entry) {
1446 hash = token_stable[token].hash;
1447 } else {
1448 switch (token) {
1449 case NGHTTP3_QPACK_TOKEN_HOST:
1450 hash = 2952701295u;
1451 break;
1452 case NGHTTP3_QPACK_TOKEN_TE:
1453 hash = 1011170994u;
1454 break;
1455 case NGHTTP3_QPACK_TOKEN__PROTOCOL:
1456 hash = 1128642621u;
1457 break;
1458 case NGHTTP3_QPACK_TOKEN_PRIORITY:
1459 hash = 2498028297u;
1460 break;
1461 }
1462 }
1463
1464 indexing_mode = qpack_encoder_decide_indexing_mode(encoder, nv, token);
1465
1466 if (static_entry) {
1467 sres = nghttp3_qpack_lookup_stable(nv, token, indexing_mode);
1468 if (sres.index != -1 && sres.name_value_match) {
1469 return nghttp3_qpack_encoder_write_static_indexed(encoder, rbuf,
1470 (size_t)sres.index);
1471 }
1472 }
1473
1474 if (hash &&
1475 nghttp3_map_size(&encoder->streams) < NGHTTP3_QPACK_MAX_QPACK_STREAMS) {
1476 dres = nghttp3_qpack_encoder_lookup_dtable(encoder, nv, token, hash,
1477 indexing_mode, encoder->krcnt,
1478 allow_blocking);
1479 just_index = indexing_mode == NGHTTP3_QPACK_INDEXING_MODE_STORE &&
1480 dres.pb_index == -1;
1481 }
1482
1483 if (dres.index != -1 && dres.name_value_match) {
1484 if (allow_blocking &&
1485 qpack_context_check_draining(&encoder->ctx, (size_t)dres.index) &&
1486 qpack_encoder_can_index_duplicate(encoder, (size_t)dres.index,
1487 *pmin_cnt)) {
1488 rv = nghttp3_qpack_encoder_write_duplicate_insert(encoder, ebuf,
1489 (size_t)dres.index);
1490 if (rv != 0) {
1491 return rv;
1492 }
1493 rv = nghttp3_qpack_encoder_dtable_duplicate_add(encoder,
1494 (size_t)dres.index);
1495 if (rv != 0) {
1496 return rv;
1497 }
1498
1499 new_ent = nghttp3_qpack_context_dtable_top(&encoder->ctx);
1500 dres.index = (nghttp3_ssize)new_ent->absidx;
1501 }
1502 *pmax_cnt = nghttp3_max(*pmax_cnt, (size_t)(dres.index + 1));
1503 *pmin_cnt = nghttp3_min(*pmin_cnt, (size_t)(dres.index + 1));
1504
1505 return nghttp3_qpack_encoder_write_dynamic_indexed(
1506 encoder, rbuf, (size_t)dres.index, base);
1507 }
1508
1509 if (sres.index != -1) {
1510 if (just_index && qpack_encoder_can_index_nv(encoder, nv, *pmin_cnt)) {
1511 rv = nghttp3_qpack_encoder_write_static_insert(encoder, ebuf,
1512 (size_t)sres.index, nv);
1513 if (rv != 0) {
1514 return rv;
1515 }
1516 rv = nghttp3_qpack_encoder_dtable_static_add(encoder, (size_t)sres.index,
1517 nv, hash);
1518 if (rv != 0) {
1519 return rv;
1520 }
1521 if (allow_blocking) {
1522 new_ent = nghttp3_qpack_context_dtable_top(&encoder->ctx);
1523 *pmax_cnt = nghttp3_max(*pmax_cnt, new_ent->absidx + 1);
1524 *pmin_cnt = nghttp3_min(*pmin_cnt, new_ent->absidx + 1);
1525
1526 return nghttp3_qpack_encoder_write_dynamic_indexed(
1527 encoder, rbuf, new_ent->absidx, base);
1528 }
1529 }
1530
1531 return nghttp3_qpack_encoder_write_static_indexed_name(
1532 encoder, rbuf, (size_t)sres.index, nv);
1533 }
1534
1535 if (dres.index != -1) {
1536 if (just_index &&
1537 qpack_encoder_can_index_nv(
1538 encoder, nv,
1539 allow_blocking ? *pmin_cnt
1540 : nghttp3_min((size_t)dres.index + 1, *pmin_cnt))) {
1541 rv = nghttp3_qpack_encoder_write_dynamic_insert(encoder, ebuf,
1542 (size_t)dres.index, nv);
1543 if (rv != 0) {
1544 return rv;
1545 }
1546
1547 if (!allow_blocking) {
1548 *pmin_cnt = nghttp3_min(*pmin_cnt, (size_t)dres.index + 1);
1549 }
1550
1551 rv = nghttp3_qpack_encoder_dtable_dynamic_add(encoder, (size_t)dres.index,
1552 nv, hash);
1553 if (rv != 0) {
1554 return rv;
1555 }
1556
1557 if (allow_blocking) {
1558 new_ent = nghttp3_qpack_context_dtable_top(&encoder->ctx);
1559 *pmax_cnt = nghttp3_max(*pmax_cnt, new_ent->absidx + 1);
1560 *pmin_cnt = nghttp3_min(*pmin_cnt, new_ent->absidx + 1);
1561
1562 return nghttp3_qpack_encoder_write_dynamic_indexed(
1563 encoder, rbuf, new_ent->absidx, base);
1564 }
1565 }
1566
1567 *pmax_cnt = nghttp3_max(*pmax_cnt, (size_t)(dres.index + 1));
1568 *pmin_cnt = nghttp3_min(*pmin_cnt, (size_t)(dres.index + 1));
1569
1570 return nghttp3_qpack_encoder_write_dynamic_indexed_name(
1571 encoder, rbuf, (size_t)dres.index, base, nv);
1572 }
1573
1574 if (just_index && qpack_encoder_can_index_nv(encoder, nv, *pmin_cnt)) {
1575 rv = nghttp3_qpack_encoder_dtable_literal_add(encoder, nv, token, hash);
1576 if (rv != 0) {
1577 return rv;
1578 }
1579 rv = nghttp3_qpack_encoder_write_literal_insert(encoder, ebuf, nv);
1580 if (rv != 0) {
1581 return rv;
1582 }
1583 if (allow_blocking) {
1584 new_ent = nghttp3_qpack_context_dtable_top(&encoder->ctx);
1585 *pmax_cnt = nghttp3_max(*pmax_cnt, new_ent->absidx + 1);
1586 *pmin_cnt = nghttp3_min(*pmin_cnt, new_ent->absidx + 1);
1587
1588 return nghttp3_qpack_encoder_write_dynamic_indexed(encoder, rbuf,
1589 new_ent->absidx, base);
1590 }
1591 }
1592
1593 return nghttp3_qpack_encoder_write_literal(encoder, rbuf, nv);
1594 }
1595
1596 nghttp3_qpack_lookup_result
nghttp3_qpack_lookup_stable(const nghttp3_nv * nv,int32_t token,nghttp3_qpack_indexing_mode indexing_mode)1597 nghttp3_qpack_lookup_stable(const nghttp3_nv *nv, int32_t token,
1598 nghttp3_qpack_indexing_mode indexing_mode) {
1599 nghttp3_qpack_lookup_result res = {(nghttp3_ssize)token_stable[token].absidx,
1600 0, -1};
1601 nghttp3_qpack_static_entry *ent;
1602 nghttp3_qpack_static_header *hdr;
1603 size_t i;
1604
1605 assert(token >= 0);
1606
1607 if (indexing_mode == NGHTTP3_QPACK_INDEXING_MODE_NEVER) {
1608 return res;
1609 }
1610
1611 for (i = (size_t)token;
1612 i < nghttp3_arraylen(token_stable) && token_stable[i].token == token;
1613 ++i) {
1614 ent = &token_stable[i];
1615 hdr = &stable[ent->absidx];
1616 if (hdr->value.len == nv->valuelen &&
1617 memeq(hdr->value.base, nv->value, nv->valuelen)) {
1618 res.index = (nghttp3_ssize)ent->absidx;
1619 res.name_value_match = 1;
1620 return res;
1621 }
1622 }
1623 return res;
1624 }
1625
nghttp3_qpack_encoder_lookup_dtable(nghttp3_qpack_encoder * encoder,const nghttp3_nv * nv,int32_t token,uint32_t hash,nghttp3_qpack_indexing_mode indexing_mode,uint64_t krcnt,int allow_blocking)1626 nghttp3_qpack_lookup_result nghttp3_qpack_encoder_lookup_dtable(
1627 nghttp3_qpack_encoder *encoder, const nghttp3_nv *nv, int32_t token,
1628 uint32_t hash, nghttp3_qpack_indexing_mode indexing_mode, uint64_t krcnt,
1629 int allow_blocking) {
1630 nghttp3_qpack_lookup_result res = {-1, 0, -1};
1631 int exact_match = 0;
1632 nghttp3_qpack_entry *match, *pb_match;
1633
1634 encoder_qpack_map_find(encoder, &exact_match, &match, &pb_match, nv, token,
1635 hash, krcnt, allow_blocking,
1636 indexing_mode == NGHTTP3_QPACK_INDEXING_MODE_NEVER);
1637 if (match) {
1638 res.index = (nghttp3_ssize)match->absidx;
1639 res.name_value_match = exact_match;
1640 }
1641 if (pb_match) {
1642 res.pb_index = (nghttp3_ssize)pb_match->absidx;
1643 }
1644
1645 return res;
1646 }
1647
nghttp3_qpack_header_block_ref_new(nghttp3_qpack_header_block_ref ** pref,uint64_t max_cnt,uint64_t min_cnt,const nghttp3_mem * mem)1648 int nghttp3_qpack_header_block_ref_new(nghttp3_qpack_header_block_ref **pref,
1649 uint64_t max_cnt, uint64_t min_cnt,
1650 const nghttp3_mem *mem) {
1651 nghttp3_qpack_header_block_ref *ref =
1652 nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_header_block_ref));
1653
1654 if (ref == NULL) {
1655 return NGHTTP3_ERR_NOMEM;
1656 }
1657
1658 ref->max_cnts_pe.index = NGHTTP3_PQ_BAD_INDEX;
1659 ref->min_cnts_pe.index = NGHTTP3_PQ_BAD_INDEX;
1660 ref->max_cnt = max_cnt;
1661 ref->min_cnt = min_cnt;
1662
1663 *pref = ref;
1664
1665 return 0;
1666 }
1667
nghttp3_qpack_header_block_ref_del(nghttp3_qpack_header_block_ref * ref,const nghttp3_mem * mem)1668 void nghttp3_qpack_header_block_ref_del(nghttp3_qpack_header_block_ref *ref,
1669 const nghttp3_mem *mem) {
1670 nghttp3_mem_free(mem, ref);
1671 }
1672
ref_max_cnt_greater(const nghttp3_pq_entry * lhsx,const nghttp3_pq_entry * rhsx)1673 static int ref_max_cnt_greater(const nghttp3_pq_entry *lhsx,
1674 const nghttp3_pq_entry *rhsx) {
1675 const nghttp3_qpack_header_block_ref *lhs =
1676 nghttp3_struct_of(lhsx, nghttp3_qpack_header_block_ref, max_cnts_pe);
1677 const nghttp3_qpack_header_block_ref *rhs =
1678 nghttp3_struct_of(rhsx, nghttp3_qpack_header_block_ref, max_cnts_pe);
1679
1680 return lhs->max_cnt > rhs->max_cnt;
1681 }
1682
nghttp3_qpack_stream_new(nghttp3_qpack_stream ** pstream,int64_t stream_id,const nghttp3_mem * mem)1683 int nghttp3_qpack_stream_new(nghttp3_qpack_stream **pstream, int64_t stream_id,
1684 const nghttp3_mem *mem) {
1685 int rv;
1686 nghttp3_qpack_stream *stream;
1687
1688 stream = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream));
1689 if (stream == NULL) {
1690 return NGHTTP3_ERR_NOMEM;
1691 }
1692
1693 rv = nghttp3_ringbuf_init(&stream->refs, 4,
1694 sizeof(nghttp3_qpack_header_block_ref *), mem);
1695 if (rv != 0) {
1696 nghttp3_mem_free(mem, stream);
1697 return rv;
1698 }
1699
1700 nghttp3_pq_init(&stream->max_cnts, ref_max_cnt_greater, mem);
1701
1702 stream->stream_id = stream_id;
1703
1704 *pstream = stream;
1705
1706 return 0;
1707 }
1708
nghttp3_qpack_stream_del(nghttp3_qpack_stream * stream,const nghttp3_mem * mem)1709 void nghttp3_qpack_stream_del(nghttp3_qpack_stream *stream,
1710 const nghttp3_mem *mem) {
1711 nghttp3_qpack_header_block_ref *ref;
1712 size_t i, len;
1713
1714 if (stream == NULL) {
1715 return;
1716 }
1717
1718 nghttp3_pq_free(&stream->max_cnts);
1719
1720 len = nghttp3_ringbuf_len(&stream->refs);
1721 for (i = 0; i < len; ++i) {
1722 ref = *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs,
1723 i);
1724 nghttp3_qpack_header_block_ref_del(ref, mem);
1725 }
1726
1727 nghttp3_ringbuf_free(&stream->refs);
1728
1729 nghttp3_mem_free(mem, stream);
1730 }
1731
nghttp3_qpack_stream_get_max_cnt(const nghttp3_qpack_stream * stream)1732 uint64_t nghttp3_qpack_stream_get_max_cnt(const nghttp3_qpack_stream *stream) {
1733 nghttp3_qpack_header_block_ref *ref;
1734
1735 if (nghttp3_pq_empty(&stream->max_cnts)) {
1736 return 0;
1737 }
1738
1739 ref = nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts),
1740 nghttp3_qpack_header_block_ref, max_cnts_pe);
1741 return ref->max_cnt;
1742 }
1743
nghttp3_qpack_stream_add_ref(nghttp3_qpack_stream * stream,nghttp3_qpack_header_block_ref * ref)1744 int nghttp3_qpack_stream_add_ref(nghttp3_qpack_stream *stream,
1745 nghttp3_qpack_header_block_ref *ref) {
1746 nghttp3_qpack_header_block_ref **dest;
1747 int rv;
1748
1749 if (nghttp3_ringbuf_full(&stream->refs)) {
1750 rv = nghttp3_ringbuf_reserve(&stream->refs,
1751 nghttp3_ringbuf_len(&stream->refs) * 2);
1752 if (rv != 0) {
1753 return rv;
1754 }
1755 }
1756
1757 dest = nghttp3_ringbuf_push_back(&stream->refs);
1758 *dest = ref;
1759
1760 return nghttp3_pq_push(&stream->max_cnts, &ref->max_cnts_pe);
1761 }
1762
nghttp3_qpack_stream_pop_ref(nghttp3_qpack_stream * stream)1763 void nghttp3_qpack_stream_pop_ref(nghttp3_qpack_stream *stream) {
1764 nghttp3_qpack_header_block_ref *ref;
1765
1766 assert(nghttp3_ringbuf_len(&stream->refs));
1767
1768 ref =
1769 *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs, 0);
1770
1771 assert(ref->max_cnts_pe.index != NGHTTP3_PQ_BAD_INDEX);
1772
1773 nghttp3_pq_remove(&stream->max_cnts, &ref->max_cnts_pe);
1774
1775 nghttp3_ringbuf_pop_front(&stream->refs);
1776 }
1777
nghttp3_qpack_encoder_write_static_indexed(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,uint64_t absidx)1778 int nghttp3_qpack_encoder_write_static_indexed(nghttp3_qpack_encoder *encoder,
1779 nghttp3_buf *rbuf,
1780 uint64_t absidx) {
1781 DEBUGF("qpack::encode: Indexed Field Line (static) absidx=%" PRIu64 "\n",
1782 absidx);
1783 return qpack_write_number(rbuf, 0xc0, absidx, 6, encoder->ctx.mem);
1784 }
1785
nghttp3_qpack_encoder_write_dynamic_indexed(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,uint64_t absidx,uint64_t base)1786 int nghttp3_qpack_encoder_write_dynamic_indexed(nghttp3_qpack_encoder *encoder,
1787 nghttp3_buf *rbuf,
1788 uint64_t absidx,
1789 uint64_t base) {
1790 DEBUGF("qpack::encode: Indexed Field Line (dynamic) absidx=%" PRIu64
1791 " base=%" PRIu64 "\n",
1792 absidx, base);
1793
1794 if (absidx < base) {
1795 return qpack_write_number(rbuf, 0x80, base - absidx - 1, 6,
1796 encoder->ctx.mem);
1797 }
1798
1799 return qpack_write_number(rbuf, 0x10, absidx - base, 4, encoder->ctx.mem);
1800 }
1801
1802 /*
1803 * qpack_encoder_write_indexed_name writes generic indexed name. |fb|
1804 * is the first byte. |nameidx| is an index of referenced name.
1805 * |prefix| is a prefix of variable integer encoding. |nv| is a
1806 * header field to encode.
1807 *
1808 * This function returns 0 if it succeeds, or one of the following
1809 * negative error codes:
1810 *
1811 * NGHTTP3_ERR_NOMEM
1812 * Out of memory.
1813 */
qpack_encoder_write_indexed_name(nghttp3_qpack_encoder * encoder,nghttp3_buf * buf,uint8_t fb,uint64_t nameidx,size_t prefix,const nghttp3_nv * nv)1814 static int qpack_encoder_write_indexed_name(nghttp3_qpack_encoder *encoder,
1815 nghttp3_buf *buf, uint8_t fb,
1816 uint64_t nameidx, size_t prefix,
1817 const nghttp3_nv *nv) {
1818 int rv;
1819 size_t len = nghttp3_qpack_put_varint_len(nameidx, prefix);
1820 uint8_t *p;
1821 size_t hlen;
1822 int h = 0;
1823
1824 hlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen);
1825 if (hlen < nv->valuelen) {
1826 h = 1;
1827 len += nghttp3_qpack_put_varint_len(hlen, 7) + hlen;
1828 } else {
1829 len += nghttp3_qpack_put_varint_len(nv->valuelen, 7) + nv->valuelen;
1830 }
1831
1832 rv = reserve_buf(buf, len, encoder->ctx.mem);
1833 if (rv != 0) {
1834 return rv;
1835 }
1836
1837 p = buf->last;
1838
1839 *p = fb;
1840 p = nghttp3_qpack_put_varint(p, nameidx, prefix);
1841
1842 if (h) {
1843 *p = 0x80;
1844 p = nghttp3_qpack_put_varint(p, hlen, 7);
1845 p = nghttp3_qpack_huffman_encode(p, nv->value, nv->valuelen);
1846 } else {
1847 *p = 0;
1848 p = nghttp3_qpack_put_varint(p, nv->valuelen, 7);
1849 if (nv->valuelen) {
1850 p = nghttp3_cpymem(p, nv->value, nv->valuelen);
1851 }
1852 }
1853
1854 assert((size_t)(p - buf->last) == len);
1855
1856 buf->last = p;
1857
1858 return 0;
1859 }
1860
nghttp3_qpack_encoder_write_static_indexed_name(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,uint64_t absidx,const nghttp3_nv * nv)1861 int nghttp3_qpack_encoder_write_static_indexed_name(
1862 nghttp3_qpack_encoder *encoder, nghttp3_buf *rbuf, uint64_t absidx,
1863 const nghttp3_nv *nv) {
1864 uint8_t fb =
1865 (uint8_t)(0x50 | ((nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? 0x20 : 0));
1866
1867 DEBUGF("qpack::encode: Literal Field Line With Name Reference (static) "
1868 "absidx=%" PRIu64 " never=%d\n",
1869 absidx, (nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) != 0);
1870 return qpack_encoder_write_indexed_name(encoder, rbuf, fb, absidx, 4, nv);
1871 }
1872
nghttp3_qpack_encoder_write_dynamic_indexed_name(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,uint64_t absidx,uint64_t base,const nghttp3_nv * nv)1873 int nghttp3_qpack_encoder_write_dynamic_indexed_name(
1874 nghttp3_qpack_encoder *encoder, nghttp3_buf *rbuf, uint64_t absidx,
1875 uint64_t base, const nghttp3_nv *nv) {
1876 uint8_t fb;
1877
1878 DEBUGF("qpack::encode: Literal Field Line With Name Reference (dynamic) "
1879 "absidx=%" PRIu64 " base=%" PRIu64 " never=%d\n",
1880 absidx, base, (nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) != 0);
1881
1882 if (absidx < base) {
1883 fb = (uint8_t)(0x40 |
1884 ((nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? 0x20 : 0));
1885 return qpack_encoder_write_indexed_name(encoder, rbuf, fb,
1886 base - absidx - 1, 4, nv);
1887 }
1888
1889 fb = (nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? 0x08 : 0;
1890 return qpack_encoder_write_indexed_name(encoder, rbuf, fb, absidx - base, 3,
1891 nv);
1892 }
1893
1894 /*
1895 * qpack_encoder_write_literal writes generic literal header field
1896 * representation. |fb| is a first byte. |prefix| is a prefix of
1897 * variable integer encoding for name length. |nv| is a header field
1898 * to encode.
1899 *
1900 * This function returns 0 if it succeeds, or one of the following
1901 * negative error codes:
1902 *
1903 * NGHTTP3_ERR_NOMEM
1904 * Out of memory.
1905 */
qpack_encoder_write_literal(nghttp3_qpack_encoder * encoder,nghttp3_buf * buf,uint8_t fb,size_t prefix,const nghttp3_nv * nv)1906 static int qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder,
1907 nghttp3_buf *buf, uint8_t fb,
1908 size_t prefix, const nghttp3_nv *nv) {
1909 int rv;
1910 size_t len;
1911 uint8_t *p;
1912 size_t nhlen, vhlen;
1913 int nh = 0, vh = 0;
1914
1915 nhlen = nghttp3_qpack_huffman_encode_count(nv->name, nv->namelen);
1916 if (nhlen < nv->namelen) {
1917 nh = 1;
1918 len = nghttp3_qpack_put_varint_len(nhlen, prefix) + nhlen;
1919 } else {
1920 len = nghttp3_qpack_put_varint_len(nv->namelen, prefix) + nv->namelen;
1921 }
1922
1923 vhlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen);
1924 if (vhlen < nv->valuelen) {
1925 vh = 1;
1926 len += nghttp3_qpack_put_varint_len(vhlen, 7) + vhlen;
1927 } else {
1928 len += nghttp3_qpack_put_varint_len(nv->valuelen, 7) + nv->valuelen;
1929 }
1930
1931 rv = reserve_buf(buf, len, encoder->ctx.mem);
1932 if (rv != 0) {
1933 return rv;
1934 }
1935
1936 p = buf->last;
1937
1938 *p = fb;
1939 if (nh) {
1940 *p |= (uint8_t)(1 << prefix);
1941 p = nghttp3_qpack_put_varint(p, nhlen, prefix);
1942 p = nghttp3_qpack_huffman_encode(p, nv->name, nv->namelen);
1943 } else {
1944 p = nghttp3_qpack_put_varint(p, nv->namelen, prefix);
1945 if (nv->namelen) {
1946 p = nghttp3_cpymem(p, nv->name, nv->namelen);
1947 }
1948 }
1949
1950 *p = 0;
1951
1952 if (vh) {
1953 *p |= 0x80;
1954 p = nghttp3_qpack_put_varint(p, vhlen, 7);
1955 p = nghttp3_qpack_huffman_encode(p, nv->value, nv->valuelen);
1956 } else {
1957 p = nghttp3_qpack_put_varint(p, nv->valuelen, 7);
1958 if (nv->valuelen) {
1959 p = nghttp3_cpymem(p, nv->value, nv->valuelen);
1960 }
1961 }
1962
1963 assert((size_t)(p - buf->last) == len);
1964
1965 buf->last = p;
1966
1967 return 0;
1968 }
1969
nghttp3_qpack_encoder_write_literal(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,const nghttp3_nv * nv)1970 int nghttp3_qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder,
1971 nghttp3_buf *rbuf,
1972 const nghttp3_nv *nv) {
1973 uint8_t fb =
1974 (uint8_t)(0x20 | ((nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? 0x10 : 0));
1975
1976 DEBUGF("qpack::encode: Literal Field Line With Literal Name\n");
1977 return qpack_encoder_write_literal(encoder, rbuf, fb, 3, nv);
1978 }
1979
nghttp3_qpack_encoder_write_static_insert(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,uint64_t absidx,const nghttp3_nv * nv)1980 int nghttp3_qpack_encoder_write_static_insert(nghttp3_qpack_encoder *encoder,
1981 nghttp3_buf *ebuf,
1982 uint64_t absidx,
1983 const nghttp3_nv *nv) {
1984 DEBUGF("qpack::encode: Insert With Name Reference (static) absidx=%" PRIu64
1985 "\n",
1986 absidx);
1987 return qpack_encoder_write_indexed_name(encoder, ebuf, 0xc0, absidx, 6, nv);
1988 }
1989
nghttp3_qpack_encoder_write_dynamic_insert(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,uint64_t absidx,const nghttp3_nv * nv)1990 int nghttp3_qpack_encoder_write_dynamic_insert(nghttp3_qpack_encoder *encoder,
1991 nghttp3_buf *ebuf,
1992 uint64_t absidx,
1993 const nghttp3_nv *nv) {
1994 DEBUGF("qpack::encode: Insert With Name Reference (dynamic) absidx=%" PRIu64
1995 "\n",
1996 absidx);
1997 return qpack_encoder_write_indexed_name(
1998 encoder, ebuf, 0x80, encoder->ctx.next_absidx - absidx - 1, 6, nv);
1999 }
2000
nghttp3_qpack_encoder_write_duplicate_insert(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,uint64_t absidx)2001 int nghttp3_qpack_encoder_write_duplicate_insert(nghttp3_qpack_encoder *encoder,
2002 nghttp3_buf *ebuf,
2003 uint64_t absidx) {
2004 uint64_t idx = encoder->ctx.next_absidx - absidx - 1;
2005 size_t len = nghttp3_qpack_put_varint_len(idx, 5);
2006 uint8_t *p;
2007 int rv;
2008
2009 DEBUGF("qpack::encode: Insert duplicate absidx=%" PRIu64 "\n", absidx);
2010
2011 rv = reserve_buf(ebuf, len, encoder->ctx.mem);
2012 if (rv != 0) {
2013 return rv;
2014 }
2015
2016 p = ebuf->last;
2017
2018 *p = 0;
2019 p = nghttp3_qpack_put_varint(p, idx, 5);
2020
2021 assert((size_t)(p - ebuf->last) == len);
2022
2023 ebuf->last = p;
2024
2025 return 0;
2026 }
2027
nghttp3_qpack_encoder_write_literal_insert(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,const nghttp3_nv * nv)2028 int nghttp3_qpack_encoder_write_literal_insert(nghttp3_qpack_encoder *encoder,
2029 nghttp3_buf *ebuf,
2030 const nghttp3_nv *nv) {
2031 DEBUGF("qpack::encode: Insert With Literal Name\n");
2032 return qpack_encoder_write_literal(encoder, ebuf, 0x40, 5, nv);
2033 }
2034
nghttp3_qpack_context_dtable_add(nghttp3_qpack_context * ctx,nghttp3_qpack_nv * qnv,nghttp3_qpack_map * dtable_map,uint32_t hash)2035 int nghttp3_qpack_context_dtable_add(nghttp3_qpack_context *ctx,
2036 nghttp3_qpack_nv *qnv,
2037 nghttp3_qpack_map *dtable_map,
2038 uint32_t hash) {
2039 nghttp3_qpack_entry *new_ent, **p, *ent;
2040 const nghttp3_mem *mem = ctx->mem;
2041 size_t space;
2042 size_t i;
2043 int rv;
2044
2045 space = table_space(qnv->name->len, qnv->value->len);
2046
2047 assert(space <= ctx->max_dtable_capacity);
2048
2049 while (ctx->dtable_size + space > ctx->max_dtable_capacity) {
2050 i = nghttp3_ringbuf_len(&ctx->dtable);
2051 assert(i);
2052 ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, i - 1);
2053
2054 ctx->dtable_size -= table_space(ent->nv.name->len, ent->nv.value->len);
2055
2056 nghttp3_ringbuf_pop_back(&ctx->dtable);
2057 if (dtable_map) {
2058 qpack_map_remove(dtable_map, ent);
2059 }
2060
2061 nghttp3_qpack_entry_free(ent);
2062 nghttp3_mem_free(mem, ent);
2063 }
2064
2065 new_ent = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_entry));
2066 if (new_ent == NULL) {
2067 return NGHTTP3_ERR_NOMEM;
2068 }
2069
2070 nghttp3_qpack_entry_init(new_ent, qnv, ctx->dtable_sum, ctx->next_absidx++,
2071 hash);
2072
2073 if (nghttp3_ringbuf_full(&ctx->dtable)) {
2074 rv = nghttp3_ringbuf_reserve(&ctx->dtable,
2075 nghttp3_ringbuf_len(&ctx->dtable) * 2);
2076 if (rv != 0) {
2077 goto fail;
2078 }
2079 }
2080
2081 p = nghttp3_ringbuf_push_front(&ctx->dtable);
2082 *p = new_ent;
2083
2084 if (dtable_map) {
2085 qpack_map_insert(dtable_map, new_ent);
2086 }
2087
2088 ctx->dtable_size += space;
2089 ctx->dtable_sum += space;
2090
2091 return 0;
2092
2093 fail:
2094 nghttp3_qpack_entry_free(new_ent);
2095 nghttp3_mem_free(mem, new_ent);
2096
2097 return rv;
2098 }
2099
nghttp3_qpack_encoder_dtable_static_add(nghttp3_qpack_encoder * encoder,uint64_t absidx,const nghttp3_nv * nv,uint32_t hash)2100 int nghttp3_qpack_encoder_dtable_static_add(nghttp3_qpack_encoder *encoder,
2101 uint64_t absidx,
2102 const nghttp3_nv *nv,
2103 uint32_t hash) {
2104 const nghttp3_qpack_static_header *shd;
2105 nghttp3_qpack_nv qnv;
2106 const nghttp3_mem *mem = encoder->ctx.mem;
2107 int rv;
2108
2109 rv = nghttp3_rcbuf_new2(&qnv.value, nv->value, nv->valuelen, mem);
2110 if (rv != 0) {
2111 return rv;
2112 }
2113
2114 assert(nghttp3_arraylen(stable) > absidx);
2115
2116 shd = &stable[absidx];
2117
2118 qnv.name = (nghttp3_rcbuf *)&shd->name;
2119 qnv.token = shd->token;
2120 qnv.flags = NGHTTP3_NV_FLAG_NONE;
2121
2122 rv = nghttp3_qpack_context_dtable_add(&encoder->ctx, &qnv,
2123 &encoder->dtable_map, hash);
2124
2125 nghttp3_rcbuf_decref(qnv.value);
2126
2127 return rv;
2128 }
2129
nghttp3_qpack_encoder_dtable_dynamic_add(nghttp3_qpack_encoder * encoder,uint64_t absidx,const nghttp3_nv * nv,uint32_t hash)2130 int nghttp3_qpack_encoder_dtable_dynamic_add(nghttp3_qpack_encoder *encoder,
2131 uint64_t absidx,
2132 const nghttp3_nv *nv,
2133 uint32_t hash) {
2134 nghttp3_qpack_nv qnv;
2135 nghttp3_qpack_entry *ent;
2136 const nghttp3_mem *mem = encoder->ctx.mem;
2137 int rv;
2138
2139 rv = nghttp3_rcbuf_new2(&qnv.value, nv->value, nv->valuelen, mem);
2140 if (rv != 0) {
2141 return rv;
2142 }
2143
2144 ent = nghttp3_qpack_context_dtable_get(&encoder->ctx, absidx);
2145
2146 qnv.name = ent->nv.name;
2147 qnv.token = ent->nv.token;
2148 qnv.flags = NGHTTP3_NV_FLAG_NONE;
2149
2150 nghttp3_rcbuf_incref(qnv.name);
2151
2152 rv = nghttp3_qpack_context_dtable_add(&encoder->ctx, &qnv,
2153 &encoder->dtable_map, hash);
2154
2155 nghttp3_rcbuf_decref(qnv.value);
2156 nghttp3_rcbuf_decref(qnv.name);
2157
2158 return rv;
2159 }
2160
nghttp3_qpack_encoder_dtable_duplicate_add(nghttp3_qpack_encoder * encoder,uint64_t absidx)2161 int nghttp3_qpack_encoder_dtable_duplicate_add(nghttp3_qpack_encoder *encoder,
2162 uint64_t absidx) {
2163 nghttp3_qpack_nv qnv;
2164 nghttp3_qpack_entry *ent;
2165 int rv;
2166
2167 ent = nghttp3_qpack_context_dtable_get(&encoder->ctx, absidx);
2168
2169 qnv = ent->nv;
2170 nghttp3_rcbuf_incref(qnv.name);
2171 nghttp3_rcbuf_incref(qnv.value);
2172
2173 rv = nghttp3_qpack_context_dtable_add(&encoder->ctx, &qnv,
2174 &encoder->dtable_map, ent->hash);
2175
2176 nghttp3_rcbuf_decref(qnv.name);
2177 nghttp3_rcbuf_decref(qnv.value);
2178
2179 return rv;
2180 }
2181
nghttp3_qpack_encoder_dtable_literal_add(nghttp3_qpack_encoder * encoder,const nghttp3_nv * nv,int32_t token,uint32_t hash)2182 int nghttp3_qpack_encoder_dtable_literal_add(nghttp3_qpack_encoder *encoder,
2183 const nghttp3_nv *nv,
2184 int32_t token, uint32_t hash) {
2185 nghttp3_qpack_nv qnv;
2186 const nghttp3_mem *mem = encoder->ctx.mem;
2187 int rv;
2188
2189 rv = nghttp3_rcbuf_new2(&qnv.name, nv->name, nv->namelen, mem);
2190 if (rv != 0) {
2191 return rv;
2192 }
2193
2194 rv = nghttp3_rcbuf_new2(&qnv.value, nv->value, nv->valuelen, mem);
2195 if (rv != 0) {
2196 nghttp3_rcbuf_decref(qnv.name);
2197 return rv;
2198 }
2199
2200 qnv.token = token;
2201 qnv.flags = NGHTTP3_NV_FLAG_NONE;
2202
2203 rv = nghttp3_qpack_context_dtable_add(&encoder->ctx, &qnv,
2204 &encoder->dtable_map, hash);
2205
2206 nghttp3_rcbuf_decref(qnv.value);
2207 nghttp3_rcbuf_decref(qnv.name);
2208
2209 return rv;
2210 }
2211
2212 nghttp3_qpack_entry *
nghttp3_qpack_context_dtable_get(nghttp3_qpack_context * ctx,uint64_t absidx)2213 nghttp3_qpack_context_dtable_get(nghttp3_qpack_context *ctx, uint64_t absidx) {
2214 size_t relidx;
2215
2216 assert(ctx->next_absidx > absidx);
2217 assert(ctx->next_absidx - absidx - 1 < nghttp3_ringbuf_len(&ctx->dtable));
2218
2219 relidx = (size_t)(ctx->next_absidx - absidx - 1);
2220
2221 return *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, relidx);
2222 }
2223
2224 nghttp3_qpack_entry *
nghttp3_qpack_context_dtable_top(nghttp3_qpack_context * ctx)2225 nghttp3_qpack_context_dtable_top(nghttp3_qpack_context *ctx) {
2226 assert(nghttp3_ringbuf_len(&ctx->dtable));
2227 return *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, 0);
2228 }
2229
nghttp3_qpack_entry_init(nghttp3_qpack_entry * ent,nghttp3_qpack_nv * qnv,size_t sum,uint64_t absidx,uint32_t hash)2230 void nghttp3_qpack_entry_init(nghttp3_qpack_entry *ent, nghttp3_qpack_nv *qnv,
2231 size_t sum, uint64_t absidx, uint32_t hash) {
2232 ent->nv = *qnv;
2233 ent->map_next = NULL;
2234 ent->sum = sum;
2235 ent->absidx = absidx;
2236 ent->hash = hash;
2237
2238 nghttp3_rcbuf_incref(ent->nv.name);
2239 nghttp3_rcbuf_incref(ent->nv.value);
2240 }
2241
nghttp3_qpack_entry_free(nghttp3_qpack_entry * ent)2242 void nghttp3_qpack_entry_free(nghttp3_qpack_entry *ent) {
2243 nghttp3_rcbuf_decref(ent->nv.value);
2244 nghttp3_rcbuf_decref(ent->nv.name);
2245 }
2246
nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder * encoder,nghttp3_qpack_stream * stream)2247 int nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder *encoder,
2248 nghttp3_qpack_stream *stream) {
2249 nghttp3_blocked_streams_key bsk = {
2250 nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts),
2251 nghttp3_qpack_header_block_ref, max_cnts_pe)
2252 ->max_cnt,
2253 (uint64_t)stream->stream_id};
2254
2255 return nghttp3_ksl_insert(&encoder->blocked_streams, NULL, &bsk, stream);
2256 }
2257
nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder * encoder,nghttp3_qpack_stream * stream)2258 void nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder *encoder,
2259 nghttp3_qpack_stream *stream) {
2260 nghttp3_blocked_streams_key bsk = {
2261 nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts),
2262 nghttp3_qpack_header_block_ref, max_cnts_pe)
2263 ->max_cnt,
2264 (uint64_t)stream->stream_id};
2265 nghttp3_ksl_it it;
2266
2267 /* This is purely debugging purpose only */
2268 it = nghttp3_ksl_lower_bound(&encoder->blocked_streams, &bsk);
2269
2270 assert(!nghttp3_ksl_it_end(&it));
2271 assert(nghttp3_ksl_it_get(&it) == stream);
2272
2273 nghttp3_ksl_remove_hint(&encoder->blocked_streams, NULL, &it, &bsk);
2274 }
2275
nghttp3_qpack_encoder_unblock(nghttp3_qpack_encoder * encoder,uint64_t max_cnt)2276 void nghttp3_qpack_encoder_unblock(nghttp3_qpack_encoder *encoder,
2277 uint64_t max_cnt) {
2278 nghttp3_blocked_streams_key bsk = {max_cnt, 0};
2279 nghttp3_ksl_it it;
2280
2281 it = nghttp3_ksl_lower_bound(&encoder->blocked_streams, &bsk);
2282
2283 for (; !nghttp3_ksl_it_end(&it);) {
2284 bsk = *(nghttp3_blocked_streams_key *)nghttp3_ksl_it_key(&it);
2285 nghttp3_ksl_remove_hint(&encoder->blocked_streams, &it, &it, &bsk);
2286 }
2287 }
2288
nghttp3_qpack_encoder_ack_header(nghttp3_qpack_encoder * encoder,int64_t stream_id)2289 int nghttp3_qpack_encoder_ack_header(nghttp3_qpack_encoder *encoder,
2290 int64_t stream_id) {
2291 nghttp3_qpack_stream *stream =
2292 nghttp3_qpack_encoder_find_stream(encoder, stream_id);
2293 const nghttp3_mem *mem = encoder->ctx.mem;
2294 nghttp3_qpack_header_block_ref *ref;
2295
2296 if (stream == NULL) {
2297 return NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR;
2298 }
2299
2300 assert(nghttp3_ringbuf_len(&stream->refs));
2301
2302 ref =
2303 *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs, 0);
2304
2305 DEBUGF("qpack::encoder: Header acknowledgement stream=%ld ricnt=%" PRIu64
2306 " krcnt=%" PRIu64 "\n",
2307 stream_id, ref->max_cnt, encoder->krcnt);
2308
2309 if (encoder->krcnt < ref->max_cnt) {
2310 encoder->krcnt = ref->max_cnt;
2311
2312 nghttp3_qpack_encoder_unblock(encoder, ref->max_cnt);
2313 }
2314
2315 nghttp3_qpack_stream_pop_ref(stream);
2316
2317 assert(ref->min_cnts_pe.index != NGHTTP3_PQ_BAD_INDEX);
2318
2319 nghttp3_pq_remove(&encoder->min_cnts, &ref->min_cnts_pe);
2320
2321 nghttp3_qpack_header_block_ref_del(ref, mem);
2322
2323 if (nghttp3_ringbuf_len(&stream->refs)) {
2324 return 0;
2325 }
2326
2327 qpack_encoder_remove_stream(encoder, stream);
2328
2329 nghttp3_qpack_stream_del(stream, mem);
2330
2331 return 0;
2332 }
2333
nghttp3_qpack_encoder_add_icnt(nghttp3_qpack_encoder * encoder,uint64_t n)2334 int nghttp3_qpack_encoder_add_icnt(nghttp3_qpack_encoder *encoder, uint64_t n) {
2335 if (n == 0 || encoder->ctx.next_absidx - encoder->krcnt < n) {
2336 return NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR;
2337 }
2338 encoder->krcnt += n;
2339
2340 nghttp3_qpack_encoder_unblock(encoder, encoder->krcnt);
2341
2342 return 0;
2343 }
2344
nghttp3_qpack_encoder_ack_everything(nghttp3_qpack_encoder * encoder)2345 void nghttp3_qpack_encoder_ack_everything(nghttp3_qpack_encoder *encoder) {
2346 encoder->krcnt = encoder->ctx.next_absidx;
2347
2348 nghttp3_ksl_clear(&encoder->blocked_streams);
2349 nghttp3_pq_clear(&encoder->min_cnts);
2350 nghttp3_map_each_free(&encoder->streams, map_stream_free,
2351 (void *)encoder->ctx.mem);
2352 nghttp3_map_clear(&encoder->streams);
2353 }
2354
nghttp3_qpack_encoder_cancel_stream(nghttp3_qpack_encoder * encoder,int64_t stream_id)2355 void nghttp3_qpack_encoder_cancel_stream(nghttp3_qpack_encoder *encoder,
2356 int64_t stream_id) {
2357 nghttp3_qpack_stream *stream =
2358 nghttp3_qpack_encoder_find_stream(encoder, stream_id);
2359 const nghttp3_mem *mem = encoder->ctx.mem;
2360
2361 if (stream == NULL) {
2362 return;
2363 }
2364
2365 if (nghttp3_qpack_encoder_stream_is_blocked(encoder, stream)) {
2366 nghttp3_qpack_encoder_unblock_stream(encoder, stream);
2367 }
2368
2369 qpack_encoder_remove_stream(encoder, stream);
2370
2371 nghttp3_qpack_stream_del(stream, mem);
2372 }
2373
2374 size_t
nghttp3_qpack_encoder_get_num_blocked_streams(nghttp3_qpack_encoder * encoder)2375 nghttp3_qpack_encoder_get_num_blocked_streams(nghttp3_qpack_encoder *encoder) {
2376 return nghttp3_ksl_len(&encoder->blocked_streams);
2377 }
2378
nghttp3_qpack_encoder_write_field_section_prefix(nghttp3_qpack_encoder * encoder,nghttp3_buf * pbuf,uint64_t ricnt,uint64_t base)2379 int nghttp3_qpack_encoder_write_field_section_prefix(
2380 nghttp3_qpack_encoder *encoder, nghttp3_buf *pbuf, uint64_t ricnt,
2381 uint64_t base) {
2382 size_t max_ents =
2383 encoder->ctx.hard_max_dtable_capacity / NGHTTP3_QPACK_ENTRY_OVERHEAD;
2384 uint64_t encricnt = ricnt == 0 ? 0 : (ricnt % (2 * max_ents)) + 1;
2385 int sign = base < ricnt;
2386 uint64_t delta_base = sign ? ricnt - base - 1 : base - ricnt;
2387 size_t len = nghttp3_qpack_put_varint_len(encricnt, 8) +
2388 nghttp3_qpack_put_varint_len(delta_base, 7);
2389 uint8_t *p;
2390 int rv;
2391
2392 DEBUGF("qpack::encode: ricnt=%" PRIu64 " base=%" PRIu64 " icnt=%" PRIu64 "\n",
2393 ricnt, base, encoder->ctx.next_absidx);
2394
2395 rv = reserve_buf(pbuf, len, encoder->ctx.mem);
2396 if (rv != 0) {
2397 return rv;
2398 }
2399
2400 p = pbuf->last;
2401
2402 p = nghttp3_qpack_put_varint(p, encricnt, 8);
2403 if (sign) {
2404 *p = 0x80;
2405 } else {
2406 *p = 0;
2407 }
2408 p = nghttp3_qpack_put_varint(p, delta_base, 7);
2409
2410 assert((size_t)(p - pbuf->last) == len);
2411
2412 pbuf->last = p;
2413
2414 return 0;
2415 }
2416
2417 /*
2418 * qpack_read_varint reads |rstate->prefix| prefixed integer stored
2419 * from |begin|. The |end| represents the 1 beyond the last of the
2420 * valid contiguous memory region from |begin|. The decoded integer
2421 * must be less than or equal to NGHTTP3_QPACK_INT_MAX.
2422 *
2423 * If the |rstate->left| is nonzero, it is used as an initial value,
2424 * and this function assumes the |begin| starts with intermediate
2425 * data. |rstate->shift| is used as initial integer shift.
2426 *
2427 * If an entire integer is decoded successfully, the |*fin| is set to
2428 * nonzero.
2429 *
2430 * This function stores the decoded integer in |rstate->left| if it
2431 * succeeds, including partial decoding (in this case, number of shift
2432 * to make in the next call will be stored in |rstate->shift|) and
2433 * returns number of bytes processed, or returns negative error code
2434 * NGHTTP3_ERR_QPACK_FATAL, indicating decoding error.
2435 */
qpack_read_varint(int * fin,nghttp3_qpack_read_state * rstate,const uint8_t * begin,const uint8_t * end)2436 static nghttp3_ssize qpack_read_varint(int *fin,
2437 nghttp3_qpack_read_state *rstate,
2438 const uint8_t *begin,
2439 const uint8_t *end) {
2440 uint64_t k = (uint8_t)((1 << rstate->prefix) - 1);
2441 uint64_t n = rstate->left;
2442 uint64_t add;
2443 const uint8_t *p = begin;
2444 size_t shift = rstate->shift;
2445
2446 rstate->shift = 0;
2447 *fin = 0;
2448
2449 if (n == 0) {
2450 if (((*p) & k) != k) {
2451 rstate->left = (*p) & k;
2452 *fin = 1;
2453 return 1;
2454 }
2455
2456 n = k;
2457
2458 if (++p == end) {
2459 rstate->left = n;
2460 return (nghttp3_ssize)(p - begin);
2461 }
2462 }
2463
2464 for (; p != end; ++p, shift += 7) {
2465 add = (*p) & 0x7f;
2466
2467 if (shift > 62) {
2468 return NGHTTP3_ERR_QPACK_FATAL;
2469 }
2470
2471 if ((NGHTTP3_QPACK_INT_MAX >> shift) < add) {
2472 return NGHTTP3_ERR_QPACK_FATAL;
2473 }
2474
2475 add <<= shift;
2476
2477 if (NGHTTP3_QPACK_INT_MAX - add < n) {
2478 return NGHTTP3_ERR_QPACK_FATAL;
2479 }
2480
2481 n += add;
2482
2483 if (((*p) & (1 << 7)) == 0) {
2484 break;
2485 }
2486 }
2487
2488 rstate->shift = shift;
2489
2490 if (p == end) {
2491 rstate->left = n;
2492 return (nghttp3_ssize)(p - begin);
2493 }
2494
2495 rstate->left = n;
2496 *fin = 1;
2497 return (nghttp3_ssize)(p + 1 - begin);
2498 }
2499
nghttp3_qpack_encoder_read_decoder(nghttp3_qpack_encoder * encoder,const uint8_t * src,size_t srclen)2500 nghttp3_ssize nghttp3_qpack_encoder_read_decoder(nghttp3_qpack_encoder *encoder,
2501 const uint8_t *src,
2502 size_t srclen) {
2503 const uint8_t *p = src, *end;
2504 int rv;
2505 nghttp3_ssize nread;
2506 int rfin;
2507
2508 if (encoder->ctx.bad) {
2509 return NGHTTP3_ERR_QPACK_FATAL;
2510 }
2511
2512 if (srclen == 0) {
2513 return 0;
2514 }
2515
2516 end = src + srclen;
2517
2518 for (; p != end;) {
2519 switch (encoder->state) {
2520 case NGHTTP3_QPACK_DS_STATE_OPCODE:
2521 if ((*p) & 0x80) {
2522 DEBUGF("qpack::encode: OPCODE_SECTION_ACK\n");
2523 encoder->opcode = NGHTTP3_QPACK_DS_OPCODE_SECTION_ACK;
2524 encoder->rstate.prefix = 7;
2525 } else if ((*p) & 0x40) {
2526 DEBUGF("qpack::encode: OPCODE_STREAM_CANCEL\n");
2527 encoder->opcode = NGHTTP3_QPACK_DS_OPCODE_STREAM_CANCEL;
2528 encoder->rstate.prefix = 6;
2529 } else {
2530 DEBUGF("qpack::encode: OPCODE_ICNT_INCREMENT\n");
2531 encoder->opcode = NGHTTP3_QPACK_DS_OPCODE_ICNT_INCREMENT;
2532 encoder->rstate.prefix = 6;
2533 }
2534 encoder->state = NGHTTP3_QPACK_DS_STATE_READ_NUMBER;
2535 /* fall through */
2536 case NGHTTP3_QPACK_DS_STATE_READ_NUMBER:
2537 nread = qpack_read_varint(&rfin, &encoder->rstate, p, end);
2538 if (nread < 0) {
2539 assert(nread == NGHTTP3_ERR_QPACK_FATAL);
2540 rv = NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR;
2541 goto fail;
2542 }
2543
2544 p += nread;
2545
2546 if (!rfin) {
2547 return p - src;
2548 }
2549
2550 switch (encoder->opcode) {
2551 case NGHTTP3_QPACK_DS_OPCODE_ICNT_INCREMENT:
2552 rv = nghttp3_qpack_encoder_add_icnt(encoder, encoder->rstate.left);
2553 if (rv != 0) {
2554 goto fail;
2555 }
2556 break;
2557 case NGHTTP3_QPACK_DS_OPCODE_SECTION_ACK:
2558 rv = nghttp3_qpack_encoder_ack_header(encoder,
2559 (int64_t)encoder->rstate.left);
2560 if (rv != 0) {
2561 goto fail;
2562 }
2563 break;
2564 case NGHTTP3_QPACK_DS_OPCODE_STREAM_CANCEL:
2565 nghttp3_qpack_encoder_cancel_stream(encoder,
2566 (int64_t)encoder->rstate.left);
2567 break;
2568 default:
2569 /* unreachable */
2570 assert(0);
2571 break;
2572 }
2573
2574 encoder->state = NGHTTP3_QPACK_DS_STATE_OPCODE;
2575 nghttp3_qpack_read_state_reset(&encoder->rstate);
2576 break;
2577 default:
2578 /* unreachable */
2579 assert(0);
2580 break;
2581 }
2582 }
2583
2584 return p - src;
2585
2586 fail:
2587 encoder->ctx.bad = 1;
2588 return rv;
2589 }
2590
nghttp3_qpack_put_varint_len(uint64_t n,size_t prefix)2591 size_t nghttp3_qpack_put_varint_len(uint64_t n, size_t prefix) {
2592 size_t k = (size_t)((1 << prefix) - 1);
2593 size_t len = 0;
2594
2595 if (n < k) {
2596 return 1;
2597 }
2598
2599 n -= k;
2600 ++len;
2601
2602 for (; n >= 128; n >>= 7, ++len)
2603 ;
2604
2605 return len + 1;
2606 }
2607
nghttp3_qpack_put_varint(uint8_t * buf,uint64_t n,size_t prefix)2608 uint8_t *nghttp3_qpack_put_varint(uint8_t *buf, uint64_t n, size_t prefix) {
2609 size_t k = (size_t)((1 << prefix) - 1);
2610
2611 *buf = (uint8_t)(*buf & ~k);
2612
2613 if (n < k) {
2614 *buf = (uint8_t)(*buf | n);
2615 return buf + 1;
2616 }
2617
2618 *buf = (uint8_t)(*buf | k);
2619 ++buf;
2620
2621 n -= k;
2622
2623 for (; n >= 128; n >>= 7) {
2624 *buf++ = (uint8_t)((1 << 7) | (n & 0x7f));
2625 }
2626
2627 *buf++ = (uint8_t)n;
2628
2629 return buf;
2630 }
2631
nghttp3_qpack_read_state_free(nghttp3_qpack_read_state * rstate)2632 void nghttp3_qpack_read_state_free(nghttp3_qpack_read_state *rstate) {
2633 nghttp3_rcbuf_decref(rstate->value);
2634 nghttp3_rcbuf_decref(rstate->name);
2635 }
2636
nghttp3_qpack_read_state_reset(nghttp3_qpack_read_state * rstate)2637 void nghttp3_qpack_read_state_reset(nghttp3_qpack_read_state *rstate) {
2638 rstate->name = NULL;
2639 rstate->value = NULL;
2640 nghttp3_buf_init(&rstate->namebuf);
2641 nghttp3_buf_init(&rstate->valuebuf);
2642 rstate->left = 0;
2643 rstate->prefix = 0;
2644 rstate->shift = 0;
2645 rstate->absidx = 0;
2646 rstate->never = 0;
2647 rstate->dynamic = 0;
2648 rstate->huffman_encoded = 0;
2649 }
2650
nghttp3_qpack_decoder_init(nghttp3_qpack_decoder * decoder,size_t max_dtable_capacity,size_t max_blocked_streams,const nghttp3_mem * mem)2651 int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder,
2652 size_t max_dtable_capacity,
2653 size_t max_blocked_streams,
2654 const nghttp3_mem *mem) {
2655 int rv;
2656
2657 rv = qpack_context_init(&decoder->ctx, max_dtable_capacity,
2658 max_blocked_streams, mem);
2659 if (rv != 0) {
2660 return rv;
2661 }
2662
2663 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
2664 decoder->opcode = 0;
2665 decoder->written_icnt = 0;
2666 decoder->max_concurrent_streams = 0;
2667
2668 nghttp3_qpack_read_state_reset(&decoder->rstate);
2669 nghttp3_buf_init(&decoder->dbuf);
2670
2671 return 0;
2672 }
2673
nghttp3_qpack_decoder_free(nghttp3_qpack_decoder * decoder)2674 void nghttp3_qpack_decoder_free(nghttp3_qpack_decoder *decoder) {
2675 nghttp3_buf_free(&decoder->dbuf, decoder->ctx.mem);
2676 nghttp3_qpack_read_state_free(&decoder->rstate);
2677 qpack_context_free(&decoder->ctx);
2678 }
2679
2680 /*
2681 * qpack_read_huffman_string decodes huffman string in buffer [begin,
2682 * end) and writes the decoded string to |dest|. This function
2683 * assumes the buffer pointed by |dest| has enough space.
2684 *
2685 * This function returns 0 if it succeeds, or one of the following
2686 * negative error codes:
2687 *
2688 * NGHTTP3_ERR_QPACK_FATAL
2689 * Could not decode huffman string.
2690 */
qpack_read_huffman_string(nghttp3_qpack_read_state * rstate,nghttp3_buf * dest,const uint8_t * begin,const uint8_t * end)2691 static nghttp3_ssize qpack_read_huffman_string(nghttp3_qpack_read_state *rstate,
2692 nghttp3_buf *dest,
2693 const uint8_t *begin,
2694 const uint8_t *end) {
2695 nghttp3_ssize nwrite;
2696 size_t len = (size_t)(end - begin);
2697 int fin = 0;
2698
2699 if (len >= rstate->left) {
2700 len = (size_t)rstate->left;
2701 fin = 1;
2702 }
2703
2704 nwrite = nghttp3_qpack_huffman_decode(&rstate->huffman_ctx, dest->last, begin,
2705 len, fin);
2706 if (nwrite < 0) {
2707 return nwrite;
2708 }
2709
2710 if (nghttp3_qpack_huffman_decode_failure_state(&rstate->huffman_ctx)) {
2711 return NGHTTP3_ERR_QPACK_FATAL;
2712 }
2713
2714 dest->last += nwrite;
2715 rstate->left -= len;
2716 return (nghttp3_ssize)len;
2717 }
2718
qpack_read_string(nghttp3_qpack_read_state * rstate,nghttp3_buf * dest,const uint8_t * begin,const uint8_t * end)2719 static nghttp3_ssize qpack_read_string(nghttp3_qpack_read_state *rstate,
2720 nghttp3_buf *dest, const uint8_t *begin,
2721 const uint8_t *end) {
2722 size_t len = (size_t)(end - begin);
2723 size_t n = (size_t)nghttp3_min((uint64_t)len, rstate->left);
2724
2725 dest->last = nghttp3_cpymem(dest->last, begin, n);
2726
2727 rstate->left -= n;
2728 return (nghttp3_ssize)n;
2729 }
2730
2731 /*
2732 * qpack_decoder_validate_index checks rstate->absidx is acceptable.
2733 *
2734 * It returns 0 if it suceeds, or one of the following negative error
2735 * codes:
2736 *
2737 * NGHTTP3_ERR_QPACK_FATAL
2738 * rstate->absidx is invalid.
2739 */
qpack_decoder_validate_index(nghttp3_qpack_decoder * decoder,nghttp3_qpack_read_state * rstate)2740 static int qpack_decoder_validate_index(nghttp3_qpack_decoder *decoder,
2741 nghttp3_qpack_read_state *rstate) {
2742 if (rstate->dynamic) {
2743 return rstate->absidx < decoder->ctx.next_absidx &&
2744 decoder->ctx.next_absidx - rstate->absidx - 1 <
2745 nghttp3_ringbuf_len(&decoder->ctx.dtable)
2746 ? 0
2747 : NGHTTP3_ERR_QPACK_FATAL;
2748 }
2749 return rstate->absidx < nghttp3_arraylen(stable) ? 0
2750 : NGHTTP3_ERR_QPACK_FATAL;
2751 }
2752
qpack_read_state_check_huffman(nghttp3_qpack_read_state * rstate,const uint8_t b)2753 static void qpack_read_state_check_huffman(nghttp3_qpack_read_state *rstate,
2754 const uint8_t b) {
2755 rstate->huffman_encoded = (b & (1 << rstate->prefix)) != 0;
2756 }
2757
qpack_read_state_terminate_name(nghttp3_qpack_read_state * rstate)2758 static void qpack_read_state_terminate_name(nghttp3_qpack_read_state *rstate) {
2759 *rstate->namebuf.last = '\0';
2760 rstate->name->len = nghttp3_buf_len(&rstate->namebuf);
2761 }
2762
qpack_read_state_terminate_value(nghttp3_qpack_read_state * rstate)2763 static void qpack_read_state_terminate_value(nghttp3_qpack_read_state *rstate) {
2764 *rstate->valuebuf.last = '\0';
2765 rstate->value->len = nghttp3_buf_len(&rstate->valuebuf);
2766 }
2767
nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder * decoder,const uint8_t * src,size_t srclen)2768 nghttp3_ssize nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder *decoder,
2769 const uint8_t *src,
2770 size_t srclen) {
2771 const uint8_t *p = src, *end;
2772 int rv;
2773 int busy = 0;
2774 const nghttp3_mem *mem = decoder->ctx.mem;
2775 nghttp3_ssize nread;
2776 int rfin;
2777
2778 if (decoder->ctx.bad) {
2779 return NGHTTP3_ERR_QPACK_FATAL;
2780 }
2781
2782 if (srclen == 0) {
2783 return 0;
2784 }
2785
2786 end = src + srclen;
2787
2788 for (; p != end || busy;) {
2789 busy = 0;
2790 switch (decoder->state) {
2791 case NGHTTP3_QPACK_ES_STATE_OPCODE:
2792 if ((*p) & 0x80) {
2793 DEBUGF("qpack::decode: OPCODE_INSERT_INDEXED\n");
2794 decoder->opcode = NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED;
2795 decoder->rstate.dynamic = !((*p) & 0x40);
2796 decoder->rstate.prefix = 6;
2797 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_INDEX;
2798 } else if ((*p) & 0x40) {
2799 DEBUGF("qpack::decode: OPCODE_INSERT\n");
2800 decoder->opcode = NGHTTP3_QPACK_ES_OPCODE_INSERT;
2801 decoder->rstate.dynamic = 0;
2802 decoder->rstate.prefix = 5;
2803 decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_NAME_HUFFMAN;
2804 } else if ((*p) & 0x20) {
2805 DEBUGF("qpack::decode: OPCODE_SET_DTABLE_TABLE_CAP\n");
2806 decoder->opcode = NGHTTP3_QPACK_ES_OPCODE_SET_DTABLE_CAP;
2807 decoder->rstate.prefix = 5;
2808 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_INDEX;
2809 } else if (!((*p) & 0x20)) {
2810 DEBUGF("qpack::decode: OPCODE_DUPLICATE\n");
2811 decoder->opcode = NGHTTP3_QPACK_ES_OPCODE_DUPLICATE;
2812 decoder->rstate.dynamic = 1;
2813 decoder->rstate.prefix = 5;
2814 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_INDEX;
2815 } else {
2816 DEBUGF("qpack::decode: unknown opcode %02x\n", *p);
2817 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2818 goto fail;
2819 }
2820 break;
2821 case NGHTTP3_QPACK_ES_STATE_READ_INDEX:
2822 nread = qpack_read_varint(&rfin, &decoder->rstate, p, end);
2823 if (nread < 0) {
2824 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
2825 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2826 goto fail;
2827 }
2828
2829 p += nread;
2830
2831 if (!rfin) {
2832 return p - src;
2833 }
2834
2835 if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_SET_DTABLE_CAP) {
2836 if (decoder->rstate.left > decoder->ctx.hard_max_dtable_capacity) {
2837 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2838 goto fail;
2839 }
2840 DEBUGF("qpack::decode: Set dtable capacity to %" PRIu64 "\n",
2841 decoder->rstate.left);
2842 nghttp3_qpack_decoder_set_max_dtable_capacity(
2843 decoder, (size_t)decoder->rstate.left);
2844
2845 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
2846 nghttp3_qpack_read_state_reset(&decoder->rstate);
2847 break;
2848 }
2849
2850 rv = nghttp3_qpack_decoder_rel2abs(decoder, &decoder->rstate);
2851 if (rv < 0) {
2852 goto fail;
2853 }
2854
2855 if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_DUPLICATE) {
2856 rv = nghttp3_qpack_decoder_dtable_duplicate_add(decoder);
2857 if (rv != 0) {
2858 goto fail;
2859 }
2860 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
2861 nghttp3_qpack_read_state_reset(&decoder->rstate);
2862 break;
2863 }
2864
2865 if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED) {
2866 decoder->rstate.prefix = 7;
2867 decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN;
2868 break;
2869 }
2870
2871 /* Unreachable */
2872 assert(0);
2873 break;
2874 case NGHTTP3_QPACK_ES_STATE_CHECK_NAME_HUFFMAN:
2875 qpack_read_state_check_huffman(&decoder->rstate, *p);
2876 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_NAMELEN;
2877 decoder->rstate.left = 0;
2878 decoder->rstate.shift = 0;
2879 /* Fall through */
2880 case NGHTTP3_QPACK_ES_STATE_READ_NAMELEN:
2881 nread = qpack_read_varint(&rfin, &decoder->rstate, p, end);
2882 if (nread < 0) {
2883 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
2884 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2885 goto fail;
2886 }
2887
2888 p += nread;
2889
2890 if (!rfin) {
2891 return p - src;
2892 }
2893
2894 if (decoder->rstate.left > NGHTTP3_QPACK_MAX_NAMELEN) {
2895 rv = NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE;
2896 goto fail;
2897 }
2898
2899 if (decoder->rstate.huffman_encoded) {
2900 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_NAME_HUFFMAN;
2901 nghttp3_qpack_huffman_decode_context_init(&decoder->rstate.huffman_ctx);
2902 rv = nghttp3_rcbuf_new(&decoder->rstate.name,
2903 (size_t)decoder->rstate.left * 2 + 1, mem);
2904 } else {
2905 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_NAME;
2906 rv = nghttp3_rcbuf_new(&decoder->rstate.name,
2907 (size_t)decoder->rstate.left + 1, mem);
2908 }
2909 if (rv != 0) {
2910 goto fail;
2911 }
2912
2913 nghttp3_buf_wrap_init(&decoder->rstate.namebuf,
2914 decoder->rstate.name->base,
2915 decoder->rstate.name->len);
2916 break;
2917 case NGHTTP3_QPACK_ES_STATE_READ_NAME_HUFFMAN:
2918 nread = qpack_read_huffman_string(&decoder->rstate,
2919 &decoder->rstate.namebuf, p, end);
2920 if (nread < 0) {
2921 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
2922 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2923 goto fail;
2924 }
2925
2926 p += nread;
2927
2928 if (decoder->rstate.left) {
2929 return p - src;
2930 }
2931
2932 qpack_read_state_terminate_name(&decoder->rstate);
2933
2934 decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN;
2935 decoder->rstate.prefix = 7;
2936 break;
2937 case NGHTTP3_QPACK_ES_STATE_READ_NAME:
2938 nread =
2939 qpack_read_string(&decoder->rstate, &decoder->rstate.namebuf, p, end);
2940 if (nread < 0) {
2941 rv = (int)nread;
2942 goto fail;
2943 }
2944
2945 p += nread;
2946
2947 if (decoder->rstate.left) {
2948 return p - src;
2949 }
2950
2951 qpack_read_state_terminate_name(&decoder->rstate);
2952
2953 decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN;
2954 decoder->rstate.prefix = 7;
2955 break;
2956 case NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN:
2957 qpack_read_state_check_huffman(&decoder->rstate, *p);
2958 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_VALUELEN;
2959 decoder->rstate.left = 0;
2960 decoder->rstate.shift = 0;
2961 /* Fall through */
2962 case NGHTTP3_QPACK_ES_STATE_READ_VALUELEN:
2963 nread = qpack_read_varint(&rfin, &decoder->rstate, p, end);
2964 if (nread < 0) {
2965 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
2966 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2967 goto fail;
2968 }
2969
2970 p += nread;
2971
2972 if (!rfin) {
2973 return p - src;
2974 }
2975
2976 if (decoder->rstate.left > NGHTTP3_QPACK_MAX_VALUELEN) {
2977 rv = NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE;
2978 goto fail;
2979 }
2980
2981 if (decoder->rstate.huffman_encoded) {
2982 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_VALUE_HUFFMAN;
2983 nghttp3_qpack_huffman_decode_context_init(&decoder->rstate.huffman_ctx);
2984 rv = nghttp3_rcbuf_new(&decoder->rstate.value,
2985 (size_t)decoder->rstate.left * 2 + 1, mem);
2986 } else {
2987 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_VALUE;
2988 rv = nghttp3_rcbuf_new(&decoder->rstate.value,
2989 (size_t)decoder->rstate.left + 1, mem);
2990 }
2991 if (rv != 0) {
2992 goto fail;
2993 }
2994
2995 nghttp3_buf_wrap_init(&decoder->rstate.valuebuf,
2996 decoder->rstate.value->base,
2997 decoder->rstate.value->len);
2998
2999 /* value might be 0 length */
3000 busy = 1;
3001 break;
3002 case NGHTTP3_QPACK_ES_STATE_READ_VALUE_HUFFMAN:
3003 nread = qpack_read_huffman_string(&decoder->rstate,
3004 &decoder->rstate.valuebuf, p, end);
3005 if (nread < 0) {
3006 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3007 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3008 goto fail;
3009 }
3010
3011 p += nread;
3012
3013 if (decoder->rstate.left) {
3014 return p - src;
3015 }
3016
3017 qpack_read_state_terminate_value(&decoder->rstate);
3018
3019 switch (decoder->opcode) {
3020 case NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED:
3021 rv = nghttp3_qpack_decoder_dtable_indexed_add(decoder);
3022 break;
3023 case NGHTTP3_QPACK_ES_OPCODE_INSERT:
3024 rv = nghttp3_qpack_decoder_dtable_literal_add(decoder);
3025 break;
3026 default:
3027 /* Unreachable */
3028 assert(0);
3029 abort();
3030 }
3031 if (rv != 0) {
3032 goto fail;
3033 }
3034
3035 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
3036 nghttp3_qpack_read_state_reset(&decoder->rstate);
3037 break;
3038 case NGHTTP3_QPACK_ES_STATE_READ_VALUE:
3039 nread = qpack_read_string(&decoder->rstate, &decoder->rstate.valuebuf, p,
3040 end);
3041 if (nread < 0) {
3042 rv = (int)nread;
3043 goto fail;
3044 }
3045
3046 p += nread;
3047
3048 if (decoder->rstate.left) {
3049 return p - src;
3050 }
3051
3052 qpack_read_state_terminate_value(&decoder->rstate);
3053
3054 switch (decoder->opcode) {
3055 case NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED:
3056 rv = nghttp3_qpack_decoder_dtable_indexed_add(decoder);
3057 break;
3058 case NGHTTP3_QPACK_ES_OPCODE_INSERT:
3059 rv = nghttp3_qpack_decoder_dtable_literal_add(decoder);
3060 break;
3061 default:
3062 /* Unreachable */
3063 assert(0);
3064 abort();
3065 }
3066 if (rv != 0) {
3067 goto fail;
3068 }
3069
3070 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
3071 nghttp3_qpack_read_state_reset(&decoder->rstate);
3072 break;
3073 }
3074 }
3075
3076 return p - src;
3077
3078 fail:
3079 decoder->ctx.bad = 1;
3080 return rv;
3081 }
3082
nghttp3_qpack_decoder_set_max_dtable_capacity(nghttp3_qpack_decoder * decoder,size_t max_dtable_capacity)3083 void nghttp3_qpack_decoder_set_max_dtable_capacity(
3084 nghttp3_qpack_decoder *decoder, size_t max_dtable_capacity) {
3085 nghttp3_qpack_entry *ent;
3086 size_t i;
3087 nghttp3_qpack_context *ctx = &decoder->ctx;
3088 const nghttp3_mem *mem = ctx->mem;
3089
3090 ctx->max_dtable_capacity = max_dtable_capacity;
3091
3092 while (ctx->dtable_size > max_dtable_capacity) {
3093 i = nghttp3_ringbuf_len(&ctx->dtable);
3094 assert(i);
3095 ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, i - 1);
3096
3097 ctx->dtable_size -= table_space(ent->nv.name->len, ent->nv.value->len);
3098
3099 nghttp3_ringbuf_pop_back(&ctx->dtable);
3100 nghttp3_qpack_entry_free(ent);
3101 nghttp3_mem_free(mem, ent);
3102 }
3103 }
3104
nghttp3_qpack_decoder_dtable_indexed_add(nghttp3_qpack_decoder * decoder)3105 int nghttp3_qpack_decoder_dtable_indexed_add(nghttp3_qpack_decoder *decoder) {
3106 DEBUGF("qpack::decode: Insert With Name Reference (%s) absidx=%" PRIu64 ": "
3107 "value=%*s\n",
3108 decoder->rstate.dynamic ? "dynamic" : "static", decoder->rstate.absidx,
3109 (int)decoder->rstate.value->len, decoder->rstate.value->base);
3110
3111 if (decoder->rstate.dynamic) {
3112 return nghttp3_qpack_decoder_dtable_dynamic_add(decoder);
3113 }
3114
3115 return nghttp3_qpack_decoder_dtable_static_add(decoder);
3116 }
3117
nghttp3_qpack_decoder_dtable_static_add(nghttp3_qpack_decoder * decoder)3118 int nghttp3_qpack_decoder_dtable_static_add(nghttp3_qpack_decoder *decoder) {
3119 nghttp3_qpack_nv qnv;
3120 int rv;
3121 const nghttp3_qpack_static_header *shd;
3122
3123 shd = &stable[decoder->rstate.absidx];
3124
3125 if (table_space(shd->name.len, decoder->rstate.value->len) >
3126 decoder->ctx.max_dtable_capacity) {
3127 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3128 }
3129
3130 qnv.name = (nghttp3_rcbuf *)&shd->name;
3131 qnv.value = decoder->rstate.value;
3132 qnv.token = shd->token;
3133 qnv.flags = NGHTTP3_NV_FLAG_NONE;
3134
3135 rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
3136
3137 nghttp3_rcbuf_decref(qnv.value);
3138
3139 return rv;
3140 }
3141
nghttp3_qpack_decoder_dtable_dynamic_add(nghttp3_qpack_decoder * decoder)3142 int nghttp3_qpack_decoder_dtable_dynamic_add(nghttp3_qpack_decoder *decoder) {
3143 nghttp3_qpack_nv qnv;
3144 int rv;
3145 nghttp3_qpack_entry *ent;
3146
3147 ent = nghttp3_qpack_context_dtable_get(&decoder->ctx, decoder->rstate.absidx);
3148
3149 if (table_space(ent->nv.name->len, decoder->rstate.value->len) >
3150 decoder->ctx.max_dtable_capacity) {
3151 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3152 }
3153
3154 qnv.name = ent->nv.name;
3155 qnv.value = decoder->rstate.value;
3156 qnv.token = ent->nv.token;
3157 qnv.flags = NGHTTP3_NV_FLAG_NONE;
3158
3159 nghttp3_rcbuf_incref(qnv.name);
3160
3161 rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
3162
3163 nghttp3_rcbuf_decref(qnv.value);
3164 nghttp3_rcbuf_decref(qnv.name);
3165
3166 return rv;
3167 }
3168
nghttp3_qpack_decoder_dtable_duplicate_add(nghttp3_qpack_decoder * decoder)3169 int nghttp3_qpack_decoder_dtable_duplicate_add(nghttp3_qpack_decoder *decoder) {
3170 int rv;
3171 nghttp3_qpack_entry *ent;
3172 nghttp3_qpack_nv qnv;
3173
3174 DEBUGF("qpack::decode: Insert duplicate absidx=%" PRIu64 "\n",
3175 decoder->rstate.absidx);
3176
3177 ent = nghttp3_qpack_context_dtable_get(&decoder->ctx, decoder->rstate.absidx);
3178
3179 if (table_space(ent->nv.name->len, ent->nv.value->len) >
3180 decoder->ctx.max_dtable_capacity) {
3181 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3182 }
3183
3184 qnv = ent->nv;
3185 nghttp3_rcbuf_incref(qnv.name);
3186 nghttp3_rcbuf_incref(qnv.value);
3187
3188 rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
3189
3190 nghttp3_rcbuf_decref(qnv.value);
3191 nghttp3_rcbuf_decref(qnv.name);
3192
3193 return rv;
3194 }
3195
nghttp3_qpack_decoder_dtable_literal_add(nghttp3_qpack_decoder * decoder)3196 int nghttp3_qpack_decoder_dtable_literal_add(nghttp3_qpack_decoder *decoder) {
3197 nghttp3_qpack_nv qnv;
3198 int rv;
3199
3200 DEBUGF("qpack::decode: Insert With Literal Name: name=%*s value=%*s\n",
3201 (int)decoder->rstate.name->len, decoder->rstate.name->base,
3202 (int)decoder->rstate.value->len, decoder->rstate.value->base);
3203
3204 if (table_space(decoder->rstate.name->len, decoder->rstate.value->len) >
3205 decoder->ctx.max_dtable_capacity) {
3206 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3207 }
3208
3209 qnv.name = decoder->rstate.name;
3210 qnv.value = decoder->rstate.value;
3211 qnv.token = qpack_lookup_token(qnv.name->base, qnv.name->len);
3212 qnv.flags = NGHTTP3_NV_FLAG_NONE;
3213
3214 rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
3215
3216 nghttp3_rcbuf_decref(qnv.value);
3217 nghttp3_rcbuf_decref(qnv.name);
3218
3219 return rv;
3220 }
3221
nghttp3_qpack_decoder_set_max_concurrent_streams(nghttp3_qpack_decoder * decoder,size_t max_concurrent_streams)3222 void nghttp3_qpack_decoder_set_max_concurrent_streams(
3223 nghttp3_qpack_decoder *decoder, size_t max_concurrent_streams) {
3224 decoder->max_concurrent_streams =
3225 nghttp3_max(decoder->max_concurrent_streams, max_concurrent_streams);
3226 }
3227
nghttp3_qpack_stream_context_init(nghttp3_qpack_stream_context * sctx,int64_t stream_id,const nghttp3_mem * mem)3228 void nghttp3_qpack_stream_context_init(nghttp3_qpack_stream_context *sctx,
3229 int64_t stream_id,
3230 const nghttp3_mem *mem) {
3231 nghttp3_qpack_read_state_reset(&sctx->rstate);
3232
3233 sctx->mem = mem;
3234 sctx->rstate.prefix = 8;
3235 sctx->state = NGHTTP3_QPACK_RS_STATE_RICNT;
3236 sctx->opcode = 0;
3237 sctx->stream_id = stream_id;
3238 sctx->ricnt = 0;
3239 sctx->dbase_sign = 0;
3240 sctx->base = 0;
3241 }
3242
nghttp3_qpack_stream_context_free(nghttp3_qpack_stream_context * sctx)3243 void nghttp3_qpack_stream_context_free(nghttp3_qpack_stream_context *sctx) {
3244 nghttp3_qpack_read_state_free(&sctx->rstate);
3245 }
3246
nghttp3_qpack_stream_context_reset(nghttp3_qpack_stream_context * sctx)3247 void nghttp3_qpack_stream_context_reset(nghttp3_qpack_stream_context *sctx) {
3248 nghttp3_qpack_stream_context_init(sctx, sctx->stream_id, sctx->mem);
3249 }
3250
3251 uint64_t
nghttp3_qpack_stream_context_get_ricnt(nghttp3_qpack_stream_context * sctx)3252 nghttp3_qpack_stream_context_get_ricnt(nghttp3_qpack_stream_context *sctx) {
3253 return sctx->ricnt;
3254 }
3255
3256 nghttp3_ssize
nghttp3_qpack_decoder_read_request(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv,uint8_t * pflags,const uint8_t * src,size_t srclen,int fin)3257 nghttp3_qpack_decoder_read_request(nghttp3_qpack_decoder *decoder,
3258 nghttp3_qpack_stream_context *sctx,
3259 nghttp3_qpack_nv *nv, uint8_t *pflags,
3260 const uint8_t *src, size_t srclen, int fin) {
3261 const uint8_t *p = src, *end = src ? src + srclen : src;
3262 int rv;
3263 int busy = 0;
3264 nghttp3_ssize nread;
3265 int rfin;
3266 const nghttp3_mem *mem = decoder->ctx.mem;
3267
3268 if (decoder->ctx.bad) {
3269 return NGHTTP3_ERR_QPACK_FATAL;
3270 }
3271
3272 *pflags = NGHTTP3_QPACK_DECODE_FLAG_NONE;
3273
3274 for (; p != end || busy;) {
3275 busy = 0;
3276 switch (sctx->state) {
3277 case NGHTTP3_QPACK_RS_STATE_RICNT:
3278 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3279 if (nread < 0) {
3280 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3281 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3282 goto fail;
3283 }
3284
3285 p += nread;
3286
3287 if (!rfin) {
3288 goto almost_ok;
3289 }
3290
3291 rv = nghttp3_qpack_decoder_reconstruct_ricnt(decoder, &sctx->ricnt,
3292 sctx->rstate.left);
3293 if (rv != 0) {
3294 goto fail;
3295 }
3296
3297 sctx->state = NGHTTP3_QPACK_RS_STATE_DBASE_SIGN;
3298 break;
3299 case NGHTTP3_QPACK_RS_STATE_DBASE_SIGN:
3300 if ((*p) & 0x80) {
3301 sctx->dbase_sign = 1;
3302 }
3303 sctx->state = NGHTTP3_QPACK_RS_STATE_DBASE;
3304 sctx->rstate.left = 0;
3305 sctx->rstate.prefix = 7;
3306 sctx->rstate.shift = 0;
3307 /* Fall through */
3308 case NGHTTP3_QPACK_RS_STATE_DBASE:
3309 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3310 if (nread < 0) {
3311 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3312 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3313 goto fail;
3314 }
3315
3316 p += nread;
3317
3318 if (!rfin) {
3319 goto almost_ok;
3320 }
3321
3322 if (sctx->dbase_sign) {
3323 if (sctx->ricnt <= sctx->rstate.left) {
3324 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3325 goto fail;
3326 }
3327 sctx->base = sctx->ricnt - sctx->rstate.left - 1;
3328 } else {
3329 sctx->base = sctx->ricnt + sctx->rstate.left;
3330 }
3331
3332 DEBUGF("qpack::decode: ricnt=%" PRIu64 " base=%" PRIu64 " icnt=%" PRIu64
3333 "\n",
3334 sctx->ricnt, sctx->base, decoder->ctx.next_absidx);
3335
3336 if (sctx->ricnt > decoder->ctx.next_absidx) {
3337 DEBUGF("qpack::decode: stream blocked\n");
3338 sctx->state = NGHTTP3_QPACK_RS_STATE_BLOCKED;
3339 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_BLOCKED;
3340 return p - src;
3341 }
3342
3343 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3344 sctx->rstate.left = 0;
3345 sctx->rstate.shift = 0;
3346 break;
3347 case NGHTTP3_QPACK_RS_STATE_OPCODE:
3348 assert(sctx->rstate.left == 0);
3349 assert(sctx->rstate.shift == 0);
3350 if ((*p) & 0x80) {
3351 DEBUGF("qpack::decode: OPCODE_INDEXED\n");
3352 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_INDEXED;
3353 sctx->rstate.dynamic = !((*p) & 0x40);
3354 sctx->rstate.prefix = 6;
3355 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_INDEX;
3356 } else if ((*p) & 0x40) {
3357 DEBUGF("qpack::decode: OPCODE_INDEXED_NAME\n");
3358 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME;
3359 sctx->rstate.never = (*p) & 0x20;
3360 sctx->rstate.dynamic = !((*p) & 0x10);
3361 sctx->rstate.prefix = 4;
3362 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_INDEX;
3363 } else if ((*p) & 0x20) {
3364 DEBUGF("qpack::decode: OPCODE_LITERAL\n");
3365 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_LITERAL;
3366 sctx->rstate.never = (*p) & 0x10;
3367 sctx->rstate.dynamic = 0;
3368 sctx->rstate.prefix = 3;
3369 sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_NAME_HUFFMAN;
3370 } else if ((*p) & 0x10) {
3371 DEBUGF("qpack::decode: OPCODE_INDEXED_PB\n");
3372 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_INDEXED_PB;
3373 sctx->rstate.dynamic = 1;
3374 sctx->rstate.prefix = 4;
3375 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_INDEX;
3376 } else {
3377 DEBUGF("qpack::decode: OPCODE_INDEXED_NAME_PB\n");
3378 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB;
3379 sctx->rstate.never = (*p) & 0x08;
3380 sctx->rstate.dynamic = 1;
3381 sctx->rstate.prefix = 3;
3382 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_INDEX;
3383 }
3384 break;
3385 case NGHTTP3_QPACK_RS_STATE_READ_INDEX:
3386 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3387 if (nread < 0) {
3388 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3389 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3390 goto fail;
3391 }
3392
3393 p += nread;
3394
3395 if (!rfin) {
3396 goto almost_ok;
3397 }
3398
3399 switch (sctx->opcode) {
3400 case NGHTTP3_QPACK_RS_OPCODE_INDEXED:
3401 rv = nghttp3_qpack_decoder_brel2abs(decoder, sctx);
3402 if (rv != 0) {
3403 goto fail;
3404 }
3405 nghttp3_qpack_decoder_emit_indexed(decoder, sctx, nv);
3406 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT;
3407
3408 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3409 nghttp3_qpack_read_state_reset(&sctx->rstate);
3410
3411 return p - src;
3412 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_PB:
3413 rv = nghttp3_qpack_decoder_pbrel2abs(decoder, sctx);
3414 if (rv != 0) {
3415 goto fail;
3416 }
3417 nghttp3_qpack_decoder_emit_indexed(decoder, sctx, nv);
3418 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT;
3419
3420 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3421 nghttp3_qpack_read_state_reset(&sctx->rstate);
3422
3423 return p - src;
3424 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME:
3425 rv = nghttp3_qpack_decoder_brel2abs(decoder, sctx);
3426 if (rv != 0) {
3427 goto fail;
3428 }
3429 sctx->rstate.prefix = 7;
3430 sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN;
3431 break;
3432 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB:
3433 rv = nghttp3_qpack_decoder_pbrel2abs(decoder, sctx);
3434 if (rv != 0) {
3435 goto fail;
3436 }
3437 sctx->rstate.prefix = 7;
3438 sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN;
3439 break;
3440 default:
3441 /* Unreachable */
3442 assert(0);
3443 }
3444 break;
3445 case NGHTTP3_QPACK_RS_STATE_CHECK_NAME_HUFFMAN:
3446 qpack_read_state_check_huffman(&sctx->rstate, *p);
3447 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_NAMELEN;
3448 sctx->rstate.left = 0;
3449 sctx->rstate.shift = 0;
3450 /* Fall through */
3451 case NGHTTP3_QPACK_RS_STATE_READ_NAMELEN:
3452 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3453 if (nread < 0) {
3454 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3455 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3456 goto fail;
3457 }
3458
3459 p += nread;
3460
3461 if (!rfin) {
3462 goto almost_ok;
3463 }
3464
3465 if (sctx->rstate.left > NGHTTP3_QPACK_MAX_NAMELEN) {
3466 rv = NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE;
3467 goto fail;
3468 }
3469
3470 if (sctx->rstate.huffman_encoded) {
3471 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_NAME_HUFFMAN;
3472 nghttp3_qpack_huffman_decode_context_init(&sctx->rstate.huffman_ctx);
3473 rv = nghttp3_rcbuf_new(&sctx->rstate.name,
3474 (size_t)sctx->rstate.left * 2 + 1, mem);
3475 } else {
3476 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_NAME;
3477 rv = nghttp3_rcbuf_new(&sctx->rstate.name,
3478 (size_t)sctx->rstate.left + 1, mem);
3479 }
3480 if (rv != 0) {
3481 goto fail;
3482 }
3483
3484 nghttp3_buf_wrap_init(&sctx->rstate.namebuf, sctx->rstate.name->base,
3485 sctx->rstate.name->len);
3486 break;
3487 case NGHTTP3_QPACK_RS_STATE_READ_NAME_HUFFMAN:
3488 nread = qpack_read_huffman_string(&sctx->rstate, &sctx->rstate.namebuf, p,
3489 end);
3490 if (nread < 0) {
3491 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3492 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3493 goto fail;
3494 }
3495
3496 p += nread;
3497
3498 if (sctx->rstate.left) {
3499 goto almost_ok;
3500 }
3501
3502 qpack_read_state_terminate_name(&sctx->rstate);
3503
3504 sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN;
3505 sctx->rstate.prefix = 7;
3506 break;
3507 case NGHTTP3_QPACK_RS_STATE_READ_NAME:
3508 nread = qpack_read_string(&sctx->rstate, &sctx->rstate.namebuf, p, end);
3509 if (nread < 0) {
3510 rv = (int)nread;
3511 goto fail;
3512 }
3513
3514 p += nread;
3515
3516 if (sctx->rstate.left) {
3517 goto almost_ok;
3518 }
3519
3520 qpack_read_state_terminate_name(&sctx->rstate);
3521
3522 sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN;
3523 sctx->rstate.prefix = 7;
3524 break;
3525 case NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN:
3526 qpack_read_state_check_huffman(&sctx->rstate, *p);
3527 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_VALUELEN;
3528 sctx->rstate.left = 0;
3529 sctx->rstate.shift = 0;
3530 /* Fall through */
3531 case NGHTTP3_QPACK_RS_STATE_READ_VALUELEN:
3532 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3533 if (nread < 0) {
3534 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3535 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3536 goto fail;
3537 }
3538
3539 p += nread;
3540
3541 if (!rfin) {
3542 goto almost_ok;
3543 }
3544
3545 if (sctx->rstate.left > NGHTTP3_QPACK_MAX_VALUELEN) {
3546 rv = NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE;
3547 goto fail;
3548 }
3549
3550 if (sctx->rstate.huffman_encoded) {
3551 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_VALUE_HUFFMAN;
3552 nghttp3_qpack_huffman_decode_context_init(&sctx->rstate.huffman_ctx);
3553 rv = nghttp3_rcbuf_new(&sctx->rstate.value,
3554 (size_t)sctx->rstate.left * 2 + 1, mem);
3555 } else {
3556 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_VALUE;
3557 rv = nghttp3_rcbuf_new(&sctx->rstate.value,
3558 (size_t)sctx->rstate.left + 1, mem);
3559 }
3560 if (rv != 0) {
3561 goto fail;
3562 }
3563
3564 nghttp3_buf_wrap_init(&sctx->rstate.valuebuf, sctx->rstate.value->base,
3565 sctx->rstate.value->len);
3566
3567 /* value might be 0 length */
3568 busy = 1;
3569 break;
3570 case NGHTTP3_QPACK_RS_STATE_READ_VALUE_HUFFMAN:
3571 nread = qpack_read_huffman_string(&sctx->rstate, &sctx->rstate.valuebuf,
3572 p, end);
3573 if (nread < 0) {
3574 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3575 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3576 goto fail;
3577 }
3578
3579 p += nread;
3580
3581 if (sctx->rstate.left) {
3582 goto almost_ok;
3583 }
3584
3585 qpack_read_state_terminate_value(&sctx->rstate);
3586
3587 switch (sctx->opcode) {
3588 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME:
3589 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB:
3590 nghttp3_qpack_decoder_emit_indexed_name(decoder, sctx, nv);
3591 break;
3592 case NGHTTP3_QPACK_RS_OPCODE_LITERAL:
3593 nghttp3_qpack_decoder_emit_literal(decoder, sctx, nv);
3594 break;
3595 default:
3596 /* Unreachable */
3597 assert(0);
3598 }
3599
3600 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT;
3601
3602 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3603 nghttp3_qpack_read_state_reset(&sctx->rstate);
3604
3605 return p - src;
3606 case NGHTTP3_QPACK_RS_STATE_READ_VALUE:
3607 nread = qpack_read_string(&sctx->rstate, &sctx->rstate.valuebuf, p, end);
3608 if (nread < 0) {
3609 rv = (int)nread;
3610 goto fail;
3611 }
3612
3613 p += nread;
3614
3615 if (sctx->rstate.left) {
3616 goto almost_ok;
3617 }
3618
3619 qpack_read_state_terminate_value(&sctx->rstate);
3620
3621 switch (sctx->opcode) {
3622 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME:
3623 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB:
3624 nghttp3_qpack_decoder_emit_indexed_name(decoder, sctx, nv);
3625 break;
3626 case NGHTTP3_QPACK_RS_OPCODE_LITERAL:
3627 nghttp3_qpack_decoder_emit_literal(decoder, sctx, nv);
3628 break;
3629 default:
3630 /* Unreachable */
3631 assert(0);
3632 }
3633
3634 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT;
3635
3636 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3637 nghttp3_qpack_read_state_reset(&sctx->rstate);
3638
3639 return p - src;
3640 case NGHTTP3_QPACK_RS_STATE_BLOCKED:
3641 if (sctx->ricnt > decoder->ctx.next_absidx) {
3642 DEBUGF("qpack::decode: stream still blocked\n");
3643 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_BLOCKED;
3644 return p - src;
3645 }
3646 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3647 nghttp3_qpack_read_state_reset(&sctx->rstate);
3648 break;
3649 }
3650 }
3651
3652 almost_ok:
3653 if (fin) {
3654 if (sctx->state != NGHTTP3_QPACK_RS_STATE_OPCODE) {
3655 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3656 goto fail;
3657 }
3658
3659 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_FINAL;
3660
3661 if (sctx->ricnt) {
3662 rv = nghttp3_qpack_decoder_write_section_ack(decoder, sctx);
3663 if (rv != 0) {
3664 goto fail;
3665 }
3666 }
3667 }
3668
3669 return p - src;
3670
3671 fail:
3672 decoder->ctx.bad = 1;
3673 return rv;
3674 }
3675
qpack_decoder_dbuf_overflow(nghttp3_qpack_decoder * decoder)3676 static int qpack_decoder_dbuf_overflow(nghttp3_qpack_decoder *decoder) {
3677 size_t limit = nghttp3_max(decoder->max_concurrent_streams, 100);
3678 /* 10 = nghttp3_qpack_put_varint_len((1ULL << 62) - 1, 2)) */
3679 return nghttp3_buf_len(&decoder->dbuf) > limit * 2 * 10;
3680 }
3681
nghttp3_qpack_decoder_write_section_ack(nghttp3_qpack_decoder * decoder,const nghttp3_qpack_stream_context * sctx)3682 int nghttp3_qpack_decoder_write_section_ack(
3683 nghttp3_qpack_decoder *decoder, const nghttp3_qpack_stream_context *sctx) {
3684 nghttp3_buf *dbuf = &decoder->dbuf;
3685 uint8_t *p;
3686 int rv;
3687
3688 if (qpack_decoder_dbuf_overflow(decoder)) {
3689 return NGHTTP3_ERR_QPACK_FATAL;
3690 }
3691
3692 rv = reserve_buf_small(
3693 dbuf, nghttp3_qpack_put_varint_len((uint64_t)sctx->stream_id, 7),
3694 decoder->ctx.mem);
3695 if (rv != 0) {
3696 return rv;
3697 }
3698
3699 p = dbuf->last;
3700 *p = 0x80;
3701 dbuf->last = nghttp3_qpack_put_varint(p, (uint64_t)sctx->stream_id, 7);
3702
3703 if (decoder->written_icnt < sctx->ricnt) {
3704 decoder->written_icnt = sctx->ricnt;
3705 }
3706
3707 return 0;
3708 }
3709
3710 size_t
nghttp3_qpack_decoder_get_decoder_streamlen(nghttp3_qpack_decoder * decoder)3711 nghttp3_qpack_decoder_get_decoder_streamlen(nghttp3_qpack_decoder *decoder) {
3712 uint64_t n;
3713 size_t len = 0;
3714
3715 if (decoder->written_icnt < decoder->ctx.next_absidx) {
3716 n = decoder->ctx.next_absidx - decoder->written_icnt;
3717 len = nghttp3_qpack_put_varint_len(n, 6);
3718 }
3719
3720 return nghttp3_buf_len(&decoder->dbuf) + len;
3721 }
3722
nghttp3_qpack_decoder_write_decoder(nghttp3_qpack_decoder * decoder,nghttp3_buf * dbuf)3723 void nghttp3_qpack_decoder_write_decoder(nghttp3_qpack_decoder *decoder,
3724 nghttp3_buf *dbuf) {
3725 uint8_t *p;
3726 uint64_t n = 0;
3727 size_t len = 0;
3728 (void)len;
3729
3730 if (decoder->written_icnt < decoder->ctx.next_absidx) {
3731 n = decoder->ctx.next_absidx - decoder->written_icnt;
3732 len = nghttp3_qpack_put_varint_len(n, 6);
3733 }
3734
3735 assert(nghttp3_buf_left(dbuf) >= nghttp3_buf_len(&decoder->dbuf) + len);
3736
3737 if (nghttp3_buf_len(&decoder->dbuf)) {
3738 dbuf->last = nghttp3_cpymem(dbuf->last, decoder->dbuf.pos,
3739 nghttp3_buf_len(&decoder->dbuf));
3740 }
3741
3742 if (n) {
3743 p = dbuf->last;
3744 *p = 0;
3745 dbuf->last = nghttp3_qpack_put_varint(p, n, 6);
3746
3747 decoder->written_icnt = decoder->ctx.next_absidx;
3748 }
3749
3750 nghttp3_buf_reset(&decoder->dbuf);
3751 }
3752
nghttp3_qpack_decoder_cancel_stream(nghttp3_qpack_decoder * decoder,int64_t stream_id)3753 int nghttp3_qpack_decoder_cancel_stream(nghttp3_qpack_decoder *decoder,
3754 int64_t stream_id) {
3755 uint8_t *p;
3756 int rv;
3757
3758 if (qpack_decoder_dbuf_overflow(decoder)) {
3759 return NGHTTP3_ERR_QPACK_FATAL;
3760 }
3761
3762 rv = reserve_buf(&decoder->dbuf,
3763 nghttp3_qpack_put_varint_len((uint64_t)stream_id, 6),
3764 decoder->ctx.mem);
3765 if (rv != 0) {
3766 return rv;
3767 }
3768
3769 p = decoder->dbuf.last;
3770 *p = 0x40;
3771 decoder->dbuf.last = nghttp3_qpack_put_varint(p, (uint64_t)stream_id, 6);
3772
3773 return 0;
3774 }
3775
nghttp3_qpack_decoder_reconstruct_ricnt(nghttp3_qpack_decoder * decoder,uint64_t * dest,uint64_t encricnt)3776 int nghttp3_qpack_decoder_reconstruct_ricnt(nghttp3_qpack_decoder *decoder,
3777 uint64_t *dest, uint64_t encricnt) {
3778 uint64_t max_ents, full, max, max_wrapped, ricnt;
3779
3780 if (encricnt == 0) {
3781 *dest = 0;
3782 return 0;
3783 }
3784
3785 max_ents =
3786 decoder->ctx.hard_max_dtable_capacity / NGHTTP3_QPACK_ENTRY_OVERHEAD;
3787 full = 2 * max_ents;
3788
3789 if (encricnt > full) {
3790 return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3791 }
3792
3793 max = decoder->ctx.next_absidx + max_ents;
3794 max_wrapped = max / full * full;
3795 ricnt = max_wrapped + encricnt - 1;
3796
3797 if (ricnt > max) {
3798 if (ricnt <= full) {
3799 return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3800 }
3801 ricnt -= full;
3802 }
3803
3804 if (ricnt == 0) {
3805 return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3806 }
3807
3808 *dest = ricnt;
3809
3810 return 0;
3811 }
3812
nghttp3_qpack_decoder_rel2abs(nghttp3_qpack_decoder * decoder,nghttp3_qpack_read_state * rstate)3813 int nghttp3_qpack_decoder_rel2abs(nghttp3_qpack_decoder *decoder,
3814 nghttp3_qpack_read_state *rstate) {
3815 DEBUGF("qpack::decode: dynamic=%d relidx=%" PRIu64 " icnt=%" PRIu64 "\n",
3816 rstate->dynamic, rstate->left, decoder->ctx.next_absidx);
3817
3818 if (rstate->dynamic) {
3819 if (decoder->ctx.next_absidx < rstate->left + 1) {
3820 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3821 }
3822 rstate->absidx = decoder->ctx.next_absidx - rstate->left - 1;
3823 } else {
3824 rstate->absidx = rstate->left;
3825 }
3826 if (qpack_decoder_validate_index(decoder, rstate) != 0) {
3827 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3828 }
3829 return 0;
3830 }
3831
nghttp3_qpack_decoder_brel2abs(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx)3832 int nghttp3_qpack_decoder_brel2abs(nghttp3_qpack_decoder *decoder,
3833 nghttp3_qpack_stream_context *sctx) {
3834 nghttp3_qpack_read_state *rstate = &sctx->rstate;
3835
3836 DEBUGF("qpack::decode: dynamic=%d relidx=%" PRIu64 " base=%" PRIu64
3837 " icnt=%" PRIu64 "\n",
3838 rstate->dynamic, rstate->left, sctx->base, decoder->ctx.next_absidx);
3839
3840 if (rstate->dynamic) {
3841 if (sctx->base < rstate->left + 1) {
3842 return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3843 }
3844 rstate->absidx = sctx->base - rstate->left - 1;
3845
3846 if (rstate->absidx >= sctx->ricnt) {
3847 return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3848 }
3849 } else {
3850 rstate->absidx = rstate->left;
3851 }
3852
3853 if (qpack_decoder_validate_index(decoder, rstate) != 0) {
3854 return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3855 }
3856 return 0;
3857 }
3858
nghttp3_qpack_decoder_pbrel2abs(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx)3859 int nghttp3_qpack_decoder_pbrel2abs(nghttp3_qpack_decoder *decoder,
3860 nghttp3_qpack_stream_context *sctx) {
3861 nghttp3_qpack_read_state *rstate = &sctx->rstate;
3862
3863 DEBUGF("qpack::decode: pbidx=%" PRIu64 " base=%" PRIu64 " icnt=%" PRIu64 "\n",
3864 rstate->left, sctx->base, decoder->ctx.next_absidx);
3865
3866 assert(rstate->dynamic);
3867
3868 rstate->absidx = rstate->left + sctx->base;
3869
3870 if (rstate->absidx >= sctx->ricnt) {
3871 return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3872 }
3873
3874 if (qpack_decoder_validate_index(decoder, rstate) != 0) {
3875 return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3876 }
3877 return 0;
3878 }
3879
3880 static void
qpack_decoder_emit_static_indexed(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv)3881 qpack_decoder_emit_static_indexed(nghttp3_qpack_decoder *decoder,
3882 nghttp3_qpack_stream_context *sctx,
3883 nghttp3_qpack_nv *nv) {
3884 const nghttp3_qpack_static_header *shd = &stable[sctx->rstate.absidx];
3885 (void)decoder;
3886
3887 nv->name = (nghttp3_rcbuf *)&shd->name;
3888 nv->value = (nghttp3_rcbuf *)&shd->value;
3889 nv->token = shd->token;
3890 nv->flags = NGHTTP3_NV_FLAG_NONE;
3891 }
3892
3893 static void
qpack_decoder_emit_dynamic_indexed(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv)3894 qpack_decoder_emit_dynamic_indexed(nghttp3_qpack_decoder *decoder,
3895 nghttp3_qpack_stream_context *sctx,
3896 nghttp3_qpack_nv *nv) {
3897 nghttp3_qpack_entry *ent =
3898 nghttp3_qpack_context_dtable_get(&decoder->ctx, sctx->rstate.absidx);
3899
3900 *nv = ent->nv;
3901
3902 nghttp3_rcbuf_incref(nv->name);
3903 nghttp3_rcbuf_incref(nv->value);
3904 }
3905
nghttp3_qpack_decoder_emit_indexed(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv)3906 void nghttp3_qpack_decoder_emit_indexed(nghttp3_qpack_decoder *decoder,
3907 nghttp3_qpack_stream_context *sctx,
3908 nghttp3_qpack_nv *nv) {
3909 DEBUGF("qpack::decode: Indexed (%s) absidx=%" PRIu64 "\n",
3910 sctx->rstate.dynamic ? "dynamic" : "static", sctx->rstate.absidx);
3911
3912 if (sctx->rstate.dynamic) {
3913 qpack_decoder_emit_dynamic_indexed(decoder, sctx, nv);
3914 } else {
3915 qpack_decoder_emit_static_indexed(decoder, sctx, nv);
3916 }
3917 }
3918
3919 static void
qpack_decoder_emit_static_indexed_name(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv)3920 qpack_decoder_emit_static_indexed_name(nghttp3_qpack_decoder *decoder,
3921 nghttp3_qpack_stream_context *sctx,
3922 nghttp3_qpack_nv *nv) {
3923 const nghttp3_qpack_static_header *shd = &stable[sctx->rstate.absidx];
3924 (void)decoder;
3925
3926 nv->name = (nghttp3_rcbuf *)&shd->name;
3927 nv->value = sctx->rstate.value;
3928 nv->token = shd->token;
3929 nv->flags =
3930 sctx->rstate.never ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE;
3931
3932 sctx->rstate.value = NULL;
3933 }
3934
3935 static void
qpack_decoder_emit_dynamic_indexed_name(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv)3936 qpack_decoder_emit_dynamic_indexed_name(nghttp3_qpack_decoder *decoder,
3937 nghttp3_qpack_stream_context *sctx,
3938 nghttp3_qpack_nv *nv) {
3939 nghttp3_qpack_entry *ent =
3940 nghttp3_qpack_context_dtable_get(&decoder->ctx, sctx->rstate.absidx);
3941 (void)decoder;
3942
3943 nv->name = ent->nv.name;
3944 nv->value = sctx->rstate.value;
3945 nv->token = ent->nv.token;
3946 nv->flags =
3947 sctx->rstate.never ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE;
3948
3949 nghttp3_rcbuf_incref(nv->name);
3950
3951 sctx->rstate.value = NULL;
3952 }
3953
nghttp3_qpack_decoder_emit_indexed_name(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv)3954 void nghttp3_qpack_decoder_emit_indexed_name(nghttp3_qpack_decoder *decoder,
3955 nghttp3_qpack_stream_context *sctx,
3956 nghttp3_qpack_nv *nv) {
3957 (void)decoder;
3958
3959 DEBUGF("qpack::decode: Indexed name (%s) absidx=%" PRIu64 " value=%*s\n",
3960 sctx->rstate.dynamic ? "dynamic" : "static", sctx->rstate.absidx,
3961 (int)sctx->rstate.value->len, sctx->rstate.value->base);
3962
3963 if (sctx->rstate.dynamic) {
3964 qpack_decoder_emit_dynamic_indexed_name(decoder, sctx, nv);
3965 } else {
3966 qpack_decoder_emit_static_indexed_name(decoder, sctx, nv);
3967 }
3968 }
3969
nghttp3_qpack_decoder_emit_literal(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv)3970 void nghttp3_qpack_decoder_emit_literal(nghttp3_qpack_decoder *decoder,
3971 nghttp3_qpack_stream_context *sctx,
3972 nghttp3_qpack_nv *nv) {
3973 (void)decoder;
3974
3975 DEBUGF("qpack::decode: Emit literal name=%*s value=%*s\n",
3976 (int)sctx->rstate.name->len, sctx->rstate.name->base,
3977 (int)sctx->rstate.value->len, sctx->rstate.value->base);
3978
3979 nv->name = sctx->rstate.name;
3980 nv->value = sctx->rstate.value;
3981 nv->token = qpack_lookup_token(nv->name->base, nv->name->len);
3982 nv->flags =
3983 sctx->rstate.never ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE;
3984
3985 sctx->rstate.name = NULL;
3986 sctx->rstate.value = NULL;
3987 }
3988
nghttp3_qpack_encoder_new(nghttp3_qpack_encoder ** pencoder,const nghttp3_mem * mem)3989 int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder,
3990 const nghttp3_mem *mem) {
3991 int rv;
3992 nghttp3_qpack_encoder *p;
3993
3994 p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_encoder));
3995 if (p == NULL) {
3996 return NGHTTP3_ERR_NOMEM;
3997 }
3998
3999 rv = nghttp3_qpack_encoder_init(p, mem);
4000 if (rv != 0) {
4001 return rv;
4002 }
4003
4004 *pencoder = p;
4005
4006 return 0;
4007 }
4008
nghttp3_qpack_encoder_del(nghttp3_qpack_encoder * encoder)4009 void nghttp3_qpack_encoder_del(nghttp3_qpack_encoder *encoder) {
4010 const nghttp3_mem *mem;
4011
4012 if (encoder == NULL) {
4013 return;
4014 }
4015
4016 mem = encoder->ctx.mem;
4017
4018 nghttp3_qpack_encoder_free(encoder);
4019 nghttp3_mem_free(mem, encoder);
4020 }
4021
nghttp3_qpack_stream_context_new(nghttp3_qpack_stream_context ** psctx,int64_t stream_id,const nghttp3_mem * mem)4022 int nghttp3_qpack_stream_context_new(nghttp3_qpack_stream_context **psctx,
4023 int64_t stream_id,
4024 const nghttp3_mem *mem) {
4025 nghttp3_qpack_stream_context *p;
4026
4027 p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream_context));
4028 if (p == NULL) {
4029 return NGHTTP3_ERR_NOMEM;
4030 }
4031
4032 nghttp3_qpack_stream_context_init(p, stream_id, mem);
4033
4034 *psctx = p;
4035
4036 return 0;
4037 }
4038
nghttp3_qpack_stream_context_del(nghttp3_qpack_stream_context * sctx)4039 void nghttp3_qpack_stream_context_del(nghttp3_qpack_stream_context *sctx) {
4040 const nghttp3_mem *mem;
4041
4042 if (sctx == NULL) {
4043 return;
4044 }
4045
4046 mem = sctx->mem;
4047
4048 nghttp3_qpack_stream_context_free(sctx);
4049 nghttp3_mem_free(mem, sctx);
4050 }
4051
nghttp3_qpack_decoder_new(nghttp3_qpack_decoder ** pdecoder,size_t max_dtable_capacity,size_t max_blocked_streams,const nghttp3_mem * mem)4052 int nghttp3_qpack_decoder_new(nghttp3_qpack_decoder **pdecoder,
4053 size_t max_dtable_capacity,
4054 size_t max_blocked_streams,
4055 const nghttp3_mem *mem) {
4056 int rv;
4057 nghttp3_qpack_decoder *p;
4058
4059 p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_decoder));
4060 if (p == NULL) {
4061 return NGHTTP3_ERR_NOMEM;
4062 }
4063
4064 rv = nghttp3_qpack_decoder_init(p, max_dtable_capacity, max_blocked_streams,
4065 mem);
4066 if (rv != 0) {
4067 return rv;
4068 }
4069
4070 *pdecoder = p;
4071
4072 return 0;
4073 }
4074
nghttp3_qpack_decoder_del(nghttp3_qpack_decoder * decoder)4075 void nghttp3_qpack_decoder_del(nghttp3_qpack_decoder *decoder) {
4076 const nghttp3_mem *mem;
4077
4078 if (decoder == NULL) {
4079 return;
4080 }
4081
4082 mem = decoder->ctx.mem;
4083
4084 nghttp3_qpack_decoder_free(decoder);
4085 nghttp3_mem_free(mem, decoder);
4086 }
4087
nghttp3_qpack_decoder_get_icnt(const nghttp3_qpack_decoder * decoder)4088 uint64_t nghttp3_qpack_decoder_get_icnt(const nghttp3_qpack_decoder *decoder) {
4089 return decoder->ctx.next_absidx;
4090 }
4091