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, (uint8_t *)(N), sizeof((N)) - 1, -1}, \
172 {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|. |hard_max_dtable_capacity|
828 * is the upper bound of the dynamic table capacity. |mem| is a
829 * memory allocator.
830 *
831 * The maximum dynamic table size is governed by
832 * ctx->max_dtable_capacity and it is initialized to 0.
833 * |hard_max_dtable_capacity| is the upper bound of
834 * ctx->max_dtable_capacity.
835 *
836 * This function returns 0 if it succeeds, or one of the following
837 * negative error codes:
838 *
839 * NGHTTP3_ERR_NOMEM
840 * Out of memory.
841 */
qpack_context_init(nghttp3_qpack_context * ctx,size_t hard_max_dtable_capacity,size_t max_blocked_streams,const nghttp3_mem * mem)842 static int qpack_context_init(nghttp3_qpack_context *ctx,
843 size_t hard_max_dtable_capacity,
844 size_t max_blocked_streams,
845 const nghttp3_mem *mem) {
846 int rv;
847 size_t len = 4096 / NGHTTP3_QPACK_ENTRY_OVERHEAD;
848 size_t len2;
849
850 for (len2 = 1; len2 < len; len2 <<= 1)
851 ;
852
853 rv = nghttp3_ringbuf_init(&ctx->dtable, len2, sizeof(nghttp3_qpack_entry *),
854 mem);
855 if (rv != 0) {
856 return rv;
857 }
858
859 ctx->mem = mem;
860 ctx->dtable_size = 0;
861 ctx->dtable_sum = 0;
862 ctx->hard_max_dtable_capacity = hard_max_dtable_capacity;
863 ctx->max_dtable_capacity = 0;
864 ctx->max_blocked_streams = max_blocked_streams;
865 ctx->next_absidx = 0;
866 ctx->bad = 0;
867
868 return 0;
869 }
870
qpack_context_free(nghttp3_qpack_context * ctx)871 static void qpack_context_free(nghttp3_qpack_context *ctx) {
872 nghttp3_qpack_entry *ent;
873 size_t i, len = nghttp3_ringbuf_len(&ctx->dtable);
874
875 for (i = 0; i < len; ++i) {
876 ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, i);
877 nghttp3_qpack_entry_free(ent);
878 nghttp3_mem_free(ctx->mem, ent);
879 }
880 nghttp3_ringbuf_free(&ctx->dtable);
881 }
882
ref_min_cnt_less(const nghttp3_pq_entry * lhsx,const nghttp3_pq_entry * rhsx)883 static int ref_min_cnt_less(const nghttp3_pq_entry *lhsx,
884 const nghttp3_pq_entry *rhsx) {
885 nghttp3_qpack_header_block_ref *lhs =
886 nghttp3_struct_of(lhsx, nghttp3_qpack_header_block_ref, min_cnts_pe);
887 nghttp3_qpack_header_block_ref *rhs =
888 nghttp3_struct_of(rhsx, nghttp3_qpack_header_block_ref, min_cnts_pe);
889
890 return lhs->min_cnt < rhs->min_cnt;
891 }
892
893 typedef struct nghttp3_blocked_streams_key {
894 uint64_t max_cnt;
895 uint64_t id;
896 } nghttp3_blocked_streams_key;
897
max_cnt_greater(const nghttp3_ksl_key * lhs,const nghttp3_ksl_key * rhs)898 static int max_cnt_greater(const nghttp3_ksl_key *lhs,
899 const nghttp3_ksl_key *rhs) {
900 const nghttp3_blocked_streams_key *a = lhs;
901 const nghttp3_blocked_streams_key *b = rhs;
902 return a->max_cnt > b->max_cnt || (a->max_cnt == b->max_cnt && a->id < b->id);
903 }
904
nghttp3_qpack_encoder_init(nghttp3_qpack_encoder * encoder,size_t hard_max_dtable_capacity,const nghttp3_mem * mem)905 int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder,
906 size_t hard_max_dtable_capacity,
907 const nghttp3_mem *mem) {
908 int rv;
909
910 rv = qpack_context_init(&encoder->ctx, hard_max_dtable_capacity, 0, mem);
911 if (rv != 0) {
912 return rv;
913 }
914
915 nghttp3_map_init(&encoder->streams, mem);
916
917 nghttp3_ksl_init(&encoder->blocked_streams, max_cnt_greater,
918 sizeof(nghttp3_blocked_streams_key), mem);
919
920 qpack_map_init(&encoder->dtable_map);
921 nghttp3_pq_init(&encoder->min_cnts, ref_min_cnt_less, mem);
922
923 encoder->krcnt = 0;
924 encoder->state = NGHTTP3_QPACK_DS_STATE_OPCODE;
925 encoder->opcode = 0;
926 encoder->min_dtable_update = SIZE_MAX;
927 encoder->last_max_dtable_update = 0;
928 encoder->flags = NGHTTP3_QPACK_ENCODER_FLAG_NONE;
929
930 nghttp3_qpack_read_state_reset(&encoder->rstate);
931
932 return 0;
933 }
934
map_stream_free(void * data,void * ptr)935 static int map_stream_free(void *data, void *ptr) {
936 const nghttp3_mem *mem = ptr;
937 nghttp3_qpack_stream *stream = data;
938 nghttp3_qpack_stream_del(stream, mem);
939 return 0;
940 }
941
nghttp3_qpack_encoder_free(nghttp3_qpack_encoder * encoder)942 void nghttp3_qpack_encoder_free(nghttp3_qpack_encoder *encoder) {
943 nghttp3_pq_free(&encoder->min_cnts);
944 nghttp3_ksl_free(&encoder->blocked_streams);
945 nghttp3_map_each_free(&encoder->streams, map_stream_free,
946 (void *)encoder->ctx.mem);
947 nghttp3_map_free(&encoder->streams);
948 qpack_context_free(&encoder->ctx);
949 }
950
nghttp3_qpack_encoder_set_max_dtable_capacity(nghttp3_qpack_encoder * encoder,size_t max_dtable_capacity)951 void nghttp3_qpack_encoder_set_max_dtable_capacity(
952 nghttp3_qpack_encoder *encoder, size_t max_dtable_capacity) {
953 max_dtable_capacity =
954 nghttp3_min(max_dtable_capacity, encoder->ctx.hard_max_dtable_capacity);
955
956 if (encoder->ctx.max_dtable_capacity == max_dtable_capacity) {
957 return;
958 }
959
960 encoder->flags |= NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP;
961
962 if (encoder->min_dtable_update > max_dtable_capacity) {
963 encoder->min_dtable_update = max_dtable_capacity;
964 encoder->ctx.max_dtable_capacity = max_dtable_capacity;
965 }
966 encoder->last_max_dtable_update = max_dtable_capacity;
967 }
968
nghttp3_qpack_encoder_set_max_blocked_streams(nghttp3_qpack_encoder * encoder,size_t max_blocked_streams)969 void nghttp3_qpack_encoder_set_max_blocked_streams(
970 nghttp3_qpack_encoder *encoder, size_t max_blocked_streams) {
971 encoder->ctx.max_blocked_streams = max_blocked_streams;
972 }
973
nghttp3_qpack_encoder_get_min_cnt(nghttp3_qpack_encoder * encoder)974 uint64_t nghttp3_qpack_encoder_get_min_cnt(nghttp3_qpack_encoder *encoder) {
975 assert(!nghttp3_pq_empty(&encoder->min_cnts));
976
977 return nghttp3_struct_of(nghttp3_pq_top(&encoder->min_cnts),
978 nghttp3_qpack_header_block_ref, min_cnts_pe)
979 ->min_cnt;
980 }
981
nghttp3_qpack_encoder_shrink_dtable(nghttp3_qpack_encoder * encoder)982 void nghttp3_qpack_encoder_shrink_dtable(nghttp3_qpack_encoder *encoder) {
983 nghttp3_ringbuf *dtable = &encoder->ctx.dtable;
984 const nghttp3_mem *mem = encoder->ctx.mem;
985 uint64_t min_cnt = UINT64_MAX;
986 size_t len;
987 nghttp3_qpack_entry *ent;
988
989 if (encoder->ctx.dtable_size <= encoder->ctx.max_dtable_capacity) {
990 return;
991 }
992
993 if (!nghttp3_pq_empty(&encoder->min_cnts)) {
994 min_cnt = nghttp3_qpack_encoder_get_min_cnt(encoder);
995 }
996
997 for (; encoder->ctx.dtable_size > encoder->ctx.max_dtable_capacity;) {
998 len = nghttp3_ringbuf_len(dtable);
999 ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(dtable, len - 1);
1000 if (ent->absidx + 1 == min_cnt) {
1001 return;
1002 }
1003
1004 encoder->ctx.dtable_size -=
1005 table_space(ent->nv.name->len, ent->nv.value->len);
1006
1007 nghttp3_ringbuf_pop_back(dtable);
1008 qpack_map_remove(&encoder->dtable_map, ent);
1009
1010 nghttp3_qpack_entry_free(ent);
1011 nghttp3_mem_free(mem, ent);
1012 }
1013 }
1014
1015 /*
1016 * qpack_encoder_add_stream_ref adds another dynamic table reference
1017 * to a stream denoted by |stream_id|. |stream| must be NULL if no
1018 * stream object is not found for the given stream ID. |max_cnt| and
1019 * |min_cnt| is the maximum and minimum insert count it references
1020 * respectively.
1021 *
1022 * This function returns 0 if it succeeds, or one of the following
1023 * negative error codes:
1024 *
1025 * NGHTTP3_ERR_NOMEM
1026 * Out of memory.
1027 */
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)1028 static int qpack_encoder_add_stream_ref(nghttp3_qpack_encoder *encoder,
1029 int64_t stream_id,
1030 nghttp3_qpack_stream *stream,
1031 uint64_t max_cnt, uint64_t min_cnt) {
1032 nghttp3_qpack_header_block_ref *ref;
1033 const nghttp3_mem *mem = encoder->ctx.mem;
1034 uint64_t prev_max_cnt = 0;
1035 int rv;
1036
1037 if (stream == NULL) {
1038 rv = nghttp3_qpack_stream_new(&stream, stream_id, mem);
1039 if (rv != 0) {
1040 assert(rv == NGHTTP3_ERR_NOMEM);
1041 return rv;
1042 }
1043 rv = nghttp3_map_insert(&encoder->streams,
1044 (nghttp3_map_key_type)stream->stream_id, stream);
1045 if (rv != 0) {
1046 assert(rv == NGHTTP3_ERR_NOMEM);
1047 nghttp3_qpack_stream_del(stream, mem);
1048 return rv;
1049 }
1050 } else {
1051 prev_max_cnt = nghttp3_qpack_stream_get_max_cnt(stream);
1052 if (nghttp3_qpack_encoder_stream_is_blocked(encoder, stream) &&
1053 max_cnt > prev_max_cnt) {
1054 nghttp3_qpack_encoder_unblock_stream(encoder, stream);
1055 }
1056 }
1057
1058 rv = nghttp3_qpack_header_block_ref_new(&ref, max_cnt, min_cnt, mem);
1059 if (rv != 0) {
1060 return rv;
1061 }
1062
1063 rv = nghttp3_qpack_stream_add_ref(stream, ref);
1064 if (rv != 0) {
1065 nghttp3_qpack_header_block_ref_del(ref, mem);
1066 return rv;
1067 }
1068
1069 if (max_cnt > prev_max_cnt &&
1070 nghttp3_qpack_encoder_stream_is_blocked(encoder, stream)) {
1071 rv = nghttp3_qpack_encoder_block_stream(encoder, stream);
1072 if (rv != 0) {
1073 return rv;
1074 }
1075 }
1076
1077 return nghttp3_pq_push(&encoder->min_cnts, &ref->min_cnts_pe);
1078 }
1079
qpack_encoder_remove_stream(nghttp3_qpack_encoder * encoder,nghttp3_qpack_stream * stream)1080 static void qpack_encoder_remove_stream(nghttp3_qpack_encoder *encoder,
1081 nghttp3_qpack_stream *stream) {
1082 size_t i, len;
1083 nghttp3_qpack_header_block_ref *ref;
1084
1085 nghttp3_map_remove(&encoder->streams,
1086 (nghttp3_map_key_type)stream->stream_id);
1087
1088 len = nghttp3_ringbuf_len(&stream->refs);
1089 for (i = 0; i < len; ++i) {
1090 ref = *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs,
1091 i);
1092
1093 assert(ref->min_cnts_pe.index != NGHTTP3_PQ_BAD_INDEX);
1094
1095 nghttp3_pq_remove(&encoder->min_cnts, &ref->min_cnts_pe);
1096 }
1097 }
1098
1099 /*
1100 * reserve_buf_internal ensures that |buf| contains at least
1101 * |extra_size| of free space. In other words, if this function
1102 * succeeds, nghttp2_buf_left(buf) >= extra_size holds. |min_size| is
1103 * the minimum size of buffer. The allocated buffer has at least
1104 * |min_size| bytes.
1105 *
1106 * This function returns 0 if it succeeds, or one of the following
1107 * negative error codes:
1108 *
1109 * NGHTTP3_ERR_NOMEM
1110 * Out of memory.
1111 */
reserve_buf_internal(nghttp3_buf * buf,size_t extra_size,size_t min_size,const nghttp3_mem * mem)1112 static int reserve_buf_internal(nghttp3_buf *buf, size_t extra_size,
1113 size_t min_size, const nghttp3_mem *mem) {
1114 size_t left = nghttp3_buf_left(buf);
1115 size_t n = min_size, need;
1116
1117 if (left >= extra_size) {
1118 return 0;
1119 }
1120
1121 need = nghttp3_buf_cap(buf) + extra_size - left;
1122
1123 for (; n < need; n *= 2)
1124 ;
1125
1126 return nghttp3_buf_reserve(buf, n, mem);
1127 }
1128
reserve_buf_small(nghttp3_buf * buf,size_t extra_size,const nghttp3_mem * mem)1129 static int reserve_buf_small(nghttp3_buf *buf, size_t extra_size,
1130 const nghttp3_mem *mem) {
1131 return reserve_buf_internal(buf, extra_size, 32, mem);
1132 }
1133
reserve_buf(nghttp3_buf * buf,size_t extra_size,const nghttp3_mem * mem)1134 static int reserve_buf(nghttp3_buf *buf, size_t extra_size,
1135 const nghttp3_mem *mem) {
1136 return reserve_buf_internal(buf, extra_size, 32, mem);
1137 }
1138
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)1139 int nghttp3_qpack_encoder_encode(nghttp3_qpack_encoder *encoder,
1140 nghttp3_buf *pbuf, nghttp3_buf *rbuf,
1141 nghttp3_buf *ebuf, int64_t stream_id,
1142 const nghttp3_nv *nva, size_t nvlen) {
1143 size_t i;
1144 uint64_t max_cnt = 0, min_cnt = UINT64_MAX;
1145 uint64_t base;
1146 int rv = 0;
1147 int allow_blocking;
1148 int blocked_stream;
1149 nghttp3_qpack_stream *stream;
1150
1151 if (encoder->ctx.bad) {
1152 return NGHTTP3_ERR_QPACK_FATAL;
1153 }
1154
1155 rv = nghttp3_qpack_encoder_process_dtable_update(encoder, ebuf);
1156 if (rv != 0) {
1157 goto fail;
1158 }
1159
1160 base = encoder->ctx.next_absidx;
1161
1162 stream = nghttp3_qpack_encoder_find_stream(encoder, stream_id);
1163 blocked_stream =
1164 stream && nghttp3_qpack_encoder_stream_is_blocked(encoder, stream);
1165 allow_blocking =
1166 blocked_stream || encoder->ctx.max_blocked_streams >
1167 nghttp3_ksl_len(&encoder->blocked_streams);
1168
1169 DEBUGF("qpack::encode: stream %ld blocked=%d allow_blocking=%d\n", stream_id,
1170 blocked_stream, allow_blocking);
1171
1172 for (i = 0; i < nvlen; ++i) {
1173 rv = nghttp3_qpack_encoder_encode_nv(encoder, &max_cnt, &min_cnt, rbuf,
1174 ebuf, &nva[i], base, allow_blocking);
1175 if (rv != 0) {
1176 goto fail;
1177 }
1178 }
1179
1180 nghttp3_qpack_encoder_write_field_section_prefix(encoder, pbuf, max_cnt,
1181 base);
1182
1183 /* TODO If max_cnt == 0, no reference is made to dtable. */
1184 if (!max_cnt) {
1185 return 0;
1186 }
1187
1188 rv = qpack_encoder_add_stream_ref(encoder, stream_id, stream, max_cnt,
1189 min_cnt);
1190 if (rv != 0) {
1191 goto fail;
1192 }
1193
1194 return 0;
1195
1196 fail:
1197 encoder->ctx.bad = 1;
1198 return rv;
1199 }
1200
1201 /*
1202 * qpack_write_number writes variable integer to |rbuf|. |num| is an
1203 * integer to write. |prefix| is a prefix of variable integer
1204 * encoding.
1205 *
1206 * This function returns 0 if it succeeds, or one of the following
1207 * negative error codes:
1208 *
1209 * NGHTTP3_ERR_NOMEM
1210 * Out of memory.
1211 */
qpack_write_number(nghttp3_buf * rbuf,uint8_t fb,uint64_t num,size_t prefix,const nghttp3_mem * mem)1212 static int qpack_write_number(nghttp3_buf *rbuf, uint8_t fb, uint64_t num,
1213 size_t prefix, const nghttp3_mem *mem) {
1214 int rv;
1215 size_t len = nghttp3_qpack_put_varint_len(num, prefix);
1216 uint8_t *p;
1217
1218 rv = reserve_buf(rbuf, len, mem);
1219 if (rv != 0) {
1220 return rv;
1221 }
1222
1223 p = rbuf->last;
1224
1225 *p = fb;
1226 p = nghttp3_qpack_put_varint(p, num, prefix);
1227
1228 assert((size_t)(p - rbuf->last) == len);
1229
1230 rbuf->last = p;
1231
1232 return 0;
1233 }
1234
nghttp3_qpack_encoder_process_dtable_update(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf)1235 int nghttp3_qpack_encoder_process_dtable_update(nghttp3_qpack_encoder *encoder,
1236 nghttp3_buf *ebuf) {
1237 int rv;
1238
1239 nghttp3_qpack_encoder_shrink_dtable(encoder);
1240
1241 if (encoder->ctx.max_dtable_capacity < encoder->ctx.dtable_size ||
1242 !(encoder->flags & NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP)) {
1243 return 0;
1244 }
1245
1246 if (encoder->min_dtable_update < encoder->last_max_dtable_update) {
1247 rv = nghttp3_qpack_encoder_write_set_dtable_cap(encoder, ebuf,
1248 encoder->min_dtable_update);
1249 if (rv != 0) {
1250 return rv;
1251 }
1252 }
1253
1254 rv = nghttp3_qpack_encoder_write_set_dtable_cap(
1255 encoder, ebuf, encoder->last_max_dtable_update);
1256 if (rv != 0) {
1257 return rv;
1258 }
1259
1260 encoder->flags &= (uint8_t)~NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP;
1261 encoder->min_dtable_update = SIZE_MAX;
1262 encoder->ctx.max_dtable_capacity = encoder->last_max_dtable_update;
1263
1264 return 0;
1265 }
1266
nghttp3_qpack_encoder_write_set_dtable_cap(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,size_t cap)1267 int nghttp3_qpack_encoder_write_set_dtable_cap(nghttp3_qpack_encoder *encoder,
1268 nghttp3_buf *ebuf, size_t cap) {
1269 DEBUGF("qpack::encode: Set Dynamic Table Capacity capacity=%zu\n", cap);
1270 return qpack_write_number(ebuf, 0x20, cap, 5, encoder->ctx.mem);
1271 }
1272
1273 nghttp3_qpack_stream *
nghttp3_qpack_encoder_find_stream(nghttp3_qpack_encoder * encoder,int64_t stream_id)1274 nghttp3_qpack_encoder_find_stream(nghttp3_qpack_encoder *encoder,
1275 int64_t stream_id) {
1276 return nghttp3_map_find(&encoder->streams, (nghttp3_map_key_type)stream_id);
1277 }
1278
nghttp3_qpack_encoder_stream_is_blocked(nghttp3_qpack_encoder * encoder,nghttp3_qpack_stream * stream)1279 int nghttp3_qpack_encoder_stream_is_blocked(nghttp3_qpack_encoder *encoder,
1280 nghttp3_qpack_stream *stream) {
1281 return stream && encoder->krcnt < nghttp3_qpack_stream_get_max_cnt(stream);
1282 }
1283
1284 /*
1285 * qpack_encoder_decide_indexing_mode determines and returns indexing
1286 * mode for header field |nv|. |token| is a token of header field
1287 * name.
1288 */
1289 static nghttp3_qpack_indexing_mode
qpack_encoder_decide_indexing_mode(nghttp3_qpack_encoder * encoder,const nghttp3_nv * nv,int32_t token)1290 qpack_encoder_decide_indexing_mode(nghttp3_qpack_encoder *encoder,
1291 const nghttp3_nv *nv, int32_t token) {
1292 if (nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) {
1293 return NGHTTP3_QPACK_INDEXING_MODE_NEVER;
1294 }
1295
1296 switch (token) {
1297 case NGHTTP3_QPACK_TOKEN_AUTHORIZATION:
1298 return NGHTTP3_QPACK_INDEXING_MODE_NEVER;
1299 case NGHTTP3_QPACK_TOKEN_COOKIE:
1300 if (nv->valuelen < 20) {
1301 return NGHTTP3_QPACK_INDEXING_MODE_NEVER;
1302 }
1303 break;
1304 case -1:
1305 case NGHTTP3_QPACK_TOKEN__PATH:
1306 case NGHTTP3_QPACK_TOKEN_AGE:
1307 case NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH:
1308 case NGHTTP3_QPACK_TOKEN_ETAG:
1309 case NGHTTP3_QPACK_TOKEN_IF_MODIFIED_SINCE:
1310 case NGHTTP3_QPACK_TOKEN_IF_NONE_MATCH:
1311 case NGHTTP3_QPACK_TOKEN_LOCATION:
1312 case NGHTTP3_QPACK_TOKEN_SET_COOKIE:
1313 return NGHTTP3_QPACK_INDEXING_MODE_LITERAL;
1314 case NGHTTP3_QPACK_TOKEN_HOST:
1315 case NGHTTP3_QPACK_TOKEN_TE:
1316 case NGHTTP3_QPACK_TOKEN__PROTOCOL:
1317 case NGHTTP3_QPACK_TOKEN_PRIORITY:
1318 break;
1319 default:
1320 if (token >= 1000) {
1321 return NGHTTP3_QPACK_INDEXING_MODE_LITERAL;
1322 }
1323 }
1324
1325 if (table_space(nv->namelen, nv->valuelen) >
1326 encoder->ctx.max_dtable_capacity * 3 / 4) {
1327 return NGHTTP3_QPACK_INDEXING_MODE_LITERAL;
1328 }
1329
1330 return NGHTTP3_QPACK_INDEXING_MODE_STORE;
1331 }
1332
1333 /*
1334 * qpack_encoder_can_index returns nonzero if an entry which occupies
1335 * |need| bytes can be inserted into dynamic table. |min_cnt| is the
1336 * minimum insert count which blocked stream requires.
1337 */
qpack_encoder_can_index(nghttp3_qpack_encoder * encoder,size_t need,uint64_t min_cnt)1338 static int qpack_encoder_can_index(nghttp3_qpack_encoder *encoder, size_t need,
1339 uint64_t min_cnt) {
1340 size_t avail = 0;
1341 size_t len;
1342 uint64_t gmin_cnt;
1343 nghttp3_qpack_entry *min_ent, *last_ent;
1344 nghttp3_ringbuf *dtable = &encoder->ctx.dtable;
1345
1346 if (encoder->ctx.max_dtable_capacity > encoder->ctx.dtable_size) {
1347 avail = encoder->ctx.max_dtable_capacity - encoder->ctx.dtable_size;
1348 if (need <= avail) {
1349 return 1;
1350 }
1351 }
1352
1353 if (!nghttp3_pq_empty(&encoder->min_cnts)) {
1354 gmin_cnt = nghttp3_qpack_encoder_get_min_cnt(encoder);
1355 min_cnt = nghttp3_min(min_cnt, gmin_cnt);
1356 }
1357
1358 if (min_cnt == UINT64_MAX) {
1359 return encoder->ctx.max_dtable_capacity >= need;
1360 }
1361
1362 min_ent = nghttp3_qpack_context_dtable_get(&encoder->ctx, min_cnt - 1);
1363
1364 len = nghttp3_ringbuf_len(&encoder->ctx.dtable);
1365 assert(len);
1366 last_ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(dtable, len - 1);
1367
1368 if (min_ent == last_ent) {
1369 return 0;
1370 }
1371
1372 return avail + min_ent->sum - last_ent->sum >= need;
1373 }
1374
1375 /*
1376 * qpack_encoder_can_index_nv returns nonzero if header field |nv| can
1377 * be inserted into dynamic table. |min_cnt| is the minimum insert
1378 * count which blocked stream requires.
1379 */
qpack_encoder_can_index_nv(nghttp3_qpack_encoder * encoder,const nghttp3_nv * nv,uint64_t min_cnt)1380 static int qpack_encoder_can_index_nv(nghttp3_qpack_encoder *encoder,
1381 const nghttp3_nv *nv, uint64_t min_cnt) {
1382 return qpack_encoder_can_index(
1383 encoder, table_space(nv->namelen, nv->valuelen), min_cnt);
1384 }
1385
1386 /*
1387 * qpack_encoder_can_index_duplicate returns nonzero if an entry at
1388 * |absidx| in dynamic table can be inserted to dynamic table as
1389 * duplicate. |min_cnt| is the minimum insert count which blocked
1390 * stream requires.
1391 */
qpack_encoder_can_index_duplicate(nghttp3_qpack_encoder * encoder,uint64_t absidx,uint64_t min_cnt)1392 static int qpack_encoder_can_index_duplicate(nghttp3_qpack_encoder *encoder,
1393 uint64_t absidx,
1394 uint64_t min_cnt) {
1395 nghttp3_qpack_entry *ent =
1396 nghttp3_qpack_context_dtable_get(&encoder->ctx, absidx);
1397
1398 return qpack_encoder_can_index(
1399 encoder, table_space(ent->nv.name->len, ent->nv.value->len), min_cnt);
1400 }
1401
1402 /*
1403 * qpack_context_check_draining returns nonzero if an entry at
1404 * |absidx| in dynamic table is one of draining entries.
1405 */
qpack_context_check_draining(nghttp3_qpack_context * ctx,uint64_t absidx)1406 static int qpack_context_check_draining(nghttp3_qpack_context *ctx,
1407 uint64_t absidx) {
1408 const size_t safe = ctx->max_dtable_capacity -
1409 nghttp3_min(512, ctx->max_dtable_capacity * 1 / 8);
1410 nghttp3_qpack_entry *ent = nghttp3_qpack_context_dtable_get(ctx, absidx);
1411
1412 return ctx->dtable_sum - ent->sum > safe;
1413 }
1414
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)1415 int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder,
1416 uint64_t *pmax_cnt, uint64_t *pmin_cnt,
1417 nghttp3_buf *rbuf, nghttp3_buf *ebuf,
1418 const nghttp3_nv *nv, uint64_t base,
1419 int allow_blocking) {
1420 uint32_t hash = 0;
1421 int32_t token;
1422 nghttp3_qpack_indexing_mode indexing_mode;
1423 nghttp3_qpack_lookup_result sres = {-1, 0, -1}, dres = {-1, 0, -1};
1424 nghttp3_qpack_entry *new_ent = NULL;
1425 int static_entry;
1426 int just_index = 0;
1427 int rv;
1428
1429 token = qpack_lookup_token(nv->name, nv->namelen);
1430 static_entry = token != -1 && (size_t)token < nghttp3_arraylen(token_stable);
1431 if (static_entry) {
1432 hash = token_stable[token].hash;
1433 } else {
1434 switch (token) {
1435 case NGHTTP3_QPACK_TOKEN_HOST:
1436 hash = 2952701295u;
1437 break;
1438 case NGHTTP3_QPACK_TOKEN_TE:
1439 hash = 1011170994u;
1440 break;
1441 case NGHTTP3_QPACK_TOKEN__PROTOCOL:
1442 hash = 1128642621u;
1443 break;
1444 case NGHTTP3_QPACK_TOKEN_PRIORITY:
1445 hash = 2498028297u;
1446 break;
1447 }
1448 }
1449
1450 indexing_mode = qpack_encoder_decide_indexing_mode(encoder, nv, token);
1451
1452 if (static_entry) {
1453 sres = nghttp3_qpack_lookup_stable(nv, token, indexing_mode);
1454 if (sres.index != -1 && sres.name_value_match) {
1455 return nghttp3_qpack_encoder_write_static_indexed(encoder, rbuf,
1456 (size_t)sres.index);
1457 }
1458 }
1459
1460 if (hash &&
1461 nghttp3_map_size(&encoder->streams) < NGHTTP3_QPACK_MAX_QPACK_STREAMS) {
1462 dres = nghttp3_qpack_encoder_lookup_dtable(encoder, nv, token, hash,
1463 indexing_mode, encoder->krcnt,
1464 allow_blocking);
1465 just_index = indexing_mode == NGHTTP3_QPACK_INDEXING_MODE_STORE &&
1466 dres.pb_index == -1;
1467 }
1468
1469 if (dres.index != -1 && dres.name_value_match) {
1470 if (allow_blocking &&
1471 qpack_context_check_draining(&encoder->ctx, (size_t)dres.index) &&
1472 qpack_encoder_can_index_duplicate(encoder, (size_t)dres.index,
1473 *pmin_cnt)) {
1474 rv = nghttp3_qpack_encoder_write_duplicate_insert(encoder, ebuf,
1475 (size_t)dres.index);
1476 if (rv != 0) {
1477 return rv;
1478 }
1479 rv = nghttp3_qpack_encoder_dtable_duplicate_add(encoder,
1480 (size_t)dres.index);
1481 if (rv != 0) {
1482 return rv;
1483 }
1484
1485 new_ent = nghttp3_qpack_context_dtable_top(&encoder->ctx);
1486 dres.index = (nghttp3_ssize)new_ent->absidx;
1487 }
1488 *pmax_cnt = nghttp3_max(*pmax_cnt, (size_t)(dres.index + 1));
1489 *pmin_cnt = nghttp3_min(*pmin_cnt, (size_t)(dres.index + 1));
1490
1491 return nghttp3_qpack_encoder_write_dynamic_indexed(
1492 encoder, rbuf, (size_t)dres.index, base);
1493 }
1494
1495 if (sres.index != -1) {
1496 if (just_index && qpack_encoder_can_index_nv(encoder, nv, *pmin_cnt)) {
1497 rv = nghttp3_qpack_encoder_write_static_insert(encoder, ebuf,
1498 (size_t)sres.index, nv);
1499 if (rv != 0) {
1500 return rv;
1501 }
1502 rv = nghttp3_qpack_encoder_dtable_static_add(encoder, (size_t)sres.index,
1503 nv, hash);
1504 if (rv != 0) {
1505 return rv;
1506 }
1507 if (allow_blocking) {
1508 new_ent = nghttp3_qpack_context_dtable_top(&encoder->ctx);
1509 *pmax_cnt = nghttp3_max(*pmax_cnt, new_ent->absidx + 1);
1510 *pmin_cnt = nghttp3_min(*pmin_cnt, new_ent->absidx + 1);
1511
1512 return nghttp3_qpack_encoder_write_dynamic_indexed(
1513 encoder, rbuf, new_ent->absidx, base);
1514 }
1515 }
1516
1517 return nghttp3_qpack_encoder_write_static_indexed_name(
1518 encoder, rbuf, (size_t)sres.index, nv);
1519 }
1520
1521 if (dres.index != -1) {
1522 if (just_index &&
1523 qpack_encoder_can_index_nv(
1524 encoder, nv,
1525 allow_blocking ? *pmin_cnt
1526 : nghttp3_min((size_t)dres.index + 1, *pmin_cnt))) {
1527 rv = nghttp3_qpack_encoder_write_dynamic_insert(encoder, ebuf,
1528 (size_t)dres.index, nv);
1529 if (rv != 0) {
1530 return rv;
1531 }
1532
1533 if (!allow_blocking) {
1534 *pmin_cnt = nghttp3_min(*pmin_cnt, (size_t)dres.index + 1);
1535 }
1536
1537 rv = nghttp3_qpack_encoder_dtable_dynamic_add(encoder, (size_t)dres.index,
1538 nv, hash);
1539 if (rv != 0) {
1540 return rv;
1541 }
1542
1543 if (allow_blocking) {
1544 new_ent = nghttp3_qpack_context_dtable_top(&encoder->ctx);
1545 *pmax_cnt = nghttp3_max(*pmax_cnt, new_ent->absidx + 1);
1546 *pmin_cnt = nghttp3_min(*pmin_cnt, new_ent->absidx + 1);
1547
1548 return nghttp3_qpack_encoder_write_dynamic_indexed(
1549 encoder, rbuf, new_ent->absidx, base);
1550 }
1551 }
1552
1553 *pmax_cnt = nghttp3_max(*pmax_cnt, (size_t)(dres.index + 1));
1554 *pmin_cnt = nghttp3_min(*pmin_cnt, (size_t)(dres.index + 1));
1555
1556 return nghttp3_qpack_encoder_write_dynamic_indexed_name(
1557 encoder, rbuf, (size_t)dres.index, base, nv);
1558 }
1559
1560 if (just_index && qpack_encoder_can_index_nv(encoder, nv, *pmin_cnt)) {
1561 rv = nghttp3_qpack_encoder_dtable_literal_add(encoder, nv, token, hash);
1562 if (rv != 0) {
1563 return rv;
1564 }
1565 rv = nghttp3_qpack_encoder_write_literal_insert(encoder, ebuf, nv);
1566 if (rv != 0) {
1567 return rv;
1568 }
1569 if (allow_blocking) {
1570 new_ent = nghttp3_qpack_context_dtable_top(&encoder->ctx);
1571 *pmax_cnt = nghttp3_max(*pmax_cnt, new_ent->absidx + 1);
1572 *pmin_cnt = nghttp3_min(*pmin_cnt, new_ent->absidx + 1);
1573
1574 return nghttp3_qpack_encoder_write_dynamic_indexed(encoder, rbuf,
1575 new_ent->absidx, base);
1576 }
1577 }
1578
1579 return nghttp3_qpack_encoder_write_literal(encoder, rbuf, nv);
1580 }
1581
1582 nghttp3_qpack_lookup_result
nghttp3_qpack_lookup_stable(const nghttp3_nv * nv,int32_t token,nghttp3_qpack_indexing_mode indexing_mode)1583 nghttp3_qpack_lookup_stable(const nghttp3_nv *nv, int32_t token,
1584 nghttp3_qpack_indexing_mode indexing_mode) {
1585 nghttp3_qpack_lookup_result res = {(nghttp3_ssize)token_stable[token].absidx,
1586 0, -1};
1587 nghttp3_qpack_static_entry *ent;
1588 nghttp3_qpack_static_header *hdr;
1589 size_t i;
1590
1591 assert(token >= 0);
1592
1593 if (indexing_mode == NGHTTP3_QPACK_INDEXING_MODE_NEVER) {
1594 return res;
1595 }
1596
1597 for (i = (size_t)token;
1598 i < nghttp3_arraylen(token_stable) && token_stable[i].token == token;
1599 ++i) {
1600 ent = &token_stable[i];
1601 hdr = &stable[ent->absidx];
1602 if (hdr->value.len == nv->valuelen &&
1603 memeq(hdr->value.base, nv->value, nv->valuelen)) {
1604 res.index = (nghttp3_ssize)ent->absidx;
1605 res.name_value_match = 1;
1606 return res;
1607 }
1608 }
1609 return res;
1610 }
1611
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)1612 nghttp3_qpack_lookup_result nghttp3_qpack_encoder_lookup_dtable(
1613 nghttp3_qpack_encoder *encoder, const nghttp3_nv *nv, int32_t token,
1614 uint32_t hash, nghttp3_qpack_indexing_mode indexing_mode, uint64_t krcnt,
1615 int allow_blocking) {
1616 nghttp3_qpack_lookup_result res = {-1, 0, -1};
1617 int exact_match = 0;
1618 nghttp3_qpack_entry *match, *pb_match;
1619
1620 encoder_qpack_map_find(encoder, &exact_match, &match, &pb_match, nv, token,
1621 hash, krcnt, allow_blocking,
1622 indexing_mode == NGHTTP3_QPACK_INDEXING_MODE_NEVER);
1623 if (match) {
1624 res.index = (nghttp3_ssize)match->absidx;
1625 res.name_value_match = exact_match;
1626 }
1627 if (pb_match) {
1628 res.pb_index = (nghttp3_ssize)pb_match->absidx;
1629 }
1630
1631 return res;
1632 }
1633
nghttp3_qpack_header_block_ref_new(nghttp3_qpack_header_block_ref ** pref,uint64_t max_cnt,uint64_t min_cnt,const nghttp3_mem * mem)1634 int nghttp3_qpack_header_block_ref_new(nghttp3_qpack_header_block_ref **pref,
1635 uint64_t max_cnt, uint64_t min_cnt,
1636 const nghttp3_mem *mem) {
1637 nghttp3_qpack_header_block_ref *ref =
1638 nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_header_block_ref));
1639
1640 if (ref == NULL) {
1641 return NGHTTP3_ERR_NOMEM;
1642 }
1643
1644 ref->max_cnts_pe.index = NGHTTP3_PQ_BAD_INDEX;
1645 ref->min_cnts_pe.index = NGHTTP3_PQ_BAD_INDEX;
1646 ref->max_cnt = max_cnt;
1647 ref->min_cnt = min_cnt;
1648
1649 *pref = ref;
1650
1651 return 0;
1652 }
1653
nghttp3_qpack_header_block_ref_del(nghttp3_qpack_header_block_ref * ref,const nghttp3_mem * mem)1654 void nghttp3_qpack_header_block_ref_del(nghttp3_qpack_header_block_ref *ref,
1655 const nghttp3_mem *mem) {
1656 nghttp3_mem_free(mem, ref);
1657 }
1658
ref_max_cnt_greater(const nghttp3_pq_entry * lhsx,const nghttp3_pq_entry * rhsx)1659 static int ref_max_cnt_greater(const nghttp3_pq_entry *lhsx,
1660 const nghttp3_pq_entry *rhsx) {
1661 const nghttp3_qpack_header_block_ref *lhs =
1662 nghttp3_struct_of(lhsx, nghttp3_qpack_header_block_ref, max_cnts_pe);
1663 const nghttp3_qpack_header_block_ref *rhs =
1664 nghttp3_struct_of(rhsx, nghttp3_qpack_header_block_ref, max_cnts_pe);
1665
1666 return lhs->max_cnt > rhs->max_cnt;
1667 }
1668
nghttp3_qpack_stream_new(nghttp3_qpack_stream ** pstream,int64_t stream_id,const nghttp3_mem * mem)1669 int nghttp3_qpack_stream_new(nghttp3_qpack_stream **pstream, int64_t stream_id,
1670 const nghttp3_mem *mem) {
1671 int rv;
1672 nghttp3_qpack_stream *stream;
1673
1674 stream = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream));
1675 if (stream == NULL) {
1676 return NGHTTP3_ERR_NOMEM;
1677 }
1678
1679 rv = nghttp3_ringbuf_init(&stream->refs, 4,
1680 sizeof(nghttp3_qpack_header_block_ref *), mem);
1681 if (rv != 0) {
1682 nghttp3_mem_free(mem, stream);
1683 return rv;
1684 }
1685
1686 nghttp3_pq_init(&stream->max_cnts, ref_max_cnt_greater, mem);
1687
1688 stream->stream_id = stream_id;
1689
1690 *pstream = stream;
1691
1692 return 0;
1693 }
1694
nghttp3_qpack_stream_del(nghttp3_qpack_stream * stream,const nghttp3_mem * mem)1695 void nghttp3_qpack_stream_del(nghttp3_qpack_stream *stream,
1696 const nghttp3_mem *mem) {
1697 nghttp3_qpack_header_block_ref *ref;
1698 size_t i, len;
1699
1700 if (stream == NULL) {
1701 return;
1702 }
1703
1704 nghttp3_pq_free(&stream->max_cnts);
1705
1706 len = nghttp3_ringbuf_len(&stream->refs);
1707 for (i = 0; i < len; ++i) {
1708 ref = *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs,
1709 i);
1710 nghttp3_qpack_header_block_ref_del(ref, mem);
1711 }
1712
1713 nghttp3_ringbuf_free(&stream->refs);
1714
1715 nghttp3_mem_free(mem, stream);
1716 }
1717
nghttp3_qpack_stream_get_max_cnt(const nghttp3_qpack_stream * stream)1718 uint64_t nghttp3_qpack_stream_get_max_cnt(const nghttp3_qpack_stream *stream) {
1719 nghttp3_qpack_header_block_ref *ref;
1720
1721 if (nghttp3_pq_empty(&stream->max_cnts)) {
1722 return 0;
1723 }
1724
1725 ref = nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts),
1726 nghttp3_qpack_header_block_ref, max_cnts_pe);
1727 return ref->max_cnt;
1728 }
1729
nghttp3_qpack_stream_add_ref(nghttp3_qpack_stream * stream,nghttp3_qpack_header_block_ref * ref)1730 int nghttp3_qpack_stream_add_ref(nghttp3_qpack_stream *stream,
1731 nghttp3_qpack_header_block_ref *ref) {
1732 nghttp3_qpack_header_block_ref **dest;
1733 int rv;
1734
1735 if (nghttp3_ringbuf_full(&stream->refs)) {
1736 rv = nghttp3_ringbuf_reserve(&stream->refs,
1737 nghttp3_ringbuf_len(&stream->refs) * 2);
1738 if (rv != 0) {
1739 return rv;
1740 }
1741 }
1742
1743 dest = nghttp3_ringbuf_push_back(&stream->refs);
1744 *dest = ref;
1745
1746 return nghttp3_pq_push(&stream->max_cnts, &ref->max_cnts_pe);
1747 }
1748
nghttp3_qpack_stream_pop_ref(nghttp3_qpack_stream * stream)1749 void nghttp3_qpack_stream_pop_ref(nghttp3_qpack_stream *stream) {
1750 nghttp3_qpack_header_block_ref *ref;
1751
1752 assert(nghttp3_ringbuf_len(&stream->refs));
1753
1754 ref =
1755 *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs, 0);
1756
1757 assert(ref->max_cnts_pe.index != NGHTTP3_PQ_BAD_INDEX);
1758
1759 nghttp3_pq_remove(&stream->max_cnts, &ref->max_cnts_pe);
1760
1761 nghttp3_ringbuf_pop_front(&stream->refs);
1762 }
1763
nghttp3_qpack_encoder_write_static_indexed(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,uint64_t absidx)1764 int nghttp3_qpack_encoder_write_static_indexed(nghttp3_qpack_encoder *encoder,
1765 nghttp3_buf *rbuf,
1766 uint64_t absidx) {
1767 DEBUGF("qpack::encode: Indexed Field Line (static) absidx=%" PRIu64 "\n",
1768 absidx);
1769 return qpack_write_number(rbuf, 0xc0, absidx, 6, encoder->ctx.mem);
1770 }
1771
nghttp3_qpack_encoder_write_dynamic_indexed(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,uint64_t absidx,uint64_t base)1772 int nghttp3_qpack_encoder_write_dynamic_indexed(nghttp3_qpack_encoder *encoder,
1773 nghttp3_buf *rbuf,
1774 uint64_t absidx,
1775 uint64_t base) {
1776 DEBUGF("qpack::encode: Indexed Field Line (dynamic) absidx=%" PRIu64
1777 " base=%" PRIu64 "\n",
1778 absidx, base);
1779
1780 if (absidx < base) {
1781 return qpack_write_number(rbuf, 0x80, base - absidx - 1, 6,
1782 encoder->ctx.mem);
1783 }
1784
1785 return qpack_write_number(rbuf, 0x10, absidx - base, 4, encoder->ctx.mem);
1786 }
1787
1788 /*
1789 * qpack_encoder_write_indexed_name writes generic indexed name. |fb|
1790 * is the first byte. |nameidx| is an index of referenced name.
1791 * |prefix| is a prefix of variable integer encoding. |nv| is a
1792 * header field to encode.
1793 *
1794 * This function returns 0 if it succeeds, or one of the following
1795 * negative error codes:
1796 *
1797 * NGHTTP3_ERR_NOMEM
1798 * Out of memory.
1799 */
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)1800 static int qpack_encoder_write_indexed_name(nghttp3_qpack_encoder *encoder,
1801 nghttp3_buf *buf, uint8_t fb,
1802 uint64_t nameidx, size_t prefix,
1803 const nghttp3_nv *nv) {
1804 int rv;
1805 size_t len = nghttp3_qpack_put_varint_len(nameidx, prefix);
1806 uint8_t *p;
1807 size_t hlen;
1808 int h = 0;
1809
1810 hlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen);
1811 if (hlen < nv->valuelen) {
1812 h = 1;
1813 len += nghttp3_qpack_put_varint_len(hlen, 7) + hlen;
1814 } else {
1815 len += nghttp3_qpack_put_varint_len(nv->valuelen, 7) + nv->valuelen;
1816 }
1817
1818 rv = reserve_buf(buf, len, encoder->ctx.mem);
1819 if (rv != 0) {
1820 return rv;
1821 }
1822
1823 p = buf->last;
1824
1825 *p = fb;
1826 p = nghttp3_qpack_put_varint(p, nameidx, prefix);
1827
1828 if (h) {
1829 *p = 0x80;
1830 p = nghttp3_qpack_put_varint(p, hlen, 7);
1831 p = nghttp3_qpack_huffman_encode(p, nv->value, nv->valuelen);
1832 } else {
1833 *p = 0;
1834 p = nghttp3_qpack_put_varint(p, nv->valuelen, 7);
1835 if (nv->valuelen) {
1836 p = nghttp3_cpymem(p, nv->value, nv->valuelen);
1837 }
1838 }
1839
1840 assert((size_t)(p - buf->last) == len);
1841
1842 buf->last = p;
1843
1844 return 0;
1845 }
1846
nghttp3_qpack_encoder_write_static_indexed_name(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,uint64_t absidx,const nghttp3_nv * nv)1847 int nghttp3_qpack_encoder_write_static_indexed_name(
1848 nghttp3_qpack_encoder *encoder, nghttp3_buf *rbuf, uint64_t absidx,
1849 const nghttp3_nv *nv) {
1850 uint8_t fb =
1851 (uint8_t)(0x50 | ((nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? 0x20 : 0));
1852
1853 DEBUGF("qpack::encode: Literal Field Line With Name Reference (static) "
1854 "absidx=%" PRIu64 " never=%d\n",
1855 absidx, (nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) != 0);
1856 return qpack_encoder_write_indexed_name(encoder, rbuf, fb, absidx, 4, nv);
1857 }
1858
nghttp3_qpack_encoder_write_dynamic_indexed_name(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,uint64_t absidx,uint64_t base,const nghttp3_nv * nv)1859 int nghttp3_qpack_encoder_write_dynamic_indexed_name(
1860 nghttp3_qpack_encoder *encoder, nghttp3_buf *rbuf, uint64_t absidx,
1861 uint64_t base, const nghttp3_nv *nv) {
1862 uint8_t fb;
1863
1864 DEBUGF("qpack::encode: Literal Field Line With Name Reference (dynamic) "
1865 "absidx=%" PRIu64 " base=%" PRIu64 " never=%d\n",
1866 absidx, base, (nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) != 0);
1867
1868 if (absidx < base) {
1869 fb = (uint8_t)(0x40 |
1870 ((nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? 0x20 : 0));
1871 return qpack_encoder_write_indexed_name(encoder, rbuf, fb,
1872 base - absidx - 1, 4, nv);
1873 }
1874
1875 fb = (nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? 0x08 : 0;
1876 return qpack_encoder_write_indexed_name(encoder, rbuf, fb, absidx - base, 3,
1877 nv);
1878 }
1879
1880 /*
1881 * qpack_encoder_write_literal writes generic literal header field
1882 * representation. |fb| is a first byte. |prefix| is a prefix of
1883 * variable integer encoding for name length. |nv| is a header field
1884 * to encode.
1885 *
1886 * This function returns 0 if it succeeds, or one of the following
1887 * negative error codes:
1888 *
1889 * NGHTTP3_ERR_NOMEM
1890 * Out of memory.
1891 */
qpack_encoder_write_literal(nghttp3_qpack_encoder * encoder,nghttp3_buf * buf,uint8_t fb,size_t prefix,const nghttp3_nv * nv)1892 static int qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder,
1893 nghttp3_buf *buf, uint8_t fb,
1894 size_t prefix, const nghttp3_nv *nv) {
1895 int rv;
1896 size_t len;
1897 uint8_t *p;
1898 size_t nhlen, vhlen;
1899 int nh = 0, vh = 0;
1900
1901 nhlen = nghttp3_qpack_huffman_encode_count(nv->name, nv->namelen);
1902 if (nhlen < nv->namelen) {
1903 nh = 1;
1904 len = nghttp3_qpack_put_varint_len(nhlen, prefix) + nhlen;
1905 } else {
1906 len = nghttp3_qpack_put_varint_len(nv->namelen, prefix) + nv->namelen;
1907 }
1908
1909 vhlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen);
1910 if (vhlen < nv->valuelen) {
1911 vh = 1;
1912 len += nghttp3_qpack_put_varint_len(vhlen, 7) + vhlen;
1913 } else {
1914 len += nghttp3_qpack_put_varint_len(nv->valuelen, 7) + nv->valuelen;
1915 }
1916
1917 rv = reserve_buf(buf, len, encoder->ctx.mem);
1918 if (rv != 0) {
1919 return rv;
1920 }
1921
1922 p = buf->last;
1923
1924 *p = fb;
1925 if (nh) {
1926 *p |= (uint8_t)(1 << prefix);
1927 p = nghttp3_qpack_put_varint(p, nhlen, prefix);
1928 p = nghttp3_qpack_huffman_encode(p, nv->name, nv->namelen);
1929 } else {
1930 p = nghttp3_qpack_put_varint(p, nv->namelen, prefix);
1931 if (nv->namelen) {
1932 p = nghttp3_cpymem(p, nv->name, nv->namelen);
1933 }
1934 }
1935
1936 *p = 0;
1937
1938 if (vh) {
1939 *p |= 0x80;
1940 p = nghttp3_qpack_put_varint(p, vhlen, 7);
1941 p = nghttp3_qpack_huffman_encode(p, nv->value, nv->valuelen);
1942 } else {
1943 p = nghttp3_qpack_put_varint(p, nv->valuelen, 7);
1944 if (nv->valuelen) {
1945 p = nghttp3_cpymem(p, nv->value, nv->valuelen);
1946 }
1947 }
1948
1949 assert((size_t)(p - buf->last) == len);
1950
1951 buf->last = p;
1952
1953 return 0;
1954 }
1955
nghttp3_qpack_encoder_write_literal(nghttp3_qpack_encoder * encoder,nghttp3_buf * rbuf,const nghttp3_nv * nv)1956 int nghttp3_qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder,
1957 nghttp3_buf *rbuf,
1958 const nghttp3_nv *nv) {
1959 uint8_t fb =
1960 (uint8_t)(0x20 | ((nv->flags & NGHTTP3_NV_FLAG_NEVER_INDEX) ? 0x10 : 0));
1961
1962 DEBUGF("qpack::encode: Literal Field Line With Literal Name\n");
1963 return qpack_encoder_write_literal(encoder, rbuf, fb, 3, nv);
1964 }
1965
nghttp3_qpack_encoder_write_static_insert(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,uint64_t absidx,const nghttp3_nv * nv)1966 int nghttp3_qpack_encoder_write_static_insert(nghttp3_qpack_encoder *encoder,
1967 nghttp3_buf *ebuf,
1968 uint64_t absidx,
1969 const nghttp3_nv *nv) {
1970 DEBUGF("qpack::encode: Insert With Name Reference (static) absidx=%" PRIu64
1971 "\n",
1972 absidx);
1973 return qpack_encoder_write_indexed_name(encoder, ebuf, 0xc0, absidx, 6, nv);
1974 }
1975
nghttp3_qpack_encoder_write_dynamic_insert(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,uint64_t absidx,const nghttp3_nv * nv)1976 int nghttp3_qpack_encoder_write_dynamic_insert(nghttp3_qpack_encoder *encoder,
1977 nghttp3_buf *ebuf,
1978 uint64_t absidx,
1979 const nghttp3_nv *nv) {
1980 DEBUGF("qpack::encode: Insert With Name Reference (dynamic) absidx=%" PRIu64
1981 "\n",
1982 absidx);
1983 return qpack_encoder_write_indexed_name(
1984 encoder, ebuf, 0x80, encoder->ctx.next_absidx - absidx - 1, 6, nv);
1985 }
1986
nghttp3_qpack_encoder_write_duplicate_insert(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,uint64_t absidx)1987 int nghttp3_qpack_encoder_write_duplicate_insert(nghttp3_qpack_encoder *encoder,
1988 nghttp3_buf *ebuf,
1989 uint64_t absidx) {
1990 uint64_t idx = encoder->ctx.next_absidx - absidx - 1;
1991 size_t len = nghttp3_qpack_put_varint_len(idx, 5);
1992 uint8_t *p;
1993 int rv;
1994
1995 DEBUGF("qpack::encode: Insert duplicate absidx=%" PRIu64 "\n", absidx);
1996
1997 rv = reserve_buf(ebuf, len, encoder->ctx.mem);
1998 if (rv != 0) {
1999 return rv;
2000 }
2001
2002 p = ebuf->last;
2003
2004 *p = 0;
2005 p = nghttp3_qpack_put_varint(p, idx, 5);
2006
2007 assert((size_t)(p - ebuf->last) == len);
2008
2009 ebuf->last = p;
2010
2011 return 0;
2012 }
2013
nghttp3_qpack_encoder_write_literal_insert(nghttp3_qpack_encoder * encoder,nghttp3_buf * ebuf,const nghttp3_nv * nv)2014 int nghttp3_qpack_encoder_write_literal_insert(nghttp3_qpack_encoder *encoder,
2015 nghttp3_buf *ebuf,
2016 const nghttp3_nv *nv) {
2017 DEBUGF("qpack::encode: Insert With Literal Name\n");
2018 return qpack_encoder_write_literal(encoder, ebuf, 0x40, 5, nv);
2019 }
2020
nghttp3_qpack_context_dtable_add(nghttp3_qpack_context * ctx,nghttp3_qpack_nv * qnv,nghttp3_qpack_map * dtable_map,uint32_t hash)2021 int nghttp3_qpack_context_dtable_add(nghttp3_qpack_context *ctx,
2022 nghttp3_qpack_nv *qnv,
2023 nghttp3_qpack_map *dtable_map,
2024 uint32_t hash) {
2025 nghttp3_qpack_entry *new_ent, **p, *ent;
2026 const nghttp3_mem *mem = ctx->mem;
2027 size_t space;
2028 size_t i;
2029 int rv;
2030
2031 space = table_space(qnv->name->len, qnv->value->len);
2032
2033 assert(space <= ctx->max_dtable_capacity);
2034
2035 while (ctx->dtable_size + space > ctx->max_dtable_capacity) {
2036 i = nghttp3_ringbuf_len(&ctx->dtable);
2037 assert(i);
2038 ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, i - 1);
2039
2040 ctx->dtable_size -= table_space(ent->nv.name->len, ent->nv.value->len);
2041
2042 nghttp3_ringbuf_pop_back(&ctx->dtable);
2043 if (dtable_map) {
2044 qpack_map_remove(dtable_map, ent);
2045 }
2046
2047 nghttp3_qpack_entry_free(ent);
2048 nghttp3_mem_free(mem, ent);
2049 }
2050
2051 new_ent = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_entry));
2052 if (new_ent == NULL) {
2053 return NGHTTP3_ERR_NOMEM;
2054 }
2055
2056 nghttp3_qpack_entry_init(new_ent, qnv, ctx->dtable_sum, ctx->next_absidx++,
2057 hash);
2058
2059 if (nghttp3_ringbuf_full(&ctx->dtable)) {
2060 rv = nghttp3_ringbuf_reserve(&ctx->dtable,
2061 nghttp3_ringbuf_len(&ctx->dtable) * 2);
2062 if (rv != 0) {
2063 goto fail;
2064 }
2065 }
2066
2067 p = nghttp3_ringbuf_push_front(&ctx->dtable);
2068 *p = new_ent;
2069
2070 if (dtable_map) {
2071 qpack_map_insert(dtable_map, new_ent);
2072 }
2073
2074 ctx->dtable_size += space;
2075 ctx->dtable_sum += space;
2076
2077 return 0;
2078
2079 fail:
2080 nghttp3_qpack_entry_free(new_ent);
2081 nghttp3_mem_free(mem, new_ent);
2082
2083 return rv;
2084 }
2085
nghttp3_qpack_encoder_dtable_static_add(nghttp3_qpack_encoder * encoder,uint64_t absidx,const nghttp3_nv * nv,uint32_t hash)2086 int nghttp3_qpack_encoder_dtable_static_add(nghttp3_qpack_encoder *encoder,
2087 uint64_t absidx,
2088 const nghttp3_nv *nv,
2089 uint32_t hash) {
2090 const nghttp3_qpack_static_header *shd;
2091 nghttp3_qpack_nv qnv;
2092 const nghttp3_mem *mem = encoder->ctx.mem;
2093 int rv;
2094
2095 rv = nghttp3_rcbuf_new2(&qnv.value, nv->value, nv->valuelen, mem);
2096 if (rv != 0) {
2097 return rv;
2098 }
2099
2100 assert(nghttp3_arraylen(stable) > absidx);
2101
2102 shd = &stable[absidx];
2103
2104 qnv.name = (nghttp3_rcbuf *)&shd->name;
2105 qnv.token = shd->token;
2106 qnv.flags = NGHTTP3_NV_FLAG_NONE;
2107
2108 rv = nghttp3_qpack_context_dtable_add(&encoder->ctx, &qnv,
2109 &encoder->dtable_map, hash);
2110
2111 nghttp3_rcbuf_decref(qnv.value);
2112
2113 return rv;
2114 }
2115
nghttp3_qpack_encoder_dtable_dynamic_add(nghttp3_qpack_encoder * encoder,uint64_t absidx,const nghttp3_nv * nv,uint32_t hash)2116 int nghttp3_qpack_encoder_dtable_dynamic_add(nghttp3_qpack_encoder *encoder,
2117 uint64_t absidx,
2118 const nghttp3_nv *nv,
2119 uint32_t hash) {
2120 nghttp3_qpack_nv qnv;
2121 nghttp3_qpack_entry *ent;
2122 const nghttp3_mem *mem = encoder->ctx.mem;
2123 int rv;
2124
2125 rv = nghttp3_rcbuf_new2(&qnv.value, nv->value, nv->valuelen, mem);
2126 if (rv != 0) {
2127 return rv;
2128 }
2129
2130 ent = nghttp3_qpack_context_dtable_get(&encoder->ctx, absidx);
2131
2132 qnv.name = ent->nv.name;
2133 qnv.token = ent->nv.token;
2134 qnv.flags = NGHTTP3_NV_FLAG_NONE;
2135
2136 nghttp3_rcbuf_incref(qnv.name);
2137
2138 rv = nghttp3_qpack_context_dtable_add(&encoder->ctx, &qnv,
2139 &encoder->dtable_map, hash);
2140
2141 nghttp3_rcbuf_decref(qnv.value);
2142 nghttp3_rcbuf_decref(qnv.name);
2143
2144 return rv;
2145 }
2146
nghttp3_qpack_encoder_dtable_duplicate_add(nghttp3_qpack_encoder * encoder,uint64_t absidx)2147 int nghttp3_qpack_encoder_dtable_duplicate_add(nghttp3_qpack_encoder *encoder,
2148 uint64_t absidx) {
2149 nghttp3_qpack_nv qnv;
2150 nghttp3_qpack_entry *ent;
2151 int rv;
2152
2153 ent = nghttp3_qpack_context_dtable_get(&encoder->ctx, absidx);
2154
2155 qnv = ent->nv;
2156 nghttp3_rcbuf_incref(qnv.name);
2157 nghttp3_rcbuf_incref(qnv.value);
2158
2159 rv = nghttp3_qpack_context_dtable_add(&encoder->ctx, &qnv,
2160 &encoder->dtable_map, ent->hash);
2161
2162 nghttp3_rcbuf_decref(qnv.name);
2163 nghttp3_rcbuf_decref(qnv.value);
2164
2165 return rv;
2166 }
2167
nghttp3_qpack_encoder_dtable_literal_add(nghttp3_qpack_encoder * encoder,const nghttp3_nv * nv,int32_t token,uint32_t hash)2168 int nghttp3_qpack_encoder_dtable_literal_add(nghttp3_qpack_encoder *encoder,
2169 const nghttp3_nv *nv,
2170 int32_t token, uint32_t hash) {
2171 nghttp3_qpack_nv qnv;
2172 const nghttp3_mem *mem = encoder->ctx.mem;
2173 int rv;
2174
2175 rv = nghttp3_rcbuf_new2(&qnv.name, nv->name, nv->namelen, mem);
2176 if (rv != 0) {
2177 return rv;
2178 }
2179
2180 rv = nghttp3_rcbuf_new2(&qnv.value, nv->value, nv->valuelen, mem);
2181 if (rv != 0) {
2182 nghttp3_rcbuf_decref(qnv.name);
2183 return rv;
2184 }
2185
2186 qnv.token = token;
2187 qnv.flags = NGHTTP3_NV_FLAG_NONE;
2188
2189 rv = nghttp3_qpack_context_dtable_add(&encoder->ctx, &qnv,
2190 &encoder->dtable_map, hash);
2191
2192 nghttp3_rcbuf_decref(qnv.value);
2193 nghttp3_rcbuf_decref(qnv.name);
2194
2195 return rv;
2196 }
2197
2198 nghttp3_qpack_entry *
nghttp3_qpack_context_dtable_get(nghttp3_qpack_context * ctx,uint64_t absidx)2199 nghttp3_qpack_context_dtable_get(nghttp3_qpack_context *ctx, uint64_t absidx) {
2200 size_t relidx;
2201
2202 assert(ctx->next_absidx > absidx);
2203 assert(ctx->next_absidx - absidx - 1 < nghttp3_ringbuf_len(&ctx->dtable));
2204
2205 relidx = (size_t)(ctx->next_absidx - absidx - 1);
2206
2207 return *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, relidx);
2208 }
2209
2210 nghttp3_qpack_entry *
nghttp3_qpack_context_dtable_top(nghttp3_qpack_context * ctx)2211 nghttp3_qpack_context_dtable_top(nghttp3_qpack_context *ctx) {
2212 assert(nghttp3_ringbuf_len(&ctx->dtable));
2213 return *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, 0);
2214 }
2215
nghttp3_qpack_entry_init(nghttp3_qpack_entry * ent,nghttp3_qpack_nv * qnv,size_t sum,uint64_t absidx,uint32_t hash)2216 void nghttp3_qpack_entry_init(nghttp3_qpack_entry *ent, nghttp3_qpack_nv *qnv,
2217 size_t sum, uint64_t absidx, uint32_t hash) {
2218 ent->nv = *qnv;
2219 ent->map_next = NULL;
2220 ent->sum = sum;
2221 ent->absidx = absidx;
2222 ent->hash = hash;
2223
2224 nghttp3_rcbuf_incref(ent->nv.name);
2225 nghttp3_rcbuf_incref(ent->nv.value);
2226 }
2227
nghttp3_qpack_entry_free(nghttp3_qpack_entry * ent)2228 void nghttp3_qpack_entry_free(nghttp3_qpack_entry *ent) {
2229 nghttp3_rcbuf_decref(ent->nv.value);
2230 nghttp3_rcbuf_decref(ent->nv.name);
2231 }
2232
nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder * encoder,nghttp3_qpack_stream * stream)2233 int nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder *encoder,
2234 nghttp3_qpack_stream *stream) {
2235 nghttp3_blocked_streams_key bsk = {
2236 nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts),
2237 nghttp3_qpack_header_block_ref, max_cnts_pe)
2238 ->max_cnt,
2239 (uint64_t)stream->stream_id};
2240
2241 return nghttp3_ksl_insert(&encoder->blocked_streams, NULL, &bsk, stream);
2242 }
2243
nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder * encoder,nghttp3_qpack_stream * stream)2244 void nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder *encoder,
2245 nghttp3_qpack_stream *stream) {
2246 nghttp3_blocked_streams_key bsk = {
2247 nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts),
2248 nghttp3_qpack_header_block_ref, max_cnts_pe)
2249 ->max_cnt,
2250 (uint64_t)stream->stream_id};
2251 nghttp3_ksl_it it;
2252
2253 /* This is purely debugging purpose only */
2254 it = nghttp3_ksl_lower_bound(&encoder->blocked_streams, &bsk);
2255
2256 assert(!nghttp3_ksl_it_end(&it));
2257 assert(nghttp3_ksl_it_get(&it) == stream);
2258
2259 nghttp3_ksl_remove_hint(&encoder->blocked_streams, NULL, &it, &bsk);
2260 }
2261
nghttp3_qpack_encoder_unblock(nghttp3_qpack_encoder * encoder,uint64_t max_cnt)2262 void nghttp3_qpack_encoder_unblock(nghttp3_qpack_encoder *encoder,
2263 uint64_t max_cnt) {
2264 nghttp3_blocked_streams_key bsk = {max_cnt, 0};
2265 nghttp3_ksl_it it;
2266
2267 it = nghttp3_ksl_lower_bound(&encoder->blocked_streams, &bsk);
2268
2269 for (; !nghttp3_ksl_it_end(&it);) {
2270 bsk = *(nghttp3_blocked_streams_key *)nghttp3_ksl_it_key(&it);
2271 nghttp3_ksl_remove_hint(&encoder->blocked_streams, &it, &it, &bsk);
2272 }
2273 }
2274
nghttp3_qpack_encoder_ack_header(nghttp3_qpack_encoder * encoder,int64_t stream_id)2275 int nghttp3_qpack_encoder_ack_header(nghttp3_qpack_encoder *encoder,
2276 int64_t stream_id) {
2277 nghttp3_qpack_stream *stream =
2278 nghttp3_qpack_encoder_find_stream(encoder, stream_id);
2279 const nghttp3_mem *mem = encoder->ctx.mem;
2280 nghttp3_qpack_header_block_ref *ref;
2281
2282 if (stream == NULL) {
2283 return NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR;
2284 }
2285
2286 assert(nghttp3_ringbuf_len(&stream->refs));
2287
2288 ref =
2289 *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs, 0);
2290
2291 DEBUGF("qpack::encoder: Header acknowledgement stream=%ld ricnt=%" PRIu64
2292 " krcnt=%" PRIu64 "\n",
2293 stream_id, ref->max_cnt, encoder->krcnt);
2294
2295 if (encoder->krcnt < ref->max_cnt) {
2296 encoder->krcnt = ref->max_cnt;
2297
2298 nghttp3_qpack_encoder_unblock(encoder, ref->max_cnt);
2299 }
2300
2301 nghttp3_qpack_stream_pop_ref(stream);
2302
2303 assert(ref->min_cnts_pe.index != NGHTTP3_PQ_BAD_INDEX);
2304
2305 nghttp3_pq_remove(&encoder->min_cnts, &ref->min_cnts_pe);
2306
2307 nghttp3_qpack_header_block_ref_del(ref, mem);
2308
2309 if (nghttp3_ringbuf_len(&stream->refs)) {
2310 return 0;
2311 }
2312
2313 qpack_encoder_remove_stream(encoder, stream);
2314
2315 nghttp3_qpack_stream_del(stream, mem);
2316
2317 return 0;
2318 }
2319
nghttp3_qpack_encoder_add_icnt(nghttp3_qpack_encoder * encoder,uint64_t n)2320 int nghttp3_qpack_encoder_add_icnt(nghttp3_qpack_encoder *encoder, uint64_t n) {
2321 if (n == 0 || encoder->ctx.next_absidx - encoder->krcnt < n) {
2322 return NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR;
2323 }
2324 encoder->krcnt += n;
2325
2326 nghttp3_qpack_encoder_unblock(encoder, encoder->krcnt);
2327
2328 return 0;
2329 }
2330
nghttp3_qpack_encoder_ack_everything(nghttp3_qpack_encoder * encoder)2331 void nghttp3_qpack_encoder_ack_everything(nghttp3_qpack_encoder *encoder) {
2332 encoder->krcnt = encoder->ctx.next_absidx;
2333
2334 nghttp3_ksl_clear(&encoder->blocked_streams);
2335 nghttp3_pq_clear(&encoder->min_cnts);
2336 nghttp3_map_each_free(&encoder->streams, map_stream_free,
2337 (void *)encoder->ctx.mem);
2338 nghttp3_map_clear(&encoder->streams);
2339 }
2340
nghttp3_qpack_encoder_cancel_stream(nghttp3_qpack_encoder * encoder,int64_t stream_id)2341 void nghttp3_qpack_encoder_cancel_stream(nghttp3_qpack_encoder *encoder,
2342 int64_t stream_id) {
2343 nghttp3_qpack_stream *stream =
2344 nghttp3_qpack_encoder_find_stream(encoder, stream_id);
2345 const nghttp3_mem *mem = encoder->ctx.mem;
2346
2347 if (stream == NULL) {
2348 return;
2349 }
2350
2351 if (nghttp3_qpack_encoder_stream_is_blocked(encoder, stream)) {
2352 nghttp3_qpack_encoder_unblock_stream(encoder, stream);
2353 }
2354
2355 qpack_encoder_remove_stream(encoder, stream);
2356
2357 nghttp3_qpack_stream_del(stream, mem);
2358 }
2359
2360 size_t
nghttp3_qpack_encoder_get_num_blocked_streams(nghttp3_qpack_encoder * encoder)2361 nghttp3_qpack_encoder_get_num_blocked_streams(nghttp3_qpack_encoder *encoder) {
2362 return nghttp3_ksl_len(&encoder->blocked_streams);
2363 }
2364
nghttp3_qpack_encoder_write_field_section_prefix(nghttp3_qpack_encoder * encoder,nghttp3_buf * pbuf,uint64_t ricnt,uint64_t base)2365 int nghttp3_qpack_encoder_write_field_section_prefix(
2366 nghttp3_qpack_encoder *encoder, nghttp3_buf *pbuf, uint64_t ricnt,
2367 uint64_t base) {
2368 size_t max_ents =
2369 encoder->ctx.hard_max_dtable_capacity / NGHTTP3_QPACK_ENTRY_OVERHEAD;
2370 uint64_t encricnt = ricnt == 0 ? 0 : (ricnt % (2 * max_ents)) + 1;
2371 int sign = base < ricnt;
2372 uint64_t delta_base = sign ? ricnt - base - 1 : base - ricnt;
2373 size_t len = nghttp3_qpack_put_varint_len(encricnt, 8) +
2374 nghttp3_qpack_put_varint_len(delta_base, 7);
2375 uint8_t *p;
2376 int rv;
2377
2378 DEBUGF("qpack::encode: ricnt=%" PRIu64 " base=%" PRIu64 " icnt=%" PRIu64 "\n",
2379 ricnt, base, encoder->ctx.next_absidx);
2380
2381 rv = reserve_buf(pbuf, len, encoder->ctx.mem);
2382 if (rv != 0) {
2383 return rv;
2384 }
2385
2386 p = pbuf->last;
2387
2388 p = nghttp3_qpack_put_varint(p, encricnt, 8);
2389 if (sign) {
2390 *p = 0x80;
2391 } else {
2392 *p = 0;
2393 }
2394 p = nghttp3_qpack_put_varint(p, delta_base, 7);
2395
2396 assert((size_t)(p - pbuf->last) == len);
2397
2398 pbuf->last = p;
2399
2400 return 0;
2401 }
2402
2403 /*
2404 * qpack_read_varint reads |rstate->prefix| prefixed integer stored
2405 * from |begin|. The |end| represents the 1 beyond the last of the
2406 * valid contiguous memory region from |begin|. The decoded integer
2407 * must be less than or equal to NGHTTP3_QPACK_INT_MAX.
2408 *
2409 * If the |rstate->left| is nonzero, it is used as an initial value,
2410 * and this function assumes the |begin| starts with intermediate
2411 * data. |rstate->shift| is used as initial integer shift.
2412 *
2413 * If an entire integer is decoded successfully, the |*fin| is set to
2414 * nonzero.
2415 *
2416 * This function stores the decoded integer in |rstate->left| if it
2417 * succeeds, including partial decoding (in this case, number of shift
2418 * to make in the next call will be stored in |rstate->shift|) and
2419 * returns number of bytes processed, or returns negative error code
2420 * NGHTTP3_ERR_QPACK_FATAL, indicating decoding error.
2421 */
qpack_read_varint(int * fin,nghttp3_qpack_read_state * rstate,const uint8_t * begin,const uint8_t * end)2422 static nghttp3_ssize qpack_read_varint(int *fin,
2423 nghttp3_qpack_read_state *rstate,
2424 const uint8_t *begin,
2425 const uint8_t *end) {
2426 uint64_t k = (uint8_t)((1 << rstate->prefix) - 1);
2427 uint64_t n = rstate->left;
2428 uint64_t add;
2429 const uint8_t *p = begin;
2430 size_t shift = rstate->shift;
2431
2432 rstate->shift = 0;
2433 *fin = 0;
2434
2435 if (n == 0) {
2436 if (((*p) & k) != k) {
2437 rstate->left = (*p) & k;
2438 *fin = 1;
2439 return 1;
2440 }
2441
2442 n = k;
2443
2444 if (++p == end) {
2445 rstate->left = n;
2446 return (nghttp3_ssize)(p - begin);
2447 }
2448 }
2449
2450 for (; p != end; ++p, shift += 7) {
2451 add = (*p) & 0x7f;
2452
2453 if (shift > 62) {
2454 return NGHTTP3_ERR_QPACK_FATAL;
2455 }
2456
2457 if ((NGHTTP3_QPACK_INT_MAX >> shift) < add) {
2458 return NGHTTP3_ERR_QPACK_FATAL;
2459 }
2460
2461 add <<= shift;
2462
2463 if (NGHTTP3_QPACK_INT_MAX - add < n) {
2464 return NGHTTP3_ERR_QPACK_FATAL;
2465 }
2466
2467 n += add;
2468
2469 if (((*p) & (1 << 7)) == 0) {
2470 break;
2471 }
2472 }
2473
2474 rstate->shift = shift;
2475
2476 if (p == end) {
2477 rstate->left = n;
2478 return (nghttp3_ssize)(p - begin);
2479 }
2480
2481 rstate->left = n;
2482 *fin = 1;
2483 return (nghttp3_ssize)(p + 1 - begin);
2484 }
2485
nghttp3_qpack_encoder_read_decoder(nghttp3_qpack_encoder * encoder,const uint8_t * src,size_t srclen)2486 nghttp3_ssize nghttp3_qpack_encoder_read_decoder(nghttp3_qpack_encoder *encoder,
2487 const uint8_t *src,
2488 size_t srclen) {
2489 const uint8_t *p = src, *end;
2490 int rv;
2491 nghttp3_ssize nread;
2492 int rfin;
2493
2494 if (encoder->ctx.bad) {
2495 return NGHTTP3_ERR_QPACK_FATAL;
2496 }
2497
2498 if (srclen == 0) {
2499 return 0;
2500 }
2501
2502 end = src + srclen;
2503
2504 for (; p != end;) {
2505 switch (encoder->state) {
2506 case NGHTTP3_QPACK_DS_STATE_OPCODE:
2507 if ((*p) & 0x80) {
2508 DEBUGF("qpack::encode: OPCODE_SECTION_ACK\n");
2509 encoder->opcode = NGHTTP3_QPACK_DS_OPCODE_SECTION_ACK;
2510 encoder->rstate.prefix = 7;
2511 } else if ((*p) & 0x40) {
2512 DEBUGF("qpack::encode: OPCODE_STREAM_CANCEL\n");
2513 encoder->opcode = NGHTTP3_QPACK_DS_OPCODE_STREAM_CANCEL;
2514 encoder->rstate.prefix = 6;
2515 } else {
2516 DEBUGF("qpack::encode: OPCODE_ICNT_INCREMENT\n");
2517 encoder->opcode = NGHTTP3_QPACK_DS_OPCODE_ICNT_INCREMENT;
2518 encoder->rstate.prefix = 6;
2519 }
2520 encoder->state = NGHTTP3_QPACK_DS_STATE_READ_NUMBER;
2521 /* fall through */
2522 case NGHTTP3_QPACK_DS_STATE_READ_NUMBER:
2523 nread = qpack_read_varint(&rfin, &encoder->rstate, p, end);
2524 if (nread < 0) {
2525 assert(nread == NGHTTP3_ERR_QPACK_FATAL);
2526 rv = NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR;
2527 goto fail;
2528 }
2529
2530 p += nread;
2531
2532 if (!rfin) {
2533 return p - src;
2534 }
2535
2536 switch (encoder->opcode) {
2537 case NGHTTP3_QPACK_DS_OPCODE_ICNT_INCREMENT:
2538 rv = nghttp3_qpack_encoder_add_icnt(encoder, encoder->rstate.left);
2539 if (rv != 0) {
2540 goto fail;
2541 }
2542 break;
2543 case NGHTTP3_QPACK_DS_OPCODE_SECTION_ACK:
2544 rv = nghttp3_qpack_encoder_ack_header(encoder,
2545 (int64_t)encoder->rstate.left);
2546 if (rv != 0) {
2547 goto fail;
2548 }
2549 break;
2550 case NGHTTP3_QPACK_DS_OPCODE_STREAM_CANCEL:
2551 nghttp3_qpack_encoder_cancel_stream(encoder,
2552 (int64_t)encoder->rstate.left);
2553 break;
2554 default:
2555 /* unreachable */
2556 assert(0);
2557 break;
2558 }
2559
2560 encoder->state = NGHTTP3_QPACK_DS_STATE_OPCODE;
2561 nghttp3_qpack_read_state_reset(&encoder->rstate);
2562 break;
2563 default:
2564 /* unreachable */
2565 assert(0);
2566 break;
2567 }
2568 }
2569
2570 return p - src;
2571
2572 fail:
2573 encoder->ctx.bad = 1;
2574 return rv;
2575 }
2576
nghttp3_qpack_put_varint_len(uint64_t n,size_t prefix)2577 size_t nghttp3_qpack_put_varint_len(uint64_t n, size_t prefix) {
2578 size_t k = (size_t)((1 << prefix) - 1);
2579 size_t len = 0;
2580
2581 if (n < k) {
2582 return 1;
2583 }
2584
2585 n -= k;
2586 ++len;
2587
2588 for (; n >= 128; n >>= 7, ++len)
2589 ;
2590
2591 return len + 1;
2592 }
2593
nghttp3_qpack_put_varint(uint8_t * buf,uint64_t n,size_t prefix)2594 uint8_t *nghttp3_qpack_put_varint(uint8_t *buf, uint64_t n, size_t prefix) {
2595 size_t k = (size_t)((1 << prefix) - 1);
2596
2597 *buf = (uint8_t)(*buf & ~k);
2598
2599 if (n < k) {
2600 *buf = (uint8_t)(*buf | n);
2601 return buf + 1;
2602 }
2603
2604 *buf = (uint8_t)(*buf | k);
2605 ++buf;
2606
2607 n -= k;
2608
2609 for (; n >= 128; n >>= 7) {
2610 *buf++ = (uint8_t)((1 << 7) | (n & 0x7f));
2611 }
2612
2613 *buf++ = (uint8_t)n;
2614
2615 return buf;
2616 }
2617
nghttp3_qpack_read_state_free(nghttp3_qpack_read_state * rstate)2618 void nghttp3_qpack_read_state_free(nghttp3_qpack_read_state *rstate) {
2619 nghttp3_rcbuf_decref(rstate->value);
2620 nghttp3_rcbuf_decref(rstate->name);
2621 }
2622
nghttp3_qpack_read_state_reset(nghttp3_qpack_read_state * rstate)2623 void nghttp3_qpack_read_state_reset(nghttp3_qpack_read_state *rstate) {
2624 rstate->name = NULL;
2625 rstate->value = NULL;
2626 nghttp3_buf_init(&rstate->namebuf);
2627 nghttp3_buf_init(&rstate->valuebuf);
2628 rstate->left = 0;
2629 rstate->prefix = 0;
2630 rstate->shift = 0;
2631 rstate->absidx = 0;
2632 rstate->never = 0;
2633 rstate->dynamic = 0;
2634 rstate->huffman_encoded = 0;
2635 }
2636
nghttp3_qpack_decoder_init(nghttp3_qpack_decoder * decoder,size_t hard_max_dtable_capacity,size_t max_blocked_streams,const nghttp3_mem * mem)2637 int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder,
2638 size_t hard_max_dtable_capacity,
2639 size_t max_blocked_streams,
2640 const nghttp3_mem *mem) {
2641 int rv;
2642
2643 rv = qpack_context_init(&decoder->ctx, hard_max_dtable_capacity,
2644 max_blocked_streams, mem);
2645 if (rv != 0) {
2646 return rv;
2647 }
2648
2649 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
2650 decoder->opcode = 0;
2651 decoder->written_icnt = 0;
2652 decoder->max_concurrent_streams = 0;
2653
2654 nghttp3_qpack_read_state_reset(&decoder->rstate);
2655 nghttp3_buf_init(&decoder->dbuf);
2656
2657 return 0;
2658 }
2659
nghttp3_qpack_decoder_free(nghttp3_qpack_decoder * decoder)2660 void nghttp3_qpack_decoder_free(nghttp3_qpack_decoder *decoder) {
2661 nghttp3_buf_free(&decoder->dbuf, decoder->ctx.mem);
2662 nghttp3_qpack_read_state_free(&decoder->rstate);
2663 qpack_context_free(&decoder->ctx);
2664 }
2665
2666 /*
2667 * qpack_read_huffman_string decodes huffman string in buffer [begin,
2668 * end) and writes the decoded string to |dest|. This function
2669 * assumes the buffer pointed by |dest| has enough space.
2670 *
2671 * This function returns 0 if it succeeds, or one of the following
2672 * negative error codes:
2673 *
2674 * NGHTTP3_ERR_QPACK_FATAL
2675 * Could not decode huffman string.
2676 */
qpack_read_huffman_string(nghttp3_qpack_read_state * rstate,nghttp3_buf * dest,const uint8_t * begin,const uint8_t * end)2677 static nghttp3_ssize qpack_read_huffman_string(nghttp3_qpack_read_state *rstate,
2678 nghttp3_buf *dest,
2679 const uint8_t *begin,
2680 const uint8_t *end) {
2681 nghttp3_ssize nwrite;
2682 size_t len = (size_t)(end - begin);
2683 int fin = 0;
2684
2685 if (len >= rstate->left) {
2686 len = (size_t)rstate->left;
2687 fin = 1;
2688 }
2689
2690 nwrite = nghttp3_qpack_huffman_decode(&rstate->huffman_ctx, dest->last, begin,
2691 len, fin);
2692 if (nwrite < 0) {
2693 return nwrite;
2694 }
2695
2696 if (nghttp3_qpack_huffman_decode_failure_state(&rstate->huffman_ctx)) {
2697 return NGHTTP3_ERR_QPACK_FATAL;
2698 }
2699
2700 dest->last += nwrite;
2701 rstate->left -= len;
2702 return (nghttp3_ssize)len;
2703 }
2704
qpack_read_string(nghttp3_qpack_read_state * rstate,nghttp3_buf * dest,const uint8_t * begin,const uint8_t * end)2705 static nghttp3_ssize qpack_read_string(nghttp3_qpack_read_state *rstate,
2706 nghttp3_buf *dest, const uint8_t *begin,
2707 const uint8_t *end) {
2708 size_t len = (size_t)(end - begin);
2709 size_t n = (size_t)nghttp3_min((uint64_t)len, rstate->left);
2710
2711 dest->last = nghttp3_cpymem(dest->last, begin, n);
2712
2713 rstate->left -= n;
2714 return (nghttp3_ssize)n;
2715 }
2716
2717 /*
2718 * qpack_decoder_validate_index checks rstate->absidx is acceptable.
2719 *
2720 * It returns 0 if it succeeds, or one of the following negative error
2721 * codes:
2722 *
2723 * NGHTTP3_ERR_QPACK_FATAL
2724 * rstate->absidx is invalid.
2725 */
qpack_decoder_validate_index(nghttp3_qpack_decoder * decoder,nghttp3_qpack_read_state * rstate)2726 static int qpack_decoder_validate_index(nghttp3_qpack_decoder *decoder,
2727 nghttp3_qpack_read_state *rstate) {
2728 if (rstate->dynamic) {
2729 return rstate->absidx < decoder->ctx.next_absidx &&
2730 decoder->ctx.next_absidx - rstate->absidx - 1 <
2731 nghttp3_ringbuf_len(&decoder->ctx.dtable)
2732 ? 0
2733 : NGHTTP3_ERR_QPACK_FATAL;
2734 }
2735 return rstate->absidx < nghttp3_arraylen(stable) ? 0
2736 : NGHTTP3_ERR_QPACK_FATAL;
2737 }
2738
qpack_read_state_check_huffman(nghttp3_qpack_read_state * rstate,const uint8_t b)2739 static void qpack_read_state_check_huffman(nghttp3_qpack_read_state *rstate,
2740 const uint8_t b) {
2741 rstate->huffman_encoded = (b & (1 << rstate->prefix)) != 0;
2742 }
2743
qpack_read_state_terminate_name(nghttp3_qpack_read_state * rstate)2744 static void qpack_read_state_terminate_name(nghttp3_qpack_read_state *rstate) {
2745 *rstate->namebuf.last = '\0';
2746 rstate->name->len = nghttp3_buf_len(&rstate->namebuf);
2747 }
2748
qpack_read_state_terminate_value(nghttp3_qpack_read_state * rstate)2749 static void qpack_read_state_terminate_value(nghttp3_qpack_read_state *rstate) {
2750 *rstate->valuebuf.last = '\0';
2751 rstate->value->len = nghttp3_buf_len(&rstate->valuebuf);
2752 }
2753
nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder * decoder,const uint8_t * src,size_t srclen)2754 nghttp3_ssize nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder *decoder,
2755 const uint8_t *src,
2756 size_t srclen) {
2757 const uint8_t *p = src, *end;
2758 int rv;
2759 int busy = 0;
2760 const nghttp3_mem *mem = decoder->ctx.mem;
2761 nghttp3_ssize nread;
2762 int rfin;
2763
2764 if (decoder->ctx.bad) {
2765 return NGHTTP3_ERR_QPACK_FATAL;
2766 }
2767
2768 if (srclen == 0) {
2769 return 0;
2770 }
2771
2772 end = src + srclen;
2773
2774 for (; p != end || busy;) {
2775 busy = 0;
2776 switch (decoder->state) {
2777 case NGHTTP3_QPACK_ES_STATE_OPCODE:
2778 if ((*p) & 0x80) {
2779 DEBUGF("qpack::decode: OPCODE_INSERT_INDEXED\n");
2780 decoder->opcode = NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED;
2781 decoder->rstate.dynamic = !((*p) & 0x40);
2782 decoder->rstate.prefix = 6;
2783 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_INDEX;
2784 } else if ((*p) & 0x40) {
2785 DEBUGF("qpack::decode: OPCODE_INSERT\n");
2786 decoder->opcode = NGHTTP3_QPACK_ES_OPCODE_INSERT;
2787 decoder->rstate.dynamic = 0;
2788 decoder->rstate.prefix = 5;
2789 decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_NAME_HUFFMAN;
2790 } else if ((*p) & 0x20) {
2791 DEBUGF("qpack::decode: OPCODE_SET_DTABLE_TABLE_CAP\n");
2792 decoder->opcode = NGHTTP3_QPACK_ES_OPCODE_SET_DTABLE_CAP;
2793 decoder->rstate.prefix = 5;
2794 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_INDEX;
2795 } else if (!((*p) & 0x20)) {
2796 DEBUGF("qpack::decode: OPCODE_DUPLICATE\n");
2797 decoder->opcode = NGHTTP3_QPACK_ES_OPCODE_DUPLICATE;
2798 decoder->rstate.dynamic = 1;
2799 decoder->rstate.prefix = 5;
2800 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_INDEX;
2801 } else {
2802 DEBUGF("qpack::decode: unknown opcode %02x\n", *p);
2803 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2804 goto fail;
2805 }
2806 break;
2807 case NGHTTP3_QPACK_ES_STATE_READ_INDEX:
2808 nread = qpack_read_varint(&rfin, &decoder->rstate, p, end);
2809 if (nread < 0) {
2810 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
2811 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2812 goto fail;
2813 }
2814
2815 p += nread;
2816
2817 if (!rfin) {
2818 return p - src;
2819 }
2820
2821 if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_SET_DTABLE_CAP) {
2822 DEBUGF("qpack::decode: Set dtable capacity to %" PRIu64 "\n",
2823 decoder->rstate.left);
2824 rv = nghttp3_qpack_decoder_set_max_dtable_capacity(
2825 decoder, (size_t)decoder->rstate.left);
2826 if (rv != 0) {
2827 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2828 goto fail;
2829 }
2830
2831 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
2832 nghttp3_qpack_read_state_reset(&decoder->rstate);
2833 break;
2834 }
2835
2836 rv = nghttp3_qpack_decoder_rel2abs(decoder, &decoder->rstate);
2837 if (rv < 0) {
2838 goto fail;
2839 }
2840
2841 if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_DUPLICATE) {
2842 rv = nghttp3_qpack_decoder_dtable_duplicate_add(decoder);
2843 if (rv != 0) {
2844 goto fail;
2845 }
2846 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
2847 nghttp3_qpack_read_state_reset(&decoder->rstate);
2848 break;
2849 }
2850
2851 if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED) {
2852 decoder->rstate.prefix = 7;
2853 decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN;
2854 break;
2855 }
2856
2857 /* Unreachable */
2858 assert(0);
2859 break;
2860 case NGHTTP3_QPACK_ES_STATE_CHECK_NAME_HUFFMAN:
2861 qpack_read_state_check_huffman(&decoder->rstate, *p);
2862 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_NAMELEN;
2863 decoder->rstate.left = 0;
2864 decoder->rstate.shift = 0;
2865 /* Fall through */
2866 case NGHTTP3_QPACK_ES_STATE_READ_NAMELEN:
2867 nread = qpack_read_varint(&rfin, &decoder->rstate, p, end);
2868 if (nread < 0) {
2869 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
2870 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2871 goto fail;
2872 }
2873
2874 p += nread;
2875
2876 if (!rfin) {
2877 return p - src;
2878 }
2879
2880 if (decoder->rstate.left > NGHTTP3_QPACK_MAX_NAMELEN) {
2881 rv = NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE;
2882 goto fail;
2883 }
2884
2885 if (decoder->rstate.huffman_encoded) {
2886 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_NAME_HUFFMAN;
2887 nghttp3_qpack_huffman_decode_context_init(&decoder->rstate.huffman_ctx);
2888 rv = nghttp3_rcbuf_new(&decoder->rstate.name,
2889 (size_t)decoder->rstate.left * 2 + 1, mem);
2890 } else {
2891 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_NAME;
2892 rv = nghttp3_rcbuf_new(&decoder->rstate.name,
2893 (size_t)decoder->rstate.left + 1, mem);
2894 }
2895 if (rv != 0) {
2896 goto fail;
2897 }
2898
2899 nghttp3_buf_wrap_init(&decoder->rstate.namebuf,
2900 decoder->rstate.name->base,
2901 decoder->rstate.name->len);
2902 break;
2903 case NGHTTP3_QPACK_ES_STATE_READ_NAME_HUFFMAN:
2904 nread = qpack_read_huffman_string(&decoder->rstate,
2905 &decoder->rstate.namebuf, p, end);
2906 if (nread < 0) {
2907 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
2908 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2909 goto fail;
2910 }
2911
2912 p += nread;
2913
2914 if (decoder->rstate.left) {
2915 return p - src;
2916 }
2917
2918 qpack_read_state_terminate_name(&decoder->rstate);
2919
2920 decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN;
2921 decoder->rstate.prefix = 7;
2922 break;
2923 case NGHTTP3_QPACK_ES_STATE_READ_NAME:
2924 nread =
2925 qpack_read_string(&decoder->rstate, &decoder->rstate.namebuf, p, end);
2926 if (nread < 0) {
2927 rv = (int)nread;
2928 goto fail;
2929 }
2930
2931 p += nread;
2932
2933 if (decoder->rstate.left) {
2934 return p - src;
2935 }
2936
2937 qpack_read_state_terminate_name(&decoder->rstate);
2938
2939 decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN;
2940 decoder->rstate.prefix = 7;
2941 break;
2942 case NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN:
2943 qpack_read_state_check_huffman(&decoder->rstate, *p);
2944 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_VALUELEN;
2945 decoder->rstate.left = 0;
2946 decoder->rstate.shift = 0;
2947 /* Fall through */
2948 case NGHTTP3_QPACK_ES_STATE_READ_VALUELEN:
2949 nread = qpack_read_varint(&rfin, &decoder->rstate, p, end);
2950 if (nread < 0) {
2951 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
2952 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2953 goto fail;
2954 }
2955
2956 p += nread;
2957
2958 if (!rfin) {
2959 return p - src;
2960 }
2961
2962 if (decoder->rstate.left > NGHTTP3_QPACK_MAX_VALUELEN) {
2963 rv = NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE;
2964 goto fail;
2965 }
2966
2967 if (decoder->rstate.huffman_encoded) {
2968 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_VALUE_HUFFMAN;
2969 nghttp3_qpack_huffman_decode_context_init(&decoder->rstate.huffman_ctx);
2970 rv = nghttp3_rcbuf_new(&decoder->rstate.value,
2971 (size_t)decoder->rstate.left * 2 + 1, mem);
2972 } else {
2973 decoder->state = NGHTTP3_QPACK_ES_STATE_READ_VALUE;
2974 rv = nghttp3_rcbuf_new(&decoder->rstate.value,
2975 (size_t)decoder->rstate.left + 1, mem);
2976 }
2977 if (rv != 0) {
2978 goto fail;
2979 }
2980
2981 nghttp3_buf_wrap_init(&decoder->rstate.valuebuf,
2982 decoder->rstate.value->base,
2983 decoder->rstate.value->len);
2984
2985 /* value might be 0 length */
2986 busy = 1;
2987 break;
2988 case NGHTTP3_QPACK_ES_STATE_READ_VALUE_HUFFMAN:
2989 nread = qpack_read_huffman_string(&decoder->rstate,
2990 &decoder->rstate.valuebuf, p, end);
2991 if (nread < 0) {
2992 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
2993 rv = NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
2994 goto fail;
2995 }
2996
2997 p += nread;
2998
2999 if (decoder->rstate.left) {
3000 return p - src;
3001 }
3002
3003 qpack_read_state_terminate_value(&decoder->rstate);
3004
3005 switch (decoder->opcode) {
3006 case NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED:
3007 rv = nghttp3_qpack_decoder_dtable_indexed_add(decoder);
3008 break;
3009 case NGHTTP3_QPACK_ES_OPCODE_INSERT:
3010 rv = nghttp3_qpack_decoder_dtable_literal_add(decoder);
3011 break;
3012 default:
3013 /* Unreachable */
3014 assert(0);
3015 abort();
3016 }
3017 if (rv != 0) {
3018 goto fail;
3019 }
3020
3021 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
3022 nghttp3_qpack_read_state_reset(&decoder->rstate);
3023 break;
3024 case NGHTTP3_QPACK_ES_STATE_READ_VALUE:
3025 nread = qpack_read_string(&decoder->rstate, &decoder->rstate.valuebuf, p,
3026 end);
3027 if (nread < 0) {
3028 rv = (int)nread;
3029 goto fail;
3030 }
3031
3032 p += nread;
3033
3034 if (decoder->rstate.left) {
3035 return p - src;
3036 }
3037
3038 qpack_read_state_terminate_value(&decoder->rstate);
3039
3040 switch (decoder->opcode) {
3041 case NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED:
3042 rv = nghttp3_qpack_decoder_dtable_indexed_add(decoder);
3043 break;
3044 case NGHTTP3_QPACK_ES_OPCODE_INSERT:
3045 rv = nghttp3_qpack_decoder_dtable_literal_add(decoder);
3046 break;
3047 default:
3048 /* Unreachable */
3049 assert(0);
3050 abort();
3051 }
3052 if (rv != 0) {
3053 goto fail;
3054 }
3055
3056 decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
3057 nghttp3_qpack_read_state_reset(&decoder->rstate);
3058 break;
3059 }
3060 }
3061
3062 return p - src;
3063
3064 fail:
3065 decoder->ctx.bad = 1;
3066 return rv;
3067 }
3068
nghttp3_qpack_decoder_set_max_dtable_capacity(nghttp3_qpack_decoder * decoder,size_t max_dtable_capacity)3069 int nghttp3_qpack_decoder_set_max_dtable_capacity(
3070 nghttp3_qpack_decoder *decoder, size_t max_dtable_capacity) {
3071 nghttp3_qpack_entry *ent;
3072 size_t i;
3073 nghttp3_qpack_context *ctx = &decoder->ctx;
3074 const nghttp3_mem *mem = ctx->mem;
3075
3076 if (max_dtable_capacity > decoder->ctx.hard_max_dtable_capacity) {
3077 return NGHTTP3_ERR_INVALID_ARGUMENT;
3078 }
3079
3080 ctx->max_dtable_capacity = max_dtable_capacity;
3081
3082 while (ctx->dtable_size > max_dtable_capacity) {
3083 i = nghttp3_ringbuf_len(&ctx->dtable);
3084 assert(i);
3085 ent = *(nghttp3_qpack_entry **)nghttp3_ringbuf_get(&ctx->dtable, i - 1);
3086
3087 ctx->dtable_size -= table_space(ent->nv.name->len, ent->nv.value->len);
3088
3089 nghttp3_ringbuf_pop_back(&ctx->dtable);
3090 nghttp3_qpack_entry_free(ent);
3091 nghttp3_mem_free(mem, ent);
3092 }
3093
3094 return 0;
3095 }
3096
nghttp3_qpack_decoder_dtable_indexed_add(nghttp3_qpack_decoder * decoder)3097 int nghttp3_qpack_decoder_dtable_indexed_add(nghttp3_qpack_decoder *decoder) {
3098 DEBUGF("qpack::decode: Insert With Name Reference (%s) absidx=%" PRIu64 ": "
3099 "value=%*s\n",
3100 decoder->rstate.dynamic ? "dynamic" : "static", decoder->rstate.absidx,
3101 (int)decoder->rstate.value->len, decoder->rstate.value->base);
3102
3103 if (decoder->rstate.dynamic) {
3104 return nghttp3_qpack_decoder_dtable_dynamic_add(decoder);
3105 }
3106
3107 return nghttp3_qpack_decoder_dtable_static_add(decoder);
3108 }
3109
nghttp3_qpack_decoder_dtable_static_add(nghttp3_qpack_decoder * decoder)3110 int nghttp3_qpack_decoder_dtable_static_add(nghttp3_qpack_decoder *decoder) {
3111 nghttp3_qpack_nv qnv;
3112 int rv;
3113 const nghttp3_qpack_static_header *shd;
3114
3115 shd = &stable[decoder->rstate.absidx];
3116
3117 if (table_space(shd->name.len, decoder->rstate.value->len) >
3118 decoder->ctx.max_dtable_capacity) {
3119 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3120 }
3121
3122 qnv.name = (nghttp3_rcbuf *)&shd->name;
3123 qnv.value = decoder->rstate.value;
3124 qnv.token = shd->token;
3125 qnv.flags = NGHTTP3_NV_FLAG_NONE;
3126
3127 rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
3128
3129 nghttp3_rcbuf_decref(qnv.value);
3130
3131 return rv;
3132 }
3133
nghttp3_qpack_decoder_dtable_dynamic_add(nghttp3_qpack_decoder * decoder)3134 int nghttp3_qpack_decoder_dtable_dynamic_add(nghttp3_qpack_decoder *decoder) {
3135 nghttp3_qpack_nv qnv;
3136 int rv;
3137 nghttp3_qpack_entry *ent;
3138
3139 ent = nghttp3_qpack_context_dtable_get(&decoder->ctx, decoder->rstate.absidx);
3140
3141 if (table_space(ent->nv.name->len, decoder->rstate.value->len) >
3142 decoder->ctx.max_dtable_capacity) {
3143 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3144 }
3145
3146 qnv.name = ent->nv.name;
3147 qnv.value = decoder->rstate.value;
3148 qnv.token = ent->nv.token;
3149 qnv.flags = NGHTTP3_NV_FLAG_NONE;
3150
3151 nghttp3_rcbuf_incref(qnv.name);
3152
3153 rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
3154
3155 nghttp3_rcbuf_decref(qnv.value);
3156 nghttp3_rcbuf_decref(qnv.name);
3157
3158 return rv;
3159 }
3160
nghttp3_qpack_decoder_dtable_duplicate_add(nghttp3_qpack_decoder * decoder)3161 int nghttp3_qpack_decoder_dtable_duplicate_add(nghttp3_qpack_decoder *decoder) {
3162 int rv;
3163 nghttp3_qpack_entry *ent;
3164 nghttp3_qpack_nv qnv;
3165
3166 DEBUGF("qpack::decode: Insert duplicate absidx=%" PRIu64 "\n",
3167 decoder->rstate.absidx);
3168
3169 ent = nghttp3_qpack_context_dtable_get(&decoder->ctx, decoder->rstate.absidx);
3170
3171 if (table_space(ent->nv.name->len, ent->nv.value->len) >
3172 decoder->ctx.max_dtable_capacity) {
3173 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3174 }
3175
3176 qnv = ent->nv;
3177 nghttp3_rcbuf_incref(qnv.name);
3178 nghttp3_rcbuf_incref(qnv.value);
3179
3180 rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
3181
3182 nghttp3_rcbuf_decref(qnv.value);
3183 nghttp3_rcbuf_decref(qnv.name);
3184
3185 return rv;
3186 }
3187
nghttp3_qpack_decoder_dtable_literal_add(nghttp3_qpack_decoder * decoder)3188 int nghttp3_qpack_decoder_dtable_literal_add(nghttp3_qpack_decoder *decoder) {
3189 nghttp3_qpack_nv qnv;
3190 int rv;
3191
3192 DEBUGF("qpack::decode: Insert With Literal Name: name=%*s value=%*s\n",
3193 (int)decoder->rstate.name->len, decoder->rstate.name->base,
3194 (int)decoder->rstate.value->len, decoder->rstate.value->base);
3195
3196 if (table_space(decoder->rstate.name->len, decoder->rstate.value->len) >
3197 decoder->ctx.max_dtable_capacity) {
3198 return NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR;
3199 }
3200
3201 qnv.name = decoder->rstate.name;
3202 qnv.value = decoder->rstate.value;
3203 qnv.token = qpack_lookup_token(qnv.name->base, qnv.name->len);
3204 qnv.flags = NGHTTP3_NV_FLAG_NONE;
3205
3206 rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
3207
3208 nghttp3_rcbuf_decref(qnv.value);
3209 nghttp3_rcbuf_decref(qnv.name);
3210
3211 return rv;
3212 }
3213
nghttp3_qpack_decoder_set_max_concurrent_streams(nghttp3_qpack_decoder * decoder,size_t max_concurrent_streams)3214 void nghttp3_qpack_decoder_set_max_concurrent_streams(
3215 nghttp3_qpack_decoder *decoder, size_t max_concurrent_streams) {
3216 decoder->max_concurrent_streams =
3217 nghttp3_max(decoder->max_concurrent_streams, max_concurrent_streams);
3218 }
3219
nghttp3_qpack_stream_context_init(nghttp3_qpack_stream_context * sctx,int64_t stream_id,const nghttp3_mem * mem)3220 void nghttp3_qpack_stream_context_init(nghttp3_qpack_stream_context *sctx,
3221 int64_t stream_id,
3222 const nghttp3_mem *mem) {
3223 nghttp3_qpack_read_state_reset(&sctx->rstate);
3224
3225 sctx->mem = mem;
3226 sctx->rstate.prefix = 8;
3227 sctx->state = NGHTTP3_QPACK_RS_STATE_RICNT;
3228 sctx->opcode = 0;
3229 sctx->stream_id = stream_id;
3230 sctx->ricnt = 0;
3231 sctx->dbase_sign = 0;
3232 sctx->base = 0;
3233 }
3234
nghttp3_qpack_stream_context_free(nghttp3_qpack_stream_context * sctx)3235 void nghttp3_qpack_stream_context_free(nghttp3_qpack_stream_context *sctx) {
3236 nghttp3_qpack_read_state_free(&sctx->rstate);
3237 }
3238
nghttp3_qpack_stream_context_reset(nghttp3_qpack_stream_context * sctx)3239 void nghttp3_qpack_stream_context_reset(nghttp3_qpack_stream_context *sctx) {
3240 nghttp3_qpack_stream_context_init(sctx, sctx->stream_id, sctx->mem);
3241 }
3242
3243 uint64_t
nghttp3_qpack_stream_context_get_ricnt(nghttp3_qpack_stream_context * sctx)3244 nghttp3_qpack_stream_context_get_ricnt(nghttp3_qpack_stream_context *sctx) {
3245 return sctx->ricnt;
3246 }
3247
3248 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)3249 nghttp3_qpack_decoder_read_request(nghttp3_qpack_decoder *decoder,
3250 nghttp3_qpack_stream_context *sctx,
3251 nghttp3_qpack_nv *nv, uint8_t *pflags,
3252 const uint8_t *src, size_t srclen, int fin) {
3253 const uint8_t *p = src, *end = src ? src + srclen : src;
3254 int rv;
3255 int busy = 0;
3256 nghttp3_ssize nread;
3257 int rfin;
3258 const nghttp3_mem *mem = decoder->ctx.mem;
3259
3260 if (decoder->ctx.bad) {
3261 return NGHTTP3_ERR_QPACK_FATAL;
3262 }
3263
3264 *pflags = NGHTTP3_QPACK_DECODE_FLAG_NONE;
3265
3266 for (; p != end || busy;) {
3267 busy = 0;
3268 switch (sctx->state) {
3269 case NGHTTP3_QPACK_RS_STATE_RICNT:
3270 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3271 if (nread < 0) {
3272 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3273 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3274 goto fail;
3275 }
3276
3277 p += nread;
3278
3279 if (!rfin) {
3280 goto almost_ok;
3281 }
3282
3283 rv = nghttp3_qpack_decoder_reconstruct_ricnt(decoder, &sctx->ricnt,
3284 sctx->rstate.left);
3285 if (rv != 0) {
3286 goto fail;
3287 }
3288
3289 sctx->state = NGHTTP3_QPACK_RS_STATE_DBASE_SIGN;
3290 break;
3291 case NGHTTP3_QPACK_RS_STATE_DBASE_SIGN:
3292 if ((*p) & 0x80) {
3293 sctx->dbase_sign = 1;
3294 }
3295 sctx->state = NGHTTP3_QPACK_RS_STATE_DBASE;
3296 sctx->rstate.left = 0;
3297 sctx->rstate.prefix = 7;
3298 sctx->rstate.shift = 0;
3299 /* Fall through */
3300 case NGHTTP3_QPACK_RS_STATE_DBASE:
3301 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3302 if (nread < 0) {
3303 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3304 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3305 goto fail;
3306 }
3307
3308 p += nread;
3309
3310 if (!rfin) {
3311 goto almost_ok;
3312 }
3313
3314 if (sctx->dbase_sign) {
3315 if (sctx->ricnt <= sctx->rstate.left) {
3316 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3317 goto fail;
3318 }
3319 sctx->base = sctx->ricnt - sctx->rstate.left - 1;
3320 } else {
3321 sctx->base = sctx->ricnt + sctx->rstate.left;
3322 }
3323
3324 DEBUGF("qpack::decode: ricnt=%" PRIu64 " base=%" PRIu64 " icnt=%" PRIu64
3325 "\n",
3326 sctx->ricnt, sctx->base, decoder->ctx.next_absidx);
3327
3328 if (sctx->ricnt > decoder->ctx.next_absidx) {
3329 DEBUGF("qpack::decode: stream blocked\n");
3330 sctx->state = NGHTTP3_QPACK_RS_STATE_BLOCKED;
3331 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_BLOCKED;
3332 return p - src;
3333 }
3334
3335 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3336 sctx->rstate.left = 0;
3337 sctx->rstate.shift = 0;
3338 break;
3339 case NGHTTP3_QPACK_RS_STATE_OPCODE:
3340 assert(sctx->rstate.left == 0);
3341 assert(sctx->rstate.shift == 0);
3342 if ((*p) & 0x80) {
3343 DEBUGF("qpack::decode: OPCODE_INDEXED\n");
3344 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_INDEXED;
3345 sctx->rstate.dynamic = !((*p) & 0x40);
3346 sctx->rstate.prefix = 6;
3347 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_INDEX;
3348 } else if ((*p) & 0x40) {
3349 DEBUGF("qpack::decode: OPCODE_INDEXED_NAME\n");
3350 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME;
3351 sctx->rstate.never = (*p) & 0x20;
3352 sctx->rstate.dynamic = !((*p) & 0x10);
3353 sctx->rstate.prefix = 4;
3354 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_INDEX;
3355 } else if ((*p) & 0x20) {
3356 DEBUGF("qpack::decode: OPCODE_LITERAL\n");
3357 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_LITERAL;
3358 sctx->rstate.never = (*p) & 0x10;
3359 sctx->rstate.dynamic = 0;
3360 sctx->rstate.prefix = 3;
3361 sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_NAME_HUFFMAN;
3362 } else if ((*p) & 0x10) {
3363 DEBUGF("qpack::decode: OPCODE_INDEXED_PB\n");
3364 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_INDEXED_PB;
3365 sctx->rstate.dynamic = 1;
3366 sctx->rstate.prefix = 4;
3367 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_INDEX;
3368 } else {
3369 DEBUGF("qpack::decode: OPCODE_INDEXED_NAME_PB\n");
3370 sctx->opcode = NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB;
3371 sctx->rstate.never = (*p) & 0x08;
3372 sctx->rstate.dynamic = 1;
3373 sctx->rstate.prefix = 3;
3374 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_INDEX;
3375 }
3376 break;
3377 case NGHTTP3_QPACK_RS_STATE_READ_INDEX:
3378 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3379 if (nread < 0) {
3380 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3381 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3382 goto fail;
3383 }
3384
3385 p += nread;
3386
3387 if (!rfin) {
3388 goto almost_ok;
3389 }
3390
3391 switch (sctx->opcode) {
3392 case NGHTTP3_QPACK_RS_OPCODE_INDEXED:
3393 rv = nghttp3_qpack_decoder_brel2abs(decoder, sctx);
3394 if (rv != 0) {
3395 goto fail;
3396 }
3397 nghttp3_qpack_decoder_emit_indexed(decoder, sctx, nv);
3398 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT;
3399
3400 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3401 nghttp3_qpack_read_state_reset(&sctx->rstate);
3402
3403 return p - src;
3404 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_PB:
3405 rv = nghttp3_qpack_decoder_pbrel2abs(decoder, sctx);
3406 if (rv != 0) {
3407 goto fail;
3408 }
3409 nghttp3_qpack_decoder_emit_indexed(decoder, sctx, nv);
3410 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT;
3411
3412 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3413 nghttp3_qpack_read_state_reset(&sctx->rstate);
3414
3415 return p - src;
3416 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME:
3417 rv = nghttp3_qpack_decoder_brel2abs(decoder, sctx);
3418 if (rv != 0) {
3419 goto fail;
3420 }
3421 sctx->rstate.prefix = 7;
3422 sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN;
3423 break;
3424 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB:
3425 rv = nghttp3_qpack_decoder_pbrel2abs(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 default:
3433 /* Unreachable */
3434 assert(0);
3435 }
3436 break;
3437 case NGHTTP3_QPACK_RS_STATE_CHECK_NAME_HUFFMAN:
3438 qpack_read_state_check_huffman(&sctx->rstate, *p);
3439 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_NAMELEN;
3440 sctx->rstate.left = 0;
3441 sctx->rstate.shift = 0;
3442 /* Fall through */
3443 case NGHTTP3_QPACK_RS_STATE_READ_NAMELEN:
3444 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3445 if (nread < 0) {
3446 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3447 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3448 goto fail;
3449 }
3450
3451 p += nread;
3452
3453 if (!rfin) {
3454 goto almost_ok;
3455 }
3456
3457 if (sctx->rstate.left > NGHTTP3_QPACK_MAX_NAMELEN) {
3458 rv = NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE;
3459 goto fail;
3460 }
3461
3462 if (sctx->rstate.huffman_encoded) {
3463 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_NAME_HUFFMAN;
3464 nghttp3_qpack_huffman_decode_context_init(&sctx->rstate.huffman_ctx);
3465 rv = nghttp3_rcbuf_new(&sctx->rstate.name,
3466 (size_t)sctx->rstate.left * 2 + 1, mem);
3467 } else {
3468 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_NAME;
3469 rv = nghttp3_rcbuf_new(&sctx->rstate.name,
3470 (size_t)sctx->rstate.left + 1, mem);
3471 }
3472 if (rv != 0) {
3473 goto fail;
3474 }
3475
3476 nghttp3_buf_wrap_init(&sctx->rstate.namebuf, sctx->rstate.name->base,
3477 sctx->rstate.name->len);
3478 break;
3479 case NGHTTP3_QPACK_RS_STATE_READ_NAME_HUFFMAN:
3480 nread = qpack_read_huffman_string(&sctx->rstate, &sctx->rstate.namebuf, p,
3481 end);
3482 if (nread < 0) {
3483 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3484 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3485 goto fail;
3486 }
3487
3488 p += nread;
3489
3490 if (sctx->rstate.left) {
3491 goto almost_ok;
3492 }
3493
3494 qpack_read_state_terminate_name(&sctx->rstate);
3495
3496 sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN;
3497 sctx->rstate.prefix = 7;
3498 break;
3499 case NGHTTP3_QPACK_RS_STATE_READ_NAME:
3500 nread = qpack_read_string(&sctx->rstate, &sctx->rstate.namebuf, p, end);
3501 if (nread < 0) {
3502 rv = (int)nread;
3503 goto fail;
3504 }
3505
3506 p += nread;
3507
3508 if (sctx->rstate.left) {
3509 goto almost_ok;
3510 }
3511
3512 qpack_read_state_terminate_name(&sctx->rstate);
3513
3514 sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN;
3515 sctx->rstate.prefix = 7;
3516 break;
3517 case NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN:
3518 qpack_read_state_check_huffman(&sctx->rstate, *p);
3519 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_VALUELEN;
3520 sctx->rstate.left = 0;
3521 sctx->rstate.shift = 0;
3522 /* Fall through */
3523 case NGHTTP3_QPACK_RS_STATE_READ_VALUELEN:
3524 nread = qpack_read_varint(&rfin, &sctx->rstate, p, end);
3525 if (nread < 0) {
3526 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3527 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3528 goto fail;
3529 }
3530
3531 p += nread;
3532
3533 if (!rfin) {
3534 goto almost_ok;
3535 }
3536
3537 if (sctx->rstate.left > NGHTTP3_QPACK_MAX_VALUELEN) {
3538 rv = NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE;
3539 goto fail;
3540 }
3541
3542 if (sctx->rstate.huffman_encoded) {
3543 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_VALUE_HUFFMAN;
3544 nghttp3_qpack_huffman_decode_context_init(&sctx->rstate.huffman_ctx);
3545 rv = nghttp3_rcbuf_new(&sctx->rstate.value,
3546 (size_t)sctx->rstate.left * 2 + 1, mem);
3547 } else {
3548 sctx->state = NGHTTP3_QPACK_RS_STATE_READ_VALUE;
3549 rv = nghttp3_rcbuf_new(&sctx->rstate.value,
3550 (size_t)sctx->rstate.left + 1, mem);
3551 }
3552 if (rv != 0) {
3553 goto fail;
3554 }
3555
3556 nghttp3_buf_wrap_init(&sctx->rstate.valuebuf, sctx->rstate.value->base,
3557 sctx->rstate.value->len);
3558
3559 /* value might be 0 length */
3560 busy = 1;
3561 break;
3562 case NGHTTP3_QPACK_RS_STATE_READ_VALUE_HUFFMAN:
3563 nread = qpack_read_huffman_string(&sctx->rstate, &sctx->rstate.valuebuf,
3564 p, end);
3565 if (nread < 0) {
3566 assert(NGHTTP3_ERR_QPACK_FATAL == nread);
3567 rv = NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3568 goto fail;
3569 }
3570
3571 p += nread;
3572
3573 if (sctx->rstate.left) {
3574 goto almost_ok;
3575 }
3576
3577 qpack_read_state_terminate_value(&sctx->rstate);
3578
3579 switch (sctx->opcode) {
3580 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME:
3581 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB:
3582 rv = nghttp3_qpack_decoder_emit_indexed_name(decoder, sctx, nv);
3583 if (rv != 0) {
3584 goto fail;
3585 }
3586
3587 break;
3588 case NGHTTP3_QPACK_RS_OPCODE_LITERAL:
3589 nghttp3_qpack_decoder_emit_literal(decoder, sctx, nv);
3590 break;
3591 default:
3592 /* Unreachable */
3593 assert(0);
3594 }
3595
3596 *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT;
3597
3598 sctx->state = NGHTTP3_QPACK_RS_STATE_OPCODE;
3599 nghttp3_qpack_read_state_reset(&sctx->rstate);
3600
3601 return p - src;
3602 case NGHTTP3_QPACK_RS_STATE_READ_VALUE:
3603 nread = qpack_read_string(&sctx->rstate, &sctx->rstate.valuebuf, p, end);
3604 if (nread < 0) {
3605 rv = (int)nread;
3606 goto fail;
3607 }
3608
3609 p += nread;
3610
3611 if (sctx->rstate.left) {
3612 goto almost_ok;
3613 }
3614
3615 qpack_read_state_terminate_value(&sctx->rstate);
3616
3617 switch (sctx->opcode) {
3618 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME:
3619 case NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB:
3620 rv = nghttp3_qpack_decoder_emit_indexed_name(decoder, sctx, nv);
3621 if (rv != 0) {
3622 goto fail;
3623 }
3624
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 int
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
3941 /* A broken encoder might change dtable capacity while processing
3942 request stream instruction. Check the absidx again. */
3943 if (qpack_decoder_validate_index(decoder, &sctx->rstate) != 0) {
3944 return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
3945 }
3946
3947 ent = nghttp3_qpack_context_dtable_get(&decoder->ctx, sctx->rstate.absidx);
3948
3949 nv->name = ent->nv.name;
3950 nv->value = sctx->rstate.value;
3951 nv->token = ent->nv.token;
3952 nv->flags =
3953 sctx->rstate.never ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE;
3954
3955 nghttp3_rcbuf_incref(nv->name);
3956
3957 sctx->rstate.value = NULL;
3958
3959 return 0;
3960 }
3961
nghttp3_qpack_decoder_emit_indexed_name(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv)3962 int nghttp3_qpack_decoder_emit_indexed_name(nghttp3_qpack_decoder *decoder,
3963 nghttp3_qpack_stream_context *sctx,
3964 nghttp3_qpack_nv *nv) {
3965 (void)decoder;
3966
3967 DEBUGF("qpack::decode: Indexed name (%s) absidx=%" PRIu64 " value=%*s\n",
3968 sctx->rstate.dynamic ? "dynamic" : "static", sctx->rstate.absidx,
3969 (int)sctx->rstate.value->len, sctx->rstate.value->base);
3970
3971 if (sctx->rstate.dynamic) {
3972 return qpack_decoder_emit_dynamic_indexed_name(decoder, sctx, nv);
3973 }
3974
3975 qpack_decoder_emit_static_indexed_name(decoder, sctx, nv);
3976
3977 return 0;
3978 }
3979
nghttp3_qpack_decoder_emit_literal(nghttp3_qpack_decoder * decoder,nghttp3_qpack_stream_context * sctx,nghttp3_qpack_nv * nv)3980 void nghttp3_qpack_decoder_emit_literal(nghttp3_qpack_decoder *decoder,
3981 nghttp3_qpack_stream_context *sctx,
3982 nghttp3_qpack_nv *nv) {
3983 (void)decoder;
3984
3985 DEBUGF("qpack::decode: Emit literal name=%*s value=%*s\n",
3986 (int)sctx->rstate.name->len, sctx->rstate.name->base,
3987 (int)sctx->rstate.value->len, sctx->rstate.value->base);
3988
3989 nv->name = sctx->rstate.name;
3990 nv->value = sctx->rstate.value;
3991 nv->token = qpack_lookup_token(nv->name->base, nv->name->len);
3992 nv->flags =
3993 sctx->rstate.never ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE;
3994
3995 sctx->rstate.name = NULL;
3996 sctx->rstate.value = NULL;
3997 }
3998
nghttp3_qpack_encoder_new(nghttp3_qpack_encoder ** pencoder,size_t hard_max_dtable_capacity,const nghttp3_mem * mem)3999 int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder,
4000 size_t hard_max_dtable_capacity,
4001 const nghttp3_mem *mem) {
4002 int rv;
4003 nghttp3_qpack_encoder *p;
4004
4005 p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_encoder));
4006 if (p == NULL) {
4007 return NGHTTP3_ERR_NOMEM;
4008 }
4009
4010 rv = nghttp3_qpack_encoder_init(p, hard_max_dtable_capacity, mem);
4011 if (rv != 0) {
4012 return rv;
4013 }
4014
4015 *pencoder = p;
4016
4017 return 0;
4018 }
4019
nghttp3_qpack_encoder_del(nghttp3_qpack_encoder * encoder)4020 void nghttp3_qpack_encoder_del(nghttp3_qpack_encoder *encoder) {
4021 const nghttp3_mem *mem;
4022
4023 if (encoder == NULL) {
4024 return;
4025 }
4026
4027 mem = encoder->ctx.mem;
4028
4029 nghttp3_qpack_encoder_free(encoder);
4030 nghttp3_mem_free(mem, encoder);
4031 }
4032
nghttp3_qpack_stream_context_new(nghttp3_qpack_stream_context ** psctx,int64_t stream_id,const nghttp3_mem * mem)4033 int nghttp3_qpack_stream_context_new(nghttp3_qpack_stream_context **psctx,
4034 int64_t stream_id,
4035 const nghttp3_mem *mem) {
4036 nghttp3_qpack_stream_context *p;
4037
4038 p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream_context));
4039 if (p == NULL) {
4040 return NGHTTP3_ERR_NOMEM;
4041 }
4042
4043 nghttp3_qpack_stream_context_init(p, stream_id, mem);
4044
4045 *psctx = p;
4046
4047 return 0;
4048 }
4049
nghttp3_qpack_stream_context_del(nghttp3_qpack_stream_context * sctx)4050 void nghttp3_qpack_stream_context_del(nghttp3_qpack_stream_context *sctx) {
4051 const nghttp3_mem *mem;
4052
4053 if (sctx == NULL) {
4054 return;
4055 }
4056
4057 mem = sctx->mem;
4058
4059 nghttp3_qpack_stream_context_free(sctx);
4060 nghttp3_mem_free(mem, sctx);
4061 }
4062
nghttp3_qpack_decoder_new(nghttp3_qpack_decoder ** pdecoder,size_t hard_max_dtable_capacity,size_t max_blocked_streams,const nghttp3_mem * mem)4063 int nghttp3_qpack_decoder_new(nghttp3_qpack_decoder **pdecoder,
4064 size_t hard_max_dtable_capacity,
4065 size_t max_blocked_streams,
4066 const nghttp3_mem *mem) {
4067 int rv;
4068 nghttp3_qpack_decoder *p;
4069
4070 p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_decoder));
4071 if (p == NULL) {
4072 return NGHTTP3_ERR_NOMEM;
4073 }
4074
4075 rv = nghttp3_qpack_decoder_init(p, hard_max_dtable_capacity,
4076 max_blocked_streams, mem);
4077 if (rv != 0) {
4078 return rv;
4079 }
4080
4081 *pdecoder = p;
4082
4083 return 0;
4084 }
4085
nghttp3_qpack_decoder_del(nghttp3_qpack_decoder * decoder)4086 void nghttp3_qpack_decoder_del(nghttp3_qpack_decoder *decoder) {
4087 const nghttp3_mem *mem;
4088
4089 if (decoder == NULL) {
4090 return;
4091 }
4092
4093 mem = decoder->ctx.mem;
4094
4095 nghttp3_qpack_decoder_free(decoder);
4096 nghttp3_mem_free(mem, decoder);
4097 }
4098
nghttp3_qpack_decoder_get_icnt(const nghttp3_qpack_decoder * decoder)4099 uint64_t nghttp3_qpack_decoder_get_icnt(const nghttp3_qpack_decoder *decoder) {
4100 return decoder->ctx.next_absidx;
4101 }
4102