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