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