Mercurial > hg > nginx
comparison src/http/modules/ngx_http_grpc_module.c @ 7619:6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Fri, 17 Jan 2020 12:13:02 +0300 |
parents | 8981dbb12254 |
children | 2096b21fcd10 |
comparison
equal
deleted
inserted
replaced
7618:8a7b59347401 | 7619:6439ef81e37d |
---|---|
24 ngx_http_grpc_headers_t headers; | 24 ngx_http_grpc_headers_t headers; |
25 ngx_array_t *headers_source; | 25 ngx_array_t *headers_source; |
26 | 26 |
27 ngx_str_t host; | 27 ngx_str_t host; |
28 ngx_uint_t host_set; | 28 ngx_uint_t host_set; |
29 | |
30 ngx_array_t *grpc_lengths; | |
31 ngx_array_t *grpc_values; | |
29 | 32 |
30 #if (NGX_HTTP_SSL) | 33 #if (NGX_HTTP_SSL) |
31 ngx_uint_t ssl; | 34 ngx_uint_t ssl; |
32 ngx_uint_t ssl_protocols; | 35 ngx_uint_t ssl_protocols; |
33 ngx_str_t ssl_ciphers; | 36 ngx_str_t ssl_ciphers; |
117 unsigned end_stream:1; | 120 unsigned end_stream:1; |
118 unsigned done:1; | 121 unsigned done:1; |
119 unsigned status:1; | 122 unsigned status:1; |
120 | 123 |
121 ngx_http_request_t *request; | 124 ngx_http_request_t *request; |
125 | |
126 ngx_str_t host; | |
122 } ngx_http_grpc_ctx_t; | 127 } ngx_http_grpc_ctx_t; |
123 | 128 |
124 | 129 |
125 typedef struct { | 130 typedef struct { |
126 u_char length_0; | 131 u_char length_0; |
133 u_char stream_id_2; | 138 u_char stream_id_2; |
134 u_char stream_id_3; | 139 u_char stream_id_3; |
135 } ngx_http_grpc_frame_t; | 140 } ngx_http_grpc_frame_t; |
136 | 141 |
137 | 142 |
143 static ngx_int_t ngx_http_grpc_eval(ngx_http_request_t *r, | |
144 ngx_http_grpc_ctx_t *ctx, ngx_http_grpc_loc_conf_t *glcf); | |
138 static ngx_int_t ngx_http_grpc_create_request(ngx_http_request_t *r); | 145 static ngx_int_t ngx_http_grpc_create_request(ngx_http_request_t *r); |
139 static ngx_int_t ngx_http_grpc_reinit_request(ngx_http_request_t *r); | 146 static ngx_int_t ngx_http_grpc_reinit_request(ngx_http_request_t *r); |
140 static ngx_int_t ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in); | 147 static ngx_int_t ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in); |
141 static ngx_int_t ngx_http_grpc_process_header(ngx_http_request_t *r); | 148 static ngx_int_t ngx_http_grpc_process_header(ngx_http_request_t *r); |
142 static ngx_int_t ngx_http_grpc_filter_init(void *data); | 149 static ngx_int_t ngx_http_grpc_filter_init(void *data); |
522 | 529 |
523 if (ngx_http_upstream_create(r) != NGX_OK) { | 530 if (ngx_http_upstream_create(r) != NGX_OK) { |
524 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 531 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
525 } | 532 } |
526 | 533 |
534 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_grpc_ctx_t)); | |
535 if (ctx == NULL) { | |
536 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
537 } | |
538 | |
539 ctx->request = r; | |
540 | |
541 ngx_http_set_ctx(r, ctx, ngx_http_grpc_module); | |
542 | |
527 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module); | 543 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module); |
528 | 544 |
529 u = r->upstream; | 545 u = r->upstream; |
530 | 546 |
547 if (glcf->grpc_lengths == NULL) { | |
548 ctx->host = glcf->host; | |
549 | |
531 #if (NGX_HTTP_SSL) | 550 #if (NGX_HTTP_SSL) |
532 u->ssl = (glcf->upstream.ssl != NULL); | 551 u->ssl = (glcf->upstream.ssl != NULL); |
533 | 552 |
534 if (u->ssl) { | 553 if (u->ssl) { |
535 ngx_str_set(&u->schema, "grpcs://"); | 554 ngx_str_set(&u->schema, "grpcs://"); |
555 | |
556 } else { | |
557 ngx_str_set(&u->schema, "grpc://"); | |
558 } | |
559 #else | |
560 ngx_str_set(&u->schema, "grpc://"); | |
561 #endif | |
536 | 562 |
537 } else { | 563 } else { |
538 ngx_str_set(&u->schema, "grpc://"); | 564 if (ngx_http_grpc_eval(r, ctx, glcf) != NGX_OK) { |
539 } | 565 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
540 #else | 566 } |
541 ngx_str_set(&u->schema, "grpc://"); | 567 } |
542 #endif | |
543 | 568 |
544 u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module; | 569 u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module; |
545 | 570 |
546 u->conf = &glcf->upstream; | 571 u->conf = &glcf->upstream; |
547 | 572 |
549 u->reinit_request = ngx_http_grpc_reinit_request; | 574 u->reinit_request = ngx_http_grpc_reinit_request; |
550 u->process_header = ngx_http_grpc_process_header; | 575 u->process_header = ngx_http_grpc_process_header; |
551 u->abort_request = ngx_http_grpc_abort_request; | 576 u->abort_request = ngx_http_grpc_abort_request; |
552 u->finalize_request = ngx_http_grpc_finalize_request; | 577 u->finalize_request = ngx_http_grpc_finalize_request; |
553 | 578 |
554 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_grpc_ctx_t)); | |
555 if (ctx == NULL) { | |
556 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
557 } | |
558 | |
559 ctx->request = r; | |
560 | |
561 ngx_http_set_ctx(r, ctx, ngx_http_grpc_module); | |
562 | |
563 u->input_filter_init = ngx_http_grpc_filter_init; | 579 u->input_filter_init = ngx_http_grpc_filter_init; |
564 u->input_filter = ngx_http_grpc_filter; | 580 u->input_filter = ngx_http_grpc_filter; |
565 u->input_filter_ctx = ctx; | 581 u->input_filter_ctx = ctx; |
566 | 582 |
567 r->request_body_no_buffering = 1; | 583 r->request_body_no_buffering = 1; |
571 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { | 587 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { |
572 return rc; | 588 return rc; |
573 } | 589 } |
574 | 590 |
575 return NGX_DONE; | 591 return NGX_DONE; |
592 } | |
593 | |
594 | |
595 static ngx_int_t | |
596 ngx_http_grpc_eval(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
597 ngx_http_grpc_loc_conf_t *glcf) | |
598 { | |
599 size_t add; | |
600 ngx_url_t url; | |
601 ngx_http_upstream_t *u; | |
602 | |
603 ngx_memzero(&url, sizeof(ngx_url_t)); | |
604 | |
605 if (ngx_http_script_run(r, &url.url, glcf->grpc_lengths->elts, 0, | |
606 glcf->grpc_values->elts) | |
607 == NULL) | |
608 { | |
609 return NGX_ERROR; | |
610 } | |
611 | |
612 if (url.url.len > 7 | |
613 && ngx_strncasecmp(url.url.data, (u_char *) "grpc://", 7) == 0) | |
614 { | |
615 add = 7; | |
616 | |
617 } else if (url.url.len > 8 | |
618 && ngx_strncasecmp(url.url.data, (u_char *) "grpcs://", 8) == 0) | |
619 { | |
620 | |
621 #if (NGX_HTTP_SSL) | |
622 add = 8; | |
623 r->upstream->ssl = 1; | |
624 #else | |
625 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
626 "grpcs protocol requires SSL support"); | |
627 return NGX_ERROR; | |
628 #endif | |
629 | |
630 } else { | |
631 add = 0; | |
632 } | |
633 | |
634 u = r->upstream; | |
635 | |
636 if (add) { | |
637 u->schema.len = add; | |
638 u->schema.data = url.url.data; | |
639 | |
640 url.url.data += add; | |
641 url.url.len -= add; | |
642 | |
643 } else { | |
644 ngx_str_set(&u->schema, "grpc://"); | |
645 } | |
646 | |
647 url.no_resolve = 1; | |
648 | |
649 if (ngx_parse_url(r->pool, &url) != NGX_OK) { | |
650 if (url.err) { | |
651 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
652 "%s in upstream \"%V\"", url.err, &url.url); | |
653 } | |
654 | |
655 return NGX_ERROR; | |
656 } | |
657 | |
658 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); | |
659 if (u->resolved == NULL) { | |
660 return NGX_ERROR; | |
661 } | |
662 | |
663 if (url.addrs) { | |
664 u->resolved->sockaddr = url.addrs[0].sockaddr; | |
665 u->resolved->socklen = url.addrs[0].socklen; | |
666 u->resolved->name = url.addrs[0].name; | |
667 u->resolved->naddrs = 1; | |
668 } | |
669 | |
670 u->resolved->host = url.host; | |
671 u->resolved->port = url.port; | |
672 u->resolved->no_port = url.no_port; | |
673 | |
674 if (url.family != AF_UNIX) { | |
675 | |
676 if (url.no_port) { | |
677 ctx->host = url.host; | |
678 | |
679 } else { | |
680 ctx->host.len = url.host.len + 1 + url.port_text.len; | |
681 ctx->host.data = url.host.data; | |
682 } | |
683 | |
684 } else { | |
685 ngx_str_set(&ctx->host, "localhost"); | |
686 } | |
687 | |
688 return NGX_OK; | |
576 } | 689 } |
577 | 690 |
578 | 691 |
579 static ngx_int_t | 692 static ngx_int_t |
580 ngx_http_grpc_create_request(ngx_http_request_t *r) | 693 ngx_http_grpc_create_request(ngx_http_request_t *r) |
585 ngx_buf_t *b; | 698 ngx_buf_t *b; |
586 ngx_uint_t i, next; | 699 ngx_uint_t i, next; |
587 ngx_chain_t *cl, *body; | 700 ngx_chain_t *cl, *body; |
588 ngx_list_part_t *part; | 701 ngx_list_part_t *part; |
589 ngx_table_elt_t *header; | 702 ngx_table_elt_t *header; |
703 ngx_http_grpc_ctx_t *ctx; | |
590 ngx_http_upstream_t *u; | 704 ngx_http_upstream_t *u; |
591 ngx_http_grpc_frame_t *f; | 705 ngx_http_grpc_frame_t *f; |
592 ngx_http_script_code_pt code; | 706 ngx_http_script_code_pt code; |
593 ngx_http_grpc_loc_conf_t *glcf; | 707 ngx_http_grpc_loc_conf_t *glcf; |
594 ngx_http_script_engine_t e, le; | 708 ngx_http_script_engine_t e, le; |
596 | 710 |
597 u = r->upstream; | 711 u = r->upstream; |
598 | 712 |
599 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module); | 713 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module); |
600 | 714 |
715 ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module); | |
716 | |
601 len = sizeof(ngx_http_grpc_connection_start) - 1 | 717 len = sizeof(ngx_http_grpc_connection_start) - 1 |
602 + sizeof(ngx_http_grpc_frame_t); /* headers frame */ | 718 + sizeof(ngx_http_grpc_frame_t); /* headers frame */ |
603 | 719 |
604 /* :method header */ | 720 /* :method header */ |
605 | 721 |
635 } | 751 } |
636 | 752 |
637 /* :authority header */ | 753 /* :authority header */ |
638 | 754 |
639 if (!glcf->host_set) { | 755 if (!glcf->host_set) { |
640 len += 1 + NGX_HTTP_V2_INT_OCTETS + glcf->host.len; | 756 len += 1 + NGX_HTTP_V2_INT_OCTETS + ctx->host.len; |
641 | 757 |
642 if (tmp_len < glcf->host.len) { | 758 if (tmp_len < ctx->host.len) { |
643 tmp_len = glcf->host.len; | 759 tmp_len = ctx->host.len; |
644 } | 760 } |
645 } | 761 } |
646 | 762 |
647 /* other headers */ | 763 /* other headers */ |
648 | 764 |
783 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 899 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
784 "grpc header: \":method: %V\"", &r->method_name); | 900 "grpc header: \":method: %V\"", &r->method_name); |
785 } | 901 } |
786 | 902 |
787 #if (NGX_HTTP_SSL) | 903 #if (NGX_HTTP_SSL) |
788 if (glcf->ssl) { | 904 if (u->ssl) { |
789 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX); | 905 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX); |
790 | 906 |
791 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 907 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
792 "grpc header: \":scheme: https\""); | 908 "grpc header: \":scheme: https\""); |
793 } else | 909 } else |
844 "grpc header: \":path: %V\"", &r->uri); | 960 "grpc header: \":path: %V\"", &r->uri); |
845 } | 961 } |
846 | 962 |
847 if (!glcf->host_set) { | 963 if (!glcf->host_set) { |
848 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX); | 964 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX); |
849 b->last = ngx_http_v2_write_value(b->last, glcf->host.data, | 965 b->last = ngx_http_v2_write_value(b->last, ctx->host.data, |
850 glcf->host.len, tmp); | 966 ctx->host.len, tmp); |
851 | 967 |
852 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 968 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
853 "grpc header: \":authority: %V\"", &glcf->host); | 969 "grpc header: \":authority: %V\"", &ctx->host); |
854 } | 970 } |
855 | 971 |
856 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); | 972 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); |
857 | 973 |
858 e.ip = glcf->headers.values->elts; | 974 e.ip = glcf->headers.values->elts; |
4317 return NGX_CONF_ERROR; | 4433 return NGX_CONF_ERROR; |
4318 } | 4434 } |
4319 | 4435 |
4320 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | 4436 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); |
4321 | 4437 |
4322 if (clcf->noname && conf->upstream.upstream == NULL) { | 4438 if (clcf->noname |
4439 && conf->upstream.upstream == NULL && conf->grpc_lengths == NULL) | |
4440 { | |
4323 conf->upstream.upstream = prev->upstream.upstream; | 4441 conf->upstream.upstream = prev->upstream.upstream; |
4324 conf->host = prev->host; | 4442 conf->host = prev->host; |
4443 | |
4444 conf->grpc_lengths = prev->grpc_lengths; | |
4445 conf->grpc_values = prev->grpc_values; | |
4446 | |
4325 #if (NGX_HTTP_SSL) | 4447 #if (NGX_HTTP_SSL) |
4326 conf->upstream.ssl = prev->upstream.ssl; | 4448 conf->upstream.ssl = prev->upstream.ssl; |
4327 #endif | 4449 #endif |
4328 } | 4450 } |
4329 | 4451 |
4330 if (clcf->lmt_excpt && clcf->handler == NULL && conf->upstream.upstream) { | 4452 if (clcf->lmt_excpt && clcf->handler == NULL |
4453 && (conf->upstream.upstream || conf->grpc_lengths)) | |
4454 { | |
4331 clcf->handler = ngx_http_grpc_handler; | 4455 clcf->handler = ngx_http_grpc_handler; |
4332 } | 4456 } |
4333 | 4457 |
4334 if (conf->headers_source == NULL) { | 4458 if (conf->headers_source == NULL) { |
4335 conf->headers = prev->headers; | 4459 conf->headers = prev->headers; |
4535 static char * | 4659 static char * |
4536 ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 4660 ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
4537 { | 4661 { |
4538 ngx_http_grpc_loc_conf_t *glcf = conf; | 4662 ngx_http_grpc_loc_conf_t *glcf = conf; |
4539 | 4663 |
4540 size_t add; | 4664 size_t add; |
4541 ngx_str_t *value, *url; | 4665 ngx_str_t *value, *url; |
4542 ngx_url_t u; | 4666 ngx_url_t u; |
4543 ngx_http_core_loc_conf_t *clcf; | 4667 ngx_uint_t n; |
4544 | 4668 ngx_http_core_loc_conf_t *clcf; |
4545 if (glcf->upstream.upstream) { | 4669 ngx_http_script_compile_t sc; |
4670 | |
4671 if (glcf->upstream.upstream || glcf->grpc_lengths) { | |
4546 return "is duplicate"; | 4672 return "is duplicate"; |
4547 } | 4673 } |
4548 | 4674 |
4675 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
4676 | |
4677 clcf->handler = ngx_http_grpc_handler; | |
4678 | |
4679 if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { | |
4680 clcf->auto_redirect = 1; | |
4681 } | |
4682 | |
4549 value = cf->args->elts; | 4683 value = cf->args->elts; |
4684 | |
4550 url = &value[1]; | 4685 url = &value[1]; |
4686 | |
4687 n = ngx_http_script_variables_count(url); | |
4688 | |
4689 if (n) { | |
4690 | |
4691 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | |
4692 | |
4693 sc.cf = cf; | |
4694 sc.source = url; | |
4695 sc.lengths = &glcf->grpc_lengths; | |
4696 sc.values = &glcf->grpc_values; | |
4697 sc.variables = n; | |
4698 sc.complete_lengths = 1; | |
4699 sc.complete_values = 1; | |
4700 | |
4701 if (ngx_http_script_compile(&sc) != NGX_OK) { | |
4702 return NGX_CONF_ERROR; | |
4703 } | |
4704 | |
4705 #if (NGX_HTTP_SSL) | |
4706 glcf->ssl = 1; | |
4707 #endif | |
4708 | |
4709 return NGX_CONF_OK; | |
4710 } | |
4551 | 4711 |
4552 if (ngx_strncasecmp(url->data, (u_char *) "grpc://", 7) == 0) { | 4712 if (ngx_strncasecmp(url->data, (u_char *) "grpc://", 7) == 0) { |
4553 add = 7; | 4713 add = 7; |
4554 | 4714 |
4555 } else if (ngx_strncasecmp(url->data, (u_char *) "grpcs://", 8) == 0) { | 4715 } else if (ngx_strncasecmp(url->data, (u_char *) "grpcs://", 8) == 0) { |
4589 glcf->host.data = u.host.data; | 4749 glcf->host.data = u.host.data; |
4590 } | 4750 } |
4591 | 4751 |
4592 } else { | 4752 } else { |
4593 ngx_str_set(&glcf->host, "localhost"); | 4753 ngx_str_set(&glcf->host, "localhost"); |
4594 } | |
4595 | |
4596 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
4597 | |
4598 clcf->handler = ngx_http_grpc_handler; | |
4599 | |
4600 if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { | |
4601 clcf->auto_redirect = 1; | |
4602 } | 4754 } |
4603 | 4755 |
4604 return NGX_CONF_OK; | 4756 return NGX_CONF_OK; |
4605 } | 4757 } |
4606 | 4758 |