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