xref: /lighttpd1.4/src/h2.c (revision 0f82722f)
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       #ifdef __COVERITY__
1403         /* Coverity does not notice that values used in s are checked.
1404          * Although silencing here, would prefer not to do so since doing so
1405          * disables Coverity from reporting questionable modifications which
1406          * might be made to the code in the future. */
1407         __coverity_tainted_data_sink__(s);
1408       #endif
1409         uint32_t flen = (s[0] << 16) | (s[1] << 8) | s[2];
1410         if (flen > fsize) {
1411             h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
1412             return 0;
1413         }
1414 
1415         /*(handle PUSH_PROMISE as connection error further below)*/
1416         /*if (s[3] == H2_FTYPE_HEADERS || s[3] == H2_FTYPE_PUSH_PROMISE)*/
1417 
1418         if (s[3] == H2_FTYPE_HEADERS) {
1419             if (cqlen < 9+flen) return 1; /* incomplete frame; go on */
1420             if (clen < 9+flen) {
1421                 clen = h2_frame_cq_compact(cq, 9+flen);
1422                 c = cq->first; /*(reload after h2_frame_cq_compact())*/
1423                 s = (uint8_t *)(c->mem->ptr + c->offset);
1424             }
1425 
1426             if (!(s[4] & H2_FLAG_END_HEADERS)) {
1427                 /* collect CONTINUATION frames (cold code path) */
1428                 /* note: h2_recv_continuation() return value is overloaded
1429                  * and the resulting clen is 9+flen of *concatenated* frames */
1430                 clen = h2_recv_continuation(9+flen, clen, cqlen, cq, con);
1431                 if (0 == clen)    return 0;
1432                 if (cqlen < clen) return 1; /* incomplete frames; go on */
1433                 c = cq->first; /*(reload after h2_recv_continuation())*/
1434                 s = (uint8_t *)(c->mem->ptr + c->offset);
1435                 /* frame size was also updated and might (legitimately)
1436                  * exceed SETTINGS_MAX_FRAME_SIZE, so do not test fsize again */
1437                 flen = (s[0]<<16)|(s[1]<<8)|s[2];
1438                 /* recalculate after CONTINUATION removed */
1439                 cqlen = chunkqueue_length(cq);
1440             }
1441 
1442             int rc = h2_recv_headers(con, s, flen);
1443             cqlen -= (9+flen);
1444             if (rc >= 0)
1445                 chunkqueue_mark_written(cq, 9+flen);
1446             if (rc <= 0)
1447                 return 0;
1448             con->read_idle_ts = log_epoch_secs;
1449         }
1450         else if (s[3] == H2_FTYPE_DATA) {
1451             /* future: might try to stream data for incomplete frames,
1452              * but that would require keeping additional state for partially
1453              * read frames, including cleaning up if errors occur.
1454              * Since well-behaved clients do not intentionally send partial
1455              * frames, and try to resend if socket buffers are full, this is
1456              * probably not a big concern in practice. */
1457             if (cqlen < 9+flen) return 1; /* incomplete frame; go on */
1458             con->read_idle_ts = log_epoch_secs;
1459             /*(h2_recv_data() must consume frame from cq or else return 0)*/
1460             if (!h2_recv_data(con, s, flen))
1461                 return 0;
1462             cqlen -= (9+flen);
1463         }
1464         else {
1465             /* frame types below are expected to be small
1466              * most frame types below have fixed (small) size
1467              *   4 bytes - WINDOW_UPDATE
1468              *   5 bytes - PRIORITY
1469              *   8 bytes - PING
1470              *   4 bytes - RST_STREAM
1471              * some are variable size
1472              *     SETTINGS (6 * #settings; 6 defined in RFC 7540 Section 6.5)
1473              *     GOAWAY   (8 + optional additional debug data (variable))
1474              * XXX: might add sanity check for a max flen here,
1475              *      before waiting to read partial frame
1476              *      (fsize limit is still enforced above for all frames)
1477              */
1478             if (cqlen < 9+flen) return 1; /* incomplete frame; go on */
1479             if (clen < 9+flen) {
1480                 clen = h2_frame_cq_compact(cq, 9+flen);
1481                 c = cq->first; /*(reload after h2_frame_cq_compact())*/
1482                 s = (uint8_t *)(c->mem->ptr + c->offset);
1483             }
1484             switch (s[3]) { /* frame type */
1485               case H2_FTYPE_WINDOW_UPDATE:
1486                 h2_recv_window_update(con, s, flen);
1487                 break;
1488               case H2_FTYPE_PRIORITY:
1489                 h2_recv_priority(con, s, flen);
1490                 break;
1491               case H2_FTYPE_SETTINGS:
1492                 h2_recv_settings(con, s, flen);
1493                 break;
1494               case H2_FTYPE_PING:
1495                 h2_recv_ping(con, s, flen);
1496                 break;
1497               case H2_FTYPE_RST_STREAM:
1498                 h2_recv_rst_stream(con, s, flen);
1499                 break;
1500               case H2_FTYPE_GOAWAY:
1501                 if (!h2_recv_goaway(con, s, flen)) return 0;
1502                 break;
1503               case H2_FTYPE_PUSH_PROMISE: /*not expected from client*/
1504               case H2_FTYPE_CONTINUATION: /*handled with HEADERS*/
1505                 h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1506                 return 0;
1507               default: /* ignore unknown frame types */
1508                 break;
1509             }
1510             cqlen -= (9+flen);
1511             chunkqueue_mark_written(cq, 9+flen);
1512         }
1513 
1514         if (h2c->sent_goaway > 0) return 0;
1515     }
1516 
1517     return 1;
1518 }
1519 
1520 
1521 int
1522 h2_want_read (connection * const con)
1523 {
1524     chunkqueue * const cq = con->read_queue;
1525     if (chunkqueue_is_empty(cq)) return 1;
1526 
1527     /* check for partial frame */
1528     const off_t cqlen = chunkqueue_length(cq);
1529     if (cqlen < 9) return 1;
1530     chunk *c = cq->first;
1531     uint32_t clen = buffer_string_length(c->mem) - c->offset;
1532     if (clen < 9) {
1533         clen = h2_frame_cq_compact(cq, 9);
1534         c = cq->first; /*(reload after h2_frame_cq_compact())*/
1535     }
1536     uint8_t *s = (uint8_t *)(c->mem->ptr + c->offset);
1537     uint32_t flen = (s[0] << 16) | (s[1] << 8) | s[2];
1538     if (clen < 9+flen) return 1;
1539 
1540     /* check if not HEADERS, or if HEADERS has END_HEADERS flag */
1541     if (s[3] != H2_FTYPE_HEADERS || (s[4] & H2_FLAG_END_HEADERS))
1542         return 0;
1543 
1544     /* check for partial CONTINUATION frames */
1545     for (uint32_t n = 9+flen; cqlen >= n+9; n += 9+flen) {
1546         if (clen < n+9) {
1547             clen = h2_frame_cq_compact(cq, n+9);
1548             c = cq->first; /*(reload after h2_frame_cq_compact())*/
1549             s = (uint8_t *)(c->mem->ptr + c->offset);
1550         }
1551         flen = (s[n+0] << 16) | (s[n+1] << 8) | s[n+2];
1552         if (cqlen < n+9+flen) return 1; /* incomplete frame; go on */
1553         if (s[4] & H2_FLAG_END_HEADERS) return 0;
1554     }
1555 
1556     return 1;
1557 }
1558 
1559 
1560 static int
1561 h2_recv_client_connection_preface (connection * const con)
1562 {
1563     /* check if the client Connection Preface (24 bytes) has been received
1564      * (initial SETTINGS frame should immediately follow, but is not checked) */
1565     chunkqueue * const cq = con->read_queue;
1566     if (chunkqueue_length(cq) < 24) {
1567         chunk * const c = cq->first;
1568         if (c && buffer_string_length(c->mem) - c->offset >= 4) {
1569             const char * const s = c->mem->ptr + c->offset;
1570             if (s[0]!='P'||s[1]!='R'||s[2]!='I'||s[3]!=' ') {
1571                 h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1572                 return 1; /* error; done receiving connection preface */
1573             }
1574         }
1575         return 0; /*(not ready yet)*/
1576     }
1577 
1578     static const char h2preface[] = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
1579     chunk *c = cq->first;
1580     const uint32_t clen = buffer_string_length(c->mem) - c->offset;
1581     if (clen < 24) h2_frame_cq_compact(cq, 24);
1582     c = cq->first; /*(reload after h2_frame_cq_compact())*/
1583     const uint8_t * const s = (uint8_t *)(c->mem->ptr + c->offset);
1584     if (0 == memcmp(s, h2preface, 24)) /* sizeof(h2preface)-1) */
1585         chunkqueue_mark_written(cq, 24);
1586     else
1587         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1588     return 1; /* done receiving connection preface (even if error occurred) */
1589 }
1590 
1591 
1592 __attribute_cold__
1593 static int
1594 h2_read_client_connection_preface (struct connection * const con, chunkqueue * const cq, off_t max_bytes)
1595 {
1596     /* temporary con->network_read() filter until connection preface received */
1597 
1598     /*(alternatively, func ptr could be saved in an element in (h2con *))*/
1599     void ** const hctx = con->plugin_ctx+0; /*(0 idx used for h2)*/
1600     int(* const network_read)(struct connection *, chunkqueue *, off_t) =
1601       (int(*)(struct connection *, chunkqueue *, off_t))(uintptr_t)(*hctx);
1602     if (max_bytes < 24) max_bytes = 24; /*(should not happen)*/
1603     int rc = (network_read)(con, cq, max_bytes);
1604     if (NULL == con->h2) return rc; /*(unexpected; already cleaned up)*/
1605     if (-1 != rc && h2_recv_client_connection_preface(con)) {
1606         con->network_read = network_read;
1607         *hctx = NULL;
1608         /*(intentionally update timestamp only after reading preface complete)*/
1609         con->read_idle_ts = log_epoch_secs;
1610     }
1611     return rc;
1612 }
1613 
1614 
1615 void
1616 h2_init_con (request_st * const restrict h2r, connection * const restrict con, const buffer * const restrict http2_settings)
1617 {
1618     h2con * const h2c = calloc(1, sizeof(h2con));
1619     force_assert(h2c);
1620     con->h2 = h2c;
1621     con->read_idle_ts = log_epoch_secs;
1622     con->keep_alive_idle = h2r->conf.max_keep_alive_idle;
1623 
1624     h2r->h2_rwin = 65535;                 /* h2 connection recv window */
1625     h2r->h2_swin = 65535;                 /* h2 connection send window */
1626     /* settings sent from peer */         /* initial values */
1627     h2c->s_header_table_size     = 4096;  /* SETTINGS_HEADER_TABLE_SIZE      */
1628     h2c->s_enable_push           = 1;     /* SETTINGS_ENABLE_PUSH            */
1629     h2c->s_max_concurrent_streams= ~0u;   /* SETTINGS_MAX_CONCURRENT_STREAMS */
1630     h2c->s_initial_window_size   = 65535; /* SETTINGS_INITIAL_WINDOW_SIZE    */
1631     h2c->s_max_frame_size        = 16384; /* SETTINGS_MAX_FRAME_SIZE         */
1632     h2c->s_max_header_list_size  = ~0u;   /* SETTINGS_MAX_HEADER_LIST_SIZE   */
1633     h2c->sent_settings           = log_epoch_secs; /*(send SETTINGS below)*/
1634 
1635     lshpack_dec_init(&h2c->decoder);
1636     lshpack_enc_init(&h2c->encoder);
1637     lshpack_enc_use_hist(&h2c->encoder, 1);
1638 
1639     if (http2_settings) /*(if Upgrade: h2c)*/
1640         h2_parse_frame_settings(con, (uint8_t *)CONST_BUF_LEN(http2_settings));
1641 
1642     static const uint8_t h2settings[] = { /*(big-endian numbers)*/
1643       /* SETTINGS */
1644       0x00, 0x00, 0x0c        /* frame length */ /* 6 * 2 for two settings */
1645      ,H2_FTYPE_SETTINGS       /* frame type */
1646      ,0x00                    /* frame flags */
1647      ,0x00, 0x00, 0x00, 0x00  /* stream identifier */
1648      ,0x00, H2_SETTINGS_MAX_CONCURRENT_STREAMS
1649      ,0x00, 0x00, 0x00, 0x08  /* 8 */
1650      #if 0  /* ? explicitly disable dynamic table ? (and adjust frame length) */
1651             /* If this is sent, must wait until peer sends SETTINGS with ACK
1652              * before disabling dynamic table in HPACK decoder */
1653             /*(before calling lshpack_dec_set_max_capacity(&h2c->decoder, 0))*/
1654      ,0x00, H2_SETTINGS_HEADER_TABLE_SIZE
1655      ,0x00, 0x00, 0x00, 0x00  /* 0 */
1656      #endif
1657      #if 0  /* ? explicitly disable push ?       (and adjust frame length) */
1658      ,0x00, H2_SETTINGS_ENABLE_PUSH
1659      ,0x00, 0x00, 0x00, 0x00  /* 0 */
1660      #endif
1661      #if 0  /* ? increase from default (65535) ? (and adjust frame length) */
1662      ,0x00, H2_SETTINGS_INITIAL_WINDOW_SIZE
1663      ,0x00, 0x02, 0x00, 0x00  /* 131072 */
1664      #endif
1665      #if 0  /* ? increase from default (16384) ? (and adjust frame length) */
1666      ,0x00, H2_SETTINGS_MAX_FRAME_SIZE
1667      ,0x00, 0x00, 0x80, 0x00  /* 32768 */
1668      #endif
1669      ,0x00, H2_SETTINGS_MAX_HEADER_LIST_SIZE
1670      ,0x00, 0x00, 0xFF, 0xFF  /* 65535 */
1671 
1672      #if 0
1673       /* WINDOW_UPDATE */
1674      ,0x00, 0x00, 0x04        /* frame length */
1675      ,H2_FTYPE_WINDOW_UPDATE  /* frame type */
1676      ,0x00                    /* frame flags */
1677      ,0x00, 0x00, 0x00, 0x00  /* stream identifier */
1678      ,0x00, 0x01, 0x00, 0x01  /* 65537 */ /* increase connection rwin to 128k */
1679      #endif
1680     };
1681 
1682     /*h2r->h2_rwin += 65537;*//*(enable if WINDOWS_UPDATE is sent above)*/
1683     chunkqueue_append_mem(con->write_queue,
1684                           (const char *)h2settings, sizeof(h2settings));
1685 
1686     if (!h2_recv_client_connection_preface(con)) {
1687         /*(alternatively, func ptr could be saved in an element in (h2con *))*/
1688         con->plugin_ctx[0] = (void *)(uintptr_t)con->network_read;
1689         con->network_read = h2_read_client_connection_preface;
1690         /* note: no steps taken to reset con->network_read() on error
1691          * as con->network_read() is always set in connection_accepted() */
1692     }
1693 
1694     buffer_string_prepare_copy(h2r->tmp_buf, 65535);
1695 }
1696 
1697 
1698 static void
1699 h2_send_hpack (request_st * const r, connection * const con, const char *data, uint32_t dlen, const uint32_t flags)
1700 {
1701     union {
1702       uint8_t c[12];
1703       uint32_t u[3];          /*(alignment)*/
1704     } headers = { {           /*(big-endian numbers)*/
1705       0x00, 0x00, 0x00        /* padding for alignment; do not send */
1706       /* HEADERS */
1707      ,0x00, 0x00, 0x00        /* frame length      (fill in below) */
1708      ,H2_FTYPE_HEADERS        /* frame type */
1709      ,(uint8_t)flags          /* frame flags (e.g. END_STREAM for trailers) */
1710      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
1711     } };
1712 
1713     headers.u[2] = htonl(r->h2id);
1714 
1715     /* similar to h2_send_data(), but unlike DATA frames there is a HEADERS
1716      * frame potentially followed by CONTINUATION frame(s) here, and the final
1717      * HEADERS or CONTINUATION frame here has END_HEADERS flag set.
1718      * For trailers, END_STREAM flag is set on HEADERS frame. */
1719 
1720     /*(approximate space needed for frames (header + payload)
1721      * with slight over-estimate of 16 bytes per frame header (> 9)
1722      * and minimum SETTING_MAX_FRAME_SIZE of 16k (could be larger)
1723      * (dlen >> 14)+1 is num 16k frames needed, multipled by 16 bytes
1724      *  per frame can be appoximated with (dlen>>10) + 9)*/
1725     buffer * const b =
1726       chunkqueue_append_buffer_open_sz(con->write_queue, dlen + (dlen>>10) + 9);
1727     char * restrict ptr = b->ptr;
1728     h2con * const h2c = con->h2;
1729     const uint32_t fsize = h2c->s_max_frame_size;
1730     do {
1731         const uint32_t len = dlen < fsize ? dlen : fsize;
1732         headers.c[3] = (len >> 16) & 0xFF; /*(off +3 to skip over align pad)*/
1733         headers.c[4] = (len >>  8) & 0xFF;
1734         headers.c[5] = (len      ) & 0xFF;
1735         if (len == dlen)
1736             headers.c[7] |= H2_FLAG_END_HEADERS;
1737       #if 0
1738         chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
1739                               (const char *)headers.c+3, sizeof(headers)-3);
1740         chunkqueue_append_mem(con->write_queue, data, len);
1741       #else
1742         memcpy(ptr, headers.c+3, sizeof(headers)-3);
1743         memcpy(ptr+sizeof(headers)-3, data, len);
1744         ptr  += len + sizeof(headers)-3;
1745       #endif
1746         data += len;
1747         dlen -= len;
1748         /*(include H2_FLAG_END_STREAM in HEADERS frame, not CONTINUATION)*/
1749         headers.c[6] = H2_FTYPE_CONTINUATION; /*(if additional frames needed)*/
1750         headers.c[7] = 0x00; /*(off +3 to skip over align pad)*/
1751     } while (dlen);
1752     buffer_string_set_length(b, (uint32_t)(ptr - b->ptr));
1753     chunkqueue_append_buffer_commit(con->write_queue);
1754 }
1755 
1756 
1757 __attribute_cold__
1758 static void
1759 h2_log_response_header_lsx(request_st * const r, const lsxpack_header_t * const lsx)
1760 {
1761     log_error(r->conf.errh, __FILE__, __LINE__,
1762       "fd:%d id:%u resp: %.*s: %.*s", r->con->fd, r->h2id,
1763       (int)lsx->name_len, lsx->buf + lsx->name_offset,
1764       (int)lsx->val_len,  lsx->buf + lsx->val_offset);
1765 }
1766 
1767 
1768 __attribute_cold__
1769 static void
1770 h2_log_response_header(request_st * const r, const int len, const char * const hdr)
1771 {
1772     log_error(r->conf.errh, __FILE__, __LINE__,
1773       "fd:%d id:%u resp: %.*s", r->con->fd, r->h2id, len, hdr);
1774 }
1775 
1776 
1777 void
1778 h2_send_headers (request_st * const r, connection * const con)
1779 {
1780     /*(set keep_alive_idle; out-of-place and non-event for most configs,
1781      * but small attempt to (maybe) preserve behavior for specific configs)*/
1782     con->keep_alive_idle = r->conf.max_keep_alive_idle;
1783 
1784     /* specialized version of http_response_write_header(); send headers
1785      * directly to HPACK encoder, rather than double-buffering in chunkqueue */
1786 
1787     if (304 == r->http_status
1788         && light_btst(r->resp_htags, HTTP_HEADER_CONTENT_ENCODING))
1789         http_header_response_unset(r, HTTP_HEADER_CONTENT_ENCODING,
1790                                    CONST_STR_LEN("Content-Encoding"));
1791 
1792     /*(h2_init_con() resized h2r->tmp_buf to 64k; shared with r->tmp_buf)*/
1793     buffer * const tb = r->tmp_buf;
1794     force_assert(tb->size >= 65536);/*(sanity check; remove in future)*/
1795     unsigned char *dst = (unsigned char *)tb->ptr;
1796     unsigned char * const dst_end = (unsigned char *)tb->ptr + tb->size;
1797 
1798     h2con * const h2c = con->h2;
1799     struct lshpack_enc * const encoder = &h2c->encoder;
1800     lsxpack_header_t lsx;
1801     uint32_t alen = 7+3+4; /* ":status: xxx\r\n" */
1802     const int log_response_header = r->conf.log_response_header;
1803     const int resp_header_repeated = r->resp_header_repeated;
1804 
1805     char status[12] = ":status: ";
1806     int x = r->http_status; /*(expect status < 1000; should be [100-599])*/
1807     status[11] = (x % 10) + '0';
1808     status[10] = (x / 10 % 10) + '0';
1809     status[9]  = (x / 100) + '0';
1810 
1811     if (log_response_header)
1812         h2_log_response_header(r, 12, status);
1813 
1814     memset(&lsx, 0, sizeof(lsxpack_header_t));
1815     lsx.buf = status;
1816     lsx.name_offset = 0;
1817     lsx.name_len = 7;
1818     lsx.val_offset = 9;
1819     lsx.val_len = 3;
1820     switch (r->http_status) {
1821       case 200: lsx.hpack_index = LSHPACK_HDR_STATUS_200; break;
1822       case 204: lsx.hpack_index = LSHPACK_HDR_STATUS_204; break;
1823       case 206: lsx.hpack_index = LSHPACK_HDR_STATUS_206; break;
1824       case 304: lsx.hpack_index = LSHPACK_HDR_STATUS_304; break;
1825       case 400: lsx.hpack_index = LSHPACK_HDR_STATUS_400; break;
1826       case 404: lsx.hpack_index = LSHPACK_HDR_STATUS_404; break;
1827       case 500: lsx.hpack_index = LSHPACK_HDR_STATUS_500; break;
1828       default:
1829         break;
1830     }
1831     dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1832     if (dst == (unsigned char *)tb->ptr) {
1833         h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1834         return;
1835     }
1836 
1837     /* add all headers */
1838     for (uint32_t i = 0, used = r->resp_headers.used; i < used; ++i) {
1839         data_string * const restrict ds =(data_string *)r->resp_headers.data[i];
1840         const uint32_t klen = buffer_string_length(&ds->key);
1841         const uint32_t vlen = buffer_string_length(&ds->value);
1842         const char * const restrict k = ds->key.ptr;
1843         if (0 == vlen || 0 == klen) continue;
1844         alen += klen + vlen + 4;
1845 
1846         if (alen > LSXPACK_MAX_STRLEN) {
1847             /* ls-hpack default limit (UINT16_MAX) is per-line, due to field
1848              * sizes of lsx.name_offset,lsx.name_len,lsx.val_offset,lsx.val_len
1849              * However, similar to elsewhere, limit total size of expanded
1850              * headers to (very generous) 64k - 1.  Peers might allow less. */
1851             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1852             return;
1853         }
1854 
1855         /* HTTP/2 requires lowercase keys
1856          * ls-hpack requires key and value be in same buffer
1857          * Since keys are typically short, append (and lowercase) key onto
1858          * end of value buffer */
1859         char * const v = buffer_string_prepare_append(&ds->value, klen);
1860         if (ds->ext != HTTP_HEADER_OTHER) {
1861             memcpy(v, http_header_lc[ds->ext], klen);
1862         }
1863         else {
1864             if ((k[0] & 0xdf) == 'X' && http_response_omit_header(r, ds)) {
1865                 alen -= klen + vlen + 4;
1866                 continue;
1867             }
1868             for (uint32_t j = 0; j < klen; ++j)
1869                 v[j] = !light_isupper(k[j]) ? k[j] : (k[j] | 0x20);
1870         }
1871         /*buffer_commit(&ds->value, klen);*//*(not necessary; truncated below)*/
1872 
1873         uint32_t voff = 0;
1874         const char *n;
1875         lsx.buf = ds->value.ptr;
1876         do {
1877             n = !resp_header_repeated
1878               ? NULL
1879               : memchr(lsx.buf+voff, '\n', vlen - voff);
1880 
1881             memset(&lsx, 0, sizeof(lsxpack_header_t));
1882             lsx.hpack_index = http_header_lshpack_idx[ds->ext];
1883             lsx.buf = ds->value.ptr;
1884             lsx.name_offset = vlen;
1885             lsx.name_len = klen;
1886             lsx.val_offset = voff;
1887             if (NULL == n)
1888                 lsx.val_len = vlen - voff;
1889             else {
1890                 /* multiple headers (same field-name) separated by "\r\n"
1891                  * and then "field-name: " (see http_header_response_insert())*/
1892                 voff = (uint32_t)(n + 1 - lsx.buf);
1893                 lsx.val_len = voff - 2 - lsx.val_offset; /*(-2 for "\r\n")*/
1894                 voff += klen + 2;
1895             }
1896 
1897             if (log_response_header)
1898                 h2_log_response_header_lsx(r, &lsx);
1899 
1900             unsigned char * const dst_in = dst;
1901             dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1902             if (dst == dst_in) {
1903                 buffer_string_set_length(&ds->value, vlen); /*(restore prior value)*/
1904                 h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1905                 return;
1906             }
1907         } while (n);
1908         buffer_string_set_length(&ds->value, vlen); /*(restore prior value)*/
1909     }
1910 
1911     if (!light_btst(r->resp_htags, HTTP_HEADER_DATE)) {
1912         /* HTTP/1.1 and later requires a Date: header */
1913         /* "date: " 6-chars + 30-chars for "%a, %d %b %Y %H:%M:%S GMT" + '\0' */
1914         static char tstr[36] = "date: ";
1915 
1916         memset(&lsx, 0, sizeof(lsxpack_header_t));
1917         lsx.buf = tstr;
1918         lsx.name_offset = 0;
1919         lsx.name_len = 4;
1920         lsx.val_offset = 6;
1921         lsx.val_len = 29;
1922         lsx.hpack_index = LSHPACK_HDR_DATE;
1923 
1924         /* cache the generated timestamp */
1925         static time_t tlast;
1926         const time_t cur_ts = log_epoch_secs;
1927         if (tlast != cur_ts) {
1928             tlast = cur_ts;
1929             strftime(tstr+6, sizeof(tstr)-6,
1930                      "%a, %d %b %Y %H:%M:%S GMT", gmtime(&tlast));
1931         }
1932 
1933         alen += 35+2;
1934 
1935         if (log_response_header)
1936             h2_log_response_header(r, 35, tstr);
1937 
1938         unsigned char * const dst_in = dst;
1939         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1940         if (dst == dst_in) {
1941             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1942             return;
1943         }
1944     }
1945 
1946     if (!light_btst(r->resp_htags, HTTP_HEADER_SERVER)
1947         && !buffer_string_is_empty(r->conf.server_tag)) {
1948         buffer * const b = chunk_buffer_acquire();
1949         const uint32_t vlen = buffer_string_length(r->conf.server_tag);
1950         buffer_copy_string_len(b, CONST_STR_LEN("server: "));
1951         buffer_append_string_len(b, CONST_BUF_LEN(r->conf.server_tag));
1952 
1953         alen += 6+vlen+4;
1954 
1955         if (log_response_header)
1956             h2_log_response_header(r, (int)6+vlen+2, b->ptr);
1957 
1958         memset(&lsx, 0, sizeof(lsxpack_header_t));
1959         lsx.buf = b->ptr;
1960         lsx.name_offset = 0;
1961         lsx.name_len = 6;
1962         lsx.val_offset = 8;
1963         lsx.val_len = vlen;
1964         lsx.hpack_index = LSHPACK_HDR_SERVER;
1965         unsigned char * const dst_in = dst;
1966         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1967         chunk_buffer_release(b);
1968         if (dst == dst_in) {
1969             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1970             return;
1971         }
1972     }
1973 
1974     alen += 2; /* "virtual" blank line ("\r\n") ending headers */
1975     r->resp_header_len = alen;
1976     /*(accounting for mod_accesslog and mod_rrdtool)*/
1977     chunkqueue * const wq = &r->write_queue;
1978     wq->bytes_in  += (off_t)alen;
1979     wq->bytes_out += (off_t)alen;
1980 
1981     const uint32_t dlen = (uint32_t)((char *)dst - tb->ptr);
1982     const uint32_t flags =
1983       (r->resp_body_finished && chunkqueue_is_empty(&r->write_queue))
1984         ? H2_FLAG_END_STREAM
1985         : 0;
1986     h2_send_hpack(r, con, tb->ptr, dlen, flags);
1987 }
1988 
1989 
1990 __attribute_cold__
1991 __attribute_noinline__
1992 static void
1993 h2_send_headers_block (request_st * const r, connection * const con, const char * const hdrs, const uint32_t hlen, uint32_t flags)
1994 {
1995     unsigned short hoff[8192]; /* max num header lines + 3; 16k on stack */
1996     hoff[0] = 1;                         /* number of lines */
1997     hoff[1] = 0;                         /* base offset for all lines */
1998     /*hoff[2] = ...;*/                   /* offset from base for 2nd line */
1999     uint32_t rc = http_header_parse_hoff(hdrs, hlen, hoff);
2000     if (0 == rc || rc > USHRT_MAX || hoff[0] >= sizeof(hoff)/sizeof(hoff[0])-1
2001         || 1 == hoff[0]) { /*(initial blank line (should not happen))*/
2002         /* error if headers incomplete or too many header fields */
2003         log_error(r->conf.errh, __FILE__, __LINE__,
2004                   "oversized response-header");
2005         hoff[0] = 1;
2006         hoff[1] = 0;
2007         http_header_parse_hoff(CONST_STR_LEN(":status: 500\r\n\r\n"), hoff);
2008     }
2009 
2010     /*(h2_init_con() resized h2r->tmp_buf to 64k; shared with r->tmp_buf)*/
2011     buffer * const tb = r->tmp_buf;
2012     force_assert(tb->size >= 65536);/*(sanity check; remove in future)*/
2013     unsigned char *dst = (unsigned char *)tb->ptr;
2014     unsigned char * const dst_end = (unsigned char *)tb->ptr + tb->size;
2015 
2016     h2con * const h2c = con->h2;
2017     struct lshpack_enc * const encoder = &h2c->encoder;
2018     lsxpack_header_t lsx;
2019 
2020     int i = 1;
2021     if (hdrs[0] == ':') {
2022         i = 2;
2023         /* expect first line to contain ":status: ..." if pseudo-header,
2024          * and expecting single pseudo-header for headers, zero for trailers */
2025         /*assert(0 == memcmp(hdrs, ":status: ", sizeof(":status: ")-1));*/
2026         memset(&lsx, 0, sizeof(lsxpack_header_t));
2027         *(const char **)&lsx.buf = hdrs;
2028         lsx.name_offset = 0;
2029         lsx.name_len = sizeof(":status")-1;
2030         lsx.val_offset = lsx.name_len + 2;
2031         lsx.val_len = 3;
2032         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
2033         if (dst == (unsigned char *)tb->ptr) {
2034             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2035             return;
2036         }
2037     }
2038 
2039     /*(note: not expecting any other pseudo-headers)*/
2040 
2041     /* note: expects field-names are lowercased (http_response_write_header())*/
2042 
2043     for (; i < hoff[0]; ++i) {
2044         const char *k = hdrs + ((i > 1) ? hoff[i] : 0);
2045         const char *end = hdrs + hoff[i+1];
2046         const char *v = memchr(k, ':', end-k);
2047         /* XXX: DOES NOT handle line wrapping (which is deprecated by RFCs)
2048          * (not expecting line wrapping; not produced internally by lighttpd,
2049          *  though possible from backends or with custom lua code)*/
2050         if (NULL == v || k == v) continue;
2051         uint32_t klen = v - k;
2052         if (0 == klen) continue;
2053         do { ++v; } while (*v == ' ' || *v == '\t'); /*(expect single ' ')*/
2054       #ifdef __COVERITY__
2055         /*(k has at least .:\n by now, so end[-2] valid)*/
2056         force_assert(end >= k + 2);
2057       #endif
2058         if (end[-2] != '\r') /*(header line must end "\r\n")*/
2059             continue;
2060         end -= 2;
2061         uint32_t vlen = end - v;
2062         if (0 == vlen) continue;
2063         memset(&lsx, 0, sizeof(lsxpack_header_t));
2064         *(const char **)&lsx.buf = hdrs;
2065         lsx.name_offset = k - hdrs;
2066         lsx.name_len = klen;
2067         lsx.val_offset = v - hdrs;
2068         lsx.val_len = vlen;
2069         unsigned char * const dst_in = dst;
2070         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
2071         if (dst == dst_in) {
2072             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2073             return;
2074         }
2075     }
2076     uint32_t dlen = (uint32_t)((char *)dst - tb->ptr);
2077     h2_send_hpack(r, con, tb->ptr, dlen, flags);
2078 }
2079 
2080 
2081 static void
2082 h2_send_1xx_block (request_st * const r, connection * const con, const char * const hdrs, const uint32_t hlen)
2083 {
2084     h2_send_headers_block(r, con, hdrs, hlen, 0);
2085 }
2086 
2087 
2088 int
2089 h2_send_1xx (request_st * const r, connection * const con)
2090 {
2091     buffer * const b = chunk_buffer_acquire();
2092 
2093     buffer_copy_string_len(b, CONST_STR_LEN(":status: "));
2094     buffer_append_int(b, r->http_status);
2095     for (uint32_t i = 0; i < r->resp_headers.used; ++i) {
2096         const data_string * const ds = (data_string *)r->resp_headers.data[i];
2097 
2098         if (buffer_string_is_empty(&ds->value)) continue;
2099         if (buffer_string_is_empty(&ds->key)) continue;
2100 
2101         buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
2102         buffer_append_string_buffer(b, &ds->key);
2103         buffer_append_string_len(b, CONST_STR_LEN(": "));
2104         buffer_append_string_buffer(b, &ds->value);
2105     }
2106     buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
2107 
2108     h2_send_1xx_block(r, con, CONST_BUF_LEN(b));
2109 
2110     chunk_buffer_release(b);
2111     return 1; /* for http_response_send_1xx_cb */
2112 }
2113 
2114 
2115 void
2116 h2_send_100_continue (request_st * const r, connection * const con)
2117 {
2118     /* 100 Continue is small and will always fit in SETTING_MAX_FRAME_SIZE;
2119      * i.e. there will not be any CONTINUATION frames here */
2120 
2121     /* XXX: need to update hpack dynamic table,
2122      * or else could hard-code header block fragment
2123      * { 0x48, 0x03, 0x31, 0x30, 0x30 }
2124      */
2125 
2126     /* short header block, so reuse shared code used for trailers
2127      * rather than adding something specific for ls-hpack here */
2128 
2129     h2_send_1xx_block(r, con, CONST_STR_LEN(":status: 100\r\n\r\n"));
2130 }
2131 
2132 
2133 static void
2134 h2_send_end_stream_data (request_st * const r, connection * const con);
2135 
2136 __attribute_cold__
2137 __attribute_noinline__
2138 static void
2139 h2_send_end_stream_trailers (request_st * const r, connection * const con, const buffer * const trailers)
2140 {
2141     /*(trailers are merged into response headers if trailers are received before
2142      * sending response headers to client.  However, if streaming response, then
2143      * trailers might need handling here)*/
2144 
2145     /* parse and lowercase field-names in trailers */
2146     unsigned short hoff[8192]; /* max num header lines + 3; 16k on stack */
2147     hoff[0] = 1;                         /* number of lines */
2148     hoff[1] = 0;                         /* base offset for all lines */
2149     /*hoff[2] = ...;*/                   /* offset from base for 2nd line */
2150     uint32_t rc = http_header_parse_hoff(CONST_BUF_LEN(trailers), hoff);
2151     if (0 == rc || rc > USHRT_MAX || hoff[0] >= sizeof(hoff)/sizeof(hoff[0])-1
2152         || 1 == hoff[0]) { /*(initial blank line (should not happen))*/
2153         /* skip trailers if incomplete, too many fields, or too long (> 64k-1)*/
2154         h2_send_end_stream_data(r, con);
2155         return;
2156     }
2157 
2158     char * const ptr = trailers->ptr;
2159     for (int i = 1; i < hoff[0]; ++i) {
2160         char *k = ptr + ((i > 1) ? hoff[i] : 0);
2161         if (*k == ':') {
2162             /*(pseudo-header should not appear in trailers)*/
2163             h2_send_end_stream_data(r, con);
2164             return;
2165         }
2166         const char * const colon = memchr(k, ':', ptr+hoff[i+1]-k);
2167         if (NULL == colon) continue;
2168         do {
2169             if (light_isupper(*k)) *k |= 0x20;
2170         } while (++k != colon);
2171     }
2172 
2173     h2_send_headers_block(r, con, CONST_BUF_LEN(trailers), H2_FLAG_END_STREAM);
2174 }
2175 
2176 
2177 #if 0 /*(replaced by h2_send_headers())*/
2178 void
2179 h2_send_cqheaders (request_st * const r, connection * const con)
2180 {
2181     /*(assumes HTTP/1.1 response headers have been prepended as first chunk)
2182      *(future: if r->write_queue is bypassed for headers, adjust
2183      * r->write_queue bytes counts (bytes_in, bytes_out) with header len)*/
2184     /* note: expects field-names are lowercased (http_response_write_header())*/
2185     chunk * const c = r->write_queue.first;
2186     const uint32_t len = buffer_string_length(c->mem) - (uint32_t)c->offset;
2187     uint32_t flags = (r->resp_body_finished && NULL == c->next)
2188       ? H2_FLAG_END_STREAM
2189       : 0;
2190     h2_send_headers_block(r, con, c->mem->ptr + c->offset, len, flags);
2191     chunkqueue_mark_written(&r->write_queue, len);
2192 }
2193 #endif
2194 
2195 
2196 #if 0
2197 
2198 void
2199 h2_send_data (request_st * const r, connection * const con, const char *data, uint32_t dlen)
2200 {
2201     /* Note: dlen should be <= MAX_WRITE_LIMIT in order to share resources */
2202 
2203     union {
2204       uint8_t c[12];
2205       uint32_t u[3];          /*(alignment)*/
2206     } dataframe = { {         /*(big-endian numbers)*/
2207       0x00, 0x00, 0x00        /* padding for alignment; do not send */
2208       /* DATA */
2209      ,0x00, 0x00, 0x00        /* frame length      (fill in below) */
2210      ,H2_FTYPE_DATA           /* frame type */
2211      ,0x00                    /* frame flags */
2212      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
2213     } };
2214 
2215     dataframe.u[2] = htonl(r->h2id);
2216 
2217     /* XXX: does not provide an optimization to send final set of data with
2218      *      END_STREAM flag; see h2_send_end_stream_data() to end stream */
2219 
2220     /* adjust stream and connection windows */
2221     /*assert(dlen <= INT32_MAX);*//* dlen should be <= MAX_WRITE_LIMIT */
2222     request_st * const h2r = &con->request;
2223     if (r->h2_swin   < 0) return;
2224     if (h2r->h2_swin < 0) return;
2225     if ((int32_t)dlen > r->h2_swin)   dlen = (uint32_t)r->h2_swin;
2226     if ((int32_t)dlen > h2r->h2_swin) dlen = (uint32_t)h2r->h2_swin;
2227     if (0 == dlen) return;
2228     r->h2_swin   -= (int32_t)dlen;
2229     h2r->h2_swin -= (int32_t)dlen;
2230 
2231     /* XXX: future: should have an interface which processes chunkqueue
2232      * and takes string refs to mmap FILE_CHUNK to avoid extra copying
2233      * since the result is likely to be consumed by TLS modules */
2234 
2235     /*(approximate space needed for frames (header + payload)
2236      * with slight over-estimate of 16 bytes per frame header (> 9)
2237      * and minimum SETTING_MAX_FRAME_SIZE of 16k (could be larger)
2238      * (dlen >> 14)+1 is num 16k frames needed, multipled by 16 bytes
2239      *  per frame can be appoximated with (dlen>>10) + 9)*/
2240     buffer * const b =
2241       chunkqueue_append_buffer_open_sz(con->write_queue, dlen + (dlen>>10) + 9);
2242     char * restrict ptr = b->ptr;
2243     h2con * const h2c = con->h2;
2244     const uint32_t fsize = h2c->s_max_frame_size;
2245     do {
2246         const uint32_t len = dlen < fsize ? dlen : fsize;
2247         dataframe.c[3] = (len >> 16) & 0xFF; /*(off +3 to skip over align pad)*/
2248         dataframe.c[4] = (len >>  8) & 0xFF;
2249         dataframe.c[5] = (len      ) & 0xFF;
2250       #if 0
2251         chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
2252                               (const char *)dataframe.c+3, sizeof(dataframe)-3);
2253         chunkqueue_append_mem(con->write_queue, data, len);
2254       #else
2255         memcpy(ptr, dataframe.c+3, sizeof(dataframe)-3);
2256         memcpy(ptr+sizeof(dataframe)-3, data, len);
2257         ptr  += len + sizeof(dataframe)-3;
2258       #endif
2259         data += len;
2260         dlen -= len;
2261     } while (dlen);
2262     buffer_string_set_length(b, (uint32_t)(ptr - b->ptr));
2263     chunkqueue_append_buffer_commit(con->write_queue);
2264 }
2265 
2266 #endif
2267 
2268 
2269 void
2270 h2_send_cqdata (request_st * const r, connection * const con, chunkqueue * const cq, uint32_t dlen)
2271 {
2272     /* Note: dlen should be <= MAX_WRITE_LIMIT in order to share resources */
2273 
2274     union {
2275       uint8_t c[12];
2276       uint32_t u[3];          /*(alignment)*/
2277     } dataframe = { {         /*(big-endian numbers)*/
2278       0x00, 0x00, 0x00        /* padding for alignment; do not send */
2279       /* DATA */
2280      ,0x00, 0x00, 0x00        /* frame length      (fill in below) */
2281      ,H2_FTYPE_DATA           /* frame type */
2282      ,0x00                    /* frame flags */
2283      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
2284     } };
2285 
2286     dataframe.u[2] = htonl(r->h2id);
2287 
2288     /* XXX: does not provide an optimization to send final set of data with
2289      *      END_STREAM flag; see h2_send_end_stream_data() to end stream */
2290 
2291     /* adjust stream and connection windows */
2292     /*assert(dlen <= INT32_MAX);*//* dlen should be <= MAX_WRITE_LIMIT */
2293     request_st * const h2r = &con->request;
2294     if (r->h2_swin   < 0) return;
2295     if (h2r->h2_swin < 0) return;
2296     if ((int32_t)dlen > r->h2_swin)   dlen = (uint32_t)r->h2_swin;
2297     if ((int32_t)dlen > h2r->h2_swin) dlen = (uint32_t)h2r->h2_swin;
2298     if (0 == dlen) return;
2299     r->h2_swin   -= (int32_t)dlen;
2300     h2r->h2_swin -= (int32_t)dlen;
2301 
2302     /* XXX: future: should have an interface which processes chunkqueue
2303      * and takes string refs to mmap FILE_CHUNK to avoid extra copying
2304      * since the result is likely to be consumed by TLS modules */
2305 
2306     h2con * const h2c = con->h2;
2307     const uint32_t fsize = h2c->s_max_frame_size;
2308     do {
2309         const uint32_t len = dlen < fsize ? dlen : fsize;
2310         dataframe.c[3] = (len >> 16) & 0xFF; /*(off +3 to skip over align pad)*/
2311         dataframe.c[4] = (len >>  8) & 0xFF;
2312         dataframe.c[5] = (len      ) & 0xFF;
2313         chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
2314                               (const char *)dataframe.c+3, sizeof(dataframe)-3);
2315         chunkqueue_steal(con->write_queue, cq, (off_t)dlen);
2316         dlen -= len;
2317     } while (dlen);
2318 }
2319 
2320 
2321 static void
2322 h2_send_end_stream_data (request_st * const r, connection * const con)
2323 {
2324     union {
2325       uint8_t c[12];
2326       uint32_t u[3];          /*(alignment)*/
2327     } dataframe = { {         /*(big-endian numbers)*/
2328       0x00, 0x00, 0x00        /* padding for alignment; do not send */
2329       /* DATA */
2330      ,0x00, 0x00, 0x00        /* frame length */
2331      ,H2_FTYPE_DATA           /* frame type */
2332      ,H2_FLAG_END_STREAM      /* frame flags */
2333      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
2334     } };
2335 
2336     dataframe.u[2] = htonl(r->h2id);
2337     r->h2state = H2_STATE_CLOSED;
2338     /*(ignore window updates when sending 0-length DATA frame with END_STREAM)*/
2339     chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
2340                           (const char *)dataframe.c+3, sizeof(dataframe)-3);
2341 }
2342 
2343 
2344 void
2345 h2_send_end_stream (request_st * const r, connection * const con)
2346 {
2347     if (r->state != CON_STATE_ERROR && r->resp_body_finished) {
2348         /* CON_STATE_RESPONSE_END */
2349         if (r->gw_dechunk && r->gw_dechunk->done
2350             && !buffer_is_empty(&r->gw_dechunk->b))
2351             h2_send_end_stream_trailers(r, con, &r->gw_dechunk->b);
2352         else
2353             h2_send_end_stream_data(r, con);
2354     }
2355     else { /* CON_STATE_ERROR */
2356         h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2357     }
2358 }
2359 
2360 
2361 /*
2362  * (XXX: might move below to separate file)
2363  */
2364 #include "base64.h"
2365 #include "chunk.h"
2366 #include "plugin.h"
2367 #include "plugin_config.h"
2368 #include "reqpool.h"
2369 
2370 
2371 static request_st *
2372 h2_init_stream (request_st * const h2r, connection * const con)
2373 {
2374     h2con * const h2c = con->h2;
2375     ++con->request_count;
2376     force_assert(h2c->rused < sizeof(h2c->r)/sizeof(*h2c->r));
2377     /* initialize stream as subrequest (request_st *) */
2378     request_st * const r = request_acquire(con);
2379     /* XXX: TODO: assign default priority, etc.
2380      *      Perhaps store stream id and priority in separate table */
2381     h2c->r[h2c->rused++] = r;
2382     r->h2_rwin = h2c->s_initial_window_size;
2383     r->h2_swin = h2c->s_initial_window_size;
2384     r->http_version = HTTP_VERSION_2;
2385 
2386     /* copy config state from h2r */
2387     server * const srv = con->srv;
2388     const uint32_t used = srv->config_context->used;
2389     r->conditional_is_valid = h2r->conditional_is_valid;
2390     memcpy(r->cond_cache, h2r->cond_cache, used * sizeof(cond_cache_t));
2391   #ifdef HAVE_PCRE_H
2392     if (used > 1) /*(save 128b per con if no conditions)*/
2393         memcpy(r->cond_match, h2r->cond_match, used * sizeof(cond_match_t));
2394   #endif
2395     /*(see config_reset_config())*/
2396     r->server_name = h2r->server_name;
2397     memcpy(&r->conf, &h2r->conf, sizeof(request_config));
2398 
2399     /* stream id must be assigned by caller */
2400     return r;
2401 }
2402 
2403 
2404 static void
2405 h2_release_stream (request_st * const r, connection * const con)
2406 {
2407     if (r->http_status) {
2408         /* (see comment in connection_handle_response_end_state()) */
2409         plugins_call_handle_request_done(r);
2410 
2411       #if 0
2412         /* (fuzzy accounting for mod_accesslog, mod_rrdtool to avoid
2413          *  double counting, but HTTP/2 framing and HPACK-encoded headers in
2414          *  con->read_queue and con->write_queue are not equivalent to the
2415          *  HPACK-decoded headers and request and response bodies in stream
2416          *  r->read_queue and r->write_queue) */
2417         /* DISABLED since mismatches invalidate the relationship between
2418          * con->bytes_in and con->bytes_out */
2419         con->read_queue->bytes_in   -= r->read_queue.bytes_in;
2420         con->write_queue->bytes_out -= r->write_queue.bytes_out;
2421       #else
2422         UNUSED(con);
2423       #endif
2424     }
2425 
2426     request_release(r);
2427 }
2428 
2429 
2430 void
2431 h2_retire_stream (request_st *r, connection * const con)
2432 {
2433     if (r == NULL) return; /*(should not happen)*/
2434     h2con * const h2c = con->h2;
2435     request_st ** const ar = h2c->r;
2436     uint32_t i = 0, rused = h2c->rused;
2437     while (i < rused && ar[i] != r) ++i;
2438     if (i != rused) {
2439         /* swap with last element; might need to revisit if ordered by priority */
2440         /*if (i != --rused) ar[i] = ar[rused];*/
2441         /* shift elements; currently choosing to preserve order requested */
2442         if (i != --rused) memmove(ar+i, ar+i+1, (rused-i)*sizeof(*ar));
2443         h2c->r[(h2c->rused = rused)] = NULL;
2444         h2_release_stream(r, con);
2445     }
2446     /*else ... should not happen*/
2447 }
2448 
2449 
2450 void
2451 h2_retire_con (request_st * const h2r, connection * const con)
2452 {
2453     h2con * const h2c = con->h2;
2454     if (NULL == h2c) return;
2455 
2456     if (h2r->state != CON_STATE_ERROR) { /*(CON_STATE_RESPONSE_END)*/
2457         h2_send_goaway(con, H2_E_NO_ERROR);
2458         for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
2459             /*(unexpected if CON_STATE_RESPONSE_END)*/
2460             request_st * const r = h2c->r[i];
2461             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2462             h2_release_stream(r, con);
2463         }
2464         if (!chunkqueue_is_empty(con->write_queue)) {
2465             /* similar to connection_handle_write() but without error checks,
2466              * without MAX_WRITE_LIMIT, and without connection throttling */
2467             /*h2r->conf.bytes_per_second = 0;*/         /* disable rate limit */
2468             /*h2r->conf.global_bytes_per_second = 0;*/  /* disable rate limit */
2469             /*con->traffic_limit_reached = 0;*/
2470             chunkqueue * const cq = con->write_queue;
2471             const off_t len = chunkqueue_length(cq);
2472             off_t written = cq->bytes_out;
2473             con->network_write(con, cq, len);
2474             /*(optional accounting)*/
2475             written = cq->bytes_out - written;
2476             con->bytes_written += written;
2477             con->bytes_written_cur_second += written;
2478             if (h2r->conf.global_bytes_per_second_cnt_ptr)
2479                 *(h2r->conf.global_bytes_per_second_cnt_ptr) += written;
2480         }
2481     }
2482     else { /* CON_STATE_ERROR */
2483         for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
2484             request_st * const r = h2c->r[i];
2485             h2_release_stream(r, con);
2486         }
2487         /* XXX: perhaps attempt to send GOAWAY?  Not when CON_STATE_ERROR */
2488     }
2489 
2490     con->h2 = NULL;
2491 
2492     /* future: might keep a pool of reusable (h2con *) */
2493     lshpack_enc_cleanup(&h2c->encoder);
2494     lshpack_dec_cleanup(&h2c->decoder);
2495     free(h2c);
2496 }
2497 
2498 
2499 static void
2500 h2_con_upgrade_h2c (request_st * const h2r, const buffer * const http2_settings)
2501 {
2502     /* status: (h2r->state == CON_STATE_REQUEST_END) for Upgrade: h2c */
2503 
2504     /* HTTP/1.1 101 Switching Protocols
2505      * Connection: Upgrade
2506      * Upgrade: h2c
2507      */
2508   #if 1
2509     static const char switch_proto[] = "HTTP/1.1 101 Switching Protocols\r\n"
2510                                        "Connection: Upgrade\r\n"
2511                                        "Upgrade: h2c\r\n\r\n";
2512     chunkqueue_append_mem(&h2r->write_queue,
2513                           CONST_STR_LEN(switch_proto));
2514     h2r->resp_header_len = sizeof(switch_proto)-1;
2515   #else
2516     h2r->http_status = 101;
2517     http_header_response_set(h2r, HTTP_HEADER_UPGRADE, CONST_STR_LEN("Upgrade"),
2518                                                        CONST_STR_LEN("h2c"));
2519     http_response_write_header(h2r);
2520     http_response_reset(h2r);
2521     h2r->http_status = 0;
2522   #endif
2523 
2524     connection * const con = h2r->con;
2525     h2_init_con(h2r, con, http2_settings);
2526     if (con->h2->sent_goaway) return;
2527 
2528     con->h2->h2_cid = 1; /* stream id 1 is assigned to h2c upgrade */
2529 
2530     /* copy request state from &con->request to subrequest r
2531      * XXX: would be nice if there were a cleaner way to do this
2532      * (This is fragile and must be kept in-sync with request_st in request.h)*/
2533 
2534     request_st * const r = h2_init_stream(h2r, con);
2535     /*(undo double-count; already incremented in CON_STATE_REQUEST_START)*/
2536     --con->request_count;
2537     r->state = h2r->state; /* CON_STATE_REQUEST_END */
2538     r->http_status = 0;
2539     r->http_method = h2r->http_method;
2540     r->h2state = H2_STATE_HALF_CLOSED_REMOTE;
2541     r->h2id = 1;
2542     r->rqst_htags = h2r->rqst_htags;
2543     h2r->rqst_htags = 0;
2544     r->rqst_header_len = h2r->rqst_header_len;
2545     h2r->rqst_header_len = 0;
2546     r->rqst_headers = h2r->rqst_headers;        /* copy struct */
2547     memset(&h2r->rqst_headers, 0, sizeof(array));
2548     r->uri = h2r->uri;                          /* copy struct */
2549   #if 0
2550     r->physical = h2r->physical;                /* copy struct */
2551     r->env = h2r->env;                          /* copy struct */
2552   #endif
2553     memset(&h2r->rqst_headers, 0, sizeof(array));
2554     memset(&h2r->uri, 0, sizeof(request_uri));
2555   #if 0
2556     memset(&h2r->physical, 0, sizeof(physical));
2557     memset(&h2r->env, 0, sizeof(array));
2558   #endif
2559   #if 0 /* expect empty request body */
2560     r->reqbody_length = h2r->reqbody_length; /* currently always 0 */
2561     r->te_chunked = h2r->te_chunked;         /* must be 0 */
2562     swap(&r->reqbody_queue,&h2r->reqbody_queue);/*currently always empty queue*/
2563   #endif
2564     r->http_host = h2r->http_host;
2565     h2r->http_host = NULL;
2566   #if 0
2567     r->server_name = h2r->server_name;
2568     h2r->server_name = NULL;
2569   #endif
2570     r->target = h2r->target;                    /* copy struct */
2571     r->target_orig = h2r->target_orig;          /* copy struct */
2572   #if 0
2573     r->pathinfo = h2r->pathinfo;                /* copy struct */
2574     r->server_name_buf = h2r->server_name_buf;  /* copy struct */
2575   #endif
2576     memset(&h2r->target, 0, sizeof(buffer));
2577     memset(&h2r->target_orig, 0, sizeof(buffer));
2578   #if 0
2579     memset(&h2r->pathinfo, 0, sizeof(buffer));
2580     memset(&h2r->server_name_buf, 0, sizeof(buffer));
2581   #endif
2582   #if 0
2583     /* skip copying response structures, other state not yet modified in h2r */
2584     /* r write_queue and read_queue are intentionally separate from h2r */
2585     /* r->gw_dechunk must be NULL for HTTP/2 */
2586     /* bytes_written_ckpt and bytes_read_ckpt are for HTTP/1.1 */
2587     /* error handlers have not yet been set */
2588   #endif
2589   #if 0
2590     r->loops_per_request = h2r->loops_per_request;
2591     r->async_callback = h2r->async_callback;
2592   #endif
2593     r->keep_alive = h2r->keep_alive;
2594     r->tmp_buf = h2r->tmp_buf;                /* shared; same as srv->tmp_buf */
2595     r->start_hp = h2r->start_hp;                /* copy struct */
2596 
2597     /* Note: HTTP/1.1 101 Switching Protocols is not immediately written to
2598      * the network here.  As this is called from cleartext Upgrade: h2c,
2599      * we choose to delay sending the status until the beginning of the response
2600      * to the HTTP/1.1 request which included Upgrade: h2c */
2601 }
2602 
2603 
2604 int
2605 h2_check_con_upgrade_h2c (request_st * const r)
2606 {
2607     /* RFC7540 3.2 Starting HTTP/2 for "http" URIs */
2608 
2609     buffer *http_connection, *http2_settings;
2610     buffer *upgrade = http_header_request_get(r, HTTP_HEADER_UPGRADE,
2611                                               CONST_STR_LEN("Upgrade"));
2612     if (NULL == upgrade) return 0;
2613     http_connection = http_header_request_get(r, HTTP_HEADER_CONNECTION,
2614                                               CONST_STR_LEN("Connection"));
2615     if (NULL == http_connection) {
2616         http_header_request_unset(r, HTTP_HEADER_UPGRADE,
2617                                   CONST_STR_LEN("Upgrade"));
2618         return 0;
2619     }
2620     if (r->http_version != HTTP_VERSION_1_1) {
2621         http_header_request_unset(r, HTTP_HEADER_UPGRADE,
2622                                   CONST_STR_LEN("Upgrade"));
2623         http_header_remove_token(http_connection, CONST_STR_LEN("Upgrade"));
2624         return 0;
2625     }
2626 
2627     if (!http_header_str_contains_token(CONST_BUF_LEN(upgrade),
2628                                         CONST_STR_LEN("h2c")))
2629         return 0;
2630 
2631     http2_settings = http_header_request_get(r, HTTP_HEADER_HTTP2_SETTINGS,
2632                                              CONST_STR_LEN("HTTP2-Settings"));
2633     if (NULL != http2_settings) {
2634         if (0 == r->reqbody_length) {
2635             buffer * const b = r->tmp_buf;
2636             buffer_clear(b);
2637             if (r->conf.h2proto > 1/*(must be enabled with server.h2c feature)*/
2638                 &&
2639                 http_header_str_contains_token(CONST_BUF_LEN(http_connection),
2640                                                CONST_STR_LEN("HTTP2-Settings"))
2641                 && buffer_append_base64_decode(b, CONST_BUF_LEN(http2_settings),
2642                                                BASE64_URL)) {
2643                 h2_con_upgrade_h2c(r, b);
2644                 r->http_version = HTTP_VERSION_2;
2645             } /* else ignore if invalid base64 */
2646         }
2647         else {
2648             /* ignore Upgrade: h2c if request body present since we do not
2649              * (currently) handle request body before transition to h2c */
2650             /* RFC7540 3.2 Requests that contain a payload body MUST be sent
2651              * in their entirety before the client can send HTTP/2 frames. */
2652         }
2653         http_header_request_unset(r, HTTP_HEADER_HTTP2_SETTINGS,
2654                                   CONST_STR_LEN("HTTP2-Settings"));
2655         http_header_remove_token(http_connection, CONST_STR_LEN("HTTP2-Settings"));
2656     } /* else ignore Upgrade: h2c; HTTP2-Settings required for Upgrade: h2c */
2657     http_header_request_unset(r, HTTP_HEADER_UPGRADE,
2658                               CONST_STR_LEN("Upgrade"));
2659     http_header_remove_token(http_connection, CONST_STR_LEN("Upgrade"));
2660     return (r->http_version == HTTP_VERSION_2);
2661 }
2662