Mercurial > hg > nginx-quic
comparison src/http/v3/ngx_http_v3_request.c @ 8006: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
8005:6e84524886d4 | 8006: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 } |