xref: /lighttpd1.4/src/h2.c (revision 2f7839e8)
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     /* move data to beginning of buffer if offset is large or data is short */
900     chunk *c = cq->first;
901     uint32_t mlen = buffer_string_length(c->mem);
902     if (mlen < c->offset) {
903         memmove(c->mem->ptr, c->mem->ptr + c->offset, mlen);
904         buffer_string_set_length(c->mem, mlen);
905         c->offset = 0;
906     }
907 
908     /* combine first mem chunk with next non-empty mem chunks up to len
909      * (loop if next chunk is empty) */
910     /* (modified from connection_handle_read_post_cq_compact()) */
911     uint32_t clen = mlen;
912     do {
913         buffer * const mem = c->next->mem;
914         const off_t offset = c->next->offset;
915         mlen = buffer_string_length(mem) - (uint32_t)offset;
916         force_assert(c->type == MEM_CHUNK);
917         force_assert(c->next->type == MEM_CHUNK);
918         if (mlen > clen - len) {
919             mlen = clen - len;
920             buffer_append_string_len(c->mem, mem->ptr+offset, mlen);
921             c->next->offset += mlen;
922             return len;
923         }
924 
925         buffer_append_string_len(c->mem, mem->ptr+offset, mlen);
926         clen += mlen;
927         /*(swap first and second chunk, then remove first chunk)*/
928         c->next->offset = c->offset;
929         c->next->mem = c->mem;
930         c->mem = mem;
931         c->offset = offset + (off_t)mlen;
932         chunkqueue_remove_finished_chunks(cq);
933     } while ((c = cq->first)); /*(need to re-read cq->first)*/
934     return clen;
935 }
936 
937 
938 __attribute_cold__
939 static uint32_t
940 h2_recv_continuation (uint32_t n, uint32_t clen, const off_t cqlen, chunkqueue * const cq, connection * const con)
941 {
942     chunk *c = cq->first;
943     uint8_t *s = (uint8_t *)(c->mem->ptr + c->offset);
944     uint32_t m = n;
945     uint32_t flags;
946     h2con * const h2c = con->h2;
947     const uint32_t fsize = h2c->s_max_frame_size;
948     const uint32_t id =
949       ((s[5] << 24) | (s[6] << 16) | (s[7] << 8) | s[8]) & ~0x80000000u;
950     do {
951         if (cqlen < n+9) return n+9; /* incomplete frame; go on */
952         if (clen < n+9) {
953             clen = h2_frame_cq_compact(cq, n+9);
954             c = cq->first; /*(reload after h2_frame_cq_compact())*/
955             s = (uint8_t *)(c->mem->ptr + c->offset);
956         }
957         if (s[n+3] != H2_FTYPE_CONTINUATION) {
958             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
959             return 0;
960         }
961         flags = s[n+4];
962         const uint32_t flen = (s[n+0]<<16)|(s[n+1]<<8)|s[n+2];
963         if (id != (uint32_t)((s[n+5]<<24)|(s[n+6]<<16)|(s[n+7]<<8)|s[n+8])) {
964             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
965             return 0;
966         }
967         if (flen > fsize) {
968             h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
969             return 0;
970         }
971         n += 9+flen;
972         if (n >= 65536) { /*(very oversized for hpack)*/
973             h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
974             return 0;
975         }
976         if (clen < n) {
977             clen = h2_frame_cq_compact(cq, n);
978             c = cq->first; /*(reload after h2_frame_cq_compact())*/
979             s = (uint8_t *)(c->mem->ptr + c->offset);
980         }
981     } while (!(flags & H2_FLAG_END_HEADERS));
982 
983     /* If some CONTINUATION frames were concatenated to earlier frames while
984      * processing above, but END_HEADERS were not received, then the next time
985      * data was read, initial frame size might exceed SETTINGS_MAX_FRAME_SIZE.
986      * (This describes the current lighttpd implementation in h2_parse_frames())
987      * While a flag could be set and checked to avoid this, such situations of
988      * large HEADERS (and CONTINUATION) across multiple network reads is
989      * expected to be rare.  Reparse and concatenate below.
990      *
991      * Aside: why would the authors of RFC 7540 go through the trouble of
992      * creating a CONTINUATION frame that must be special-cased when use of
993      * CONTINUATION is so restricted e.g. no other intervening frames and
994      * that HEADERS and PUSH_PROMISE HPACK must be parsed as a single block?
995      * IMHO, it would have been simpler to avoid CONTINUATION entirely, and have
996      * a special-case for HEADERS and PUSH_PROMISE to be allowed to exceed
997      * SETTINGS_MAX_FRAME_SIZE with implementations providing a different limit.
998      * While intermediates would not know such a limit of origin servers,
999      * there could have been a reasonable default set with a different SETTINGS
1000      * parameter aimed just at HEADERS and PUSH_PROMISE.  The parameter
1001      * SETTINGS_MAX_HEADER_LIST_SIZE could even have been (re)used, had it been
1002      * given a reasonable initial value instead of "unlimited", since HPACK
1003      * encoded headers are smaller than the HPACK decoded headers to which the
1004      * limit SETTINGS_MAX_HEADER_LIST_SIZE applies. */
1005 
1006     n = m; /* reset n to beginning of first CONTINUATION frame */
1007 
1008     /* Eliminate padding from first frame (HEADERS or PUSH_PROMISE) if PADDED */
1009     if (s[4] & H2_FLAG_PADDED) {
1010         const uint32_t plen = s[9];
1011         /* validate padding */
1012         const uint32_t flen = (s[0]<<16)|(s[1]<<8)|s[2];
1013         if (flen < 1 + plen + ((s[n+4] & H2_FLAG_PRIORITY) ? 5 : 0)) {
1014             /* Padding that exceeds the size remaining for the header block
1015              * fragment MUST be treated as a PROTOCOL_ERROR. */
1016             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1017             return 0;
1018         }
1019         /* set padding to 0 since we will overwrite padding in merge below */
1020         /* (alternatively, could memmove() 9 bytes of frame header over the
1021          *  pad length octet, remove PADDED flag, add 1 to c->offset,
1022          *  add 1 to s, subtract 1 from clen and substract 1 from cqlen,
1023          *  substract 1 from n, add 1 to cq->bytes_out) */
1024         s[9] = 0;
1025         /* set offset to beginning of padding at end of first frame */
1026         m -= plen;
1027         /* XXX: layer violation; adjusts chunk.c internal accounting */
1028         cq->bytes_out += plen;
1029     }
1030 
1031     do {
1032         const uint32_t flen = (s[n+0]<<16)|(s[n+1]<<8)|s[n+2];
1033         flags = s[n+4];
1034         memmove(s+m, s+n+9, flen);
1035         m += flen;
1036         n += 9+flen;
1037         /* XXX: layer violation; adjusts chunk.c internal accounting */
1038         cq->bytes_out += 9;
1039     } while (!(flags & H2_FLAG_END_HEADERS));
1040     /* overwrite frame size */
1041     m -= 9; /*(temporarily remove frame header from len)*/
1042     s[0] = (m >> 16) & 0xFF;
1043     s[1] = (m >>  8) & 0xFF;
1044     s[2] = (m      ) & 0xFF;
1045     m += 9;
1046     /* adjust chunk c->mem */
1047     if (n < clen) { /*(additional frames after CONTINUATION)*/
1048         memmove(s+m, s+n, clen-n);
1049         n = m + (clen-n);
1050     }
1051     else
1052         n = m;
1053     buffer_string_set_length(c->mem, n + (uint32_t)c->offset);
1054 
1055     return m;
1056 }
1057 
1058 
1059 __attribute_cold__
1060 static request_st *
1061 h2_recv_trailers_r (connection * const con, h2con * const h2c, const uint32_t id, const uint32_t flags)
1062 {
1063     /* rant: RFC 7230 HTTP/1.1 trailer-part would have been much simpler
1064      * to support in RFC 7540 HTTP/2 as a distinct frame type rather than
1065      * HEADERS.  As trailers are not known at the time the request is made,
1066      * reuse of such trailers is limited and so a theoretical TRAILERS frame
1067      * could have been implemented without HPACK encoding, and would have
1068      * been more straightforward to implement than overloading and having to
1069      * handle multiple cases for HEADERS.  TRAILERS support could then also
1070      * be optional, like in HTTP/1.1 */
1071     request_st *r = NULL;
1072     for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
1073         request_st * const rr = h2c->r[i];
1074         if (rr->h2id != id) continue;
1075         r = rr;
1076         break;
1077     }
1078     if (NULL == r) {
1079         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1080         return NULL;
1081     }
1082     if (r->h2state != H2_STATE_OPEN
1083         && r->h2state != H2_STATE_HALF_CLOSED_LOCAL) {
1084         h2_send_rst_stream(r, con, H2_E_STREAM_CLOSED);
1085         return NULL;
1086     }
1087     /* RFC 7540 is not explicit in restricting HEADERS (trailers) following
1088      * (optional) DATA frames, but in following HTTP/1.1, we limit to single
1089      * (optional) HEADERS (+ CONTINUATIONs) after (optional) DATA frame(s)
1090      * and require that the HEADERS frame set END_STREAM flag. */
1091     if (!(flags & H2_FLAG_END_STREAM)) {
1092         h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
1093         return NULL;
1094     }
1095 
1096     return h2_recv_end_data(r, con, 0) ? r : NULL;
1097 }
1098 
1099 
1100 static void
1101 h2_parse_headers_frame (request_st * const restrict r, const unsigned char *psrc, const uint32_t plen, const int trailers)
1102 {
1103     h2con * const h2c = r->con->h2;
1104     struct lshpack_dec * const restrict decoder = &h2c->decoder;
1105     const unsigned char * const endp = psrc + plen;
1106     http_header_parse_ctx hpctx;
1107     hpctx.hlen     = 0;
1108     hpctx.pseudo   = 1;
1109     hpctx.scheme   = 0;
1110     hpctx.trailers = trailers;
1111     hpctx.max_request_field_size = r->conf.max_request_field_size;
1112     hpctx.http_parseopts = r->conf.http_parseopts;
1113     const int log_request_header = r->conf.log_request_header;
1114     int rc = LSHPACK_OK;
1115     /*buffer_clear(&r->target);*//*(initial state)*/
1116 
1117     /*(h2_init_con() resized h2r->tmp_buf to 64k; shared with r->tmp_buf)*/
1118     buffer * const tb = r->tmp_buf;
1119     force_assert(tb->size >= 65536);/*(sanity check; remove in future)*/
1120     const lsxpack_strlen_t tbsz = (tb->size <= LSXPACK_MAX_STRLEN)
1121       ? tb->size
1122       : LSXPACK_MAX_STRLEN;
1123 
1124     /* note: #define LSHPACK_DEC_HTTP1X_OUTPUT 1 (default) configures
1125      * decoder to produce output in format: "field-name: value\r\n"
1126      * future: modify build system to define value to 0 in lshpack.h
1127      * against which lighttpd builds (or define value in build systems)
1128      * Then adjust code below to not use the HTTP/1.x compatibility,
1129      * as it is less efficient to copy into HTTP/1.1 request and reparse
1130      * than it is to directly parse each decoded header line. */
1131     lsxpack_header_t lsx;
1132     while (psrc < endp) {
1133         memset(&lsx, 0, sizeof(lsxpack_header_t));
1134         lsx.buf = tb->ptr;
1135         lsx.val_len = tbsz;
1136         rc = lshpack_dec_decode(decoder, &psrc, endp, &lsx);
1137         if (0 == lsx.name_len)
1138             rc = LSHPACK_ERR_BAD_DATA;
1139         if (rc == LSHPACK_OK) {
1140             hpctx.k = lsx.buf+lsx.name_offset;
1141             hpctx.v = lsx.buf+lsx.val_offset;
1142             hpctx.klen = lsx.name_len;
1143             hpctx.vlen = lsx.val_len;
1144             /*assert(lsx.hpack_index < sizeof(lshpack_idx_http_header));*/
1145             hpctx.id = lshpack_idx_http_header[lsx.hpack_index];
1146 
1147             if (log_request_header)
1148                 log_error(r->conf.errh, __FILE__, __LINE__,
1149                   "fd:%d id:%u rqst: %.*s: %.*s", r->con->fd, r->h2id,
1150                   (int)hpctx.klen, hpctx.k, (int)hpctx.vlen, hpctx.v);
1151 
1152           #if 0
1153             /* might not be worth special-casing pseudo headers here and
1154              * repeating the code in http_request_parse_header() to avoid
1155              * memcmp() for pseudo headers (request.c does not know ls-hpack)*/
1156             if (hpctx.pseudo && lsx.hpack_index
1157                 && lsx.hpack_index < LSHPACK_HDR_STATUS_200 && !trailers) {
1158                 /* lsx.hpack_index:
1159                  *   LSHPACK_HDR_AUTHORITY
1160                  *   LSHPACK_HDR_METHOD_GET
1161                  *   LSHPACK_HDR_METHOD_POST
1162                  *   LSHPACK_HDR_PATH
1163                  *   LSHPACK_HDR_PATH_INDEX_HTML
1164                  *   LSHPACK_HDR_SCHEME_HTTP
1165                  *   LSHPACK_HDR_SCHEME_HTTPS
1166                  */
1167             }
1168           #endif
1169 
1170             r->http_status = http_request_parse_header(r, &hpctx);
1171             if (0 != r->http_status)
1172                 break;
1173         }
1174       #if 0 /*(see catch-all below)*/
1175         /* Send GOAWAY (further below) (decoder state not maintained on error)
1176          * (see comments above why decoder state must be maintained) */
1177         /* XXX: future: could try to send :status 431 here
1178          * and reset other active streams in H2_STATE_OPEN */
1179         else if (rc == LSHPACK_ERR_MORE_BUF) {
1180             /* XXX: TODO if (r->conf.log_request_header_on_error) */
1181             r->http_status = 431; /* Request Header Fields Too Large */
1182             /*(try to avoid reading/buffering more data for this request)*/
1183             r->h2_rwin = 0; /*(out-of-sync with peer, but is error case)*/
1184             /*r->h2state = H2_STATE_HALF_CLOSED_REMOTE*/
1185             /* psrc was not advanced if LSHPACK_ERR_MORE_BUF;
1186              * processing must stop (since not retrying w/ larger buf)*/
1187             break;
1188         }
1189       #endif
1190         else { /* LSHPACK_ERR_BAD_DATA */
1191             /* GOAWAY with H2_E_PROTOCOL_ERROR is not specific enough
1192              * to tell peer to not retry request, so send RST_STREAM
1193              * (slightly more specific, but not by much) before GOAWAY*/
1194             /* LSHPACK_ERR_MORE_BUF is treated as an attack, send GOAWAY
1195              * (h2r->tmp_buf was resized to 64k in h2_init_con()) */
1196             request_h2error_t err = H2_E_COMPRESSION_ERROR;
1197             if (rc != LSHPACK_ERR_BAD_DATA) {
1198                 /* LSHPACK_ERR_TOO_LARGE, LSHPACK_ERR_MORE_BUF */
1199                 err = H2_E_PROTOCOL_ERROR;
1200                 h2_send_rst_stream(r, r->con, err);
1201             }
1202             if (!h2c->sent_goaway && !trailers)
1203                 h2c->h2_cid = r->h2id;
1204             h2_send_goaway_e(r->con, err);
1205             if (!trailers) {
1206                 h2_retire_stream(r, r->con);
1207                 return;
1208             }
1209             else {
1210                 r->state = CON_STATE_ERROR;
1211                 r->h2state = H2_STATE_CLOSED;
1212             }
1213             break;
1214         }
1215     }
1216 
1217     hpctx.hlen += 2;
1218     r->rqst_header_len += hpctx.hlen;
1219     /*(accounting for mod_accesslog and mod_rrdtool)*/
1220     chunkqueue * const rq = &r->read_queue;
1221     rq->bytes_in  += (off_t)hpctx.hlen;
1222     rq->bytes_out += (off_t)hpctx.hlen;
1223 
1224     if (0 == r->http_status && LSHPACK_OK == rc) {
1225         if (hpctx.pseudo)
1226             r->http_status =
1227               http_request_validate_pseudohdrs(r, hpctx.scheme,
1228                                                hpctx.http_parseopts);
1229         if (0 == r->http_status)
1230             http_request_headers_process_h2(r, r->con->proto_default_port);
1231     }
1232 }
1233 
1234 
1235 static int
1236 h2_recv_headers (connection * const con, uint8_t * const s, uint32_t flen)
1237 {
1238     request_st *r = NULL;
1239     h2con * const h2c = con->h2;
1240     const uint32_t id =
1241       ((s[5] << 24) | (s[6] << 16) | (s[7] << 8) | s[8]) & ~0x80000000u;
1242     if (0 == id) { /* HEADERS, PUSH_PROMISE stream id must != 0 */
1243         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1244         return 0;
1245     }
1246     if (!(id & 1)) { /* stream id from client must be odd */
1247         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1248         return 0;
1249     }
1250 
1251     request_st * const h2r = &con->request;
1252     int trailers = 0;
1253 
1254     if (id > h2c->h2_cid) {
1255         if (h2c->rused == sizeof(h2c->r)/sizeof(*h2c->r)) {
1256             if (0 == h2c->sent_settings) { /*(see h2_recv_settings() comments)*/
1257                 /* too many active streams; refuse new stream */
1258                 h2c->h2_cid = id;
1259                 h2_send_rst_stream_id(id, con, H2_E_REFUSED_STREAM);
1260                 return 1;
1261             }
1262             else {
1263                 /* alternative: stop processing frames and defer processing this
1264                  * HEADERS frame until num active streams drops below limit.
1265                  * lighttpd sends SETTINGS_MAX_CONCURRENT_STREAMS <limit> with
1266                  * server Connection Preface, so a well-behaved client will
1267                  * adjust after it sends its initial requests.
1268                  * (e.g. h2load -n 100 -m 100 sends 100 requests upon connect)*/
1269                 return -1;
1270             }
1271         }
1272         /* Note: MUST process HPACK decode even if already sent GOAWAY.
1273          * This is necessary since there may be active streams not in
1274          * H2_STATE_HALF_CLOSED_REMOTE, e.g. H2_STATE_OPEN, still possibly
1275          * receiving DATA and, more relevantly, still might receive HEADERS
1276          * frame with trailers, for which the decoder state is required.
1277          * XXX: future might try to reduce other processing done if sent
1278          *      GOAWAY, e.g. might avoid allocating (request_st *r) */
1279         r = h2_init_stream(h2r, con);
1280         r->h2id = id;
1281         r->h2state = (s[4] & H2_FLAG_END_STREAM)
1282           ? H2_STATE_HALF_CLOSED_REMOTE
1283           : H2_STATE_OPEN;
1284         r->state = CON_STATE_REQUEST_END;
1285         /* Note: timestamps here are updated only after receipt of entire header
1286          * (HEADERS frame might have been sent in multiple packets
1287          *  and CONTINUATION frames may have been sent in multiple packets)
1288          * (affects high precision timestamp, if enabled)
1289          * (large sets of headers are not typical, and even when they do
1290          *  occur, they will typically be sent within the same second)
1291          * (future: might keep high precision timestamp in h2con when first
1292          *  packet of HEADERS or PUSH_PROMISE is received, and clear that
1293          *  timestamp when frame + CONTINUATION(s) are complete (so that
1294          *  re-read of initial frame does not overwrite the timestamp))
1295          */
1296         r->start_hp.tv_sec = log_epoch_secs;
1297         if (r->conf.high_precision_timestamps)
1298             log_clock_gettime_realtime(&r->start_hp);
1299     }
1300     else {
1301         r = h2_recv_trailers_r(con, h2c, id, s[4]); /* (cold code path) */
1302         if (NULL == r)
1303             return (h2c->sent_goaway > 0) ? 0 : 1;
1304         trailers = 1;
1305     }
1306 
1307     const unsigned char *psrc = s + 9;
1308     uint32_t alen = flen;
1309     if (s[4] & H2_FLAG_PADDED) {
1310         ++psrc;
1311         const uint32_t pad = s[9];
1312         if (flen < 1 + pad + ((s[4] & H2_FLAG_PRIORITY) ? 5 : 0)) {
1313             /* Padding that exceeds the size remaining for the header block
1314              * fragment MUST be treated as a PROTOCOL_ERROR. */
1315             h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1316             if (!trailers)
1317                 h2_retire_stream(r, con);
1318             else {
1319                 r->state = CON_STATE_ERROR;
1320                 r->h2state = H2_STATE_CLOSED;
1321             }
1322             return 0;
1323         }
1324         alen -= (1 + pad); /*(alen is adjusted for PRIORITY below)*/
1325     }
1326     if (s[4] & H2_FLAG_PRIORITY) {
1327         /* XXX: TODO: handle PRIORITY (prio fields start at *psrc) */
1328         const uint32_t prio =
1329           ((psrc[0]<<24)|(psrc[1]<<16)|(psrc[2]<<8)|psrc[3]) & ~0x80000000u;
1330         if (prio == id) {
1331             h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
1332             if (!trailers)
1333                 h2_retire_stream(r, con);
1334             return 1;
1335         }
1336       #if 0
1337         uint32_t exclusive_dependency = (psrc[0] & 0x80) ? 1 : 0;
1338         uint32_t weight = psrc[4];
1339       #endif
1340         psrc += 5;
1341         alen -= 5;
1342     }
1343 
1344     h2_parse_headers_frame(r, psrc, alen, trailers);
1345 
1346   #if 0 /*(handled in h2_parse_frames() as a connection error)*/
1347     /* not handled here:
1348      * r is invalid if h2_parse_headers_frame() HPACK decode error */
1349     if (s[3] == H2_FTYPE_PUSH_PROMISE && !trailers) {
1350         /* Had to process HPACK to keep HPACK tables sync'd with peer but now
1351          * discard the request if PUSH_PROMISE, since not expected, as this code
1352          * is running as a server, not as a client.
1353          * XXX: future might try to reduce other processing done if
1354          * discarding, e.g. might avoid allocating (request_st *r) */
1355         /* rant: PUSH_PROMISE could have been a flag on HEADERS frame
1356          *       instead of an independent frame type */
1357         r->http_status = 0;
1358         h2_retire_stream(r, con);
1359     }
1360   #endif
1361 
1362     if (!h2c->sent_goaway) {
1363         h2c->h2_cid = id;
1364         if (!light_btst(r->rqst_htags, HTTP_HEADER_CONTENT_LENGTH))
1365             r->reqbody_length = (s[4] & H2_FLAG_END_STREAM) ? 0 : -1;
1366       #if 0
1367         else if (r->reqbody_length > 0 && (s[4] & H2_FLAG_END_STREAM)) {
1368             /*(handled in connection_handle_read_post_state())*/
1369             /* XXX: TODO if (r->conf.log_request_header_on_error) */
1370             r->http_status = 400; /* Bad Request */
1371         }
1372       #endif
1373 
1374         /* RFC 7540 Section 8. HTTP Message Exchanges
1375          * 8.1.2.6. Malformed Requests and Responses
1376          *   For malformed requests, a server MAY send an HTTP
1377          *   response prior to closing or resetting the stream.
1378          * However, h2spec expects stream PROTOCOL_ERROR.
1379          * (This is unfortunate, since we would rather send
1380          *  400 Bad Request which tells client *do not* retry
1381          *  the bad request without modification)
1382          * https://github.com/summerwind/h2spec/issues/120
1383          * https://github.com/summerwind/h2spec/issues/121
1384          * https://github.com/summerwind/h2spec/issues/122
1385          */
1386       #if 0
1387         if (400 == r->http_status && !trailers) {
1388             h2_send_rst_stream(r, con, H2_E_PROTOCOL_ERROR);
1389             h2_retire_stream(r, con);
1390         }
1391       #endif
1392     }
1393     else if (h2c->h2_cid < id) {
1394         /* Had to process HPACK to keep HPACK tables sync'd with peer
1395          * but now discard the request if id is after id sent in GOAWAY.
1396          * XXX: future might try to reduce other processing done if
1397          * discarding, e.g. might avoid allocating (request_st *r) */
1398         r->http_status = 0;
1399         h2_retire_stream(r, con);
1400     }
1401 
1402     return 1;
1403 }
1404 
1405 
1406 int
1407 h2_parse_frames (connection * const con)
1408 {
1409     /* read and process HTTP/2 frames from socket */
1410     h2con * const h2c = con->h2;
1411     chunkqueue * const cq = con->read_queue;
1412     /* initial max frame size is the minimum: 16k
1413      * (lighttpd does not currently increase max frame size)
1414      * (lighttpd does not currently decrease max frame size)
1415      * (XXX: If SETTINGS_MAX_FRAME_SIZE were increased and then decreased,
1416      *       should accept the larger frame size until SETTINGS is ACK'd) */
1417     const uint32_t fsize = h2c->s_max_frame_size;
1418     for (off_t cqlen = chunkqueue_length(cq); cqlen >= 9; ) {
1419         chunk *c = cq->first;
1420         /*assert(c->type == MEM_CHUNK);*/
1421         /* copy data if frame header crosses chunk boundary
1422          * future: be more efficient than blind full chunk copy */
1423         uint32_t clen = buffer_string_length(c->mem) - c->offset;
1424         if (clen < 9) {
1425             clen = h2_frame_cq_compact(cq, 9);
1426             c = cq->first; /*(reload after h2_frame_cq_compact())*/
1427         }
1428         uint8_t *s = (uint8_t *)(c->mem->ptr + c->offset);
1429         uint32_t flen = (s[0] << 16) | (s[1] << 8) | s[2];
1430         if (flen > fsize) {
1431             h2_send_goaway_e(con, H2_E_FRAME_SIZE_ERROR);
1432             return 0;
1433         }
1434 
1435         /*(handle PUSH_PROMISE as connection error further below)*/
1436         /*if (s[3] == H2_FTYPE_HEADERS || s[3] == H2_FTYPE_PUSH_PROMISE)*/
1437 
1438         if (s[3] == H2_FTYPE_HEADERS) {
1439             if (cqlen < 9+flen) return 1; /* incomplete frame; go on */
1440             if (clen < 9+flen) {
1441                 clen = h2_frame_cq_compact(cq, 9+flen);
1442                 c = cq->first; /*(reload after h2_frame_cq_compact())*/
1443                 s = (uint8_t *)(c->mem->ptr + c->offset);
1444             }
1445 
1446             if (!(s[4] & H2_FLAG_END_HEADERS)) {
1447                 /* collect CONTINUATION frames (cold code path) */
1448                 /* note: h2_recv_continuation() return value is overloaded
1449                  * and the resulting clen is 9+flen of *concatenated* frames */
1450                 clen = h2_recv_continuation(9+flen, clen, cqlen, cq, con);
1451                 if (0 == clen)    return 0;
1452                 if (cqlen < clen) return 1; /* incomplete frames; go on */
1453                 c = cq->first; /*(reload after h2_recv_continuation())*/
1454                 s = (uint8_t *)(c->mem->ptr + c->offset);
1455                 /* frame size was also updated and might (legitimately)
1456                  * exceed SETTINGS_MAX_FRAME_SIZE, so do not test fsize again */
1457                 flen = (s[0]<<16)|(s[1]<<8)|s[2];
1458                 /* recalculate after CONTINUATION removed */
1459                 cqlen = chunkqueue_length(cq);
1460             }
1461 
1462             int rc = h2_recv_headers(con, s, flen);
1463             cqlen -= (9+flen);
1464             if (rc >= 0)
1465                 chunkqueue_mark_written(cq, 9+flen);
1466             if (rc <= 0)
1467                 return 0;
1468             con->read_idle_ts = log_epoch_secs;
1469         }
1470         else if (s[3] == H2_FTYPE_DATA) {
1471             /* future: might try to stream data for incomplete frames,
1472              * but that would require keeping additional state for partially
1473              * read frames, including cleaning up if errors occur.
1474              * Since well-behaved clients do not intentionally send partial
1475              * frames, and try to resend if socket buffers are full, this is
1476              * probably not a big concern in practice. */
1477             if (cqlen < 9+flen) return 1; /* incomplete frame; go on */
1478             con->read_idle_ts = log_epoch_secs;
1479             /*(h2_recv_data() must consume frame from cq or else return 0)*/
1480             if (!h2_recv_data(con, s, flen))
1481                 return 0;
1482             cqlen -= (9+flen);
1483         }
1484         else {
1485             /* frame types below are expected to be small
1486              * most frame types below have fixed (small) size
1487              *   4 bytes - WINDOW_UPDATE
1488              *   5 bytes - PRIORITY
1489              *   8 bytes - PING
1490              *   4 bytes - RST_STREAM
1491              * some are variable size
1492              *     SETTINGS (6 * #settings; 6 defined in RFC 7540 Section 6.5)
1493              *     GOAWAY   (8 + optional additional debug data (variable))
1494              * XXX: might add sanity check for a max flen here,
1495              *      before waiting to read partial frame
1496              *      (fsize limit is still enforced above for all frames)
1497              */
1498             if (cqlen < 9+flen) return 1; /* incomplete frame; go on */
1499             if (clen < 9+flen) {
1500                 clen = h2_frame_cq_compact(cq, 9+flen);
1501                 c = cq->first; /*(reload after h2_frame_cq_compact())*/
1502                 s = (uint8_t *)(c->mem->ptr + c->offset);
1503             }
1504             switch (s[3]) { /* frame type */
1505               case H2_FTYPE_WINDOW_UPDATE:
1506                 h2_recv_window_update(con, s, flen);
1507                 break;
1508               case H2_FTYPE_PRIORITY:
1509                 h2_recv_priority(con, s, flen);
1510                 break;
1511               case H2_FTYPE_SETTINGS:
1512                 h2_recv_settings(con, s, flen);
1513                 break;
1514               case H2_FTYPE_PING:
1515                 h2_recv_ping(con, s, flen);
1516                 break;
1517               case H2_FTYPE_RST_STREAM:
1518                 h2_recv_rst_stream(con, s, flen);
1519                 break;
1520               case H2_FTYPE_GOAWAY:
1521                 if (!h2_recv_goaway(con, s, flen)) return 0;
1522                 break;
1523               case H2_FTYPE_PUSH_PROMISE: /*not expected from client*/
1524               case H2_FTYPE_CONTINUATION: /*handled with HEADERS*/
1525                 h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1526                 return 0;
1527               default: /* ignore unknown frame types */
1528                 break;
1529             }
1530             cqlen -= (9+flen);
1531             chunkqueue_mark_written(cq, 9+flen);
1532         }
1533 
1534         if (h2c->sent_goaway > 0) return 0;
1535     }
1536 
1537     return 1;
1538 }
1539 
1540 
1541 int
1542 h2_want_read (connection * const con)
1543 {
1544     chunkqueue * const cq = con->read_queue;
1545     if (chunkqueue_is_empty(cq)) return 1;
1546 
1547     /* check for partial frame */
1548     const off_t cqlen = chunkqueue_length(cq);
1549     if (cqlen < 9) return 1;
1550     chunk *c = cq->first;
1551     uint32_t clen = buffer_string_length(c->mem) - c->offset;
1552     if (clen < 9) {
1553         clen = h2_frame_cq_compact(cq, 9);
1554         c = cq->first; /*(reload after h2_frame_cq_compact())*/
1555     }
1556     uint8_t *s = (uint8_t *)(c->mem->ptr + c->offset);
1557     uint32_t flen = (s[0] << 16) | (s[1] << 8) | s[2];
1558     if (clen < 9+flen) return 1;
1559 
1560     /* check if not HEADERS, or if HEADERS has END_HEADERS flag */
1561     if (s[3] != H2_FTYPE_HEADERS || (s[4] & H2_FLAG_END_HEADERS))
1562         return 0;
1563 
1564     /* check for partial CONTINUATION frames */
1565     for (uint32_t n = 9+flen; cqlen >= n+9; n += 9+flen) {
1566         if (clen < n+9) {
1567             clen = h2_frame_cq_compact(cq, n+9);
1568             c = cq->first; /*(reload after h2_frame_cq_compact())*/
1569             s = (uint8_t *)(c->mem->ptr + c->offset);
1570         }
1571         flen = (s[n+0] << 16) | (s[n+1] << 8) | s[n+2];
1572         if (cqlen < n+9+flen) return 1; /* incomplete frame; go on */
1573         if (s[4] & H2_FLAG_END_HEADERS) return 0;
1574     }
1575 
1576     return 1;
1577 }
1578 
1579 
1580 static int
1581 h2_recv_client_connection_preface (connection * const con)
1582 {
1583     /* check if the client Connection Preface (24 bytes) has been received
1584      * (initial SETTINGS frame should immediately follow, but is not checked) */
1585     chunkqueue * const cq = con->read_queue;
1586     if (chunkqueue_length(cq) < 24) {
1587         chunk * const c = cq->first;
1588         if (c && buffer_string_length(c->mem) - c->offset >= 4) {
1589             const char * const s = c->mem->ptr + c->offset;
1590             if (s[0]!='P'||s[1]!='R'||s[2]!='I'||s[3]!=' ') {
1591                 h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1592                 return 1; /* error; done receiving connection preface */
1593             }
1594         }
1595         return 0; /*(not ready yet)*/
1596     }
1597 
1598     static const char h2preface[] = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
1599     chunk *c = cq->first;
1600     const uint32_t clen = buffer_string_length(c->mem) - c->offset;
1601     if (clen < 24) h2_frame_cq_compact(cq, 24);
1602     c = cq->first; /*(reload after h2_frame_cq_compact())*/
1603     const uint8_t * const s = (uint8_t *)(c->mem->ptr + c->offset);
1604     if (0 == memcmp(s, h2preface, 24)) /* sizeof(h2preface)-1) */
1605         chunkqueue_mark_written(cq, 24);
1606     else
1607         h2_send_goaway_e(con, H2_E_PROTOCOL_ERROR);
1608     return 1; /* done receiving connection preface (even if error occurred) */
1609 }
1610 
1611 
1612 __attribute_cold__
1613 static int
1614 h2_read_client_connection_preface (struct connection * const con, chunkqueue * const cq, off_t max_bytes)
1615 {
1616     /* temporary con->network_read() filter until connection preface received */
1617 
1618     /*(alternatively, func ptr could be saved in an element in (h2con *))*/
1619     void ** const hctx = con->plugin_ctx+0; /*(0 idx used for h2)*/
1620     int(* const network_read)(struct connection *, chunkqueue *, off_t) =
1621       (int(*)(struct connection *, chunkqueue *, off_t))(uintptr_t)(*hctx);
1622     if (max_bytes < 24) max_bytes = 24; /*(should not happen)*/
1623     int rc = (network_read)(con, cq, max_bytes);
1624     if (NULL == con->h2) return rc; /*(unexpected; already cleaned up)*/
1625     if (-1 != rc && h2_recv_client_connection_preface(con)) {
1626         con->network_read = network_read;
1627         *hctx = NULL;
1628         /*(intentionally update timestamp only after reading preface complete)*/
1629         con->read_idle_ts = log_epoch_secs;
1630     }
1631     return rc;
1632 }
1633 
1634 
1635 void
1636 h2_init_con (request_st * const restrict h2r, connection * const restrict con, const buffer * const restrict http2_settings)
1637 {
1638     h2con * const h2c = calloc(1, sizeof(h2con));
1639     force_assert(h2c);
1640     con->h2 = h2c;
1641     con->read_idle_ts = log_epoch_secs;
1642     con->keep_alive_idle = h2r->conf.max_keep_alive_idle;
1643 
1644     h2r->h2_rwin = 65535;                 /* h2 connection recv window */
1645     h2r->h2_swin = 65535;                 /* h2 connection send window */
1646     /* settings sent from peer */         /* initial values */
1647     h2c->s_header_table_size     = 4096;  /* SETTINGS_HEADER_TABLE_SIZE      */
1648     h2c->s_enable_push           = 1;     /* SETTINGS_ENABLE_PUSH            */
1649     h2c->s_max_concurrent_streams= ~0u;   /* SETTINGS_MAX_CONCURRENT_STREAMS */
1650     h2c->s_initial_window_size   = 65535; /* SETTINGS_INITIAL_WINDOW_SIZE    */
1651     h2c->s_max_frame_size        = 16384; /* SETTINGS_MAX_FRAME_SIZE         */
1652     h2c->s_max_header_list_size  = ~0u;   /* SETTINGS_MAX_HEADER_LIST_SIZE   */
1653     h2c->sent_settings           = log_epoch_secs; /*(send SETTINGS below)*/
1654 
1655     lshpack_dec_init(&h2c->decoder);
1656     lshpack_enc_init(&h2c->encoder);
1657     lshpack_enc_use_hist(&h2c->encoder, 1);
1658 
1659     if (http2_settings) /*(if Upgrade: h2c)*/
1660         h2_parse_frame_settings(con, (uint8_t *)CONST_BUF_LEN(http2_settings));
1661 
1662     static const uint8_t h2settings[] = { /*(big-endian numbers)*/
1663       /* SETTINGS */
1664       0x00, 0x00, 0x0c        /* frame length */ /* 6 * 2 for two settings */
1665      ,H2_FTYPE_SETTINGS       /* frame type */
1666      ,0x00                    /* frame flags */
1667      ,0x00, 0x00, 0x00, 0x00  /* stream identifier */
1668      ,0x00, H2_SETTINGS_MAX_CONCURRENT_STREAMS
1669      ,0x00, 0x00, 0x00, 0x08  /* 8 */
1670      #if 0  /* ? explicitly disable dynamic table ? (and adjust frame length) */
1671             /* If this is sent, must wait until peer sends SETTINGS with ACK
1672              * before disabling dynamic table in HPACK decoder */
1673             /*(before calling lshpack_dec_set_max_capacity(&h2c->decoder, 0))*/
1674      ,0x00, H2_SETTINGS_HEADER_TABLE_SIZE
1675      ,0x00, 0x00, 0x00, 0x00  /* 0 */
1676      #endif
1677      #if 0  /* ? explicitly disable push ?       (and adjust frame length) */
1678      ,0x00, H2_SETTINGS_ENABLE_PUSH
1679      ,0x00, 0x00, 0x00, 0x00  /* 0 */
1680      #endif
1681      #if 0  /* ? increase from default (65535) ? (and adjust frame length) */
1682      ,0x00, H2_SETTINGS_INITIAL_WINDOW_SIZE
1683      ,0x00, 0x02, 0x00, 0x00  /* 131072 */
1684      #endif
1685      #if 0  /* ? increase from default (16384) ? (and adjust frame length) */
1686      ,0x00, H2_SETTINGS_MAX_FRAME_SIZE
1687      ,0x00, 0x00, 0x80, 0x00  /* 32768 */
1688      #endif
1689      ,0x00, H2_SETTINGS_MAX_HEADER_LIST_SIZE
1690      ,0x00, 0x00, 0xFF, 0xFF  /* 65535 */
1691 
1692      #if 0
1693       /* WINDOW_UPDATE */
1694      ,0x00, 0x00, 0x04        /* frame length */
1695      ,H2_FTYPE_WINDOW_UPDATE  /* frame type */
1696      ,0x00                    /* frame flags */
1697      ,0x00, 0x00, 0x00, 0x00  /* stream identifier */
1698      ,0x00, 0x01, 0x00, 0x01  /* 65537 */ /* increase connection rwin to 128k */
1699      #endif
1700     };
1701 
1702     /*h2r->h2_rwin += 65537;*//*(enable if WINDOWS_UPDATE is sent above)*/
1703     chunkqueue_append_mem(con->write_queue,
1704                           (const char *)h2settings, sizeof(h2settings));
1705 
1706     if (!h2_recv_client_connection_preface(con)) {
1707         /*(alternatively, func ptr could be saved in an element in (h2con *))*/
1708         con->plugin_ctx[0] = (void *)(uintptr_t)con->network_read;
1709         con->network_read = h2_read_client_connection_preface;
1710         /* note: no steps taken to reset con->network_read() on error
1711          * as con->network_read() is always set in connection_accepted() */
1712     }
1713 
1714     buffer_string_prepare_copy(h2r->tmp_buf, 65535);
1715 }
1716 
1717 
1718 static void
1719 h2_send_hpack (request_st * const r, connection * const con, const char *data, uint32_t dlen, const uint32_t flags)
1720 {
1721     union {
1722       uint8_t c[12];
1723       uint32_t u[3];          /*(alignment)*/
1724     } headers = { {           /*(big-endian numbers)*/
1725       0x00, 0x00, 0x00        /* padding for alignment; do not send */
1726       /* HEADERS */
1727      ,0x00, 0x00, 0x00        /* frame length      (fill in below) */
1728      ,H2_FTYPE_HEADERS        /* frame type */
1729      ,(uint8_t)flags          /* frame flags (e.g. END_STREAM for trailers) */
1730      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
1731     } };
1732 
1733     headers.u[2] = htonl(r->h2id);
1734 
1735     /* similar to h2_send_data(), but unlike DATA frames there is a HEADERS
1736      * frame potentially followed by CONTINUATION frame(s) here, and the final
1737      * HEADERS or CONTINUATION frame here has END_HEADERS flag set.
1738      * For trailers, END_STREAM flag is set on HEADERS frame. */
1739 
1740     /*(approximate space needed for frames (header + payload)
1741      * with slight over-estimate of 16 bytes per frame header (> 9)
1742      * and minimum SETTING_MAX_FRAME_SIZE of 16k (could be larger)
1743      * (dlen >> 14)+1 is num 16k frames needed, multipled by 16 bytes
1744      *  per frame can be appoximated with (dlen>>10) + 9)*/
1745     buffer * const b =
1746       chunkqueue_append_buffer_open_sz(con->write_queue, dlen + (dlen>>10) + 9);
1747     char * restrict ptr = b->ptr;
1748     h2con * const h2c = con->h2;
1749     const uint32_t fsize = h2c->s_max_frame_size;
1750     do {
1751         const uint32_t len = dlen < fsize ? dlen : fsize;
1752         headers.c[3] = (len >> 16) & 0xFF; /*(off +3 to skip over align pad)*/
1753         headers.c[4] = (len >>  8) & 0xFF;
1754         headers.c[5] = (len      ) & 0xFF;
1755         if (len == dlen)
1756             headers.c[7] |= H2_FLAG_END_HEADERS;
1757       #if 0
1758         chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
1759                               (const char *)headers.c+3, sizeof(headers)-3);
1760         chunkqueue_append_mem(con->write_queue, data, len);
1761       #else
1762         memcpy(ptr, headers.c+3, sizeof(headers)-3);
1763         memcpy(ptr+sizeof(headers)-3, data, len);
1764         ptr  += len + sizeof(headers)-3;
1765       #endif
1766         data += len;
1767         dlen -= len;
1768         /*(include H2_FLAG_END_STREAM in HEADERS frame, not CONTINUATION)*/
1769         headers.c[6] = H2_FTYPE_CONTINUATION; /*(if additional frames needed)*/
1770         headers.c[7] = 0x00; /*(off +3 to skip over align pad)*/
1771     } while (dlen);
1772     buffer_string_set_length(b, (uint32_t)(ptr - b->ptr));
1773     chunkqueue_append_buffer_commit(con->write_queue);
1774 }
1775 
1776 
1777 __attribute_cold__
1778 static void
1779 h2_log_response_header_lsx(request_st * const r, const lsxpack_header_t * const lsx)
1780 {
1781     log_error(r->conf.errh, __FILE__, __LINE__,
1782       "fd:%d id:%u resp: %.*s: %.*s", r->con->fd, r->h2id,
1783       (int)lsx->name_len, lsx->buf + lsx->name_offset,
1784       (int)lsx->val_len,  lsx->buf + lsx->val_offset);
1785 }
1786 
1787 
1788 __attribute_cold__
1789 static void
1790 h2_log_response_header(request_st * const r, const int len, const char * const hdr)
1791 {
1792     log_error(r->conf.errh, __FILE__, __LINE__,
1793       "fd:%d id:%u resp: %.*s", r->con->fd, r->h2id, len, hdr);
1794 }
1795 
1796 
1797 void
1798 h2_send_headers (request_st * const r, connection * const con)
1799 {
1800     /*(set keep_alive_idle; out-of-place and non-event for most configs,
1801      * but small attempt to (maybe) preserve behavior for specific configs)*/
1802     con->keep_alive_idle = r->conf.max_keep_alive_idle;
1803 
1804     /* specialized version of http_response_write_header(); send headers
1805      * directly to HPACK encoder, rather than double-buffering in chunkqueue */
1806 
1807     if (304 == r->http_status
1808         && light_btst(r->resp_htags, HTTP_HEADER_CONTENT_ENCODING))
1809         http_header_response_unset(r, HTTP_HEADER_CONTENT_ENCODING,
1810                                    CONST_STR_LEN("Content-Encoding"));
1811 
1812     /*(h2_init_con() resized h2r->tmp_buf to 64k; shared with r->tmp_buf)*/
1813     buffer * const tb = r->tmp_buf;
1814     force_assert(tb->size >= 65536);/*(sanity check; remove in future)*/
1815     unsigned char *dst = (unsigned char *)tb->ptr;
1816     unsigned char * const dst_end = (unsigned char *)tb->ptr + tb->size;
1817 
1818     h2con * const h2c = con->h2;
1819     struct lshpack_enc * const encoder = &h2c->encoder;
1820     lsxpack_header_t lsx;
1821     uint32_t alen = 7+3+4; /* ":status: xxx\r\n" */
1822     const int log_response_header = r->conf.log_response_header;
1823     const int resp_header_repeated = r->resp_header_repeated;
1824 
1825     char status[12] = ":status: ";
1826     int x = r->http_status; /*(expect status < 1000; should be [100-599])*/
1827     status[11] = (x % 10) + '0';
1828     status[10] = (x / 10 % 10) + '0';
1829     status[9]  = (x / 100) + '0';
1830 
1831     if (log_response_header)
1832         h2_log_response_header(r, 12, status);
1833 
1834     memset(&lsx, 0, sizeof(lsxpack_header_t));
1835     lsx.buf = status;
1836     lsx.name_offset = 0;
1837     lsx.name_len = 7;
1838     lsx.val_offset = 9;
1839     lsx.val_len = 3;
1840     switch (r->http_status) {
1841       case 200: lsx.hpack_index = LSHPACK_HDR_STATUS_200; break;
1842       case 204: lsx.hpack_index = LSHPACK_HDR_STATUS_204; break;
1843       case 206: lsx.hpack_index = LSHPACK_HDR_STATUS_206; break;
1844       case 304: lsx.hpack_index = LSHPACK_HDR_STATUS_304; break;
1845       case 400: lsx.hpack_index = LSHPACK_HDR_STATUS_400; break;
1846       case 404: lsx.hpack_index = LSHPACK_HDR_STATUS_404; break;
1847       case 500: lsx.hpack_index = LSHPACK_HDR_STATUS_500; break;
1848       default:
1849         break;
1850     }
1851     dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1852     if (dst == (unsigned char *)tb->ptr) {
1853         h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1854         return;
1855     }
1856 
1857     /* add all headers */
1858     for (uint32_t i = 0, used = r->resp_headers.used; i < used; ++i) {
1859         data_string * const restrict ds =(data_string *)r->resp_headers.data[i];
1860         const uint32_t klen = buffer_string_length(&ds->key);
1861         const uint32_t vlen = buffer_string_length(&ds->value);
1862         const char * const restrict k = ds->key.ptr;
1863         if (0 == vlen || 0 == klen) continue;
1864         alen += klen + vlen + 4;
1865 
1866         if (alen > LSXPACK_MAX_STRLEN) {
1867             /* ls-hpack default limit (UINT16_MAX) is per-line, due to field
1868              * sizes of lsx.name_offset,lsx.name_len,lsx.val_offset,lsx.val_len
1869              * However, similar to elsewhere, limit total size of expanded
1870              * headers to (very generous) 64k - 1.  Peers might allow less. */
1871             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1872             return;
1873         }
1874 
1875         /* HTTP/2 requires lowercase keys
1876          * ls-hpack requires key and value be in same buffer
1877          * Since keys are typically short, append (and lowercase) key onto
1878          * end of value buffer */
1879         char * const v = buffer_string_prepare_append(&ds->value, klen);
1880         if (ds->ext != HTTP_HEADER_OTHER) {
1881             memcpy(v, http_header_lc[ds->ext], klen);
1882         }
1883         else {
1884             if ((k[0] & 0xdf) == 'X' && http_response_omit_header(r, ds)) {
1885                 alen -= klen + vlen + 4;
1886                 continue;
1887             }
1888             for (uint32_t j = 0; j < klen; ++j)
1889                 v[j] = !light_isupper(k[j]) ? k[j] : (k[j] | 0x20);
1890         }
1891         /*buffer_commit(&ds->value, klen);*//*(not necessary; truncated below)*/
1892 
1893         uint32_t voff = 0;
1894         const char *n;
1895         lsx.buf = ds->value.ptr;
1896         do {
1897             n = !resp_header_repeated
1898               ? NULL
1899               : memchr(lsx.buf+voff, '\n', vlen - voff);
1900 
1901             memset(&lsx, 0, sizeof(lsxpack_header_t));
1902             lsx.hpack_index = http_header_lshpack_idx[ds->ext];
1903             lsx.buf = ds->value.ptr;
1904             lsx.name_offset = vlen;
1905             lsx.name_len = klen;
1906             lsx.val_offset = voff;
1907             if (NULL == n)
1908                 lsx.val_len = vlen - voff;
1909             else {
1910                 /* multiple headers (same field-name) separated by "\r\n"
1911                  * and then "field-name: " (see http_header_response_insert())*/
1912                 voff = (uint32_t)(n + 1 - lsx.buf);
1913                 lsx.val_len = voff - 2 - lsx.val_offset; /*(-2 for "\r\n")*/
1914                 voff += klen + 2;
1915             }
1916 
1917             if (log_response_header)
1918                 h2_log_response_header_lsx(r, &lsx);
1919 
1920             unsigned char * const dst_in = dst;
1921             dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1922             if (dst == dst_in) {
1923                 buffer_string_set_length(&ds->value, vlen); /*(restore prior value)*/
1924                 h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1925                 return;
1926             }
1927         } while (n);
1928         buffer_string_set_length(&ds->value, vlen); /*(restore prior value)*/
1929     }
1930 
1931     if (!light_btst(r->resp_htags, HTTP_HEADER_DATE)) {
1932         /* HTTP/1.1 and later requires a Date: header */
1933         /* "date: " 6-chars + 30-chars for "%a, %d %b %Y %H:%M:%S GMT" + '\0' */
1934         static char tstr[36] = "date: ";
1935 
1936         memset(&lsx, 0, sizeof(lsxpack_header_t));
1937         lsx.buf = tstr;
1938         lsx.name_offset = 0;
1939         lsx.name_len = 4;
1940         lsx.val_offset = 6;
1941         lsx.val_len = 29;
1942         lsx.hpack_index = LSHPACK_HDR_DATE;
1943 
1944         /* cache the generated timestamp */
1945         static time_t tlast;
1946         const time_t cur_ts = log_epoch_secs;
1947         if (tlast != cur_ts) {
1948             tlast = cur_ts;
1949             strftime(tstr+6, sizeof(tstr)-6,
1950                      "%a, %d %b %Y %H:%M:%S GMT", gmtime(&tlast));
1951         }
1952 
1953         alen += 35+2;
1954 
1955         if (log_response_header)
1956             h2_log_response_header(r, 35, tstr);
1957 
1958         unsigned char * const dst_in = dst;
1959         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1960         if (dst == dst_in) {
1961             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1962             return;
1963         }
1964     }
1965 
1966     if (!light_btst(r->resp_htags, HTTP_HEADER_SERVER)
1967         && !buffer_string_is_empty(r->conf.server_tag)) {
1968         buffer * const b = chunk_buffer_acquire();
1969         const uint32_t vlen = buffer_string_length(r->conf.server_tag);
1970         buffer_copy_string_len(b, CONST_STR_LEN("server: "));
1971         buffer_append_string_len(b, CONST_BUF_LEN(r->conf.server_tag));
1972 
1973         alen += 6+vlen+4;
1974 
1975         if (log_response_header)
1976             h2_log_response_header(r, (int)6+vlen+2, b->ptr);
1977 
1978         memset(&lsx, 0, sizeof(lsxpack_header_t));
1979         lsx.buf = b->ptr;
1980         lsx.name_offset = 0;
1981         lsx.name_len = 6;
1982         lsx.val_offset = 8;
1983         lsx.val_len = vlen;
1984         lsx.hpack_index = LSHPACK_HDR_SERVER;
1985         unsigned char * const dst_in = dst;
1986         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
1987         chunk_buffer_release(b);
1988         if (dst == dst_in) {
1989             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
1990             return;
1991         }
1992     }
1993 
1994     alen += 2; /* "virtual" blank line ("\r\n") ending headers */
1995     r->resp_header_len = alen;
1996     /*(accounting for mod_accesslog and mod_rrdtool)*/
1997     chunkqueue * const wq = &r->write_queue;
1998     wq->bytes_in  += (off_t)alen;
1999     wq->bytes_out += (off_t)alen;
2000 
2001     const uint32_t dlen = (uint32_t)((char *)dst - tb->ptr);
2002     const uint32_t flags =
2003       (r->resp_body_finished && chunkqueue_is_empty(&r->write_queue))
2004         ? H2_FLAG_END_STREAM
2005         : 0;
2006     h2_send_hpack(r, con, tb->ptr, dlen, flags);
2007 }
2008 
2009 
2010 __attribute_cold__
2011 __attribute_noinline__
2012 static void
2013 h2_send_headers_block (request_st * const r, connection * const con, const char * const hdrs, const uint32_t hlen, uint32_t flags)
2014 {
2015     unsigned short hoff[8192]; /* max num header lines + 3; 16k on stack */
2016     hoff[0] = 1;                         /* number of lines */
2017     hoff[1] = 0;                         /* base offset for all lines */
2018     /*hoff[2] = ...;*/                   /* offset from base for 2nd line */
2019     uint32_t rc = http_header_parse_hoff(hdrs, hlen, hoff);
2020     if (0 == rc || rc > USHRT_MAX || hoff[0] >= sizeof(hoff)/sizeof(hoff[0])-1
2021         || 1 == hoff[0]) { /*(initial blank line (should not happen))*/
2022         /* error if headers incomplete or too many header fields */
2023         log_error(r->conf.errh, __FILE__, __LINE__,
2024                   "oversized response-header");
2025         hoff[0] = 1;
2026         hoff[1] = 0;
2027         http_header_parse_hoff(CONST_STR_LEN(":status: 500\r\n\r\n"), hoff);
2028     }
2029 
2030     /*(h2_init_con() resized h2r->tmp_buf to 64k; shared with r->tmp_buf)*/
2031     buffer * const tb = r->tmp_buf;
2032     force_assert(tb->size >= 65536);/*(sanity check; remove in future)*/
2033     unsigned char *dst = (unsigned char *)tb->ptr;
2034     unsigned char * const dst_end = (unsigned char *)tb->ptr + tb->size;
2035 
2036     h2con * const h2c = con->h2;
2037     struct lshpack_enc * const encoder = &h2c->encoder;
2038     lsxpack_header_t lsx;
2039 
2040     int i = 1;
2041     if (hdrs[0] == ':') {
2042         i = 2;
2043         /* expect first line to contain ":status: ..." if pseudo-header,
2044          * and expecting single pseudo-header for headers, zero for trailers */
2045         /*assert(0 == memcmp(hdrs, ":status: ", sizeof(":status: ")-1));*/
2046         memset(&lsx, 0, sizeof(lsxpack_header_t));
2047         *(const char **)&lsx.buf = hdrs;
2048         lsx.name_offset = 0;
2049         lsx.name_len = sizeof(":status")-1;
2050         lsx.val_offset = lsx.name_len + 2;
2051         lsx.val_len = 3;
2052         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
2053         if (dst == (unsigned char *)tb->ptr) {
2054             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2055             return;
2056         }
2057     }
2058 
2059     /*(note: not expecting any other pseudo-headers)*/
2060 
2061     /* note: expects field-names are lowercased (http_response_write_header())*/
2062 
2063     for (; i < hoff[0]; ++i) {
2064         const char *k = hdrs + ((i > 1) ? hoff[i] : 0);
2065         const char *end = hdrs + hoff[i+1];
2066         const char *v = memchr(k, ':', end-k);
2067         /* XXX: DOES NOT handle line wrapping (which is deprecated by RFCs)
2068          * (not expecting line wrapping; not produced internally by lighttpd,
2069          *  though possible from backends or with custom lua code)*/
2070         if (NULL == v || k == v) continue;
2071         uint32_t klen = v - k;
2072         if (0 == klen) continue;
2073         do { ++v; } while (*v == ' ' || *v == '\t'); /*(expect single ' ')*/
2074       #ifdef __COVERITY__
2075         /*(k has at least .:\n by now, so end[-2] valid)*/
2076         force_assert(end >= k + 2);
2077       #endif
2078         if (end[-2] != '\r') /*(header line must end "\r\n")*/
2079             continue;
2080         end -= 2;
2081         uint32_t vlen = end - v;
2082         if (0 == vlen) continue;
2083         memset(&lsx, 0, sizeof(lsxpack_header_t));
2084         *(const char **)&lsx.buf = hdrs;
2085         lsx.name_offset = k - hdrs;
2086         lsx.name_len = klen;
2087         lsx.val_offset = v - hdrs;
2088         lsx.val_len = vlen;
2089         unsigned char * const dst_in = dst;
2090         dst = lshpack_enc_encode(encoder, dst, dst_end, &lsx);
2091         if (dst == dst_in) {
2092             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2093             return;
2094         }
2095     }
2096     uint32_t dlen = (uint32_t)((char *)dst - tb->ptr);
2097     h2_send_hpack(r, con, tb->ptr, dlen, flags);
2098 }
2099 
2100 
2101 static void
2102 h2_send_1xx_block (request_st * const r, connection * const con, const char * const hdrs, const uint32_t hlen)
2103 {
2104     h2_send_headers_block(r, con, hdrs, hlen, 0);
2105 }
2106 
2107 
2108 int
2109 h2_send_1xx (request_st * const r, connection * const con)
2110 {
2111     buffer * const b = chunk_buffer_acquire();
2112 
2113     buffer_copy_string_len(b, CONST_STR_LEN(":status: "));
2114     buffer_append_int(b, r->http_status);
2115     for (uint32_t i = 0; i < r->resp_headers.used; ++i) {
2116         const data_string * const ds = (data_string *)r->resp_headers.data[i];
2117 
2118         if (buffer_string_is_empty(&ds->value)) continue;
2119         if (buffer_string_is_empty(&ds->key)) continue;
2120 
2121         buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
2122         buffer_append_string_buffer(b, &ds->key);
2123         buffer_append_string_len(b, CONST_STR_LEN(": "));
2124         buffer_append_string_buffer(b, &ds->value);
2125     }
2126     buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
2127 
2128     h2_send_1xx_block(r, con, CONST_BUF_LEN(b));
2129 
2130     chunk_buffer_release(b);
2131     return 1; /* for http_response_send_1xx_cb */
2132 }
2133 
2134 
2135 void
2136 h2_send_100_continue (request_st * const r, connection * const con)
2137 {
2138     /* 100 Continue is small and will always fit in SETTING_MAX_FRAME_SIZE;
2139      * i.e. there will not be any CONTINUATION frames here */
2140 
2141     /* XXX: need to update hpack dynamic table,
2142      * or else could hard-code header block fragment
2143      * { 0x48, 0x03, 0x31, 0x30, 0x30 }
2144      */
2145 
2146     /* short header block, so reuse shared code used for trailers
2147      * rather than adding something specific for ls-hpack here */
2148 
2149     h2_send_1xx_block(r, con, CONST_STR_LEN(":status: 100\r\n\r\n"));
2150 }
2151 
2152 
2153 static void
2154 h2_send_end_stream_data (request_st * const r, connection * const con);
2155 
2156 __attribute_cold__
2157 __attribute_noinline__
2158 static void
2159 h2_send_end_stream_trailers (request_st * const r, connection * const con, const buffer * const trailers)
2160 {
2161     /*(trailers are merged into response headers if trailers are received before
2162      * sending response headers to client.  However, if streaming response, then
2163      * trailers might need handling here)*/
2164 
2165     /* parse and lowercase field-names in trailers */
2166     unsigned short hoff[8192]; /* max num header lines + 3; 16k on stack */
2167     hoff[0] = 1;                         /* number of lines */
2168     hoff[1] = 0;                         /* base offset for all lines */
2169     /*hoff[2] = ...;*/                   /* offset from base for 2nd line */
2170     uint32_t rc = http_header_parse_hoff(CONST_BUF_LEN(trailers), hoff);
2171     if (0 == rc || rc > USHRT_MAX || hoff[0] >= sizeof(hoff)/sizeof(hoff[0])-1
2172         || 1 == hoff[0]) { /*(initial blank line (should not happen))*/
2173         /* skip trailers if incomplete, too many fields, or too long (> 64k-1)*/
2174         h2_send_end_stream_data(r, con);
2175         return;
2176     }
2177 
2178     char * const ptr = trailers->ptr;
2179     for (int i = 1; i < hoff[0]; ++i) {
2180         char *k = ptr + ((i > 1) ? hoff[i] : 0);
2181         if (*k == ':') {
2182             /*(pseudo-header should not appear in trailers)*/
2183             h2_send_end_stream_data(r, con);
2184             return;
2185         }
2186         const char * const colon = memchr(k, ':', ptr+hoff[i+1]-k);
2187         if (NULL == colon) continue;
2188         do {
2189             if (light_isupper(*k)) *k |= 0x20;
2190         } while (++k != colon);
2191     }
2192 
2193     h2_send_headers_block(r, con, CONST_BUF_LEN(trailers), H2_FLAG_END_STREAM);
2194 }
2195 
2196 
2197 #if 0 /*(replaced by h2_send_headers())*/
2198 void
2199 h2_send_cqheaders (request_st * const r, connection * const con)
2200 {
2201     /*(assumes HTTP/1.1 response headers have been prepended as first chunk)
2202      *(future: if r->write_queue is bypassed for headers, adjust
2203      * r->write_queue bytes counts (bytes_in, bytes_out) with header len)*/
2204     /* note: expects field-names are lowercased (http_response_write_header())*/
2205     chunk * const c = r->write_queue.first;
2206     const uint32_t len = buffer_string_length(c->mem) - (uint32_t)c->offset;
2207     uint32_t flags = (r->resp_body_finished && NULL == c->next)
2208       ? H2_FLAG_END_STREAM
2209       : 0;
2210     h2_send_headers_block(r, con, c->mem->ptr + c->offset, len, flags);
2211     chunkqueue_mark_written(&r->write_queue, len);
2212 }
2213 #endif
2214 
2215 
2216 #if 0
2217 
2218 void
2219 h2_send_data (request_st * const r, connection * const con, const char *data, uint32_t dlen)
2220 {
2221     /* Note: dlen should be <= MAX_WRITE_LIMIT in order to share resources */
2222 
2223     union {
2224       uint8_t c[12];
2225       uint32_t u[3];          /*(alignment)*/
2226     } dataframe = { {         /*(big-endian numbers)*/
2227       0x00, 0x00, 0x00        /* padding for alignment; do not send */
2228       /* DATA */
2229      ,0x00, 0x00, 0x00        /* frame length      (fill in below) */
2230      ,H2_FTYPE_DATA           /* frame type */
2231      ,0x00                    /* frame flags */
2232      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
2233     } };
2234 
2235     dataframe.u[2] = htonl(r->h2id);
2236 
2237     /* XXX: does not provide an optimization to send final set of data with
2238      *      END_STREAM flag; see h2_send_end_stream_data() to end stream */
2239 
2240     /* adjust stream and connection windows */
2241     /*assert(dlen <= INT32_MAX);*//* dlen should be <= MAX_WRITE_LIMIT */
2242     request_st * const h2r = &con->request;
2243     if (r->h2_swin   < 0) return;
2244     if (h2r->h2_swin < 0) return;
2245     if ((int32_t)dlen > r->h2_swin)   dlen = (uint32_t)r->h2_swin;
2246     if ((int32_t)dlen > h2r->h2_swin) dlen = (uint32_t)h2r->h2_swin;
2247     if (0 == dlen) return;
2248     r->h2_swin   -= (int32_t)dlen;
2249     h2r->h2_swin -= (int32_t)dlen;
2250 
2251     /* XXX: future: should have an interface which processes chunkqueue
2252      * and takes string refs to mmap FILE_CHUNK to avoid extra copying
2253      * since the result is likely to be consumed by TLS modules */
2254 
2255     /*(approximate space needed for frames (header + payload)
2256      * with slight over-estimate of 16 bytes per frame header (> 9)
2257      * and minimum SETTING_MAX_FRAME_SIZE of 16k (could be larger)
2258      * (dlen >> 14)+1 is num 16k frames needed, multipled by 16 bytes
2259      *  per frame can be appoximated with (dlen>>10) + 9)*/
2260     buffer * const b =
2261       chunkqueue_append_buffer_open_sz(con->write_queue, dlen + (dlen>>10) + 9);
2262     char * restrict ptr = b->ptr;
2263     h2con * const h2c = con->h2;
2264     const uint32_t fsize = h2c->s_max_frame_size;
2265     do {
2266         const uint32_t len = dlen < fsize ? dlen : fsize;
2267         dataframe.c[3] = (len >> 16) & 0xFF; /*(off +3 to skip over align pad)*/
2268         dataframe.c[4] = (len >>  8) & 0xFF;
2269         dataframe.c[5] = (len      ) & 0xFF;
2270       #if 0
2271         chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
2272                               (const char *)dataframe.c+3, sizeof(dataframe)-3);
2273         chunkqueue_append_mem(con->write_queue, data, len);
2274       #else
2275         memcpy(ptr, dataframe.c+3, sizeof(dataframe)-3);
2276         memcpy(ptr+sizeof(dataframe)-3, data, len);
2277         ptr  += len + sizeof(dataframe)-3;
2278       #endif
2279         data += len;
2280         dlen -= len;
2281     } while (dlen);
2282     buffer_string_set_length(b, (uint32_t)(ptr - b->ptr));
2283     chunkqueue_append_buffer_commit(con->write_queue);
2284 }
2285 
2286 #endif
2287 
2288 
2289 void
2290 h2_send_cqdata (request_st * const r, connection * const con, chunkqueue * const cq, uint32_t dlen)
2291 {
2292     /* Note: dlen should be <= MAX_WRITE_LIMIT in order to share resources */
2293 
2294     union {
2295       uint8_t c[12];
2296       uint32_t u[3];          /*(alignment)*/
2297     } dataframe = { {         /*(big-endian numbers)*/
2298       0x00, 0x00, 0x00        /* padding for alignment; do not send */
2299       /* DATA */
2300      ,0x00, 0x00, 0x00        /* frame length      (fill in below) */
2301      ,H2_FTYPE_DATA           /* frame type */
2302      ,0x00                    /* frame flags */
2303      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
2304     } };
2305 
2306     dataframe.u[2] = htonl(r->h2id);
2307 
2308     /* XXX: does not provide an optimization to send final set of data with
2309      *      END_STREAM flag; see h2_send_end_stream_data() to end stream */
2310 
2311     /* adjust stream and connection windows */
2312     /*assert(dlen <= INT32_MAX);*//* dlen should be <= MAX_WRITE_LIMIT */
2313     request_st * const h2r = &con->request;
2314     if (r->h2_swin   < 0) return;
2315     if (h2r->h2_swin < 0) return;
2316     if ((int32_t)dlen > r->h2_swin)   dlen = (uint32_t)r->h2_swin;
2317     if ((int32_t)dlen > h2r->h2_swin) dlen = (uint32_t)h2r->h2_swin;
2318     if (0 == dlen) return;
2319     r->h2_swin   -= (int32_t)dlen;
2320     h2r->h2_swin -= (int32_t)dlen;
2321 
2322     /* XXX: future: should have an interface which processes chunkqueue
2323      * and takes string refs to mmap FILE_CHUNK to avoid extra copying
2324      * since the result is likely to be consumed by TLS modules */
2325 
2326     h2con * const h2c = con->h2;
2327     const uint32_t fsize = h2c->s_max_frame_size;
2328     do {
2329         const uint32_t len = dlen < fsize ? dlen : fsize;
2330         dataframe.c[3] = (len >> 16) & 0xFF; /*(off +3 to skip over align pad)*/
2331         dataframe.c[4] = (len >>  8) & 0xFF;
2332         dataframe.c[5] = (len      ) & 0xFF;
2333         chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
2334                               (const char *)dataframe.c+3, sizeof(dataframe)-3);
2335         chunkqueue_steal(con->write_queue, cq, (off_t)dlen);
2336         dlen -= len;
2337     } while (dlen);
2338 }
2339 
2340 
2341 static void
2342 h2_send_end_stream_data (request_st * const r, connection * const con)
2343 {
2344     union {
2345       uint8_t c[12];
2346       uint32_t u[3];          /*(alignment)*/
2347     } dataframe = { {         /*(big-endian numbers)*/
2348       0x00, 0x00, 0x00        /* padding for alignment; do not send */
2349       /* DATA */
2350      ,0x00, 0x00, 0x00        /* frame length */
2351      ,H2_FTYPE_DATA           /* frame type */
2352      ,H2_FLAG_END_STREAM      /* frame flags */
2353      ,0x00, 0x00, 0x00, 0x00  /* stream identifier (fill in below) */
2354     } };
2355 
2356     dataframe.u[2] = htonl(r->h2id);
2357     r->h2state = H2_STATE_CLOSED;
2358     /*(ignore window updates when sending 0-length DATA frame with END_STREAM)*/
2359     chunkqueue_append_mem(con->write_queue,  /*(+3 to skip over align pad)*/
2360                           (const char *)dataframe.c+3, sizeof(dataframe)-3);
2361 }
2362 
2363 
2364 void
2365 h2_send_end_stream (request_st * const r, connection * const con)
2366 {
2367     if (r->state != CON_STATE_ERROR && r->resp_body_finished) {
2368         /* CON_STATE_RESPONSE_END */
2369         if (r->gw_dechunk && r->gw_dechunk->done
2370             && !buffer_is_empty(&r->gw_dechunk->b))
2371             h2_send_end_stream_trailers(r, con, &r->gw_dechunk->b);
2372         else
2373             h2_send_end_stream_data(r, con);
2374     }
2375     else { /* CON_STATE_ERROR */
2376         h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2377     }
2378 }
2379 
2380 
2381 /*
2382  * (XXX: might move below to separate file)
2383  */
2384 #include "base64.h"
2385 #include "chunk.h"
2386 #include "plugin.h"
2387 #include "plugin_config.h"
2388 #include "reqpool.h"
2389 
2390 
2391 static request_st *
2392 h2_init_stream (request_st * const h2r, connection * const con)
2393 {
2394     h2con * const h2c = con->h2;
2395     ++con->request_count;
2396     force_assert(h2c->rused < sizeof(h2c->r)/sizeof(*h2c->r));
2397     /* initialize stream as subrequest (request_st *) */
2398     request_st * const r = request_acquire(con);
2399     /* XXX: TODO: assign default priority, etc.
2400      *      Perhaps store stream id and priority in separate table */
2401     h2c->r[h2c->rused++] = r;
2402     r->h2_rwin = h2c->s_initial_window_size;
2403     r->h2_swin = h2c->s_initial_window_size;
2404     r->http_version = HTTP_VERSION_2;
2405 
2406     /* copy config state from h2r */
2407     server * const srv = con->srv;
2408     const uint32_t used = srv->config_context->used;
2409     r->conditional_is_valid = h2r->conditional_is_valid;
2410     memcpy(r->cond_cache, h2r->cond_cache, used * sizeof(cond_cache_t));
2411   #ifdef HAVE_PCRE_H
2412     if (used > 1) /*(save 128b per con if no conditions)*/
2413         memcpy(r->cond_match, h2r->cond_match, used * sizeof(cond_match_t));
2414   #endif
2415     /*(see config_reset_config())*/
2416     r->server_name = h2r->server_name;
2417     memcpy(&r->conf, &h2r->conf, sizeof(request_config));
2418 
2419     /* stream id must be assigned by caller */
2420     return r;
2421 }
2422 
2423 
2424 static void
2425 h2_release_stream (request_st * const r, connection * const con)
2426 {
2427     if (r->http_status) {
2428         /* (see comment in connection_handle_response_end_state()) */
2429         plugins_call_handle_request_done(r);
2430 
2431       #if 0
2432         /* (fuzzy accounting for mod_accesslog, mod_rrdtool to avoid
2433          *  double counting, but HTTP/2 framing and HPACK-encoded headers in
2434          *  con->read_queue and con->write_queue are not equivalent to the
2435          *  HPACK-decoded headers and request and response bodies in stream
2436          *  r->read_queue and r->write_queue) */
2437         /* DISABLED since mismatches invalidate the relationship between
2438          * con->bytes_in and con->bytes_out */
2439         con->read_queue->bytes_in   -= r->read_queue.bytes_in;
2440         con->write_queue->bytes_out -= r->write_queue.bytes_out;
2441       #else
2442         UNUSED(con);
2443       #endif
2444     }
2445 
2446     request_release(r);
2447 }
2448 
2449 
2450 void
2451 h2_retire_stream (request_st *r, connection * const con)
2452 {
2453     if (r == NULL) return; /*(should not happen)*/
2454     h2con * const h2c = con->h2;
2455     request_st ** const ar = h2c->r;
2456     for (uint32_t i = 0, j = 0, rused = h2c->rused; i < rused; ++i) {
2457         if (ar[i] != r)
2458             ar[j++] = ar[i];
2459         else {
2460             h2_release_stream(r, con);
2461             r = NULL;
2462         }
2463     }
2464     if (r == NULL) /* found */
2465         h2c->r[--h2c->rused] = NULL;
2466     /*else ... should not happen*/
2467 }
2468 
2469 
2470 void
2471 h2_retire_con (request_st * const h2r, connection * const con)
2472 {
2473     h2con * const h2c = con->h2;
2474     if (NULL == h2c) return;
2475 
2476     if (h2r->state != CON_STATE_ERROR) { /*(CON_STATE_RESPONSE_END)*/
2477         h2_send_goaway(con, H2_E_NO_ERROR);
2478         for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
2479             /*(unexpected if CON_STATE_RESPONSE_END)*/
2480             request_st * const r = h2c->r[i];
2481             h2_send_rst_stream(r, con, H2_E_INTERNAL_ERROR);
2482             h2_release_stream(r, con);
2483         }
2484         if (!chunkqueue_is_empty(con->write_queue)) {
2485             /* similar to connection_handle_write() but without error checks,
2486              * without MAX_WRITE_LIMIT, and without connection throttling */
2487             /*h2r->conf.bytes_per_second = 0;*/         /* disable rate limit */
2488             /*h2r->conf.global_bytes_per_second = 0;*/  /* disable rate limit */
2489             /*con->traffic_limit_reached = 0;*/
2490             chunkqueue * const cq = con->write_queue;
2491             const off_t len = chunkqueue_length(cq);
2492             off_t written = cq->bytes_out;
2493             con->network_write(con, cq, len);
2494             /*(optional accounting)*/
2495             written = cq->bytes_out - written;
2496             con->bytes_written += written;
2497             con->bytes_written_cur_second += written;
2498             if (h2r->conf.global_bytes_per_second_cnt_ptr)
2499                 *(h2r->conf.global_bytes_per_second_cnt_ptr) += written;
2500         }
2501     }
2502     else { /* CON_STATE_ERROR */
2503         for (uint32_t i = 0, rused = h2c->rused; i < rused; ++i) {
2504             request_st * const r = h2c->r[i];
2505             h2_release_stream(r, con);
2506         }
2507         /* XXX: perhaps attempt to send GOAWAY?  Not when CON_STATE_ERROR */
2508     }
2509 
2510     con->h2 = NULL;
2511 
2512     /* future: might keep a pool of reusable (h2con *) */
2513     lshpack_enc_cleanup(&h2c->encoder);
2514     lshpack_dec_cleanup(&h2c->decoder);
2515     free(h2c);
2516 }
2517 
2518 
2519 static void
2520 h2_con_upgrade_h2c (request_st * const h2r, const buffer * const http2_settings)
2521 {
2522     /* status: (h2r->state == CON_STATE_REQUEST_END) for Upgrade: h2c */
2523 
2524     /* HTTP/1.1 101 Switching Protocols
2525      * Connection: Upgrade
2526      * Upgrade: h2c
2527      */
2528   #if 1
2529     static const char switch_proto[] = "HTTP/1.1 101 Switching Protocols\r\n"
2530                                        "Connection: Upgrade\r\n"
2531                                        "Upgrade: h2c\r\n\r\n";
2532     chunkqueue_append_mem(&h2r->write_queue,
2533                           CONST_STR_LEN(switch_proto));
2534     h2r->resp_header_len = sizeof(switch_proto)-1;
2535   #else
2536     h2r->http_status = 101;
2537     http_header_response_set(h2r, HTTP_HEADER_UPGRADE, CONST_STR_LEN("Upgrade"),
2538                                                        CONST_STR_LEN("h2c"));
2539     http_response_write_header(h2r);
2540     http_response_reset(h2r);
2541     h2r->http_status = 0;
2542   #endif
2543 
2544     connection * const con = h2r->con;
2545     h2_init_con(h2r, con, http2_settings);
2546     if (con->h2->sent_goaway) return;
2547 
2548     con->h2->h2_cid = 1; /* stream id 1 is assigned to h2c upgrade */
2549 
2550     /* copy request state from &con->request to subrequest r
2551      * XXX: would be nice if there were a cleaner way to do this
2552      * (This is fragile and must be kept in-sync with request_st in request.h)*/
2553 
2554     request_st * const r = h2_init_stream(h2r, con);
2555     /*(undo double-count; already incremented in CON_STATE_REQUEST_START)*/
2556     --con->request_count;
2557     r->state = h2r->state; /* CON_STATE_REQUEST_END */
2558     r->http_status = 0;
2559     r->http_method = h2r->http_method;
2560     r->h2state = H2_STATE_HALF_CLOSED_REMOTE;
2561     r->h2id = 1;
2562     r->rqst_htags = h2r->rqst_htags;
2563     h2r->rqst_htags = 0;
2564     r->rqst_header_len = h2r->rqst_header_len;
2565     h2r->rqst_header_len = 0;
2566     r->rqst_headers = h2r->rqst_headers;        /* copy struct */
2567     memset(&h2r->rqst_headers, 0, sizeof(array));
2568     r->uri = h2r->uri;                          /* copy struct */
2569   #if 0
2570     r->physical = h2r->physical;                /* copy struct */
2571     r->env = h2r->env;                          /* copy struct */
2572   #endif
2573     memset(&h2r->rqst_headers, 0, sizeof(array));
2574     memset(&h2r->uri, 0, sizeof(request_uri));
2575   #if 0
2576     memset(&h2r->physical, 0, sizeof(physical));
2577     memset(&h2r->env, 0, sizeof(array));
2578   #endif
2579   #if 0 /* expect empty request body */
2580     r->reqbody_length = h2r->reqbody_length; /* currently always 0 */
2581     r->te_chunked = h2r->te_chunked;         /* must be 0 */
2582     swap(&r->reqbody_queue,&h2r->reqbody_queue);/*currently always empty queue*/
2583   #endif
2584     r->http_host = h2r->http_host;
2585     h2r->http_host = NULL;
2586   #if 0
2587     r->server_name = h2r->server_name;
2588     h2r->server_name = NULL;
2589   #endif
2590     r->target = h2r->target;                    /* copy struct */
2591     r->target_orig = h2r->target_orig;          /* copy struct */
2592   #if 0
2593     r->pathinfo = h2r->pathinfo;                /* copy struct */
2594     r->server_name_buf = h2r->server_name_buf;  /* copy struct */
2595   #endif
2596     memset(&h2r->target, 0, sizeof(buffer));
2597     memset(&h2r->target_orig, 0, sizeof(buffer));
2598   #if 0
2599     memset(&h2r->pathinfo, 0, sizeof(buffer));
2600     memset(&h2r->server_name_buf, 0, sizeof(buffer));
2601   #endif
2602   #if 0
2603     /* skip copying response structures, other state not yet modified in h2r */
2604     /* r write_queue and read_queue are intentionally separate from h2r */
2605     /* r->gw_dechunk must be NULL for HTTP/2 */
2606     /* bytes_written_ckpt and bytes_read_ckpt are for HTTP/1.1 */
2607     /* error handlers have not yet been set */
2608   #endif
2609   #if 0
2610     r->loops_per_request = h2r->loops_per_request;
2611     r->async_callback = h2r->async_callback;
2612   #endif
2613     r->keep_alive = h2r->keep_alive;
2614     r->tmp_buf = h2r->tmp_buf;                /* shared; same as srv->tmp_buf */
2615     r->start_hp = h2r->start_hp;                /* copy struct */
2616 
2617     /* Note: HTTP/1.1 101 Switching Protocols is not immediately written to
2618      * the network here.  As this is called from cleartext Upgrade: h2c,
2619      * we choose to delay sending the status until the beginning of the response
2620      * to the HTTP/1.1 request which included Upgrade: h2c */
2621 }
2622 
2623 
2624 int
2625 h2_check_con_upgrade_h2c (request_st * const r)
2626 {
2627     /* RFC7540 3.2 Starting HTTP/2 for "http" URIs */
2628 
2629     buffer *http_connection, *http2_settings;
2630     buffer *upgrade = http_header_request_get(r, HTTP_HEADER_UPGRADE,
2631                                               CONST_STR_LEN("Upgrade"));
2632     if (NULL == upgrade) return 0;
2633     http_connection = http_header_request_get(r, HTTP_HEADER_CONNECTION,
2634                                               CONST_STR_LEN("Connection"));
2635     if (NULL == http_connection) {
2636         http_header_request_unset(r, HTTP_HEADER_UPGRADE,
2637                                   CONST_STR_LEN("Upgrade"));
2638         return 0;
2639     }
2640     if (r->http_version != HTTP_VERSION_1_1) {
2641         http_header_request_unset(r, HTTP_HEADER_UPGRADE,
2642                                   CONST_STR_LEN("Upgrade"));
2643         http_header_remove_token(http_connection, CONST_STR_LEN("Upgrade"));
2644         return 0;
2645     }
2646 
2647     if (!http_header_str_contains_token(CONST_BUF_LEN(upgrade),
2648                                         CONST_STR_LEN("h2c")))
2649         return 0;
2650 
2651     http2_settings = http_header_request_get(r, HTTP_HEADER_HTTP2_SETTINGS,
2652                                              CONST_STR_LEN("HTTP2-Settings"));
2653     if (NULL != http2_settings) {
2654         if (0 == r->reqbody_length) {
2655             buffer * const b = r->tmp_buf;
2656             buffer_clear(b);
2657             if (r->conf.h2proto > 1/*(must be enabled with server.h2c feature)*/
2658                 &&
2659                 http_header_str_contains_token(CONST_BUF_LEN(http_connection),
2660                                                CONST_STR_LEN("HTTP2-Settings"))
2661                 && buffer_append_base64_decode(b, CONST_BUF_LEN(http2_settings),
2662                                                BASE64_URL)) {
2663                 h2_con_upgrade_h2c(r, b);
2664                 r->http_version = HTTP_VERSION_2;
2665             } /* else ignore if invalid base64 */
2666         }
2667         else {
2668             /* ignore Upgrade: h2c if request body present since we do not
2669              * (currently) handle request body before transition to h2c */
2670             /* RFC7540 3.2 Requests that contain a payload body MUST be sent
2671              * in their entirety before the client can send HTTP/2 frames. */
2672         }
2673         http_header_request_unset(r, HTTP_HEADER_HTTP2_SETTINGS,
2674                                   CONST_STR_LEN("HTTP2-Settings"));
2675         http_header_remove_token(http_connection, CONST_STR_LEN("HTTP2-Settings"));
2676     } /* else ignore Upgrade: h2c; HTTP2-Settings required for Upgrade: h2c */
2677     http_header_request_unset(r, HTTP_HEADER_UPGRADE,
2678                               CONST_STR_LEN("Upgrade"));
2679     http_header_remove_token(http_connection, CONST_STR_LEN("Upgrade"));
2680     return (r->http_version == HTTP_VERSION_2);
2681 }
2682