comparison src/http/modules/ngx_http_grpc_module.c @ 7234:c693daca57f7

gRPC: special handling of the TE request header. According to the gRPC protocol specification, the "TE" header is used to detect incompatible proxies, and at least grpc-c server rejects requests without "TE: trailers". To preserve the logic, we have to pass "TE: trailers" to the backend if and only if the original request contains "trailers" in the "TE" header. Note that no other TE values are allowed in HTTP/2, so we have to remove anything else.
author Maxim Dounin <mdounin@mdounin.ru>
date Sat, 17 Mar 2018 23:04:25 +0300
parents 2713b2dbf5bb
children c2a0a838c40f
comparison
equal deleted inserted replaced
7233:2713b2dbf5bb 7234:c693daca57f7
174 174
175 static void ngx_http_grpc_abort_request(ngx_http_request_t *r); 175 static void ngx_http_grpc_abort_request(ngx_http_request_t *r);
176 static void ngx_http_grpc_finalize_request(ngx_http_request_t *r, 176 static void ngx_http_grpc_finalize_request(ngx_http_request_t *r,
177 ngx_int_t rc); 177 ngx_int_t rc);
178 178
179 static ngx_int_t ngx_http_grpc_internal_trailers_variable(
180 ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
181
182 static ngx_int_t ngx_http_grpc_add_variables(ngx_conf_t *cf);
179 static void *ngx_http_grpc_create_loc_conf(ngx_conf_t *cf); 183 static void *ngx_http_grpc_create_loc_conf(ngx_conf_t *cf);
180 static char *ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, 184 static char *ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf,
181 void *parent, void *child); 185 void *parent, void *child);
182 static ngx_int_t ngx_http_grpc_init_headers(ngx_conf_t *cf, 186 static ngx_int_t ngx_http_grpc_init_headers(ngx_conf_t *cf,
183 ngx_http_grpc_loc_conf_t *conf, ngx_http_grpc_headers_t *headers, 187 ngx_http_grpc_loc_conf_t *conf, ngx_http_grpc_headers_t *headers,
417 ngx_null_command 421 ngx_null_command
418 }; 422 };
419 423
420 424
421 static ngx_http_module_t ngx_http_grpc_module_ctx = { 425 static ngx_http_module_t ngx_http_grpc_module_ctx = {
422 NULL, /* preconfiguration */ 426 ngx_http_grpc_add_variables, /* preconfiguration */
423 NULL, /* postconfiguration */ 427 NULL, /* postconfiguration */
424 428
425 NULL, /* create main configuration */ 429 NULL, /* create main configuration */
426 NULL, /* init main configuration */ 430 NULL, /* init main configuration */
427 431
461 "\x7f\xff\x00\x00"; 465 "\x7f\xff\x00\x00";
462 466
463 467
464 static ngx_keyval_t ngx_http_grpc_headers[] = { 468 static ngx_keyval_t ngx_http_grpc_headers[] = {
465 { ngx_string("Content-Length"), ngx_string("$content_length") }, 469 { ngx_string("Content-Length"), ngx_string("$content_length") },
470 { ngx_string("TE"), ngx_string("$grpc_internal_trailers") },
466 { ngx_string("Host"), ngx_string("") }, 471 { ngx_string("Host"), ngx_string("") },
467 { ngx_string("Connection"), ngx_string("") }, 472 { ngx_string("Connection"), ngx_string("") },
468 { ngx_string("Transfer-Encoding"), ngx_string("") }, 473 { ngx_string("Transfer-Encoding"), ngx_string("") },
469 { ngx_string("TE"), ngx_string("") },
470 { ngx_string("Keep-Alive"), ngx_string("") }, 474 { ngx_string("Keep-Alive"), ngx_string("") },
471 { ngx_string("Expect"), ngx_string("") }, 475 { ngx_string("Expect"), ngx_string("") },
472 { ngx_string("Upgrade"), ngx_string("") }, 476 { ngx_string("Upgrade"), ngx_string("") },
473 { ngx_null_string, ngx_null_string } 477 { ngx_null_string, ngx_null_string }
474 }; 478 };
481 ngx_string("X-Accel-Redirect"), 485 ngx_string("X-Accel-Redirect"),
482 ngx_string("X-Accel-Limit-Rate"), 486 ngx_string("X-Accel-Limit-Rate"),
483 ngx_string("X-Accel-Buffering"), 487 ngx_string("X-Accel-Buffering"),
484 ngx_string("X-Accel-Charset"), 488 ngx_string("X-Accel-Charset"),
485 ngx_null_string 489 ngx_null_string
490 };
491
492
493 static ngx_http_variable_t ngx_http_grpc_vars[] = {
494
495 { ngx_string("grpc_internal_trailers"), NULL,
496 ngx_http_grpc_internal_trailers_variable, 0,
497 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
498
499 ngx_http_null_variable
486 }; 500 };
487 501
488 502
489 static ngx_int_t 503 static ngx_int_t
490 ngx_http_grpc_handler(ngx_http_request_t *r) 504 ngx_http_grpc_handler(ngx_http_request_t *r)
3994 "finalize grpc request"); 4008 "finalize grpc request");
3995 return; 4009 return;
3996 } 4010 }
3997 4011
3998 4012
4013 static ngx_int_t
4014 ngx_http_grpc_internal_trailers_variable(ngx_http_request_t *r,
4015 ngx_http_variable_value_t *v, uintptr_t data)
4016 {
4017 ngx_table_elt_t *te;
4018
4019 te = r->headers_in.te;
4020
4021 if (te == NULL) {
4022 v->not_found = 1;
4023 return NGX_OK;
4024 }
4025
4026 if (ngx_strlcasestrn(te->value.data, te->value.data + te->value.len,
4027 (u_char *) "trailers", 8 - 1)
4028 == NULL)
4029 {
4030 v->not_found = 1;
4031 return NGX_OK;
4032 }
4033
4034 v->valid = 1;
4035 v->no_cacheable = 0;
4036 v->not_found = 0;
4037
4038 v->data = (u_char *) "trailers";
4039 v->len = sizeof("trailers") - 1;
4040
4041 return NGX_OK;
4042 }
4043
4044
4045 static ngx_int_t
4046 ngx_http_grpc_add_variables(ngx_conf_t *cf)
4047 {
4048 ngx_http_variable_t *var, *v;
4049
4050 for (v = ngx_http_grpc_vars; v->name.len; v++) {
4051 var = ngx_http_add_variable(cf, &v->name, v->flags);
4052 if (var == NULL) {
4053 return NGX_ERROR;
4054 }
4055
4056 var->get_handler = v->get_handler;
4057 var->data = v->data;
4058 }
4059
4060 return NGX_OK;
4061 }
4062
4063
3999 static void * 4064 static void *
4000 ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) 4065 ngx_http_grpc_create_loc_conf(ngx_conf_t *cf)
4001 { 4066 {
4002 ngx_http_grpc_loc_conf_t *conf; 4067 ngx_http_grpc_loc_conf_t *conf;
4003 4068