lsquic_frame_writer.c revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_frame_writer.c -- write frames to HEADERS stream. 4 * 5 * The frame is first written to list of frame_buf's (frabs) and then 6 * out to the stream. This is done because frame's size is written out 7 * to the stream and we may not have enough room in the stream to fit 8 * the whole frame. 9 */ 10 11#ifndef WIN32 12#include <arpa/inet.h> 13#endif 14#include <assert.h> 15#include <errno.h> 16#include <inttypes.h> 17#include <stdlib.h> 18#include <string.h> 19#include <sys/queue.h> 20 21#include "lshpack.h" 22#include "lsquic_mm.h" 23#include "lsquic.h" 24#include "lsquic_int_types.h" 25#include "lsquic_hash.h" 26#include "lsquic_conn.h" 27 28#include "lsquic_frame_writer.h" 29#include "lsquic_frame_common.h" 30#include "lsquic_frab_list.h" 31#include "lsquic_ev_log.h" 32 33#include "fiu-local.h" 34 35#define LSQUIC_LOGGER_MODULE LSQLM_FRAME_WRITER 36#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(\ 37 lsquic_stream_conn(fw->fw_stream)) 38#include "lsquic_logger.h" 39 40/* Size of the buffer passed to lshpack_enc_encode() -- this limits the size 41 * of a single compressed header field. 42 */ 43#define MAX_COMP_HEADER_FIELD_SIZE (64 * 1024) 44 45 46struct lsquic_frame_writer 47{ 48 struct lsquic_stream *fw_stream; 49 fw_writef_f fw_writef; 50 struct lsquic_mm *fw_mm; 51 struct lshpack_enc *fw_henc; 52#if LSQUIC_CONN_STATS 53 struct conn_stats *fw_conn_stats; 54#endif 55 struct frab_list fw_fral; 56 unsigned fw_max_frame_sz; 57 uint32_t fw_max_header_list_sz; /* 0 means unlimited */ 58 enum { 59 FW_SERVER = (1 << 0), 60 } fw_flags; 61}; 62 63 64/* RFC 7540, Section 4.2 */ 65#define MIN_MAX_FRAME_SIZE (1 << 14) 66#define MAX_MAX_FRAME_SIZE ((1 << 24) - 1) 67 68#define MAX(a, b) ((a) > (b) ? (a) : (b)) 69#define SETTINGS_FRAME_SZ 6 70#define ABS_MIN_FRAME_SIZE MAX(SETTINGS_FRAME_SZ, \ 71 sizeof(struct http_prio_frame)) 72 73static void * 74fw_alloc (void *ctx, size_t size) 75{ 76 return lsquic_mm_get_4k(ctx); 77} 78 79 80struct lsquic_frame_writer * 81lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream, 82 unsigned max_frame_sz, struct lshpack_enc *henc, fw_writef_f writef, 83#if LSQUIC_CONN_STATS 84 struct conn_stats *conn_stats, 85#endif 86 int is_server) 87{ 88 struct lsquic_frame_writer *fw; 89 90 /* When frame writer is instantiated, limit the maximum size to 91 * MIN_MAX_FRAME_SIZE. The reference implementation has this value 92 * hardcoded and QUIC does not provide a mechanism to advertise a 93 * different value. 94 */ 95 if (0 == max_frame_sz) 96 max_frame_sz = MIN_MAX_FRAME_SIZE; 97 else 98 LSQ_LOG1(LSQ_LOG_WARN, "max frame size specified to be %u bytes " 99 "-- this better be test code!", max_frame_sz); 100 101 if (!is_server && max_frame_sz < ABS_MIN_FRAME_SIZE) 102 { 103 LSQ_LOG1(LSQ_LOG_ERROR, "max frame size must be at least %zd bytes, " 104 "which is the size of priority information that client always " 105 "writes", ABS_MIN_FRAME_SIZE); 106 return NULL; 107 } 108 109 fw = calloc(1, sizeof(*fw)); 110 if (!fw) 111 return NULL; 112 113 fw->fw_mm = mm; 114 fw->fw_henc = henc; 115 fw->fw_stream = stream; 116 fw->fw_writef = writef; 117 fw->fw_max_frame_sz = max_frame_sz; 118 fw->fw_max_header_list_sz = 0; 119 if (is_server) 120 fw->fw_flags = FW_SERVER; 121 else 122 fw->fw_flags = 0; 123#if LSQUIC_CONN_STATS 124 fw->fw_conn_stats = conn_stats; 125#endif 126 lsquic_frab_list_init(&fw->fw_fral, 0x1000, fw_alloc, 127 (void (*)(void *, void *)) lsquic_mm_put_4k, mm); 128 return fw; 129} 130 131 132void 133lsquic_frame_writer_destroy (struct lsquic_frame_writer *fw) 134{ 135 lsquic_frab_list_cleanup(&fw->fw_fral); 136 free(fw); 137} 138 139 140int 141lsquic_frame_writer_have_leftovers (const struct lsquic_frame_writer *fw) 142{ 143 return !lsquic_frab_list_empty(&fw->fw_fral); 144} 145 146 147int 148lsquic_frame_writer_flush (struct lsquic_frame_writer *fw) 149{ 150 struct lsquic_reader reader = { 151 .lsqr_read = lsquic_frab_list_read, 152 .lsqr_size = lsquic_frab_list_size, 153 .lsqr_ctx = &fw->fw_fral, 154 }; 155 ssize_t nw; 156 157 nw = fw->fw_writef(fw->fw_stream, &reader); 158 159 if (nw >= 0) 160 return 0; 161 else 162 return -1; 163} 164 165 166struct header_framer_ctx 167{ 168 struct lsquic_frame_writer 169 *hfc_fw; 170 struct { 171 struct frame_buf *frab; 172 unsigned short off; 173 } hfc_header_ptr; /* Points to byte *after* current frame header */ 174 unsigned hfc_max_frame_sz; /* Maximum frame size. We always fill it. */ 175 unsigned hfc_cur_sz; /* Number of bytes in the current frame. */ 176 unsigned hfc_n_frames; /* Number of frames written. */ 177 lsquic_stream_id_t 178 hfc_stream_id; /* Stream ID */ 179 enum http_frame_header_flags 180 hfc_first_flags; 181 enum http_frame_type 182 hfc_frame_type; 183}; 184 185 186static void 187hfc_init (struct header_framer_ctx *hfc, struct lsquic_frame_writer *fw, 188 unsigned max_frame_sz, enum http_frame_type frame_type, 189 lsquic_stream_id_t stream_id, enum http_frame_header_flags first_flags) 190{ 191 memset(hfc, 0, sizeof(*hfc)); 192 hfc->hfc_fw = fw; 193 hfc->hfc_frame_type = frame_type; 194 hfc->hfc_stream_id = stream_id; 195 hfc->hfc_first_flags = first_flags; 196 hfc->hfc_max_frame_sz = max_frame_sz; 197 hfc->hfc_cur_sz = max_frame_sz; 198} 199 200 201static void 202hfc_save_ptr (struct header_framer_ctx *hfc) 203{ 204 hfc->hfc_header_ptr.frab = TAILQ_LAST(&hfc->hfc_fw->fw_fral.fl_frabs, frame_buf_head); 205 hfc->hfc_header_ptr.off = hfc->hfc_header_ptr.frab->frab_size; 206} 207 208 209static void 210hfc_terminate_frame (struct header_framer_ctx *hfc, 211 enum http_frame_header_flags flags) 212{ 213 union { 214 struct http_frame_header fh; 215 unsigned char buf[ sizeof(struct http_frame_header) ]; 216 } u; 217 uint32_t stream_id; 218 struct frame_buf *frab; 219 220 /* Construct the frame */ 221 u.fh.hfh_length[0] = hfc->hfc_cur_sz >> 16; 222 u.fh.hfh_length[1] = hfc->hfc_cur_sz >> 8; 223 u.fh.hfh_length[2] = hfc->hfc_cur_sz; 224 u.fh.hfh_flags = flags; 225 if (1 == hfc->hfc_n_frames) 226 { 227 u.fh.hfh_type = hfc->hfc_frame_type; 228 u.fh.hfh_flags |= hfc->hfc_first_flags; 229 } 230 else 231 u.fh.hfh_type = HTTP_FRAME_CONTINUATION; 232 stream_id = htonl(hfc->hfc_stream_id); 233 memcpy(u.fh.hfh_stream_id, &stream_id, sizeof(stream_id)); 234 235 if (hfc->hfc_header_ptr.off >= sizeof(u.fh)) 236 { /* Write in a single chunk */ 237 assert(0 == memcmp("123456789", hfc->hfc_header_ptr.frab->frab_buf + 238 hfc->hfc_header_ptr.off - sizeof(u.buf), sizeof(u.buf))); 239 memcpy(hfc->hfc_header_ptr.frab->frab_buf + hfc->hfc_header_ptr.off - 240 sizeof(u.buf), u.buf, sizeof(u.buf)); 241 } 242 else 243 { /* Write across frab boundary */ 244 memcpy(hfc->hfc_header_ptr.frab->frab_buf, 245 u.buf + sizeof(u.buf) - hfc->hfc_header_ptr.off, 246 hfc->hfc_header_ptr.off); 247 frab = TAILQ_PREV(hfc->hfc_header_ptr.frab, frame_buf_head, frab_next); 248 memcpy(frab->frab_buf + frab->frab_size - sizeof(u.buf) + 249 hfc->hfc_header_ptr.off, u.buf, 250 sizeof(u.buf) - hfc->hfc_header_ptr.off); 251 } 252} 253 254 255static int 256hfc_write (struct header_framer_ctx *hfc, const void *buf, size_t sz) 257{ 258 const unsigned char *p = buf; 259 unsigned avail; 260 int s; 261 262 while (sz > 0) 263 { 264 if (hfc->hfc_max_frame_sz == hfc->hfc_cur_sz) 265 { 266 if (hfc->hfc_n_frames > 0) 267 hfc_terminate_frame(hfc, 0); 268 s = lsquic_frab_list_write(&hfc->hfc_fw->fw_fral, "123456789", 269 sizeof(struct http_frame_header)); 270 if (s < 0) 271 return s; 272 ++hfc->hfc_n_frames; 273 hfc_save_ptr(hfc); 274 hfc->hfc_cur_sz = 0; 275 } 276 277 avail = hfc->hfc_max_frame_sz - hfc->hfc_cur_sz; 278 if (sz < avail) 279 avail = sz; 280 if (avail) 281 { 282 s = lsquic_frab_list_write(&hfc->hfc_fw->fw_fral, p, avail); 283 if (s < 0) 284 return s; 285 hfc->hfc_cur_sz += avail; 286 sz -= avail; 287 p += avail; 288 } 289 } 290 291 return 0; 292} 293 294 295static unsigned 296count_uppercase (const unsigned char *buf, size_t sz) 297{ 298 static const unsigned char uppercase[0x100] = { 299 ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, 300 ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, 301 ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, 302 ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, 303 ['Y'] = 1, ['Z'] = 1, 304 }; 305 unsigned n_uppercase, i; 306 n_uppercase = 0; 307 for (i = 0; i < sz; ++i) 308 n_uppercase += uppercase[ buf[i] ]; 309 return n_uppercase; 310} 311 312 313static uint32_t 314calc_headers_size (const struct lsquic_http_headers *headers) 315{ 316 int i; 317 uint32_t size = 0; 318 for (i = 0; i < headers->count; ++i) 319 if (headers->headers[i].buf) 320 size += 32 + headers->headers[i].name_len + 321 headers->headers[i].val_len; 322 return size; 323} 324 325 326static int 327have_oversize_strings (const struct lsquic_http_headers *headers) 328{ 329#if LSXPACK_MAX_STRLEN > LSHPACK_MAX_STRLEN 330 int i, have; 331 for (i = 0, have = 0; i < headers->count; ++i) 332 { 333 if (headers->headers[i].buf) 334 { 335 have |= headers->headers[i].name_len > LSHPACK_MAX_STRLEN; 336 have |= headers->headers[i].val_len > LSHPACK_MAX_STRLEN; 337 } 338 } 339 return have; 340#else 341 return 0; 342#endif 343} 344 345 346static int 347check_headers_size (const struct lsquic_frame_writer *fw, 348 const struct lsquic_http_headers *headers) 349{ 350 uint32_t headers_sz; 351 headers_sz = calc_headers_size(headers); 352 353 if (headers_sz <= fw->fw_max_header_list_sz) 354 return 0; 355 else if (fw->fw_flags & FW_SERVER) 356 { 357 LSQ_INFO("Sending headers larger (%u bytes) than max allowed (%u)", 358 headers_sz, fw->fw_max_header_list_sz); 359 return 0; 360 } 361 else 362 { 363 LSQ_INFO("Headers size %u is larger than max allowed (%u)", 364 headers_sz, fw->fw_max_header_list_sz); 365 errno = EMSGSIZE; 366 return -1; 367 } 368} 369 370 371static int 372check_headers_case (const struct lsquic_frame_writer *fw, 373 const struct lsquic_http_headers *headers) 374{ 375 unsigned n_uppercase; 376 int i; 377 n_uppercase = 0; 378 for (i = 0; i < headers->count; ++i) 379 if (headers->headers[i].buf) 380 n_uppercase += count_uppercase((unsigned char *) 381 lsxpack_header_get_name(&headers->headers[i]), 382 headers->headers[i].name_len); 383 if (n_uppercase) 384 { 385 LSQ_INFO("Uppercase letters in header names"); 386 errno = EINVAL; 387 return -1; 388 } 389 return 0; 390} 391 392 393static int 394write_headers (struct lsquic_frame_writer *fw, 395 const struct lsquic_http_headers *headers, 396 struct header_framer_ctx *hfc, unsigned char *buf, 397 const unsigned buf_sz) 398{ 399 unsigned char *end; 400 int i, s; 401 for (i = 0; i < headers->count; ++i) 402 { 403 if (headers->headers[i].buf == NULL) 404 continue; 405 end = lshpack_enc_encode(fw->fw_henc, buf, buf + buf_sz, 406 &headers->headers[i]); 407 if (end > buf) 408 { 409 s = hfc_write(hfc, buf, end - buf); 410 if (s < 0) 411 return s; 412#if LSQUIC_CONN_STATS 413 fw->fw_conn_stats->out.headers_uncomp += 414 headers->headers[i].name_len 415 + headers->headers[i].val_len; 416 fw->fw_conn_stats->out.headers_comp += end - buf; 417#endif 418 } 419 else 420 { 421 /* Ignore errors, matching HTTP2 behavior in our server code */ 422 } 423 } 424 425 return 0; 426} 427 428 429int 430lsquic_frame_writer_write_headers (struct lsquic_frame_writer *fw, 431 lsquic_stream_id_t stream_id, 432 const struct lsquic_http_headers *headers, 433 int eos, unsigned weight) 434{ 435 struct header_framer_ctx hfc; 436 int s; 437 struct http_prio_frame prio_frame; 438 enum http_frame_header_flags flags; 439 unsigned char *buf; 440 441 /* Internal function: weight must be valid here */ 442 assert(weight >= 1 && weight <= 256); 443 444 if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers)) 445 return -1; 446 447 if (0 != check_headers_case(fw, headers)) 448 return -1; 449 450 if (have_oversize_strings(headers)) 451 return -1; 452 453 if (eos) 454 flags = HFHF_END_STREAM; 455 else 456 flags = 0; 457 458 if (!(fw->fw_flags & FW_SERVER)) 459 flags |= HFHF_PRIORITY; 460 461 hfc_init(&hfc, fw, fw->fw_max_frame_sz, HTTP_FRAME_HEADERS, stream_id, 462 flags); 463 464 if (!(fw->fw_flags & FW_SERVER)) 465 { 466 memset(&prio_frame.hpf_stream_id, 0, sizeof(prio_frame.hpf_stream_id)); 467 prio_frame.hpf_weight = weight - 1; 468 s = hfc_write(&hfc, &prio_frame, sizeof(struct http_prio_frame)); 469 if (s < 0) 470 return s; 471 } 472 473 buf = malloc(MAX_COMP_HEADER_FIELD_SIZE); 474 if (!buf) 475 return -1; 476 s = write_headers(fw, headers, &hfc, buf, MAX_COMP_HEADER_FIELD_SIZE); 477 free(buf); 478 if (0 == s) 479 { 480 EV_LOG_GENERATED_HTTP_HEADERS(LSQUIC_LOG_CONN_ID, stream_id, 481 fw->fw_flags & FW_SERVER, &prio_frame, headers); 482 hfc_terminate_frame(&hfc, HFHF_END_HEADERS); 483 return lsquic_frame_writer_flush(fw); 484 } 485 else 486 return s; 487} 488 489 490int 491lsquic_frame_writer_write_promise (struct lsquic_frame_writer *fw, 492 lsquic_stream_id_t stream_id64, lsquic_stream_id_t promised_stream_id64, 493 const struct lsquic_http_headers *headers) 494{ 495 uint32_t stream_id = stream_id64; 496 uint32_t promised_stream_id = promised_stream_id64; 497 struct header_framer_ctx hfc; 498 struct http_push_promise_frame push_frame; 499 unsigned char *buf; 500 int s; 501 502 fiu_return_on("frame_writer/writer_promise", -1); 503 504 if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers)) 505 return -1; 506 507 if (0 != check_headers_case(fw, headers)) 508 return -1; 509 510 if (have_oversize_strings(headers)) 511 return -1; 512 513 hfc_init(&hfc, fw, fw->fw_max_frame_sz, HTTP_FRAME_PUSH_PROMISE, 514 stream_id, 0); 515 516 promised_stream_id = htonl(promised_stream_id); 517 memcpy(push_frame.hppf_promised_id, &promised_stream_id, 4); 518 s = hfc_write(&hfc, &push_frame, sizeof(struct http_push_promise_frame)); 519 if (s < 0) 520 return s; 521 522 buf = malloc(MAX_COMP_HEADER_FIELD_SIZE); 523 if (!buf) 524 return -1; 525 526 s = write_headers(fw, headers, &hfc, buf, MAX_COMP_HEADER_FIELD_SIZE); 527 if (s != 0) 528 { 529 free(buf); 530 return -1; 531 } 532 533 free(buf); 534 535 EV_LOG_GENERATED_HTTP_PUSH_PROMISE(LSQUIC_LOG_CONN_ID, stream_id, 536 htonl(promised_stream_id), headers); 537 hfc_terminate_frame(&hfc, HFHF_END_HEADERS); 538 return lsquic_frame_writer_flush(fw); 539} 540 541 542void 543lsquic_frame_writer_max_header_list_size (struct lsquic_frame_writer *fw, 544 uint32_t max_size) 545{ 546 LSQ_DEBUG("set max_header_list_sz to %u", max_size); 547 fw->fw_max_header_list_sz = max_size; 548} 549 550 551static int 552write_settings (struct lsquic_frame_writer *fw, 553 const struct lsquic_http2_setting *settings, unsigned n_settings) 554{ 555 struct http_frame_header fh; 556 unsigned payload_length; 557 uint32_t val; 558 uint16_t id; 559 int s; 560 561 payload_length = n_settings * 6; 562 563 memset(&fh, 0, sizeof(fh)); 564 fh.hfh_type = HTTP_FRAME_SETTINGS; 565 fh.hfh_length[0] = payload_length >> 16; 566 fh.hfh_length[1] = payload_length >> 8; 567 fh.hfh_length[2] = payload_length; 568 569 s = lsquic_frab_list_write(&fw->fw_fral, &fh, sizeof(fh)); 570 if (s != 0) 571 return s; 572 573 do 574 { 575 id = htons(settings->id); 576 val = htonl(settings->value); 577 if (0 != (s = lsquic_frab_list_write(&fw->fw_fral, &id, sizeof(id))) || 578 0 != (s = lsquic_frab_list_write(&fw->fw_fral, &val, sizeof(val)))) 579 return s; 580 EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "wrote HTTP SETTINGS frame: " 581 "%s=%"PRIu32, lsquic_http_setting_id2str(settings->id), 582 settings->value); 583 ++settings; 584 } 585 while (--n_settings); 586 587 return 0; 588} 589 590int 591lsquic_frame_writer_write_settings (struct lsquic_frame_writer *fw, 592 const struct lsquic_http2_setting *settings, unsigned n_settings) 593{ 594 unsigned settings_per_frame; 595 unsigned n; 596 597 if (0 == n_settings) 598 { 599 errno = EINVAL; 600 return -1; 601 } 602 603 settings_per_frame = fw->fw_max_frame_sz / SETTINGS_FRAME_SZ; 604 n = 0; 605 606 do { 607 if (settings_per_frame > n_settings - n) 608 settings_per_frame = n_settings - n; 609 if (0 != write_settings(fw, &settings[n], settings_per_frame)) 610 return -1; 611 n += settings_per_frame; 612 } while (n < n_settings); 613 614 return lsquic_frame_writer_flush(fw); 615} 616 617 618int 619lsquic_frame_writer_write_priority (struct lsquic_frame_writer *fw, 620 lsquic_stream_id_t stream_id64, int exclusive, 621 lsquic_stream_id_t stream_dep_id64, unsigned weight) 622{ 623 uint32_t stream_id = stream_id64; 624 uint32_t stream_dep_id = stream_dep_id64; 625 unsigned char buf[ sizeof(struct http_frame_header) + 626 sizeof(struct http_prio_frame) ]; 627 struct http_frame_header *fh = (void *) &buf[0]; 628 struct http_prio_frame *prio_frame = (void *) &buf[sizeof(*fh)]; 629 int s; 630 631 if (stream_dep_id & (1UL << 31)) 632 { 633 LSQ_WARN("stream ID too high (%u): cannot write PRIORITY frame", 634 stream_dep_id); 635 return -1; 636 } 637 638 if (weight < 1 || weight > 256) 639 return -1; 640 641 memset(fh, 0, sizeof(*fh)); 642 fh->hfh_type = HTTP_FRAME_PRIORITY; 643 fh->hfh_length[2] = sizeof(struct http_prio_frame); 644 stream_id = htonl(stream_id); 645 memcpy(fh->hfh_stream_id, &stream_id, 4); 646 647 stream_dep_id |= !!exclusive << 31; 648 stream_id = htonl(stream_dep_id); 649 memcpy(prio_frame->hpf_stream_id, &stream_id, 4); 650 prio_frame->hpf_weight = weight - 1; 651 652 s = lsquic_frab_list_write(&fw->fw_fral, buf, sizeof(buf)); 653 if (s != 0) 654 return s; 655 656 EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "wrote HTTP PRIORITY frame: " 657 "stream %"PRIu32"; weight: %u; exclusive: %d", 658 htonl(stream_id), weight, !!exclusive); 659 660 return lsquic_frame_writer_flush(fw); 661} 662 663 664size_t 665lsquic_frame_writer_mem_used (const struct lsquic_frame_writer *fw) 666{ 667 size_t size; 668 669 size = sizeof(*fw) 670 + lsquic_frab_list_mem_used(&fw->fw_fral) 671 - sizeof(fw->fw_fral); 672 673 return size; 674} 675