xref: /lighttpd1.4/src/h2.c (revision d5e899e2)
1 /*
2  * h2 - HTTP/2 protocol layer
3  *
4  * Copyright(c) 2020 Glenn Strauss gstrauss()gluelogic.com  All rights reserved
5  * License: BSD 3-clause (same as lighttpd)
6  */
7 #include "first.h"
8 #include "h2.h"
9 
10 #include <arpa/inet.h>  /* htonl() */
11 #include <stdint.h>     /* INT32_MAX INT32_MIN */
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "base.h"
16 #include "buffer.h"
17 #include "chunk.h"
18 #include "fdevent.h"    /* FDEVENT_STREAM_REQUEST_BUFMIN */
19 #include "http_header.h"
20 #include "log.h"
21 #include "request.h"
22 #include "response.h"   /* http_response_omit_header() */
23 
24 
25 /* lowercased field-names
26  * (32-byte record (power-2) and single block of memory for memory locality) */
27 static const char http_header_lc[][32] = {
28   [HTTP_HEADER_OTHER]                     = ""
29  ,[HTTP_HEADER_ACCEPT]                    = "accept"
30  ,[HTTP_HEADER_ACCEPT_ENCODING]           = "accept-encoding"
31  ,[HTTP_HEADER_ACCEPT_LANGUAGE]           = "accept-language"
32  ,[HTTP_HEADER_ACCEPT_RANGES]             = "accept-ranges"
33  ,[HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN]="access-control-allow-origin"
34  ,[HTTP_HEADER_AGE]                       = "age"
35  ,[HTTP_HEADER_ALLOW]                     = "allow"
36  ,[HTTP_HEADER_ALT_SVC]                   = "alt-svc"
37  ,[HTTP_HEADER_ALT_USED]                  = "alt-used"
38  ,[HTTP_HEADER_AUTHORIZATION]             = "authorization"
39  ,[HTTP_HEADER_CACHE_CONTROL]             = "cache-control"
40  ,[HTTP_HEADER_CONNECTION]                = "connection"
41  ,[HTTP_HEADER_CONTENT_ENCODING]          = "content-encoding"
42  ,[HTTP_HEADER_CONTENT_LENGTH]            = "content-length"
43  ,[HTTP_HEADER_CONTENT_LOCATION]          = "content-location"
44  ,[HTTP_HEADER_CONTENT_RANGE]             = "content-range"
45  ,[HTTP_HEADER_CONTENT_SECURITY_POLICY]   = "content-security-policy"
46  ,[HTTP_HEADER_CONTENT_TYPE]              = "content-type"
47  ,[HTTP_HEADER_COOKIE]                    = "cookie"
48  ,[HTTP_HEADER_DATE]                      = "date"
49  ,[HTTP_HEADER_DNT]                       = "dnt"
50  ,[HTTP_HEADER_ETAG]                      = "etag"
51  ,[HTTP_HEADER_EXPECT]                    = "expect"
52  ,[HTTP_HEADER_EXPECT_CT]                 = "expect-ct"
53  ,[HTTP_HEADER_EXPIRES]                   = "expires"
54  ,[HTTP_HEADER_FORWARDED]                 = "forwarded"
55  ,[HTTP_HEADER_HOST]                      = "host"
56  ,[HTTP_HEADER_HTTP2_SETTINGS]            = "http2-settings"
57  ,[HTTP_HEADER_IF_MATCH]                  = "if-match"
58  ,[HTTP_HEADER_IF_MODIFIED_SINCE]         = "if-modified-since"
59  ,[HTTP_HEADER_IF_NONE_MATCH]             = "if-none-match"
60  ,[HTTP_HEADER_IF_RANGE]                  = "if-range"
61  ,[HTTP_HEADER_IF_UNMODIFIED_SINCE]       = "if-unmodified-since"
62  ,[HTTP_HEADER_LAST_MODIFIED]             = "last-modified"
63  ,[HTTP_HEADER_LINK]                      = "link"
64  ,[HTTP_HEADER_LOCATION]                  = "location"
65  ,[HTTP_HEADER_ONION_LOCATION]            = "onion-location"
66  ,[HTTP_HEADER_P3P]                       = "p3p"
67  ,[HTTP_HEADER_PRAGMA]                    = "pragma"
68  ,[HTTP_HEADER_RANGE]                     = "range"
69  ,[HTTP_HEADER_REFERER]                   = "referer"
70  ,[HTTP_HEADER_REFERRER_POLICY]           = "referrer-policy"
71  ,[HTTP_HEADER_SERVER]                    = "server"
72  ,[HTTP_HEADER_SET_COOKIE]                = "set-cookie"
73  ,[HTTP_HEADER_STATUS]                    = "status"
74  ,[HTTP_HEADER_STRICT_TRANSPORT_SECURITY] = "strict-transport-security"
75  ,[HTTP_HEADER_TE]                        = "te"
76  ,[HTTP_HEADER_TRANSFER_ENCODING]         = "transfer-encoding"
77  ,[HTTP_HEADER_UPGRADE]                   = "upgrade"
78  ,[HTTP_HEADER_UPGRADE_INSECURE_REQUESTS] = "upgrade-insecure-requests"
79  ,[HTTP_HEADER_USER_AGENT]                = "user-agent"
80  ,[HTTP_HEADER_VARY]                      = "vary"
81  ,[HTTP_HEADER_WWW_AUTHENTICATE]          = "www-authenticate"
82  ,[HTTP_HEADER_X_CONTENT_TYPE_OPTIONS]    = "x-content-type-options"
83  ,[HTTP_HEADER_X_FORWARDED_FOR]           = "x-forwarded-for"
84  ,[HTTP_HEADER_X_FORWARDED_PROTO]         = "x-forwarded-proto"
85  ,[HTTP_HEADER_X_FRAME_OPTIONS]           = "x-frame-options"
86  ,[HTTP_HEADER_X_XSS_PROTECTION]          = "x-xss-protection"
87 };
88 
89 
90 /* future optimization: could conceivably store static XXH32() hash values for
91  * field-name (e.g. for benefit of entries marked LSHPACK_HDR_UNKNOWN) to
92  * incrementally reduce cost of calculating hash values for field-name on each
93  * request where those headers are used.  Might also store single element
94  * static caches for "date:" value (updated each time static buffer is updated)
95  * and for "server:" value (often global to server), keyed on r->conf.server_tag
96  * pointer addr.  HTTP_HEADER_STATUS could be overloaded for ":status", since
97  * lighttpd should not send "Status:" response header (should not happen) */
98 
99 static const uint8_t http_header_lshpack_idx[] = {
100   [HTTP_HEADER_OTHER]                     = LSHPACK_HDR_UNKNOWN
101  ,[HTTP_HEADER_ACCEPT_ENCODING]           = LSHPACK_HDR_ACCEPT_ENCODING
102  ,[HTTP_HEADER_AUTHORIZATION]             = LSHPACK_HDR_AUTHORIZATION
103  ,[HTTP_HEADER_CACHE_CONTROL]             = LSHPACK_HDR_CACHE_CONTROL
104  ,[HTTP_HEADER_CONNECTION]                = LSHPACK_HDR_UNKNOWN
105  ,[HTTP_HEADER_CONTENT_ENCODING]          = LSHPACK_HDR_CONTENT_ENCODING
106  ,[HTTP_HEADER_CONTENT_LENGTH]            = LSHPACK_HDR_CONTENT_LENGTH
107  ,[HTTP_HEADER_CONTENT_LOCATION]          = LSHPACK_HDR_CONTENT_LOCATION
108  ,[HTTP_HEADER_CONTENT_TYPE]              = LSHPACK_HDR_CONTENT_TYPE
109  ,[HTTP_HEADER_COOKIE]                    = LSHPACK_HDR_COOKIE
110  ,[HTTP_HEADER_DATE]                      = LSHPACK_HDR_DATE
111  ,[HTTP_HEADER_ETAG]                      = LSHPACK_HDR_ETAG
112  ,[HTTP_HEADER_EXPECT]                    = LSHPACK_HDR_EXPECT
113  ,[HTTP_HEADER_FORWARDED]                 = LSHPACK_HDR_UNKNOWN
114  ,[HTTP_HEADER_HOST]                      = LSHPACK_HDR_HOST
115  ,[HTTP_HEADER_IF_MODIFIED_SINCE]         = LSHPACK_HDR_IF_MODIFIED_SINCE
116  ,[HTTP_HEADER_IF_NONE_MATCH]             = LSHPACK_HDR_IF_NONE_MATCH
117  ,[HTTP_HEADER_LAST_MODIFIED]             = LSHPACK_HDR_LAST_MODIFIED
118  ,[HTTP_HEADER_LOCATION]                  = LSHPACK_HDR_LOCATION
119  ,[HTTP_HEADER_RANGE]                     = LSHPACK_HDR_RANGE
120  ,[HTTP_HEADER_SERVER]                    = LSHPACK_HDR_SERVER
121  ,[HTTP_HEADER_SET_COOKIE]                = LSHPACK_HDR_SET_COOKIE
122  ,[HTTP_HEADER_STATUS]                    = LSHPACK_HDR_UNKNOWN
123  ,[HTTP_HEADER_TRANSFER_ENCODING]         = LSHPACK_HDR_TRANSFER_ENCODING
124  ,[HTTP_HEADER_UPGRADE]                   = LSHPACK_HDR_UNKNOWN
125  ,[HTTP_HEADER_USER_AGENT]                = LSHPACK_HDR_USER_AGENT
126  ,[HTTP_HEADER_VARY]                      = LSHPACK_HDR_VARY
127  ,[HTTP_HEADER_X_FORWARDED_FOR]           = LSHPACK_HDR_UNKNOWN
128  ,[HTTP_HEADER_X_FORWARDED_PROTO]         = LSHPACK_HDR_UNKNOWN
129  ,[HTTP_HEADER_HTTP2_SETTINGS]            = LSHPACK_HDR_UNKNOWN
130  ,[HTTP_HEADER_ACCEPT]                    = LSHPACK_HDR_ACCEPT
131  ,[HTTP_HEADER_ACCEPT_LANGUAGE]           = LSHPACK_HDR_ACCEPT_LANGUAGE
132  ,[HTTP_HEADER_ACCEPT_RANGES]             = LSHPACK_HDR_ACCEPT_RANGES
133  ,[HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN]=LSHPACK_HDR_ACCESS_CONTROL_ALLOW_ORIGIN
134  ,[HTTP_HEADER_AGE]                       = LSHPACK_HDR_AGE
135  ,[HTTP_HEADER_ALLOW]                     = LSHPACK_HDR_ALLOW
136  ,[HTTP_HEADER_ALT_SVC]                   = LSHPACK_HDR_UNKNOWN
137  ,[HTTP_HEADER_ALT_USED]                  = LSHPACK_HDR_UNKNOWN
138  ,[HTTP_HEADER_CONTENT_RANGE]             = LSHPACK_HDR_CONTENT_RANGE
139  ,[HTTP_HEADER_CONTENT_SECURITY_POLICY]   = LSHPACK_HDR_UNKNOWN
140  ,[HTTP_HEADER_DNT]                       = LSHPACK_HDR_UNKNOWN
141  ,[HTTP_HEADER_EXPECT_CT]                 = LSHPACK_HDR_UNKNOWN
142  ,[HTTP_HEADER_EXPIRES]                   = LSHPACK_HDR_EXPIRES
143  ,[HTTP_HEADER_IF_MATCH]                  = LSHPACK_HDR_IF_MATCH
144  ,[HTTP_HEADER_IF_RANGE]                  = LSHPACK_HDR_IF_RANGE
145  ,[HTTP_HEADER_IF_UNMODIFIED_SINCE]       = LSHPACK_HDR_IF_UNMODIFIED_SINCE
146  ,[HTTP_HEADER_LINK]                      = LSHPACK_HDR_LINK
147  ,[HTTP_HEADER_ONION_LOCATION]            = LSHPACK_HDR_UNKNOWN
148  ,[HTTP_HEADER_P3P]                       = LSHPACK_HDR_UNKNOWN
149  ,[HTTP_HEADER_PRAGMA]                    = LSHPACK_HDR_UNKNOWN
150  ,[HTTP_HEADER_REFERER]                   = LSHPACK_HDR_REFERER
151  ,[HTTP_HEADER_REFERRER_POLICY]           = LSHPACK_HDR_UNKNOWN
152  ,[HTTP_HEADER_STRICT_TRANSPORT_SECURITY] = LSHPACK_HDR_STRICT_TRANSPORT_SECURITY
153  ,[HTTP_HEADER_TE]                        = LSHPACK_HDR_UNKNOWN
154  ,[HTTP_HEADER_UPGRADE_INSECURE_REQUESTS] = LSHPACK_HDR_UNKNOWN
155  ,[HTTP_HEADER_WWW_AUTHENTICATE]          = LSHPACK_HDR_WWW_AUTHENTICATE
156  ,[HTTP_HEADER_X_CONTENT_TYPE_OPTIONS]    = LSHPACK_HDR_UNKNOWN
157  ,[HTTP_HEADER_X_FRAME_OPTIONS]           = LSHPACK_HDR_UNKNOWN
158  ,[HTTP_HEADER_X_XSS_PROTECTION]          = LSHPACK_HDR_UNKNOWN
159 };
160 
161 
162 /* Note: must be kept in sync with ls-hpack/lshpack.h:lshpack_static_hdr_idx[]*/
163 static const uint8_t lshpack_idx_http_header[] = {
164   [LSHPACK_HDR_UNKNOWN]                   = HTTP_HEADER_OTHER
165  ,[LSHPACK_HDR_AUTHORITY]                 = HTTP_HEADER_OTHER
166  ,[LSHPACK_HDR_METHOD_GET]                = HTTP_HEADER_OTHER
167  ,[LSHPACK_HDR_METHOD_POST]               = HTTP_HEADER_OTHER
168  ,[LSHPACK_HDR_PATH]                      = HTTP_HEADER_OTHER
169  ,[LSHPACK_HDR_PATH_INDEX_HTML]           = HTTP_HEADER_OTHER
170  ,[LSHPACK_HDR_SCHEME_HTTP]               = HTTP_HEADER_OTHER
171  ,[LSHPACK_HDR_SCHEME_HTTPS]              = HTTP_HEADER_OTHER
172  ,[LSHPACK_HDR_STATUS_200]                = HTTP_HEADER_OTHER
173  ,[LSHPACK_HDR_STATUS_204]                = HTTP_HEADER_OTHER
174  ,[LSHPACK_HDR_STATUS_206]                = HTTP_HEADER_OTHER
175  ,[LSHPACK_HDR_STATUS_304]                = HTTP_HEADER_OTHER
176  ,[LSHPACK_HDR_STATUS_400]                = HTTP_HEADER_OTHER
177  ,[LSHPACK_HDR_STATUS_404]                = HTTP_HEADER_OTHER
178  ,[LSHPACK_HDR_STATUS_500]                = HTTP_HEADER_OTHER
179  ,[LSHPACK_HDR_ACCEPT_CHARSET]            = HTTP_HEADER_OTHER
180  ,[LSHPACK_HDR_ACCEPT_ENCODING]           = HTTP_HEADER_ACCEPT_ENCODING
181  ,[LSHPACK_HDR_ACCEPT_LANGUAGE]           = HTTP_HEADER_ACCEPT_LANGUAGE
182  ,[LSHPACK_HDR_ACCEPT_RANGES]             = HTTP_HEADER_ACCEPT_RANGES
183  ,[LSHPACK_HDR_ACCEPT]                    = HTTP_HEADER_ACCEPT
184  ,[LSHPACK_HDR_ACCESS_CONTROL_ALLOW_ORIGIN]=HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN
185  ,[LSHPACK_HDR_AGE]                       = HTTP_HEADER_AGE
186  ,[LSHPACK_HDR_ALLOW]                     = HTTP_HEADER_ALLOW
187  ,[LSHPACK_HDR_AUTHORIZATION]             = HTTP_HEADER_AUTHORIZATION
188  ,[LSHPACK_HDR_CACHE_CONTROL]             = HTTP_HEADER_CACHE_CONTROL
189  ,[LSHPACK_HDR_CONTENT_DISPOSITION]       = HTTP_HEADER_OTHER
190  ,[LSHPACK_HDR_CONTENT_ENCODING]          = HTTP_HEADER_CONTENT_ENCODING
191  ,[LSHPACK_HDR_CONTENT_LANGUAGE]          = HTTP_HEADER_OTHER
192  ,[LSHPACK_HDR_CONTENT_LENGTH]            = HTTP_HEADER_CONTENT_LENGTH
193  ,[LSHPACK_HDR_CONTENT_LOCATION]          = HTTP_HEADER_CONTENT_LOCATION
194  ,[LSHPACK_HDR_CONTENT_RANGE]             = HTTP_HEADER_CONTENT_RANGE
195  ,[LSHPACK_HDR_CONTENT_TYPE]              = HTTP_HEADER_CONTENT_TYPE
196  ,[LSHPACK_HDR_COOKIE]                    = HTTP_HEADER_COOKIE
197  ,[LSHPACK_HDR_DATE]                      = HTTP_HEADER_DATE
198  ,[LSHPACK_HDR_ETAG]                      = HTTP_HEADER_ETAG
199  ,[LSHPACK_HDR_EXPECT]                    = HTTP_HEADER_EXPECT
200  ,[LSHPACK_HDR_EXPIRES]                   = HTTP_HEADER_EXPIRES
201  ,[LSHPACK_HDR_FROM]                      = HTTP_HEADER_OTHER
202  ,[LSHPACK_HDR_HOST]                      = HTTP_HEADER_HOST
203  ,[LSHPACK_HDR_IF_MATCH]                  = HTTP_HEADER_IF_MATCH
204  ,[LSHPACK_HDR_IF_MODIFIED_SINCE]         = HTTP_HEADER_IF_MODIFIED_SINCE
205  ,[LSHPACK_HDR_IF_NONE_MATCH]             = HTTP_HEADER_IF_NONE_MATCH
206  ,[LSHPACK_HDR_IF_RANGE]                  = HTTP_HEADER_IF_RANGE
207  ,[LSHPACK_HDR_IF_UNMODIFIED_SINCE]       = HTTP_HEADER_IF_UNMODIFIED_SINCE
208  ,[LSHPACK_HDR_LAST_MODIFIED]             = HTTP_HEADER_LAST_MODIFIED
209  ,[LSHPACK_HDR_LINK]                      = HTTP_HEADER_LINK
210  ,[LSHPACK_HDR_LOCATION]                  = HTTP_HEADER_LOCATION
211  ,[LSHPACK_HDR_MAX_FORWARDS]              = HTTP_HEADER_OTHER
212  ,[LSHPACK_HDR_PROXY_AUTHENTICATE]        = HTTP_HEADER_OTHER
213  ,[LSHPACK_HDR_PROXY_AUTHORIZATION]       = HTTP_HEADER_OTHER
214  ,[LSHPACK_HDR_RANGE]                     = HTTP_HEADER_RANGE
215  ,[LSHPACK_HDR_REFERER]                   = HTTP_HEADER_REFERER
216  ,[LSHPACK_HDR_REFRESH]                   = HTTP_HEADER_OTHER
217  ,[LSHPACK_HDR_RETRY_AFTER]               = HTTP_HEADER_OTHER
218  ,[LSHPACK_HDR_SERVER]                    = HTTP_HEADER_SERVER
219  ,[LSHPACK_HDR_SET_COOKIE]                = HTTP_HEADER_SET_COOKIE
220  ,[LSHPACK_HDR_STRICT_TRANSPORT_SECURITY] = HTTP_HEADER_STRICT_TRANSPORT_SECURITY
221  ,[LSHPACK_HDR_TRANSFER_ENCODING]         = HTTP_HEADER_TRANSFER_ENCODING
222  ,[LSHPACK_HDR_USER_AGENT]                = HTTP_HEADER_USER_AGENT
223  ,[LSHPACK_HDR_VARY]                      = HTTP_HEADER_VARY
224  ,[LSHPACK_HDR_VIA]                       = HTTP_HEADER_OTHER
225  ,[LSHPACK_HDR_WWW_AUTHENTICATE]          = HTTP_HEADER_WWW_AUTHENTICATE
226 };
227 
228 
229 static request_st * h2_init_stream (request_st * const h2r, connection * const con);
230 
231 
232 static void
233 h2_send_settings_ack (connection * const con)
234 {
235     static const uint8_t settings_ack[] = {
236       /* SETTINGS w/ ACK */
237       0x00, 0x00, 0x00        /* frame length */
238      ,H2_FTYPE_SETTINGS       /* frame type */
239      ,H2_FLAG_ACK             /* frame flags */
240      ,0x00, 0x00, 0x00, 0x00  /* stream identifier */
241     };
242 
243     chunkqueue_append_mem(con->write_queue,
244                           (const char *)settings_ack, sizeof(settings_ack));
245 }
246 
247 
248 __attribute_cold__
249 static void
250 h2_send_rst_stream_id (uint32_t h2id, connection * const con, const request_h2error_t e)
251 {
252     union {
253       uint8_t c[16];
254       uint32_t u[4];          /*(alignment)*/
255     } rst_stream = { {        /*(big-endian numbers)*/
256       0x00, 0x00, 0x00        /* padding for alignment; do not send */
257       /* RST_STREAM */
258      ,0x00, 0x00, 0x04        /* frame length */
259      ,H2_FTYPE_RST_STREAM     /* frame type */
260      ,0x00                    /* frame flags */
261      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
262      ,0x00, 0x00, 0x00, 0x00  /* error code;       (fill in below) */
263     } };
264 
265     rst_stream.u[2] = htonl(h2id);
266     rst_stream.u[3] = htonl(e);
267     chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align padding)*/
268                           (const char *)rst_stream.c+3, sizeof(rst_stream)-3);
269 }
270 
271 
272 __attribute_cold__
273 static void
274 h2_send_rst_stream (request_st * const r, connection * const con, const request_h2error_t e)
275 {
276     r->state = CON_STATE_ERROR;
277     r->h2state = H2_STATE_CLOSED;
278     h2_send_rst_stream_id(r->h2id, con, e);
279 }
280 
281 
282 __attribute_cold__
283 static void
284 h2_send_goaway_rst_stream (connection * const con)
285 {
286     h2con * const h2c = con->h2;
287     const int sent_goaway = h2c->sent_goaway;
288     for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
289         request_st * const r = h2c->r[i];
290         if (r->h2state == H2_STATE_CLOSED) continue;
291         /*(XXX: might consider always sending RST_STREAM)*/
292         if (!sent_goaway) {
293             r->state = CON_STATE_ERROR;
294             r->h2state = H2_STATE_CLOSED;
295         }
296         else /*(also sets r->h2state = H2_STATE_CLOSED)*/
297             h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
298     }
299 }
300 
301 
302 void
303 h2_send_goaway (connection * const con, const request_h2error_t e)
304 {
305     /* future: RFC 7540 Section 6.8 notes that server initiating graceful
306      * connection shutdown SHOULD send GOAWAY with stream id 2^31-1 and a
307      * NO_ERROR code, and later send another GOAWAY with an updated last
308      * stream identifier.  (This is not done here, but doing so would be
309      * friendlier to clients that send streaming requests which the client
310      * is unable to retry.) */
311 
312     if (e != H2_E_NO_ERROR)
313         h2_send_goaway_rst_stream(con);
314     /*XXX: else should send RST_STREAM w/ CANCEL for any active PUSH_PROMISE */
315 
316     h2con * const h2c = con->h2;
317     if (h2c->sent_goaway && (h2c->sent_goaway > 0 || e == H2_E_NO_ERROR))
318         return;
319     h2c->sent_goaway = (e == H2_E_NO_ERROR) ? -1 : (int32_t)e;
320 
321     union {
322       uint8_t c[20];
323       uint32_t u[5];          /*(alignment)*/
324     } goaway = { {            /*(big-endian numbers)*/
325       0x00, 0x00, 0x00        /* padding for alignment; do not send */
326       /* GOAWAY */
327      ,0x00, 0x00, 0x08        /* frame length */
328      ,H2_FTYPE_GOAWAY         /* frame type */
329      ,0x00                    /* frame flags */
330      ,0x00, 0x00, 0x00, 0x00  /* stream identifier */
331      ,0x00, 0x00, 0x00, 0x00  /* last-stream-id (fill in below) */
332      ,0x00, 0x00, 0x00, 0x00  /* error code     (fill in below) */
333                               /* additional debug data (*); (optional)
334                                * adjust frame length if any additional
335                                * debug data is sent */
336     } };
337 
338     goaway.u[3] = htonl(h2c->h2_cid); /* last-stream-id */
339     goaway.u[4] = htonl(e);
340     chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align padding)*/
341                           (const char *)goaway.c+3, sizeof(goaway)-3);
342 }
343 
344 
345 __attribute_cold__
346 static void
347 h2_send_goaway_e (connection * const con, const request_h2error_t e)
348 {
349     h2_send_goaway(con, e);
350 }
351 
352 
353 static int
354 h2_recv_goaway (connection * const con, const uint8_t * const s, uint32_t len)
355 {
356     /*(s must be entire GOAWAY frame and len the frame length field)*/
357     /*assert(s[3] == H2_FTYPE_GOAWAY);*/
358     UNUSED(len);
359     if ((s[5] & ~0x80) | s[6] | s[7] | s[8]) { /*(GOAWAY stream id must be 0)*/
360         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
361         return 0;
362     }
363     const uint32_t e = (s[13]<< 24) | (s[14]<< 16) | (s[15]<< 8) | s[16];
364   #if 0
365     /* XXX: debug: could log error code sent by peer */
366   #endif
367   #if 0
368     /* XXX: debug: could log additional debug info (if any) sent by peer */
369     if (len > 8) {
370     }
371   #endif
372   #if 0
373     /* XXX: could validate/use Last-Stream-ID sent by peer */
374     const uint32_t last_id = (s[9] << 24) | (s[10]<< 16) | (s[11]<< 8) | s[12];
375   #endif
376 
377     /* send PROTOCOL_ERROR back to peer if peer sent an error code
378      * (i.e. not NO_ERROR) in order to terminate connection more quickly */
379     h2_send_goaway(con, e==H2_E_NO_ERROR ? H2_E_NO_ERROR : H2_E_PROTOCOL_ERROR);
380     h2con * const h2c = con->h2;
381     if (0 == h2c->rused) return 0;
382     return 1;
383 }
384 
385 
386 static void
387 h2_recv_rst_stream (connection * const con, const uint8_t * const s, const uint32_t len)
388 {
389     /*(s must be entire RST_STREAM frame and len the frame length field)*/
390     /*assert(s[3] == H2_FTYPE_RST_STREAM);*/
391     if (4 != len) {                  /*(RST_STREAM frame length must be 4)*/
392         h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
393         return;
394     }
395     const uint32_t id =
396       ((s[5] << 24) | (s[6] << 16) | (s[7] << 8) | s[8]) & ~0x80000000u;
397     if (0 == id) {                   /*(RST_STREAM id must not be 0)*/
398         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
399         return;
400     }
401     h2con * const h2c = con->h2;
402     for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
403         request_st * const r = h2c->r[i];
404         if (r->h2id != id) continue;
405         if (r->h2state == H2_STATE_IDLE) {
406             /*(RST_STREAM must not be for stream in "idle" state)*/
407             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
408             return;
409         }
410         /* XXX: ? add debug trace including error code from RST_STREAM ? */
411         r->state = CON_STATE_ERROR;
412         r->h2state = H2_STATE_CLOSED;
413         return;
414     }
415     /* unknown/inactive stream id
416      * XXX: how should we handle RST_STREAM for unknown/inactive stream id?
417      * (stream id may have been closed recently and server forgot about it,
418      *  but client (peer) sent RST_STREAM prior to receiving stream end from
419      *  server)*/
420   #if 0
421     if (h2c->sent_goaway && h2c->h2_cid < id) return;
422     h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
423   #else
424     if (h2c->h2_cid < id) {
425         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
426         return;
427     }
428   #endif
429 }
430 
431 
432 static void
433 h2_recv_ping (connection * const con, uint8_t * const s, const uint32_t len)
434 {
435   #if 0
436     union {
437       uint8_t c[20];
438       uint32_t u[5];          /*(alignment)*/
439     } ping = { {              /*(big-endian numbers)*/
440       0x00, 0x00, 0x00        /* padding for alignment; do not send */
441       /* PING */
442      ,0x00, 0x00, 0x08        /* frame length */
443      ,H2_FTYPE_PING           /* frame type */
444      ,H2_FLAG_ACK             /* frame flags */
445      ,0x00, 0x00, 0x00, 0x00  /* stream identifier */
446      ,0x00, 0x00, 0x00, 0x00  /* opaque            (fill in below) */
447      ,0x00, 0x00, 0x00, 0x00
448     } };
449   #endif
450 
451     /*(s must be entire PING frame and len the frame length field)*/
452     /*assert(s[3] == H2_FTYPE_PING);*/
453     if (8 != len) {                  /*(PING frame length must be 8)*/
454         h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
455         return;
456     }
457     s[5] &= ~0x80; /* reserved bit must be ignored */
458     if (s[5] | s[6] | s[7] | s[8]) { /*(PING stream id must be 0)*/
459         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
460         return;
461     }
462     if (s[4] & H2_FLAG_ACK) /*(ignore; unexpected if we did not send PING)*/
463         return;
464     /* reflect PING back to peer with frame flag ACK */
465     /* (9 byte frame header plus 8 byte PING payload = 17 bytes)*/
466     s[4] = H2_FLAG_ACK;
467     chunkqueue_append_mem(con->write_queue, (const char *)s, 17);
468 }
469 
470 
471 static void
472 h2_recv_priority (connection * const con, const uint8_t * const s, const uint32_t len)
473 {
474     /*(s must be entire PRIORITY frame and len the frame length field)*/
475     /*assert(s[3] == H2_FTYPE_PRIORITY);*/
476     if (5 != len) {                  /*(PRIORITY frame length must be 5)*/
477         h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
478         return;
479     }
480     const uint32_t id =
481       ((s[5] << 24) | (s[6] << 16) | (s[7] << 8) | s[8]) & ~0x80000000u;
482     if (0 == id) {                   /*(PRIORITY id must not be 0)*/
483         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
484         return;
485     }
486     const uint32_t prio =
487       ((s[9] << 24) | (s[10] << 16) | (s[11] << 8) | s[12]) & ~0x80000000u;
488   #if 0
489     uint32_t exclusive_dependency = (s[9] & 0x80) ? 1 : 0;
490     uint32_t weight = s[13];
491   #endif
492     h2con * const h2c = con->h2;
493     for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
494         request_st * const r = h2c->r[i];
495         if (r->h2id != id) continue;
496         /* XXX: TODO: update priority info */
497         if (prio == id) {
498             h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
499             return;
500         }
501         return;
502     }
503     /* XXX: TODO: update priority info for unknown/inactive stream */
504     /*if (h2c->sent_goaway && h2c->h2_cid < id) return;*/
505     if (prio == id) {
506         h2_send_rst_stream_id(id, con, H2_E_PROTOCOL_ERROR);
507         return;
508     }
509 }
510 
511 
512 static void
513 h2_recv_window_update (connection * const con, const uint8_t * const s, const uint32_t len)
514 {
515     /*(s must be entire WINDOW_UPDATE frame and len the frame length field)*/
516     /*assert(s[3] == H2_FTYPE_WINDOW_UPDATE);*/
517     if (4 != len) {                  /*(WINDOW_UPDATE frame length must be 4)*/
518         h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
519         return;
520     }
521     const uint32_t id =
522       ((s[5] << 24) | (s[6] << 16) | (s[7] << 8) | s[8]) & ~0x80000000u;
523     const int32_t v =
524       (int32_t)(((s[9] << 24)|(s[10] << 16)|(s[11] << 8)|s[12]) & ~0x80000000);
525     request_st *r = NULL;
526     if (0 == id)
527         r = &con->request;
528     else {
529         h2con * const h2c = con->h2;
530         for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
531             request_st * const rr = h2c->r[i];
532             if (rr->h2id != id) continue;
533             r = rr;
534             break;
535         }
536         /* peer should not send WINDOW_UPDATE for an inactive stream,
537          * but RFC 7540 does not explicitly call this out.  On the other hand,
538          * since there may be a temporary mismatch in stream state between
539          * peers, ignore window update if stream id is unknown/inactive.
540          * Also, it is not an error if GOAWAY sent and h2c->h2_cid < id */
541         if (NULL == r) {
542             if (h2c->h2_cid < id && 0 == h2c->sent_goaway)
543                 h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
544           #if 0
545             /*(needed for h2spec if testing with response < 16k+1 over TLS
546              * or response <= socket send buffer size over cleartext, due to
547              * completing response too quickly for the test frame sequence) */
548             if (v == 0)        /* h2spec: 6.9-2   (after we retired id 1) */
549                 h2_send_rst_stream_id(id, con, H2_E_PROTOCOL_ERROR);
550             if (v == INT32_MAX)/* h2spec: 6.9.1-3 (after we retired id 1) */
551                 h2_send_rst_stream_id(id, con, H2_E_FLOW_CONTROL_ERROR);
552           #endif
553             return;
554         }
555         /* MUST NOT be treated as error if stream is in closed state; ignore */
556         if (r->h2state == H2_STATE_CLOSED
557             || r->h2state == H2_STATE_HALF_CLOSED_LOCAL) return;
558     }
559     if (0 == v || r->h2_swin > INT32_MAX - v) {
560         request_h2error_t e = (0 == v)
561           ? H2_E_PROTOCOL_ERROR
562           : H2_E_FLOW_CONTROL_ERROR;
563         if (0 == id)
564             h2_send_goaway_e(con, e);
565         else
566             h2_send_rst_stream(r, con, e);
567         return;
568     }
569     r->h2_swin += v;
570 }
571 
572 
573 static void
574 h2_send_window_update (connection * const con, uint32_t h2id, const uint32_t len)
575 {
576     if (0 == len) return;
577     union {
578       uint8_t c[16];
579       uint32_t u[4];          /*(alignment)*/
580     } window_upd = { {        /*(big-endian numbers)*/
581       0x00, 0x00, 0x00        /* padding for alignment; do not send */
582       /* WINDOW_UPDATE */
583      ,0x00, 0x00, 0x04        /* frame length */
584      ,H2_FTYPE_WINDOW_UPDATE  /* frame type */
585      ,0x00                    /* frame flags */
586      ,0x00, 0x00, 0x00, 0x00  /* stream identifier      (fill in below) */
587      ,0x00, 0x00, 0x00, 0x00  /* window update increase (fill in below) */
588     } };
589 
590     window_upd.u[2] = htonl(h2id);
591     window_upd.u[3] = htonl(len);
592     chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align padding)*/
593                           (const char *)window_upd.c+3, sizeof(window_upd)-3);
594 }
595 
596 
597 static void
598 h2_parse_frame_settings (connection * const con, const uint8_t *s, uint32_t len)
599 {
600     /*(s and len must be SETTINGS frame payload)*/
601     /*(caller must validate frame len, frame type == 0x04, frame id == 0)*/
602     h2con * const h2c = con->h2;
603     for (; len >= 6; len -= 6, s += 6) {
604         uint32_t v = (s[2] << 24) | (s[3] << 16) | (s[4] << 8) | s[5];
605         switch (((s[0] << 8) | s[1])) {
606           case H2_SETTINGS_HEADER_TABLE_SIZE:
607             /* encoder may use any table size <= value sent by peer */
608             /* For simple compliance with RFC and constrained memory use,
609              * choose to not increase table size beyond the default 4096,
610              * but allow smaller sizes to be set and then reset up to 4096,
611              * e.g. set to 0 to evict all dynamic table entries,
612              * and then set to 4096 to restore dynamic table use */
613             if (v > 4096) v = 4096;
614             if (v == h2c->s_header_table_size) break;
615             h2c->s_header_table_size = v;
616             lshpack_enc_set_max_capacity(&h2c->encoder, v);
617             break;
618           case H2_SETTINGS_ENABLE_PUSH:
619             if ((v|1) != 1) { /*(v == 0 || v == 1)*/
620                 h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
621                 return;
622             }
623             h2c->s_enable_push = v;
624             break;
625           case H2_SETTINGS_MAX_CONCURRENT_STREAMS:
626             h2c->s_max_concurrent_streams = v;
627             break;
628           case H2_SETTINGS_INITIAL_WINDOW_SIZE:
629             if (v > INT32_MAX) { /*(2^31 - 1)*/
630                 h2_send_goaway_e(con, H2_E_FLOW_CONTROL_ERROR);
631                 return;
632             }
633             else if (h2c->rused) { /*(update existing streams)*/
634                 /*(underflow is ok; unsigned integer math)*/
635                 /*(h2c->s_initial_window_size is >= 0)*/
636                 int32_t diff =
637                   (int32_t)((uint32_t)v - (uint32_t)h2c->s_initial_window_size);
638                 for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
639                     request_st * const r = h2c->r[i];
640                     const int32_t swin = r->h2_swin;
641                     if (r->h2state == H2_STATE_HALF_CLOSED_LOCAL
642                         || r->h2state == H2_STATE_CLOSED) continue;
643                     if (diff >= 0
644                         ? swin > INT32_MAX - diff
645                         : swin < INT32_MIN - diff) {
646                         h2_send_rst_stream(r, con, H2_E_FLOW_CONTROL_ERROR);
647                         continue;
648                     }
649                     r->h2_swin += diff;
650                 }
651             }
652             h2c->s_initial_window_size = (int32_t)v;
653             break;
654           case H2_SETTINGS_MAX_FRAME_SIZE:
655             if (v < 16384 || v > 16777215) { /*[(2^14),(2^24-1)]*/
656                 h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
657                 return;
658             }
659             h2c->s_max_frame_size = v;
660             break;
661           case H2_SETTINGS_MAX_HEADER_LIST_SIZE:
662             h2c->s_max_header_list_size = v;
663             break;
664           default:
665             break;
666         }
667     }
668 
669     if (len) {
670         h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
671         return;
672     }
673 
674     /* caller must send SETTINGS frame with ACK flag,
675      * if appropriate, and if h2c->sent_goaway is not set
676      * (Do not send ACK for Upgrade: h2c and HTTP2-Settings header) */
677 }
678 
679 
680 static void
681 h2_recv_settings (connection * const con, const uint8_t * const s, const uint32_t len)
682 {
683     /*(s must be entire SETTINGS frame, len must be the frame length field)*/
684     /*assert(s[3] == H2_FTYPE_SETTINGS);*/
685     if ((s[5] & ~0x80) | s[6] | s[7] | s[8]) {/*(SETTINGS stream id must be 0)*/
686         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
687         return;
688     }
689 
690     h2con * const h2c = con->h2;
691     if (!(s[4] & H2_FLAG_ACK)) {
692         h2_parse_frame_settings(con, s+9, len);
693         if (h2c->sent_goaway <= 0)
694             h2_send_settings_ack(con);
695     }
696     else {
697         /* lighttpd currently sends SETTINGS in server preface, and not again,
698          * so this does not have to handle another SETTINGS frame being sent
699          * before receiving an ACK from prior SETTINGS frame.  (If it does,
700          * then we will need some sort of counter.) */
701         if (0 != len)
702             h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
703         else if (h2c->sent_settings)
704             h2c->sent_settings = 0;
705         else /* SETTINGS with ACK for SETTINGS frame we did not send */
706             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
707     }
708 }
709 
710 
711 static int
712 h2_recv_end_data (request_st * const r, connection * const con, const uint32_t alen)
713 {
714     chunkqueue * const reqbody_queue = &r->reqbody_queue;
715     r->h2state = (r->h2state == H2_STATE_OPEN)
716       ? H2_STATE_HALF_CLOSED_REMOTE
717       : H2_STATE_CLOSED;
718     if (r->reqbody_length == -1)
719         r->reqbody_length = reqbody_queue->bytes_in + (off_t)alen;
720     else if (r->reqbody_length != reqbody_queue->bytes_in + (off_t)alen) {
721         if (0 == reqbody_queue->bytes_out) {
722             h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
723             return 0;
724         } /* else let reqbody streaming consumer handle truncated reqbody */
725     }
726 
727     return 1;
728 }
729 
730 
731 static int
732 h2_recv_data (connection * const con, const uint8_t * const s, const uint32_t len)
733 {
734     /*(s must be entire DATA frame, len must be the frame length field)*/
735     /*assert(s[3] == H2_FTYPE_DATA);*/
736 
737     /* future: consider string refs rather than copying DATA from chunkqueue
738      * or try to consume entire chunk, or to split chunks with less copying */
739 
740     h2con * const h2c = con->h2;
741     const uint32_t id =
742       ((s[5] << 24) | (s[6] << 16) | (s[7] << 8) | s[8]) & ~0x80000000u;
743     if (0 == id || h2c->h2_cid < id) { /*(RST_STREAM id must not be 0)*/
744         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
745         return 0;
746     }
747 
748     uint32_t alen = len; /* actual data len, minus padding */
749     uint32_t pad = 0;
750     if (s[4] & H2_FLAG_PADDED) {
751         pad = s[9];
752         if (pad >= len) {
753             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
754             return 0;
755         }
756         alen -= (1 + pad);
757     }
758 
759     request_st * const h2r = &con->request;
760     if (h2r->h2_rwin <= 0 && 0 != alen) { /*(always proceed if 0 == alen)*/
761         /*(connection_state_machine_h2() must ensure con is rescheduled,
762          * when backends consume data if con->read_queue is not empty,
763          * whether or not con->fd has data to read from the network)*/
764         /*(leave frame in cq to be re-read later)*/
765         return 0;
766     }
767     /*(allow h2r->h2_rwin to dip below 0 so that entire frame is processed)*/
768     /*(not worried about underflow while
769      * SETTINGS_MAX_FRAME_SIZE is small (e.g. 16k or 32k) and
770      * SETTINGS_MAX_CONCURRENT_STREAMS is small (h2c->r[8]))*/
771     /*h2r->h2_rwin -= (int32_t)len;*//* update connection recv window (below) */
772 
773     request_st *r = NULL;
774     for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
775         request_st * const rr = h2c->r[i];
776         if (rr->h2id != id) continue;
777         r = rr;
778         break;
779     }
780     chunkqueue * const cq = con->read_queue;
781     if (NULL == r) {
782         /* XXX: TODO: might need to keep a list of recently retired streams
783          * for a few seconds so that if we send RST_STREAM, then we ignore
784          * further DATA and do not send connection error, though recv windows
785          * still must be updated. */
786         if (h2c->h2_cid < id || (!h2c->sent_goaway && 0 != alen))
787             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
788         chunkqueue_mark_written(cq, 9+len);
789         return 0;
790     }
791 
792     if (r->h2state == H2_STATE_CLOSED
793         || r->h2state == H2_STATE_HALF_CLOSED_REMOTE) {
794         h2_send_rst_stream_id(id, con, H2_E_STREAM_CLOSED);
795         chunkqueue_mark_written(cq, 9+len);
796         h2_send_window_update(con, 0, len); /*(h2r->h2_rwin)*/
797         return 1;
798     }
799 
800     if (r->h2_rwin <= 0 && 0 != alen) {/*(always proceed if 0==alen)*/
801         if (r->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN) {
802             /*(connection_state_machine_h2() must ensure con is rescheduled,
803              * when backends consume data if con->read_queue is not empty,
804              * whether or not con->fd has data to read from the network)*/
805             /*(leave frame in cq to be re-read later)*/
806             return 0;
807         }
808     }
809     /*(allow h2r->h2_rwin to dip below 0 so that entire frame is processed)*/
810     /*(undeflow will not occur (with reasonable SETTINGS_MAX_FRAME_SIZE used)
811      * since windows updated elsewhere and data is streamed to temp files if
812      * not FDEVENT_STREAM_REQUEST_BUFMIN)*/
813     /*r->h2_rwin -= (int32_t)len;*/
814     h2_send_window_update(con, r->h2id, len); /*(r->h2_rwin)*/
815     h2_send_window_update(con, 0, len);       /*(h2r->h2_rwin)*/
816 
817     chunkqueue * const dst = &r->reqbody_queue;
818 
819     if (r->reqbody_length >= 0 && r->reqbody_length < dst->bytes_in + alen) {
820         /* data exceeds Content-Length specified (client mistake) */
821       #if 0 /* truncate */
822         alen = r->reqbody_length - dst->bytes_in;
823         /*(END_STREAM may follow in 0-length DATA frame or HEADERS (trailers))*/
824       #else /* reject */
825         h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
826         chunkqueue_mark_written(cq, 9+len);
827         return 1;
828       #endif
829     }
830 
831     /*(accounting for mod_accesslog and mod_rrdtool)*/
832     chunkqueue * const rq = &r->read_queue;
833     rq->bytes_in  += (off_t)alen;
834     rq->bytes_out += (off_t)alen;
835 
836     /* r->conf.max_request_size is in kBytes */
837     const off_t max_request_size = (off_t)r->conf.max_request_size << 10;
838     if (0 != max_request_size
839         && dst->bytes_in + (off_t)alen > max_request_size) {
840         if (0 == r->http_status) {
841             r->http_status = 413; /* Payload Too Large */
842             log_error(r->conf.errh, __FILE__, __LINE__,
843               "request-size too long: %lld -> 413",
844               (long long) (dst->bytes_in + (off_t)alen));
845         }
846         chunkqueue_mark_written(cq, 9+len);
847         return 1;
848     }
849 
850     if ((s[4] & H2_FLAG_END_STREAM) && !h2_recv_end_data(r, con, alen)) {
851         chunkqueue_mark_written(cq, 9+len);
852         return 1;
853     }
854 
855     chunkqueue_mark_written(cq, 9 + ((s[4] & H2_FLAG_PADDED) ? 1 : 0));
856 
857   #if 0
858     if (pad) {
859         /* XXX: future optimization: if data is at end of chunk, then adjust
860          * size of chunk by reducing c->mem->used to avoid copying chunk
861          * when it is split (below) since the split would be due to padding
862          * (also adjust cq->bytes_out)*/
863         /*(might quickly check 9+len == cqlen if cqlen passed in as param)*/
864         /*(then check if cq->last contains all of padding, or leave alone)*/
865         /*(if handled here, then set pad = 0 here)*/
866     }
867   #endif
868 
869     /*(similar decision logic to that in http_chunk_uses_tempfile())*/
870     const chunk * const c = dst->last;
871     if ((c && c->type == FILE_CHUNK && c->file.is_temp)
872         || chunkqueue_length(dst) + alen > 65536) {
873         log_error_st * const errh = r->conf.errh;
874         if (0 != chunkqueue_steal_with_tempfiles(dst, cq, (off_t)alen, errh)) {
875             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
876             return 0;
877         }
878     }
879     else
880         chunkqueue_steal(dst, cq, (off_t)alen);
881 
882     if (pad)
883         chunkqueue_mark_written(cq, pad);
884     return 1;
885 }
886 
887 
888 __attribute_cold__
889 static uint32_t
890 h2_frame_cq_compact (chunkqueue * const cq, uint32_t len)
891 {
892     /*(marked cold since most frames not expect to cross chunk boundary)*/
893 
894     /*(must be guaranteed by caller)*/
895         /*assert(chunkqueue_length(cq) >= len);*/
896         /*assert(cq->first != cq->last);*//*(multiple chunks)*/
897     /* caller must guarantee that chunks in chunkqueue are all MEM_CHUNK */
898 
899     chunkqueue_compact_mem(cq, len);
900     return buffer_string_length(cq->first->mem) - (uint32_t)cq->first->offset;
901 }
902 
903 
904 __attribute_cold__
905 static uint32_t
906 h2_recv_continuation (uint32_t n, uint32_t clen, const off_t cqlen, chunkqueue * const cq, connection * const con)
907 {
908     chunk *c = cq->first;
909     uint8_t *s = (uint8_t *)(c->mem->ptr + c->offset);
910     uint32_t m = n;
911     uint32_t flags;
912     h2con * const h2c = con->h2;
913     const uint32_t fsize = h2c->s_max_frame_size;
914     const uint32_t id =
915       ((s[5] << 24) | (s[6] << 16) | (s[7] << 8) | s[8]) & ~0x80000000u;
916     do {
917         if (cqlen < n+9) return n+9; /* incomplete frame; go on */
918         if (clen < n+9) {
919             clen = h2_frame_cq_compact(cq, n+9);
920             c = cq->first; /*(reload after h2_frame_cq_compact())*/
921             s = (uint8_t *)(c->mem->ptr + c->offset);
922         }
923         if (s[n+3] != H2_FTYPE_CONTINUATION) {
924             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
925             return 0;
926         }
927         flags = s[n+4];
928         const uint32_t flen = (s[n+0]<<16)|(s[n+1]<<8)|s[n+2];
929         if (id != (uint32_t)((s[n+5]<<24)|(s[n+6]<<16)|(s[n+7]<<8)|s[n+8])) {
930             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
931             return 0;
932         }
933         if (flen > fsize) {
934             h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
935             return 0;
936         }
937         n += 9+flen;
938         if (n >= 65536) { /*(very oversized for hpack)*/
939             h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
940             return 0;
941         }
942         if (clen < n) {
943             clen = h2_frame_cq_compact(cq, n);
944             c = cq->first; /*(reload after h2_frame_cq_compact())*/
945             s = (uint8_t *)(c->mem->ptr + c->offset);
946         }
947     } while (!(flags & H2_FLAG_END_HEADERS));
948 
949     /* If some CONTINUATION frames were concatenated to earlier frames while
950      * processing above, but END_HEADERS were not received, then the next time
951      * data was read, initial frame size might exceed SETTINGS_MAX_FRAME_SIZE.
952      * (This describes the current lighttpd implementation in h2_parse_frames())
953      * While a flag could be set and checked to avoid this, such situations of
954      * large HEADERS (and CONTINUATION) across multiple network reads is
955      * expected to be rare.  Reparse and concatenate below.
956      *
957      * Aside: why would the authors of RFC 7540 go through the trouble of
958      * creating a CONTINUATION frame that must be special-cased when use of
959      * CONTINUATION is so restricted e.g. no other intervening frames and
960      * that HEADERS and PUSH_PROMISE HPACK must be parsed as a single block?
961      * IMHO, it would have been simpler to avoid CONTINUATION entirely, and have
962      * a special-case for HEADERS and PUSH_PROMISE to be allowed to exceed
963      * SETTINGS_MAX_FRAME_SIZE with implementations providing a different limit.
964      * While intermediates would not know such a limit of origin servers,
965      * there could have been a reasonable default set with a different SETTINGS
966      * parameter aimed just at HEADERS and PUSH_PROMISE.  The parameter
967      * SETTINGS_MAX_HEADER_LIST_SIZE could even have been (re)used, had it been
968      * given a reasonable initial value instead of "unlimited", since HPACK
969      * encoded headers are smaller than the HPACK decoded headers to which the
970      * limit SETTINGS_MAX_HEADER_LIST_SIZE applies. */
971 
972     n = m; /* reset n to beginning of first CONTINUATION frame */
973 
974     /* Eliminate padding from first frame (HEADERS or PUSH_PROMISE) if PADDED */
975     if (s[4] & H2_FLAG_PADDED) {
976         const uint32_t plen = s[9];
977         /* validate padding */
978         const uint32_t flen = (s[0]<<16)|(s[1]<<8)|s[2];
979         if (flen < 1 + plen + ((s[n+4] & H2_FLAG_PRIORITY) ? 5 : 0)) {
980             /* Padding that exceeds the size remaining for the header block
981              * fragment MUST be treated as a PROTOCOL_ERROR. */
982             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
983             return 0;
984         }
985         /* set padding to 0 since we will overwrite padding in merge below */
986         /* (alternatively, could memmove() 9 bytes of frame header over the
987          *  pad length octet, remove PADDED flag, add 1 to c->offset,
988          *  add 1 to s, subtract 1 from clen and substract 1 from cqlen,
989          *  substract 1 from n, add 1 to cq->bytes_out) */
990         s[9] = 0;
991         /* set offset to beginning of padding at end of first frame */
992         m -= plen;
993         /* XXX: layer violation; adjusts chunk.c internal accounting */
994         cq->bytes_out += plen;
995     }
996 
997     do {
998         const uint32_t flen = (s[n+0]<<16)|(s[n+1]<<8)|s[n+2];
999         flags = s[n+4];
1000         memmove(s+m, s+n+9, flen);
1001         m += flen;
1002         n += 9+flen;
1003         /* XXX: layer violation; adjusts chunk.c internal accounting */
1004         cq->bytes_out += 9;
1005     } while (!(flags & H2_FLAG_END_HEADERS));
1006     /* overwrite frame size */
1007     m -= 9; /*(temporarily remove frame header from len)*/
1008     s[0] = (m >> 16) & 0xFF;
1009     s[1] = (m >>  8) & 0xFF;
1010     s[2] = (m      ) & 0xFF;
1011     m += 9;
1012     /* adjust chunk c->mem */
1013     if (n < clen) { /*(additional frames after CONTINUATION)*/
1014         memmove(s+m, s+n, clen-n);
1015         n = m + (clen-n);
1016     }
1017     else
1018         n = m;
1019     buffer_string_set_length(c->mem, n + (uint32_t)c->offset);
1020 
1021     return m;
1022 }
1023 
1024 
1025 __attribute_cold__
1026 static request_st *
1027 h2_recv_trailers_r (connection * const con, h2con * const h2c, const uint32_t id, const uint32_t flags)
1028 {
1029     /* rant: RFC 7230 HTTP/1.1 trailer-part would have been much simpler
1030      * to support in RFC 7540 HTTP/2 as a distinct frame type rather than
1031      * HEADERS.  As trailers are not known at the time the request is made,
1032      * reuse of such trailers is limited and so a theoretical TRAILERS frame
1033      * could have been implemented without HPACK encoding, and would have
1034      * been more straightforward to implement than overloading and having to
1035      * handle multiple cases for HEADERS.  TRAILERS support could then also
1036      * be optional, like in HTTP/1.1 */
1037     request_st *r = NULL;
1038     for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
1039         request_st * const rr = h2c->r[i];
1040         if (rr->h2id != id) continue;
1041         r = rr;
1042         break;
1043     }
1044     if (NULL == r) {
1045         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1046         return NULL;
1047     }
1048     if (r->h2state != H2_STATE_OPEN
1049         && r->h2state != H2_STATE_HALF_CLOSED_LOCAL) {
1050         h2_send_rst_stream(r, con, H2_E_STREAM_CLOSED);
1051         return NULL;
1052     }
1053     /* RFC 7540 is not explicit in restricting HEADERS (trailers) following
1054      * (optional) DATA frames, but in following HTTP/1.1, we limit to single
1055      * (optional) HEADERS (+ CONTINUATIONs) after (optional) DATA frame(s)
1056      * and require that the HEADERS frame set END_STREAM flag. */
1057     if (!(flags & H2_FLAG_END_STREAM)) {
1058         h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
1059         return NULL;
1060     }
1061 
1062     return h2_recv_end_data(r, con, 0) ? r : NULL;
1063 }
1064 
1065 
1066 static void
1067 h2_parse_headers_frame (request_st * const restrict r, const unsigned char *psrc, const uint32_t plen, const int trailers)
1068 {
1069     h2con * const h2c = r->con->h2;
1070     struct lshpack_dec * const restrict decoder = &h2c->decoder;
1071     const unsigned char * const endp = psrc + plen;
1072     http_header_parse_ctx hpctx;
1073     hpctx.hlen     = 0;
1074     hpctx.pseudo   = 1;
1075     hpctx.scheme   = 0;
1076     hpctx.trailers = trailers;
1077     hpctx.max_request_field_size = r->conf.max_request_field_size;
1078     hpctx.http_parseopts = r->conf.http_parseopts;
1079     const int log_request_header = r->conf.log_request_header;
1080     int rc = LSHPACK_OK;
1081     /*buffer_clear(&r->target);*//*(initial state)*/
1082 
1083     /*(h2_init_con() resized h2r->tmp_buf to 64k; shared with r->tmp_buf)*/
1084     buffer * const tb = r->tmp_buf;
1085     force_assert(tb->size >= 65536);/*(sanity check; remove in future)*/
1086     const lsxpack_strlen_t tbsz = (tb->size <= LSXPACK_MAX_STRLEN)
1087       ? tb->size
1088       : LSXPACK_MAX_STRLEN;
1089 
1090     /* note: #define LSHPACK_DEC_HTTP1X_OUTPUT 1 (default) configures
1091      * decoder to produce output in format: "field-name: value\r\n"
1092      * future: modify build system to define value to 0 in lshpack.h
1093      * against which lighttpd builds (or define value in build systems)
1094      * Then adjust code below to not use the HTTP/1.x compatibility,
1095      * as it is less efficient to copy into HTTP/1.1 request and reparse
1096      * than it is to directly parse each decoded header line. */
1097     lsxpack_header_t lsx;
1098     while (psrc < endp) {
1099         memset(&lsx, 0, sizeof(lsxpack_header_t));
1100         lsx.buf = tb->ptr;
1101         lsx.val_len = tbsz;
1102         rc = lshpack_dec_decode(decoder, &psrc, endp, &lsx);
1103         if (0 == lsx.name_len)
1104             rc = LSHPACK_ERR_BAD_DATA;
1105         if (rc == LSHPACK_OK) {
1106             hpctx.k = lsx.buf+lsx.name_offset;
1107             hpctx.v = lsx.buf+lsx.val_offset;
1108             hpctx.klen = lsx.name_len;
1109             hpctx.vlen = lsx.val_len;
1110             /*assert(lsx.hpack_index < sizeof(lshpack_idx_http_header));*/
1111             hpctx.id = lshpack_idx_http_header[lsx.hpack_index];
1112 
1113             if (log_request_header)
1114                 log_error(r->conf.errh, __FILE__, __LINE__,
1115                   "fd:%d id:%u rqst: %.*s: %.*s", r->con->fd, r->h2id,
1116                   (int)hpctx.klen, hpctx.k, (int)hpctx.vlen, hpctx.v);
1117 
1118           #if 0
1119             /* might not be worth special-casing pseudo headers here and
1120              * repeating the code in http_request_parse_header() to avoid
1121              * memcmp() for pseudo headers (request.c does not know ls-hpack)*/
1122             if (hpctx.pseudo && lsx.hpack_index
1123                 && lsx.hpack_index < LSHPACK_HDR_STATUS_200 && !trailers) {
1124                 /* lsx.hpack_index:
1125                  *   LSHPACK_HDR_AUTHORITY
1126                  *   LSHPACK_HDR_METHOD_GET
1127                  *   LSHPACK_HDR_METHOD_POST
1128                  *   LSHPACK_HDR_PATH
1129                  *   LSHPACK_HDR_PATH_INDEX_HTML
1130                  *   LSHPACK_HDR_SCHEME_HTTP
1131                  *   LSHPACK_HDR_SCHEME_HTTPS
1132                  */
1133             }
1134           #endif
1135 
1136             r->http_status = http_request_parse_header(r, &hpctx);
1137             if (0 != r->http_status)
1138                 break;
1139         }
1140       #if 0 /*(see catch-all below)*/
1141         /* Send GOAWAY (further below) (decoder state not maintained on error)
1142          * (see comments above why decoder state must be maintained) */
1143         /* XXX: future: could try to send :status 431 here
1144          * and reset other active streams in H2_STATE_OPEN */
1145         else if (rc == LSHPACK_ERR_MORE_BUF) {
1146             /* XXX: TODO if (r->conf.log_request_header_on_error) */
1147             r->http_status = 431; /* Request Header Fields Too Large */
1148             /*(try to avoid reading/buffering more data for this request)*/
1149             r->h2_rwin = 0; /*(out-of-sync with peer, but is error case)*/
1150             /*r->h2state = H2_STATE_HALF_CLOSED_REMOTE*/
1151             /* psrc was not advanced if LSHPACK_ERR_MORE_BUF;
1152              * processing must stop (since not retrying w/ larger buf)*/
1153             break;
1154         }
1155       #endif
1156         else { /* LSHPACK_ERR_BAD_DATA */
1157             /* GOAWAY with H2_E_PROTOCOL_ERROR is not specific enough
1158              * to tell peer to not retry request, so send RST_STREAM
1159              * (slightly more specific, but not by much) before GOAWAY*/
1160             /* LSHPACK_ERR_MORE_BUF is treated as an attack, send GOAWAY
1161              * (h2r->tmp_buf was resized to 64k in h2_init_con()) */
1162             request_h2error_t err = H2_E_COMPRESSION_ERROR;
1163             if (rc != LSHPACK_ERR_BAD_DATA) {
1164                 /* LSHPACK_ERR_TOO_LARGE, LSHPACK_ERR_MORE_BUF */
1165                 err = H2_E_PROTOCOL_ERROR;
1166                 h2_send_rst_stream(r, r->con, err);
1167             }
1168             if (!h2c->sent_goaway && !trailers)
1169                 h2c->h2_cid = r->h2id;
1170             h2_send_goaway_e(r->con, err);
1171             if (!trailers) {
1172                 h2_retire_stream(r, r->con);
1173                 return;
1174             }
1175             else {
1176                 r->state = CON_STATE_ERROR;
1177                 r->h2state = H2_STATE_CLOSED;
1178             }
1179             break;
1180         }
1181     }
1182 
1183     hpctx.hlen += 2;
1184     r->rqst_header_len += hpctx.hlen;
1185     /*(accounting for mod_accesslog and mod_rrdtool)*/
1186     chunkqueue * const rq = &r->read_queue;
1187     rq->bytes_in  += (off_t)hpctx.hlen;
1188     rq->bytes_out += (off_t)hpctx.hlen;
1189 
1190     if (0 == r->http_status && LSHPACK_OK == rc) {
1191         if (hpctx.pseudo)
1192             r->http_status =
1193               http_request_validate_pseudohdrs(r, hpctx.scheme,
1194                                                hpctx.http_parseopts);
1195         if (0 == r->http_status)
1196             http_request_headers_process_h2(r, r->con->proto_default_port);
1197     }
1198 }
1199 
1200 
1201 static int
1202 h2_recv_headers (connection * const con, uint8_t * const s, uint32_t flen)
1203 {
1204   #ifdef __COVERITY__
1205     /* Coverity does not notice that values used in s are checked.
1206      * Although silencing here, would prefer not to do so since doing so
1207      * disables Coverity from reporting questionable modifications which
1208      * might be made to the code in the future. */
1209     __coverity_tainted_data_sink__(s);
1210   #endif
1211     request_st *r = NULL;
1212     h2con * const h2c = con->h2;
1213     const uint32_t id =
1214       ((s[5] << 24) | (s[6] << 16) | (s[7] << 8) | s[8]) & ~0x80000000u;
1215     if (0 == id) { /* HEADERS, PUSH_PROMISE stream id must != 0 */
1216         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1217         return 0;
1218     }
1219     if (!(id & 1)) { /* stream id from client must be odd */
1220         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1221         return 0;
1222     }
1223 
1224     request_st * const h2r = &con->request;
1225     int trailers = 0;
1226 
1227     if (id > h2c->h2_cid) {
1228         if (h2c->rused == sizeof(h2c->r)/sizeof(*h2c->r)) {
1229             if (0 == h2c->sent_settings) { /*(see h2_recv_settings() comments)*/
1230                 /* too many active streams; refuse new stream */
1231                 h2c->h2_cid = id;
1232                 h2_send_rst_stream_id(id, con, H2_E_REFUSED_STREAM);
1233                 return 1;
1234             }
1235             else {
1236                 /* alternative: stop processing frames and defer processing this
1237                  * HEADERS frame until num active streams drops below limit.
1238                  * lighttpd sends SETTINGS_MAX_CONCURRENT_STREAMS <limit> with
1239                  * server Connection Preface, so a well-behaved client will
1240                  * adjust after it sends its initial requests.
1241                  * (e.g. h2load -n 100 -m 100 sends 100 requests upon connect)*/
1242                 return -1;
1243             }
1244         }
1245         /* Note: MUST process HPACK decode even if already sent GOAWAY.
1246          * This is necessary since there may be active streams not in
1247          * H2_STATE_HALF_CLOSED_REMOTE, e.g. H2_STATE_OPEN, still possibly
1248          * receiving DATA and, more relevantly, still might receive HEADERS
1249          * frame with trailers, for which the decoder state is required.
1250          * XXX: future might try to reduce other processing done if sent
1251          *      GOAWAY, e.g. might avoid allocating (request_st *r) */
1252         r = h2_init_stream(h2r, con);
1253         r->h2id = id;
1254         r->h2state = (s[4] & H2_FLAG_END_STREAM)
1255           ? H2_STATE_HALF_CLOSED_REMOTE
1256           : H2_STATE_OPEN;
1257         r->state = CON_STATE_REQUEST_END;
1258         /* Note: timestamps here are updated only after receipt of entire header
1259          * (HEADERS frame might have been sent in multiple packets
1260          *  and CONTINUATION frames may have been sent in multiple packets)
1261          * (affects high precision timestamp, if enabled)
1262          * (large sets of headers are not typical, and even when they do
1263          *  occur, they will typically be sent within the same second)
1264          * (future: might keep high precision timestamp in h2con when first
1265          *  packet of HEADERS or PUSH_PROMISE is received, and clear that
1266          *  timestamp when frame + CONTINUATION(s) are complete (so that
1267          *  re-read of initial frame does not overwrite the timestamp))
1268          */
1269         r->start_hp.tv_sec = log_epoch_secs;
1270         if (r->conf.high_precision_timestamps)
1271             log_clock_gettime_realtime(&r->start_hp);
1272     }
1273     else {
1274         r = h2_recv_trailers_r(con, h2c, id, s[4]); /* (cold code path) */
1275         if (NULL == r)
1276             return (h2c->sent_goaway > 0) ? 0 : 1;
1277         trailers = 1;
1278     }
1279 
1280     const unsigned char *psrc = s + 9;
1281     uint32_t alen = flen;
1282     if (s[4] & H2_FLAG_PADDED) {
1283         ++psrc;
1284         const uint32_t pad = s[9];
1285         if (flen < 1 + pad + ((s[4] & H2_FLAG_PRIORITY) ? 5 : 0)) {
1286             /* Padding that exceeds the size remaining for the header block
1287              * fragment MUST be treated as a PROTOCOL_ERROR. */
1288             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1289             if (!trailers)
1290                 h2_retire_stream(r, con);
1291             else {
1292                 r->state = CON_STATE_ERROR;
1293                 r->h2state = H2_STATE_CLOSED;
1294             }
1295             return 0;
1296         }
1297         alen -= (1 + pad); /*(alen is adjusted for PRIORITY below)*/
1298     }
1299     if (s[4] & H2_FLAG_PRIORITY) {
1300         /* XXX: TODO: handle PRIORITY (prio fields start at *psrc) */
1301         const uint32_t prio =
1302           ((psrc[0]<<24)|(psrc[1]<<16)|(psrc[2]<<8)|psrc[3]) & ~0x80000000u;
1303         if (prio == id) {
1304             h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
1305             if (!trailers)
1306                 h2_retire_stream(r, con);
1307             return 1;
1308         }
1309       #if 0
1310         uint32_t exclusive_dependency = (psrc[0] & 0x80) ? 1 : 0;
1311         uint32_t weight = psrc[4];
1312       #endif
1313         psrc += 5;
1314         alen -= 5;
1315     }
1316 
1317     h2_parse_headers_frame(r, psrc, alen, trailers);
1318 
1319   #if 0 /*(handled in h2_parse_frames() as a connection error)*/
1320     /* not handled here:
1321      * r is invalid if h2_parse_headers_frame() HPACK decode error */
1322     if (s[3] == H2_FTYPE_PUSH_PROMISE && !trailers) {
1323         /* Had to process HPACK to keep HPACK tables sync'd with peer but now
1324          * discard the request if PUSH_PROMISE, since not expected, as this code
1325          * is running as a server, not as a client.
1326          * XXX: future might try to reduce other processing done if
1327          * discarding, e.g. might avoid allocating (request_st *r) */
1328         /* rant: PUSH_PROMISE could have been a flag on HEADERS frame
1329          *       instead of an independent frame type */
1330         r->http_status = 0;
1331         h2_retire_stream(r, con);
1332     }
1333   #endif
1334 
1335     if (!h2c->sent_goaway) {
1336         h2c->h2_cid = id;
1337         if (!light_btst(r->rqst_htags, HTTP_HEADER_CONTENT_LENGTH))
1338             r->reqbody_length = (s[4] & H2_FLAG_END_STREAM) ? 0 : -1;
1339       #if 0
1340         else if (r->reqbody_length > 0 && (s[4] & H2_FLAG_END_STREAM)) {
1341             /*(handled in connection_handle_read_post_state())*/
1342             /* XXX: TODO if (r->conf.log_request_header_on_error) */
1343             r->http_status = 400; /* Bad Request */
1344         }
1345       #endif
1346 
1347         /* RFC 7540 Section 8. HTTP Message Exchanges
1348          * 8.1.2.6. Malformed Requests and Responses
1349          *   For malformed requests, a server MAY send an HTTP
1350          *   response prior to closing or resetting the stream.
1351          * However, h2spec expects stream PROTOCOL_ERROR.
1352          * (This is unfortunate, since we would rather send
1353          *  400 Bad Request which tells client *do not* retry
1354          *  the bad request without modification)
1355          * https://github.com/summerwind/h2spec/issues/120
1356          * https://github.com/summerwind/h2spec/issues/121
1357          * https://github.com/summerwind/h2spec/issues/122
1358          */
1359       #if 0
1360         if (400 == r->http_status && !trailers) {
1361             h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
1362             h2_retire_stream(r, con);
1363         }
1364       #endif
1365     }
1366     else if (h2c->h2_cid < id) {
1367         /* Had to process HPACK to keep HPACK tables sync'd with peer
1368          * but now discard the request if id is after id sent in GOAWAY.
1369          * XXX: future might try to reduce other processing done if
1370          * discarding, e.g. might avoid allocating (request_st *r) */
1371         r->http_status = 0;
1372         h2_retire_stream(r, con);
1373     }
1374 
1375     return 1;
1376 }
1377 
1378 
1379 int
1380 h2_parse_frames (connection * const con)
1381 {
1382     /* read and process HTTP/2 frames from socket */
1383     h2con * const h2c = con->h2;
1384     chunkqueue * const cq = con->read_queue;
1385     /* initial max frame size is the minimum: 16k
1386      * (lighttpd does not currently increase max frame size)
1387      * (lighttpd does not currently decrease max frame size)
1388      * (XXX: If SETTINGS_MAX_FRAME_SIZE were increased and then decreased,
1389      *       should accept the larger frame size until SETTINGS is ACK'd) */
1390     const uint32_t fsize = h2c->s_max_frame_size;
1391     for (off_t cqlen = chunkqueue_length(cq); cqlen >= 9; ) {
1392         chunk *c = cq->first;
1393         /*assert(c->type == MEM_CHUNK);*/
1394         /* copy data if frame header crosses chunk boundary
1395          * future: be more efficient than blind full chunk copy */
1396         uint32_t clen = buffer_string_length(c->mem) - c->offset;
1397         if (clen < 9) {
1398             clen = h2_frame_cq_compact(cq, 9);
1399             c = cq->first; /*(reload after h2_frame_cq_compact())*/
1400         }
1401         uint8_t *s = (uint8_t *)(c->mem->ptr + c->offset);
1402         uint32_t flen = (s[0] << 16) | (s[1] << 8) | s[2];
1403         if (flen > fsize) {
1404             h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
1405             return 0;
1406         }
1407 
1408         /*(handle PUSH_PROMISE as connection error further below)*/
1409         /*if (s[3] == H2_FTYPE_HEADERS || s[3] == H2_FTYPE_PUSH_PROMISE)*/
1410 
1411         if (s[3] == H2_FTYPE_HEADERS) {
1412             if (cqlen < 9+flen) return 1; /* incomplete frame; go on */
1413             if (clen < 9+flen) {
1414                 clen = h2_frame_cq_compact(cq, 9+flen);
1415                 c = cq->first; /*(reload after h2_frame_cq_compact())*/
1416                 s = (uint8_t *)(c->mem->ptr + c->offset);
1417             }
1418 
1419             if (!(s[4] & H2_FLAG_END_HEADERS)) {
1420                 /* collect CONTINUATION frames (cold code path) */
1421                 /* note: h2_recv_continuation() return value is overloaded
1422                  * and the resulting clen is 9+flen of *concatenated* frames */
1423                 clen = h2_recv_continuation(9+flen, clen, cqlen, cq, con);
1424                 if (0 == clen)    return 0;
1425                 if (cqlen < clen) return 1; /* incomplete frames; go on */
1426                 c = cq->first; /*(reload after h2_recv_continuation())*/
1427                 s = (uint8_t *)(c->mem->ptr + c->offset);
1428                 /* frame size was also updated and might (legitimately)
1429                  * exceed SETTINGS_MAX_FRAME_SIZE, so do not test fsize again */
1430                 flen = (s[0]<<16)|(s[1]<<8)|s[2];
1431                 /* recalculate after CONTINUATION removed */
1432                 cqlen = chunkqueue_length(cq);
1433             }
1434 
1435           #ifdef __COVERITY__
1436             /* Coverity does not notice that values used in s are checked.
1437              * Although silencing here, would prefer not to do so since doing so
1438              * disables Coverity from reporting questionable modifications which
1439              * might be made to the code in the future. */
1440             __coverity_tainted_data_sink__(s);
1441           #endif
1442 
1443             int rc = h2_recv_headers(con, s, flen);
1444             cqlen -= (9+flen);
1445             if (rc >= 0)
1446                 chunkqueue_mark_written(cq, 9+flen);
1447             if (rc <= 0)
1448                 return 0;
1449             con->read_idle_ts = log_epoch_secs;
1450         }
1451         else if (s[3] == H2_FTYPE_DATA) {
1452             /* future: might try to stream data for incomplete frames,
1453              * but that would require keeping additional state for partially
1454              * read frames, including cleaning up if errors occur.
1455              * Since well-behaved clients do not intentionally send partial
1456              * frames, and try to resend if socket buffers are full, this is
1457              * probably not a big concern in practice. */
1458             if (cqlen < 9+flen) return 1; /* incomplete frame; go on */
1459             con->read_idle_ts = log_epoch_secs;
1460             /*(h2_recv_data() must consume frame from cq or else return 0)*/
1461             if (!h2_recv_data(con, s, flen))
1462                 return 0;
1463             cqlen -= (9+flen);
1464         }
1465         else {
1466             /* frame types below are expected to be small
1467              * most frame types below have fixed (small) size
1468              *   4 bytes - WINDOW_UPDATE
1469              *   5 bytes - PRIORITY
1470              *   8 bytes - PING
1471              *   4 bytes - RST_STREAM
1472              * some are variable size
1473              *     SETTINGS (6 * #settings; 6 defined in RFC 7540 Section 6.5)
1474              *     GOAWAY   (8 + optional additional debug data (variable))
1475              * XXX: might add sanity check for a max flen here,
1476              *      before waiting to read partial frame
1477              *      (fsize limit is still enforced above for all frames)
1478              */
1479             if (cqlen < 9+flen) return 1; /* incomplete frame; go on */
1480             if (clen < 9+flen) {
1481                 clen = h2_frame_cq_compact(cq, 9+flen);
1482                 c = cq->first; /*(reload after h2_frame_cq_compact())*/
1483                 s = (uint8_t *)(c->mem->ptr + c->offset);
1484             }
1485             switch (s[3]) { /* frame type */
1486               case H2_FTYPE_WINDOW_UPDATE:
1487                 h2_recv_window_update(con, s, flen);
1488                 break;
1489               case H2_FTYPE_PRIORITY:
1490                 h2_recv_priority(con, s, flen);
1491                 break;
1492               case H2_FTYPE_SETTINGS:
1493                 h2_recv_settings(con, s, flen);
1494                 break;
1495               case H2_FTYPE_PING:
1496                 h2_recv_ping(con, s, flen);
1497                 break;
1498               case H2_FTYPE_RST_STREAM:
1499                 h2_recv_rst_stream(con, s, flen);
1500                 break;
1501               case H2_FTYPE_GOAWAY:
1502                 if (!h2_recv_goaway(con, s, flen)) return 0;
1503                 break;
1504               case H2_FTYPE_PUSH_PROMISE: /*not expected from client*/
1505               case H2_FTYPE_CONTINUATION: /*handled with HEADERS*/
1506                 h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1507                 return 0;
1508               default: /* ignore unknown frame types */
1509                 break;
1510             }
1511             cqlen -= (9+flen);
1512             chunkqueue_mark_written(cq, 9+flen);
1513         }
1514 
1515         if (h2c->sent_goaway > 0) return 0;
1516     }
1517 
1518     return 1;
1519 }
1520 
1521 
1522 int
1523 h2_want_read (connection * const con)
1524 {
1525     chunkqueue * const cq = con->read_queue;
1526     if (chunkqueue_is_empty(cq)) return 1;
1527 
1528     /* check for partial frame */
1529     const off_t cqlen = chunkqueue_length(cq);
1530     if (cqlen < 9) return 1;
1531     chunk *c = cq->first;
1532     uint32_t clen = buffer_string_length(c->mem) - c->offset;
1533     if (clen < 9) {
1534         clen = h2_frame_cq_compact(cq, 9);
1535         c = cq->first; /*(reload after h2_frame_cq_compact())*/
1536     }
1537     uint8_t *s = (uint8_t *)(c->mem->ptr + c->offset);
1538     uint32_t flen = (s[0] << 16) | (s[1] << 8) | s[2];
1539     if (clen < 9+flen) return 1;
1540 
1541     /* check if not HEADERS, or if HEADERS has END_HEADERS flag */
1542     if (s[3] != H2_FTYPE_HEADERS || (s[4] & H2_FLAG_END_HEADERS))
1543         return 0;
1544 
1545     /* check for partial CONTINUATION frames */
1546     for (uint32_t n = 9+flen; cqlen >= n+9; n += 9+flen) {
1547         if (clen < n+9) {
1548             clen = h2_frame_cq_compact(cq, n+9);
1549             c = cq->first; /*(reload after h2_frame_cq_compact())*/
1550             s = (uint8_t *)(c->mem->ptr + c->offset);
1551         }
1552         flen = (s[n+0] << 16) | (s[n+1] << 8) | s[n+2];
1553         if (cqlen < n+9+flen) return 1; /* incomplete frame; go on */
1554         if (s[4] & H2_FLAG_END_HEADERS) return 0;
1555     }
1556 
1557     return 1;
1558 }
1559 
1560 
1561 static int
1562 h2_recv_client_connection_preface (connection * const con)
1563 {
1564     /* check if the client Connection Preface (24 bytes) has been received
1565      * (initial SETTINGS frame should immediately follow, but is not checked) */
1566     chunkqueue * const cq = con->read_queue;
1567     if (chunkqueue_length(cq) < 24) {
1568         chunk * const c = cq->first;
1569         if (c && buffer_string_length(c->mem) - c->offset >= 4) {
1570             const char * const s = c->mem->ptr + c->offset;
1571             if (s[0]!='P'||s[1]!='R'||s[2]!='I'||s[3]!=' ') {
1572                 h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1573                 return 1; /* error; done receiving connection preface */
1574             }
1575         }
1576         return 0; /*(not ready yet)*/
1577     }
1578 
1579     static const char h2preface[] = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
1580     chunk *c = cq->first;
1581     const uint32_t clen = buffer_string_length(c->mem) - c->offset;
1582     if (clen < 24) h2_frame_cq_compact(cq, 24);
1583     c = cq->first; /*(reload after h2_frame_cq_compact())*/
1584     const uint8_t * const s = (uint8_t *)(c->mem->ptr + c->offset);
1585     if (0 == memcmp(s, h2preface, 24)) /* sizeof(h2preface)-1) */
1586         chunkqueue_mark_written(cq, 24);
1587     else
1588         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1589     return 1; /* done receiving connection preface (even if error occurred) */
1590 }
1591 
1592 
1593 __attribute_cold__
1594 static int
1595 h2_read_client_connection_preface (struct connection * const con, chunkqueue * const cq, off_t max_bytes)
1596 {
1597     /* temporary con->network_read() filter until connection preface received */
1598 
1599     /*(alternatively, func ptr could be saved in an element in (h2con *))*/
1600     void ** const hctx = con->plugin_ctx+0; /*(0 idx used for h2)*/
1601     int(* const network_read)(struct connection *, chunkqueue *, off_t) =
1602       (int(*)(struct connection *, chunkqueue *, off_t))(uintptr_t)(*hctx);
1603     if (max_bytes < 24) max_bytes = 24; /*(should not happen)*/
1604     int rc = (network_read)(con, cq, max_bytes);
1605     if (NULL == con->h2) return rc; /*(unexpected; already cleaned up)*/
1606     if (-1 != rc && h2_recv_client_connection_preface(con)) {
1607         con->network_read = network_read;
1608         *hctx = NULL;
1609         /*(intentionally update timestamp only after reading preface complete)*/
1610         con->read_idle_ts = log_epoch_secs;
1611     }
1612     return rc;
1613 }
1614 
1615 
1616 void
1617 h2_init_con (request_st * const restrict h2r, connection * const restrict con, const buffer * const restrict http2_settings)
1618 {
1619     h2con * const h2c = calloc(1, sizeof(h2con));
1620     force_assert(h2c);
1621     con->h2 = h2c;
1622     con->read_idle_ts = log_epoch_secs;
1623     con->keep_alive_idle = h2r->conf.max_keep_alive_idle;
1624 
1625     h2r->h2_rwin = 65535;                 /* h2 connection recv window */
1626     h2r->h2_swin = 65535;                 /* h2 connection send window */
1627     /* settings sent from peer */         /* initial values */
1628     h2c->s_header_table_size     = 4096;  /* SETTINGS_HEADER_TABLE_SIZE      */
1629     h2c->s_enable_push           = 1;     /* SETTINGS_ENABLE_PUSH            */
1630     h2c->s_max_concurrent_streams= ~0u;   /* SETTINGS_MAX_CONCURRENT_STREAMS */
1631     h2c->s_initial_window_size   = 65535; /* SETTINGS_INITIAL_WINDOW_SIZE    */
1632     h2c->s_max_frame_size        = 16384; /* SETTINGS_MAX_FRAME_SIZE         */
1633     h2c->s_max_header_list_size  = ~0u;   /* SETTINGS_MAX_HEADER_LIST_SIZE   */
1634     h2c->sent_settings           = log_epoch_secs; /*(send SETTINGS below)*/
1635 
1636     lshpack_dec_init(&h2c->decoder);
1637     lshpack_enc_init(&h2c->encoder);
1638     lshpack_enc_use_hist(&h2c->encoder, 1);
1639 
1640     if (http2_settings) /*(if Upgrade: h2c)*/
1641         h2_parse_frame_settings(con, (uint8_t *)CONST_BUF_LEN(http2_settings));
1642 
1643     static const uint8_t h2settings[] = { /*(big-endian numbers)*/
1644       /* SETTINGS */
1645       0x00, 0x00, 0x0c        /* frame length */ /* 6 * 2 for two settings */
1646      ,H2_FTYPE_SETTINGS       /* frame type */
1647      ,0x00                    /* frame flags */
1648      ,0x00, 0x00, 0x00, 0x00  /* stream identifier */
1649      ,0x00, H2_SETTINGS_MAX_CONCURRENT_STREAMS
1650      ,0x00, 0x00, 0x00, 0x08  /* 8 */
1651      #if 0  /* ? explicitly disable dynamic table ? (and adjust frame length) */
1652             /* If this is sent, must wait until peer sends SETTINGS with ACK
1653              * before disabling dynamic table in HPACK decoder */
1654             /*(before calling lshpack_dec_set_max_capacity(&h2c->decoder, 0))*/
1655      ,0x00, H2_SETTINGS_HEADER_TABLE_SIZE
1656      ,0x00, 0x00, 0x00, 0x00  /* 0 */
1657      #endif
1658      #if 0  /* ? explicitly disable push ?       (and adjust frame length) */
1659      ,0x00, H2_SETTINGS_ENABLE_PUSH
1660      ,0x00, 0x00, 0x00, 0x00  /* 0 */
1661      #endif
1662      #if 0  /* ? increase from default (65535) ? (and adjust frame length) */
1663      ,0x00, H2_SETTINGS_INITIAL_WINDOW_SIZE
1664      ,0x00, 0x02, 0x00, 0x00  /* 131072 */
1665      #endif
1666      #if 0  /* ? increase from default (16384) ? (and adjust frame length) */
1667      ,0x00, H2_SETTINGS_MAX_FRAME_SIZE
1668      ,0x00, 0x00, 0x80, 0x00  /* 32768 */
1669      #endif
1670      ,0x00, H2_SETTINGS_MAX_HEADER_LIST_SIZE
1671      ,0x00, 0x00, 0xFF, 0xFF  /* 65535 */
1672 
1673      #if 0
1674       /* WINDOW_UPDATE */
1675      ,0x00, 0x00, 0x04        /* frame length */
1676      ,H2_FTYPE_WINDOW_UPDATE  /* frame type */
1677      ,0x00                    /* frame flags */
1678      ,0x00, 0x00, 0x00, 0x00  /* stream identifier */
1679      ,0x00, 0x01, 0x00, 0x01  /* 65537 */ /* increase connection rwin to 128k */
1680      #endif
1681     };
1682 
1683     /*h2r->h2_rwin += 65537;*//*(enable if WINDOWS_UPDATE is sent above)*/
1684     chunkqueue_append_mem(con->write_queue,
1685                           (const char *)h2settings, sizeof(h2settings));
1686 
1687     if (!h2_recv_client_connection_preface(con)) {
1688         /*(alternatively, func ptr could be saved in an element in (h2con *))*/
1689         con->plugin_ctx[0] = (void *)(uintptr_t)con->network_read;
1690         con->network_read = h2_read_client_connection_preface;
1691         /* note: no steps taken to reset con->network_read() on error
1692          * as con->network_read() is always set in connection_accepted() */
1693     }
1694 
1695     buffer_string_prepare_copy(h2r->tmp_buf, 65535);
1696 }
1697 
1698 
1699 static void
1700 h2_send_hpack (request_st * const r, connection * const con, const char *data, uint32_t dlen, const uint32_t flags)
1701 {
1702     union {
1703       uint8_t c[12];
1704       uint32_t u[3];          /*(alignment)*/
1705     } headers = { {           /*(big-endian numbers)*/
1706       0x00, 0x00, 0x00        /* padding for alignment; do not send */
1707       /* HEADERS */
1708      ,0x00, 0x00, 0x00        /* frame length      (fill in below) */
1709      ,H2_FTYPE_HEADERS        /* frame type */
1710      ,(uint8_t)flags          /* frame flags (e.g. END_STREAM for trailers) */
1711      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
1712     } };
1713 
1714     headers.u[2] = htonl(r->h2id);
1715 
1716     /* similar to h2_send_data(), but unlike DATA frames there is a HEADERS
1717      * frame potentially followed by CONTINUATION frame(s) here, and the final
1718      * HEADERS or CONTINUATION frame here has END_HEADERS flag set.
1719      * For trailers, END_STREAM flag is set on HEADERS frame. */
1720 
1721     /*(approximate space needed for frames (header + payload)
1722      * with slight over-estimate of 16 bytes per frame header (> 9)
1723      * and minimum SETTING_MAX_FRAME_SIZE of 16k (could be larger)
1724      * (dlen >> 14)+1 is num 16k frames needed, multipled by 16 bytes
1725      *  per frame can be appoximated with (dlen>>10) + 9)*/
1726     buffer * const b =
1727       chunkqueue_append_buffer_open_sz(con->write_queue, dlen + (dlen>>10) + 9);
1728     char * restrict ptr = b->ptr;
1729     h2con * const h2c = con->h2;
1730     const uint32_t fsize = h2c->s_max_frame_size;
1731     do {
1732         const uint32_t len = dlen < fsize ? dlen : fsize;
1733         headers.c[3] = (len >> 16) & 0xFF; /*(off +3 to skip over align pad)*/
1734         headers.c[4] = (len >>  8) & 0xFF;
1735         headers.c[5] = (len      ) & 0xFF;
1736         if (len == dlen)
1737             headers.c[7] |= H2_FLAG_END_HEADERS;
1738       #if 0
1739         chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
1740                               (const char *)headers.c+3, sizeof(headers)-3);
1741         chunkqueue_append_mem(con->write_queue, data, len);
1742       #else
1743         memcpy(ptr, headers.c+3, sizeof(headers)-3);
1744         memcpy(ptr+sizeof(headers)-3, data, len);
1745         ptr  += len + sizeof(headers)-3;
1746       #endif
1747         data += len;
1748         dlen -= len;
1749         /*(include H2_FLAG_END_STREAM in HEADERS frame, not CONTINUATION)*/
1750         headers.c[6] = H2_FTYPE_CONTINUATION; /*(if additional frames needed)*/
1751         headers.c[7] = 0x00; /*(off +3 to skip over align pad)*/
1752     } while (dlen);
1753     buffer_string_set_length(b, (uint32_t)(ptr - b->ptr));
1754     chunkqueue_append_buffer_commit(con->write_queue);
1755 }
1756 
1757 
1758 __attribute_cold__
1759 static void
1760 h2_log_response_header_lsx(request_st * const r, const lsxpack_header_t * const lsx)
1761 {
1762     log_error(r->conf.errh, __FILE__, __LINE__,
1763       "fd:%d id:%u resp: %.*s: %.*s", r->con->fd, r->h2id,
1764       (int)lsx->name_len, lsx->buf + lsx->name_offset,
1765       (int)lsx->val_len,  lsx->buf + lsx->val_offset);
1766 }
1767 
1768 
1769 __attribute_cold__
1770 static void
1771 h2_log_response_header(request_st * const r, const int len, const char * const hdr)
1772 {
1773     log_error(r->conf.errh, __FILE__, __LINE__,
1774       "fd:%d id:%u resp: %.*s", r->con->fd, r->h2id, len, hdr);
1775 }
1776 
1777 
1778 void
1779 h2_send_headers (request_st * const r, connection * const con)
1780 {
1781     /*(set keep_alive_idle; out-of-place and non-event for most configs,
1782      * but small attempt to (maybe) preserve behavior for specific configs)*/
1783     con->keep_alive_idle = r->conf.max_keep_alive_idle;
1784 
1785     /* specialized version of http_response_write_header(); send headers
1786      * directly to HPACK encoder, rather than double-buffering in chunkqueue */
1787 
1788     if (304 == r->http_status
1789         && light_btst(r->resp_htags, HTTP_HEADER_CONTENT_ENCODING))
1790         http_header_response_unset(r, HTTP_HEADER_CONTENT_ENCODING,
1791                                    CONST_STR_LEN("Content-Encoding"));
1792 
1793     /*(h2_init_con() resized h2r->tmp_buf to 64k; shared with r->tmp_buf)*/
1794     buffer * const tb = r->tmp_buf;
1795     force_assert(tb->size >= 65536);/*(sanity check; remove in future)*/
1796     unsigned char *dst = (unsigned char *)tb->ptr;
1797     unsigned char * const dst_end = (unsigned char *)tb->ptr + tb->size;
1798 
1799     h2con * const h2c = con->h2;
1800     struct lshpack_enc * const encoder = &h2c->encoder;
1801     lsxpack_header_t lsx;
1802     uint32_t alen = 7+3+4; /* ":status: xxx\r\n" */
1803     const int log_response_header = r->conf.log_response_header;
1804     const int resp_header_repeated = r->resp_header_repeated;
1805 
1806     char status[12] = ":status: ";
1807     int x = r->http_status; /*(expect status < 1000; should be [100-599])*/
1808     status[11] = (x % 10) + '0';
1809     status[10] = (x / 10 % 10) + '0';
1810     status[9]  = (x / 100) + '0';
1811 
1812     if (log_response_header)
1813         h2_log_response_header(r, 12, status);
1814 
1815     memset(&lsx, 0, sizeof(lsxpack_header_t));
1816     lsx.buf = status;
1817     lsx.name_offset = 0;
1818     lsx.name_len = 7;
1819     lsx.val_offset = 9;
1820     lsx.val_len = 3;
1821     switch (r->http_status) {
1822       case 200: lsx.hpack_index = LSHPACK_HDR_STATUS_200; break;
1823       case 204: lsx.hpack_index = LSHPACK_HDR_STATUS_204; break;
1824       case 206: lsx.hpack_index = LSHPACK_HDR_STATUS_206; break;
1825       case 304: lsx.hpack_index = LSHPACK_HDR_STATUS_304; break;
1826       case 400: lsx.hpack_index = LSHPACK_HDR_STATUS_400; break;
1827       case 404: lsx.hpack_index = LSHPACK_HDR_STATUS_404; break;
1828       case 500: lsx.hpack_index = LSHPACK_HDR_STATUS_500; break;
1829       default:
1830         break;
1831     }
1832     dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1833     if (dst == (unsigned char *)tb->ptr) {
1834         h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1835         return;
1836     }
1837 
1838     /* add all headers */
1839     for (uint32_t i = 0, used = r->resp_headers.used; i < used; ++i) {
1840         data_string * const restrict ds =(data_string *)r->resp_headers.data[i];
1841         const uint32_t klen = buffer_string_length(&ds->key);
1842         const uint32_t vlen = buffer_string_length(&ds->value);
1843         const char * const restrict k = ds->key.ptr;
1844         if (0 == vlen || 0 == klen) continue;
1845         alen += klen + vlen + 4;
1846 
1847         if (alen > LSXPACK_MAX_STRLEN) {
1848             /* ls-hpack default limit (UINT16_MAX) is per-line, due to field
1849              * sizes of lsx.name_offset,lsx.name_len,lsx.val_offset,lsx.val_len
1850              * However, similar to elsewhere, limit total size of expanded
1851              * headers to (very generous) 64k - 1.  Peers might allow less. */
1852             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1853             return;
1854         }
1855 
1856         /* HTTP/2 requires lowercase keys
1857          * ls-hpack requires key and value be in same buffer
1858          * Since keys are typically short, append (and lowercase) key onto
1859          * end of value buffer */
1860         char * const v = buffer_string_prepare_append(&ds->value, klen);
1861         if (ds->ext != HTTP_HEADER_OTHER) {
1862             memcpy(v, http_header_lc[ds->ext], klen);
1863         }
1864         else {
1865             if ((k[0] & 0xdf) == 'X' && http_response_omit_header(r, ds)) {
1866                 alen -= klen + vlen + 4;
1867                 continue;
1868             }
1869             for (uint32_t j = 0; j < klen; ++j)
1870                 v[j] = !light_isupper(k[j]) ? k[j] : (k[j] | 0x20);
1871         }
1872         /*buffer_commit(&ds->value, klen);*//*(not necessary; truncated below)*/
1873 
1874         uint32_t voff = 0;
1875         const char *n;
1876         lsx.buf = ds->value.ptr;
1877         do {
1878             n = !resp_header_repeated
1879               ? NULL
1880               : memchr(lsx.buf+voff, '\n', vlen - voff);
1881 
1882             memset(&lsx, 0, sizeof(lsxpack_header_t));
1883             lsx.hpack_index = http_header_lshpack_idx[ds->ext];
1884             lsx.buf = ds->value.ptr;
1885             lsx.name_offset = vlen;
1886             lsx.name_len = klen;
1887             lsx.val_offset = voff;
1888             if (NULL == n)
1889                 lsx.val_len = vlen - voff;
1890             else {
1891                 /* multiple headers (same field-name) separated by "\r\n"
1892                  * and then "field-name: " (see http_header_response_insert())*/
1893                 voff = (uint32_t)(n + 1 - lsx.buf);
1894                 lsx.val_len = voff - 2 - lsx.val_offset; /*(-2 for "\r\n")*/
1895                 voff += klen + 2;
1896             }
1897 
1898             if (log_response_header)
1899                 h2_log_response_header_lsx(r, &lsx);
1900 
1901             unsigned char * const dst_in = dst;
1902             dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1903             if (dst == dst_in) {
1904                 buffer_string_set_length(&ds->value, vlen); /*(restore prior value)*/
1905                 h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1906                 return;
1907             }
1908         } while (n);
1909         buffer_string_set_length(&ds->value, vlen); /*(restore prior value)*/
1910     }
1911 
1912     if (!light_btst(r->resp_htags, HTTP_HEADER_DATE)) {
1913         /* HTTP/1.1 and later requires a Date: header */
1914         /* "date: " 6-chars + 30-chars for "%a, %d %b %Y %H:%M:%S GMT" + '\0' */
1915         static char tstr[36] = "date: ";
1916 
1917         memset(&lsx, 0, sizeof(lsxpack_header_t));
1918         lsx.buf = tstr;
1919         lsx.name_offset = 0;
1920         lsx.name_len = 4;
1921         lsx.val_offset = 6;
1922         lsx.val_len = 29;
1923         lsx.hpack_index = LSHPACK_HDR_DATE;
1924 
1925         /* cache the generated timestamp */
1926         static time_t tlast;
1927         const time_t cur_ts = log_epoch_secs;
1928         if (tlast != cur_ts) {
1929             tlast = cur_ts;
1930             strftime(tstr+6, sizeof(tstr)-6,
1931                      "%a, %d %b %Y %H:%M:%S GMT", gmtime(&tlast));
1932         }
1933 
1934         alen += 35+2;
1935 
1936         if (log_response_header)
1937             h2_log_response_header(r, 35, tstr);
1938 
1939         unsigned char * const dst_in = dst;
1940         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1941         if (dst == dst_in) {
1942             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1943             return;
1944         }
1945     }
1946 
1947     if (!light_btst(r->resp_htags, HTTP_HEADER_SERVER)
1948         && !buffer_string_is_empty(r->conf.server_tag)) {
1949         buffer * const b = chunk_buffer_acquire();
1950         const uint32_t vlen = buffer_string_length(r->conf.server_tag);
1951         buffer_copy_string_len(b, CONST_STR_LEN("server: "));
1952         buffer_append_string_len(b, CONST_BUF_LEN(r->conf.server_tag));
1953 
1954         alen += 6+vlen+4;
1955 
1956         if (log_response_header)
1957             h2_log_response_header(r, (int)6+vlen+2, b->ptr);
1958 
1959         memset(&lsx, 0, sizeof(lsxpack_header_t));
1960         lsx.buf = b->ptr;
1961         lsx.name_offset = 0;
1962         lsx.name_len = 6;
1963         lsx.val_offset = 8;
1964         lsx.val_len = vlen;
1965         lsx.hpack_index = LSHPACK_HDR_SERVER;
1966         unsigned char * const dst_in = dst;
1967         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1968         chunk_buffer_release(b);
1969         if (dst == dst_in) {
1970             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1971             return;
1972         }
1973     }
1974 
1975     alen += 2; /* "virtual" blank line ("\r\n") ending headers */
1976     r->resp_header_len = alen;
1977     /*(accounting for mod_accesslog and mod_rrdtool)*/
1978     chunkqueue * const wq = &r->write_queue;
1979     wq->bytes_in  += (off_t)alen;
1980     wq->bytes_out += (off_t)alen;
1981 
1982     const uint32_t dlen = (uint32_t)((char *)dst - tb->ptr);
1983     const uint32_t flags =
1984       (r->resp_body_finished && chunkqueue_is_empty(&r->write_queue))
1985         ? H2_FLAG_END_STREAM
1986         : 0;
1987     h2_send_hpack(r, con, tb->ptr, dlen, flags);
1988 }
1989 
1990 
1991 __attribute_cold__
1992 __attribute_noinline__
1993 static void
1994 h2_send_headers_block (request_st * const r, connection * const con, const char * const hdrs, const uint32_t hlen, uint32_t flags)
1995 {
1996     unsigned short hoff[8192]; /* max num header lines + 3; 16k on stack */
1997     hoff[0] = 1;                         /* number of lines */
1998     hoff[1] = 0;                         /* base offset for all lines */
1999     /*hoff[2] = ...;*/                   /* offset from base for 2nd line */
2000     uint32_t rc = http_header_parse_hoff(hdrs, hlen, hoff);
2001     if (0 == rc || rc > USHRT_MAX || hoff[0] >= sizeof(hoff)/sizeof(hoff[0])-1
2002         || 1 == hoff[0]) { /*(initial blank line (should not happen))*/
2003         /* error if headers incomplete or too many header fields */
2004         log_error(r->conf.errh, __FILE__, __LINE__,
2005                   "oversized response-header");
2006         hoff[0] = 1;
2007         hoff[1] = 0;
2008         http_header_parse_hoff(CONST_STR_LEN(":status: 500\r\n\r\n"), hoff);
2009     }
2010 
2011     /*(h2_init_con() resized h2r->tmp_buf to 64k; shared with r->tmp_buf)*/
2012     buffer * const tb = r->tmp_buf;
2013     force_assert(tb->size >= 65536);/*(sanity check; remove in future)*/
2014     unsigned char *dst = (unsigned char *)tb->ptr;
2015     unsigned char * const dst_end = (unsigned char *)tb->ptr + tb->size;
2016 
2017     h2con * const h2c = con->h2;
2018     struct lshpack_enc * const encoder = &h2c->encoder;
2019     lsxpack_header_t lsx;
2020 
2021     int i = 1;
2022     if (hdrs[0] == ':') {
2023         i = 2;
2024         /* expect first line to contain ":status: ..." if pseudo-header,
2025          * and expecting single pseudo-header for headers, zero for trailers */
2026         /*assert(0 == memcmp(hdrs, ":status: ", sizeof(":status: ")-1));*/
2027         memset(&lsx, 0, sizeof(lsxpack_header_t));
2028         *(const char **)&lsx.buf = hdrs;
2029         lsx.name_offset = 0;
2030         lsx.name_len = sizeof(":status")-1;
2031         lsx.val_offset = lsx.name_len + 2;
2032         lsx.val_len = 3;
2033         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
2034         if (dst == (unsigned char *)tb->ptr) {
2035             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2036             return;
2037         }
2038     }
2039 
2040     /*(note: not expecting any other pseudo-headers)*/
2041 
2042     /* note: expects field-names are lowercased (http_response_write_header())*/
2043 
2044     for (; i < hoff[0]; ++i) {
2045         const char *k = hdrs + ((i > 1) ? hoff[i] : 0);
2046         const char *end = hdrs + hoff[i+1];
2047         const char *v = memchr(k, ':', end-k);
2048         /* XXX: DOES NOT handle line wrapping (which is deprecated by RFCs)
2049          * (not expecting line wrapping; not produced internally by lighttpd,
2050          *  though possible from backends or with custom lua code)*/
2051         if (NULL == v || k == v) continue;
2052         uint32_t klen = v - k;
2053         if (0 == klen) continue;
2054         do { ++v; } while (*v == ' ' || *v == '\t'); /*(expect single ' ')*/
2055       #ifdef __COVERITY__
2056         /*(k has at least .:\n by now, so end[-2] valid)*/
2057         force_assert(end >= k + 2);
2058       #endif
2059         if (end[-2] != '\r') /*(header line must end "\r\n")*/
2060             continue;
2061         end -= 2;
2062         uint32_t vlen = end - v;
2063         if (0 == vlen) continue;
2064         memset(&lsx, 0, sizeof(lsxpack_header_t));
2065         *(const char **)&lsx.buf = hdrs;
2066         lsx.name_offset = k - hdrs;
2067         lsx.name_len = klen;
2068         lsx.val_offset = v - hdrs;
2069         lsx.val_len = vlen;
2070         unsigned char * const dst_in = dst;
2071         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
2072         if (dst == dst_in) {
2073             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2074             return;
2075         }
2076     }
2077     uint32_t dlen = (uint32_t)((char *)dst - tb->ptr);
2078     h2_send_hpack(r, con, tb->ptr, dlen, flags);
2079 }
2080 
2081 
2082 static void
2083 h2_send_1xx_block (request_st * const r, connection * const con, const char * const hdrs, const uint32_t hlen)
2084 {
2085     h2_send_headers_block(r, con, hdrs, hlen, 0);
2086 }
2087 
2088 
2089 int
2090 h2_send_1xx (request_st * const r, connection * const con)
2091 {
2092     buffer * const b = chunk_buffer_acquire();
2093 
2094     buffer_copy_string_len(b, CONST_STR_LEN(":status: "));
2095     buffer_append_int(b, r->http_status);
2096     for (uint32_t i = 0; i < r->resp_headers.used; ++i) {
2097         const data_string * const ds = (data_string *)r->resp_headers.data[i];
2098 
2099         if (buffer_string_is_empty(&ds->value)) continue;
2100         if (buffer_string_is_empty(&ds->key)) continue;
2101 
2102         buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
2103         buffer_append_string_buffer(b, &ds->key);
2104         buffer_append_string_len(b, CONST_STR_LEN(": "));
2105         buffer_append_string_buffer(b, &ds->value);
2106     }
2107     buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
2108 
2109     h2_send_1xx_block(r, con, CONST_BUF_LEN(b));
2110 
2111     chunk_buffer_release(b);
2112     return 1; /* for http_response_send_1xx_cb */
2113 }
2114 
2115 
2116 void
2117 h2_send_100_continue (request_st * const r, connection * const con)
2118 {
2119     /* 100 Continue is small and will always fit in SETTING_MAX_FRAME_SIZE;
2120      * i.e. there will not be any CONTINUATION frames here */
2121 
2122     /* XXX: need to update hpack dynamic table,
2123      * or else could hard-code header block fragment
2124      * { 0x48, 0x03, 0x31, 0x30, 0x30 }
2125      */
2126 
2127     /* short header block, so reuse shared code used for trailers
2128      * rather than adding something specific for ls-hpack here */
2129 
2130     h2_send_1xx_block(r, con, CONST_STR_LEN(":status: 100\r\n\r\n"));
2131 }
2132 
2133 
2134 static void
2135 h2_send_end_stream_data (request_st * const r, connection * const con);
2136 
2137 __attribute_cold__
2138 __attribute_noinline__
2139 static void
2140 h2_send_end_stream_trailers (request_st * const r, connection * const con, const buffer * const trailers)
2141 {
2142     /*(trailers are merged into response headers if trailers are received before
2143      * sending response headers to client.  However, if streaming response, then
2144      * trailers might need handling here)*/
2145 
2146     /* parse and lowercase field-names in trailers */
2147     unsigned short hoff[8192]; /* max num header lines + 3; 16k on stack */
2148     hoff[0] = 1;                         /* number of lines */
2149     hoff[1] = 0;                         /* base offset for all lines */
2150     /*hoff[2] = ...;*/                   /* offset from base for 2nd line */
2151     uint32_t rc = http_header_parse_hoff(CONST_BUF_LEN(trailers), hoff);
2152     if (0 == rc || rc > USHRT_MAX || hoff[0] >= sizeof(hoff)/sizeof(hoff[0])-1
2153         || 1 == hoff[0]) { /*(initial blank line (should not happen))*/
2154         /* skip trailers if incomplete, too many fields, or too long (> 64k-1)*/
2155         h2_send_end_stream_data(r, con);
2156         return;
2157     }
2158 
2159     char * const ptr = trailers->ptr;
2160     for (int i = 1; i < hoff[0]; ++i) {
2161         char *k = ptr + ((i > 1) ? hoff[i] : 0);
2162         if (*k == ':') {
2163             /*(pseudo-header should not appear in trailers)*/
2164             h2_send_end_stream_data(r, con);
2165             return;
2166         }
2167         const char * const colon = memchr(k, ':', ptr+hoff[i+1]-k);
2168         if (NULL == colon) continue;
2169         do {
2170             if (light_isupper(*k)) *k |= 0x20;
2171         } while (++k != colon);
2172     }
2173 
2174     h2_send_headers_block(r, con, CONST_BUF_LEN(trailers), H2_FLAG_END_STREAM);
2175 }
2176 
2177 
2178 #if 0 /*(replaced by h2_send_headers())*/
2179 void
2180 h2_send_cqheaders (request_st * const r, connection * const con)
2181 {
2182     /*(assumes HTTP/1.1 response headers have been prepended as first chunk)
2183      *(future: if r->write_queue is bypassed for headers, adjust
2184      * r->write_queue bytes counts (bytes_in, bytes_out) with header len)*/
2185     /* note: expects field-names are lowercased (http_response_write_header())*/
2186     chunk * const c = r->write_queue.first;
2187     const uint32_t len = buffer_string_length(c->mem) - (uint32_t)c->offset;
2188     uint32_t flags = (r->resp_body_finished && NULL == c->next)
2189       ? H2_FLAG_END_STREAM
2190       : 0;
2191     h2_send_headers_block(r, con, c->mem->ptr + c->offset, len, flags);
2192     chunkqueue_mark_written(&r->write_queue, len);
2193 }
2194 #endif
2195 
2196 
2197 #if 0
2198 
2199 void
2200 h2_send_data (request_st * const r, connection * const con, const char *data, uint32_t dlen)
2201 {
2202     /* Note: dlen should be <= MAX_WRITE_LIMIT in order to share resources */
2203 
2204     union {
2205       uint8_t c[12];
2206       uint32_t u[3];          /*(alignment)*/
2207     } dataframe = { {         /*(big-endian numbers)*/
2208       0x00, 0x00, 0x00        /* padding for alignment; do not send */
2209       /* DATA */
2210      ,0x00, 0x00, 0x00        /* frame length      (fill in below) */
2211      ,H2_FTYPE_DATA           /* frame type */
2212      ,0x00                    /* frame flags */
2213      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
2214     } };
2215 
2216     dataframe.u[2] = htonl(r->h2id);
2217 
2218     /* XXX: does not provide an optimization to send final set of data with
2219      *      END_STREAM flag; see h2_send_end_stream_data() to end stream */
2220 
2221     /* adjust stream and connection windows */
2222     /*assert(dlen <= INT32_MAX);*//* dlen should be <= MAX_WRITE_LIMIT */
2223     request_st * const h2r = &con->request;
2224     if (r->h2_swin   < 0) return;
2225     if (h2r->h2_swin < 0) return;
2226     if ((int32_t)dlen > r->h2_swin)   dlen = (uint32_t)r->h2_swin;
2227     if ((int32_t)dlen > h2r->h2_swin) dlen = (uint32_t)h2r->h2_swin;
2228     if (0 == dlen) return;
2229     r->h2_swin   -= (int32_t)dlen;
2230     h2r->h2_swin -= (int32_t)dlen;
2231 
2232     /* XXX: future: should have an interface which processes chunkqueue
2233      * and takes string refs to mmap FILE_CHUNK to avoid extra copying
2234      * since the result is likely to be consumed by TLS modules */
2235 
2236     /*(approximate space needed for frames (header + payload)
2237      * with slight over-estimate of 16 bytes per frame header (> 9)
2238      * and minimum SETTING_MAX_FRAME_SIZE of 16k (could be larger)
2239      * (dlen >> 14)+1 is num 16k frames needed, multipled by 16 bytes
2240      *  per frame can be appoximated with (dlen>>10) + 9)*/
2241     buffer * const b =
2242       chunkqueue_append_buffer_open_sz(con->write_queue, dlen + (dlen>>10) + 9);
2243     char * restrict ptr = b->ptr;
2244     h2con * const h2c = con->h2;
2245     const uint32_t fsize = h2c->s_max_frame_size;
2246     do {
2247         const uint32_t len = dlen < fsize ? dlen : fsize;
2248         dataframe.c[3] = (len >> 16) & 0xFF; /*(off +3 to skip over align pad)*/
2249         dataframe.c[4] = (len >>  8) & 0xFF;
2250         dataframe.c[5] = (len      ) & 0xFF;
2251       #if 0
2252         chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
2253                               (const char *)dataframe.c+3, sizeof(dataframe)-3);
2254         chunkqueue_append_mem(con->write_queue, data, len);
2255       #else
2256         memcpy(ptr, dataframe.c+3, sizeof(dataframe)-3);
2257         memcpy(ptr+sizeof(dataframe)-3, data, len);
2258         ptr  += len + sizeof(dataframe)-3;
2259       #endif
2260         data += len;
2261         dlen -= len;
2262     } while (dlen);
2263     buffer_string_set_length(b, (uint32_t)(ptr - b->ptr));
2264     chunkqueue_append_buffer_commit(con->write_queue);
2265 }
2266 
2267 #endif
2268 
2269 
2270 void
2271 h2_send_cqdata (request_st * const r, connection * const con, chunkqueue * const cq, uint32_t dlen)
2272 {
2273     /* Note: dlen should be <= MAX_WRITE_LIMIT in order to share resources */
2274 
2275     union {
2276       uint8_t c[12];
2277       uint32_t u[3];          /*(alignment)*/
2278     } dataframe = { {         /*(big-endian numbers)*/
2279       0x00, 0x00, 0x00        /* padding for alignment; do not send */
2280       /* DATA */
2281      ,0x00, 0x00, 0x00        /* frame length      (fill in below) */
2282      ,H2_FTYPE_DATA           /* frame type */
2283      ,0x00                    /* frame flags */
2284      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
2285     } };
2286 
2287     dataframe.u[2] = htonl(r->h2id);
2288 
2289     /* XXX: does not provide an optimization to send final set of data with
2290      *      END_STREAM flag; see h2_send_end_stream_data() to end stream */
2291 
2292     /* adjust stream and connection windows */
2293     /*assert(dlen <= INT32_MAX);*//* dlen should be <= MAX_WRITE_LIMIT */
2294     request_st * const h2r = &con->request;
2295     if (r->h2_swin   < 0) return;
2296     if (h2r->h2_swin < 0) return;
2297     if ((int32_t)dlen > r->h2_swin)   dlen = (uint32_t)r->h2_swin;
2298     if ((int32_t)dlen > h2r->h2_swin) dlen = (uint32_t)h2r->h2_swin;
2299     if (0 == dlen) return;
2300     r->h2_swin   -= (int32_t)dlen;
2301     h2r->h2_swin -= (int32_t)dlen;
2302 
2303     /* XXX: future: should have an interface which processes chunkqueue
2304      * and takes string refs to mmap FILE_CHUNK to avoid extra copying
2305      * since the result is likely to be consumed by TLS modules */
2306 
2307     h2con * const h2c = con->h2;
2308     const uint32_t fsize = h2c->s_max_frame_size;
2309     do {
2310         const uint32_t len = dlen < fsize ? dlen : fsize;
2311         dataframe.c[3] = (len >> 16) & 0xFF; /*(off +3 to skip over align pad)*/
2312         dataframe.c[4] = (len >>  8) & 0xFF;
2313         dataframe.c[5] = (len      ) & 0xFF;
2314         chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
2315                               (const char *)dataframe.c+3, sizeof(dataframe)-3);
2316         chunkqueue_steal(con->write_queue, cq, (off_t)dlen);
2317         dlen -= len;
2318     } while (dlen);
2319 }
2320 
2321 
2322 static void
2323 h2_send_end_stream_data (request_st * const r, connection * const con)
2324 {
2325     union {
2326       uint8_t c[12];
2327       uint32_t u[3];          /*(alignment)*/
2328     } dataframe = { {         /*(big-endian numbers)*/
2329       0x00, 0x00, 0x00        /* padding for alignment; do not send */
2330       /* DATA */
2331      ,0x00, 0x00, 0x00        /* frame length */
2332      ,H2_FTYPE_DATA           /* frame type */
2333      ,H2_FLAG_END_STREAM      /* frame flags */
2334      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
2335     } };
2336 
2337     dataframe.u[2] = htonl(r->h2id);
2338     r->h2state = H2_STATE_CLOSED;
2339     /*(ignore window updates when sending 0-length DATA frame with END_STREAM)*/
2340     chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
2341                           (const char *)dataframe.c+3, sizeof(dataframe)-3);
2342 }
2343 
2344 
2345 void
2346 h2_send_end_stream (request_st * const r, connection * const con)
2347 {
2348     if (r->state != CON_STATE_ERROR && r->resp_body_finished) {
2349         /* CON_STATE_RESPONSE_END */
2350         if (r->gw_dechunk && r->gw_dechunk->done
2351             && !buffer_is_empty(&r->gw_dechunk->b))
2352             h2_send_end_stream_trailers(r, con, &r->gw_dechunk->b);
2353         else
2354             h2_send_end_stream_data(r, con);
2355     }
2356     else { /* CON_STATE_ERROR */
2357         h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2358     }
2359 }
2360 
2361 
2362 /*
2363  * (XXX: might move below to separate file)
2364  */
2365 #include "base64.h"
2366 #include "chunk.h"
2367 #include "plugin.h"
2368 #include "plugin_config.h"
2369 #include "reqpool.h"
2370 
2371 
2372 static request_st *
2373 h2_init_stream (request_st * const h2r, connection * const con)
2374 {
2375     h2con * const h2c = con->h2;
2376     ++con->request_count;
2377     force_assert(h2c->rused < sizeof(h2c->r)/sizeof(*h2c->r));
2378     /* initialize stream as subrequest (request_st *) */
2379     request_st * const r = request_acquire(con);
2380     /* XXX: TODO: assign default priority, etc.
2381      *      Perhaps store stream id and priority in separate table */
2382     h2c->r[h2c->rused++] = r;
2383     r->h2_rwin = h2c->s_initial_window_size;
2384     r->h2_swin = h2c->s_initial_window_size;
2385     r->http_version = HTTP_VERSION_2;
2386 
2387     /* copy config state from h2r */
2388     server * const srv = con->srv;
2389     const uint32_t used = srv->config_context->used;
2390     r->conditional_is_valid = h2r->conditional_is_valid;
2391     memcpy(r->cond_cache, h2r->cond_cache, used * sizeof(cond_cache_t));
2392   #ifdef HAVE_PCRE_H
2393     if (used > 1) /*(save 128b per con if no conditions)*/
2394         memcpy(r->cond_match, h2r->cond_match, used * sizeof(cond_match_t));
2395   #endif
2396     /*(see config_reset_config())*/
2397     r->server_name = h2r->server_name;
2398     memcpy(&r->conf, &h2r->conf, sizeof(request_config));
2399 
2400     /* stream id must be assigned by caller */
2401     return r;
2402 }
2403 
2404 
2405 static void
2406 h2_release_stream (request_st * const r, connection * const con)
2407 {
2408     if (r->http_status) {
2409         /* (see comment in connection_handle_response_end_state()) */
2410         plugins_call_handle_request_done(r);
2411 
2412       #if 0
2413         /* (fuzzy accounting for mod_accesslog, mod_rrdtool to avoid
2414          *  double counting, but HTTP/2 framing and HPACK-encoded headers in
2415          *  con->read_queue and con->write_queue are not equivalent to the
2416          *  HPACK-decoded headers and request and response bodies in stream
2417          *  r->read_queue and r->write_queue) */
2418         /* DISABLED since mismatches invalidate the relationship between
2419          * con->bytes_in and con->bytes_out */
2420         con->read_queue->bytes_in   -= r->read_queue.bytes_in;
2421         con->write_queue->bytes_out -= r->write_queue.bytes_out;
2422       #else
2423         UNUSED(con);
2424       #endif
2425     }
2426 
2427     request_release(r);
2428 }
2429 
2430 
2431 void
2432 h2_retire_stream (request_st *r, connection * const con)
2433 {
2434     if (r == NULL) return; /*(should not happen)*/
2435     h2con * const h2c = con->h2;
2436     request_st ** const ar = h2c->r;
2437     uint32_t i = 0, rused = h2c->rused;
2438     while (i < rused && ar[i] != r) ++i;
2439     if (i != rused) {
2440         /* swap with last element; might need to revisit if ordered by priority */
2441         /*if (i != --rused) ar[i] = ar[rused];*/
2442         /* shift elements; currently choosing to preserve order requested */
2443         if (i != --rused) memmove(ar+i, ar+i+1, (rused-i)*sizeof(*ar));
2444         h2c->r[(h2c->rused = rused)] = NULL;
2445         h2_release_stream(r, con);
2446     }
2447     /*else ... should not happen*/
2448 }
2449 
2450 
2451 void
2452 h2_retire_con (request_st * const h2r, connection * const con)
2453 {
2454     h2con * const h2c = con->h2;
2455     if (NULL == h2c) return;
2456 
2457     if (h2r->state != CON_STATE_ERROR) { /*(CON_STATE_RESPONSE_END)*/
2458         h2_send_goaway(con, H2_E_NO_ERROR);
2459         for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
2460             /*(unexpected if CON_STATE_RESPONSE_END)*/
2461             request_st * const r = h2c->r[i];
2462             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2463             h2_release_stream(r, con);
2464         }
2465         if (!chunkqueue_is_empty(con->write_queue)) {
2466             /* similar to connection_handle_write() but without error checks,
2467              * without MAX_WRITE_LIMIT, and without connection throttling */
2468             /*h2r->conf.bytes_per_second = 0;*/         /* disable rate limit */
2469             /*h2r->conf.global_bytes_per_second = 0;*/  /* disable rate limit */
2470             /*con->traffic_limit_reached = 0;*/
2471             chunkqueue * const cq = con->write_queue;
2472             const off_t len = chunkqueue_length(cq);
2473             off_t written = cq->bytes_out;
2474             con->network_write(con, cq, len);
2475             /*(optional accounting)*/
2476             written = cq->bytes_out - written;
2477             con->bytes_written += written;
2478             con->bytes_written_cur_second += written;
2479             if (h2r->conf.global_bytes_per_second_cnt_ptr)
2480                 *(h2r->conf.global_bytes_per_second_cnt_ptr) += written;
2481         }
2482     }
2483     else { /* CON_STATE_ERROR */
2484         for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
2485             request_st * const r = h2c->r[i];
2486             h2_release_stream(r, con);
2487         }
2488         /* XXX: perhaps attempt to send GOAWAY?  Not when CON_STATE_ERROR */
2489     }
2490 
2491     con->h2 = NULL;
2492 
2493     /* future: might keep a pool of reusable (h2con *) */
2494     lshpack_enc_cleanup(&h2c->encoder);
2495     lshpack_dec_cleanup(&h2c->decoder);
2496     free(h2c);
2497 }
2498 
2499 
2500 static void
2501 h2_con_upgrade_h2c (request_st * const h2r, const buffer * const http2_settings)
2502 {
2503     /* status: (h2r->state == CON_STATE_REQUEST_END) for Upgrade: h2c */
2504 
2505     /* HTTP/1.1 101 Switching Protocols
2506      * Connection: Upgrade
2507      * Upgrade: h2c
2508      */
2509   #if 1
2510     static const char switch_proto[] = "HTTP/1.1 101 Switching Protocols\r\n"
2511                                        "Connection: Upgrade\r\n"
2512                                        "Upgrade: h2c\r\n\r\n";
2513     chunkqueue_append_mem(&h2r->write_queue,
2514                           CONST_STR_LEN(switch_proto));
2515     h2r->resp_header_len = sizeof(switch_proto)-1;
2516   #else
2517     h2r->http_status = 101;
2518     http_header_response_set(h2r, HTTP_HEADER_UPGRADE, CONST_STR_LEN("Upgrade"),
2519                                                        CONST_STR_LEN("h2c"));
2520     http_response_write_header(h2r);
2521     http_response_reset(h2r);
2522     h2r->http_status = 0;
2523   #endif
2524 
2525     connection * const con = h2r->con;
2526     h2_init_con(h2r, con, http2_settings);
2527     if (con->h2->sent_goaway) return;
2528 
2529     con->h2->h2_cid = 1; /* stream id 1 is assigned to h2c upgrade */
2530 
2531     /* copy request state from &con->request to subrequest r
2532      * XXX: would be nice if there were a cleaner way to do this
2533      * (This is fragile and must be kept in-sync with request_st in request.h)*/
2534 
2535     request_st * const r = h2_init_stream(h2r, con);
2536     /*(undo double-count; already incremented in CON_STATE_REQUEST_START)*/
2537     --con->request_count;
2538     r->state = h2r->state; /* CON_STATE_REQUEST_END */
2539     r->http_status = 0;
2540     r->http_method = h2r->http_method;
2541     r->h2state = H2_STATE_HALF_CLOSED_REMOTE;
2542     r->h2id = 1;
2543     r->rqst_htags = h2r->rqst_htags;
2544     h2r->rqst_htags = 0;
2545     r->rqst_header_len = h2r->rqst_header_len;
2546     h2r->rqst_header_len = 0;
2547     r->rqst_headers = h2r->rqst_headers;        /* copy struct */
2548     memset(&h2r->rqst_headers, 0, sizeof(array));
2549     r->uri = h2r->uri;                          /* copy struct */
2550   #if 0
2551     r->physical = h2r->physical;                /* copy struct */
2552     r->env = h2r->env;                          /* copy struct */
2553   #endif
2554     memset(&h2r->rqst_headers, 0, sizeof(array));
2555     memset(&h2r->uri, 0, sizeof(request_uri));
2556   #if 0
2557     memset(&h2r->physical, 0, sizeof(physical));
2558     memset(&h2r->env, 0, sizeof(array));
2559   #endif
2560   #if 0 /* expect empty request body */
2561     r->reqbody_length = h2r->reqbody_length; /* currently always 0 */
2562     r->te_chunked = h2r->te_chunked;         /* must be 0 */
2563     swap(&r->reqbody_queue,&h2r->reqbody_queue);/*currently always empty queue*/
2564   #endif
2565     r->http_host = h2r->http_host;
2566     h2r->http_host = NULL;
2567   #if 0
2568     r->server_name = h2r->server_name;
2569     h2r->server_name = NULL;
2570   #endif
2571     r->target = h2r->target;                    /* copy struct */
2572     r->target_orig = h2r->target_orig;          /* copy struct */
2573   #if 0
2574     r->pathinfo = h2r->pathinfo;                /* copy struct */
2575     r->server_name_buf = h2r->server_name_buf;  /* copy struct */
2576   #endif
2577     memset(&h2r->target, 0, sizeof(buffer));
2578     memset(&h2r->target_orig, 0, sizeof(buffer));
2579   #if 0
2580     memset(&h2r->pathinfo, 0, sizeof(buffer));
2581     memset(&h2r->server_name_buf, 0, sizeof(buffer));
2582   #endif
2583   #if 0
2584     /* skip copying response structures, other state not yet modified in h2r */
2585     /* r write_queue and read_queue are intentionally separate from h2r */
2586     /* r->gw_dechunk must be NULL for HTTP/2 */
2587     /* bytes_written_ckpt and bytes_read_ckpt are for HTTP/1.1 */
2588     /* error handlers have not yet been set */
2589   #endif
2590   #if 0
2591     r->loops_per_request = h2r->loops_per_request;
2592     r->async_callback = h2r->async_callback;
2593   #endif
2594     r->keep_alive = h2r->keep_alive;
2595     r->tmp_buf = h2r->tmp_buf;                /* shared; same as srv->tmp_buf */
2596     r->start_hp = h2r->start_hp;                /* copy struct */
2597 
2598     /* Note: HTTP/1.1 101 Switching Protocols is not immediately written to
2599      * the network here.  As this is called from cleartext Upgrade: h2c,
2600      * we choose to delay sending the status until the beginning of the response
2601      * to the HTTP/1.1 request which included Upgrade: h2c */
2602 }
2603 
2604 
2605 int
2606 h2_check_con_upgrade_h2c (request_st * const r)
2607 {
2608     /* RFC7540 3.2 Starting HTTP/2 for "http" URIs */
2609 
2610     buffer *http_connection, *http2_settings;
2611     buffer *upgrade = http_header_request_get(r, HTTP_HEADER_UPGRADE,
2612                                               CONST_STR_LEN("Upgrade"));
2613     if (NULL == upgrade) return 0;
2614     http_connection = http_header_request_get(r, HTTP_HEADER_CONNECTION,
2615                                               CONST_STR_LEN("Connection"));
2616     if (NULL == http_connection) {
2617         http_header_request_unset(r, HTTP_HEADER_UPGRADE,
2618                                   CONST_STR_LEN("Upgrade"));
2619         return 0;
2620     }
2621     if (r->http_version != HTTP_VERSION_1_1) {
2622         http_header_request_unset(r, HTTP_HEADER_UPGRADE,
2623                                   CONST_STR_LEN("Upgrade"));
2624         http_header_remove_token(http_connection, CONST_STR_LEN("Upgrade"));
2625         return 0;
2626     }
2627 
2628     if (!http_header_str_contains_token(CONST_BUF_LEN(upgrade),
2629                                         CONST_STR_LEN("h2c")))
2630         return 0;
2631 
2632     http2_settings = http_header_request_get(r, HTTP_HEADER_HTTP2_SETTINGS,
2633                                              CONST_STR_LEN("HTTP2-Settings"));
2634     if (NULL != http2_settings) {
2635         if (0 == r->reqbody_length) {
2636             buffer * const b = r->tmp_buf;
2637             buffer_clear(b);
2638             if (r->conf.h2proto > 1/*(must be enabled with server.h2c feature)*/
2639                 &&
2640                 http_header_str_contains_token(CONST_BUF_LEN(http_connection),
2641                                                CONST_STR_LEN("HTTP2-Settings"))
2642                 && buffer_append_base64_decode(b, CONST_BUF_LEN(http2_settings),
2643                                                BASE64_URL)) {
2644                 h2_con_upgrade_h2c(r, b);
2645                 r->http_version = HTTP_VERSION_2;
2646             } /* else ignore if invalid base64 */
2647         }
2648         else {
2649             /* ignore Upgrade: h2c if request body present since we do not
2650              * (currently) handle request body before transition to h2c */
2651             /* RFC7540 3.2 Requests that contain a payload body MUST be sent
2652              * in their entirety before the client can send HTTP/2 frames. */
2653         }
2654         http_header_request_unset(r, HTTP_HEADER_HTTP2_SETTINGS,
2655                                   CONST_STR_LEN("HTTP2-Settings"));
2656         http_header_remove_token(http_connection, CONST_STR_LEN("HTTP2-Settings"));
2657     } /* else ignore Upgrade: h2c; HTTP2-Settings required for Upgrade: h2c */
2658     http_header_request_unset(r, HTTP_HEADER_UPGRADE,
2659                               CONST_STR_LEN("Upgrade"));
2660     http_header_remove_token(http_connection, CONST_STR_LEN("Upgrade"));
2661     return (r->http_version == HTTP_VERSION_2);
2662 }
2663