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