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