xref: /trafficserver/proxy/http2/HTTP2.cc (revision 48bcbe69)
1 /** @file
2  *
3  *  Fundamental HTTP/2 protocol definitions and parsers.
4  *
5  *  @section license License
6  *
7  *  Licensed to the Apache Software Foundation (ASF) under one
8  *  or more contributor license agreements.  See the NOTICE file
9  *  distributed with this work for additional information
10  *  regarding copyright ownership.  The ASF licenses this file
11  *  to you under the Apache License, Version 2.0 (the
12  *  "License"); you may not use this file except in compliance
13  *  with the License.  You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  *  Unless required by applicable law or agreed to in writing, software
18  *  distributed under the License is distributed on an "AS IS" BASIS,
19  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  *  See the License for the specific language governing permissions and
21  *  limitations under the License.
22  */
23 
24 #include "HTTP2.h"
25 #include "HPACK.h"
26 #include "tscore/ink_assert.h"
27 #include "records/P_RecCore.h"
28 #include "records/P_RecProcess.h"
29 
30 const char *const HTTP2_CONNECTION_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
31 
32 // Constant strings for pseudo headers
33 const char *HTTP2_VALUE_SCHEME    = ":scheme";
34 const char *HTTP2_VALUE_METHOD    = ":method";
35 const char *HTTP2_VALUE_AUTHORITY = ":authority";
36 const char *HTTP2_VALUE_PATH      = ":path";
37 const char *HTTP2_VALUE_STATUS    = ":status";
38 
39 const unsigned HTTP2_LEN_SCHEME    = countof(":scheme") - 1;
40 const unsigned HTTP2_LEN_METHOD    = countof(":method") - 1;
41 const unsigned HTTP2_LEN_AUTHORITY = countof(":authority") - 1;
42 const unsigned HTTP2_LEN_PATH      = countof(":path") - 1;
43 const unsigned HTTP2_LEN_STATUS    = countof(":status") - 1;
44 
45 static size_t HTTP2_LEN_STATUS_VALUE_STR         = 3;
46 static const uint32_t HTTP2_MAX_TABLE_SIZE_LIMIT = 64 * 1024;
47 
48 // Statistics
49 RecRawStatBlock *http2_rsb;
50 static const char *const HTTP2_STAT_CURRENT_CLIENT_CONNECTION_NAME        = "proxy.process.http2.current_client_connections";
51 static const char *const HTTP2_STAT_CURRENT_ACTIVE_CLIENT_CONNECTION_NAME = "proxy.process.http2.current_active_client_connections";
52 static const char *const HTTP2_STAT_CURRENT_CLIENT_STREAM_NAME            = "proxy.process.http2.current_client_streams";
53 static const char *const HTTP2_STAT_TOTAL_CLIENT_STREAM_NAME              = "proxy.process.http2.total_client_streams";
54 static const char *const HTTP2_STAT_TOTAL_TRANSACTIONS_TIME_NAME          = "proxy.process.http2.total_transactions_time";
55 static const char *const HTTP2_STAT_TOTAL_CLIENT_CONNECTION_NAME          = "proxy.process.http2.total_client_connections";
56 static const char *const HTTP2_STAT_CONNECTION_ERRORS_NAME                = "proxy.process.http2.connection_errors";
57 static const char *const HTTP2_STAT_STREAM_ERRORS_NAME                    = "proxy.process.http2.stream_errors";
58 static const char *const HTTP2_STAT_SESSION_DIE_DEFAULT_NAME              = "proxy.process.http2.session_die_default";
59 static const char *const HTTP2_STAT_SESSION_DIE_OTHER_NAME                = "proxy.process.http2.session_die_other";
60 static const char *const HTTP2_STAT_SESSION_DIE_ACTIVE_NAME               = "proxy.process.http2.session_die_active";
61 static const char *const HTTP2_STAT_SESSION_DIE_INACTIVE_NAME             = "proxy.process.http2.session_die_inactive";
62 static const char *const HTTP2_STAT_SESSION_DIE_EOS_NAME                  = "proxy.process.http2.session_die_eos";
63 static const char *const HTTP2_STAT_SESSION_DIE_ERROR_NAME                = "proxy.process.http2.session_die_error";
64 static const char *const HTTP2_STAT_SESSION_DIE_HIGH_ERROR_RATE_NAME      = "proxy.process.http2.session_die_high_error_rate";
65 static const char *const HTTP2_STAT_MAX_SETTINGS_PER_FRAME_EXCEEDED_NAME  = "proxy.process.http2.max_settings_per_frame_exceeded";
66 static const char *const HTTP2_STAT_MAX_SETTINGS_PER_MINUTE_EXCEEDED_NAME = "proxy.process.http2.max_settings_per_minute_exceeded";
67 static const char *const HTTP2_STAT_MAX_SETTINGS_FRAMES_PER_MINUTE_EXCEEDED_NAME =
68   "proxy.process.http2.max_settings_frames_per_minute_exceeded";
69 static const char *const HTTP2_STAT_MAX_PING_FRAMES_PER_MINUTE_EXCEEDED_NAME =
70   "proxy.process.http2.max_ping_frames_per_minute_exceeded";
71 static const char *const HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED_NAME =
72   "proxy.process.http2.max_priority_frames_per_minute_exceeded";
73 static const char *const HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE_NAME = "proxy.process.http2.insufficient_avg_window_update";
74 
75 union byte_pointer {
byte_pointer(void * p)76   byte_pointer(void *p) : ptr(p) {}
77   void *ptr;
78   uint8_t *u8;
79   uint16_t *u16;
80   uint32_t *u32;
81 };
82 
83 template <typename T> union byte_addressable_value {
84   uint8_t bytes[sizeof(T)];
85   T value;
86 };
87 
88 static void
write_and_advance(byte_pointer & dst,const uint8_t * src,size_t length)89 write_and_advance(byte_pointer &dst, const uint8_t *src, size_t length)
90 {
91   memcpy(dst.u8, src, length);
92   dst.u8 += length;
93 }
94 
95 static void
write_and_advance(byte_pointer & dst,uint32_t src)96 write_and_advance(byte_pointer &dst, uint32_t src)
97 {
98   byte_addressable_value<uint32_t> pval;
99 
100   // cppcheck-suppress unreadVariable ; it's an union and be read as pval.bytes
101   pval.value = htonl(src);
102   memcpy(dst.u8, pval.bytes, sizeof(pval.bytes));
103   dst.u8 += sizeof(pval.bytes);
104 }
105 
106 static void
write_and_advance(byte_pointer & dst,uint16_t src)107 write_and_advance(byte_pointer &dst, uint16_t src)
108 {
109   byte_addressable_value<uint16_t> pval;
110 
111   // cppcheck-suppress unreadVariable ; it's an union and be read as pval.bytes
112   pval.value = htons(src);
113   memcpy(dst.u8, pval.bytes, sizeof(pval.bytes));
114   dst.u8 += sizeof(pval.bytes);
115 }
116 
117 static void
write_and_advance(byte_pointer & dst,uint8_t src)118 write_and_advance(byte_pointer &dst, uint8_t src)
119 {
120   *dst.u8 = src;
121   dst.u8++;
122 }
123 
124 template <unsigned N>
125 static void
memcpy_and_advance(uint8_t (& dst)[N],byte_pointer & src)126 memcpy_and_advance(uint8_t (&dst)[N], byte_pointer &src)
127 {
128   memcpy(dst, src.u8, N);
129   src.u8 += N;
130 }
131 
132 static void
memcpy_and_advance(uint8_t (& dst),byte_pointer & src)133 memcpy_and_advance(uint8_t(&dst), byte_pointer &src)
134 {
135   dst = *src.u8;
136   ++src.u8;
137 }
138 
139 bool
http2_frame_header_is_valid(const Http2FrameHeader & hdr,unsigned max_frame_size)140 http2_frame_header_is_valid(const Http2FrameHeader &hdr, unsigned max_frame_size)
141 {
142   // 6.1 If a DATA frame is received whose stream identifier field is 0x0, the recipient MUST
143   // respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
144   if (hdr.type == HTTP2_FRAME_TYPE_DATA && hdr.streamid == 0) {
145     return false;
146   }
147 
148   return true;
149 }
150 
151 bool
http2_settings_parameter_is_valid(const Http2SettingsParameter & param)152 http2_settings_parameter_is_valid(const Http2SettingsParameter &param)
153 {
154   // Static maximum values for Settings parameters.
155   static const uint32_t settings_max[HTTP2_SETTINGS_MAX] = {
156     0,
157     UINT_MAX,              // HTTP2_SETTINGS_HEADER_TABLE_SIZE
158     1,                     // HTTP2_SETTINGS_ENABLE_PUSH
159     UINT_MAX,              // HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS
160     HTTP2_MAX_WINDOW_SIZE, // HTTP2_SETTINGS_INITIAL_WINDOW_SIZE
161     16777215,              // HTTP2_SETTINGS_MAX_FRAME_SIZE
162     UINT_MAX,              // HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE
163   };
164 
165   if (param.id == 0 || param.id >= HTTP2_SETTINGS_MAX) {
166     // Do nothing - 6.5.2 Unsupported parameters MUST be ignored
167     return true;
168   }
169 
170   if (param.value > settings_max[param.id]) {
171     return false;
172   }
173 
174   if (param.id == HTTP2_SETTINGS_ENABLE_PUSH && param.value != 0 && param.value != 1) {
175     return false;
176   }
177 
178   if (param.id == HTTP2_SETTINGS_MAX_FRAME_SIZE && (param.value < (1 << 14) || param.value > (1 << 24) - 1)) {
179     return false;
180   }
181 
182   return true;
183 }
184 
185 // 4.1.  Frame Format
186 //
187 //  0                   1                   2                   3
188 //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
189 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190 // |                 Length (24)                   |
191 // +---------------+---------------+---------------+
192 // |   Type (8)    |   Flags (8)   |
193 // +-+-+-----------+---------------+-------------------------------+
194 // |R|                 Stream Identifier (31)                      |
195 // +=+=============================================================+
196 // |                   Frame Payload (0...)                      ...
197 // +---------------------------------------------------------------+
198 
199 bool
http2_parse_frame_header(IOVec iov,Http2FrameHeader & hdr)200 http2_parse_frame_header(IOVec iov, Http2FrameHeader &hdr)
201 {
202   byte_pointer ptr(iov.iov_base);
203   byte_addressable_value<uint32_t> length_and_type;
204   byte_addressable_value<uint32_t> streamid;
205 
206   if (unlikely(iov.iov_len < HTTP2_FRAME_HEADER_LEN)) {
207     return false;
208   }
209 
210   memcpy_and_advance(length_and_type.bytes, ptr);
211   memcpy_and_advance(hdr.flags, ptr);
212   memcpy_and_advance(streamid.bytes, ptr);
213 
214   hdr.length = ntohl(length_and_type.value) >> 8;
215   hdr.type   = ntohl(length_and_type.value) & 0xff;
216   streamid.bytes[0] &= 0x7f; // Clear the high reserved bit
217   hdr.streamid = ntohl(streamid.value);
218 
219   return true;
220 }
221 
222 bool
http2_write_frame_header(const Http2FrameHeader & hdr,IOVec iov)223 http2_write_frame_header(const Http2FrameHeader &hdr, IOVec iov)
224 {
225   byte_pointer ptr(iov.iov_base);
226 
227   if (unlikely(iov.iov_len < HTTP2_FRAME_HEADER_LEN)) {
228     return false;
229   }
230 
231   byte_addressable_value<uint32_t> length;
232   // cppcheck-suppress unreadVariable ; it's an union and be read as pval.bytes
233   length.value = htonl(hdr.length);
234   // MSB length.bytes[0] is unused.
235   write_and_advance(ptr, length.bytes[1]);
236   write_and_advance(ptr, length.bytes[2]);
237   write_and_advance(ptr, length.bytes[3]);
238 
239   write_and_advance(ptr, hdr.type);
240   write_and_advance(ptr, hdr.flags);
241   write_and_advance(ptr, hdr.streamid);
242 
243   return true;
244 }
245 
246 bool
http2_write_rst_stream(uint32_t error_code,IOVec iov)247 http2_write_rst_stream(uint32_t error_code, IOVec iov)
248 {
249   byte_pointer ptr(iov.iov_base);
250 
251   write_and_advance(ptr, error_code);
252 
253   return true;
254 }
255 
256 bool
http2_write_settings(const Http2SettingsParameter & param,const IOVec & iov)257 http2_write_settings(const Http2SettingsParameter &param, const IOVec &iov)
258 {
259   byte_pointer ptr(iov.iov_base);
260 
261   if (unlikely(iov.iov_len < HTTP2_SETTINGS_PARAMETER_LEN)) {
262     return false;
263   }
264 
265   write_and_advance(ptr, param.id);
266   write_and_advance(ptr, param.value);
267 
268   return true;
269 }
270 
271 bool
http2_write_ping(const uint8_t * opaque_data,IOVec iov)272 http2_write_ping(const uint8_t *opaque_data, IOVec iov)
273 {
274   byte_pointer ptr(iov.iov_base);
275 
276   if (unlikely(iov.iov_len < HTTP2_PING_LEN)) {
277     return false;
278   }
279 
280   write_and_advance(ptr, opaque_data, HTTP2_PING_LEN);
281 
282   return true;
283 }
284 
285 bool
http2_write_goaway(const Http2Goaway & goaway,IOVec iov)286 http2_write_goaway(const Http2Goaway &goaway, IOVec iov)
287 {
288   byte_pointer ptr(iov.iov_base);
289 
290   if (unlikely(iov.iov_len < HTTP2_GOAWAY_LEN)) {
291     return false;
292   }
293 
294   write_and_advance(ptr, goaway.last_streamid);
295   write_and_advance(ptr, static_cast<uint32_t>(goaway.error_code));
296 
297   return true;
298 }
299 
300 bool
http2_write_window_update(const uint32_t new_size,const IOVec & iov)301 http2_write_window_update(const uint32_t new_size, const IOVec &iov)
302 {
303   byte_pointer ptr(iov.iov_base);
304   write_and_advance(ptr, new_size);
305 
306   return true;
307 }
308 
309 bool
http2_write_push_promise(const Http2PushPromise & push_promise,const uint8_t * src,size_t length,const IOVec & iov)310 http2_write_push_promise(const Http2PushPromise &push_promise, const uint8_t *src, size_t length, const IOVec &iov)
311 {
312   byte_pointer ptr(iov.iov_base);
313   write_and_advance(ptr, push_promise.promised_streamid);
314   write_and_advance(ptr, src, length);
315   return true;
316 }
317 
318 bool
http2_parse_headers_parameter(IOVec iov,Http2HeadersParameter & params)319 http2_parse_headers_parameter(IOVec iov, Http2HeadersParameter &params)
320 {
321   byte_pointer ptr(iov.iov_base);
322   memcpy_and_advance(params.pad_length, ptr);
323 
324   return true;
325 }
326 
327 bool
http2_parse_priority_parameter(IOVec iov,Http2Priority & priority)328 http2_parse_priority_parameter(IOVec iov, Http2Priority &priority)
329 {
330   byte_pointer ptr(iov.iov_base);
331   byte_addressable_value<uint32_t> dependency;
332 
333   memcpy_and_advance(dependency.bytes, ptr);
334 
335   priority.exclusive_flag = dependency.bytes[0] & 0x80;
336 
337   dependency.bytes[0] &= 0x7f; // Clear the highest bit for exclusive flag
338   priority.stream_dependency = ntohl(dependency.value);
339 
340   memcpy_and_advance(priority.weight, ptr);
341 
342   return true;
343 }
344 
345 bool
http2_parse_rst_stream(IOVec iov,Http2RstStream & rst_stream)346 http2_parse_rst_stream(IOVec iov, Http2RstStream &rst_stream)
347 {
348   byte_pointer ptr(iov.iov_base);
349   byte_addressable_value<uint32_t> ec;
350 
351   memcpy_and_advance(ec.bytes, ptr);
352 
353   rst_stream.error_code = ntohl(ec.value);
354 
355   return true;
356 }
357 
358 bool
http2_parse_settings_parameter(IOVec iov,Http2SettingsParameter & param)359 http2_parse_settings_parameter(IOVec iov, Http2SettingsParameter &param)
360 {
361   byte_pointer ptr(iov.iov_base);
362   byte_addressable_value<uint16_t> pid;
363   byte_addressable_value<uint32_t> pval;
364 
365   if (unlikely(iov.iov_len < HTTP2_SETTINGS_PARAMETER_LEN)) {
366     return false;
367   }
368 
369   memcpy_and_advance(pid.bytes, ptr);
370   memcpy_and_advance(pval.bytes, ptr);
371 
372   param.id    = ntohs(pid.value);
373   param.value = ntohl(pval.value);
374 
375   return true;
376 }
377 
378 bool
http2_parse_goaway(IOVec iov,Http2Goaway & goaway)379 http2_parse_goaway(IOVec iov, Http2Goaway &goaway)
380 {
381   byte_pointer ptr(iov.iov_base);
382   byte_addressable_value<uint32_t> sid;
383   byte_addressable_value<uint32_t> ec;
384 
385   memcpy_and_advance(sid.bytes, ptr);
386   memcpy_and_advance(ec.bytes, ptr);
387 
388   goaway.last_streamid = ntohl(sid.value);
389   goaway.error_code    = static_cast<Http2ErrorCode>(ntohl(ec.value));
390   return true;
391 }
392 
393 bool
http2_parse_window_update(IOVec iov,uint32_t & size)394 http2_parse_window_update(IOVec iov, uint32_t &size)
395 {
396   byte_pointer ptr(iov.iov_base);
397   byte_addressable_value<uint32_t> s;
398 
399   memcpy_and_advance(s.bytes, ptr);
400 
401   size = ntohl(s.value);
402 
403   return true;
404 }
405 
406 ParseResult
http2_convert_header_from_2_to_1_1(HTTPHdr * headers)407 http2_convert_header_from_2_to_1_1(HTTPHdr *headers)
408 {
409   MIMEField *field;
410 
411   ink_assert(http_hdr_type_get(headers->m_http) != HTTP_TYPE_UNKNOWN);
412 
413   if (http_hdr_type_get(headers->m_http) == HTTP_TYPE_REQUEST) {
414     const char *scheme, *authority, *path;
415     int scheme_len, authority_len, path_len;
416 
417     // Get values of :scheme, :authority and :path to assemble requested URL
418     if ((field = headers->field_find(HTTP2_VALUE_SCHEME, HTTP2_LEN_SCHEME)) != nullptr && field->value_is_valid()) {
419       scheme = field->value_get(&scheme_len);
420     } else {
421       return PARSE_RESULT_ERROR;
422     }
423 
424     if ((field = headers->field_find(HTTP2_VALUE_AUTHORITY, HTTP2_LEN_AUTHORITY)) != nullptr && field->value_is_valid()) {
425       authority = field->value_get(&authority_len);
426     } else {
427       return PARSE_RESULT_ERROR;
428     }
429 
430     if ((field = headers->field_find(HTTP2_VALUE_PATH, HTTP2_LEN_PATH)) != nullptr && field->value_is_valid()) {
431       path = field->value_get(&path_len);
432     } else {
433       return PARSE_RESULT_ERROR;
434     }
435 
436     // Parse URL
437     Arena arena;
438     size_t url_length     = scheme_len + 3 + authority_len + path_len;
439     char *url             = arena.str_alloc(url_length);
440     const char *url_start = url;
441 
442     memcpy(url, scheme, scheme_len);
443     memcpy(url + scheme_len, "://", 3);
444     memcpy(url + scheme_len + 3, authority, authority_len);
445     memcpy(url + scheme_len + 3 + authority_len, path, path_len);
446     url_parse(headers->m_heap, headers->m_http->u.req.m_url_impl, &url_start, url + url_length, true);
447     arena.str_free(url);
448 
449     // Get value of :method
450     if ((field = headers->field_find(HTTP2_VALUE_METHOD, HTTP2_LEN_METHOD)) != nullptr && field->value_is_valid()) {
451       int method_len;
452       const char *method = field->value_get(&method_len);
453 
454       int method_wks_idx = hdrtoken_tokenize(method, method_len);
455       http_hdr_method_set(headers->m_heap, headers->m_http, method, method_wks_idx, method_len, false);
456     } else {
457       return PARSE_RESULT_ERROR;
458     }
459 
460     // Combine Cookie headers ([RFC 7540] 8.1.2.5.)
461     field = headers->field_find(MIME_FIELD_COOKIE, MIME_LEN_COOKIE);
462     if (field) {
463       headers->field_combine_dups(field, true, ';');
464     }
465 
466     // Convert HTTP version to 1.1
467     int32_t version = HTTP_VERSION(1, 1);
468     http_hdr_version_set(headers->m_http, version);
469 
470     // Remove HTTP/2 style headers
471     headers->field_delete(HTTP2_VALUE_SCHEME, HTTP2_LEN_SCHEME);
472     headers->field_delete(HTTP2_VALUE_METHOD, HTTP2_LEN_METHOD);
473     headers->field_delete(HTTP2_VALUE_AUTHORITY, HTTP2_LEN_AUTHORITY);
474     headers->field_delete(HTTP2_VALUE_PATH, HTTP2_LEN_PATH);
475   } else {
476     // Set HTTP Version 1.1
477     int32_t version = HTTP_VERSION(1, 1);
478     http_hdr_version_set(headers->m_http, version);
479 
480     // Set status from :status
481     if ((field = headers->field_find(HTTP2_VALUE_STATUS, HTTP2_LEN_STATUS)) != nullptr) {
482       int status_len;
483       const char *status = field->value_get(&status_len);
484       headers->status_set(http_parse_status(status, status + status_len));
485     } else {
486       return PARSE_RESULT_ERROR;
487     }
488 
489     // Remove HTTP/2 style headers
490     headers->field_delete(HTTP2_VALUE_STATUS, HTTP2_LEN_STATUS);
491   }
492 
493   // Check validity of all names and values
494   MIMEFieldIter iter;
495   for (auto *mf = headers->iter_get_first(&iter); mf != nullptr; mf = headers->iter_get_next(&iter)) {
496     if (!mf->name_is_valid() || !mf->value_is_valid()) {
497       return PARSE_RESULT_ERROR;
498     }
499   }
500 
501   return PARSE_RESULT_DONE;
502 }
503 
504 void
http2_generate_h2_header_from_1_1(HTTPHdr * headers,HTTPHdr * h2_headers)505 http2_generate_h2_header_from_1_1(HTTPHdr *headers, HTTPHdr *h2_headers)
506 {
507   h2_headers->create(http_hdr_type_get(headers->m_http));
508 
509   if (http_hdr_type_get(headers->m_http) == HTTP_TYPE_RESPONSE) {
510     // Add ':status' header field
511     char status_str[HTTP2_LEN_STATUS_VALUE_STR + 1];
512     snprintf(status_str, sizeof(status_str), "%d", headers->status_get());
513     MIMEField *status_field = h2_headers->field_create(HTTP2_VALUE_STATUS, HTTP2_LEN_STATUS);
514     status_field->value_set(h2_headers->m_heap, h2_headers->m_mime, status_str, HTTP2_LEN_STATUS_VALUE_STR);
515     h2_headers->field_attach(status_field);
516 
517   } else if (http_hdr_type_get(headers->m_http) == HTTP_TYPE_REQUEST) {
518     MIMEField *field;
519     const char *value;
520     int value_len;
521 
522     // Add ':authority' header field
523     // TODO: remove host/Host header
524     // [RFC 7540] 8.1.2.3. Clients that generate HTTP/2 requests directly SHOULD use the ":authority" pseudo-header field instead of
525     // the Host header field.
526     field = h2_headers->field_create(HTTP2_VALUE_AUTHORITY, HTTP2_LEN_AUTHORITY);
527     value = headers->host_get(&value_len);
528     if (headers->is_port_in_header()) {
529       int port            = headers->port_get();
530       char *host_and_port = static_cast<char *>(ats_malloc(value_len + 8));
531       value_len           = snprintf(host_and_port, value_len + 8, "%.*s:%d", value_len, value, port);
532       field->value_set(h2_headers->m_heap, h2_headers->m_mime, host_and_port, value_len);
533       ats_free(host_and_port);
534     } else {
535       field->value_set(h2_headers->m_heap, h2_headers->m_mime, value, value_len);
536     }
537     h2_headers->field_attach(field);
538 
539     // Add ':method' header field
540     field = h2_headers->field_create(HTTP2_VALUE_METHOD, HTTP2_LEN_METHOD);
541     value = headers->method_get(&value_len);
542     field->value_set(h2_headers->m_heap, h2_headers->m_mime, value, value_len);
543     h2_headers->field_attach(field);
544 
545     // Add ':path' header field
546     field      = h2_headers->field_create(HTTP2_VALUE_PATH, HTTP2_LEN_PATH);
547     value      = headers->path_get(&value_len);
548     char *path = static_cast<char *>(ats_malloc(value_len + 1));
549     path[0]    = '/';
550     memcpy(path + 1, value, value_len);
551     field->value_set(h2_headers->m_heap, h2_headers->m_mime, path, value_len + 1);
552     ats_free(path);
553     h2_headers->field_attach(field);
554 
555     // Add ':scheme' header field
556     field = h2_headers->field_create(HTTP2_VALUE_SCHEME, HTTP2_LEN_SCHEME);
557     value = headers->scheme_get(&value_len);
558     field->value_set(h2_headers->m_heap, h2_headers->m_mime, value, value_len);
559     h2_headers->field_attach(field);
560   }
561 
562   // Copy headers
563   // Intermediaries SHOULD remove connection-specific header fields.
564   MIMEFieldIter field_iter;
565   for (MIMEField *field = headers->iter_get_first(&field_iter); field != nullptr; field = headers->iter_get_next(&field_iter)) {
566     const char *name;
567     int name_len;
568     const char *value;
569     int value_len;
570     name = field->name_get(&name_len);
571     if ((name_len == MIME_LEN_CONNECTION && strncasecmp(name, MIME_FIELD_CONNECTION, name_len) == 0) ||
572         (name_len == MIME_LEN_KEEP_ALIVE && strncasecmp(name, MIME_FIELD_KEEP_ALIVE, name_len) == 0) ||
573         (name_len == MIME_LEN_PROXY_CONNECTION && strncasecmp(name, MIME_FIELD_PROXY_CONNECTION, name_len) == 0) ||
574         (name_len == MIME_LEN_TRANSFER_ENCODING && strncasecmp(name, MIME_FIELD_TRANSFER_ENCODING, name_len) == 0) ||
575         (name_len == MIME_LEN_UPGRADE && strncasecmp(name, MIME_FIELD_UPGRADE, name_len) == 0)) {
576       continue;
577     }
578     MIMEField *newfield;
579     name     = field->name_get(&name_len);
580     newfield = h2_headers->field_create(name, name_len);
581     value    = field->value_get(&value_len);
582     newfield->value_set(h2_headers->m_heap, h2_headers->m_mime, value, value_len);
583     h2_headers->field_attach(newfield);
584   }
585 }
586 
587 Http2ErrorCode
http2_encode_header_blocks(HTTPHdr * in,uint8_t * out,uint32_t out_len,uint32_t * len_written,HpackHandle & handle,int32_t maximum_table_size)588 http2_encode_header_blocks(HTTPHdr *in, uint8_t *out, uint32_t out_len, uint32_t *len_written, HpackHandle &handle,
589                            int32_t maximum_table_size)
590 {
591   // Limit the maximum table size to the configured value or 64kB at maximum, which is the size advertised by major clients
592   maximum_table_size =
593     std::min(maximum_table_size, static_cast<int32_t>(std::min(Http2::header_table_size_limit, HTTP2_MAX_TABLE_SIZE_LIMIT)));
594   // Set maximum table size only if it is different from current maximum size
595   if (maximum_table_size == hpack_get_maximum_table_size(handle)) {
596     maximum_table_size = -1;
597   }
598   // TODO: It would be better to split Cookie header value
599   int64_t result = hpack_encode_header_block(handle, out, out_len, in, maximum_table_size);
600   if (result < 0) {
601     return Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR;
602   }
603   if (len_written) {
604     *len_written = result;
605   }
606   return Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
607 }
608 
609 /*
610  * Decode Header Blocks to Header List.
611  */
612 Http2ErrorCode
http2_decode_header_blocks(HTTPHdr * hdr,const uint8_t * buf_start,const uint32_t buf_len,uint32_t * len_read,HpackHandle & handle,bool & trailing_header,uint32_t maximum_table_size)613 http2_decode_header_blocks(HTTPHdr *hdr, const uint8_t *buf_start, const uint32_t buf_len, uint32_t *len_read, HpackHandle &handle,
614                            bool &trailing_header, uint32_t maximum_table_size)
615 {
616   const MIMEField *field;
617   const char *value;
618   int len;
619   bool is_trailing_header = trailing_header;
620   int64_t result = hpack_decode_header_block(handle, hdr, buf_start, buf_len, Http2::max_header_list_size, maximum_table_size);
621 
622   if (result < 0) {
623     if (result == HPACK_ERROR_COMPRESSION_ERROR) {
624       return Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR;
625     } else if (result == HPACK_ERROR_SIZE_EXCEEDED_ERROR) {
626       return Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM;
627     }
628 
629     return Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
630   }
631   if (len_read) {
632     *len_read = result;
633   }
634 
635   MIMEFieldIter iter;
636   unsigned int expected_pseudo_header_count = 4;
637   unsigned int pseudo_header_count          = 0;
638 
639   if (is_trailing_header) {
640     expected_pseudo_header_count = 0;
641   }
642   for (field = hdr->iter_get_first(&iter); field != nullptr; field = hdr->iter_get_next(&iter)) {
643     value = field->name_get(&len);
644     // Pseudo headers must appear before regular headers
645     if (len && value[0] == ':') {
646       ++pseudo_header_count;
647       if (pseudo_header_count > expected_pseudo_header_count) {
648         return Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
649       }
650     } else if (len <= 0) {
651       return Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
652     } else {
653       if (pseudo_header_count != expected_pseudo_header_count) {
654         return Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
655       }
656     }
657   }
658 
659   // rfc7540,sec8.1.2.2: Any message containing connection-specific header
660   // fields MUST be treated as malformed
661   if (hdr->field_find(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION) != nullptr ||
662       hdr->field_find(MIME_FIELD_KEEP_ALIVE, MIME_LEN_KEEP_ALIVE) != nullptr ||
663       hdr->field_find(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION) != nullptr ||
664       hdr->field_find(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING) != nullptr ||
665       hdr->field_find(MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE) != nullptr) {
666     return Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
667   }
668 
669   // :path pseudo header MUST NOT empty for http or https URIs
670   field = hdr->field_find(HTTP2_VALUE_PATH, HTTP2_LEN_PATH);
671   if (field) {
672     field->value_get(&len);
673     if (len == 0) {
674       return Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
675     }
676   }
677 
678   // turn on that we have a trailer header
679   const char trailer_name[] = "trailer";
680   field                     = hdr->field_find(trailer_name, sizeof(trailer_name) - 1);
681   if (field) {
682     trailing_header = true;
683   }
684 
685   // when The TE header field is received, it MUST NOT contain any
686   // value other than "trailers".
687   field = hdr->field_find(MIME_FIELD_TE, MIME_LEN_TE);
688   if (field) {
689     value = field->value_get(&len);
690     if (!(len == 8 && memcmp(value, "trailers", 8) == 0)) {
691       return Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
692     }
693   }
694 
695   if (!is_trailing_header) {
696     // Check pseudo headers
697     if (hdr->fields_count() >= 4) {
698       if (hdr->field_find(HTTP2_VALUE_SCHEME, HTTP2_LEN_SCHEME) == nullptr ||
699           hdr->field_find(HTTP2_VALUE_METHOD, HTTP2_LEN_METHOD) == nullptr ||
700           hdr->field_find(HTTP2_VALUE_PATH, HTTP2_LEN_PATH) == nullptr ||
701           hdr->field_find(HTTP2_VALUE_AUTHORITY, HTTP2_LEN_AUTHORITY) == nullptr ||
702           hdr->field_find(HTTP2_VALUE_STATUS, HTTP2_LEN_STATUS) != nullptr) {
703         // Decoded header field is invalid
704         return Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
705       }
706     } else {
707       // Pseudo headers is insufficient
708       return Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
709     }
710   }
711 
712   return Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
713 }
714 
715 // Initialize this subsystem with librecords configs (for now)
716 uint32_t Http2::max_concurrent_streams_in      = 100;
717 uint32_t Http2::min_concurrent_streams_in      = 10;
718 uint32_t Http2::max_active_streams_in          = 0;
719 bool Http2::throttling                         = false;
720 uint32_t Http2::stream_priority_enabled        = 0;
721 uint32_t Http2::initial_window_size            = 1048576;
722 uint32_t Http2::max_frame_size                 = 16384;
723 uint32_t Http2::header_table_size              = 4096;
724 uint32_t Http2::max_header_list_size           = 4294967295;
725 uint32_t Http2::accept_no_activity_timeout     = 120;
726 uint32_t Http2::no_activity_timeout_in         = 120;
727 uint32_t Http2::active_timeout_in              = 0;
728 uint32_t Http2::push_diary_size                = 256;
729 uint32_t Http2::zombie_timeout_in              = 0;
730 float Http2::stream_error_rate_threshold       = 0.1;
731 uint32_t Http2::max_settings_per_frame         = 7;
732 uint32_t Http2::max_settings_per_minute        = 14;
733 uint32_t Http2::max_settings_frames_per_minute = 14;
734 uint32_t Http2::max_ping_frames_per_minute     = 60;
735 uint32_t Http2::max_priority_frames_per_minute = 120;
736 float Http2::min_avg_window_update             = 2560.0;
737 uint32_t Http2::con_slow_log_threshold         = 0;
738 uint32_t Http2::stream_slow_log_threshold      = 0;
739 uint32_t Http2::header_table_size_limit        = 65536;
740 
741 void
init()742 Http2::init()
743 {
744   REC_EstablishStaticConfigInt32U(max_concurrent_streams_in, "proxy.config.http2.max_concurrent_streams_in");
745   REC_EstablishStaticConfigInt32U(min_concurrent_streams_in, "proxy.config.http2.min_concurrent_streams_in");
746   REC_EstablishStaticConfigInt32U(max_active_streams_in, "proxy.config.http2.max_active_streams_in");
747   REC_EstablishStaticConfigInt32U(stream_priority_enabled, "proxy.config.http2.stream_priority_enabled");
748   REC_EstablishStaticConfigInt32U(initial_window_size, "proxy.config.http2.initial_window_size_in");
749   REC_EstablishStaticConfigInt32U(max_frame_size, "proxy.config.http2.max_frame_size");
750   REC_EstablishStaticConfigInt32U(header_table_size, "proxy.config.http2.header_table_size");
751   REC_EstablishStaticConfigInt32U(max_header_list_size, "proxy.config.http2.max_header_list_size");
752   REC_EstablishStaticConfigInt32U(accept_no_activity_timeout, "proxy.config.http2.accept_no_activity_timeout");
753   REC_EstablishStaticConfigInt32U(no_activity_timeout_in, "proxy.config.http2.no_activity_timeout_in");
754   REC_EstablishStaticConfigInt32U(active_timeout_in, "proxy.config.http2.active_timeout_in");
755   REC_EstablishStaticConfigInt32U(push_diary_size, "proxy.config.http2.push_diary_size");
756   REC_EstablishStaticConfigInt32U(zombie_timeout_in, "proxy.config.http2.zombie_debug_timeout_in");
757   REC_EstablishStaticConfigFloat(stream_error_rate_threshold, "proxy.config.http2.stream_error_rate_threshold");
758   REC_EstablishStaticConfigInt32U(max_settings_per_frame, "proxy.config.http2.max_settings_per_frame");
759   REC_EstablishStaticConfigInt32U(max_settings_per_minute, "proxy.config.http2.max_settings_per_minute");
760   REC_EstablishStaticConfigInt32U(max_settings_frames_per_minute, "proxy.config.http2.max_settings_frames_per_minute");
761   REC_EstablishStaticConfigInt32U(max_ping_frames_per_minute, "proxy.config.http2.max_ping_frames_per_minute");
762   REC_EstablishStaticConfigInt32U(max_priority_frames_per_minute, "proxy.config.http2.max_priority_frames_per_minute");
763   REC_EstablishStaticConfigFloat(min_avg_window_update, "proxy.config.http2.min_avg_window_update");
764   REC_EstablishStaticConfigInt32U(con_slow_log_threshold, "proxy.config.http2.connection.slow.log.threshold");
765   REC_EstablishStaticConfigInt32U(stream_slow_log_threshold, "proxy.config.http2.stream.slow.log.threshold");
766   REC_EstablishStaticConfigInt32U(header_table_size_limit, "proxy.config.http2.header_table_size_limit");
767 
768   // If any settings is broken, ATS should not start
769   ink_release_assert(http2_settings_parameter_is_valid({HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, max_concurrent_streams_in}));
770   ink_release_assert(http2_settings_parameter_is_valid({HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, min_concurrent_streams_in}));
771   ink_release_assert(http2_settings_parameter_is_valid({HTTP2_SETTINGS_INITIAL_WINDOW_SIZE, initial_window_size}));
772   ink_release_assert(http2_settings_parameter_is_valid({HTTP2_SETTINGS_MAX_FRAME_SIZE, max_frame_size}));
773   ink_release_assert(http2_settings_parameter_is_valid({HTTP2_SETTINGS_HEADER_TABLE_SIZE, header_table_size}));
774   ink_release_assert(http2_settings_parameter_is_valid({HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, max_header_list_size}));
775 
776 #define HTTP2_CLEAR_DYN_STAT(x)          \
777   do {                                   \
778     RecSetRawStatSum(http2_rsb, x, 0);   \
779     RecSetRawStatCount(http2_rsb, x, 0); \
780   } while (0);
781 
782   // Setup statistics
783   http2_rsb = RecAllocateRawStatBlock(static_cast<int>(HTTP2_N_STATS));
784   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_CURRENT_CLIENT_CONNECTION_NAME, RECD_INT, RECP_NON_PERSISTENT,
785                      static_cast<int>(HTTP2_STAT_CURRENT_CLIENT_SESSION_COUNT), RecRawStatSyncSum);
786   HTTP2_CLEAR_DYN_STAT(HTTP2_STAT_CURRENT_CLIENT_SESSION_COUNT);
787   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_CURRENT_ACTIVE_CLIENT_CONNECTION_NAME, RECD_INT, RECP_NON_PERSISTENT,
788                      static_cast<int>(HTTP2_STAT_CURRENT_ACTIVE_CLIENT_CONNECTION_COUNT), RecRawStatSyncSum);
789   HTTP2_CLEAR_DYN_STAT(HTTP2_STAT_CURRENT_ACTIVE_CLIENT_CONNECTION_COUNT);
790   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_CURRENT_CLIENT_STREAM_NAME, RECD_INT, RECP_NON_PERSISTENT,
791                      static_cast<int>(HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT), RecRawStatSyncSum);
792   HTTP2_CLEAR_DYN_STAT(HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT);
793   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_TOTAL_CLIENT_STREAM_NAME, RECD_INT, RECP_PERSISTENT,
794                      static_cast<int>(HTTP2_STAT_TOTAL_CLIENT_STREAM_COUNT), RecRawStatSyncCount);
795   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_TOTAL_TRANSACTIONS_TIME_NAME, RECD_INT, RECP_PERSISTENT,
796                      static_cast<int>(HTTP2_STAT_TOTAL_TRANSACTIONS_TIME), RecRawStatSyncSum);
797   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_TOTAL_CLIENT_CONNECTION_NAME, RECD_INT, RECP_PERSISTENT,
798                      static_cast<int>(HTTP2_STAT_TOTAL_CLIENT_CONNECTION_COUNT), RecRawStatSyncSum);
799   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_CONNECTION_ERRORS_NAME, RECD_INT, RECP_PERSISTENT,
800                      static_cast<int>(HTTP2_STAT_CONNECTION_ERRORS_COUNT), RecRawStatSyncSum);
801   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_STREAM_ERRORS_NAME, RECD_INT, RECP_PERSISTENT,
802                      static_cast<int>(HTTP2_STAT_STREAM_ERRORS_COUNT), RecRawStatSyncSum);
803   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_SESSION_DIE_DEFAULT_NAME, RECD_INT, RECP_PERSISTENT,
804                      static_cast<int>(HTTP2_STAT_SESSION_DIE_DEFAULT), RecRawStatSyncSum);
805   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_SESSION_DIE_OTHER_NAME, RECD_INT, RECP_PERSISTENT,
806                      static_cast<int>(HTTP2_STAT_SESSION_DIE_OTHER), RecRawStatSyncSum);
807   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_SESSION_DIE_EOS_NAME, RECD_INT, RECP_PERSISTENT,
808                      static_cast<int>(HTTP2_STAT_SESSION_DIE_EOS), RecRawStatSyncSum);
809   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_SESSION_DIE_ACTIVE_NAME, RECD_INT, RECP_PERSISTENT,
810                      static_cast<int>(HTTP2_STAT_SESSION_DIE_ACTIVE), RecRawStatSyncSum);
811   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_SESSION_DIE_INACTIVE_NAME, RECD_INT, RECP_PERSISTENT,
812                      static_cast<int>(HTTP2_STAT_SESSION_DIE_INACTIVE), RecRawStatSyncSum);
813   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_SESSION_DIE_ERROR_NAME, RECD_INT, RECP_PERSISTENT,
814                      static_cast<int>(HTTP2_STAT_SESSION_DIE_ERROR), RecRawStatSyncSum);
815   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_SESSION_DIE_HIGH_ERROR_RATE_NAME, RECD_INT, RECP_PERSISTENT,
816                      static_cast<int>(HTTP2_STAT_SESSION_DIE_HIGH_ERROR_RATE), RecRawStatSyncSum);
817   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_MAX_SETTINGS_PER_FRAME_EXCEEDED_NAME, RECD_INT, RECP_PERSISTENT,
818                      static_cast<int>(HTTP2_STAT_MAX_SETTINGS_PER_FRAME_EXCEEDED), RecRawStatSyncSum);
819   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_MAX_SETTINGS_PER_MINUTE_EXCEEDED_NAME, RECD_INT, RECP_PERSISTENT,
820                      static_cast<int>(HTTP2_STAT_MAX_SETTINGS_PER_MINUTE_EXCEEDED), RecRawStatSyncSum);
821   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_MAX_SETTINGS_FRAMES_PER_MINUTE_EXCEEDED_NAME, RECD_INT, RECP_PERSISTENT,
822                      static_cast<int>(HTTP2_STAT_MAX_SETTINGS_FRAMES_PER_MINUTE_EXCEEDED), RecRawStatSyncSum);
823   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_MAX_PING_FRAMES_PER_MINUTE_EXCEEDED_NAME, RECD_INT, RECP_PERSISTENT,
824                      static_cast<int>(HTTP2_STAT_MAX_PING_FRAMES_PER_MINUTE_EXCEEDED), RecRawStatSyncSum);
825   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED_NAME, RECD_INT, RECP_PERSISTENT,
826                      static_cast<int>(HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED), RecRawStatSyncSum);
827   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE_NAME, RECD_INT, RECP_PERSISTENT,
828                      static_cast<int>(HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE), RecRawStatSyncSum);
829 }
830 
831 #if TS_HAS_TESTS
832 
833 void forceLinkRegressionHPACK();
834 void
forceLinkRegressionHPACKCaller()835 forceLinkRegressionHPACKCaller()
836 {
837   forceLinkRegressionHPACK();
838 }
839 
840 #include "tscore/TestBox.h"
841 
842 /***********************************************************************************
843  *                                                                                 *
844  *                       Regression test for HTTP/2                                *
845  *                                                                                 *
846  ***********************************************************************************/
847 
848 const static struct {
849   uint8_t ftype;
850   uint8_t fflags;
851   bool valid;
852 } http2_frame_flags_test_case[] = {{HTTP2_FRAME_TYPE_DATA, 0x00, true},
853                                    {HTTP2_FRAME_TYPE_DATA, 0x01, true},
854                                    {HTTP2_FRAME_TYPE_DATA, 0x02, false},
855                                    {HTTP2_FRAME_TYPE_DATA, 0x04, false},
856                                    {HTTP2_FRAME_TYPE_DATA, 0x08, true},
857                                    {HTTP2_FRAME_TYPE_DATA, 0x10, false},
858                                    {HTTP2_FRAME_TYPE_DATA, 0x20, false},
859                                    {HTTP2_FRAME_TYPE_DATA, 0x40, false},
860                                    {HTTP2_FRAME_TYPE_DATA, 0x80, false},
861                                    {HTTP2_FRAME_TYPE_HEADERS, 0x00, true},
862                                    {HTTP2_FRAME_TYPE_HEADERS, 0x01, true},
863                                    {HTTP2_FRAME_TYPE_HEADERS, 0x02, false},
864                                    {HTTP2_FRAME_TYPE_HEADERS, 0x04, true},
865                                    {HTTP2_FRAME_TYPE_HEADERS, 0x08, true},
866                                    {HTTP2_FRAME_TYPE_HEADERS, 0x10, false},
867                                    {HTTP2_FRAME_TYPE_HEADERS, 0x20, true},
868                                    {HTTP2_FRAME_TYPE_HEADERS, 0x40, false},
869                                    {HTTP2_FRAME_TYPE_HEADERS, 0x80, false},
870                                    {HTTP2_FRAME_TYPE_PRIORITY, 0x00, true},
871                                    {HTTP2_FRAME_TYPE_PRIORITY, 0x01, false},
872                                    {HTTP2_FRAME_TYPE_PRIORITY, 0x02, false},
873                                    {HTTP2_FRAME_TYPE_PRIORITY, 0x04, false},
874                                    {HTTP2_FRAME_TYPE_PRIORITY, 0x08, false},
875                                    {HTTP2_FRAME_TYPE_PRIORITY, 0x10, false},
876                                    {HTTP2_FRAME_TYPE_PRIORITY, 0x20, false},
877                                    {HTTP2_FRAME_TYPE_PRIORITY, 0x40, false},
878                                    {HTTP2_FRAME_TYPE_PRIORITY, 0x80, false},
879                                    {HTTP2_FRAME_TYPE_RST_STREAM, 0x00, true},
880                                    {HTTP2_FRAME_TYPE_RST_STREAM, 0x01, false},
881                                    {HTTP2_FRAME_TYPE_RST_STREAM, 0x02, false},
882                                    {HTTP2_FRAME_TYPE_RST_STREAM, 0x04, false},
883                                    {HTTP2_FRAME_TYPE_RST_STREAM, 0x08, false},
884                                    {HTTP2_FRAME_TYPE_RST_STREAM, 0x10, false},
885                                    {HTTP2_FRAME_TYPE_RST_STREAM, 0x20, false},
886                                    {HTTP2_FRAME_TYPE_RST_STREAM, 0x40, false},
887                                    {HTTP2_FRAME_TYPE_RST_STREAM, 0x80, false},
888                                    {HTTP2_FRAME_TYPE_SETTINGS, 0x00, true},
889                                    {HTTP2_FRAME_TYPE_SETTINGS, 0x01, true},
890                                    {HTTP2_FRAME_TYPE_SETTINGS, 0x02, false},
891                                    {HTTP2_FRAME_TYPE_SETTINGS, 0x04, false},
892                                    {HTTP2_FRAME_TYPE_SETTINGS, 0x08, false},
893                                    {HTTP2_FRAME_TYPE_SETTINGS, 0x10, false},
894                                    {HTTP2_FRAME_TYPE_SETTINGS, 0x20, false},
895                                    {HTTP2_FRAME_TYPE_SETTINGS, 0x40, false},
896                                    {HTTP2_FRAME_TYPE_SETTINGS, 0x80, false},
897                                    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x00, true},
898                                    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x01, false},
899                                    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x02, false},
900                                    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x04, true},
901                                    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x08, true},
902                                    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x10, false},
903                                    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x20, false},
904                                    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x40, false},
905                                    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x80, false},
906                                    {HTTP2_FRAME_TYPE_PING, 0x00, true},
907                                    {HTTP2_FRAME_TYPE_PING, 0x01, true},
908                                    {HTTP2_FRAME_TYPE_PING, 0x02, false},
909                                    {HTTP2_FRAME_TYPE_PING, 0x04, false},
910                                    {HTTP2_FRAME_TYPE_PING, 0x08, false},
911                                    {HTTP2_FRAME_TYPE_PING, 0x10, false},
912                                    {HTTP2_FRAME_TYPE_PING, 0x20, false},
913                                    {HTTP2_FRAME_TYPE_PING, 0x40, false},
914                                    {HTTP2_FRAME_TYPE_PING, 0x80, false},
915                                    {HTTP2_FRAME_TYPE_GOAWAY, 0x00, true},
916                                    {HTTP2_FRAME_TYPE_GOAWAY, 0x01, false},
917                                    {HTTP2_FRAME_TYPE_GOAWAY, 0x02, false},
918                                    {HTTP2_FRAME_TYPE_GOAWAY, 0x04, false},
919                                    {HTTP2_FRAME_TYPE_GOAWAY, 0x08, false},
920                                    {HTTP2_FRAME_TYPE_GOAWAY, 0x10, false},
921                                    {HTTP2_FRAME_TYPE_GOAWAY, 0x20, false},
922                                    {HTTP2_FRAME_TYPE_GOAWAY, 0x40, false},
923                                    {HTTP2_FRAME_TYPE_GOAWAY, 0x80, false},
924                                    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x00, true},
925                                    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x01, false},
926                                    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x02, false},
927                                    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x04, false},
928                                    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x08, false},
929                                    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x10, false},
930                                    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x20, false},
931                                    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x40, false},
932                                    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x80, false},
933                                    {HTTP2_FRAME_TYPE_CONTINUATION, 0x00, true},
934                                    {HTTP2_FRAME_TYPE_CONTINUATION, 0x01, false},
935                                    {HTTP2_FRAME_TYPE_CONTINUATION, 0x02, false},
936                                    {HTTP2_FRAME_TYPE_CONTINUATION, 0x04, true},
937                                    {HTTP2_FRAME_TYPE_CONTINUATION, 0x08, false},
938                                    {HTTP2_FRAME_TYPE_CONTINUATION, 0x10, false},
939                                    {HTTP2_FRAME_TYPE_CONTINUATION, 0x20, false},
940                                    {HTTP2_FRAME_TYPE_CONTINUATION, 0x40, false},
941                                    {HTTP2_FRAME_TYPE_CONTINUATION, 0x80, false},
942                                    {HTTP2_FRAME_TYPE_MAX, 0x00, true},
943                                    {HTTP2_FRAME_TYPE_MAX, 0x01, true},
944                                    {HTTP2_FRAME_TYPE_MAX, 0x02, true},
945                                    {HTTP2_FRAME_TYPE_MAX, 0x04, true},
946                                    {HTTP2_FRAME_TYPE_MAX, 0x08, true},
947                                    {HTTP2_FRAME_TYPE_MAX, 0x10, true},
948                                    {HTTP2_FRAME_TYPE_MAX, 0x20, true},
949                                    {HTTP2_FRAME_TYPE_MAX, 0x40, true},
950                                    {HTTP2_FRAME_TYPE_MAX, 0x80, true}};
951 
952 static const uint8_t HTTP2_FRAME_FLAGS_MASKS[HTTP2_FRAME_TYPE_MAX] = {
953   HTTP2_FLAGS_DATA_MASK,          HTTP2_FLAGS_HEADERS_MASK,      HTTP2_FLAGS_PRIORITY_MASK, HTTP2_FLAGS_RST_STREAM_MASK,
954   HTTP2_FLAGS_SETTINGS_MASK,      HTTP2_FLAGS_PUSH_PROMISE_MASK, HTTP2_FLAGS_PING_MASK,     HTTP2_FLAGS_GOAWAY_MASK,
955   HTTP2_FLAGS_WINDOW_UPDATE_MASK, HTTP2_FLAGS_CONTINUATION_MASK,
956 };
957 
REGRESSION_TEST(HTTP2_FRAME_FLAGS)958 REGRESSION_TEST(HTTP2_FRAME_FLAGS)(RegressionTest *t, int, int *pstatus)
959 {
960   TestBox box(t, pstatus);
961   box = REGRESSION_TEST_PASSED;
962 
963   for (auto i : http2_frame_flags_test_case) {
964     box.check((i.ftype >= HTTP2_FRAME_TYPE_MAX || (i.fflags & ~HTTP2_FRAME_FLAGS_MASKS[i.ftype]) == 0) == i.valid,
965               "Validation of frame flags (type: %d, flags: %d) are expected %d, but not", i.ftype, i.fflags, i.valid);
966   }
967 }
968 
969 #endif /* TS_HAS_TESTS */
970