lsquic_http1x_if.c revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <assert.h> 3#include <ctype.h> 4#include <stddef.h> 5#include <stdlib.h> 6#include <string.h> 7 8#include "lsquic.h" 9#include "lsquic_headers.h" 10#include "lsquic_http1x_if.h" 11#include "lshpack.h" 12 13#define LSQUIC_LOGGER_MODULE LSQLM_HTTP1X 14#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(hwc->hwc_conn) 15#include "lsquic_logger.h" 16 17enum pseudo_header 18{ 19 PSEH_METHOD, 20 PSEH_SCHEME, 21 PSEH_AUTHORITY, 22 PSEH_PATH, 23 PSEH_STATUS, 24 N_PSEH 25}; 26 27#define BIT(x) (1 << (x)) 28 29#define ALL_REQUEST_PSEH (BIT(PSEH_METHOD)|BIT(PSEH_SCHEME)|BIT(PSEH_AUTHORITY)|BIT(PSEH_PATH)) 30#define REQUIRED_REQUEST_PSEH (BIT(PSEH_METHOD)|BIT(PSEH_SCHEME)|BIT(PSEH_PATH)) 31 32#define ALL_SERVER_PSEH BIT(PSEH_STATUS) 33#define REQUIRED_SERVER_PSEH ALL_SERVER_PSEH 34 35#define PSEH_LEN(h) (sizeof(#h) - 5) 36 37struct header_writer_ctx 38{ 39 const struct lsquic_conn *hwc_conn; 40 char *buf; 41 char *cookie_val; 42 unsigned cookie_sz, cookie_nalloc; 43 unsigned max_headers_sz, 44 headers_sz, 45 w_off; 46 enum { 47 HWC_SERVER = 1 << 0, 48 HWC_EXPECT_COLON = 1 << 1, 49 HWC_SEEN_HOST = 1 << 2, 50 HWC_PUSH_PROMISE = 1 << 3, 51 } hwc_flags; 52 enum pseudo_header pseh_mask; 53 char *pseh_bufs[N_PSEH]; 54 struct http1x_headers hwc_h1h; 55 size_t hwc_header_buf_nalloc; 56 struct lsxpack_header hwc_xhdr; 57}; 58 59 60#define HWC_PSEH_LEN(hwc, ph) ((int) strlen((hwc)->pseh_bufs[ph])) 61 62#define HWC_PSEH_VAL(hwc, ph) ((hwc)->pseh_bufs[ph]) 63 64static void * 65h1h_create_header_set (void *ctx, lsquic_stream_t *stream, int is_push_promise) 66{ 67 const struct http1x_ctor_ctx *hcc = ctx; 68 struct header_writer_ctx *hwc; 69 70 hwc = calloc(1, sizeof(*hwc)); 71 if (!hwc) 72 return NULL; 73 74 hwc->hwc_flags = HWC_EXPECT_COLON; 75 if (hcc->is_server) 76 hwc->hwc_flags |= HWC_SERVER; 77 if (is_push_promise) 78 hwc->hwc_flags |= HWC_PUSH_PROMISE; 79 hwc->max_headers_sz = hcc->max_headers_sz; 80 hwc->hwc_conn = hcc->conn; 81 return &hwc->hwc_h1h; 82} 83 84 85static int 86hwc_uh_write (struct header_writer_ctx *hwc, const void *buf, size_t sz) 87{ 88 char *h1h_buf; 89 90 if (hwc->w_off + sz > hwc->headers_sz) 91 { 92 if (hwc->headers_sz * 2 >= hwc->w_off + sz) 93 hwc->headers_sz *= 2; 94 else 95 hwc->headers_sz = hwc->w_off + sz; 96 h1h_buf = realloc(hwc->hwc_h1h.h1h_buf, hwc->headers_sz); 97 if (!h1h_buf) 98 return -1; 99 hwc->hwc_h1h.h1h_buf = h1h_buf; 100 } 101 memcpy(&hwc->hwc_h1h.h1h_buf[hwc->w_off], buf, sz); 102 hwc->w_off += sz; 103 return 0; 104} 105 106 107static int 108save_pseudo_header (struct header_writer_ctx *hwc, enum pseudo_header ph, 109 const char *val, unsigned val_len) 110{ 111 if (0 == (hwc->pseh_mask & BIT(ph))) 112 { 113 assert(!hwc->pseh_bufs[ph]); 114 hwc->pseh_bufs[ph] = malloc(val_len + 1); 115 if (!hwc->pseh_bufs[ph]) 116 return -1; 117 hwc->pseh_mask |= BIT(ph); 118 memcpy(hwc->pseh_bufs[ph], val, val_len); 119 hwc->pseh_bufs[ph][val_len] = '\0'; 120 return 0; 121 } 122 else 123 { 124 LSQ_INFO("header %u is already present", ph); 125 return 1; 126 } 127} 128 129 130static int 131add_pseudo_header (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr) 132{ 133 const char *name, *val; 134 unsigned name_len, val_len; 135 136 if (!(hwc->hwc_flags & HWC_EXPECT_COLON)) 137 { 138 LSQ_INFO("unexpected colon"); 139 return 1; 140 } 141 142 name = lsxpack_header_get_name(xhdr); 143 val = lsxpack_header_get_value(xhdr); 144 name_len = xhdr->name_len; 145 val_len = xhdr->val_len; 146 147 switch (name_len) 148 { 149 case 5: 150 if (0 == memcmp(name, ":path", 5)) 151 return save_pseudo_header(hwc, PSEH_PATH, val, val_len); 152 break; 153 case 7: 154 switch (name[2]) 155 { 156 case 'c': 157 if (0 == memcmp(name, ":scheme", 7)) 158 return save_pseudo_header(hwc, PSEH_SCHEME, val, val_len); 159 break; 160 case 'e': 161 if (0 == memcmp(name, ":method", 7)) 162 return save_pseudo_header(hwc, PSEH_METHOD, val, val_len); 163 break; 164 case 't': 165 if (0 == memcmp(name, ":status", 7)) 166 return save_pseudo_header(hwc, PSEH_STATUS, val, val_len); 167 break; 168 } 169 break; 170 case 10: 171 if (0 == memcmp(name, ":authority", 10)) 172 return save_pseudo_header(hwc, PSEH_AUTHORITY, val, val_len); 173 break; 174 } 175 176 LSQ_INFO("unknown pseudo-header `%.*s'", name_len, name); 177 return 1; 178} 179 180 181#define HTTP_CODE_LEN 3 182 183static const char * 184code_str_to_reason (const char code_str[HTTP_CODE_LEN]) 185{ 186 /* RFC 7231, Section 6: */ 187 static const char *const http_reason_phrases[] = 188 { 189 #define HTTP_REASON_CODE(code, reason) [code - 100] = reason 190 HTTP_REASON_CODE(100, "Continue"), 191 HTTP_REASON_CODE(101, "Switching Protocols"), 192 HTTP_REASON_CODE(200, "OK"), 193 HTTP_REASON_CODE(201, "Created"), 194 HTTP_REASON_CODE(202, "Accepted"), 195 HTTP_REASON_CODE(203, "Non-Authoritative Information"), 196 HTTP_REASON_CODE(204, "No Content"), 197 HTTP_REASON_CODE(205, "Reset Content"), 198 HTTP_REASON_CODE(206, "Partial Content"), 199 HTTP_REASON_CODE(300, "Multiple Choices"), 200 HTTP_REASON_CODE(301, "Moved Permanently"), 201 HTTP_REASON_CODE(302, "Found"), 202 HTTP_REASON_CODE(303, "See Other"), 203 HTTP_REASON_CODE(304, "Not Modified"), 204 HTTP_REASON_CODE(305, "Use Proxy"), 205 HTTP_REASON_CODE(307, "Temporary Redirect"), 206 HTTP_REASON_CODE(400, "Bad Request"), 207 HTTP_REASON_CODE(401, "Unauthorized"), 208 HTTP_REASON_CODE(402, "Payment Required"), 209 HTTP_REASON_CODE(403, "Forbidden"), 210 HTTP_REASON_CODE(404, "Not Found"), 211 HTTP_REASON_CODE(405, "Method Not Allowed"), 212 HTTP_REASON_CODE(406, "Not Acceptable"), 213 HTTP_REASON_CODE(407, "Proxy Authentication Required"), 214 HTTP_REASON_CODE(408, "Request Timeout"), 215 HTTP_REASON_CODE(409, "Conflict"), 216 HTTP_REASON_CODE(410, "Gone"), 217 HTTP_REASON_CODE(411, "Length Required"), 218 HTTP_REASON_CODE(412, "Precondition Failed"), 219 HTTP_REASON_CODE(413, "Payload Too Large"), 220 HTTP_REASON_CODE(414, "URI Too Long"), 221 HTTP_REASON_CODE(415, "Unsupported Media Type"), 222 HTTP_REASON_CODE(416, "Range Not Satisfiable"), 223 HTTP_REASON_CODE(417, "Expectation Failed"), 224 HTTP_REASON_CODE(426, "Upgrade Required"), 225 HTTP_REASON_CODE(500, "Internal Server Error"), 226 HTTP_REASON_CODE(501, "Not Implemented"), 227 HTTP_REASON_CODE(502, "Bad Gateway"), 228 HTTP_REASON_CODE(503, "Service Unavailable"), 229 HTTP_REASON_CODE(504, "Gateway Timeout"), 230 HTTP_REASON_CODE(505, "HTTP Version Not Supported"), 231 #undef HTTP_REASON_CODE 232 }; 233 234 long code; 235 char code_buf[HTTP_CODE_LEN + 1]; 236 237 memcpy(code_buf, code_str, HTTP_CODE_LEN); 238 code_buf[HTTP_CODE_LEN] = '\0'; 239 code = strtol(code_buf, NULL, 10) - 100; 240 if (code > 0 && code < (long) (sizeof(http_reason_phrases) / 241 sizeof(http_reason_phrases[0]))) 242 return http_reason_phrases[code]; 243 else 244 return NULL; 245} 246 247 248static int 249convert_response_pseudo_headers (struct header_writer_ctx *hwc) 250{ 251 if ((hwc->pseh_mask & REQUIRED_SERVER_PSEH) != REQUIRED_SERVER_PSEH) 252 { 253 LSQ_INFO("not all response pseudo-headers are specified"); 254 return 1; 255 } 256 if (hwc->pseh_mask & ALL_REQUEST_PSEH) 257 { 258 LSQ_INFO("response pseudo-headers contain request-only headers"); 259 return 1; 260 } 261 262 const char *code_str, *reason; 263 int code_len; 264 265 code_str = HWC_PSEH_VAL(hwc, PSEH_STATUS); 266 code_len = HWC_PSEH_LEN(hwc, PSEH_STATUS); 267 268#define HWC_UH_WRITE(h, buf, sz) do { \ 269 if (0 != hwc_uh_write(h, buf, sz)) \ 270 return -1; \ 271} while (0) 272 273 HWC_UH_WRITE(hwc, "HTTP/1.1 ", 9); 274 HWC_UH_WRITE(hwc, code_str, code_len); 275 if (HTTP_CODE_LEN == code_len && (reason = code_str_to_reason(code_str))) 276 { 277 HWC_UH_WRITE(hwc, " ", 1); 278 HWC_UH_WRITE(hwc, reason, strlen(reason)); 279 HWC_UH_WRITE(hwc, "\r\n", 2); 280 } 281 else 282 HWC_UH_WRITE(hwc, " \r\n", 3); 283 if (hwc->max_headers_sz && hwc->w_off > hwc->max_headers_sz) 284 { 285 LSQ_INFO("headers too large"); 286 return 1; 287 } 288 return 0; 289 290#undef HWC_UH_WRITE 291} 292 293 294static int 295convert_request_pseudo_headers (struct header_writer_ctx *hwc) 296{ 297 if ((hwc->pseh_mask & REQUIRED_REQUEST_PSEH) != REQUIRED_REQUEST_PSEH) 298 { 299 LSQ_INFO("not all request pseudo-headers are specified"); 300 return 1; 301 } 302 if (hwc->pseh_mask & ALL_SERVER_PSEH) 303 { 304 LSQ_INFO("request pseudo-headers contain response-only headers"); 305 return 1; 306 } 307 308#define HWC_UH_WRITE(h, buf, sz) do { \ 309 if (0 != hwc_uh_write(h, buf, sz)) \ 310 return -1; \ 311} while (0) 312 313 HWC_UH_WRITE(hwc, HWC_PSEH_VAL(hwc, PSEH_METHOD), HWC_PSEH_LEN(hwc, PSEH_METHOD)); 314 HWC_UH_WRITE(hwc, " ", 1); 315 HWC_UH_WRITE(hwc, HWC_PSEH_VAL(hwc, PSEH_PATH), HWC_PSEH_LEN(hwc, PSEH_PATH)); 316 HWC_UH_WRITE(hwc, " HTTP/1.1\r\n", 11); 317 318 if (hwc->max_headers_sz && hwc->w_off > hwc->max_headers_sz) 319 { 320 LSQ_INFO("headers too large"); 321 return 1; 322 } 323 324 return 0; 325 326#undef HWC_UH_WRITE 327} 328 329 330static int 331convert_pseudo_headers (struct header_writer_ctx *hwc) 332{ 333 /* We are *reading* the message. Thus, a server expects a request, and a 334 * client expects a response. Unless we receive a push promise from the 335 * server, in which case this should also be a request. 336 */ 337 if (hwc->hwc_flags & (HWC_SERVER|HWC_PUSH_PROMISE)) 338 return convert_request_pseudo_headers(hwc); 339 else 340 return convert_response_pseudo_headers(hwc); 341} 342 343 344static int 345save_cookie (struct header_writer_ctx *hwc, const char *val, unsigned val_len) 346{ 347 char *cookie_val; 348 349 if (0 == hwc->cookie_sz) 350 { 351 hwc->cookie_nalloc = hwc->cookie_sz = val_len; 352 cookie_val = malloc(hwc->cookie_nalloc); 353 if (!cookie_val) 354 return -1; 355 hwc->cookie_val = cookie_val; 356 memcpy(hwc->cookie_val, val, val_len); 357 } 358 else 359 { 360 hwc->cookie_sz += val_len + 2 /* "; " */; 361 if (hwc->cookie_sz > hwc->cookie_nalloc) 362 { 363 hwc->cookie_nalloc = hwc->cookie_nalloc * 2 + val_len + 2; 364 cookie_val = realloc(hwc->cookie_val, hwc->cookie_nalloc); 365 if (!cookie_val) 366 return -1; 367 hwc->cookie_val = cookie_val; 368 } 369 memcpy(hwc->cookie_val + hwc->cookie_sz - val_len - 2, "; ", 2); 370 memcpy(hwc->cookie_val + hwc->cookie_sz - val_len, val, val_len); 371 } 372 373 return 0; 374} 375 376 377static int 378add_real_header (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr) 379{ 380 int err; 381 unsigned i; 382 int n_upper; 383 const char *name, *val; 384 unsigned name_len, val_len; 385 386 if (hwc->hwc_flags & HWC_EXPECT_COLON) 387 { 388 if (0 != (err = convert_pseudo_headers(hwc))) 389 return err; 390 hwc->hwc_flags &= ~HWC_EXPECT_COLON; 391 } 392 393 name = lsxpack_header_get_name(xhdr); 394 val = lsxpack_header_get_value(xhdr); 395 name_len = xhdr->name_len; 396 val_len = xhdr->val_len; 397 398 if (4 == name_len && 0 == memcmp(name, "host", 4)) 399 hwc->hwc_flags |= HWC_SEEN_HOST; 400 401 n_upper = 0; 402 for (i = 0; i < name_len; ++i) 403 n_upper += isupper(name[i]); 404 if (n_upper > 0) 405 { 406 LSQ_INFO("Header name `%.*s' contains uppercase letters", 407 name_len, name); 408 return 1; 409 } 410 411 if (6 == name_len && memcmp(name, "cookie", 6) == 0) 412 { 413 return save_cookie(hwc, val, val_len); 414 } 415 416#define HWC_UH_WRITE(h, buf, sz) do { \ 417 if (0 != hwc_uh_write(h, buf, sz)) \ 418 return -1; \ 419} while (0) 420 421 HWC_UH_WRITE(hwc, name, name_len); 422 HWC_UH_WRITE(hwc, ": ", 2); 423 HWC_UH_WRITE(hwc, val, val_len); 424 HWC_UH_WRITE(hwc, "\r\n", 2); 425 426 if (hwc->max_headers_sz && hwc->w_off > hwc->max_headers_sz) 427 { 428 LSQ_INFO("headers too large"); 429 return 1; 430 } 431 432 return 0; 433 434#undef HWC_UH_WRITE 435} 436 437 438static int 439add_header_to_uh (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr) 440{ 441 const char *name; 442 443 name = lsxpack_header_get_name(xhdr); 444 LSQ_DEBUG("Got header '%.*s': '%.*s'", (int) xhdr->name_len, name, 445 (int) xhdr->val_len, lsxpack_header_get_value(xhdr)); 446 if (':' == name[0]) 447 return add_pseudo_header(hwc, xhdr); 448 else 449 return add_real_header(hwc, xhdr); 450} 451 452 453static int 454h1h_finish_hset (struct header_writer_ctx *hwc) 455{ 456 int st; 457 458 if (hwc->hwc_flags & HWC_EXPECT_COLON) 459 { 460 st = convert_pseudo_headers(hwc); 461 if (0 != st) 462 return st; 463 hwc->hwc_flags &= ~HWC_EXPECT_COLON; 464 } 465 466#define HWC_UH_WRITE(h, buf, sz) do { \ 467 st = hwc_uh_write(h, buf, sz); \ 468 if (0 != st) \ 469 return st; \ 470} while (0) 471 472 if ((hwc->pseh_mask & BIT(PSEH_AUTHORITY)) && 473 0 == (hwc->hwc_flags & HWC_SEEN_HOST)) 474 { 475 LSQ_DEBUG("Setting 'Host: %.*s'", HWC_PSEH_LEN(hwc, PSEH_AUTHORITY), 476 HWC_PSEH_VAL(hwc, PSEH_AUTHORITY)); 477 HWC_UH_WRITE(hwc, "Host: ", 6); 478 HWC_UH_WRITE(hwc, HWC_PSEH_VAL(hwc, PSEH_AUTHORITY), 479 HWC_PSEH_LEN(hwc, PSEH_AUTHORITY)); 480 HWC_UH_WRITE(hwc, "\r\n", 2); 481 } 482 483 if (hwc->cookie_val) 484 { 485 LSQ_DEBUG("Setting 'Cookie: %.*s'", hwc->cookie_sz, hwc->cookie_val); 486 HWC_UH_WRITE(hwc, "Cookie: ", 8); 487 HWC_UH_WRITE(hwc, hwc->cookie_val, hwc->cookie_sz); 488 HWC_UH_WRITE(hwc, "\r\n", 2); 489 } 490 491 HWC_UH_WRITE(hwc, "\r\n", 2 + 1 /* NUL byte */); 492 hwc->w_off -= 1; /* Do not count NUL byte */ 493 hwc->hwc_h1h.h1h_size = hwc->w_off; 494 495 if (hwc->max_headers_sz && hwc->w_off > hwc->max_headers_sz) 496 { 497 LSQ_INFO("headers too large"); 498 return 1; 499 } 500 501 return 0; 502} 503 504#define HWC_PTR(data_in) (struct header_writer_ctx *) \ 505 ((unsigned char *) (hset) - offsetof(struct header_writer_ctx, hwc_h1h)) 506 507 508static struct lsxpack_header * 509h1h_prepare_decode (void *hset, struct lsxpack_header *xhdr, size_t req_space) 510{ 511 struct header_writer_ctx *const hwc = HWC_PTR(hset); 512 size_t nalloc; 513 char *buf; 514 515 if (req_space < 0x100) 516 req_space = 0x100; 517 518 if (req_space > MAX_HTTP1X_HEADERS_SIZE || req_space > LSXPACK_MAX_STRLEN) 519 { 520 LSQ_DEBUG("requested space for header is too large: %zd bytes", 521 req_space); 522 return NULL; 523 } 524 525 if (!xhdr) 526 { 527 if (0 == hwc->hwc_header_buf_nalloc 528 || req_space > hwc->hwc_header_buf_nalloc) 529 { 530 buf = malloc(req_space); 531 if (!buf) 532 { 533 LSQ_DEBUG("cannot allocate %zd bytes", req_space); 534 return NULL; 535 } 536 hwc->hwc_header_buf_nalloc = req_space; 537 } 538 else 539 buf = hwc->hwc_xhdr.buf; 540 lsxpack_header_prepare_decode(&hwc->hwc_xhdr, buf, 0, req_space); 541 } 542 else 543 { 544 if (req_space > hwc->hwc_header_buf_nalloc) 545 { 546 if (req_space < hwc->hwc_header_buf_nalloc * 2) 547 nalloc = hwc->hwc_header_buf_nalloc * 2; 548 else 549 nalloc = req_space; 550 buf = realloc(hwc->hwc_xhdr.buf, nalloc); 551 if (!buf) 552 { 553 LSQ_DEBUG("cannot reallocate to %zd bytes", nalloc); 554 return NULL; 555 } 556 hwc->hwc_xhdr.buf = buf; 557 hwc->hwc_header_buf_nalloc = nalloc; 558 } 559 hwc->hwc_xhdr.val_len = req_space; 560 } 561 562 return &hwc->hwc_xhdr; 563} 564 565 566static int 567h1h_process_header (void *hset, struct lsxpack_header *xhdr) 568{ 569 struct header_writer_ctx *const hwc = HWC_PTR(hset); 570 if (xhdr) 571 return add_header_to_uh(hwc, xhdr); 572 else 573 return h1h_finish_hset(hwc); 574} 575 576 577static void 578h1h_discard_header_set (void *hset) 579{ 580 struct header_writer_ctx *const hwc = HWC_PTR(hset); 581 unsigned i; 582 583 for (i = 0; i < sizeof(hwc->pseh_bufs) / sizeof(hwc->pseh_bufs[0]); ++i) 584 if (hwc->pseh_bufs[i]) 585 free(hwc->pseh_bufs[i]); 586 if (hwc->cookie_val) 587 free(hwc->cookie_val); 588 free(hwc->hwc_h1h.h1h_buf); 589 free(hwc->hwc_xhdr.buf); 590 free(hwc); 591} 592 593 594static const struct lsquic_hset_if http1x_if = 595{ 596 .hsi_create_header_set = h1h_create_header_set, 597 .hsi_prepare_decode = h1h_prepare_decode, 598 .hsi_process_header = h1h_process_header, 599 .hsi_discard_header_set = h1h_discard_header_set, 600}; 601 602const struct lsquic_hset_if *const lsquic_http1x_if = &http1x_if; 603