comparison src/http/v3/ngx_http_v3_request.c @ 8488:79125ef2e39f quic

HTTP/3: header encoding functions.
author Roman Arutyunyan <arut@nginx.com>
date Mon, 13 Jul 2020 16:00:00 +0300
parents 72f9ff4e0a88
children 5d2e285677a7
comparison
equal deleted inserted replaced
8487:6e84524886d4 8488:79125ef2e39f
6 6
7 7
8 #include <ngx_config.h> 8 #include <ngx_config.h>
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11
12
13 /* static table indices */
14 #define NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO 4
15 #define NGX_HTTP_V3_HEADER_DATE 6
16 #define NGX_HTTP_V3_HEADER_LAST_MODIFIED 10
17 #define NGX_HTTP_V3_HEADER_STATUS_200 25
18 #define NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN 53
19 #define NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING 59
20 #define NGX_HTTP_V3_HEADER_SERVER 92
11 21
12 22
13 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, 23 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r,
14 ngx_str_t *name, ngx_str_t *value); 24 ngx_str_t *name, ngx_str_t *value);
15 25
414 ngx_http_v3_create_header(ngx_http_request_t *r) 424 ngx_http_v3_create_header(ngx_http_request_t *r)
415 { 425 {
416 u_char *p; 426 u_char *p;
417 size_t len, n; 427 size_t len, n;
418 ngx_buf_t *b; 428 ngx_buf_t *b;
419 ngx_uint_t i, j; 429 ngx_uint_t i;
420 ngx_chain_t *hl, *cl, *bl; 430 ngx_chain_t *hl, *cl, *bl;
421 ngx_list_part_t *part; 431 ngx_list_part_t *part;
422 ngx_table_elt_t *header; 432 ngx_table_elt_t *header;
423 ngx_connection_t *c; 433 ngx_connection_t *c;
424 ngx_http_core_loc_conf_t *clcf; 434 ngx_http_core_loc_conf_t *clcf;
425 435
426 c = r->connection; 436 c = r->connection;
427 437
428 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 create header"); 438 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 create header");
429 439
430 len = 2; 440 len = ngx_http_v3_encode_header_block_prefix(NULL, 0, 0, 0);
431 441
432 if (r->headers_out.status == NGX_HTTP_OK) { 442 if (r->headers_out.status == NGX_HTTP_OK) {
433 len += ngx_http_v3_encode_prefix_int(NULL, 25, 6); 443 len += ngx_http_v3_encode_header_ri(NULL, 0,
444 NGX_HTTP_V3_HEADER_STATUS_200);
434 445
435 } else { 446 } else {
436 len += 3 + ngx_http_v3_encode_prefix_int(NULL, 25, 4) 447 len += ngx_http_v3_encode_header_lri(NULL, 0,
437 + ngx_http_v3_encode_prefix_int(NULL, 3, 7); 448 NGX_HTTP_V3_HEADER_STATUS_200,
449 NULL, 3);
438 } 450 }
439 451
440 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 452 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
441 453
442 if (r->headers_out.server == NULL) { 454 if (r->headers_out.server == NULL) {
448 460
449 } else { 461 } else {
450 n = sizeof("nginx") - 1; 462 n = sizeof("nginx") - 1;
451 } 463 }
452 464
453 len += ngx_http_v3_encode_prefix_int(NULL, 92, 4) 465 len += ngx_http_v3_encode_header_lri(NULL, 0,
454 + ngx_http_v3_encode_prefix_int(NULL, n, 7) + n; 466 NGX_HTTP_V3_HEADER_SERVER,
467 NULL, n);
455 } 468 }
456 469
457 if (r->headers_out.date == NULL) { 470 if (r->headers_out.date == NULL) {
458 len += ngx_http_v3_encode_prefix_int(NULL, 6, 4) 471 len += ngx_http_v3_encode_header_lri(NULL, 0, NGX_HTTP_V3_HEADER_DATE,
459 + ngx_http_v3_encode_prefix_int(NULL, ngx_cached_http_time.len, 472 NULL, ngx_cached_http_time.len);
460 7)
461 + ngx_cached_http_time.len;
462 } 473 }
463 474
464 if (r->headers_out.content_type.len) { 475 if (r->headers_out.content_type.len) {
465 n = r->headers_out.content_type.len; 476 n = r->headers_out.content_type.len;
466 477
468 && r->headers_out.charset.len) 479 && r->headers_out.charset.len)
469 { 480 {
470 n += sizeof("; charset=") - 1 + r->headers_out.charset.len; 481 n += sizeof("; charset=") - 1 + r->headers_out.charset.len;
471 } 482 }
472 483
473 len += ngx_http_v3_encode_prefix_int(NULL, 53, 4) 484 len += ngx_http_v3_encode_header_lri(NULL, 0,
474 + ngx_http_v3_encode_prefix_int(NULL, n, 7) + n; 485 NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN,
475 } 486 NULL, n);
476 487 }
477 if (r->headers_out.content_length_n > 0) { 488
478 len += ngx_http_v3_encode_prefix_int(NULL, 4, 4) + 1 + NGX_OFF_T_LEN; 489 if (r->headers_out.content_length == NULL) {
479 490 if (r->headers_out.content_length_n > 0) {
480 } else if (r->headers_out.content_length_n == 0) { 491 len += ngx_http_v3_encode_header_lri(NULL, 0,
481 len += ngx_http_v3_encode_prefix_int(NULL, 4, 6); 492 NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO,
493 NULL, NGX_OFF_T_LEN);
494
495 } else if (r->headers_out.content_length_n == 0) {
496 len += ngx_http_v3_encode_header_ri(NULL, 0,
497 NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO);
498 }
482 } 499 }
483 500
484 if (r->headers_out.last_modified == NULL 501 if (r->headers_out.last_modified == NULL
485 && r->headers_out.last_modified_time != -1) 502 && r->headers_out.last_modified_time != -1)
486 { 503 {
487 len += ngx_http_v3_encode_prefix_int(NULL, 10, 4) + 1 504 len += ngx_http_v3_encode_header_lri(NULL, 0,
488 + sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT"); 505 NGX_HTTP_V3_HEADER_LAST_MODIFIED, NULL,
506 sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
489 } 507 }
490 508
491 /* XXX location */ 509 /* XXX location */
492 510
493 #if (NGX_HTTP_GZIP) 511 #if (NGX_HTTP_GZIP)
494 if (r->gzip_vary) { 512 if (r->gzip_vary) {
495 if (clcf->gzip_vary) { 513 if (clcf->gzip_vary) {
496 /* Vary: Accept-Encoding */ 514 len += ngx_http_v3_encode_header_ri(NULL, 0,
497 len += ngx_http_v3_encode_prefix_int(NULL, 59, 6); 515 NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING);
498 516
499 } else { 517 } else {
500 r->gzip_vary = 0; 518 r->gzip_vary = 0;
501 } 519 }
502 } 520 }
519 537
520 if (header[i].hash == 0) { 538 if (header[i].hash == 0) {
521 continue; 539 continue;
522 } 540 }
523 541
524 len += ngx_http_v3_encode_prefix_int(NULL, header[i].key.len, 3) 542 len += ngx_http_v3_encode_header_l(NULL, &header[i].key,
525 + header[i].key.len 543 &header[i].value);
526 + ngx_http_v3_encode_prefix_int(NULL, header[i].value.len, 7 )
527 + header[i].value.len;
528 } 544 }
529 545
530 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 header len:%uz", len); 546 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 header len:%uz", len);
531 547
532 b = ngx_create_temp_buf(r->pool, len); 548 b = ngx_create_temp_buf(r->pool, len);
533 if (b == NULL) { 549 if (b == NULL) {
534 return NULL; 550 return NULL;
535 } 551 }
536 552
537 *b->last++ = 0; 553 b->last = (u_char *) ngx_http_v3_encode_header_block_prefix(b->last,
538 *b->last++ = 0; 554 0, 0, 0);
539 555
540 if (r->headers_out.status == NGX_HTTP_OK) { 556 if (r->headers_out.status == NGX_HTTP_OK) {
541 /* :status: 200 */ 557 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
542 *b->last = 0xc0; 558 NGX_HTTP_V3_HEADER_STATUS_200);
543 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 25, 6);
544 559
545 } else { 560 } else {
546 /* :status: 200 */ 561 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
547 *b->last = 0x70; 562 NGX_HTTP_V3_HEADER_STATUS_200,
548 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 25, 4); 563 NULL, 3);
549 *b->last = 0;
550 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 3, 7);
551 b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status); 564 b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status);
552 } 565 }
553 566
554 if (r->headers_out.server == NULL) { 567 if (r->headers_out.server == NULL) {
555 if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) { 568 if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
563 } else { 576 } else {
564 p = (u_char *) "nginx"; 577 p = (u_char *) "nginx";
565 n = sizeof("nginx") - 1; 578 n = sizeof("nginx") - 1;
566 } 579 }
567 580
568 /* server */ 581 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
569 *b->last = 0x70; 582 NGX_HTTP_V3_HEADER_SERVER,
570 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 92, 4); 583 p, n);
571 *b->last = 0;
572 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, n, 7);
573 b->last = ngx_cpymem(b->last, p, n);
574 } 584 }
575 585
576 if (r->headers_out.date == NULL) { 586 if (r->headers_out.date == NULL) {
577 /* date */ 587 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
578 *b->last = 0x70; 588 NGX_HTTP_V3_HEADER_DATE,
579 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 6, 4); 589 ngx_cached_http_time.data,
580 *b->last = 0; 590 ngx_cached_http_time.len);
581 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last,
582 ngx_cached_http_time.len, 7);
583 b->last = ngx_cpymem(b->last, ngx_cached_http_time.data,
584 ngx_cached_http_time.len);
585 } 591 }
586 592
587 if (r->headers_out.content_type.len) { 593 if (r->headers_out.content_type.len) {
588 n = r->headers_out.content_type.len; 594 n = r->headers_out.content_type.len;
589 595
591 && r->headers_out.charset.len) 597 && r->headers_out.charset.len)
592 { 598 {
593 n += sizeof("; charset=") - 1 + r->headers_out.charset.len; 599 n += sizeof("; charset=") - 1 + r->headers_out.charset.len;
594 } 600 }
595 601
596 /* content-type: text/plain */ 602 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
597 *b->last = 0x70; 603 NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN,
598 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 53, 4); 604 NULL, n);
599 *b->last = 0;
600 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, n, 7);
601 605
602 p = b->last; 606 p = b->last;
603 b->last = ngx_copy(b->last, r->headers_out.content_type.data, 607 b->last = ngx_cpymem(b->last, r->headers_out.content_type.data,
604 r->headers_out.content_type.len); 608 r->headers_out.content_type.len);
605 609
606 if (r->headers_out.content_type_len == r->headers_out.content_type.len 610 if (r->headers_out.content_type_len == r->headers_out.content_type.len
607 && r->headers_out.charset.len) 611 && r->headers_out.charset.len)
608 { 612 {
609 b->last = ngx_cpymem(b->last, "; charset=", 613 b->last = ngx_cpymem(b->last, "; charset=",
610 sizeof("; charset=") - 1); 614 sizeof("; charset=") - 1);
611 b->last = ngx_copy(b->last, r->headers_out.charset.data, 615 b->last = ngx_cpymem(b->last, r->headers_out.charset.data,
612 r->headers_out.charset.len); 616 r->headers_out.charset.len);
613 617
614 /* update r->headers_out.content_type for possible logging */ 618 /* update r->headers_out.content_type for possible logging */
615 619
616 r->headers_out.content_type.len = b->last - p; 620 r->headers_out.content_type.len = b->last - p;
617 r->headers_out.content_type.data = p; 621 r->headers_out.content_type.data = p;
618 } 622 }
619 } 623 }
620 624
621 if (r->headers_out.content_length_n > 0) { 625 if (r->headers_out.content_length == NULL) {
622 /* content-length: 0 */ 626 if (r->headers_out.content_length_n > 0) {
623 *b->last = 0x70; 627 p = ngx_sprintf(b->last, "%O", r->headers_out.content_length_n);
624 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 4, 4); 628 n = p - b->last;
625 p = b->last++; 629
626 b->last = ngx_sprintf(b->last, "%O", r->headers_out.content_length_n); 630 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
627 *p = b->last - p - 1; 631 NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO,
628 632 NULL, n);
629 } else if (r->headers_out.content_length_n == 0) { 633
630 /* content-length: 0 */ 634 b->last = ngx_sprintf(b->last, "%O",
631 *b->last = 0xc0; 635 r->headers_out.content_length_n);
632 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 4, 6); 636
637 } else if (r->headers_out.content_length_n == 0) {
638 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
639 NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO);
640 }
633 } 641 }
634 642
635 if (r->headers_out.last_modified == NULL 643 if (r->headers_out.last_modified == NULL
636 && r->headers_out.last_modified_time != -1) 644 && r->headers_out.last_modified_time != -1)
637 { 645 {
638 /* last-modified */ 646 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
639 *b->last = 0x70; 647 NGX_HTTP_V3_HEADER_LAST_MODIFIED, NULL,
640 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 10, 4); 648 sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
641 p = b->last++; 649
642 b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); 650 b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);
643 *p = b->last - p - 1;
644 } 651 }
645 652
646 #if (NGX_HTTP_GZIP) 653 #if (NGX_HTTP_GZIP)
647 if (r->gzip_vary) { 654 if (r->gzip_vary) {
648 /* vary: accept-encoding */ 655 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
649 *b->last = 0xc0; 656 NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING);
650 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 59, 6);
651 } 657 }
652 #endif 658 #endif
653 659
654 part = &r->headers_out.headers.part; 660 part = &r->headers_out.headers.part;
655 header = part->elts; 661 header = part->elts;
668 674
669 if (header[i].hash == 0) { 675 if (header[i].hash == 0) {
670 continue; 676 continue;
671 } 677 }
672 678
673 *b->last = 0x30; 679 b->last = (u_char *) ngx_http_v3_encode_header_l(b->last,
674 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 680 &header[i].key,
675 header[i].key.len, 681 &header[i].value);
676 3);
677 for (j = 0; j < header[i].key.len; j++) {
678 *b->last++ = ngx_tolower(header[i].key.data[j]);
679 }
680
681 *b->last = 0;
682 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last,
683 header[i].value.len,
684 7);
685 b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
686 } 682 }
687 683
688 if (r->header_only) { 684 if (r->header_only) {
689 b->last_buf = 1; 685 b->last_buf = 1;
690 } 686 }