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